Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Resources & Textures

Render graph resources are the GPU textures and buffers that passes read from and write to. Every resource is referenced through a ResourceId handle. The graph hands you the handle when you declare the resource, and you pass that handle to add_pass() to wire it into slot bindings.

ResourceId

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ResourceId(pub u32);
}

ResourceId is an opaque integer handle. It survives across frames and across graph recompilations. The actual GPU texture or buffer the handle points to can change (aliasing, resize), but the handle does not.

Resource Types

There are six variants. The split is along two axes: color versus depth versus buffer, and external versus transient.

TypeDescription
ExternalColorColor texture provided externally each frame (e.g. swapchain)
TransientColorColor texture managed by the graph (allocated, aliased, freed automatically)
ExternalDepthDepth texture provided externally
TransientDepthDepth texture managed by the graph
ExternalBufferGPU buffer provided externally
TransientBufferGPU buffer managed by the graph

External vs Transient

External resources are owned by the caller. The graph never creates or destroys them. Every frame, the application provides them via set_external_texture(). The swapchain texture is the canonical example.

Transient resources are owned by the graph. The graph creates the underlying GPU texture or buffer, tracks its lifetime across the frame, and can alias it with other transients to reduce VRAM. A transient with first_use at pass 1 and last_use at pass 3 has no GPU object outside that window, so its memory can be reused by another transient whose lifetime falls outside the same range.

Creating Color Textures

The fluent builder is the entry point.

#![allow(unused)]
fn main() {
// Transient - graph manages lifetime and may alias memory
let hdr = graph.add_color_texture("scene_color")
    .format(wgpu::TextureFormat::Rgba16Float)
    .size(1920, 1080)
    .clear_color(wgpu::Color::BLACK)
    .transient();

// External - you provide the texture each frame
let swapchain = graph.add_color_texture("swapchain")
    .format(wgpu::TextureFormat::Bgra8UnormSrgb)
    .external();
}

Builder Methods

MethodDescription
format(TextureFormat)Pixel format (default: Rgba8UnormSrgb)
size(width, height)Texture dimensions
usage(TextureUsages)GPU usage flags
sample_count(u32)MSAA sample count
mip_levels(u32)Mipmap level count
clear_color(Color)Clear color (only for the first pass that writes)
no_store()Don't force store after last write
transient()Finalize as transient (returns ResourceId)
external()Finalize as external (returns ResourceId)

Creating Depth Textures

#![allow(unused)]
fn main() {
let depth = graph.add_depth_texture("depth")
    .size(1920, 1080)
    .format(wgpu::TextureFormat::Depth32Float)
    .clear_depth(0.0)
    .transient();
}

Depth Builder Methods

MethodDescription
format(TextureFormat)Depth format (default: Depth32Float)
size(width, height)Texture dimensions
usage(TextureUsages)GPU usage flags
array_layers(u32)For texture arrays (e.g. shadow cascades)
clear_depth(f32)Clear depth value
no_store()Don't force store
transient() / external()Finalize

Creating Buffers

#![allow(unused)]
fn main() {
let data_buffer = graph.add_buffer("compute_data")
    .size(1024 * 1024)
    .usage(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST)
    .transient();
}

Resource Templates

A template captures the shared shape of a set of textures. Useful when you need a bunch of textures with the same format, size, and usage and only the name differs.

#![allow(unused)]
fn main() {
let template = ResourceTemplate::new(
    wgpu::TextureFormat::Rgba16Float,
    1920,
    1080,
).usage(wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING);

let texture_a = graph.transient_color_from_template("blur_a", &template);
let texture_b = graph.transient_color_from_template("blur_b", &template);
}

Template Methods

MethodDescription
new(format, width, height)Create a template
usage(TextureUsages)Set usage flags
sample_count(u32)MSAA samples
mip_levels(u32)Mipmap levels
array_layers(u32)Texture array layers
cube_map()Configure as cube map (6 layers)
dimension_3d(depth)3D texture

Resource Pools

A pool batches the allocation of several transients from one template.

#![allow(unused)]
fn main() {
let mut pool = graph.resource_pool(&template);
let [blur_a, blur_b, blur_c] = [
    pool.transient("blur_a"),
    pool.transient("blur_b"),
    pool.transient("blur_c"),
];
}

Setting External Textures Per-Frame

External textures must be provided before execute() runs.

#![allow(unused)]
fn main() {
// Each frame, provide the swapchain texture
let surface_texture = surface.get_current_texture()?;
let view = surface_texture.texture.create_view(&Default::default());
graph.set_external_texture(swapchain_id, view, width, height);
}

Resizing Transient Textures

When the window resizes, every transient that tracks the window size needs to be told.

#![allow(unused)]
fn main() {
graph.resize_transient_resource(&device, depth_id, new_width, new_height)?;
graph.resize_transient_resource(&device, scene_color_id, new_width, new_height)?;
}

Resizing invalidates the aliasing info. Reallocation happens on the next execution.