Opt-in logging of egui-wgpu using puffin

This commit is contained in:
Emil Ernerfeldt 2022-11-10 16:27:31 +01:00
parent b2edbe617e
commit e225c6b8d0
6 changed files with 100 additions and 25 deletions

1
Cargo.lock generated
View file

@ -1175,6 +1175,7 @@ dependencies = [
"document-features", "document-features",
"egui", "egui",
"pollster", "pollster",
"puffin",
"tracing", "tracing",
"type-map", "type-map",
"wgpu", "wgpu",

View file

@ -47,7 +47,7 @@ persistence = [
## ##
## Only enabled on native, because of the low resolution (1ms) of time keeping in browsers. ## Only enabled on native, because of the low resolution (1ms) of time keeping in browsers.
## `eframe` will call `puffin::GlobalProfiler::lock().new_frame()` for you ## `eframe` will call `puffin::GlobalProfiler::lock().new_frame()` for you
puffin = ["dep:puffin", "egui_glow?/puffin"] puffin = ["dep:puffin", "egui_glow?/puffin", "egui-wgpu?/puffin"]
## Enable screen reader support (requires `ctx.options().screen_reader = true;`) ## Enable screen reader support (requires `ctx.options().screen_reader = true;`)
screen_reader = ["egui-winit/screen_reader", "tts"] screen_reader = ["egui-winit/screen_reader", "tts"]

View file

@ -3,9 +3,9 @@ name = "egui-wgpu"
version = "0.19.0" version = "0.19.0"
description = "Bindings for using egui natively using the wgpu library" description = "Bindings for using egui natively using the wgpu library"
authors = [ authors = [
"Nils Hasenbanck <nils@hasenbanck.de>", "Nils Hasenbanck <nils@hasenbanck.de>",
"embotech <opensource@embotech.com>", "embotech <opensource@embotech.com>",
"Emil Ernerfeldt <emil.ernerfeldt@gmail.com>", "Emil Ernerfeldt <emil.ernerfeldt@gmail.com>",
] ]
edition = "2021" edition = "2021"
rust-version = "1.62" rust-version = "1.62"
@ -28,13 +28,16 @@ all-features = true
[features] [features]
## Enable profiling with the [`puffin`](https://docs.rs/puffin) crate.
puffin = ["dep:puffin"]
## Enable [`winit`](https://docs.rs/winit) integration. ## Enable [`winit`](https://docs.rs/winit) integration.
winit = ["dep:pollster", "dep:winit"] winit = ["dep:pollster", "dep:winit"]
[dependencies] [dependencies]
egui = { version = "0.19.0", path = "../egui", default-features = false, features = [ egui = { version = "0.19.0", path = "../egui", default-features = false, features = [
"bytemuck", "bytemuck",
] } ] }
bytemuck = "1.7" bytemuck = "1.7"
@ -48,3 +51,7 @@ document-features = { version = "0.2", optional = true }
pollster = { version = "0.2", optional = true } pollster = { version = "0.2", optional = true }
winit = { version = "0.27.2", optional = true } winit = { version = "0.27.2", optional = true }
# Native:
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
puffin = { version = "0.14", optional = true }

View file

@ -95,3 +95,25 @@ pub fn preferred_framebuffer_format(formats: &[wgpu::TextureFormat]) -> wgpu::Te
} }
formats[0] // take the first formats[0] // take the first
} }
// ---------------------------------------------------------------------------
/// Profiling macro for feature "puffin"
macro_rules! profile_function {
($($arg: tt)*) => {
#[cfg(feature = "puffin")]
#[cfg(not(target_arch = "wasm32"))]
puffin::profile_function!($($arg)*);
};
}
pub(crate) use profile_function;
/// Profiling macro for feature "puffin"
macro_rules! profile_scope {
($($arg: tt)*) => {
#[cfg(feature = "puffin")]
#[cfg(not(target_arch = "wasm32"))]
puffin::profile_scope!($($arg)*);
};
}
pub(crate) use profile_scope;

View file

