From ca59ccb3c82bd428602b04afab618c4438a85d2b Mon Sep 17 00:00:00 2001 From: Zicklag Date: Wed, 1 Jun 2022 12:38:37 -0500 Subject: [PATCH 1/3] Expose egui WGPU Textures and Limit Exposed API This allows paint callbacks to access textures allocated by egui, and also hides the functions on the `RenderPass` that users should not need to call. --- egui-wgpu/src/renderer.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/egui-wgpu/src/renderer.rs b/egui-wgpu/src/renderer.rs index 2b202de7498..2bfe0b237e5 100644 --- a/egui-wgpu/src/renderer.rs +++ b/egui-wgpu/src/renderer.rs @@ -139,7 +139,7 @@ impl RenderPass { /// Creates a new render pass to render a egui UI. /// /// If the format passed is not a *Srgb format, the shader will automatically convert to `sRGB` colors in the shader. - pub fn new( + pub(crate) fn new( device: &wgpu::Device, output_format: wgpu::TextureFormat, msaa_samples: u32, @@ -292,7 +292,7 @@ impl RenderPass { } /// Executes the egui render pass. - pub fn execute( + pub(crate) fn execute( &self, encoder: &mut wgpu::CommandEncoder, color_attachment: &wgpu::TextureView, @@ -326,7 +326,7 @@ impl RenderPass { } /// Executes the egui render pass onto an existing wgpu renderpass. - pub fn execute_with_renderpass<'rpass>( + pub(crate) fn execute_with_renderpass<'rpass>( &'rpass self, rpass: &mut wgpu::RenderPass<'rpass>, paint_jobs: &[egui::epaint::ClippedPrimitive], @@ -452,7 +452,7 @@ impl RenderPass { } /// Should be called before `execute()`. - pub fn update_texture( + pub(crate) fn update_texture( &mut self, device: &wgpu::Device, queue: &wgpu::Queue, @@ -564,10 +564,22 @@ impl RenderPass { }; } - pub fn free_texture(&mut self, id: &egui::TextureId) { + pub(crate) fn free_texture(&mut self, id: &egui::TextureId) { self.textures.remove(id); } + /// Get the WGPU texture and bind group associated to a texture that has been allocated by egui. + /// + /// This could be used by custom paint hooks to render images that have been added through with + /// [`egui_extras::RetainedImage`](https://docs.rs/egui_extras/latest/egui_extras/image/struct.RetainedImage.html) + /// or [`egui::Context::load_texture`]. + pub fn get_texture( + &self, + id: &egui::TextureId, + ) -> Option<&(Option, wgpu::BindGroup)> { + self.textures.get(id) + } + /// Registers a `wgpu::Texture` with a `egui::TextureId`. /// /// This enables the application to reference the texture inside an image ui element. @@ -649,7 +661,7 @@ impl RenderPass { /// Uploads the uniform, vertex and index data used by the render pass. /// Should be called before `execute()`. - pub fn update_buffers( + pub(crate) fn update_buffers( &mut self, device: &wgpu::Device, queue: &wgpu::Queue, From dd7ffdfcee0e9ed71471b949bddae8c0ce789450 Mon Sep 17 00:00:00 2001 From: Zicklag Date: Wed, 1 Jun 2022 12:39:40 -0500 Subject: [PATCH 2/3] Fix WGPU Rendering Bug When Using Paint Callbacks Depending on the order custom paint callbacks were rendered, some of the egui meshes would previously not be rendered at all in a seemingly random fashion. --- egui-wgpu/src/renderer.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/egui-wgpu/src/renderer.rs b/egui-wgpu/src/renderer.rs index 2bfe0b237e5..2b994ae03e1 100644 --- a/egui-wgpu/src/renderer.rs +++ b/egui-wgpu/src/renderer.rs @@ -339,19 +339,13 @@ impl RenderPass { // run. let mut needs_reset = true; - for ( - ( - egui::ClippedPrimitive { - clip_rect, - primitive, - }, - vertex_buffer, - ), - index_buffer, - ) in paint_jobs - .iter() - .zip(&self.vertex_buffers) - .zip(&self.index_buffers) + let mut index_buffers = self.index_buffers.iter(); + let mut vertex_buffers = self.vertex_buffers.iter(); + + for egui::ClippedPrimitive { + clip_rect, + primitive, + } in paint_jobs { if needs_reset { rpass.set_viewport( @@ -384,6 +378,9 @@ impl RenderPass { match primitive { Primitive::Mesh(mesh) => { if let Some((_texture, bind_group)) = self.textures.get(&mesh.texture_id) { + let index_buffer = index_buffers.next().unwrap(); + let vertex_buffer = vertex_buffers.next().unwrap(); + rpass.set_bind_group(1, bind_group, &[]); rpass.set_index_buffer( index_buffer.buffer.slice(..), @@ -681,12 +678,13 @@ impl RenderPass { }]), ); - for (i, egui::ClippedPrimitive { primitive, .. }) in paint_jobs.iter().enumerate() { + let mut mesh_idx = 0; + for egui::ClippedPrimitive { primitive, .. } in paint_jobs.iter() { match primitive { Primitive::Mesh(mesh) => { let data: &[u8] = bytemuck::cast_slice(&mesh.indices); - if i < self.index_buffers.len() { - self.update_buffer(device, queue, &BufferType::Index, i, data); + if mesh_idx < self.index_buffers.len() { + self.update_buffer(device, queue, &BufferType::Index, mesh_idx, data); } else { let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("egui_index_buffer"), @@ -700,8 +698,8 @@ impl RenderPass { } let data: &[u8] = bytemuck::cast_slice(&mesh.vertices); - if i < self.vertex_buffers.len() { - self.update_buffer(device, queue, &BufferType::Vertex, i, data); + if mesh_idx < self.vertex_buffers.len() { + self.update_buffer(device, queue, &BufferType::Vertex, mesh_idx, data); } else { let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("egui_vertex_buffer"), @@ -714,6 +712,8 @@ impl RenderPass { size: data.len(), }); } + + mesh_idx += 1; } Primitive::Callback(callback) => { let cbfn = if let Some(c) = callback.callback.downcast_ref::() { From ba56e4df6f8e9ed99edd1222dea461347e5de76f Mon Sep 17 00:00:00 2001 From: Zicklag Date: Thu, 2 Jun 2022 14:32:42 -0500 Subject: [PATCH 3/3] Make egui_wgpu::Renderer Functions Public Again --- egui-wgpu/src/renderer.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/egui-wgpu/src/renderer.rs b/egui-wgpu/src/renderer.rs index 2b994ae03e1..f41d4ea0fc4 100644 --- a/egui-wgpu/src/renderer.rs +++ b/egui-wgpu/src/renderer.rs @@ -139,7 +139,7 @@ impl RenderPass { /// Creates a new render pass to render a egui UI. /// /// If the format passed is not a *Srgb format, the shader will automatically convert to `sRGB` colors in the shader. - pub(crate) fn new( + pub fn new( device: &wgpu::Device, output_format: wgpu::TextureFormat, msaa_samples: u32, @@ -292,7 +292,7 @@ impl RenderPass { } /// Executes the egui render pass. - pub(crate) fn execute( + pub fn execute( &self, encoder: &mut wgpu::CommandEncoder, color_attachment: &wgpu::TextureView, @@ -326,7 +326,7 @@ impl RenderPass { } /// Executes the egui render pass onto an existing wgpu renderpass. - pub(crate) fn execute_with_renderpass<'rpass>( + pub fn execute_with_renderpass<'rpass>( &'rpass self, rpass: &mut wgpu::RenderPass<'rpass>, paint_jobs: &[egui::epaint::ClippedPrimitive], @@ -449,7 +449,7 @@ impl RenderPass { } /// Should be called before `execute()`. - pub(crate) fn update_texture( + pub fn update_texture( &mut self, device: &wgpu::Device, queue: &wgpu::Queue, @@ -561,7 +561,7 @@ impl RenderPass { }; } - pub(crate) fn free_texture(&mut self, id: &egui::TextureId) { + pub fn free_texture(&mut self, id: &egui::TextureId) { self.textures.remove(id); } @@ -658,7 +658,7 @@ impl RenderPass { /// Uploads the uniform, vertex and index data used by the render pass. /// Should be called before `execute()`. - pub(crate) fn update_buffers( + pub fn update_buffers( &mut self, device: &wgpu::Device, queue: &wgpu::Queue,