Skip to main content

ShaderAppExt

Trait ShaderAppExt 

Source
pub trait ShaderAppExt {
    // Required methods
    fn register_uniform_buffer<U>(
        &mut self,
        group_index: u32,
        binding_index: u32,
    ) -> &mut Self
       where U: ShaderType + WriteInto + Default + Resource + Clone + Send + Sync + 'static;
    fn register_storage_buffer<S>(
        &mut self,
        group_index: u32,
        binding_index: u32,
        read_write: bool,
    ) -> &mut Self
       where S: ShaderType + WriteInto + Default + Resource + Clone + Send + Sync + 'static;
    fn register_array_buffer<Tag, T, const N: usize>(
        &mut self,
        group_index: u32,
        binding_index: u32,
        read_write: bool,
    ) -> &mut Self
       where Tag: Send + Sync + 'static,
             T: ShaderSize + WriteInto + Default + Send + Sync + 'static;
    fn register_gpu_buffer<Tag, T>(
        &mut self,
        group_index: u32,
        binding_index: u32,
        len: u32,
    ) -> &mut Self
       where Tag: Send + Sync + 'static,
             T: ShaderSize + WriteInto + Default + Send + Sync + 'static;
    fn read_back_gpu_buffer<Tag, T>(&mut self, mode: ReadbackMode) -> &mut Self
       where Tag: Send + Sync + 'static,
             T: ShaderSize + CreateFrom + Send + Sync + 'static;
    fn read_back_array_buffer<Tag, T>(
        &mut self,
        mode: ReadbackMode,
    ) -> &mut Self
       where Tag: Send + Sync + 'static,
             T: ShaderSize + CreateFrom + Send + Sync + 'static;
    fn read_back_storage_buffer<S>(&mut self, mode: ReadbackMode) -> &mut Self
       where S: ShaderType + WriteInto + CreateFrom + Default + Resource + Clone + Send + Sync + 'static;
}
Expand description

Extension methods on App for registering buffers shared by the fullscreen fragment shader and the compute shader.

Every registered buffer is visible to both stages at the same @group/@binding. Declare each binding with the same access mode (read or read_write) in every shader that uses it — wgpu rejects a mismatch.

Required Methods§

Source

fn register_uniform_buffer<U>( &mut self, group_index: u32, binding_index: u32, ) -> &mut Self
where U: ShaderType + WriteInto + Default + Resource + Clone + Send + Sync + 'static,

Register an auto-managed uniform buffer at @group(group_index) @binding(binding_index).

U must be inserted as a Resource in the main world. The library extracts it to the render world and uploads it to a persistent uniform buffer whenever the resource changes.

Multiple calls with the same group_index but different binding_index values pack several uniform bindings into one bind group.

§Example
ⓘ
#[derive(Resource, Default, ShaderType, Clone)]
struct TimeUniforms { elapsed: f32 }

app.insert_resource(TimeUniforms::default())
   .register_uniform_buffer::<TimeUniforms>(0, 0);
// WGSL: @group(0) @binding(0) var<uniform> time_uniforms: TimeUniforms;
Source

fn register_storage_buffer<S>( &mut self, group_index: u32, binding_index: u32, read_write: bool, ) -> &mut Self
where S: ShaderType + WriteInto + Default + Resource + Clone + Send + Sync + 'static,

Register an auto-managed storage buffer at @group(group_index) @binding(binding_index).

S must be inserted as a Resource in the main world. The library extracts it to the render world and uploads it to a persistent storage buffer whenever the resource changes.

Multiple calls with the same group_index but different binding_index values pack several storage bindings into one bind group. read_write: false → var<storage, read>, true → var<storage, read_write>.

The CPU owns this buffer: shader writes persist until the resource next changes, then the CPU upload replaces the whole buffer. For data the GPU owns, use register_gpu_buffer.

§Example
ⓘ
#[derive(Resource, Default, ShaderType, Clone)]
struct Palette { colors: [Vec4; 16] }

app.insert_resource(Palette::default())
   .register_storage_buffer::<Palette>(1, 0, false);
// WGSL: @group(1) @binding(0) var<storage, read> palette: Palette;
Source

fn register_array_buffer<Tag, T, const N: usize>( &mut self, group_index: u32, binding_index: u32, read_write: bool, ) -> &mut Self
where Tag: Send + Sync + 'static, T: ShaderSize + WriteInto + Default + Send + Sync + 'static,

Register a fixed-size array buffer at @group(group_index) @binding(binding_index).

Maps to WGSL array<T, N>. The buffer is initialized once with T::default() values and persists across frames — only elements explicitly changed via ArrayBufferChanges are uploaded each frame, batched into contiguous write_buffer runs.

Tag is a user-defined zero-sized marker type. Define one per registration so that multiple buffers of the same element type and length can coexist:

ⓘ
struct Colors;
struct Positions;
app.register_array_buffer::<Colors, Vec4, 64>(1, 0, false);
app.register_array_buffer::<Positions, Vec4, 64>(2, 0, false);

// Each system names only its tag — no T or N required:
fn update_colors(mut changes: ResMut<ArrayBufferChanges<Colors>>) {
    changes.set(0, Vec4::ONE);
}

read_write: false → var<storage, read>, true → var<storage, read_write>.

Source

