bevy_core_pipeline/deferred/
copy_lighting_id.rs1use crate::{
2 fullscreen_vertex_shader::fullscreen_shader_vertex_state,
3 prepass::{DeferredPrepass, ViewPrepassTextures},
4};
5use bevy_app::prelude::*;
6use bevy_asset::{load_internal_asset, Handle};
7use bevy_ecs::prelude::*;
8use bevy_math::UVec2;
9use bevy_render::{
10 camera::ExtractedCamera,
11 render_resource::{binding_types::texture_2d, *},
12 renderer::RenderDevice,
13 texture::{CachedTexture, TextureCache},
14 view::ViewTarget,
15 Render, RenderApp, RenderSet,
16};
17
18use bevy_ecs::query::QueryItem;
19use bevy_render::{
20 render_graph::{NodeRunError, RenderGraphContext, ViewNode},
21 renderer::RenderContext,
22};
23
24use super::DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT;
25
26pub const COPY_DEFERRED_LIGHTING_ID_SHADER_HANDLE: Handle<Shader> =
27 Handle::weak_from_u128(5230948520734987);
28pub struct CopyDeferredLightingIdPlugin;
29
30impl Plugin for CopyDeferredLightingIdPlugin {
31 fn build(&self, app: &mut App) {
32 load_internal_asset!(
33 app,
34 COPY_DEFERRED_LIGHTING_ID_SHADER_HANDLE,
35 "copy_deferred_lighting_id.wgsl",
36 Shader::from_wgsl
37 );
38 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
39 return;
40 };
41 render_app.add_systems(
42 Render,
43 (prepare_deferred_lighting_id_textures.in_set(RenderSet::PrepareResources),),
44 );
45 }
46
47 fn finish(&self, app: &mut App) {
48 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
49 return;
50 };
51
52 render_app.init_resource::<CopyDeferredLightingIdPipeline>();
53 }
54}
55
56#[derive(Default)]
57pub struct CopyDeferredLightingIdNode;
58impl CopyDeferredLightingIdNode {
59 pub const NAME: &'static str = "copy_deferred_lighting_id";
60}
61
62impl ViewNode for CopyDeferredLightingIdNode {
63 type ViewQuery = (
64 &'static ViewTarget,
65 &'static ViewPrepassTextures,
66 &'static DeferredLightingIdDepthTexture,
67 );
68
69 fn run(
70 &self,
71 _graph: &mut RenderGraphContext,
72 render_context: &mut RenderContext,
73 (_view_target, view_prepass_textures, deferred_lighting_id_depth_texture): QueryItem<
74 Self::ViewQuery,
75 >,
76 world: &World,
77 ) -> Result<(), NodeRunError> {
78 let copy_deferred_lighting_id_pipeline = world.resource::<CopyDeferredLightingIdPipeline>();
79
80 let pipeline_cache = world.resource::<PipelineCache>();
81
82 let Some(pipeline) =
83 pipeline_cache.get_render_pipeline(copy_deferred_lighting_id_pipeline.pipeline_id)
84 else {
85 return Ok(());
86 };
87 let Some(deferred_lighting_pass_id_texture) =
88 &view_prepass_textures.deferred_lighting_pass_id
89 else {
90 return Ok(());
91 };
92
93 let bind_group = render_context.render_device().create_bind_group(
94 "copy_deferred_lighting_id_bind_group",
95 ©_deferred_lighting_id_pipeline.layout,
96 &BindGroupEntries::single(&deferred_lighting_pass_id_texture.texture.default_view),
97 );
98
99 let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
100 label: Some("copy_deferred_lighting_id_pass"),
101 color_attachments: &[],
102 depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
103 view: &deferred_lighting_id_depth_texture.texture.default_view,
104 depth_ops: Some(Operations {
105 load: LoadOp::Clear(0.0),
106 store: StoreOp::Store,
107 }),
108 stencil_ops: None,
109 }),
110 timestamp_writes: None,
111 occlusion_query_set: None,
112 });
113
114 render_pass.set_render_pipeline(pipeline);
115 render_pass.set_bind_group(0, &bind_group, &[]);
116 render_pass.draw(0..3, 0..1);
117
118 Ok(())
119 }
120}
121
122#[derive(Resource)]
123struct CopyDeferredLightingIdPipeline {
124 layout: BindGroupLayout,
125 pipeline_id: CachedRenderPipelineId,
126}
127
128impl FromWorld for CopyDeferredLightingIdPipeline {
129 fn from_world(world: &mut World) -> Self {
130 let render_device = world.resource::<RenderDevice>();
131
132 let layout = render_device.create_bind_group_layout(
133 "copy_deferred_lighting_id_bind_group_layout",
134 &BindGroupLayoutEntries::single(
135 ShaderStages::FRAGMENT,
136 texture_2d(TextureSampleType::Uint),
137 ),
138 );
139
140 let pipeline_id =
141 world
142 .resource_mut::<PipelineCache>()
143 .queue_render_pipeline(RenderPipelineDescriptor {
144 label: Some("copy_deferred_lighting_id_pipeline".into()),
145 layout: vec![layout.clone()],
146 vertex: fullscreen_shader_vertex_state(),
147 fragment: Some(FragmentState {
148 shader: COPY_DEFERRED_LIGHTING_ID_SHADER_HANDLE,
149 shader_defs: vec![],
150 entry_point: "fragment".into(),
151 targets: vec![],
152 }),
153 primitive: PrimitiveState::default(),
154 depth_stencil: Some(DepthStencilState {
155 format: DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT,
156 depth_write_enabled: true,
157 depth_compare: CompareFunction::Always,
158 stencil: StencilState::default(),
159 bias: DepthBiasState::default(),
160 }),
161 multisample: MultisampleState::default(),
162 push_constant_ranges: vec![],
163 zero_initialize_workgroup_memory: false,
164 });
165
166 Self {
167 layout,
168 pipeline_id,
169 }
170 }
171}
172
173#[derive(Component)]
174pub struct DeferredLightingIdDepthTexture {
175 pub texture: CachedTexture,
176}
177
178fn prepare_deferred_lighting_id_textures(
179 mut commands: Commands,
180 mut texture_cache: ResMut<TextureCache>,
181 render_device: Res<RenderDevice>,
182 views: Query<(Entity, &ExtractedCamera), With<DeferredPrepass>>,
183) {
184 for (entity, camera) in &views {
185 if let Some(UVec2 {
186 x: width,
187 y: height,
188 }) = camera.physical_target_size
189 {
190 let texture_descriptor = TextureDescriptor {
191 label: Some("deferred_lighting_id_depth_texture_a"),
192 size: Extent3d {
193 width,
194 height,
195 depth_or_array_layers: 1,
196 },
197 mip_level_count: 1,
198 sample_count: 1,
199 dimension: TextureDimension::D2,
200 format: DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT,
201 usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::COPY_SRC,
202 view_formats: &[],
203 };
204 let texture = texture_cache.get(&render_device, texture_descriptor);
205 commands
206 .entity(entity)
207 .insert(DeferredLightingIdDepthTexture { texture });
208 }
209 }
210}