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::{ViewDepthTexture, 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        &ViewDepthTexture,
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(bind_group) = bind_group else {
46        return;
47    };
48    let Some(pipeline) = pipeline_cache.get_render_pipeline(oit_resolve_pipeline_id.0) else {
49        return;
50    };
51
52    let depth_bind_group = if !depth_prepass {
53        Some(ctx.render_device().create_bind_group(
54            "oit_resolve_depth_bind_group",
55            &pipeline_cache.get_bind_group_layout(&resolve_pipeline.oit_depth_bind_group_layout),
56            &BindGroupEntries::single(depth.view()),
57        ))
58    } else {
59        None
60    };
61
62    let diagnostics = ctx.diagnostic_recorder();
63    let diagnostics = diagnostics.as_deref();
64
65    let mut render_pass = ctx.begin_tracked_render_pass(RenderPassDescriptor {
66        label: Some("oit_resolve"),
67        color_attachments: &[Some(view_target.get_color_attachment())],
68        depth_stencil_attachment: None,
69        timestamp_writes: None,
70        occlusion_query_set: None,
71        multiview_mask: None,
72    });
73    let pass_span = diagnostics.pass_span(&mut render_pass, "oit_resolve");
74
75    if let Some(viewport) =
76        Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
77    {
78        render_pass.set_camera_viewport(&viewport);
79    }
80
81    render_pass.set_render_pipeline(pipeline);
82    render_pass.set_bind_group(0, &bind_group, &[view_uniform.offset]);
83    if let Some(depth_bind_group) = &depth_bind_group {
84        render_pass.set_bind_group(1, depth_bind_group, &[]);
85    }
86    render_pass.draw(0..3, 0..1);
87
88    pass_span.end(&mut render_pass);
89}