fn register_gpu_buffer<Tag, T>( &mut self, group_index: u32, binding_index: u32, len: u32, ) -> &mut Self
where Tag: Send + Sync + 'static, T: ShaderSize + WriteInto + Default + Send + Sync + 'static,

Register a GPU-owned buffer of len elements at @group(group_index) @binding(binding_index).

Maps to WGSL var<storage, read_write> name: array<T> (always read_write). The buffer starts filled with T::default() and is never uploaded from the CPU again, so shader writes persist across frames — use it for simulation state that compute passes update. Its handle is available in the main world as GpuBuffer<Tag>.

Tag is a user-defined marker type naming the buffer, also used to size dispatches with Workgroups::over:

ⓘ
#[derive(ShaderType, Clone, Copy, Default)]
struct Particle { pos: Vec2, vel: Vec2 }
struct Particles;

app.register_gpu_buffer::<Particles, Particle>(1, 0, 1024);
// WGSL: @group(1) @binding(0) var<storage, read_write> particles: array<Particle>;
Source

fn read_back_gpu_buffer<Tag, T>(&mut self, mode: ReadbackMode) -> &mut Self
where Tag: Send + Sync + 'static, T: ShaderSize + CreateFrom + Send + Sync + 'static,

Enable reading the GPU buffer tagged Tag back to the CPU, decoded as T values into the GpuReadback<Tag, T> resource. Call after register_gpu_buffer, with the same T.

With ReadbackMode::OnRequest, call GpuReadback::request whenever you want a copy. With ReadbackMode::EveryFrame, the buffer is copied every frame. Results arrive 1–3 frames after the copy is made.

ⓘ
app.register_gpu_buffer::<Particles, Particle>(1, 0, 1024)
   .read_back_gpu_buffer::<Particles, Particle>(ReadbackMode::OnRequest);

fn request(readback: Res<GpuReadback<Particles, Particle>>) {
    readback.request();
}

fn print(readback: Res<GpuReadback<Particles, Particle>>) {
    if !readback.is_changed() { return; }
    let Some(particles) = readback.latest() else { return };
    info!("{} particles", particles.len());
}
Source

fn read_back_array_buffer<Tag, T>(&mut self, mode: ReadbackMode) -> &mut Self
where Tag: Send + Sync + 'static, T: ShaderSize + CreateFrom + Send + Sync + 'static,

Enable reading the array buffer tagged Tag back to the CPU, decoded as T values into the GpuReadback<Tag, T> resource. Call after register_array_buffer, with the same T.

Works exactly like read_back_gpu_buffer. Useful when a shader writes to a read_write array buffer.

Source

fn read_back_storage_buffer<S>(&mut self, mode: ReadbackMode) -> &mut Self
where S: ShaderType + WriteInto + CreateFrom + Default + Resource + Clone + Send + Sync + 'static,

Enable reading the storage buffer of resource type S back to the CPU, decoded as an S into the StorageReadback<S> resource. Call after register_storage_buffer. If S is registered at several bindings, the first storage registration is read.

Useful when a shader writes to a read_write storage buffer. With ReadbackMode::OnRequest, call StorageReadback::request whenever you want a copy. With ReadbackMode::EveryFrame, the buffer is copied every frame.

ⓘ
app.register_storage_buffer::<Stats>(1, 0, true)
   .init_resource::<Stats>()
   .read_back_storage_buffer::<Stats>(ReadbackMode::EveryFrame);

fn print(readback: Res<StorageReadback<Stats>>) {
    let Some(stats) = readback.latest() else { return };
    info!("{:?}", stats.total);
}

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl ShaderAppExt for App

Source§

fn register_uniform_buffer<U>( &mut self, group_index: u32, binding_index: u32, ) -> &mut Self
where U: ShaderType + WriteInto + Default + Resource + Clone + Send + Sync + 'static,

Source§

fn register_storage_buffer<S>( &mut self, group_index: u32, binding_index: u32, read_write: bool, ) -> &mut Self
where S: ShaderType + WriteInto + Default + Resource + Clone + Send + Sync + 'static,

Source§

fn register_array_buffer<Tag, T, const N: usize>( &mut self, group_index: u32, binding_index: u32, read_write: bool, ) -> &mut Self
where Tag: Send + Sync + 'static, T: ShaderSize + WriteInto + Default + Send + Sync + 'static,

Source§

fn register_gpu_buffer<Tag, T>( &mut self, group_index: u32, binding_index: u32, len: u32, ) -> &mut Self
where Tag: Send + Sync + 'static, T: ShaderSize + WriteInto + Default + Send + Sync + 'static,

Source§

fn read_back_gpu_buffer<Tag, T>(&mut self, mode: ReadbackMode) -> &mut Self
where Tag: Send + Sync + 'static, T: ShaderSize + CreateFrom + Send + Sync + 'static,

Source§

fn read_back_array_buffer<Tag, T>(&mut self, mode: ReadbackMode) -> &mut Self
where Tag: Send + Sync + 'static, T: ShaderSize + CreateFrom + Send + Sync + 'static,

Source§

fn read_back_storage_buffer<S>(&mut self, mode: ReadbackMode) -> &mut Self
where S: ShaderType + WriteInto + CreateFrom + Default + Resource + Clone + Send + Sync + 'static,

Implementors§