WGPU PaintCallback Fixes (#1704)

* 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.

* 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.

* Make egui_wgpu::Renderer Functions Public Again
This commit is contained in:
Zicklag 2022-06-02 15:45:54 -05:00 committed by GitHub
parent 083e20474b
commit 218d4d4eea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -339,19 +339,13 @@ impl RenderPass {
// run. // run.
let mut needs_reset = true; let mut needs_reset = true;
for ( let mut index_buffers = self.index_buffers.iter();
( let mut vertex_buffers = self.vertex_buffers.iter();
egui::ClippedPrimitive {
clip_rect, for egui::ClippedPrimitive {
primitive, clip_rect,
}, primitive,
vertex_buffer, } in paint_jobs
),
index_buffer,
) in paint_jobs
.iter()
.zip(&self.vertex_buffers)
.zip(&self.index_buffers)
{ {
if needs_reset { if needs_reset {
rpass.set_viewport( rpass.set_viewport(
@ -384,6 +378,9 @@ impl RenderPass {
match primitive { match primitive {
Primitive::Mesh(mesh) => { Primitive::Mesh(mesh) => {
if let Some((_texture, bind_group)) = self.textures.get(&mesh.texture_id) { 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_bind_group(1, bind_group, &[]);
rpass.set_index_buffer( rpass.set_index_buffer(
index_buffer.buffer.slice(..), index_buffer.buffer.slice(..),
@ -568,6 +565,18 @@ impl RenderPass {
self.textures.remove(id); 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::Texture>, wgpu::BindGroup)> {
self.textures.get(id)
}
/// Registers a `wgpu::Texture` with a `egui::TextureId`. /// Registers a `wgpu::Texture` with a `egui::TextureId`.
/// ///
/// This enables the application to reference the texture inside an image ui element. /// This enables the application to reference the texture inside an image ui element.
@ -669,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 { match primitive {
Primitive::Mesh(mesh) => { Primitive::Mesh(mesh) => {
let data: &[u8] = bytemuck::cast_slice(&mesh.indices); let data: &[u8] = bytemuck::cast_slice(&mesh.indices);
if i < self.index_buffers.len() { if mesh_idx < self.index_buffers.len() {
self.update_buffer(device, queue, &BufferType::Index, i, data); self.update_buffer(device, queue, &BufferType::Index, mesh_idx, data);
} else { } else {
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("egui_index_buffer"), label: Some("egui_index_buffer"),
@ -688,8 +698,8 @@ impl RenderPass {
} }
let data: &[u8] = bytemuck::cast_slice(&mesh.vertices); let data: &[u8] = bytemuck::cast_slice(&mesh.vertices);
if i < self.vertex_buffers.len() { if mesh_idx < self.vertex_buffers.len() {
self.update_buffer(device, queue, &BufferType::Vertex, i, data); self.update_buffer(device, queue, &BufferType::Vertex, mesh_idx, data);
} else { } else {
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("egui_vertex_buffer"), label: Some("egui_vertex_buffer"),
@ -702,6 +712,8 @@ impl RenderPass {
size: data.len(), size: data.len(),
}); });
} }
mesh_idx += 1;
} }
Primitive::Callback(callback) => { Primitive::Callback(callback) => {
let cbfn = if let Some(c) = callback.callback.downcast_ref::<CallbackFn>() { let cbfn = if let Some(c) = callback.callback.downcast_ref::<CallbackFn>() {