bevy_core_pipeline/deferred/
copy_lighting_id.rs1use crate::{
2 prepass::{DeferredPrepass, ViewPrepassTextures},
3 FullscreenShader,
4};
5use bevy_app::prelude::*;
6use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer};
7use bevy_ecs::prelude::*;
8use bevy_image::ToExtents;
9use bevy_render::{
10 camera::ExtractedCamera,
11 diagnostic::RecordDiagnostics,
12 render_resource::{binding_types::texture_2d, *},
13 renderer::RenderDevice,
14 texture::{CachedTexture, TextureCache},
15 view::ViewTarget,
16 Render, RenderApp, RenderStartup, RenderSystems,
17};
18
19use super::DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT;
20use bevy_render::renderer::{RenderContext, ViewQuery};
21use bevy_utils::default;
22
23pub struct CopyDeferredLightingIdPlugin;
24
25impl Plugin for CopyDeferredLightingIdPlugin {
26 fn build(&self, app: &mut App) {
27 embedded_asset!(app, "copy_deferred_lighting_id.wgsl");
28 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
29 return;
30 };
31 render_app
32 .add_systems(RenderStartup, init_copy_deferred_lighting_id_pipeline)
33 .add_systems(
34 Render,
35 (prepare_deferred_lighting_id_textures.in_set(RenderSystems::PrepareResources),),
36 );
37 }
38}
39
40pub(crate) fn copy_deferred_lighting_id(
41 view: ViewQuery<(
42 &ViewTarget,
43 &ViewPrepassTextures,
44 &DeferredLightingIdDepthTexture,
45 )>,
46 copy_pipeline: Res<CopyDeferredLightingIdPipeline>,
47 pipeline_cache: Res<PipelineCache>,
48 mut ctx: RenderContext,
49) {
50 let (_view_target, view_prepass_textures, deferred_lighting_id_depth_texture) =
51 view.into_inner();
52
53 let Some(pipeline) = pipeline_cache.get_render_pipeline(copy_pipeline.pipeline_id) else {
54 return;
55 };
56 let Some(deferred_lighting_pass_id_texture) = &view_prepass_textures.deferred_lighting_pass_id
57 else {
58 return;
59 };
60
61 let bind_group = ctx.render_device().create_bind_group(
62 "copy_deferred_lighting_id_bind_group",
63 &pipeline_cache.get_bind_group_layout(©_pipeline.layout),
64 &BindGroupEntries::single(&deferred_lighting_pass_id_texture.texture.default_view),
65 );
66
67 let diagnostics = ctx.diagnostic_recorder();
68 let diagnostics = diagnostics.as_deref();
69
70 let mut render_pass = ctx.begin_tracked_render_pass(RenderPassDescriptor {
71 label: Some("copy_deferred_lighting_id"),
72 color_attachments: &[],
73 depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
74 view: &deferred_lighting_id_depth_texture.texture.default_view,
75 depth_ops: Some(Operations {
76 load: LoadOp::Clear(0.0),
77 store: StoreOp::Store,
78 }),
79 stencil_ops: None,
80 }),
81 timestamp_writes: None,
82 occlusion_query_set: None,
83 multiview_mask: None,
84 });
85 let pass_span = diagnostics.pass_span(&mut render_pass, "copy_deferred_lighting_id");
86
87 render_pass.set_render_pipeline(pipeline);
88 render_pass.set_bind_group(0, &bind_group, &[]);
89 render_pass.draw(0..3, 0..1);
90
91 pass_span.end(&mut render_pass);
92}
93
94#[derive(Resource)]
95pub(crate) struct CopyDeferredLightingIdPipeline {
96 layout: BindGroupLayoutDescriptor,
97 pipeline_id: CachedRenderPipelineId,
98}
99
100pub fn init_copy_deferred_lighting_id_pipeline(
101 mut commands: Commands,
102 fullscreen_shader: Res<FullscreenShader>,
103 asset_server: Res<AssetServer>,
104 pipeline_cache: Res<PipelineCache>,
105) {
106 let layout = BindGroupLayoutDescriptor::new(
107 "copy_deferred_lighting_id_bind_group_layout",
108 &BindGroupLayoutEntries::single(
109 ShaderStages::FRAGMENT,
110 texture_2d(TextureSampleType::Uint),
111 ),
112 );
113
114 let vertex_state = fullscreen_shader.to_vertex_state();
115 let shader = load_embedded_asset!(asset_server.as_ref(), "copy_deferred_lighting_id.wgsl");
116
117 let pipeline_id = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor {
118 label: Some("copy_deferred_lighting_id_pipeline".into()),
119 layout: vec![layout.clone()],
120 vertex: vertex_state,
121 fragment: Some(FragmentState {
122 shader,
123 ..default()
124 }),
125 depth_stencil: Some(DepthStencilState {
126 format: DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT,
127 depth_write_enabled: Some(true),
128 depth_compare: Some(CompareFunction::Always),
129 stencil: StencilState::default(),
130 bias: DepthBiasState::default(),
131 }),
132 ..default()
133 });
134
135 commands.insert_resource(CopyDeferredLightingIdPipeline {
136 layout,
137 pipeline_id,
138 });
139}
140
141#[derive(Component)]
142pub struct DeferredLightingIdDepthTexture {
143 pub texture: CachedTexture,
144}
145
146fn prepare_deferred_lighting_id_textures(
147 mut commands: Commands,
148 mut texture_cache: ResMut<TextureCache>,
149 render_device: Res<RenderDevice>,
150 views: Query<(Entity, &ExtractedCamera), With<DeferredPrepass>>,
151) {
152 for (entity, camera) in &views {
153 if let Some(physical_target_size) = camera.physical_target_size {
154 let texture_descriptor = TextureDescriptor {
155 label: Some("deferred_lighting_id_depth_texture_a"),
156 size: physical_target_size.to_extents(),
157 mip_level_count: 1,
158 sample_count: 1,
159 dimension: TextureDimension::D2,
160 format: DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT,
161 usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::COPY_SRC,
162 view_formats: &[],
163 };
164 let texture = texture_cache.get(&render_device, texture_descriptor);
165 commands
166 .entity(entity)
167 .insert(DeferredLightingIdDepthTexture { texture });
168 }
169 }
170}