Move initializing the ComputePipeline and adding to the render graph to build for gpu_readback example.

This commit is contained in:
andriyDev 2025-07-13 13:56:06 -07:00
parent 4fc5e440aa
commit ab5a35a677

View File

@ -15,7 +15,7 @@ use bevy::{
renderer::{RenderContext, RenderDevice}, renderer::{RenderContext, RenderDevice},
storage::{GpuShaderStorageBuffer, ShaderStorageBuffer}, storage::{GpuShaderStorageBuffer, ShaderStorageBuffer},
texture::GpuImage, texture::GpuImage,
Render, RenderApp, RenderSystems, Render, RenderApp, RenderStartup, RenderSystems,
}, },
}; };
@ -41,24 +41,22 @@ fn main() {
// We need a plugin to organize all the systems and render node required for this example // We need a plugin to organize all the systems and render node required for this example
struct GpuReadbackPlugin; struct GpuReadbackPlugin;
impl Plugin for GpuReadbackPlugin { impl Plugin for GpuReadbackPlugin {
fn build(&self, _app: &mut App) {} fn build(&self, app: &mut App) {
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
fn finish(&self, app: &mut App) { return;
let render_app = app.sub_app_mut(RenderApp); };
render_app.init_resource::<ComputePipeline>().add_systems(
Render,
prepare_bind_group
.in_set(RenderSystems::PrepareBindGroups)
// We don't need to recreate the bind group every frame
.run_if(not(resource_exists::<GpuBufferBindGroup>)),
);
// Add the compute node as a top level node to the render graph
// This means it will only execute once per frame
render_app render_app
.world_mut() .add_systems(
.resource_mut::<RenderGraph>() RenderStartup,
.add_node(ComputeNodeLabel, ComputeNode::default()); (init_compute_pipeline, add_compute_render_graph_node),
)
.add_systems(
Render,
prepare_bind_group
.in_set(RenderSystems::PrepareBindGroups)
// We don't need to recreate the bind group every frame
.run_if(not(resource_exists::<GpuBufferBindGroup>)),
);
} }
} }
@ -127,6 +125,13 @@ fn setup(
commands.insert_resource(ReadbackImage(image)); commands.insert_resource(ReadbackImage(image));
} }
fn add_compute_render_graph_node(mut render_graph: ResMut<RenderGraph>) {
// Add the compute node as a top-level node to the render graph. This means it will only execute
// once per frame. Normally, adding a node would use the `RenderGraphApp::add_render_graph_node`
// method, but it does not allow adding as a top-level node.
render_graph.add_node(ComputeNodeLabel, ComputeNode::default());
}
#[derive(Resource)] #[derive(Resource)]
struct GpuBufferBindGroup(BindGroup); struct GpuBufferBindGroup(BindGroup);
@ -158,29 +163,30 @@ struct ComputePipeline {
pipeline: CachedComputePipelineId, pipeline: CachedComputePipelineId,
} }
impl FromWorld for ComputePipeline { fn init_compute_pipeline(
fn from_world(world: &mut World) -> Self { mut commands: Commands,
let render_device = world.resource::<RenderDevice>(); render_device: Res<RenderDevice>,
let layout = render_device.create_bind_group_layout( asset_server: Res<AssetServer>,
None, pipeline_cache: Res<PipelineCache>,
&BindGroupLayoutEntries::sequential( ) {
ShaderStages::COMPUTE, let layout = render_device.create_bind_group_layout(
( None,
storage_buffer::<Vec<u32>>(false), &BindGroupLayoutEntries::sequential(
texture_storage_2d(TextureFormat::R32Uint, StorageTextureAccess::WriteOnly), ShaderStages::COMPUTE,
), (
storage_buffer::<Vec<u32>>(false),
texture_storage_2d(TextureFormat::R32Uint, StorageTextureAccess::WriteOnly),
), ),
); ),
let shader = world.load_asset(SHADER_ASSET_PATH); );
let pipeline_cache = world.resource::<PipelineCache>(); let shader = asset_server.load(SHADER_ASSET_PATH);
let pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { let pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
label: Some("GPU readback compute shader".into()), label: Some("GPU readback compute shader".into()),
layout: vec![layout.clone()], layout: vec![layout.clone()],
shader: shader.clone(), shader: shader.clone(),
..default() ..default()
}); });
ComputePipeline { layout, pipeline } commands.insert_resource(ComputePipeline { layout, pipeline });
}
} }
/// Label to identify the node in the render graph /// Label to identify the node in the render graph