gfx

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

moon add mizchi/gfx@0.1.0
Download zip
Author
Version
0.1.0
License
Apache-2.0
Last updated
2 months ago
Downloads
4K
README

#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 bufferDrawTrianglesCommand, DrawCommandDispatch, DstRegion, Color, RenderPassDesc, dispatch_checksum, build_draw_command_dispatch.
  • HandlesImageHandle, ShaderHandle, PipelineHandle, FilterMode.
  • Blend stateBlendFactor, BlendOperation, BlendEquation, BlendMode, plus blend_mode_to_equation, blend_mode_to_int, etc.
  • Driver traitGraphicsDriver (initialize / begin / end / resize / new_image / new_shader / draw_triangles / read_pixels) and a FramebufferSnapshot / PixelDiffResult harness for VRT.
  • Command queueCommandQueue trait and SimpleCommandQueue (reference impl with adjacent-batch merging under a 16k-float vertex budget) plus flush_commands / clear_screen.
  • Backend registryStubGraphicsDriver, create_{webgpu,webgl,wgpu_native,null}_graphics, NativeGraphicsHooks, WebGraphicsHooks, GraphicsBackendFactory, GraphicsBackendKind, GraphicsBackendOptions.
  • Shader plumbingShaderFrontend, UniformCanonicalizer, BuiltinShaderSourceRepo traits with BasicShaderFrontend, BasicUniformCanonicalizer, BasicBuiltinShaderSourceRepo reference implementations. UniformLayout, NamedUniform, UniformValue, PackedUniforms, PreservedUniformContext, plus validation helpers and double_to_f32_bits.
  • Builtin shader keysBuiltinShaderKey, BuiltinShaderKeyEx, BuiltinShaderFilter, BuiltinShaderAddress, SamplerSpec.
  • Surface descriptorSurfaceKind, 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