diff --git a/crates/bevy_core_pipeline/src/fullscreen_material.rs b/crates/bevy_core_pipeline/src/fullscreen_material.rs index 1b1b47fd8a4af..1bcad43ebe18b 100644 --- a/crates/bevy_core_pipeline/src/fullscreen_material.rs +++ b/crates/bevy_core_pipeline/src/fullscreen_material.rs @@ -17,10 +17,11 @@ use bevy_ecs::{ query::With, resource::Resource, schedule::{IntoScheduleConfigs, ScheduleConfigs, ScheduleLabel}, - system::{BoxedSystem, Commands, Query, Res, ResMut}, + system::{BoxedSystem, Commands, Local, Query, Res, ResMut}, }; use bevy_render::{ camera::ExtractedCamera, + diagnostic::RecordDiagnostics, extract_component::{ ComponentUniforms, DynamicUniformIndex, ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin, @@ -295,6 +296,7 @@ pub fn fullscreen_material_system( )>, pipeline_cache: Res, mut ctx: RenderContext, + mut pass_label: Local, ) { let (view_target, settings_index, bind_groups, pipeline_id) = view.into_inner(); @@ -308,8 +310,11 @@ pub fn fullscreen_material_system( let bind_group = bind_groups.cache.get_current_bind_group(source); + if pass_label.is_empty() { + *pass_label = format!("fullscreen_material_pass<{}>", type_name::()); + } let pass_descriptor = RenderPassDescriptor { - label: Some("fullscreen_material_pass"), + label: Some(&pass_label), color_attachments: &[Some(RenderPassColorAttachment { view: destination, depth_slice: None, @@ -323,9 +328,15 @@ pub fn fullscreen_material_system( }; { + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let mut render_pass = ctx.command_encoder().begin_render_pass(&pass_descriptor); + let pass_span = diagnostics.pass_span(&mut render_pass, pass_label.clone()); + render_pass.set_pipeline(pipeline); render_pass.set_bind_group(0, bind_group, &[settings_index.index()]); render_pass.draw(0..3, 0..1); + pass_span.end(&mut render_pass); } } diff --git a/crates/bevy_core_pipeline/src/mip_generation/experimental/depth.rs b/crates/bevy_core_pipeline/src/mip_generation/experimental/depth.rs index 162d3e947c0af..5704aa1cf3d19 100644 --- a/crates/bevy_core_pipeline/src/mip_generation/experimental/depth.rs +++ b/crates/bevy_core_pipeline/src/mip_generation/experimental/depth.rs @@ -21,6 +21,7 @@ use bevy_log::debug; use bevy_math::{uvec2, UVec2, Vec4Swizzles as _}; use bevy_render::{ batching::gpu_preprocessing::GpuPreprocessingSupport, + diagnostic::RecordDiagnostics, occlusion_culling::{ OcclusionCulling, OcclusionCullingSubview, OcclusionCullingSubviewEntities, }, @@ -87,6 +88,13 @@ pub fn early_downsample_depth( maybe_view_light_entities, ) = view.into_inner(); + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let time_span = diagnostics.time_span( + ctx.command_encoder(), + "mip_generation::early_downsample_depth", + ); + // Downsample depth for the main Z-buffer. downsample_depth( "early_downsample_depth", @@ -122,6 +130,7 @@ pub fn early_downsample_depth( ); } } + time_span.end(ctx.command_encoder()); } /// Produces a hierarchical Z-buffer (depth pyramid) for occlusion culling. diff --git a/crates/bevy_core_pipeline/src/schedule.rs b/crates/bevy_core_pipeline/src/schedule.rs index 24bc97650ea7b..e1d889445f63f 100644 --- a/crates/bevy_core_pipeline/src/schedule.rs +++ b/crates/bevy_core_pipeline/src/schedule.rs @@ -23,6 +23,7 @@ use bevy_log::info_span; use bevy_reflect::Reflect; use bevy_render::{ camera::{ExtractedCamera, SortedCameras}, + diagnostic::{DiagnosticsRecorder, RecordDiagnostics}, render_resource::{ CommandEncoderDescriptor, LoadOp, Operations, RenderPassColorAttachment, RenderPassDescriptor, StoreOp, @@ -152,6 +153,33 @@ pub fn camera_driver( let mut camera_windows = EntityHashSet::default(); + let diagnostics_enabled = world.contains_resource::(); + let mut reached_root_camera = false; + if diagnostics_enabled { + let device = world.resource::().clone(); + let mut encoder = device.create_command_encoder(&CommandEncoderDescriptor { + label: Some("camera_driver_diagnostic_span"), + }); + world + .resource::() + .begin_time_span(&mut encoder, "auxiliary_views".into()); + world + .resource_mut::() + .push_encoder(encoder, "camera_driver_span_begin"); + } + let end_time_span = |world: &mut World| { + let device = world.resource::().clone(); + let mut encoder = device.create_command_encoder(&CommandEncoderDescriptor { + label: Some("camera_driver_diagnostic_span"), + }); + world + .resource::() + .end_time_span(&mut encoder); + world + .resource_mut::() + .push_encoder(encoder, "camera_driver_span_end"); + }; + for root_view in root_views { let mut run_schedule = true; let (schedule, view_entity); @@ -161,6 +189,10 @@ pub fn camera_driver( entity: camera_entity, .. } => { + if diagnostics_enabled && !reached_root_camera { + reached_root_camera = true; + end_time_span(world); + } let Some(camera) = world.get::(camera_entity) else { continue; }; @@ -206,6 +238,10 @@ pub fn camera_driver( world.run_schedule(schedule); } } + if diagnostics_enabled && !reached_root_camera { + end_time_span(world); + } + world.remove_resource::(); world.insert_resource(CameraWindows(camera_windows)); diff --git a/crates/bevy_pbr/src/atmosphere/environment.rs b/crates/bevy_pbr/src/atmosphere/environment.rs index 43944c5299da6..7137f1c8e2e76 100644 --- a/crates/bevy_pbr/src/atmosphere/environment.rs +++ b/crates/bevy_pbr/src/atmosphere/environment.rs @@ -18,6 +18,7 @@ use bevy_image::Image; use bevy_light::{AtmosphereEnvironmentMapLight, GeneratedEnvironmentMapLight}; use bevy_math::{Quat, UVec2}; use bevy_render::{ + diagnostic::RecordDiagnostics, extract_component::{ComponentUniforms, DynamicUniformIndex, ExtractComponent}, render_asset::RenderAssets, render_resource::{binding_types::*, *}, @@ -270,6 +271,10 @@ pub fn atmosphere_environment( lights_uniforms_offset, ) = view.into_inner(); + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let time_span = diagnostics.time_span(ctx.command_encoder(), "atmosphere_environment"); + for (bind_groups, env_map_light) in probe_query.iter() { let command_encoder = ctx.command_encoder(); let mut pass = command_encoder.begin_compute_pass(&ComputePassDescriptor { @@ -296,4 +301,6 @@ pub fn atmosphere_environment( 6, // 6 cubemap faces ); } + + time_span.end(ctx.command_encoder()); } diff --git a/crates/bevy_pbr/src/atmosphere/node.rs b/crates/bevy_pbr/src/atmosphere/node.rs index 8a531e743b7e5..196e31e96f68f 100644 --- a/crates/bevy_pbr/src/atmosphere/node.rs +++ b/crates/bevy_pbr/src/atmosphere/node.rs @@ -3,6 +3,7 @@ use bevy_ecs::system::Res; use bevy_math::{UVec2, Vec3Swizzles}; use bevy_render::{ camera::ExtractedCamera, + diagnostic::RecordDiagnostics, extract_component::DynamicUniformIndex, render_resource::{ComputePass, ComputePassDescriptor, PipelineCache, RenderPassDescriptor}, renderer::{RenderContext, ViewQuery}, @@ -58,12 +59,16 @@ pub fn atmosphere_luts( return; }; + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let command_encoder = ctx.command_encoder(); let mut luts_pass = command_encoder.begin_compute_pass(&ComputePassDescriptor { label: Some("atmosphere_luts"), timestamp_writes: None, }); + let pass_span = diagnostics.pass_span(&mut luts_pass, "atmosphere_luts"); fn dispatch_2d(compute_pass: &mut ComputePass, size: UVec2) { const WORKGROUP_SIZE: u32 = 16; @@ -136,6 +141,7 @@ pub fn atmosphere_luts( ); dispatch_2d(&mut luts_pass, settings.aerial_view_lut_size.xy()); + pass_span.end(&mut luts_pass); } pub fn render_sky( @@ -172,6 +178,9 @@ pub fn render_sky( return; }; //TODO: warning + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let command_encoder = ctx.command_encoder(); let mut render_sky_pass = command_encoder.begin_render_pass(&RenderPassDescriptor { @@ -182,6 +191,7 @@ pub fn render_sky( occlusion_query_set: None, multiview_mask: None, }); + let pass_span = diagnostics.pass_span(&mut render_sky_pass, "render_sky"); if let Some(viewport) = Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override) @@ -209,4 +219,5 @@ pub fn render_sky( ], ); render_sky_pass.draw(0..3, 0..1); + pass_span.end(&mut render_sky_pass); } diff --git a/crates/bevy_pbr/src/deferred/mod.rs b/crates/bevy_pbr/src/deferred/mod.rs index 9559a148f883e..e3cdd8186a064 100644 --- a/crates/bevy_pbr/src/deferred/mod.rs +++ b/crates/bevy_pbr/src/deferred/mod.rs @@ -16,6 +16,7 @@ use bevy_core_pipeline::{ use bevy_ecs::prelude::*; use bevy_render::{ camera::ExtractedCamera, + diagnostic::RecordDiagnostics, extract_component::{ ComponentUniforms, ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin, }, @@ -148,6 +149,9 @@ pub fn deferred_lighting( return; }; + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let bind_group_2 = ctx.render_device().create_bind_group( "deferred_lighting_layout_group_2", &pipeline_cache.get_bind_group_layout(&deferred_lighting_layout.bind_group_layout_2), @@ -169,6 +173,7 @@ pub fn deferred_lighting( occlusion_query_set: None, multiview_mask: None, }); + let pass_span = diagnostics.pass_span(&mut render_pass, "deferred_lighting"); render_pass.set_render_pipeline(pipeline); @@ -180,6 +185,7 @@ pub fn deferred_lighting( render_pass.set_bind_group(1, &mesh_view_bind_group.binding_array, &[]); render_pass.set_bind_group(2, &bind_group_2, &[]); render_pass.draw(0..3, 0..1); + pass_span.end(&mut render_pass); } #[derive(Resource)] diff --git a/crates/bevy_pbr/src/meshlet/material_shade_nodes.rs b/crates/bevy_pbr/src/meshlet/material_shade_nodes.rs index 6cf224c434871..67a4065ef4794 100644 --- a/crates/bevy_pbr/src/meshlet/material_shade_nodes.rs +++ b/crates/bevy_pbr/src/meshlet/material_shade_nodes.rs @@ -15,6 +15,7 @@ use bevy_core_pipeline::prepass::{ use bevy_ecs::{prelude::*, query::Has}; use bevy_render::{ camera::ExtractedCamera, + diagnostic::RecordDiagnostics, render_resource::{ LoadOp, Operations, PipelineCache, RenderPassDepthStencilAttachment, RenderPassDescriptor, StoreOp, @@ -60,6 +61,9 @@ pub fn meshlet_main_opaque_pass( return; }; + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let mut render_pass = ctx.begin_tracked_render_pass(RenderPassDescriptor { label: Some("meshlet_material_opaque_3d_pass"), color_attachments: &[Some(target.get_color_attachment())], @@ -75,6 +79,7 @@ pub fn meshlet_main_opaque_pass( occlusion_query_set: None, multiview_mask: None, }); + let pass_span = diagnostics.pass_span(&mut render_pass, "meshlet_material_opaque_3d_pass"); if let Some(viewport) = Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override) @@ -102,6 +107,7 @@ pub fn meshlet_main_opaque_pass( render_pass.draw(x..(x + 3), 0..1); } } + pass_span.end(&mut render_pass); } /// @@ -160,6 +166,9 @@ pub fn meshlet_prepass( None, ]; + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let mut render_pass = ctx.begin_tracked_render_pass(RenderPassDescriptor { label: Some("meshlet_material_prepass"), color_attachments: &color_attachments, @@ -175,6 +184,7 @@ pub fn meshlet_prepass( occlusion_query_set: None, multiview_mask: None, }); + let pass_span = diagnostics.pass_span(&mut render_pass, "meshlet_material_prepass"); if let Some(viewport) = Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override) @@ -214,6 +224,8 @@ pub fn meshlet_prepass( render_pass.draw(x..(x + 3), 0..1); } } + + pass_span.end(&mut render_pass); } /// Fullscreen pass to generate a gbuffer based on the visibility buffer generated from rasterizing meshlets. @@ -276,6 +288,9 @@ pub fn meshlet_deferred_gbuffer_prepass( .map(|deferred_lighting_pass_id| deferred_lighting_pass_id.get_attachment()), ]; + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let mut render_pass = ctx.begin_tracked_render_pass(RenderPassDescriptor { label: Some("meshlet_material_deferred_prepass"), color_attachments: &color_attachments, @@ -291,6 +306,7 @@ pub fn meshlet_deferred_gbuffer_prepass( occlusion_query_set: None, multiview_mask: None, }); + let pass_span = diagnostics.pass_span(&mut render_pass, "meshlet_material_deferred_prepass"); if let Some(viewport) = Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override) @@ -330,4 +346,6 @@ pub fn meshlet_deferred_gbuffer_prepass( render_pass.draw(x..(x + 3), 0..1); } } + + pass_span.end(&mut render_pass); } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index ace5aad0c95d4..4ec60e58d92b8 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -43,6 +43,7 @@ use bevy_render::batching::gpu_preprocessing::{ BuildIndirectParametersMetadata, IndirectParametersBuffers, }; use bevy_render::camera::{DirtySpecializations, PendingQueues}; +use bevy_render::diagnostic::RecordDiagnostics; use bevy_render::erased_render_asset::ErasedRenderAssets; use bevy_render::mesh::allocator::MeshSlabs; use bevy_render::occlusion_culling::{ @@ -2929,6 +2930,10 @@ pub fn per_view_shadow_pass( ) { let view_lights = view.into_inner(); + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let time_span = diagnostics.time_span(ctx.command_encoder(), "per_view_shadow_pass"); + for view_light_entity in view_lights.lights.iter().copied() { let Ok(( view_light, @@ -2982,6 +2987,8 @@ pub fn per_view_shadow_pass( &mut ctx, ); } + + time_span.end(ctx.command_encoder()); } /// A common helper function to render a shadow map. diff --git a/crates/bevy_pbr/src/volumetric_fog/render.rs b/crates/bevy_pbr/src/volumetric_fog/render.rs index 97a5aef0153e5..915155bab6b5a 100644 --- a/crates/bevy_pbr/src/volumetric_fog/render.rs +++ b/crates/bevy_pbr/src/volumetric_fog/render.rs @@ -18,6 +18,7 @@ use bevy_light::{FogVolume, VolumetricFog, VolumetricLight}; use bevy_math::{vec4, Affine3A, Mat4, Vec3, Vec3A, Vec4}; use bevy_mesh::{Mesh, MeshVertexBufferLayoutRef}; use bevy_render::{ + diagnostic::RecordDiagnostics, mesh::{allocator::MeshAllocator, RenderMesh, RenderMeshBufferInfo}, render_asset::RenderAssets, render_resource::{ @@ -320,6 +321,10 @@ pub fn volumetric_fog( return; }; + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let time_span = diagnostics.time_span(ctx.command_encoder(), "volumetric_lighting"); + let command_encoder = ctx.command_encoder(); command_encoder.push_debug_group("volumetric_lighting"); @@ -329,6 +334,7 @@ pub fn volumetric_fog( .depth_stencil_views() .depth_only_view() else { + time_span.end(ctx.command_encoder()); return; }; @@ -360,6 +366,7 @@ pub fn volumetric_fog( // This should always succeed, but if the asset was unloaded don't // panic. let Some(render_mesh) = render_meshes.get(&mesh_handle) else { + time_span.end(ctx.command_encoder()); return; }; @@ -451,6 +458,7 @@ pub fn volumetric_fog( } ctx.command_encoder().pop_debug_group(); + time_span.end(ctx.command_encoder()); } impl SpecializedRenderPipeline for VolumetricFogPipeline { diff --git a/crates/bevy_post_process/src/dof/mod.rs b/crates/bevy_post_process/src/dof/mod.rs index 4ac7183f28a6e..6145c972f896d 100644 --- a/crates/bevy_post_process/src/dof/mod.rs +++ b/crates/bevy_post_process/src/dof/mod.rs @@ -31,6 +31,7 @@ use bevy_math::ops; use bevy_reflect::{prelude::ReflectDefault, Reflect}; use bevy_render::{ camera::ExtractedCamera, + diagnostic::RecordDiagnostics, extract_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin}, render_resource::{ binding_types::{ @@ -791,6 +792,10 @@ pub(crate) fn depth_of_field( else { return; }; + let diagnostics = ctx.diagnostic_recorder(); + let diagnostics = diagnostics.as_deref(); + let time_span = diagnostics.time_span(ctx.command_encoder(), "depth_of_field"); + // We can be in either Gaussian blur or bokeh mode here. Both modes are // similar, consisting of two passes each. for pipeline_render_info in view_pipelines.pipeline_render_info().iter() { @@ -799,6 +804,7 @@ pub(crate) fn depth_of_field( view_uniforms.uniforms.binding(), &**global_bind_group, ) else { + time_span.end(ctx.command_encoder()); return; }; @@ -896,4 +902,5 @@ pub(crate) fn depth_of_field( // Render the full-screen pass. render_pass.draw(0..3, 0..1); } + time_span.end(ctx.command_encoder()); }