bevy_core_pipeline/deferred/
copy_lighting_id.rs

1use 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            &copy_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}