Use BufferVec
for gpu_readback
example (#13668)
# Objective - Where possible, it's recommended to use `BufferVec` over `encase::StorageBuffer` for performance reason. It doesn't really matter for the example, but it's still important to teach the better solution. ## Solution - Use BufferVec in the gpu_readback example
This commit is contained in:
parent
fd82ef8956
commit
16207e4043
@ -12,7 +12,7 @@ use bevy::{
|
|||||||
render::{
|
render::{
|
||||||
render_graph::{self, RenderGraph, RenderLabel},
|
render_graph::{self, RenderGraph, RenderLabel},
|
||||||
render_resource::{binding_types::storage_buffer, *},
|
render_resource::{binding_types::storage_buffer, *},
|
||||||
renderer::{RenderContext, RenderDevice},
|
renderer::{RenderContext, RenderDevice, RenderQueue},
|
||||||
Render, RenderApp, RenderSet,
|
Render, RenderApp, RenderSet,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -91,28 +91,33 @@ impl Plugin for GpuReadbackPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Holds the buffers that will be used to communicate between the cpu and gpu
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
struct Buffers {
|
struct Buffers {
|
||||||
// The buffer that will be used by the compute shader
|
/// The buffer that will be used by the compute shader
|
||||||
gpu_buffer: Buffer,
|
///
|
||||||
// The buffer that will be read on the cpu.
|
/// In this example, we want to write a `Vec<u32>` to a `Buffer`. `BufferVec` is a wrapper around a `Buffer`
|
||||||
// The `gpu_buffer` will be copied to this buffer every frame
|
/// that will make sure the data is correctly aligned for the gpu and will simplify uploading the data to the gpu.
|
||||||
|
gpu_buffer: BufferVec<u32>,
|
||||||
|
/// The buffer that will be read on the cpu.
|
||||||
|
/// The `gpu_buffer` will be copied to this buffer every frame
|
||||||
cpu_buffer: Buffer,
|
cpu_buffer: Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWorld for Buffers {
|
impl FromWorld for Buffers {
|
||||||
fn from_world(world: &mut World) -> Self {
|
fn from_world(world: &mut World) -> Self {
|
||||||
let render_device = world.resource::<RenderDevice>();
|
let render_device = world.resource::<RenderDevice>();
|
||||||
let mut init_data = encase::StorageBuffer::new(Vec::new());
|
let render_queue = world.resource::<RenderQueue>();
|
||||||
// Init the buffer with 0
|
|
||||||
let data = vec![0; BUFFER_LEN];
|
// Create the buffer that will be accessed by the gpu
|
||||||
init_data.write(&data).expect("Failed to write buffer");
|
let mut gpu_buffer = BufferVec::new(BufferUsages::STORAGE | BufferUsages::COPY_SRC);
|
||||||
// The buffer that will be accessed by the gpu
|
for _ in 0..BUFFER_LEN {
|
||||||
let gpu_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
|
// Init the buffer with zeroes
|
||||||
label: Some("gpu_buffer"),
|
gpu_buffer.push(0);
|
||||||
contents: init_data.as_ref(),
|
}
|
||||||
usage: BufferUsages::STORAGE | BufferUsages::COPY_SRC,
|
// Write the buffer so the data is accessible on the gpu
|
||||||
});
|
gpu_buffer.write_buffer(render_device, render_queue);
|
||||||
|
|
||||||
// For portability reasons, WebGPU draws a distinction between memory that is
|
// For portability reasons, WebGPU draws a distinction between memory that is
|
||||||
// accessible by the CPU and memory that is accessible by the GPU. Only
|
// accessible by the CPU and memory that is accessible by the GPU. Only
|
||||||
// buffers accessible by the CPU can be mapped and accessed by the CPU and
|
// buffers accessible by the CPU can be mapped and accessed by the CPU and
|
||||||
@ -145,7 +150,13 @@ fn prepare_bind_group(
|
|||||||
let bind_group = render_device.create_bind_group(
|
let bind_group = render_device.create_bind_group(
|
||||||
None,
|
None,
|
||||||
&pipeline.layout,
|
&pipeline.layout,
|
||||||
&BindGroupEntries::single(buffers.gpu_buffer.as_entire_binding()),
|
&BindGroupEntries::single(
|
||||||
|
buffers
|
||||||
|
.gpu_buffer
|
||||||
|
.binding()
|
||||||
|
// We already did it when creating the buffer so this should never happen
|
||||||
|
.expect("Buffer should have already been uploaded to the gpu"),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
commands.insert_resource(GpuBufferBindGroup(bind_group));
|
commands.insert_resource(GpuBufferBindGroup(bind_group));
|
||||||
}
|
}
|
||||||
@ -285,7 +296,10 @@ impl render_graph::Node for ComputeNode {
|
|||||||
// Copy the gpu accessible buffer to the cpu accessible buffer
|
// Copy the gpu accessible buffer to the cpu accessible buffer
|
||||||
let buffers = world.resource::<Buffers>();
|
let buffers = world.resource::<Buffers>();
|
||||||
render_context.command_encoder().copy_buffer_to_buffer(
|
render_context.command_encoder().copy_buffer_to_buffer(
|
||||||
&buffers.gpu_buffer,
|
buffers
|
||||||
|
.gpu_buffer
|
||||||
|
.buffer()
|
||||||
|
.expect("Buffer should have already been uploaded to the gpu"),
|
||||||
0,
|
0,
|
||||||
&buffers.cpu_buffer,
|
&buffers.cpu_buffer,
|
||||||
0,
|
0,
|
||||||
|
Loading…
Reference in New Issue
Block a user