Skip to content

Commit

Permalink
Add RenderStatistics resource, providing pipeline statistics (such as…
Browse files Browse the repository at this point in the history
… primitives count) per each render pass
  • Loading branch information
LeshaInc committed Jul 12, 2023
1 parent cd0a642 commit 2137782
Show file tree
Hide file tree
Showing 6 changed files with 368 additions and 11 deletions.
15 changes: 13 additions & 2 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub mod prelude {
color::Color,
mesh::{morph::MorphWeights, shape, Mesh},
render_resource::Shader,
renderer::RenderStatistics,
spatial_bundle::SpatialBundle,
texture::{Image, ImagePlugin},
view::{ComputedVisibility, Msaa, Visibility, VisibilityBundle},
Expand All @@ -43,7 +44,10 @@ pub mod prelude {

use bevy_window::{PrimaryWindow, RawHandleWrapper};
use globals::GlobalsPlugin;
use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue};
use renderer::{
sync_render_statistics, RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue,
RenderStatistics, RenderStatisticsMutex,
};
use wgpu::Instance;

use crate::{
Expand All @@ -54,7 +58,7 @@ use crate::{
settings::WgpuSettings,
view::{ViewPlugin, WindowRenderPlugin},
};
use bevy_app::{App, AppLabel, Plugin, SubApp};
use bevy_app::{App, AppLabel, Plugin, PreUpdate, SubApp};
use bevy_asset::{AddAsset, AssetServer};
use bevy_ecs::{prelude::*, schedule::ScheduleLabel, system::SystemState};
use bevy_utils::tracing::debug;
Expand Down Expand Up @@ -270,11 +274,18 @@ impl Plugin for RenderPlugin {
let mut extract_schedule = Schedule::new();
extract_schedule.set_apply_final_deferred(false);

let render_statistics = RenderStatisticsMutex::default();

app.insert_resource(render_statistics.clone())
.add_systems(PreUpdate, sync_render_statistics)
.init_resource::<RenderStatistics>();

render_app
.add_schedule(ExtractSchedule, extract_schedule)
.add_schedule(Render, Render::base_schedule())
.init_resource::<render_graph::RenderGraph>()
.insert_resource(app.world.resource::<AssetServer>().clone())
.insert_resource(render_statistics)
.add_systems(ExtractSchedule, PipelineCache::extract_shaders)
.add_systems(
Render,
Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_render/src/render_phase/draw_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use crate::{
BindGroup, BindGroupId, Buffer, BufferId, BufferSlice, RenderPipeline, RenderPipelineId,
ShaderStages,
},
renderer::RenderDevice,
renderer::{MeasuredRenderPass, RenderDevice},
};
use bevy_utils::{default, detailed_trace};
use std::ops::Range;
use wgpu::{IndexFormat, RenderPass};
use wgpu::IndexFormat;

/// Tracks the state of a [`TrackedRenderPass`].
///
Expand Down Expand Up @@ -101,13 +101,13 @@ impl DrawState {
/// It is used to set the current [`RenderPipeline`], [`BindGroup`]s and [`Buffer`]s.
/// After all requirements are specified, draw calls can be issued.
pub struct TrackedRenderPass<'a> {
pass: RenderPass<'a>,
pass: MeasuredRenderPass<'a>,
state: DrawState,
}

impl<'a> TrackedRenderPass<'a> {
/// Tracks the supplied render pass.
pub fn new(device: &RenderDevice, pass: RenderPass<'a>) -> Self {
pub fn new(device: &RenderDevice, pass: MeasuredRenderPass<'a>) -> Self {
let limits = device.limits();
let max_bind_groups = limits.max_bind_groups as usize;
let max_vertex_buffers = limits.max_vertex_buffers as usize;
Expand Down
10 changes: 9 additions & 1 deletion crates/bevy_render/src/renderer/graph_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use crate::{
renderer::{RenderContext, RenderDevice},
};

use super::RenderStatisticsMutex;

pub(crate) struct RenderGraphRunner;

#[derive(Error, Debug)]
Expand Down Expand Up @@ -59,7 +61,7 @@ impl RenderGraphRunner {
world: &World,
finalizer: impl FnOnce(&mut wgpu::CommandEncoder),
) -> Result<(), RenderGraphRunnerError> {
let mut render_context = RenderContext::new(render_device);
let mut render_context = RenderContext::new(render_device, queue);
Self::run_graph(graph, None, &mut render_context, world, &[], None)?;
finalizer(render_context.command_encoder());

Expand All @@ -68,6 +70,12 @@ impl RenderGraphRunner {
let _span = info_span!("submit_graph_commands").entered();
queue.submit(render_context.finish());
}

let render_statistics_mutex = world.resource::<RenderStatisticsMutex>().0.clone();
render_context.download_statistics(&queue, move |statistics| {
*render_statistics_mutex.lock() = Some(statistics);
});

Ok(())
}

Expand Down
36 changes: 32 additions & 4 deletions crates/bevy_render/src/renderer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod graph_runner;
mod render_device;
mod statistics;

use bevy_derive::{Deref, DerefMut};
use bevy_utils::tracing::{error, info, info_span};
pub use graph_runner::*;
pub use render_device::*;
pub use statistics::*;

use crate::{
render_graph::RenderGraph,
Expand Down Expand Up @@ -291,15 +293,18 @@ pub struct RenderContext {
render_device: RenderDevice,
command_encoder: Option<CommandEncoder>,
command_buffers: Vec<CommandBuffer>,
statistics_recorder: StatisticsRecorder,
}

impl RenderContext {
/// Creates a new [`RenderContext`] from a [`RenderDevice`].
pub fn new(render_device: RenderDevice) -> Self {
pub fn new(render_device: RenderDevice, queue: &Queue) -> Self {
let statistics_recorder = StatisticsRecorder::new(&render_device, queue);
Self {
render_device,
command_encoder: None,
command_buffers: Vec::new(),
statistics_recorder,
}
}

Expand All @@ -308,6 +313,11 @@ impl RenderContext {
&self.render_device
}

/// Gets the underlying [`StatisticsRecorder`].
pub fn statistics_encoder(&mut self) -> &mut StatisticsRecorder {
&mut self.statistics_recorder
}

/// Gets the current [`CommandEncoder`].
pub fn command_encoder(&mut self) -> &mut CommandEncoder {
self.command_encoder.get_or_insert_with(|| {
Expand All @@ -327,7 +337,8 @@ impl RenderContext {
self.render_device
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default())
});
let render_pass = command_encoder.begin_render_pass(&descriptor);
let render_pass =
MeasuredRenderPass::new(command_encoder, &mut self.statistics_recorder, descriptor);
TrackedRenderPass::new(&self.render_device, render_pass)
}

Expand All @@ -342,9 +353,26 @@ impl RenderContext {
}

/// Finalizes the queue and returns the queue of [`CommandBuffer`]s.
pub fn finish(mut self) -> Vec<CommandBuffer> {
pub fn finish(&mut self) -> Vec<CommandBuffer> {
let command_encoder = self.command_encoder.get_or_insert_with(|| {
self.render_device
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default())
});

self.statistics_recorder
.resolve(command_encoder, &self.render_device);

self.flush_encoder();
self.command_buffers
std::mem::take(&mut self.command_buffers)
}

pub fn download_statistics(
&mut self,
queue: &Queue,
callback: impl FnOnce(RenderStatistics) + Send + 'static,
) {
self.statistics_recorder
.download(&self.render_device, queue, callback);
}

fn flush_encoder(&mut self) {
Expand Down
Loading

0 comments on commit 2137782

Please sign in to comment.