gfx

    Backend-agnostic GPU command buffer and driver contracts (extracted from kagura)

    Download zip
    Author
    Version
    0.1.1
    License
    Apache-2.0
    Last updated
    8 days ago
    Downloads
    10K

    #mizchi/gfx

    Backend-agnostic GPU command-buffer and driver contracts for MoonBit.

    Extracted from mizchi/kagura so other MoonBit projects can reuse the rendering primitives without pulling in the whole game engine.

    #At a glance

    ┌─────────────────────────────────────────────────────────┐ │ your renderer │ │ builds DrawTrianglesCommand values │ └────────────────┬────────────────────────────────────────┘ │ enqueue_draw_triangles ┌────────────────▼────────────────────────────────────────┐ │ CommandQueue (SimpleCommandQueue or your own) │ │ merges adjacent compatible draws │ └────────────────┬────────────────────────────────────────┘ │ flush_commands ┌────────────────▼────────────────────────────────────────┐ │ GraphicsDriver (your backend impl) │ │ WebGPU / wgpu-native / WebGL2 / offscreen / null │ └─────────────────────────────────────────────────────────┘

    Renderers build DrawTrianglesCommands; a CommandQueue collects and optionally merges them; flush_commands drives a GraphicsDriver through one render pass. The driver is the only piece that talks to a real GPU API; the rest is plain data.

    #Minimum working example

    This uses the bundled StubGraphicsDriver (the null backend) so it can run anywhere moon test runs.

    test "draw two triangles into a null driver" {
    // 1. Pick a driver. `create_null_graphics` returns a StubGraphicsDriver
    // that counts begin/end/draw calls but doesn't talk to a GPU.
    let driver = @gfx.create_null_graphics(640, 480)
    driver.initialize()

    // 2. Allocate a render target image and a shader from the driver.
    let dst = driver.new_image(640, 480)
    let shader = driver.new_shader("// dummy WGSL")

    // 3. Build a draw command. Layout is type-erased: vertex_data is a
    // flat Array[Double], indices are Array[Int].
    let region = @gfx.new_dst_region(0, 0, 640, 480, 6)
    let command = @gfx.new_draw_triangles_command(
    dst,
    shader,
    [region],
    0,
    1, // pipeline_id (opaque)
    0, // uniform_hash
    @gfx.BlendMode::Alpha,
    [
    0.0, 0.0, 0.0, 0.0,
    1.0, 0.0, 1.0, 0.0,
    0.0, 1.0, 0.0, 1.0,
    1.0, 1.0, 1.0, 1.0,
    ],
    [0, 1, 2, 1, 3, 2],
    [], // no source textures
    [], // no uniforms
    )

    // 4. Inspect the command summary (useful for batching / debug).
    let dispatch = command.build_dispatch()
    let _ = dispatch.checksum() // stable Int fingerprint

    // 5. Enqueue and flush through the driver. Two identical commands
    // will be merged by SimpleCommandQueue into one backend draw.
    let queue = @gfx.new_simple_command_queue()
    queue.enqueue_draw_triangles(command)
    queue.enqueue_draw_triangles(command)
    @gfx.flush_commands(driver, queue, false)
    }

    Take the same command, swap the driver for a WebGPU or wgpu-native impl, and nothing else changes.

    The conversion helpers are also exposed as methods on each type: BlendMode::Alpha.to_int(), BlendMode::from_int(1), command.build_dispatch(), dispatch.checksum(), result.diff_ratio(), request.validate(), etc.

    #Implementing a backend

    A new backend impls GraphicsDriver and (if the host wants to negotiate backends at runtime) GraphicsBackendFactory:

    struct MyDriver { /* device, queue, swapchain, ... */ }

    impl @gfx.GraphicsDriver for MyDriver with initialize(self) {
    // bind a device / swapchain
    }

    impl @gfx.GraphicsDriver for MyDriver with begin(self, pass) {
    // open a render pass; `pass.clear_color` / `pass.clear_enabled`
    }

    impl @gfx.GraphicsDriver for MyDriver with end(self, present) {
    // close the pass; swap buffers if `present`
    }

    impl @gfx.GraphicsDriver for MyDriver with resize(self, w, h) { ... }
    impl @gfx.GraphicsDriver for MyDriver with new_image(self, w, h) {
    // allocate a texture and return a handle that wraps your backend id
    @gfx.new_image_handle(/* backend id */ 1, w, h)
    }
    impl @gfx.GraphicsDriver for MyDriver with new_shader(self, src) { ... }
    impl @gfx.GraphicsDriver for MyDriver with draw_triangles(self, cmd) {
    // upload cmd.vertex_data / cmd.indices (or reuse a cached payload
    // when cmd.resource_cache_key != 0) and issue one draw call per
    // cmd.dst_regions entry, respecting cmd.blend, cmd.uniform_dwords, ...
    }
    impl @gfx.GraphicsDriver for MyDriver with read_pixels(self, x, y, w, h) {
    // None if not supported; otherwise an RGBA8 Array[Int]
    }

    For host shells that want to defer backend choice, also impl GraphicsBackendFactory.create(kind, surface, options) to switch on GraphicsBackendKind.

    #What's in here

    The package exposes a layered surface that any WebGPU / wgpu-native / offscreen backend can implement:

    • Command buffer — DrawTrianglesCommand, DrawCommandDispatch, DstRegion, Color, RenderPassDesc, dispatch_checksum, build_draw_command_dispatch.
    • Handles — ImageHandle, ShaderHandle, PipelineHandle, FilterMode.
    • Blend state — BlendFactor, BlendOperation, BlendEquation, BlendMode, plus blend_mode_to_equation, blend_mode_to_int, etc.
    • Driver trait — GraphicsDriver (initialize / begin / end / resize / new_image / new_shader / draw_triangles / read_pixels) and a FramebufferSnapshot / PixelDiffResult harness for VRT.
    • Command queue — CommandQueue trait and SimpleCommandQueue (reference impl with adjacent-batch merging under a 16k-float vertex budget) plus flush_commands / clear_screen.
    • Backend registry — StubGraphicsDriver, create_{webgpu,webgl,wgpu_native,null}_graphics, NativeGraphicsHooks, WebGraphicsHooks, GraphicsBackendFactory, GraphicsBackendKind, GraphicsBackendOptions.
    • Shader plumbing — ShaderFrontend, UniformCanonicalizer, BuiltinShaderSourceRepo traits with BasicShaderFrontend, BasicUniformCanonicalizer, BasicBuiltinShaderSourceRepo reference implementations. UniformLayout, NamedUniform, UniformValue, PackedUniforms, PreservedUniformContext, plus validation helpers and double_to_f32_bits.
    • Builtin shader keys — BuiltinShaderKey, BuiltinShaderKeyEx, BuiltinShaderFilter, BuiltinShaderAddress, SamplerSpec.
    • Surface descriptor — SurfaceKind, SurfaceToken, SurfaceProvider trait, create_offscreen_surface_token / create_webgpu_surface_token / create_webgl_surface_token.

    Nothing here knows about games, scenes, ECS, assets, or platform shells; those layers live elsewhere (in kagura, in your engine, ...).

    #API tiers

    TierMeaningExamples
    Stable input (pub(all) struct/enum)You build these as struct literalsColor, DrawTrianglesCommand, DstRegion, RenderPassDesc, blend / filter / uniform enums, ShaderCompileRequest, BuiltinShaderKey, ...
    Stable output (pub struct)gfx hands these to you; read-only fields, no struct-literal constructionStubGraphicsDriver, Basic{ShaderFrontend,UniformCanonicalizer,BuiltinShaderSourceRepo}, BuiltinShaderCacheStats, GraphicsResizeStats, FramebufferSnapshot, PixelDiffResult, SimpleCommandQueue, {Native,Web}GraphicsHooks
    Backend-return (pub(all) struct)You build these only from inside a trait impl that returns themImageHandle, ShaderHandle, PipelineHandle, ShaderIR, ShaderSourceHash, PackedUniforms, SurfaceToken
    Open trait (pub(open) trait)You implement these in your backend / canonicalizer / etc.GraphicsDriver, CommandQueue, ShaderFrontend, UniformCanonicalizer, BuiltinShaderSourceRepo, SurfaceProvider, GraphicsBackendFactory

    For factory-only types there is always a constructor: new_basic_*, new_*_graphics_hooks{,_full}, create_{webgpu,webgl,wgpu_native,null}_graphics, new_simple_command_queue, etc.

    #Layout

    src/ handle.mbt ImageHandle / ShaderHandle / PipelineHandle / FilterMode blend.mbt BlendFactor / Operation / Equation / Mode + conversions contracts.mbt DstRegion / Color / RenderPassDesc / DrawTrianglesCommand / DrawCommandDispatch / dispatch_checksum driver.mbt GraphicsDriver trait + FramebufferSnapshot / PixelDiffResult queue.mbt CommandQueue trait + SimpleCommandQueue + merge logic surface.mbt SurfaceKind / SurfaceToken / SurfaceProvider + factories backend_contracts.mbt StubGraphicsDriver / GraphicsBackendKind / hooks registry backend_native_hooks_stub.mbt backend_web_hooks_stub.mbt shader_contracts.mbt ShaderIR / ShaderFrontend / Uniform plumbing

    #Status

    • API is unstable while the kagura migration settles. Until a 1.0 line ships, treat the surface as if it could break between any two 0.x.y versions.
    • Tests: 109 whitebox tests covering the command-buffer types, queue merge logic, shader IR / uniform packing, and the null driver. Run moon test --target js.
    • Targets: js is the primary target; native works for the contract types (the only target-specific pieces are downstream backend impls).

    #Using it locally

    moon.mod.json:

    { "deps": { "mizchi/gfx": { "path": "../gfx-mbt" } } }

    moon.pkg:

    import { "mizchi/gfx" @gfx }

    #License

    Apache-2.0. Inherited from kagura.

    BuiltinShaderSourceRepo

    pub(open) trait BuiltinShaderSourceRepo {
    fn shader_source(Self, key : BuiltinShaderKey) -> String
    fn shader_source_ex(Self, key : BuiltinShaderKeyEx) -> String
    }

    Source of WGSL / shader code for built-in shaders keyed by filter + address mode (and optionally a color matrix).

    BasicBuiltinShaderSourceRepo is the reference implementation; it caches generated WGSL by key.

    CommandQueue

    pub(open) trait CommandQueue {
    fn enqueue_draw_triangles(Self, command : DrawTrianglesCommand) -> Unit
    fn flush(Self) -> Array[DrawTrianglesCommand]
    }

    A renderer-facing buffer of pending DrawTrianglesCommands.

    Renderers enqueue_draw_triangles during their draw pass and the frame driver later calls flush to consume them. The flush phase is where an implementation may merge adjacent compatible commands (same pipeline / shader / blend / images / uniforms) to reduce the number of backend draw calls.

    SimpleCommandQueue is the reference implementation; bring your own if you need a different merge policy.

    GraphicsBackendFactory

    pub(open) trait GraphicsBackendFactory {
    fn create(Self, kind : GraphicsBackendKind, surface : SurfaceToken, options : GraphicsBackendOptions) -> Unit raise
    }

    A factory that constructs a backend driver for a given kind / surface / options triple. Useful when a host wants to defer the choice of (wgpu-native vs WebGPU vs WebGL2 vs Null) until runtime feature detection.

    GraphicsDriver

    pub(open) trait GraphicsDriver {
    fn initialize(Self) -> Unit raise
    fn begin(Self, pass : RenderPassDesc) -> Unit raise
    fn end(Self, present : Bool) -> Unit raise
    fn resize(Self, width : Int, height : Int) -> Unit raise
    fn new_image(Self, width : Int, height : Int) -> ImageHandle raise
    fn new_shader(Self, source : String) -> ShaderHandle raise
    fn draw_triangles(Self, command : DrawTrianglesCommand) -> Unit raise
    fn read_pixels(Self, x : Int, y : Int, width : Int, height : Int) -> Array[Int]? raise
    }

    The contract a graphics backend implements to render a frame.

    One driver instance owns the device, the swapchain / surface, and the per-frame command lifecycle. Renderers talk to a driver through this trait and never reach for backend-specific APIs.

    A typical frame:

    driver.begin(pass) for command in commands { driver.draw_triangles(command) } driver.end(present)

    More commonly, drive it from a CommandQueue via flush_commands.

    Implementors should be idempotent on initialize and should de-duplicate identical resize calls.

    ShaderFrontend

    pub(open) trait ShaderFrontend {
    fn compile_ir(Self, request : ShaderCompileRequest) -> ShaderIR raise
    fn calc_source_hash(Self, request : ShaderCompileRequest) -> ShaderSourceHash raise
    }

    Frontend for shader sources: lowers a ShaderCompileRequest into a ShaderIR and computes a stable hash. The hash is used to dedupe builtin shader variants in the backend cache.

    BasicShaderFrontend is the reference implementation.

    SurfaceProvider

    pub(open) trait SurfaceProvider {
    fn current_surface(Self) -> SurfaceToken raise
    }

    A host platform that can hand a backend the GPU surface to render onto (a canvas context, a CAMetalLayer, an offscreen buffer ...).

    Kagura's platform package implements this for DesktopGlfwPlatform and WebCanvasPlatform; other hosts implement it themselves or use the create_*_surface_token helpers below for static cases.

    UniformCanonicalizer

    pub(open) trait UniformCanonicalizer {
    fn append_user_uniforms(Self, layout : UniformLayout, uniforms : Array[NamedUniform]) -> PackedUniforms raise
    fn prepend_preserved_uniforms(Self, uniforms : PackedUniforms, context : PreservedUniformContext) -> PackedUniforms
    fn filter_unused_uniforms(Self, ir : ShaderIR, layout : UniformLayout, uniforms : PackedUniforms) -> PackedUniforms
    }

    Packs user-visible uniforms (NamedUniforms) into the dense dword buffer the backend actually uploads, and prepends the engine-defined "preserved" prefix (destination size, source regions, etc.).

    BasicUniformCanonicalizer is the reference implementation.

    BasicBuiltinShaderSourceRepo

    pub struct BasicBuiltinShaderSourceRepo {
    cache : Array[BuiltinShaderSourceCacheEntry]
    cache_ex : Array[BuiltinShaderSourceCacheEntryEx]
    tick : Int
    max_cache_entries : Int
    hit_count : Int
    miss_count : Int
    } derive(
    Debug
    )

    BasicBuiltinShaderSourceRepo::cache_limit

    BasicBuiltinShaderSourceRepo::cache_size

    BasicBuiltinShaderSourceRepo::cache_stats

    BasicBuiltinShaderSourceRepo::clear_cache

    BasicShaderFrontend

    pub struct BasicShaderFrontend {
    } derive(
    Debug
    )

    BasicUniformCanonicalizer

    pub struct BasicUniformCanonicalizer {
    } derive(
    Debug
    )

    BlendEquation

    pub(all) struct BlendEquation {
    src_factor_rgb : BlendFactor
    dst_factor_rgb : BlendFactor
    op_rgb : BlendOperation
    src_factor_alpha : BlendFactor
    dst_factor_alpha : BlendFactor
    op_alpha : BlendOperation
    } derive(
    Debug
    )

    Custom blend equation with separate RGB and Alpha channels.

    BlendFactor

    pub(all) enum BlendFactor {
    Zero
    One
    SrcAlpha
    OneMinusSrcAlpha
    DstAlpha
    OneMinusDstAlpha
    SrcColor
    OneMinusSrcColor
    DstColor
    OneMinusDstColor
    } derive(
    Debug
    )

    Blend factor for custom blend equations.
    impl Show for BlendFactor

    BlendFactor::from_int

    fn BlendFactor::from_int(value : Int) -> BlendFactor

    BlendFactor::to_int

    fn BlendFactor::to_int(self : BlendFactor) -> Int

    BlendMode

    pub(all) enum BlendMode {
    Copy
    Alpha
    Add
    Multiply
    Custom(BlendEquation)
    } derive(
    Debug
    )

    impl Show for BlendMode

    BlendMode::from_int

    fn BlendMode::from_int(value : Int) -> BlendMode

    BlendMode::to_equation

    fn BlendMode::to_equation(self : BlendMode) -> BlendEquation

    Get the blend equation for any BlendMode including presets.

    BlendMode::to_int

    fn BlendMode::to_int(self : BlendMode) -> Int

    BlendOperation

    pub(all) enum BlendOperation {
    Add
    Subtract
    ReverseSubtract
    Min
    Max
    } derive(
    Debug
    )

    Blend operation for custom blend equations.

    BlendOperation::from_int

    fn BlendOperation::from_int(value : Int) -> BlendOperation

    BlendOperation::to_int

    fn BlendOperation::to_int(self : BlendOperation) -> Int

    BuiltinShaderAddress

    pub(all) enum BuiltinShaderAddress {
    Unsafe
    ClampToZero
    ClampToEdge
    Repeat
    MirrorRepeat
    } derive(
    Debug
    )

    BuiltinShaderAddress::from_int

    fn BuiltinShaderAddress::from_int(value : Int) -> BuiltinShaderAddress

    BuiltinShaderAddress::to_int

    fn BuiltinShaderAddress::to_int(self : BuiltinShaderAddress) -> Int

    BuiltinShaderCacheStats

    pub struct BuiltinShaderCacheStats {
    hit_count : Int
    miss_count : Int
    } derive(
    Debug
    )

    BuiltinShaderFilter

    pub(all) enum BuiltinShaderFilter {
    Nearest
    Linear
    Pixelated
    } derive(
    Debug
    )

    BuiltinShaderFilter::from_int

    fn BuiltinShaderFilter::from_int(value : Int) -> BuiltinShaderFilter

    BuiltinShaderFilter::to_int

    fn BuiltinShaderFilter::to_int(self : BuiltinShaderFilter) -> Int

    BuiltinShaderKey

    pub(all) struct BuiltinShaderKey {
    filter : BuiltinShaderFilter
    address : BuiltinShaderAddress
    use_color_m : Bool
    } derive(
    Debug
    )

    BuiltinShaderKey::to_ex

    Convert a classic BuiltinShaderKey to extended form.

    BuiltinShaderKeyEx

    pub(all) struct BuiltinShaderKeyEx {
    sampler : SamplerSpec
    use_color_m : Bool
    } derive(
    Debug
    )

    Extended shader key that supports per-axis address modes.

    BuiltinShaderSourceCacheEntry

    type BuiltinShaderSourceCacheEntry derive(
    Debug
    )

    BuiltinShaderSourceCacheEntryEx

    type BuiltinShaderSourceCacheEntryEx derive(
    Debug
    )

    Color

    pub(all) struct Color {
    r : Double
    g : Double
    b : Double
    a : Double
    } derive(
    Debug
    )

    RGBA color with channels in [0.0, 1.0] (linear, premultiplied is left to the shader). Values outside the range are not clamped here.
    impl Show for Color

    DrawCommandDispatch

    pub(all) struct DrawCommandDispatch {
    draw_calls : Int
    pipeline_id : Int
    uniform_hash : Int
    blend_mode : Int
    dst_image_id : Int
    shader_id : Int
    index_offset : Int
    region_count : Int
    total_index_count : Int
    vertex_float_count : Int
    index_count : Int
    src_image_count : Int
    uniform_dword_count : Int
    } derive(
    Debug
    )

    DrawCommandDispatch::checksum

    fn DrawCommandDispatch::checksum(self : DrawCommandDispatch) -> Int

    Sum of every Int field of a DrawCommandDispatch. Cheap, branch-free fingerprint useful in benches and tests where the caller just needs a b.keep-able value derived from the whole dispatch (it is not a cryptographic hash and is not collision-free).

    DrawTrianglesCommand

    pub(all) struct DrawTrianglesCommand {
    dst : ImageHandle
    shader : ShaderHandle
    dst_regions : Array[DstRegion]
    index_offset : Int
    pipeline_id : Int
    uniform_hash : Int
    blend : BlendMode
    vertex_data : Array[Double]
    indices : Array[Int]
    src_image_ids : Array[Int]
    uniform_dwords : Array[Int]
    instance_count : Int
    resource_cache_key : Int
    vertex_stride_hint : Int
    } derive(
    Debug
    )

    One indexed-triangle draw issued against a render target.

    This is the unit of work both the CommandQueue and the GraphicsDriver traffic in. Two adjacent commands with the same dst / shader / pipeline_id / uniform_hash / blend / src_image_ids / uniform_dwords and equal index_offset can be merged into one larger draw by the queue.

    Vertex / index data is type-erased into flat arrays so the command stays backend-neutral; the shader interprets vertex_data according to its declared input layout. vertex_stride_hint is a hint to the backend pipeline picker (0 = auto, 4 = 2D, 8 = 3D, 16 = skinned).

    DrawTrianglesCommand::build_dispatch

    Build the DrawCommandDispatch summary the backend / queue use for fingerprinting and merge decisions.

    DrawTrianglesCommand::estimated_draw_call_count

    fn DrawTrianglesCommand::estimated_draw_call_count(self : DrawTrianglesCommand) -> Int

    DrawTrianglesCommand::estimated_total_index_count

    fn DrawTrianglesCommand::estimated_total_index_count(self : DrawTrianglesCommand) -> Int

    DstRegion

    pub(all) struct DstRegion {
    x : Int
    y : Int
    width : Int
    height : Int
    index_count : Int
    } derive(
    Debug
    )

    One destination scissor rectangle on the target image, plus the number of indices the caller intends to consume inside it. A command can have several DstRegions when batching independent scissors that share state.
    impl Show for DstRegion

    FilterMode

    pub(all) enum FilterMode {
    Nearest
    Linear
    Pixelated
    } derive(
    Debug
    )

    Sampling mode for an image. Pixelated is a stricter form of Nearest used for low-res 2D art that must stay sharp at upscale.
    impl Show for FilterMode

    FilterMode::from_int

    fn FilterMode::from_int(value : Int) -> FilterMode

    FilterMode::to_int

    fn FilterMode::to_int(self : FilterMode) -> Int

    FloatRect

    pub(all) struct FloatRect {
    x : Double
    y : Double
    width : Double
    height : Double
    } derive(
    Debug
    )

    impl Show for FloatRect

    FramebufferSnapshot

    pub struct FramebufferSnapshot {
    x : Int
    y : Int
    width : Int
    height : Int
    pixels : Array[Int]
    } derive(
    Debug
    )

    FramebufferSnapshot::compare_with

    fn FramebufferSnapshot::compare_with(self : FramebufferSnapshot, other : FramebufferSnapshot, threshold : Int) -> PixelDiffResult

    Per-channel diff against another snapshot. Any channel whose absolute difference exceeds threshold counts the pixel as changed; mismatched dimensions report all pixels as different.

    FramebufferSnapshot::from_pixels

    fn FramebufferSnapshot::from_pixels(x : Int, y : Int, width : Int, height : Int, pixels : Array[Int]) -> FramebufferSnapshot

    Wrap an already-captured RGBA8 pixel buffer into a snapshot. Useful when the pixels come from a non-GraphicsDriver source (golden fixtures on disk, a manual PNG decode, ...). The buffer must be width * height * 4 bytes; this is not checked here.

    GraphicsBackendKind

    pub(all) enum GraphicsBackendKind {
    WgpuNative
    WebGpu
    WebGl2
    Null
    } derive(
    Debug
    )

    GraphicsBackendOptions

    pub(all) struct GraphicsBackendOptions {
    enable_validation : Bool
    prefer_low_power : Bool
    enable_vsync : Bool
    } derive(
    Debug
    )

    GraphicsResizeStats

    pub struct GraphicsResizeStats {
    resize_count : Int
    suppressed_count : Int
    current_width : Int
    current_height : Int
    last_resize_duration_ms : Double
    total_resize_duration_ms : Double
    } derive(
    Debug
    )

    ImageHandle

    pub(all) struct ImageHandle {
    id : Int
    width : Int
    height : Int
    } derive(
    Debug
    )

    Backend-defined image identifier plus a cached size for cheap CPU-side width/height queries. Constructed by GraphicsDriver.new_image (or new_image_handle when bridging from a non-MoonBit allocator).
    impl Show for ImageHandle

    IntSize

    pub(all) struct IntSize {
    width : Int
    height : Int
    } derive(
    Debug
    )

    impl Show for IntSize

    NamedUniform

    pub(all) struct NamedUniform {
    name : String
    value : UniformValue
    } derive(
    Debug
    )

    NativeGraphicsHooks

    pub struct NativeGraphicsHooks {
    try_initialize : (Int, Int) -> Bool
    on_begin : (Bool, RenderPassDesc) -> Unit
    on_end : (Bool, Bool) -> Unit
    on_draw : (Bool, DrawTrianglesCommand) -> Unit
    on_resize : (Bool, Int, Int) -> Unit
    on_read_pixels : (Bool, Int, Int, Int, Int) -> Array[Int]?
    on_new_image : (Bool, Int, Int, Int) -> Unit
    }

    PackedUniforms

    pub(all) struct PackedUniforms {
    dwords : Array[Int]
    } derive(
    Debug
    )

    PipelineHandle

    pub(all) struct PipelineHandle {
    id : Int
    } derive(
    Debug
    )

    Backend-defined pipeline state identifier. Pipelines are hashed by DrawTrianglesCommand.pipeline_id so two commands hashing to the same pipeline can share a draw call.

    PixelDiffResult

    pub struct PixelDiffResult {
    total_pixels : Int
    diff_pixels : Int
    max_channel_diff : Int
    } derive(
    Debug
    )

    PixelDiffResult::diff_ratio

    fn PixelDiffResult::diff_ratio(self : PixelDiffResult) -> Double

    Fraction of pixels that exceeded the diff threshold, in [0.0, 1.0].

    PreservedUniformContext

    pub(all) struct PreservedUniformContext {
    dst_texture_size : IntSize
    dst_region : FloatRect
    src_texture_sizes : Array[IntSize]
    src_regions : Array[FloatRect]
    } derive(
    Debug
    )

    PreservedUniformContext::expected_dwords

    fn PreservedUniformContext::expected_dwords(self : PreservedUniformContext) -> Int

    Number of dwords the preserved prefix should occupy for this context. Ebiten layout: dst_size(2) + dst_region(4) + per_src(size(2) + region(4)).

    PreservedUniformContext::validate

    fn PreservedUniformContext::validate(self : PreservedUniformContext) -> String?

    Check that the preserved-uniform context is internally consistent. Returns None if valid, Some(error_message) if invalid.

    RenderPassDesc

    pub(all) struct RenderPassDesc {
    clear_color : Color
    clear_enabled : Bool
    present : Bool
    } derive(
    Debug
    )

    What GraphicsDriver.begin does before any draw calls of a pass.

    clear_enabled=false keeps the previous framebuffer contents (useful for additive overlays). present=true swaps buffers at end; set false for offscreen render-to-texture passes.

    SamplerSpec

    pub(all) struct SamplerSpec {
    filter : BuiltinShaderFilter
    address_u : BuiltinShaderAddress
    address_v : BuiltinShaderAddress
    } derive(
    Debug
    )

    Per-axis sampler specification for texture sampling.
    impl Show for SamplerSpec

    ShaderCompileRequest

    pub(all) struct ShaderCompileRequest {
    source : String
    unit_hint : ShaderUnit?
    src_image_count : Int
    entrypoints : ShaderEntrypoints
    debug_name : String
    } derive(
    Debug
    )

    ShaderCompileRequest::validate

    fn ShaderCompileRequest::validate(self : ShaderCompileRequest) -> String?

    Sanity-check the request before handing it to a ShaderFrontend. Returns None if valid, Some(error_message) if invalid.

    ShaderEntrypoints

    pub(all) struct ShaderEntrypoints {
    vertex : String
    fragment : String
    } derive(
    Debug
    )

    ShaderHandle

    pub(all) struct ShaderHandle {
    id : Int
    source : String
    } derive(
    Debug
    )

    Backend-defined shader identifier plus a copy of the source string so the queue can fingerprint or re-emit the shader without round-tripping the backend.

    ShaderIR

    pub(all) struct ShaderIR {
    source : String
    unit : ShaderUnit
    noperspective : Bool
    src_image_count : Int
    entrypoints : ShaderEntrypoints
    debug_name : String
    source_hash : ShaderSourceHash
    } derive(
    Debug
    )

    impl Show for ShaderIR

    ShaderSourceHash

    pub(all) struct ShaderSourceHash {
    value : String
    } derive(
    Debug
    )

    ShaderSourceHash::eq

    fn ShaderSourceHash::eq(self : ShaderSourceHash, rhs : ShaderSourceHash) -> Bool

    ShaderUnit

    pub(all) enum ShaderUnit {
    Pixels
    Texels
    } derive(
    Debug
    )

    impl Show for ShaderUnit

    ShaderUnit::eq

    fn ShaderUnit::eq(self : ShaderUnit, rhs : ShaderUnit) -> Bool

    SimpleCommandQueue

    pub struct SimpleCommandQueue {
    commands : Array[DrawTrianglesCommand]
    } derive(
    Debug
    )

    StubGraphicsDriver

    #alias(NativeGraphicsDriver)
    #alias(WebGlGraphicsDriver)
    #alias(WebGpuGraphicsDriver)
    #alias(NullGraphicsDriver)
    pub struct StubGraphicsDriver {
    backend : GraphicsBackendKind
    width : Int
    height : Int
    initialized : Bool
    native_active : Bool
    web_active : Bool
    next_id : Int
    begin_count : Int
    end_count : Int
    draw_count : Int
    resize_count : Int
    resize_suppressed_count : Int
    last_resize_duration_ms : Double
    total_resize_duration_ms : Double
    } derive(
    Debug
    )

    StubGraphicsDriver::resize_stats

    Snapshot of resize counters and the latest resize duration. Useful for diagnosing flaps where the host requests many no-op resizes.

    SurfaceKind

    pub(all) enum SurfaceKind {
    MetalLayer
    WebGpuCanvasContext
    WebGlCanvasContext
    OffscreenBuffer
    } derive(
    Debug
    )

    impl Show for SurfaceKind

    SurfaceToken

    pub(all) struct SurfaceToken {
    kind : SurfaceKind
    opaque_id : Int
    width : Int
    height : Int
    device_scale_factor : Double
    } derive(
    Debug
    )

    UniformLayout

    pub(all) struct UniformLayout {
    names : Array[String]
    dword_counts : Array[Int]
    preserved_prefix_dwords : Int
    } derive(
    Debug
    )

    UniformLayout::validate

    fn UniformLayout::validate(self : UniformLayout) -> String?

    Sanity-check a uniform layout for common errors. Returns None if valid, Some(error_message) if invalid.

    UniformValue

    pub(all) enum UniformValue {
    Bool(Bool)
    Int(Int)
    Float(Double)
    Bools(Array[Bool])
    Ints(Array[Int])
    Floats(Array[Double])
    } derive(
    Debug
    )

    WebGraphicsHooks

    pub struct WebGraphicsHooks {
    try_initialize : (GraphicsBackendKind, Int, Int) -> Bool
    on_begin : (Bool, GraphicsBackendKind, RenderPassDesc) -> Unit
    on_end : (Bool, GraphicsBackendKind, Bool) -> Unit
    on_draw : (Bool, GraphicsBackendKind, DrawTrianglesCommand) -> Unit
    on_resize : (Bool, GraphicsBackendKind, Int, Int) -> Unit
    on_read_pixels : (Bool, GraphicsBackendKind, Int, Int, Int, Int) -> Array[Int]?
    }

    build_builtin_shader_source_ex

    fn build_builtin_shader_source_ex(key : BuiltinShaderKeyEx) -> String

    Build shader source from extended key with per-axis address support.

    build_canonical_uniforms

    fn[T : UniformCanonicalizer] build_canonical_uniforms(canonicalizer : T, layout : UniformLayout, user_uniforms : Array[NamedUniform], context : PreservedUniformContext, ir : ShaderIR) -> PackedUniforms raise

    Compose append_user_uniforms + prepend_preserved_uniforms + filter_unused_uniforms and normalize the result to the layout length. Most callers want this rather than the trait methods individually.

    build_resource_cache_key

    fn build_resource_cache_key(seed : Int, values : Array[Int]) -> Int

    clear_screen

    fn[T : GraphicsDriver] clear_screen(driver : T, color : Color) -> Unit raise

    create_framebuffer_snapshot

    fn create_framebuffer_snapshot(driver : &GraphicsDriver, x : Int, y : Int, width : Int, height : Int) -> FramebufferSnapshot? raise

    create_null_graphics

    fn create_null_graphics(width : Int, height : Int) -> StubGraphicsDriver

    create_offscreen_surface_token

    fn create_offscreen_surface_token(width : Int, height : Int) -> SurfaceToken

    create_webgl_graphics

    fn create_webgl_graphics(surface : SurfaceToken, options : GraphicsBackendOptions) -> StubGraphicsDriver

    create_webgl_surface_token

    fn create_webgl_surface_token(opaque_id : Int, width : Int, height : Int, device_scale_factor : Double) -> SurfaceToken

    create_webgpu_graphics

    fn create_webgpu_graphics(surface : SurfaceToken, options : GraphicsBackendOptions) -> StubGraphicsDriver

    create_webgpu_surface_token

    fn create_webgpu_surface_token(opaque_id : Int, width : Int, height : Int, device_scale_factor : Double) -> SurfaceToken

    create_wgpu_native_graphics

    fn create_wgpu_native_graphics(surface : SurfaceToken, options : GraphicsBackendOptions) -> StubGraphicsDriver

    default_builtin_shader_source

    fn default_builtin_shader_source() -> String

    Returns a minimal valid builtin shader source for the default 2D pipeline. Use this instead of passing arbitrary strings (e.g. game title) to new_shader.

    default_graphics_backend_options

    fn default_graphics_backend_options() -> GraphicsBackendOptions

    default_sampler_spec

    fn default_sampler_spec() -> SamplerSpec

    default_shader_entrypoints

    fn default_shader_entrypoints() -> ShaderEntrypoints

    double_to_f32_bits

    fn double_to_f32_bits(v : Double) -> Int

    Convert a Double to IEEE 754 f32 bit representation as Int.

    f32_bits_to_double

    fn f32_bits_to_double(bits : Int) -> Double

    Convert IEEE 754 f32 bits (as Int) back to Double.

    flush_commands

    fn[T : GraphicsDriver, Q : CommandQueue] flush_commands(driver : T, queue : Q, present : Bool, clear_color? : Color) -> Unit raise

    new_basic_builtin_shader_source_repo

    fn new_basic_builtin_shader_source_repo() -> BasicBuiltinShaderSourceRepo

    new_basic_shader_frontend

    fn new_basic_shader_frontend() -> BasicShaderFrontend

    new_basic_uniform_canonicalizer

    fn new_basic_uniform_canonicalizer() -> BasicUniformCanonicalizer

    new_color

    fn new_color(r : Double, g : Double, b : Double, a : Double) -> Color

    new_draw_triangles_command

    fn new_draw_triangles_command(dst : ImageHandle, shader : ShaderHandle, dst_regions : Array[DstRegion], index_offset : Int, pipeline_id : Int, uniform_hash : Int, blend : BlendMode, vertex_data : Array[Double], indices : Array[Int], src_image_ids : Array[Int], uniform_dwords : Array[Int], instance_count? : Int, resource_cache_key? : Int, vertex_stride_hint? : Int) -> DrawTrianglesCommand

    new_dst_region

    fn new_dst_region(x : Int, y : Int, width : Int, height : Int, index_count : Int) -> DstRegion

    new_image_handle

    fn new_image_handle(id : Int, width : Int, height : Int) -> ImageHandle

    Wrap a backend-assigned id with its size. Use only from a backend that allocated id; ordinary callers get handles from GraphicsDriver.new_image.

    new_native_graphics_hooks

    fn new_native_graphics_hooks(try_initialize : (Int, Int) -> Bool, on_begin : (Bool, RenderPassDesc) -> Unit, on_end : (Bool, Bool) -> Unit, on_draw : (Bool, DrawTrianglesCommand) -> Unit, on_resize : (Bool, Int, Int) -> Unit) -> NativeGraphicsHooks

    new_native_graphics_hooks_full

    fn new_native_graphics_hooks_full(try_initialize : (Int, Int) -> Bool, on_begin : (Bool, RenderPassDesc) -> Unit, on_end : (Bool, Bool) -> Unit, on_draw : (Bool, DrawTrianglesCommand) -> Unit, on_resize : (Bool, Int, Int) -> Unit, on_read_pixels : (Bool, Int, Int, Int, Int) -> Array[Int]?, on_new_image : (Bool, Int, Int, Int) -> Unit) -> NativeGraphicsHooks

    new_pipeline_handle

    fn new_pipeline_handle(id : Int) -> PipelineHandle

    new_render_pass_desc

    fn new_render_pass_desc(clear_color : Color, clear_enabled : Bool, present? : Bool) -> RenderPassDesc

    new_shader_handle

    fn new_shader_handle(id : Int, source : String) -> ShaderHandle

    Wrap a backend-assigned shader id together with its compiled source.

    new_simple_command_queue

    fn new_simple_command_queue() -> SimpleCommandQueue

    new_web_graphics_hooks

    fn new_web_graphics_hooks(try_initialize : (GraphicsBackendKind, Int, Int) -> Bool, on_begin : (Bool, GraphicsBackendKind, RenderPassDesc) -> Unit, on_end : (Bool, GraphicsBackendKind, Bool) -> Unit, on_draw : (Bool, GraphicsBackendKind, DrawTrianglesCommand) -> Unit, on_resize : (Bool, GraphicsBackendKind, Int, Int) -> Unit) -> WebGraphicsHooks

    new_web_graphics_hooks_full

    fn new_web_graphics_hooks_full(try_initialize : (GraphicsBackendKind, Int, Int) -> Bool, on_begin : (Bool, GraphicsBackendKind, RenderPassDesc) -> Unit, on_end : (Bool, GraphicsBackendKind, Bool) -> Unit, on_draw : (Bool, GraphicsBackendKind, DrawTrianglesCommand) -> Unit, on_resize : (Bool, GraphicsBackendKind, Int, Int) -> Unit, on_read_pixels : (Bool, GraphicsBackendKind, Int, Int, Int, Int) -> Array[Int]?) -> WebGraphicsHooks

    parse_kage_noperspective_directive

    fn parse_kage_noperspective_directive(source : String) -> Bool

    reset_graphics_clock_provider

    fn reset_graphics_clock_provider() -> Unit

    reset_native_graphics_hooks

    fn reset_native_graphics_hooks() -> Unit

    reset_web_graphics_hooks

    fn reset_web_graphics_hooks() -> Unit

    sampler_spec

    fn sampler_spec(filter : BuiltinShaderFilter, address : BuiltinShaderAddress) -> SamplerSpec

    Convenience: create SamplerSpec with same address on both axes.

    set_graphics_clock_provider

    fn set_graphics_clock_provider(clock : () -> Double) -> Unit

    set_native_graphics_hooks

    fn set_native_graphics_hooks(hooks : NativeGraphicsHooks) -> Unit

    set_web_graphics_hooks

    fn set_web_graphics_hooks(hooks : WebGraphicsHooks) -> Unit