Path: blob/main/crates/bevy_pbr/src/meshlet/visibility_buffer_raster_node.rs
6600 views
use super::{1pipelines::MeshletPipelines,2resource_manager::{MeshletViewBindGroups, MeshletViewResources},3};4use crate::{5meshlet::resource_manager::ResourceManager, LightEntity, ShadowView, ViewLightEntities,6};7use bevy_color::LinearRgba;8use bevy_core_pipeline::prepass::PreviousViewUniformOffset;9use bevy_ecs::{10query::QueryState,11world::{FromWorld, World},12};13use bevy_math::UVec2;14use bevy_render::{15camera::ExtractedCamera,16diagnostic::RecordDiagnostics,17render_graph::{Node, NodeRunError, RenderGraphContext},18render_resource::*,19renderer::RenderContext,20view::{ViewDepthTexture, ViewUniformOffset},21};2223/// Rasterize meshlets into a depth buffer, and optional visibility buffer + material depth buffer for shading passes.24pub struct MeshletVisibilityBufferRasterPassNode {25main_view_query: QueryState<(26&'static ExtractedCamera,27&'static ViewDepthTexture,28&'static ViewUniformOffset,29&'static PreviousViewUniformOffset,30&'static MeshletViewBindGroups,31&'static MeshletViewResources,32&'static ViewLightEntities,33)>,34view_light_query: QueryState<(35&'static ShadowView,36&'static LightEntity,37&'static ViewUniformOffset,38&'static PreviousViewUniformOffset,39&'static MeshletViewBindGroups,40&'static MeshletViewResources,41)>,42}4344impl FromWorld for MeshletVisibilityBufferRasterPassNode {45fn from_world(world: &mut World) -> Self {46Self {47main_view_query: QueryState::new(world),48view_light_query: QueryState::new(world),49}50}51}5253impl Node for MeshletVisibilityBufferRasterPassNode {54fn update(&mut self, world: &mut World) {55self.main_view_query.update_archetypes(world);56self.view_light_query.update_archetypes(world);57}5859// TODO: Reuse compute/render passes between logical passes where possible, as they're expensive60fn run(61&self,62graph: &mut RenderGraphContext,63render_context: &mut RenderContext,64world: &World,65) -> Result<(), NodeRunError> {66let Ok((67camera,68view_depth,69view_offset,70previous_view_offset,71meshlet_view_bind_groups,72meshlet_view_resources,73lights,74)) = self.main_view_query.get_manual(world, graph.view_entity())75else {76return Ok(());77};7879let Some((80clear_visibility_buffer_pipeline,81clear_visibility_buffer_shadow_view_pipeline,82first_instance_cull_pipeline,83second_instance_cull_pipeline,84first_bvh_cull_pipeline,85second_bvh_cull_pipeline,86first_meshlet_cull_pipeline,87second_meshlet_cull_pipeline,88downsample_depth_first_pipeline,89downsample_depth_second_pipeline,90downsample_depth_first_shadow_view_pipeline,91downsample_depth_second_shadow_view_pipeline,92visibility_buffer_software_raster_pipeline,93visibility_buffer_software_raster_shadow_view_pipeline,94visibility_buffer_hardware_raster_pipeline,95visibility_buffer_hardware_raster_shadow_view_pipeline,96visibility_buffer_hardware_raster_shadow_view_unclipped_pipeline,97resolve_depth_pipeline,98resolve_depth_shadow_view_pipeline,99resolve_material_depth_pipeline,100remap_1d_to_2d_dispatch_pipeline,101fill_counts_pipeline,102)) = MeshletPipelines::get(world)103else {104return Ok(());105};106107let diagnostics = render_context.diagnostic_recorder();108109render_context110.command_encoder()111.push_debug_group("meshlet_visibility_buffer_raster");112let time_span = diagnostics.time_span(113render_context.command_encoder(),114"meshlet_visibility_buffer_raster",115);116117let resource_manager = world.get_resource::<ResourceManager>().unwrap();118render_context.command_encoder().clear_buffer(119&resource_manager.visibility_buffer_raster_cluster_prev_counts,1200,121None,122);123124clear_visibility_buffer_pass(125render_context,126&meshlet_view_bind_groups.clear_visibility_buffer,127clear_visibility_buffer_pipeline,128meshlet_view_resources.view_size,129);130131render_context132.command_encoder()133.push_debug_group("meshlet_first_pass");134first_cull(135render_context,136meshlet_view_bind_groups,137meshlet_view_resources,138view_offset,139previous_view_offset,140first_instance_cull_pipeline,141first_bvh_cull_pipeline,142first_meshlet_cull_pipeline,143remap_1d_to_2d_dispatch_pipeline,144);145raster_pass(146true,147render_context,148&meshlet_view_resources.visibility_buffer_software_raster_indirect_args,149&meshlet_view_resources.visibility_buffer_hardware_raster_indirect_args,150&meshlet_view_resources.dummy_render_target.default_view,151meshlet_view_bind_groups,152view_offset,153visibility_buffer_software_raster_pipeline,154visibility_buffer_hardware_raster_pipeline,155fill_counts_pipeline,156Some(camera),157meshlet_view_resources.rightmost_slot,158);159render_context.command_encoder().pop_debug_group();160161meshlet_view_resources.depth_pyramid.downsample_depth(162"downsample_depth",163render_context,164meshlet_view_resources.view_size,165&meshlet_view_bind_groups.downsample_depth,166downsample_depth_first_pipeline,167downsample_depth_second_pipeline,168);169170render_context171.command_encoder()172.push_debug_group("meshlet_second_pass");173second_cull(174render_context,175meshlet_view_bind_groups,176meshlet_view_resources,177view_offset,178previous_view_offset,179second_instance_cull_pipeline,180second_bvh_cull_pipeline,181second_meshlet_cull_pipeline,182remap_1d_to_2d_dispatch_pipeline,183);184raster_pass(185false,186render_context,187&meshlet_view_resources.visibility_buffer_software_raster_indirect_args,188&meshlet_view_resources.visibility_buffer_hardware_raster_indirect_args,189&meshlet_view_resources.dummy_render_target.default_view,190meshlet_view_bind_groups,191view_offset,192visibility_buffer_software_raster_pipeline,193visibility_buffer_hardware_raster_pipeline,194fill_counts_pipeline,195Some(camera),196meshlet_view_resources.rightmost_slot,197);198render_context.command_encoder().pop_debug_group();199200resolve_depth(201render_context,202view_depth.get_attachment(StoreOp::Store),203meshlet_view_bind_groups,204resolve_depth_pipeline,205camera,206);207resolve_material_depth(208render_context,209meshlet_view_resources,210meshlet_view_bind_groups,211resolve_material_depth_pipeline,212camera,213);214meshlet_view_resources.depth_pyramid.downsample_depth(215"downsample_depth",216render_context,217meshlet_view_resources.view_size,218&meshlet_view_bind_groups.downsample_depth,219downsample_depth_first_pipeline,220downsample_depth_second_pipeline,221);222render_context.command_encoder().pop_debug_group();223224for light_entity in &lights.lights {225let Ok((226shadow_view,227light_type,228view_offset,229previous_view_offset,230meshlet_view_bind_groups,231meshlet_view_resources,232)) = self.view_light_query.get_manual(world, *light_entity)233else {234continue;235};236237let shadow_visibility_buffer_hardware_raster_pipeline =238if let LightEntity::Directional { .. } = light_type {239visibility_buffer_hardware_raster_shadow_view_unclipped_pipeline240} else {241visibility_buffer_hardware_raster_shadow_view_pipeline242};243244render_context.command_encoder().push_debug_group(&format!(245"meshlet_visibility_buffer_raster: {}",246shadow_view.pass_name247));248let pass_span = diagnostics.time_span(249render_context.command_encoder(),250shadow_view.pass_name.clone(),251);252clear_visibility_buffer_pass(253render_context,254&meshlet_view_bind_groups.clear_visibility_buffer,255clear_visibility_buffer_shadow_view_pipeline,256meshlet_view_resources.view_size,257);258259render_context260.command_encoder()261.push_debug_group("meshlet_first_pass");262first_cull(263render_context,264meshlet_view_bind_groups,265meshlet_view_resources,266view_offset,267previous_view_offset,268first_instance_cull_pipeline,269first_bvh_cull_pipeline,270first_meshlet_cull_pipeline,271remap_1d_to_2d_dispatch_pipeline,272);273raster_pass(274true,275render_context,276&meshlet_view_resources.visibility_buffer_software_raster_indirect_args,277&meshlet_view_resources.visibility_buffer_hardware_raster_indirect_args,278&meshlet_view_resources.dummy_render_target.default_view,279meshlet_view_bind_groups,280view_offset,281visibility_buffer_software_raster_shadow_view_pipeline,282shadow_visibility_buffer_hardware_raster_pipeline,283fill_counts_pipeline,284None,285meshlet_view_resources.rightmost_slot,286);287render_context.command_encoder().pop_debug_group();288289meshlet_view_resources.depth_pyramid.downsample_depth(290"downsample_depth",291render_context,292meshlet_view_resources.view_size,293&meshlet_view_bind_groups.downsample_depth,294downsample_depth_first_shadow_view_pipeline,295downsample_depth_second_shadow_view_pipeline,296);297298render_context299.command_encoder()300.push_debug_group("meshlet_second_pass");301second_cull(302render_context,303meshlet_view_bind_groups,304meshlet_view_resources,305view_offset,306previous_view_offset,307second_instance_cull_pipeline,308second_bvh_cull_pipeline,309second_meshlet_cull_pipeline,310remap_1d_to_2d_dispatch_pipeline,311);312raster_pass(313false,314render_context,315&meshlet_view_resources.visibility_buffer_software_raster_indirect_args,316&meshlet_view_resources.visibility_buffer_hardware_raster_indirect_args,317&meshlet_view_resources.dummy_render_target.default_view,318meshlet_view_bind_groups,319view_offset,320visibility_buffer_software_raster_shadow_view_pipeline,321shadow_visibility_buffer_hardware_raster_pipeline,322fill_counts_pipeline,323None,324meshlet_view_resources.rightmost_slot,325);326render_context.command_encoder().pop_debug_group();327328resolve_depth(329render_context,330shadow_view.depth_attachment.get_attachment(StoreOp::Store),331meshlet_view_bind_groups,332resolve_depth_shadow_view_pipeline,333camera,334);335meshlet_view_resources.depth_pyramid.downsample_depth(336"downsample_depth",337render_context,338meshlet_view_resources.view_size,339&meshlet_view_bind_groups.downsample_depth,340downsample_depth_first_shadow_view_pipeline,341downsample_depth_second_shadow_view_pipeline,342);343render_context.command_encoder().pop_debug_group();344pass_span.end(render_context.command_encoder());345}346347time_span.end(render_context.command_encoder());348349Ok(())350}351}352353// TODO: Replace this with vkCmdClearColorImage once wgpu supports it354fn clear_visibility_buffer_pass(355render_context: &mut RenderContext,356clear_visibility_buffer_bind_group: &BindGroup,357clear_visibility_buffer_pipeline: &ComputePipeline,358view_size: UVec2,359) {360let command_encoder = render_context.command_encoder();361let mut clear_visibility_buffer_pass =362command_encoder.begin_compute_pass(&ComputePassDescriptor {363label: Some("clear_visibility_buffer"),364timestamp_writes: None,365});366clear_visibility_buffer_pass.set_pipeline(clear_visibility_buffer_pipeline);367clear_visibility_buffer_pass.set_push_constants(0, bytemuck::bytes_of(&view_size));368clear_visibility_buffer_pass.set_bind_group(0, clear_visibility_buffer_bind_group, &[]);369clear_visibility_buffer_pass.dispatch_workgroups(370view_size.x.div_ceil(16),371view_size.y.div_ceil(16),3721,373);374}375376fn first_cull(377render_context: &mut RenderContext,378meshlet_view_bind_groups: &MeshletViewBindGroups,379meshlet_view_resources: &MeshletViewResources,380view_offset: &ViewUniformOffset,381previous_view_offset: &PreviousViewUniformOffset,382first_instance_cull_pipeline: &ComputePipeline,383first_bvh_cull_pipeline: &ComputePipeline,384first_meshlet_cull_pipeline: &ComputePipeline,385remap_1d_to_2d_pipeline: Option<&ComputePipeline>,386) {387let workgroups = meshlet_view_resources.scene_instance_count.div_ceil(128);388cull_pass(389"meshlet_first_instance_cull",390render_context,391&meshlet_view_bind_groups.first_instance_cull,392view_offset,393previous_view_offset,394first_instance_cull_pipeline,395&[meshlet_view_resources.scene_instance_count],396)397.dispatch_workgroups(workgroups, 1, 1);398399render_context400.command_encoder()401.push_debug_group("meshlet_first_bvh_cull");402let mut ping = true;403for _ in 0..meshlet_view_resources.max_bvh_depth {404cull_pass(405"meshlet_first_bvh_cull_dispatch",406render_context,407if ping {408&meshlet_view_bind_groups.first_bvh_cull_ping409} else {410&meshlet_view_bind_groups.first_bvh_cull_pong411},412view_offset,413previous_view_offset,414first_bvh_cull_pipeline,415&[ping as u32, meshlet_view_resources.rightmost_slot],416)417.dispatch_workgroups_indirect(418if ping {419&meshlet_view_resources.first_bvh_cull_dispatch_front420} else {421&meshlet_view_resources.first_bvh_cull_dispatch_back422},4230,424);425render_context.command_encoder().clear_buffer(426if ping {427&meshlet_view_resources.first_bvh_cull_count_front428} else {429&meshlet_view_resources.first_bvh_cull_count_back430},4310,432Some(4),433);434render_context.command_encoder().clear_buffer(435if ping {436&meshlet_view_resources.first_bvh_cull_dispatch_front437} else {438&meshlet_view_resources.first_bvh_cull_dispatch_back439},4400,441Some(4),442);443ping = !ping;444}445render_context.command_encoder().pop_debug_group();446447let mut pass = cull_pass(448"meshlet_first_meshlet_cull",449render_context,450&meshlet_view_bind_groups.first_meshlet_cull,451view_offset,452previous_view_offset,453first_meshlet_cull_pipeline,454&[meshlet_view_resources.rightmost_slot],455);456pass.dispatch_workgroups_indirect(&meshlet_view_resources.front_meshlet_cull_dispatch, 0);457remap_1d_to_2d(458pass,459remap_1d_to_2d_pipeline,460meshlet_view_bind_groups.remap_1d_to_2d_dispatch.as_ref(),461);462}463464fn second_cull(465render_context: &mut RenderContext,466meshlet_view_bind_groups: &MeshletViewBindGroups,467meshlet_view_resources: &MeshletViewResources,468view_offset: &ViewUniformOffset,469previous_view_offset: &PreviousViewUniformOffset,470second_instance_cull_pipeline: &ComputePipeline,471second_bvh_cull_pipeline: &ComputePipeline,472second_meshlet_cull_pipeline: &ComputePipeline,473remap_1d_to_2d_pipeline: Option<&ComputePipeline>,474) {475cull_pass(476"meshlet_second_instance_cull",477render_context,478&meshlet_view_bind_groups.second_instance_cull,479view_offset,480previous_view_offset,481second_instance_cull_pipeline,482&[meshlet_view_resources.scene_instance_count],483)484.dispatch_workgroups_indirect(&meshlet_view_resources.second_pass_dispatch, 0);485486render_context487.command_encoder()488.push_debug_group("meshlet_second_bvh_cull");489let mut ping = true;490for _ in 0..meshlet_view_resources.max_bvh_depth {491cull_pass(492"meshlet_second_bvh_cull_dispatch",493render_context,494if ping {495&meshlet_view_bind_groups.second_bvh_cull_ping496} else {497&meshlet_view_bind_groups.second_bvh_cull_pong498},499view_offset,500previous_view_offset,501second_bvh_cull_pipeline,502&[ping as u32, meshlet_view_resources.rightmost_slot],503)504.dispatch_workgroups_indirect(505if ping {506&meshlet_view_resources.second_bvh_cull_dispatch_front507} else {508&meshlet_view_resources.second_bvh_cull_dispatch_back509},5100,511);512ping = !ping;513}514render_context.command_encoder().pop_debug_group();515516let mut pass = cull_pass(517"meshlet_second_meshlet_cull",518render_context,519&meshlet_view_bind_groups.second_meshlet_cull,520view_offset,521previous_view_offset,522second_meshlet_cull_pipeline,523&[meshlet_view_resources.rightmost_slot],524);525pass.dispatch_workgroups_indirect(&meshlet_view_resources.back_meshlet_cull_dispatch, 0);526remap_1d_to_2d(527pass,528remap_1d_to_2d_pipeline,529meshlet_view_bind_groups.remap_1d_to_2d_dispatch.as_ref(),530);531}532533fn cull_pass<'a>(534label: &'static str,535render_context: &'a mut RenderContext,536bind_group: &'a BindGroup,537view_offset: &'a ViewUniformOffset,538previous_view_offset: &'a PreviousViewUniformOffset,539pipeline: &'a ComputePipeline,540push_constants: &[u32],541) -> ComputePass<'a> {542let command_encoder = render_context.command_encoder();543let mut pass = command_encoder.begin_compute_pass(&ComputePassDescriptor {544label: Some(label),545timestamp_writes: None,546});547pass.set_pipeline(pipeline);548pass.set_bind_group(5490,550bind_group,551&[view_offset.offset, previous_view_offset.offset],552);553pass.set_push_constants(0, bytemuck::cast_slice(push_constants));554pass555}556557fn remap_1d_to_2d(558mut pass: ComputePass,559pipeline: Option<&ComputePipeline>,560bind_group: Option<&BindGroup>,561) {562if let (Some(pipeline), Some(bind_group)) = (pipeline, bind_group) {563pass.set_pipeline(pipeline);564pass.set_bind_group(0, bind_group, &[]);565pass.dispatch_workgroups(1, 1, 1);566}567}568569fn raster_pass(570first_pass: bool,571render_context: &mut RenderContext,572visibility_buffer_software_raster_indirect_args: &Buffer,573visibility_buffer_hardware_raster_indirect_args: &Buffer,574dummy_render_target: &TextureView,575meshlet_view_bind_groups: &MeshletViewBindGroups,576view_offset: &ViewUniformOffset,577visibility_buffer_software_raster_pipeline: &ComputePipeline,578visibility_buffer_hardware_raster_pipeline: &RenderPipeline,579fill_counts_pipeline: &ComputePipeline,580camera: Option<&ExtractedCamera>,581raster_cluster_rightmost_slot: u32,582) {583let mut software_pass =584render_context585.command_encoder()586.begin_compute_pass(&ComputePassDescriptor {587label: Some(if first_pass {588"raster_software_first"589} else {590"raster_software_second"591}),592timestamp_writes: None,593});594software_pass.set_pipeline(visibility_buffer_software_raster_pipeline);595software_pass.set_bind_group(5960,597&meshlet_view_bind_groups.visibility_buffer_raster,598&[view_offset.offset],599);600software_pass.dispatch_workgroups_indirect(visibility_buffer_software_raster_indirect_args, 0);601drop(software_pass);602603let mut hardware_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {604label: Some(if first_pass {605"raster_hardware_first"606} else {607"raster_hardware_second"608}),609color_attachments: &[Some(RenderPassColorAttachment {610view: dummy_render_target,611depth_slice: None,612resolve_target: None,613ops: Operations {614load: LoadOp::Clear(LinearRgba::BLACK.into()),615store: StoreOp::Discard,616},617})],618depth_stencil_attachment: None,619timestamp_writes: None,620occlusion_query_set: None,621});622if let Some(viewport) = camera.and_then(|camera| camera.viewport.as_ref()) {623hardware_pass.set_camera_viewport(viewport);624}625hardware_pass.set_render_pipeline(visibility_buffer_hardware_raster_pipeline);626hardware_pass.set_push_constants(627ShaderStages::VERTEX,6280,629&raster_cluster_rightmost_slot.to_le_bytes(),630);631hardware_pass.set_bind_group(6320,633&meshlet_view_bind_groups.visibility_buffer_raster,634&[view_offset.offset],635);636hardware_pass.draw_indirect(visibility_buffer_hardware_raster_indirect_args, 0);637drop(hardware_pass);638639let mut fill_counts_pass =640render_context641.command_encoder()642.begin_compute_pass(&ComputePassDescriptor {643label: Some("fill_counts"),644timestamp_writes: None,645});646fill_counts_pass.set_pipeline(fill_counts_pipeline);647fill_counts_pass.set_bind_group(0, &meshlet_view_bind_groups.fill_counts, &[]);648fill_counts_pass.dispatch_workgroups(1, 1, 1);649}650651fn resolve_depth(652render_context: &mut RenderContext,653depth_stencil_attachment: RenderPassDepthStencilAttachment,654meshlet_view_bind_groups: &MeshletViewBindGroups,655resolve_depth_pipeline: &RenderPipeline,656camera: &ExtractedCamera,657) {658let mut resolve_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {659label: Some("resolve_depth"),660color_attachments: &[],661depth_stencil_attachment: Some(depth_stencil_attachment),662timestamp_writes: None,663occlusion_query_set: None,664});665if let Some(viewport) = &camera.viewport {666resolve_pass.set_camera_viewport(viewport);667}668resolve_pass.set_render_pipeline(resolve_depth_pipeline);669resolve_pass.set_bind_group(0, &meshlet_view_bind_groups.resolve_depth, &[]);670resolve_pass.draw(0..3, 0..1);671}672673fn resolve_material_depth(674render_context: &mut RenderContext,675meshlet_view_resources: &MeshletViewResources,676meshlet_view_bind_groups: &MeshletViewBindGroups,677resolve_material_depth_pipeline: &RenderPipeline,678camera: &ExtractedCamera,679) {680if let (Some(material_depth), Some(resolve_material_depth_bind_group)) = (681meshlet_view_resources.material_depth.as_ref(),682meshlet_view_bind_groups.resolve_material_depth.as_ref(),683) {684let mut resolve_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {685label: Some("resolve_material_depth"),686color_attachments: &[],687depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {688view: &material_depth.default_view,689depth_ops: Some(Operations {690load: LoadOp::Clear(0.0),691store: StoreOp::Store,692}),693stencil_ops: None,694}),695timestamp_writes: None,696occlusion_query_set: None,697});698if let Some(viewport) = &camera.viewport {699resolve_pass.set_camera_viewport(viewport);700}701resolve_pass.set_render_pipeline(resolve_material_depth_pipeline);702resolve_pass.set_bind_group(0, resolve_material_depth_bind_group, &[]);703resolve_pass.draw(0..3, 0..1);704}705}706707708