Skip to main content

bevy_core_pipeline/oit/resolve/
node.rs

1use bevy_camera::{MainPassResolutionOverride, Viewport};
2use bevy_ecs::prelude::*;
3use bevy_render::{
4    camera::ExtractedCamera,
5    diagnostic::RecordDiagnostics,
6    render_resource::{BindGroupEntries, PipelineCache, RenderPassDescriptor},
7    renderer::{RenderContext, ViewQuery},
8    view::{ViewDepthStencilTexture, ViewTarget, ViewUniformOffset},
9};
10
11use crate::prepass::DepthPrepass;
12
13use super::{OitResolveBindGroup, OitResolvePipeline, OitResolvePipelineId};
14
15pub fn oit_resolve(
16    view: ViewQuery<(
17        &ExtractedCamera,
18        &ViewTarget,
19        &ViewUniformOffset,
20        &OitResolvePipelineId,
21        &ViewDepthStencilTexture,
22        Option<&MainPassResolutionOverride>,
23        Has<DepthPrepass>,
24    )>,
25    resolve_pipeline: Option<Res<OitResolvePipeline>>,
26    bind_group: Option<Res<OitResolveBindGroup>>,
27    pipeline_cache: Res<PipelineCache>,
28    mut ctx: RenderContext,
29) {
30    let (
31        camera,
32        view_target,
33        view_uniform,
34        oit_resolve_pipeline_id,
35        depth,
36        resolution_override,
37        depth_prepass,
38    ) = view.into_inner();
39
40    // This *must* run after main_transparent_pass_3d to reset the `oit_atomic_counter` and `oit_heads` buffer
41    // Otherwise transparent pass will construct a corrupted linked list(can have circular references which causes infinite loop and device lost) on the next pass.
42    let Some(resolve_pipeline) = resolve_pipeline else {
43        return;
44    };
45    let Some(depth_view) = depth.attachment.depth_stencil_views().depth_only_view() else {
46        return;
47    };
48    let Some(bind_group) = bind_group else {
49        return;
50    };
51    let Some(pipeline) = pipeline_cache.get_render_pipeline(oit_resolve_pipeline_id.0) else {
52        return;
53    };
54
55    let depth_bind_group = if !depth_prepass {
56        Some(ctx.render_device().create_bind_group(
57            "oit_resolve_depth_bind_group",
58            &pipeline_cache.get_bind_group_layout(&resolve_pipeline.oit_depth_bind_group_layout),
59            &BindGroupEntries::single(depth_view),
60        ))
61    } else {
62        None
63    };
64
65    let diagnostics = ctx.diagnostic_recorder();
66    let diagnostics = diagnostics.as_deref();
67
68    let mut render_pass = ctx.begin_tracked_render_pass(RenderPassDescriptor {
69        label: Some("oit_resolve"),
70        color_attachments: &[Some(view_target.get_color_attachment())],
71        depth_stencil_attachment: None,
72        timestamp_writes: None,
73        occlusion_query_set: None,
74        multiview_mask: None,
75    });
76    let pass_span = diagnostics.pass_span(&mut render_pass, "oit_resolve");
77
78    if let Some(viewport) =
79        Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
80    {
81        render_pass.set_camera_viewport(&viewport);
82    }
83
84    render_pass.set_render_pipeline(pipeline);
85    render_pass.set_bind_group(0, &bind_group, &[view_uniform.offset]);
86    if let Some(depth_bind_group) = &depth_bind_group {
87        render_pass.set_bind_group(1, depth_bind_group, &[]);
88    }
89    render_pass.draw(0..3, 0..1);
90
91    pass_span.end(&mut render_pass);
92}