Skip to main content

bevy_core_pipeline/deferred/
copy_lighting_id.rs

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