Skip to content

Commit

Permalink
Postpone call to get_current_texture (#3914)
Browse files Browse the repository at this point in the history
This should help slightly with CPU/GPU parallelism when vsync is on.

I also return the time spent on vsync, which can help users figure out
how much CPU wall-time was used on non-vsync stuff
  • Loading branch information
emilk authored Jan 29, 2024
1 parent 1d1b07c commit 21253d8
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 27 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ glow = "0.13"
puffin = "0.18"
raw-window-handle = "0.6.0"
thiserror = "1.0.37"
web-time = "0.2" # Timekeeping for native and web
wgpu = { version = "0.19.1", default-features = false, features = [
# Make the renderer `Sync` even on wasm32, because it makes the code simpler:
"fragile-send-sync-non-atomic-wasm",
Expand Down
2 changes: 1 addition & 1 deletion crates/eframe/src/native/wgpu_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ impl WgpuWinitRunning {
let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point);

let screenshot_requested = std::mem::take(&mut viewport.screenshot_requested);
let screenshot = painter.paint_and_update_textures(
let (_vsync_secs, screenshot) = painter.paint_and_update_textures(
viewport_id,
pixels_per_point,
app.clear_color(&egui_ctx.style().visuals),
Expand Down
1 change: 1 addition & 0 deletions crates/egui-wgpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ bytemuck = "1.7"
log = { version = "0.4", features = ["std"] }
thiserror.workspace = true
type-map = "0.5.0"
web-time.workspace = true
wgpu = { workspace = true, features = ["wgsl"] }

#! ### Optional dependencies
Expand Down
75 changes: 50 additions & 25 deletions crates/egui-wgpu/src/winit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,10 @@ impl Painter {
})
}

// Returns a vector with the frame's pixel data if it was requested.
/// Returns two things:
///
/// The approximate number of seconds spent on vsync-waiting (if any),
/// and the captures captured screenshot if it was requested.
pub fn paint_and_update_textures(
&mut self,
viewport_id: ViewportId,
Expand All @@ -513,29 +516,16 @@ impl Painter {
clipped_primitives: &[epaint::ClippedPrimitive],
textures_delta: &epaint::textures::TexturesDelta,
capture: bool,
) -> Option<epaint::ColorImage> {
) -> (f32, Option<epaint::ColorImage>) {
crate::profile_function!();

let render_state = self.render_state.as_mut()?;
let surface_state = self.surfaces.get(&viewport_id)?;
let mut vsync_sec = 0.0;

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 Some(render_state) = self.render_state.as_mut() else {
return (vsync_sec, None);
};

let output_frame = match output_frame {
Ok(frame) => frame,
Err(err) => match (*self.configuration.on_surface_error)(err) {
SurfaceErrorAction::RecreateSurface => {
Self::configure_surface(surface_state, render_state, &self.configuration);
return None;
}
SurfaceErrorAction::SkipFrame => {
return None;
}
},
let Some(surface_state) = self.surfaces.get(&viewport_id) else {
return (vsync_sec, None);
};

let mut encoder =
Expand Down Expand Up @@ -580,6 +570,28 @@ impl Painter {
}
};

let output_frame = {
crate::profile_scope!("get_current_texture");
// This is what vsync-waiting happens on my Mac.
let start = web_time::Instant::now();
let output_frame = surface_state.surface.get_current_texture();
vsync_sec += start.elapsed().as_secs_f32();
output_frame
};

let output_frame = match output_frame {
Ok(frame) => frame,
Err(err) => match (*self.configuration.on_surface_error)(err) {
SurfaceErrorAction::RecreateSurface => {
Self::configure_surface(surface_state, render_state, &self.configuration);
return (vsync_sec, None);
}
SurfaceErrorAction::SkipFrame => {
return (vsync_sec, None);
}
},
};

{
let renderer = render_state.renderer.read();
let frame_view = if capture {
Expand All @@ -589,8 +601,11 @@ impl Painter {
render_state,
);
self.screen_capture_state
.as_ref()?
.texture
.as_ref()
.map_or_else(
|| &output_frame.texture,
|capture_state| &capture_state.texture,
)
.create_view(&wgpu::TextureViewDescriptor::default())
} else {
output_frame
Expand Down Expand Up @@ -654,23 +669,33 @@ impl Painter {
// Submit the commands: both the main buffer and user-defined ones.
{
crate::profile_scope!("Queue::submit");
// wgpu doesn't document where vsync can happen. Maybe here?
let start = web_time::Instant::now();
render_state
.queue
.submit(user_cmd_bufs.into_iter().chain([encoded]));
vsync_sec += start.elapsed().as_secs_f32();
};

let screenshot = if capture {
let screen_capture_state = self.screen_capture_state.as_ref()?;
Self::read_screen_rgba(screen_capture_state, render_state, &output_frame)
self.screen_capture_state
.as_ref()
.and_then(|screen_capture_state| {
Self::read_screen_rgba(screen_capture_state, render_state, &output_frame)
})
} else {
None
};

{
crate::profile_scope!("present");
// wgpu doesn't document where vsync can happen. Maybe here?
let start = web_time::Instant::now();
output_frame.present();
vsync_sec += start.elapsed().as_secs_f32();
}
screenshot

(vsync_sec, screenshot)
}

pub fn gc_viewports(&mut self, active_viewports: &ViewportIdSet) {
Expand Down
2 changes: 1 addition & 1 deletion crates/egui-winit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ egui = { version = "0.25.0", path = "../egui", default-features = false, feature
] }
log = { version = "0.4", features = ["std"] }
raw-window-handle.workspace = true
web-time = { version = "0.2" } # We use web-time so we can (maybe) compile for web
web-time.workspace = true
winit = { workspace = true, default-features = false, features = ["rwh_06"] }

#! ### Optional dependencies
Expand Down

0 comments on commit 21253d8

Please sign in to comment.