Add a stats display for scene complexity (#322)

This commit is contained in:
Daniel McNab 2023-05-18 18:50:57 +01:00 committed by GitHub
parent 2c394aa265
commit abfe9fbb56
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 11 deletions

View file

@ -20,5 +20,6 @@ $ cargo run -p with_winit --release -- [SVG FILES]
- Space resets the position and zoom of the image.
- S toggles the frame statistics layer
- C resets the min/max frame time tracked by statistics
- D toggles displaying the required number of each kind of dynamically allocated element (default: off)
- V toggles VSync on/off (default: on)
- Escape exits the program.

View file

@ -27,7 +27,7 @@ use vello::{
util::RenderContext,
Renderer, Scene, SceneBuilder,
};
use vello::{RendererOptions, SceneFragment};
use vello::{BumpAllocators, RendererOptions, SceneFragment};
use winit::{
event_loop::{EventLoop, EventLoopBuilder},
@ -100,6 +100,8 @@ fn run(
let mut images = ImageCache::new();
let mut stats = stats::Stats::new();
let mut stats_shown = true;
let mut scene_complexity: Option<BumpAllocators> = None;
let mut complexity_shown = false;
let mut vsync_on = true;
let mut frame_start_time = Instant::now();
let start = Instant::now();
@ -150,6 +152,9 @@ fn run(
Some(VirtualKeyCode::S) => {
stats_shown = !stats_shown;
}
Some(VirtualKeyCode::D) => {
complexity_shown = !complexity_shown;
}
Some(VirtualKeyCode::C) => {
stats.clear_min_and_max();
}
@ -326,6 +331,7 @@ fn run(
width as f64,
height as f64,
stats.samples(),
complexity_shown.then_some(scene_complexity).flatten(),
vsync_on,
);
}
@ -336,7 +342,7 @@ fn run(
.expect("failed to get surface texture");
#[cfg(not(target_arch = "wasm32"))]
{
vello::block_on_wgpu(
scene_complexity = vello::block_on_wgpu(
&device_handle.device,
renderers[render_state.surface.dev_id]
.as_mut()

View file

@ -19,7 +19,7 @@ use std::collections::VecDeque;
use vello::{
kurbo::{Affine, PathEl, Rect},
peniko::{Brush, Color, Fill, Stroke},
SceneBuilder,
BumpAllocators, SceneBuilder,
};
const SLIDING_WINDOW_SIZE: usize = 100;
@ -40,6 +40,7 @@ impl Snapshot {
viewport_width: f64,
viewport_height: f64,
samples: T,
bump: Option<BumpAllocators>,
vsync: bool,
) where
T: Iterator<Item = &'a u64>,
@ -59,13 +60,23 @@ impl Snapshot {
&Rect::new(0., 0., width, height),
);
let labels = [
let mut labels = vec![
format!("Frame Time: {:.2} ms", self.frame_time_ms),
format!("Frame Time (min): {:.2} ms", self.frame_time_min_ms),
format!("Frame Time (max): {:.2} ms", self.frame_time_max_ms),
format!("VSync: {}", if vsync { "on" } else { "off" }),
format!("Resolution: {viewport_width}x{viewport_height}"),
];
if let Some(bump) = &bump {
if bump.failed >= 1 {
labels.push(format!("Allocation Failed!"));
}
labels.push(format!("binning: {}", bump.binning));
labels.push(format!("ptcl: {}", bump.ptcl));
labels.push(format!("tile: {}", bump.tile));
labels.push(format!("segments: {}", bump.segments));
labels.push(format!("blend: {}", bump.blend));
}
// height / 2 is dedicated to the text labels and the rest is filled by the bar graph.
let text_height = height * 0.5 / (1 + labels.len()) as f64;

View file

@ -37,6 +37,8 @@ pub use util::block_on_wgpu;
use engine::{Engine, ExternalResource, Recording};
use shaders::FullShaders;
/// Temporary export, used in with_winit for stats
pub use vello_encoding::BumpAllocators;
use wgpu::{Device, Queue, SurfaceTexture, TextureFormat, TextureView};
/// Catch-all error type.
@ -196,6 +198,12 @@ impl Renderer {
/// The texture is assumed to be of the specified dimensions and have been created with
/// the [wgpu::TextureFormat::Rgba8Unorm] format and the [wgpu::TextureUsages::STORAGE_BINDING]
/// flag set.
///
/// The return value is the value of the `BumpAllocators` in this rendering, which is currently used
/// for debug output.
///
/// This return type is not stable, and will likely be changed when a more principled way to access
/// relevant statistics is implemented
pub async fn render_to_texture_async(
&mut self,
device: &Device,
@ -203,13 +211,15 @@ impl Renderer {
scene: &Scene,
texture: &TextureView,
params: &RenderParams,
) -> Result<()> {
) -> Result<Option<BumpAllocators>> {
let mut render = Render::new();
let encoding = scene.data();
let recording = render.render_encoding_coarse(encoding, &self.shaders, params, true);
let target = render.out_image();
let bump_buf = render.bump_buf();
self.engine.run_recording(device, queue, &recording, &[])?;
let mut bump: Option<BumpAllocators> = None;
if let Some(bump_buf) = self.engine.get_download(bump_buf) {
let buf_slice = bump_buf.slice(..);
let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel();
@ -219,8 +229,8 @@ impl Renderer {
} else {
return Err("channel was closed".into());
}
let _mapped = buf_slice.get_mapped_range();
// println!("{:?}", bytemuck::cast_slice::<_, u32>(&mapped));
let mapped = buf_slice.get_mapped_range();
bump = Some(bytemuck::pod_read_unaligned(&*mapped));
}
// TODO: apply logic to determine whether we need to rerun coarse, and also
// allocate the blend stack as needed.
@ -231,7 +241,7 @@ impl Renderer {
let external_resources = [ExternalResource::Image(target, texture)];
self.engine
.run_recording(device, queue, &recording, &external_resources)?;
Ok(())
Ok(bump)
}
/// See [Self::render_to_surface]
@ -242,7 +252,7 @@ impl Renderer {
scene: &Scene,
surface: &SurfaceTexture,
params: &RenderParams,
) -> Result<()> {
) -> Result<Option<BumpAllocators>> {
let width = params.width;
let height = params.height;
let mut target = self
@ -254,7 +264,8 @@ impl Renderer {
if target.width != width || target.height != height {
target = TargetTexture::new(device, width, height);
}
self.render_to_texture_async(device, queue, scene, &target.view, params)
let bump = self
.render_to_texture_async(device, queue, scene, &target.view, params)
.await?;
let blit = self
.blit
@ -292,7 +303,7 @@ impl Renderer {
}
queue.submit(Some(encoder.finish()));
self.target = Some(target);
Ok(())
Ok(bump)
}
}