Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wgpu render pass on paint callback has now static lifetime #5149

Merged
merged 2 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions crates/eframe/src/web/web_painter_wgpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ impl WebPainter for WebPainterWgpu {
let frame_view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &frame_view,
resolve_target: None,
Expand Down Expand Up @@ -333,7 +333,14 @@ impl WebPainter for WebPainterWgpu {
timestamp_writes: None,
});

renderer.render(&mut render_pass, clipped_primitives, &screen_descriptor);
// Forgetting the pass' lifetime means that we are no longer compile-time protected from
// runtime errors caused by accessing the parent encoder before the render pass is dropped.
// Since we don't pass it on to the renderer, we should be perfectly safe against this mistake here!
renderer.render(
&mut render_pass.forget_lifetime(),
clipped_primitives,
&screen_descriptor,
);
}

Some(frame)
Expand Down
22 changes: 14 additions & 8 deletions crates/egui-wgpu/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ pub trait CallbackTrait: Send + Sync {
///
/// It is given access to the [`wgpu::RenderPass`] so that it can issue draw commands
/// into the same [`wgpu::RenderPass`] that is used for all other egui elements.
fn paint<'a>(
&'a self,
fn paint(
&self,
info: PaintCallbackInfo,
render_pass: &mut wgpu::RenderPass<'a>,
callback_resources: &'a CallbackResources,
render_pass: &mut wgpu::RenderPass<'static>,
callback_resources: &CallbackResources,
);
}

Expand Down Expand Up @@ -408,10 +408,16 @@ impl Renderer {
}

/// Executes the egui renderer onto an existing wgpu renderpass.
pub fn render<'rp>(
&'rp self,
render_pass: &mut wgpu::RenderPass<'rp>,
paint_jobs: &'rp [epaint::ClippedPrimitive],
///
/// Note that the lifetime of `render_pass` is `'static` which requires a call to [`wgpu::RenderPass::forget_lifetime`].
/// This allows users to pass resources that live outside of the callback resources to the render pass.
/// The render pass internally keeps all referenced resources alive as long as necessary.
/// The only consequence of `forget_lifetime` is that any operation on the parent encoder will cause a runtime error
/// instead of a compile time error.
pub fn render(
&self,
render_pass: &mut wgpu::RenderPass<'static>,
paint_jobs: &[epaint::ClippedPrimitive],
screen_descriptor: &ScreenDescriptor,
) {
crate::profile_function!();
Expand Down
11 changes: 9 additions & 2 deletions crates/egui-wgpu/src/winit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ impl Painter {
(texture_view, Some(&frame_view))
});

let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("egui_render"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
Expand Down Expand Up @@ -658,7 +658,14 @@ impl Painter {
occlusion_query_set: None,
});

renderer.render(&mut render_pass, clipped_primitives, &screen_descriptor);
// Forgetting the pass' lifetime means that we are no longer compile-time protected from
// runtime errors caused by accessing the parent encoder before the render pass is dropped.
// Since we don't pass it on to the renderer, we should be perfectly safe against this mistake here!
renderer.render(
&mut render_pass.forget_lifetime(),
clipped_primitives,
&screen_descriptor,
);
}

{
Expand Down
8 changes: 4 additions & 4 deletions crates/egui_demo_app/src/apps/custom3d_wgpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,11 @@ impl egui_wgpu::CallbackTrait for CustomTriangleCallback {
Vec::new()
}

fn paint<'a>(
fn paint(
&self,
_info: egui::PaintCallbackInfo,
render_pass: &mut wgpu::RenderPass<'a>,
resources: &'a egui_wgpu::CallbackResources,
render_pass: &mut wgpu::RenderPass<'static>,
resources: &egui_wgpu::CallbackResources,
) {
let resources: &TriangleRenderResources = resources.get().unwrap();
resources.paint(render_pass);
Expand Down Expand Up @@ -200,7 +200,7 @@ impl TriangleRenderResources {
);
}

fn paint<'rp>(&'rp self, render_pass: &mut wgpu::RenderPass<'rp>) {
fn paint(&self, render_pass: &mut wgpu::RenderPass<'_>) {
// Draw our triangle!
render_pass.set_pipeline(&self.pipeline);
render_pass.set_bind_group(0, &self.bind_group, &[]);
Expand Down
Loading