Documentation
¶
Overview ¶
Package render provides the integration layer between gg and GPU frameworks.
This package defines the core abstractions for device integration, allowing gg to render to GPU surfaces provided by host applications (like gogpu.App).
Key Principle ¶
gg RECEIVES a GPU device from the host application, it does NOT create its own. This follows the Vello/femtovg/Skia pattern where the rendering library is injected with GPU resources rather than managing them itself.
Core Interfaces ¶
- DeviceHandle: Provides GPU device access from the host application
- RenderTarget: Defines where rendering output goes (Pixmap, Texture, Surface)
- Renderer: Executes drawing commands to a target
- EventSource: Input events for UI integration (future)
Renderer Implementations ¶
- SoftwareRenderer: CPU-based rendering using the core/ package
- GPURenderer: GPU-accelerated rendering (stub for Phase 3)
RenderTarget Implementations ¶
- PixmapTarget: CPU-backed *image.RGBA target
- TextureTarget: GPU texture target (stub)
- SurfaceTarget: Window surface from host (stub)
Usage ¶
Integration with gogpu:
app := gogpu.NewApp(gogpu.Config{...})
var renderer render.Renderer
var scene *Scene
var initialized bool
app.OnDraw(func(dc *gogpu.Context) {
if !initialized {
// Get gpucontext.DeviceProvider from gogpu
provider := app.GPUContextProvider()
if provider != nil {
// gg receives GPU device from gogpu (zero overhead)
renderer, _ = render.NewGPURenderer(provider)
// Build scene (retained mode)
scene = NewScene()
scene.SetFillColor(Red)
scene.Circle(100, 100, 50)
scene.Fill()
initialized = true
}
}
// Render scene to CPU target (GPU targets in Phase 3)
target := render.NewPixmapTarget(800, 600)
renderer.Render(target, scene)
})
Software rendering fallback:
// Create CPU-backed target target := render.NewPixmapTarget(800, 600) // Create software renderer renderer := render.NewSoftwareRenderer() // Render scene renderer.Render(target, scene) // Get rendered image img := target.Image()
Architecture ¶
User Application
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
gogpu.App gg.Context gg.Scene
(windowing) (immediate) (retained)
│ │ │
└────────────────┼────────────────┘
│
▼
gg/render package
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
DeviceHandle RenderTarget Renderer
(GPU access) (output target) (execution)
│ │ │
└────────────────┼────────────────┘
│
▼
gg/core package
(CPU rasterization)
Thread Safety ¶
Renderers are NOT thread-safe. Each renderer should be used from a single goroutine, or external synchronization must be used.
References ¶
- Vello DeviceProvider pattern: https://github.com/AhornGraphics/vello
- femtovg Renderer trait: https://github.com/AhornGraphics/femtovg
- Skia GrDirectContext: https://skia.org/docs/user/api/
Index ¶
- type CapableRenderer
- type DeviceCapabilities
- type DeviceHandle
- type DirtyRect
- type GPURenderer
- type LayeredPixmapTarget
- func (t *LayeredPixmapTarget) Clear(c color.Color)
- func (t *LayeredPixmapTarget) ClearLayer(z int, c color.Color) error
- func (t *LayeredPixmapTarget) Composite()
- func (t *LayeredPixmapTarget) CreateLayer(z int) (RenderTarget, error)
- func (t *LayeredPixmapTarget) Format() gputypes.TextureFormat
- func (t *LayeredPixmapTarget) GetLayer(z int) RenderTarget
- func (t *LayeredPixmapTarget) Height() int
- func (t *LayeredPixmapTarget) Image() *image.RGBA
- func (t *LayeredPixmapTarget) Layers() []int
- func (t *LayeredPixmapTarget) Pixels() []byte
- func (t *LayeredPixmapTarget) RemoveLayer(z int) error
- func (t *LayeredPixmapTarget) SetLayerVisible(z int, visible bool)
- func (t *LayeredPixmapTarget) Stride() int
- func (t *LayeredPixmapTarget) TextureView() TextureView
- func (t *LayeredPixmapTarget) Width() int
- type LayeredTarget
- type NullDeviceHandle
- type PixmapTarget
- func (t *PixmapTarget) Clear(c color.Color)
- func (t *PixmapTarget) Format() gputypes.TextureFormat
- func (t *PixmapTarget) GetPixel(x, y int) color.Color
- func (t *PixmapTarget) Height() int
- func (t *PixmapTarget) Image() *image.RGBA
- func (t *PixmapTarget) Pixels() []byte
- func (t *PixmapTarget) Resize(width, height int)
- func (t *PixmapTarget) SetPixel(x, y int, c color.Color)
- func (t *PixmapTarget) Stride() int
- func (t *PixmapTarget) TextureView() TextureView
- func (t *PixmapTarget) Width() int
- type RenderTarget
- type Renderer
- type RendererCapabilities
- type Scene
- func (s *Scene) Circle(cx, cy, r float64)
- func (s *Scene) Clear(c color.Color)
- func (s *Scene) ClearDirty()
- func (s *Scene) ClosePath()
- func (s *Scene) CommandCount() int
- func (s *Scene) CubicTo(c1x, c1y, c2x, c2y, x, y float64)
- func (s *Scene) DirtyRects() []DirtyRect
- func (s *Scene) Fill()
- func (s *Scene) HasDirtyRegions() bool
- func (s *Scene) Invalidate(rect DirtyRect)
- func (s *Scene) InvalidateAll()
- func (s *Scene) IsEmpty() bool
- func (s *Scene) LineTo(x, y float64)
- func (s *Scene) MoveTo(x, y float64)
- func (s *Scene) NeedsFullRedraw() bool
- func (s *Scene) QuadTo(cx, cy, x, y float64)
- func (s *Scene) Rectangle(x, y, width, height float64)
- func (s *Scene) Reset()
- func (s *Scene) SetFillColor(c color.Color)
- func (s *Scene) SetFillRule(rule raster.FillRule)
- func (s *Scene) SetStrokeColor(c color.Color)
- func (s *Scene) SetStrokeWidth(width float64)
- func (s *Scene) Stroke()
- type SoftwareRenderer
- type SurfaceTarget
- type Texture
- type TextureDescriptor
- type TextureTarget
- type TextureUsage
- type TextureView
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CapableRenderer ¶
type CapableRenderer interface {
Renderer
// Capabilities returns the renderer's capabilities.
Capabilities() RendererCapabilities
}
CapableRenderer is an optional interface for renderers that can report their capabilities.
type DeviceCapabilities ¶
type DeviceCapabilities struct {
// MaxTextureSize is the maximum texture dimension supported.
MaxTextureSize uint32
// MaxBindGroups is the maximum number of bind groups.
MaxBindGroups uint32
// SupportsCompute indicates if compute shaders are supported.
SupportsCompute bool
// SupportsStorageTextures indicates if storage textures are supported.
SupportsStorageTextures bool
// VendorName is the GPU vendor name.
VendorName string
// DeviceName is the GPU device name.
DeviceName string
}
DeviceCapabilities describes the capabilities of a GPU device. Used to determine available features and limits for rendering decisions.
type DeviceHandle ¶
type DeviceHandle = gpucontext.DeviceProvider
DeviceHandle provides GPU device access from the host application.
This interface is the primary integration point between gg and GPU frameworks like gogpu. The host application (e.g., gogpu.App) implements DeviceHandle and passes it to gg renderers, allowing gg to use the shared GPU device.
Key principle: gg RECEIVES the device from the host, it does NOT create one. This enables:
- Shared GPU resources between gg and the host application
- Zero device creation overhead in gg
- Consistent resource management across the stack
Example implementation in gogpu:
type contextDeviceHandle struct {
ctx *gogpu.Context
}
func (h *contextDeviceHandle) Device() gpucontext.Device {
return h.ctx.device
}
func (h *contextDeviceHandle) Queue() gpucontext.Queue {
return h.ctx.queue
}
DeviceHandle is an alias for gpucontext.DeviceProvider, providing a gg-specific name for the interface while maintaining full compatibility with the gpucontext ecosystem.
type DirtyRect ¶
type DirtyRect struct {
X, Y, Width, Height float64
}
DirtyRect represents a region that needs redraw. Used for damage tracking to enable efficient partial redraws.
type GPURenderer ¶
type GPURenderer struct {
// contains filtered or unexported fields
}
GPURenderer is a GPU-accelerated renderer using WebGPU.
This renderer uses the GPU device provided by the host application to perform hardware-accelerated 2D rendering. It leverages compute shaders for path rasterization and the render pipeline for compositing.
Note: This is a stub implementation for Phase 1. Full GPU rendering will be implemented in Phase 3.
Example:
app := gogpu.NewApp(gogpu.Config{...})
var renderer *render.GPURenderer
var initialized bool
app.OnDraw(func(dc *gogpu.Context) {
if !initialized {
provider := app.GPUContextProvider()
if provider != nil {
renderer, _ = render.NewGPURenderer(provider)
initialized = true
}
}
// Render scene (CPU target for now, GPU targets in Phase 3)
target := render.NewPixmapTarget(800, 600)
renderer.Render(target, scene)
})
func NewGPURenderer ¶
func NewGPURenderer(handle DeviceHandle) (*GPURenderer, error)
NewGPURenderer creates a new GPU-accelerated renderer.
The DeviceHandle must be provided by the host application (e.g., gogpu.App). The renderer does NOT create its own GPU device.
Returns an error if the device handle is invalid or GPU rendering is not supported on this device.
Note: Phase 1 implementation falls back to software rendering.
Example ¶
ExampleNewGPURenderer demonstrates creating a GPU renderer with a DeviceHandle.
In real usage, the DeviceHandle would come from the host application (e.g., gogpu.App.GPUContextProvider()). For testing without a GPU, use NullDeviceHandle.
package main
import (
"fmt"
"image/color"
"github.com/gogpu/gg/render"
)
func main() {
// Create renderer with null device (for testing without GPU)
renderer, err := render.NewGPURenderer(render.NullDeviceHandle{})
if err != nil {
fmt.Println("failed to create renderer:", err)
return
}
// Create a CPU target for software fallback rendering
target := render.NewPixmapTarget(100, 100)
// Create a scene with a red rectangle
scene := render.NewScene()
scene.Clear(color.White)
scene.SetFillColor(color.RGBA{R: 255, G: 0, B: 0, A: 255})
scene.Rectangle(10, 10, 80, 80)
scene.Fill()
// Render the scene (falls back to software in Phase 1)
if err := renderer.Render(target, scene); err != nil {
fmt.Println("render failed:", err)
return
}
fmt.Println("rendered successfully")
}
Output: rendered successfully
func (*GPURenderer) Capabilities ¶
func (r *GPURenderer) Capabilities() RendererCapabilities
Capabilities returns the renderer's capabilities.
Example ¶
ExampleGPURenderer_Capabilities demonstrates querying renderer capabilities.
package main
import (
"fmt"
"github.com/gogpu/gg/render"
)
func main() {
renderer, err := render.NewGPURenderer(render.NullDeviceHandle{})
if err != nil {
fmt.Println("failed:", err)
return
}
caps := renderer.Capabilities()
fmt.Printf("GPU renderer: %v\n", caps.IsGPU)
fmt.Printf("supports antialiasing: %v\n", caps.SupportsAntialiasing)
}
Output: GPU renderer: true supports antialiasing: true
func (*GPURenderer) CreateTextureTarget ¶
func (r *GPURenderer) CreateTextureTarget(width, height int) (*TextureTarget, error)
CreateTextureTarget creates a GPU texture render target.
Note: Phase 1 implementation returns an error. Phase 3 will implement actual texture creation.
func (*GPURenderer) DeviceHandle ¶
func (r *GPURenderer) DeviceHandle() DeviceHandle
DeviceHandle returns the underlying device handle. This allows advanced users to access the GPU device for custom rendering.
func (*GPURenderer) Flush ¶
func (r *GPURenderer) Flush() error
Flush ensures all GPU commands are submitted and complete.
This method:
- Submits any pending command buffers
- Waits for GPU completion
For CPU targets, this is a no-op.
func (*GPURenderer) Render ¶
func (r *GPURenderer) Render(target RenderTarget, scene *Scene) error
Render draws the scene to the target.
For GPU targets (TextureView != nil), rendering is performed on the GPU. For CPU targets (Pixels != nil), rendering falls back to software.
Note: Phase 1 implementation always uses software fallback.
type LayeredPixmapTarget ¶
type LayeredPixmapTarget struct {
// contains filtered or unexported fields
}
LayeredPixmapTarget is a CPU-backed implementation of LayeredTarget. It uses *image.RGBA for each layer and composites them in z-order.
func NewLayeredPixmapTarget ¶
func NewLayeredPixmapTarget(width, height int) *LayeredPixmapTarget
NewLayeredPixmapTarget creates a new layered CPU render target.
func (*LayeredPixmapTarget) Clear ¶
func (t *LayeredPixmapTarget) Clear(c color.Color)
Clear fills the base layer with the given color. Does not affect other layers.
func (*LayeredPixmapTarget) ClearLayer ¶
func (t *LayeredPixmapTarget) ClearLayer(z int, c color.Color) error
ClearLayer fills a specific layer with a color. Returns error if the layer does not exist.
func (*LayeredPixmapTarget) Composite ¶
func (t *LayeredPixmapTarget) Composite()
Composite blends all visible layers onto the base target in z-order. Layers are composited using standard alpha blending (source over).
func (*LayeredPixmapTarget) CreateLayer ¶
func (t *LayeredPixmapTarget) CreateLayer(z int) (RenderTarget, error)
CreateLayer creates a new layer at the specified z-order. Returns a RenderTarget that can be used for drawing to the layer.
func (*LayeredPixmapTarget) Format ¶
func (t *LayeredPixmapTarget) Format() gputypes.TextureFormat
Format returns the pixel format (RGBA8).
func (*LayeredPixmapTarget) GetLayer ¶
func (t *LayeredPixmapTarget) GetLayer(z int) RenderTarget
GetLayer returns the RenderTarget for a specific layer. Returns nil if the layer does not exist.
func (*LayeredPixmapTarget) Height ¶
func (t *LayeredPixmapTarget) Height() int
Height returns the target height in pixels.
func (*LayeredPixmapTarget) Image ¶
func (t *LayeredPixmapTarget) Image() *image.RGBA
Image returns the base layer image. Note: This returns the base layer, not the composited result. Call Composite() first, then Image() to get the composited image.
func (*LayeredPixmapTarget) Layers ¶
func (t *LayeredPixmapTarget) Layers() []int
Layers returns all layer z-orders in render order (ascending).
func (*LayeredPixmapTarget) Pixels ¶
func (t *LayeredPixmapTarget) Pixels() []byte
Pixels returns direct access to the base layer pixel data. Note: This returns the base layer, not the composited result. Call Composite() first to get the composited image.
func (*LayeredPixmapTarget) RemoveLayer ¶
func (t *LayeredPixmapTarget) RemoveLayer(z int) error
RemoveLayer removes a layer by z-order.
func (*LayeredPixmapTarget) SetLayerVisible ¶
func (t *LayeredPixmapTarget) SetLayerVisible(z int, visible bool)
SetLayerVisible controls layer visibility.
func (*LayeredPixmapTarget) Stride ¶
func (t *LayeredPixmapTarget) Stride() int
Stride returns the number of bytes per row.
func (*LayeredPixmapTarget) TextureView ¶
func (t *LayeredPixmapTarget) TextureView() TextureView
TextureView returns nil as this is a CPU-only target.
func (*LayeredPixmapTarget) Width ¶
func (t *LayeredPixmapTarget) Width() int
Width returns the target width in pixels.
type LayeredTarget ¶
type LayeredTarget interface {
RenderTarget
// CreateLayer creates a new layer at the specified z-order.
// Higher z values are rendered on top of lower values.
// Returns an error if a layer with the same z-order already exists.
CreateLayer(z int) (RenderTarget, error)
// RemoveLayer removes a layer by z-order.
// Returns an error if the layer does not exist.
RemoveLayer(z int) error
// SetLayerVisible controls layer visibility without removing it.
// Invisible layers are not composited but retain their content.
SetLayerVisible(z int, visible bool)
// Layers returns all layer z-orders in render order (ascending).
Layers() []int
// Composite blends all visible layers onto the base target.
// This should be called after drawing to layers is complete.
Composite()
}
LayeredTarget supports z-ordered layers for popups, dropdowns, and tooltips.
This interface extends RenderTarget with layer management capabilities. Layers are rendered in ascending z-order (lower z values behind higher ones). This is useful for UI frameworks that need to render overlays without managing separate surfaces.
type NullDeviceHandle ¶
type NullDeviceHandle struct{}
NullDeviceHandle is a DeviceHandle that provides nil implementations. Used for CPU-only rendering where no GPU is available.
Example ¶
ExampleNullDeviceHandle demonstrates the null device for testing.
package main
import (
"fmt"
"github.com/gogpu/gg/render"
)
func main() {
handle := render.NullDeviceHandle{}
// NullDeviceHandle returns nil for all GPU resources
fmt.Printf("device: %v\n", handle.Device())
fmt.Printf("queue: %v\n", handle.Queue())
fmt.Printf("adapter: %v\n", handle.Adapter())
}
Output: device: <nil> queue: <nil> adapter: <nil>
func (NullDeviceHandle) Adapter ¶
func (NullDeviceHandle) Adapter() gpucontext.Adapter
Adapter returns nil for the null device.
func (NullDeviceHandle) Device ¶
func (NullDeviceHandle) Device() gpucontext.Device
Device returns nil for the null device.
func (NullDeviceHandle) Queue ¶
func (NullDeviceHandle) Queue() gpucontext.Queue
Queue returns nil for the null device.
func (NullDeviceHandle) SurfaceFormat ¶
func (NullDeviceHandle) SurfaceFormat() gputypes.TextureFormat
SurfaceFormat returns undefined format for the null device.
type PixmapTarget ¶
type PixmapTarget struct {
// contains filtered or unexported fields
}
PixmapTarget is a CPU-backed render target using *image.RGBA.
This target supports software rendering and provides direct pixel access. It is the default target for pure CPU rendering workflows.
Example:
target := render.NewPixmapTarget(800, 600) renderer.Render(target, scene) img := target.Image()
func NewPixmapTarget ¶
func NewPixmapTarget(width, height int) *PixmapTarget
NewPixmapTarget creates a new CPU-backed render target.
Example ¶
ExampleNewPixmapTarget demonstrates creating and using a CPU render target.
package main
import (
"fmt"
"github.com/gogpu/gg/render"
)
func main() {
// Create a 400x300 pixel render target
target := render.NewPixmapTarget(400, 300)
fmt.Printf("target size: %dx%d\n", target.Width(), target.Height())
fmt.Printf("stride: %d bytes per row\n", target.Stride())
fmt.Printf("pixels: %d bytes total\n", len(target.Pixels()))
}
Output: target size: 400x300 stride: 1600 bytes per row pixels: 480000 bytes total
func NewPixmapTargetFromImage ¶
func NewPixmapTargetFromImage(img *image.RGBA) *PixmapTarget
NewPixmapTargetFromImage wraps an existing *image.RGBA as a render target. The image is used directly without copying.
func (*PixmapTarget) Clear ¶
func (t *PixmapTarget) Clear(c color.Color)
Clear fills the entire target with the given color.
Example ¶
ExamplePixmapTarget_Clear demonstrates clearing a target with a color.
package main
import (
"fmt"
"image/color"
"github.com/gogpu/gg/render"
)
func main() {
target := render.NewPixmapTarget(100, 100)
// Clear to red
target.Clear(color.RGBA{R: 255, G: 0, B: 0, A: 255})
// Check a pixel
pixel := target.GetPixel(50, 50).(color.RGBA)
fmt.Printf("pixel at (50,50): R=%d, G=%d, B=%d, A=%d\n",
pixel.R, pixel.G, pixel.B, pixel.A)
}
Output: pixel at (50,50): R=255, G=0, B=0, A=255
func (*PixmapTarget) Format ¶
func (t *PixmapTarget) Format() gputypes.TextureFormat
Format returns the pixel format (RGBA8).
func (*PixmapTarget) GetPixel ¶
func (t *PixmapTarget) GetPixel(x, y int) color.Color
GetPixel returns the color at the given coordinates.
func (*PixmapTarget) Height ¶
func (t *PixmapTarget) Height() int
Height returns the target height in pixels.
func (*PixmapTarget) Image ¶
func (t *PixmapTarget) Image() *image.RGBA
Image returns the underlying *image.RGBA. The returned image shares memory with the target.
Example ¶
ExamplePixmapTarget_Image demonstrates accessing the underlying image.
package main
import (
"fmt"
"image/color"
"github.com/gogpu/gg/render"
)
func main() {
target := render.NewPixmapTarget(100, 100)
// Render something
renderer := render.NewSoftwareRenderer()
scene := render.NewScene()
scene.Clear(color.RGBA{R: 128, G: 128, B: 128, A: 255})
_ = renderer.Render(target, scene)
// Get the image for further processing (e.g., saving to file)
img := target.Image()
bounds := img.Bounds()
fmt.Printf("image bounds: %v\n", bounds)
}
Output: image bounds: (0,0)-(100,100)
func (*PixmapTarget) Pixels ¶
func (t *PixmapTarget) Pixels() []byte
Pixels returns direct access to the pixel data.
func (*PixmapTarget) Resize ¶
func (t *PixmapTarget) Resize(width, height int)
Resize creates a new target with the given dimensions. The contents are not preserved.
func (*PixmapTarget) SetPixel ¶
func (t *PixmapTarget) SetPixel(x, y int, c color.Color)
SetPixel sets a single pixel at the given coordinates.
func (*PixmapTarget) Stride ¶
func (t *PixmapTarget) Stride() int
Stride returns the number of bytes per row.
func (*PixmapTarget) TextureView ¶
func (t *PixmapTarget) TextureView() TextureView
TextureView returns nil as this is a CPU-only target.
func (*PixmapTarget) Width ¶
func (t *PixmapTarget) Width() int
Width returns the target width in pixels.
type RenderTarget ¶
type RenderTarget interface {
// Width returns the target width in pixels.
Width() int
// Height returns the target height in pixels.
Height() int
// Format returns the pixel format of the target.
Format() gputypes.TextureFormat
// TextureView returns the GPU texture view for this target.
// Returns nil for CPU-only targets.
TextureView() TextureView
// Pixels returns direct access to pixel data.
// Returns nil for GPU-only targets.
// For RGBA format, each pixel is 4 bytes: R, G, B, A.
Pixels() []byte
// Stride returns the number of bytes per row.
// For RGBA, this is typically Width * 4, but may include padding.
Stride() int
}
RenderTarget defines where rendering output goes.
A RenderTarget is an abstraction over different rendering destinations:
- PixmapTarget: CPU-backed *image.RGBA for software rendering
- TextureTarget: GPU texture for offscreen rendering
- SurfaceTarget: Window surface from the host application
Targets may support CPU access (Pixels), GPU access (TextureView), or both. The Renderer implementation chooses the appropriate access method.
type Renderer ¶
type Renderer interface {
// Render draws the scene to the target.
//
// The scene is processed and drawn to the target in order of commands.
// Returns an error if rendering fails (e.g., incompatible target format).
//
// The scene is not modified by this operation and can be rendered
// multiple times to different targets.
Render(target RenderTarget, scene *Scene) error
// Flush ensures all pending rendering operations are complete.
//
// For CPU renderers, this is typically a no-op as operations are
// synchronous. For GPU renderers, this may submit command buffers
// and wait for completion.
//
// Returns an error if flushing fails.
Flush() error
}
Renderer executes drawing commands to a render target.
The Renderer interface is the primary abstraction for rendering backends. Different implementations provide CPU or GPU rendering:
- SoftwareRenderer: CPU-based rendering using core/ package algorithms
- GPURenderer: GPU-accelerated rendering using WebGPU (Phase 3)
Renderers are stateless between Render calls, allowing the same renderer to be used with different targets and scenes.
Thread Safety: Renderers are NOT thread-safe. Each renderer should be used from a single goroutine, or external synchronization must be used.
Example:
// Create renderer
renderer := render.NewSoftwareRenderer()
// Create target
target := render.NewPixmapTarget(800, 600)
// Render scene
if err := renderer.Render(target, scene); err != nil {
log.Printf("render failed: %v", err)
}
type RendererCapabilities ¶
type RendererCapabilities struct {
// IsGPU indicates if this is a GPU-accelerated renderer.
IsGPU bool
// SupportsAntialiasing indicates if anti-aliased rendering is supported.
SupportsAntialiasing bool
// SupportsBlendModes indicates if custom blend modes are supported.
SupportsBlendModes bool
// SupportsGradients indicates if gradient fills are supported.
SupportsGradients bool
// SupportsTextures indicates if texture sampling is supported.
SupportsTextures bool
// MaxTextureSize is the maximum texture dimension (0 = unlimited).
MaxTextureSize int
}
RendererCapabilities describes the features supported by a renderer.
type Scene ¶
type Scene struct {
// contains filtered or unexported fields
}
Scene represents a retained-mode drawing tree.
Unlike immediate-mode drawing (Context.DrawCircle, etc.), a Scene captures drawing commands that can be:
- Rendered multiple times without rebuilding
- Partially invalidated for efficient UI updates
- Optimized by the renderer for batching
Scene is designed to work with the Renderer interface, allowing both CPU and GPU rendering backends to process the same scene data.
Example:
scene := render.NewScene()
scene.SetFillColor(color.RGBA{255, 0, 0, 255})
scene.MoveTo(100, 50)
scene.LineTo(150, 150)
scene.LineTo(50, 150)
scene.ClosePath()
scene.Fill()
// Render to any target
renderer.Render(target1, scene)
renderer.Render(target2, scene)
Example ¶
ExampleScene demonstrates building a scene with various drawing commands.
package main
import (
"fmt"
"image/color"
"github.com/gogpu/gg/render"
)
func main() {
scene := render.NewScene()
// Clear background
scene.Clear(color.White)
// Draw a red triangle
scene.SetFillColor(color.RGBA{R: 255, G: 0, B: 0, A: 255})
scene.MoveTo(100, 50)
scene.LineTo(150, 150)
scene.LineTo(50, 150)
scene.ClosePath()
scene.Fill()
// Draw a blue circle
scene.SetFillColor(color.RGBA{R: 0, G: 0, B: 255, A: 255})
scene.Circle(100, 100, 30)
scene.Fill()
// Draw a green rectangle outline
scene.SetStrokeColor(color.RGBA{R: 0, G: 255, B: 0, A: 255})
scene.SetStrokeWidth(2.0)
scene.Rectangle(20, 20, 60, 40)
scene.Stroke()
fmt.Printf("scene has %d commands\n", scene.CommandCount())
}
Output: scene has 4 commands
Example (Damage) ¶
ExampleScene_damage demonstrates damage tracking for efficient redraws.
package main
import (
"fmt"
"github.com/gogpu/gg/render"
)
func main() {
scene := render.NewScene()
// Initially no dirty regions
fmt.Printf("has dirty: %v\n", scene.HasDirtyRegions())
// Invalidate a region
scene.Invalidate(render.DirtyRect{X: 10, Y: 10, Width: 100, Height: 50})
fmt.Printf("has dirty: %v\n", scene.HasDirtyRegions())
fmt.Printf("dirty rects: %d\n", len(scene.DirtyRects()))
// Clear dirty state after rendering
scene.ClearDirty()
fmt.Printf("has dirty after clear: %v\n", scene.HasDirtyRegions())
}
Output: has dirty: false has dirty: true dirty rects: 1 has dirty after clear: false
func (*Scene) ClearDirty ¶
func (s *Scene) ClearDirty()
ClearDirty resets the dirty state after rendering. This should be called after each render pass.
func (*Scene) CommandCount ¶
CommandCount returns the number of drawing commands in the scene.
func (*Scene) DirtyRects ¶
DirtyRects returns the accumulated dirty rectangles. Returns nil if the scene needs a full redraw (check NeedsFullRedraw first). The returned slice should not be modified by the caller.
func (*Scene) HasDirtyRegions ¶
HasDirtyRegions returns true if there are any dirty regions to redraw. This includes both individual rects and full redraw state.
func (*Scene) Invalidate ¶
Invalidate marks a rectangular region as needing redraw. This is used for damage tracking to enable efficient partial redraws. If the accumulated dirty rects exceed maxDirtyRects, the scene switches to full redraw mode for efficiency.
func (*Scene) InvalidateAll ¶
func (s *Scene) InvalidateAll()
InvalidateAll marks the entire scene as needing redraw. This forces a full redraw on the next render pass.
func (*Scene) NeedsFullRedraw ¶
NeedsFullRedraw returns true if the scene should be fully redrawn. This is true when InvalidateAll was called or when too many dirty rects have accumulated (more than maxDirtyRects).
func (*Scene) SetFillColor ¶
SetFillColor sets the color for subsequent fill operations.
func (*Scene) SetFillRule ¶
SetFillRule sets the fill rule for subsequent fill operations.
func (*Scene) SetStrokeColor ¶
SetStrokeColor sets the color for subsequent stroke operations.
func (*Scene) SetStrokeWidth ¶
SetStrokeWidth sets the width for subsequent stroke operations.
type SoftwareRenderer ¶
type SoftwareRenderer struct {
// contains filtered or unexported fields
}
SoftwareRenderer is a CPU-based renderer using the core/ package algorithms.
This renderer provides anti-aliased 2D rendering without any GPU dependencies. It uses AnalyticFiller for high-quality coverage-based anti-aliasing.
Performance characteristics:
- Single-threaded (future: parallel scanline processing)
- O(n) where n is the number of pixels covered
- Memory: O(width) for scanline buffers
Example:
renderer := render.NewSoftwareRenderer()
target := render.NewPixmapTarget(800, 600)
scene := render.NewScene()
scene.SetFillColor(color.RGBA{255, 0, 0, 255})
scene.Circle(400, 300, 100)
scene.Fill()
renderer.Render(target, scene)
img := target.Image()
func NewSoftwareRenderer ¶
func NewSoftwareRenderer() *SoftwareRenderer
NewSoftwareRenderer creates a new CPU-based software renderer.
Example ¶
ExampleNewSoftwareRenderer demonstrates CPU-based software rendering.
package main
import (
"fmt"
"image/color"
"github.com/gogpu/gg/render"
)
func main() {
// Create software renderer (no GPU required)
renderer := render.NewSoftwareRenderer()
// Create a CPU-backed render target
target := render.NewPixmapTarget(200, 200)
// Build a scene
scene := render.NewScene()
scene.Clear(color.White)
scene.SetFillColor(color.RGBA{R: 0, G: 0, B: 255, A: 255})
scene.Circle(100, 100, 50)
scene.Fill()
// Render the scene
if err := renderer.Render(target, scene); err != nil {
fmt.Println("render failed:", err)
return
}
// Access the rendered image
img := target.Image()
fmt.Printf("rendered %dx%d image\n", img.Bounds().Dx(), img.Bounds().Dy())
}
Output: rendered 200x200 image
func (*SoftwareRenderer) Capabilities ¶
func (r *SoftwareRenderer) Capabilities() RendererCapabilities
Capabilities returns the renderer's capabilities.
Example ¶
ExampleSoftwareRenderer_Capabilities demonstrates querying software renderer capabilities.
package main
import (
"fmt"
"github.com/gogpu/gg/render"
)
func main() {
renderer := render.NewSoftwareRenderer()
caps := renderer.Capabilities()
fmt.Printf("GPU renderer: %v\n", caps.IsGPU)
fmt.Printf("supports antialiasing: %v\n", caps.SupportsAntialiasing)
}
Output: GPU renderer: false supports antialiasing: true
func (*SoftwareRenderer) Flush ¶
func (r *SoftwareRenderer) Flush() error
Flush ensures all rendering is complete. For the software renderer, this is a no-op as operations are synchronous.
func (*SoftwareRenderer) Render ¶
func (r *SoftwareRenderer) Render(target RenderTarget, scene *Scene) error
Render draws the scene to the target.
This method processes each drawing command in the scene and renders it to the target using CPU-based rasterization.
Returns an error if the target is GPU-only (no Pixels() support).
type SurfaceTarget ¶
type SurfaceTarget struct {
// contains filtered or unexported fields
}
SurfaceTarget wraps a window surface from the host application.
This target allows gg to render directly to a window surface provided by gogpu or another host framework. This enables zero-copy rendering where gg draws directly to the display surface.
Note: Full implementation requires GPU backend support (Phase 3).
func NewSurfaceTarget ¶
func NewSurfaceTarget(width, height int, format gputypes.TextureFormat, view TextureView) *SurfaceTarget
NewSurfaceTarget creates a render target from a window surface.
Note: This is a stub. Full implementation in Phase 3 will accept a Surface interface from the host application.
func (*SurfaceTarget) Format ¶
func (t *SurfaceTarget) Format() gputypes.TextureFormat
Format returns the surface pixel format.
func (*SurfaceTarget) Height ¶
func (t *SurfaceTarget) Height() int
Height returns the surface height in pixels.
func (*SurfaceTarget) Pixels ¶
func (t *SurfaceTarget) Pixels() []byte
Pixels returns nil as surfaces do not support CPU access.
func (*SurfaceTarget) Stride ¶
func (t *SurfaceTarget) Stride() int
Stride returns 0 as surfaces do not support CPU access.
func (*SurfaceTarget) TextureView ¶
func (t *SurfaceTarget) TextureView() TextureView
TextureView returns the current frame's texture view.
func (*SurfaceTarget) Width ¶
func (t *SurfaceTarget) Width() int
Width returns the surface width in pixels.
type Texture ¶
type Texture interface {
// Width returns the texture width in pixels.
Width() uint32
// Height returns the texture height in pixels.
Height() uint32
// Format returns the texture pixel format.
Format() gputypes.TextureFormat
// CreateView creates a view for this texture.
CreateView() TextureView
// Destroy releases GPU resources associated with this texture.
Destroy()
}
Texture represents a GPU texture resource. This interface wraps the underlying WebGPU texture.
type TextureDescriptor ¶
type TextureDescriptor struct {
// Label is an optional debug label for the texture.
Label string
// Width is the texture width in pixels.
Width uint32
// Height is the texture height in pixels.
Height uint32
// Depth is the texture depth for 3D textures, or array layer count.
// Use 1 for regular 2D textures.
Depth uint32
// MipLevelCount is the number of mipmap levels.
// Use 1 for no mipmaps.
MipLevelCount uint32
// SampleCount is the number of samples for multisampling.
// Use 1 for no multisampling.
SampleCount uint32
// Format is the texture pixel format.
Format gputypes.TextureFormat
// Usage specifies how the texture will be used.
Usage TextureUsage
}
TextureDescriptor describes parameters for creating a texture. This mirrors the WebGPU GPUTextureDescriptor specification.
func DefaultTextureDescriptor ¶
func DefaultTextureDescriptor(width, height uint32, format gputypes.TextureFormat) TextureDescriptor
DefaultTextureDescriptor returns a TextureDescriptor with sensible defaults. Only Width, Height, and Format need to be set.
type TextureTarget ¶
type TextureTarget struct {
// contains filtered or unexported fields
}
TextureTarget is a GPU texture-backed render target.
This target wraps a GPU texture and allows rendering to offscreen surfaces for post-processing, texture caching, or multi-pass rendering.
Note: Full implementation requires GPU backend support (Phase 3).
func NewTextureTarget ¶
func NewTextureTarget(handle DeviceHandle, width, height int, format gputypes.TextureFormat) (*TextureTarget, error)
NewTextureTarget creates a new GPU texture render target. Requires a DeviceHandle to create the texture.
Note: This is a stub. Full implementation in Phase 3.
func (*TextureTarget) Format ¶
func (t *TextureTarget) Format() gputypes.TextureFormat
Format returns the pixel format.
func (*TextureTarget) Height ¶
func (t *TextureTarget) Height() int
Height returns the target height in pixels.
func (*TextureTarget) Pixels ¶
func (t *TextureTarget) Pixels() []byte
Pixels returns nil as this is a GPU-only target. Use ReadPixels for GPU readback (expensive).
func (*TextureTarget) Stride ¶
func (t *TextureTarget) Stride() int
Stride returns 0 as this is a GPU-only target.
func (*TextureTarget) TextureView ¶
func (t *TextureTarget) TextureView() TextureView
TextureView returns the GPU texture view.
func (*TextureTarget) Width ¶
func (t *TextureTarget) Width() int
Width returns the target width in pixels.
type TextureUsage ¶
type TextureUsage uint32
TextureUsage specifies how a texture can be used. These flags can be combined with bitwise OR.
const ( // TextureUsageCopySrc allows the texture to be used as a copy source. TextureUsageCopySrc TextureUsage = 1 << iota // TextureUsageCopyDst allows the texture to be used as a copy destination. TextureUsageCopyDst // TextureUsageTextureBinding allows the texture to be used in a texture binding. TextureUsageTextureBinding // TextureUsageStorageBinding allows the texture to be used in a storage binding. TextureUsageStorageBinding // TextureUsageRenderAttachment allows the texture to be used as a render attachment. TextureUsageRenderAttachment )
type TextureView ¶
type TextureView interface {
// Destroy releases resources associated with this view.
Destroy()
}
TextureView represents a view into a texture. Views are used to bind textures to shader stages.