@ -174,6 +174,8 @@ impl Renderer {
output_depth_format: Option<wgpu::TextureFormat>, output_depth_format: Option<wgpu::TextureFormat>,
msaa_samples: u32, msaa_samples: u32,
) -> Self { ) -> Self {
crate::profile_function!();
let shader = wgpu::ShaderModuleDescriptor { let shader = wgpu::ShaderModuleDescriptor {
label: Some("egui"), label: Some("egui"),
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("egui.wgsl"))), source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("egui.wgsl"))),
@ -347,6 +349,8 @@ impl Renderer {
paint_jobs: &[egui::epaint::ClippedPrimitive], paint_jobs: &[egui::epaint::ClippedPrimitive],
screen_descriptor: &ScreenDescriptor, screen_descriptor: &ScreenDescriptor,
) { ) {
crate::profile_function!();
let pixels_per_point = screen_descriptor.pixels_per_point; let pixels_per_point = screen_descriptor.pixels_per_point;
let size_in_pixels = screen_descriptor.size_in_pixels; let size_in_pixels = screen_descriptor.size_in_pixels;
@ -421,6 +425,8 @@ impl Renderer {
}; };
if callback.rect.is_positive() { if callback.rect.is_positive() {
crate::profile_scope!("callback");
needs_reset = true; needs_reset = true;
{ {
@ -472,6 +478,8 @@ impl Renderer {
id: egui::TextureId, id: egui::TextureId,
image_delta: &egui::epaint::ImageDelta, image_delta: &egui::epaint::ImageDelta,
) { ) {
crate::profile_function!();
let width = image_delta.image.width() as u32; let width = image_delta.image.width() as u32;
let height = image_delta.image.height() as u32; let height = image_delta.image.height() as u32;
@ -653,6 +661,8 @@ impl Renderer {
texture: &wgpu::TextureView, texture: &wgpu::TextureView,
sampler_descriptor: wgpu::SamplerDescriptor<'_>, sampler_descriptor: wgpu::SamplerDescriptor<'_>,
) -> egui::TextureId { ) -> egui::TextureId {
crate::profile_function!();
let sampler = device.create_sampler(&wgpu::SamplerDescriptor { let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
compare: None, compare: None,
..sampler_descriptor ..sampler_descriptor
@ -692,6 +702,8 @@ impl Renderer {
sampler_descriptor: wgpu::SamplerDescriptor<'_>, sampler_descriptor: wgpu::SamplerDescriptor<'_>,
id: egui::TextureId, id: egui::TextureId,
) { ) {
crate::profile_function!();
let (_user_texture, user_texture_binding) = self let (_user_texture, user_texture_binding) = self
.textures .textures
.get_mut(&id) .get_mut(&id)
@ -732,20 +744,26 @@ impl Renderer {
paint_jobs: &[egui::epaint::ClippedPrimitive], paint_jobs: &[egui::epaint::ClippedPrimitive],
screen_descriptor: &ScreenDescriptor, screen_descriptor: &ScreenDescriptor,
) -> Vec<wgpu::CommandBuffer> { ) -> Vec<wgpu::CommandBuffer> {
crate::profile_function!();
let screen_size_in_points = screen_descriptor.screen_size_in_points(); let screen_size_in_points = screen_descriptor.screen_size_in_points();
// Update uniform buffer {
queue.write_buffer( crate::profile_scope!("uniforms");
&self.uniform_buffer, // Update uniform buffer
0, queue.write_buffer(
bytemuck::cast_slice(&[UniformBuffer { &self.uniform_buffer,
screen_size_in_points, 0,
_padding: Default::default(), bytemuck::cast_slice(&[UniformBuffer {
}]), screen_size_in_points,
); _padding: Default::default(),
}]),
);
}
// Determine how many vertices & indices need to be rendered. // Determine how many vertices & indices need to be rendered.
let (vertex_count, index_count) = let (vertex_count, index_count) = {
crate::profile_scope!("count_vertices_indices");
paint_jobs.iter().fold((0, 0), |acc, clipped_primitive| { paint_jobs.iter().fold((0, 0), |acc, clipped_primitive| {
match &clipped_primitive.primitive { match &clipped_primitive.primitive {
Primitive::Mesh(mesh) => { Primitive::Mesh(mesh) => {
@ -753,9 +771,11 @@ impl Renderer {
} }
Primitive::Callback(_) => acc, Primitive::Callback(_) => acc,
} }
}); })
// Resize index buffer if needed. };
{ {
// Resize index buffer if needed:
self.index_buffer.slices.clear(); self.index_buffer.slices.clear();
let required_size = (std::mem::size_of::<u32>() * index_count) as u64; let required_size = (std::mem::size_of::<u32>() * index_count) as u64;
if self.index_buffer.capacity < required_size { if self.index_buffer.capacity < required_size {
@ -764,8 +784,9 @@ impl Renderer {
self.index_buffer.buffer = create_index_buffer(device, self.index_buffer.capacity); self.index_buffer.buffer = create_index_buffer(device, self.index_buffer.capacity);
} }
} }
// Resize vertex buffer if needed.
{ {
// Resize vertex buffer if needed:
self.vertex_buffer.slices.clear(); self.vertex_buffer.slices.clear();
let required_size = (std::mem::size_of::<Vertex>() * vertex_count) as u64; let required_size = (std::mem::size_of::<Vertex>() * vertex_count) as u64;
if self.vertex_buffer.capacity < required_size { if self.vertex_buffer.capacity < required_size {
@ -778,6 +799,8 @@ impl Renderer {
// Upload index & vertex data and call user callbacks // Upload index & vertex data and call user callbacks
let mut user_cmd_bufs = Vec::new(); // collect user command buffers let mut user_cmd_bufs = Vec::new(); // collect user command buffers
crate::profile_scope!("primitives");
for egui::ClippedPrimitive { primitive, .. } in paint_jobs.iter() { for egui::ClippedPrimitive { primitive, .. } in paint_jobs.iter() {
match primitive { match primitive {
Primitive::Mesh(mesh) => { Primitive::Mesh(mesh) => {
@ -806,6 +829,7 @@ impl Renderer {
continue; continue;
}; };
crate::profile_scope!("callback");
user_cmd_bufs.extend((cbfn.prepare)( user_cmd_bufs.extend((cbfn.prepare)(
device, device,
queue, queue,
@ -841,6 +865,7 @@ fn create_sampler(options: egui::TextureOptions, device: &wgpu::Device) -> wgpu:
} }
fn create_vertex_buffer(device: &wgpu::Device, size: u64) -> wgpu::Buffer { fn create_vertex_buffer(device: &wgpu::Device, size: u64) -> wgpu::Buffer {
crate::profile_function!();
device.create_buffer(&wgpu::BufferDescriptor { device.create_buffer(&wgpu::BufferDescriptor {
label: Some("egui_vertex_buffer"), label: Some("egui_vertex_buffer"),
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
@ -850,6 +875,7 @@ fn create_vertex_buffer(device: &wgpu::Device, size: u64) -> wgpu::Buffer {
} }
fn create_index_buffer(device: &wgpu::Device, size: u64) -> wgpu::Buffer { fn create_index_buffer(device: &wgpu::Device, size: u64) -> wgpu::Buffer {
crate::profile_function!();
device.create_buffer(&wgpu::BufferDescriptor { device.create_buffer(&wgpu::BufferDescriptor {
label: Some("egui_index_buffer"), label: Some("egui_index_buffer"),
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,

View file

@ -109,6 +109,8 @@ impl Painter {
} }
fn configure_surface(&mut self, width_in_pixels: u32, height_in_pixels: u32) { fn configure_surface(&mut self, width_in_pixels: u32, height_in_pixels: u32) {
crate::profile_function!();
let render_state = self let render_state = self
.render_state .render_state
.as_ref() .as_ref()
@ -227,6 +229,8 @@ impl Painter {
clipped_primitives: &[egui::ClippedPrimitive], clipped_primitives: &[egui::ClippedPrimitive],
textures_delta: &egui::TexturesDelta, textures_delta: &egui::TexturesDelta,
) { ) {
crate::profile_function!();
let render_state = match self.render_state.as_mut() { let render_state = match self.render_state.as_mut() {
Some(rs) => rs, Some(rs) => rs,
None => return, None => return,
@ -237,7 +241,13 @@ impl Painter {
}; };
let (width, height) = (surface_state.width, surface_state.height); let (width, height) = (surface_state.width, surface_state.height);
let output_frame = match surface_state.surface.get_current_texture() { let output_frame = {
crate::profile_scope!("get_current_texture");
// This is what vsync-waiting happens, at least on Mac.
surface_state.surface.get_current_texture()
};
let output_frame = match output_frame {
Ok(frame) => frame, Ok(frame) => frame,
#[allow(clippy::single_match_else)] #[allow(clippy::single_match_else)]
Err(e) => match (*self.configuration.on_surface_error)(e) { Err(e) => match (*self.configuration.on_surface_error)(e) {
@ -326,15 +336,24 @@ impl Painter {
} }
} }
let encoded = {
crate::profile_scope!("CommandEncoder::finish");
encoder.finish()
};
// Submit the commands: both the main buffer and user-defined ones. // Submit the commands: both the main buffer and user-defined ones.
render_state.queue.submit( {
user_cmd_bufs crate::profile_scope!("Queue::submit");
.into_iter() render_state
.chain(std::iter::once(encoder.finish())), .queue
); .submit(user_cmd_bufs.into_iter().chain(std::iter::once(encoded)));
};
// Redraw egui // Redraw egui
output_frame.present(); {
crate::profile_scope!("present");
output_frame.present();
}
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]