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.
| Type | Description |
|---|---|
ExternalColor | Color texture provided externally each frame (e.g. swapchain) |
TransientColor | Color texture managed by the graph (allocated, aliased, freed automatically) |
ExternalDepth | Depth texture provided externally |
TransientDepth | Depth texture managed by the graph |
ExternalBuffer | GPU buffer provided externally |
TransientBuffer | GPU 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
| Method | Description |
|---|---|
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
| Method | Description |
|---|---|
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
| Method | Description |
|---|---|
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.