|
@ -4,14 +4,13 @@ use std::num::NonZeroU64; |
|
|
use std::ops::Range; |
|
|
use std::ops::Range; |
|
|
use std::{borrow::Cow, collections::HashMap, num::NonZeroU32}; |
|
|
use std::{borrow::Cow, collections::HashMap, num::NonZeroU32}; |
|
|
|
|
|
|
|
|
use egui::epaint::Vertex; |
|
|
|
|
|
use egui::NumExt; |
|
|
|
|
|
use egui::{epaint::Primitive, PaintCallbackInfo}; |
|
|
|
|
|
use type_map::concurrent::TypeMap; |
|
|
use type_map::concurrent::TypeMap; |
|
|
use wgpu; |
|
|
use wgpu; |
|
|
use wgpu::util::DeviceExt as _; |
|
|
use wgpu::util::DeviceExt as _; |
|
|
|
|
|
|
|
|
/// A callback function that can be used to compose an [`egui::PaintCallback`] for custom WGPU
|
|
|
use epaint::{emath::NumExt, PaintCallbackInfo, Primitive, Vertex}; |
|
|
|
|
|
|
|
|
|
|
|
/// A callback function that can be used to compose an [`epaint::PaintCallback`] for custom WGPU
|
|
|
/// rendering.
|
|
|
/// rendering.
|
|
|
///
|
|
|
///
|
|
|
/// The callback is composed of two functions: `prepare` and `paint`:
|
|
|
/// The callback is composed of two functions: `prepare` and `paint`:
|
|
@ -154,11 +153,11 @@ pub struct Renderer { |
|
|
/// Map of egui texture IDs to textures and their associated bindgroups (texture view +
|
|
|
/// Map of egui texture IDs to textures and their associated bindgroups (texture view +
|
|
|
/// sampler). The texture may be None if the TextureId is just a handle to a user-provided
|
|
|
/// sampler). The texture may be None if the TextureId is just a handle to a user-provided
|
|
|
/// sampler.
|
|
|
/// sampler.
|
|
|
textures: HashMap<egui::TextureId, (Option<wgpu::Texture>, wgpu::BindGroup)>, |
|
|
textures: HashMap<epaint::TextureId, (Option<wgpu::Texture>, wgpu::BindGroup)>, |
|
|
next_user_texture_id: u64, |
|
|
next_user_texture_id: u64, |
|
|
samplers: HashMap<egui::TextureOptions, wgpu::Sampler>, |
|
|
samplers: HashMap<epaint::textures::TextureOptions, wgpu::Sampler>, |
|
|
|
|
|
|
|
|
/// Storage for use by [`egui::PaintCallback`]'s that need to store resources such as render
|
|
|
/// Storage for use by [`epaint::PaintCallback`]'s that need to store resources such as render
|
|
|
/// pipelines that must have the lifetime of the renderpass.
|
|
|
/// pipelines that must have the lifetime of the renderpass.
|
|
|
pub paint_callback_resources: TypeMap, |
|
|
pub paint_callback_resources: TypeMap, |
|
|
} |
|
|
} |
|
@ -346,7 +345,7 @@ impl Renderer { |
|
|
pub fn render<'rp>( |
|
|
pub fn render<'rp>( |
|
|
&'rp self, |
|
|
&'rp self, |
|
|
render_pass: &mut wgpu::RenderPass<'rp>, |
|
|
render_pass: &mut wgpu::RenderPass<'rp>, |
|
|
paint_jobs: &[egui::epaint::ClippedPrimitive], |
|
|
paint_jobs: &[epaint::ClippedPrimitive], |
|
|
screen_descriptor: &ScreenDescriptor, |
|
|
screen_descriptor: &ScreenDescriptor, |
|
|
) { |
|
|
) { |
|
|
crate::profile_function!(); |
|
|
crate::profile_function!(); |
|
@ -361,7 +360,7 @@ impl Renderer { |
|
|
let mut index_buffer_slices = self.index_buffer.slices.iter(); |
|
|
let mut index_buffer_slices = self.index_buffer.slices.iter(); |
|
|
let mut vertex_buffer_slices = self.vertex_buffer.slices.iter(); |
|
|
let mut vertex_buffer_slices = self.vertex_buffer.slices.iter(); |
|
|
|
|
|
|
|
|
for egui::ClippedPrimitive { |
|
|
for epaint::ClippedPrimitive { |
|
|
clip_rect, |
|
|
clip_rect, |
|
|
primitive, |
|
|
primitive, |
|
|
} in paint_jobs |
|
|
} in paint_jobs |
|
@ -475,8 +474,8 @@ impl Renderer { |
|
|
&mut self, |
|
|
&mut self, |
|
|
device: &wgpu::Device, |
|
|
device: &wgpu::Device, |
|
|
queue: &wgpu::Queue, |
|
|
queue: &wgpu::Queue, |
|
|
id: egui::TextureId, |
|
|
id: epaint::TextureId, |
|
|
image_delta: &egui::epaint::ImageDelta, |
|
|
image_delta: &epaint::ImageDelta, |
|
|
) { |
|
|
) { |
|
|
crate::profile_function!(); |
|
|
crate::profile_function!(); |
|
|
|
|
|
|
|
@ -490,7 +489,7 @@ impl Renderer { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
let data_color32 = match &image_delta.image { |
|
|
let data_color32 = match &image_delta.image { |
|
|
egui::ImageData::Color(image) => { |
|
|
epaint::ImageData::Color(image) => { |
|
|
assert_eq!( |
|
|
assert_eq!( |
|
|
width as usize * height as usize, |
|
|
width as usize * height as usize, |
|
|
image.pixels.len(), |
|
|
image.pixels.len(), |
|
@ -498,7 +497,7 @@ impl Renderer { |
|
|
); |
|
|
); |
|
|
Cow::Borrowed(&image.pixels) |
|
|
Cow::Borrowed(&image.pixels) |
|
|
} |
|
|
} |
|
|
egui::ImageData::Font(image) => { |
|
|
epaint::ImageData::Font(image) => { |
|
|
assert_eq!( |
|
|
assert_eq!( |
|
|
width as usize * height as usize, |
|
|
width as usize * height as usize, |
|
|
image.pixels.len(), |
|
|
image.pixels.len(), |
|
@ -582,7 +581,7 @@ impl Renderer { |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub fn free_texture(&mut self, id: &egui::TextureId) { |
|
|
pub fn free_texture(&mut self, id: &epaint::TextureId) { |
|
|
self.textures.remove(id); |
|
|
self.textures.remove(id); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -590,15 +589,15 @@ impl Renderer { |
|
|
///
|
|
|
///
|
|
|
/// This could be used by custom paint hooks to render images that have been added through with
|
|
|
/// 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)
|
|
|
/// [`egui_extras::RetainedImage`](https://docs.rs/egui_extras/latest/egui_extras/image/struct.RetainedImage.html)
|
|
|
/// or [`egui::Context::load_texture`].
|
|
|
/// or [`epaint::Context::load_texture`](https://docs.rs/egui/latest/egui/struct.Context.html#method.load_texture).
|
|
|
pub fn texture( |
|
|
pub fn texture( |
|
|
&self, |
|
|
&self, |
|
|
id: &egui::TextureId, |
|
|
id: &epaint::TextureId, |
|
|
) -> Option<&(Option<wgpu::Texture>, wgpu::BindGroup)> { |
|
|
) -> Option<&(Option<wgpu::Texture>, wgpu::BindGroup)> { |
|
|
self.textures.get(id) |
|
|
self.textures.get(id) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// Registers a `wgpu::Texture` with a `egui::TextureId`.
|
|
|
/// Registers a `wgpu::Texture` with a `epaint::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.
|
|
|
/// This effectively enables off-screen rendering inside the egui UI. Texture must have
|
|
|
/// This effectively enables off-screen rendering inside the egui UI. Texture must have
|
|
@ -609,7 +608,7 @@ impl Renderer { |
|
|
device: &wgpu::Device, |
|
|
device: &wgpu::Device, |
|
|
texture: &wgpu::TextureView, |
|
|
texture: &wgpu::TextureView, |
|
|
texture_filter: wgpu::FilterMode, |
|
|
texture_filter: wgpu::FilterMode, |
|
|
) -> egui::TextureId { |
|
|
) -> epaint::TextureId { |
|
|
self.register_native_texture_with_sampler_options( |
|
|
self.register_native_texture_with_sampler_options( |
|
|
device, |
|
|
device, |
|
|
texture, |
|
|
texture, |
|
@ -622,7 +621,7 @@ impl Renderer { |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// Registers a `wgpu::Texture` with an existing `egui::TextureId`.
|
|
|
/// Registers a `wgpu::Texture` with an existing `epaint::TextureId`.
|
|
|
///
|
|
|
///
|
|
|
/// This enables applications to reuse `TextureId`s.
|
|
|
/// This enables applications to reuse `TextureId`s.
|
|
|
pub fn update_egui_texture_from_wgpu_texture( |
|
|
pub fn update_egui_texture_from_wgpu_texture( |
|
@ -630,7 +629,7 @@ impl Renderer { |
|
|
device: &wgpu::Device, |
|
|
device: &wgpu::Device, |
|
|
texture: &wgpu::TextureView, |
|
|
texture: &wgpu::TextureView, |
|
|
texture_filter: wgpu::FilterMode, |
|
|
texture_filter: wgpu::FilterMode, |
|
|
id: egui::TextureId, |
|
|
id: epaint::TextureId, |
|
|
) { |
|
|
) { |
|
|
self.update_egui_texture_from_wgpu_texture_with_sampler_options( |
|
|
self.update_egui_texture_from_wgpu_texture_with_sampler_options( |
|
|
device, |
|
|
device, |
|
@ -645,7 +644,7 @@ impl Renderer { |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// Registers a `wgpu::Texture` with a `egui::TextureId` while also accepting custom
|
|
|
/// Registers a `wgpu::Texture` with a `epaint::TextureId` while also accepting custom
|
|
|
/// `wgpu::SamplerDescriptor` options.
|
|
|
/// `wgpu::SamplerDescriptor` options.
|
|
|
///
|
|
|
///
|
|
|
/// This allows applications to specify individual minification/magnification filters as well as
|
|
|
/// This allows applications to specify individual minification/magnification filters as well as
|
|
@ -660,7 +659,7 @@ impl Renderer { |
|
|
device: &wgpu::Device, |
|
|
device: &wgpu::Device, |
|
|
texture: &wgpu::TextureView, |
|
|
texture: &wgpu::TextureView, |
|
|
sampler_descriptor: wgpu::SamplerDescriptor<'_>, |
|
|
sampler_descriptor: wgpu::SamplerDescriptor<'_>, |
|
|
) -> egui::TextureId { |
|
|
) -> epaint::TextureId { |
|
|
crate::profile_function!(); |
|
|
crate::profile_function!(); |
|
|
|
|
|
|
|
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor { |
|
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor { |
|
@ -683,14 +682,14 @@ impl Renderer { |
|
|
], |
|
|
], |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
let id = egui::TextureId::User(self.next_user_texture_id); |
|
|
let id = epaint::TextureId::User(self.next_user_texture_id); |
|
|
self.textures.insert(id, (None, bind_group)); |
|
|
self.textures.insert(id, (None, bind_group)); |
|
|
self.next_user_texture_id += 1; |
|
|
self.next_user_texture_id += 1; |
|
|
|
|
|
|
|
|
id |
|
|
id |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// Registers a `wgpu::Texture` with an existing `egui::TextureId` while also accepting custom
|
|
|
/// Registers a `wgpu::Texture` with an existing `epaint::TextureId` while also accepting custom
|
|
|
/// `wgpu::SamplerDescriptor` options.
|
|
|
/// `wgpu::SamplerDescriptor` options.
|
|
|
///
|
|
|
///
|
|
|
/// This allows applications to reuse `TextureId`s created with custom sampler options.
|
|
|
/// This allows applications to reuse `TextureId`s created with custom sampler options.
|
|
@ -700,7 +699,7 @@ impl Renderer { |
|
|
device: &wgpu::Device, |
|
|
device: &wgpu::Device, |
|
|
texture: &wgpu::TextureView, |
|
|
texture: &wgpu::TextureView, |
|
|
sampler_descriptor: wgpu::SamplerDescriptor<'_>, |
|
|
sampler_descriptor: wgpu::SamplerDescriptor<'_>, |
|
|
id: egui::TextureId, |
|
|
id: epaint::TextureId, |
|
|
) { |
|
|
) { |
|
|
crate::profile_function!(); |
|
|
crate::profile_function!(); |
|
|
|
|
|
|
|
@ -741,7 +740,7 @@ impl Renderer { |
|
|
device: &wgpu::Device, |
|
|
device: &wgpu::Device, |
|
|
queue: &wgpu::Queue, |
|
|
queue: &wgpu::Queue, |
|
|
encoder: &mut wgpu::CommandEncoder, |
|
|
encoder: &mut wgpu::CommandEncoder, |
|
|
paint_jobs: &[egui::epaint::ClippedPrimitive], |
|
|
paint_jobs: &[epaint::ClippedPrimitive], |
|
|
screen_descriptor: &ScreenDescriptor, |
|
|
screen_descriptor: &ScreenDescriptor, |
|
|
) -> Vec<wgpu::CommandBuffer> { |
|
|
) -> Vec<wgpu::CommandBuffer> { |
|
|
crate::profile_function!(); |
|
|
crate::profile_function!(); |
|
@ -801,7 +800,7 @@ impl Renderer { |
|
|
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"); |
|
|
crate::profile_scope!("primitives"); |
|
|
for egui::ClippedPrimitive { primitive, .. } in paint_jobs.iter() { |
|
|
for epaint::ClippedPrimitive { primitive, .. } in paint_jobs.iter() { |
|
|
match primitive { |
|
|
match primitive { |
|
|
Primitive::Mesh(mesh) => { |
|
|
Primitive::Mesh(mesh) => { |
|
|
{ |
|
|
{ |
|
@ -844,14 +843,17 @@ impl Renderer { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
fn create_sampler(options: egui::TextureOptions, device: &wgpu::Device) -> wgpu::Sampler { |
|
|
fn create_sampler( |
|
|
|
|
|
options: epaint::textures::TextureOptions, |
|
|
|
|
|
device: &wgpu::Device, |
|
|
|
|
|
) -> wgpu::Sampler { |
|
|
let mag_filter = match options.magnification { |
|
|
let mag_filter = match options.magnification { |
|
|
egui::TextureFilter::Nearest => wgpu::FilterMode::Nearest, |
|
|
epaint::textures::TextureFilter::Nearest => wgpu::FilterMode::Nearest, |
|
|
egui::TextureFilter::Linear => wgpu::FilterMode::Linear, |
|
|
epaint::textures::TextureFilter::Linear => wgpu::FilterMode::Linear, |
|
|
}; |
|
|
}; |
|
|
let min_filter = match options.minification { |
|
|
let min_filter = match options.minification { |
|
|
egui::TextureFilter::Nearest => wgpu::FilterMode::Nearest, |
|
|
epaint::textures::TextureFilter::Nearest => wgpu::FilterMode::Nearest, |
|
|
egui::TextureFilter::Linear => wgpu::FilterMode::Linear, |
|
|
epaint::textures::TextureFilter::Linear => wgpu::FilterMode::Linear, |
|
|
}; |
|
|
}; |
|
|
device.create_sampler(&wgpu::SamplerDescriptor { |
|
|
device.create_sampler(&wgpu::SamplerDescriptor { |
|
|
label: Some(&format!( |
|
|
label: Some(&format!( |
|
@ -893,7 +895,7 @@ struct ScissorRect { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
impl ScissorRect { |
|
|
impl ScissorRect { |
|
|
fn new(clip_rect: &egui::Rect, pixels_per_point: f32, target_size: [u32; 2]) -> Self { |
|
|
fn new(clip_rect: &epaint::Rect, pixels_per_point: f32, target_size: [u32; 2]) -> Self { |
|
|
// Transform clip rect to physical pixels:
|
|
|
// Transform clip rect to physical pixels:
|
|
|
let clip_min_x = pixels_per_point * clip_rect.min.x; |
|
|
let clip_min_x = pixels_per_point * clip_rect.min.x; |
|
|
let clip_min_y = pixels_per_point * clip_rect.min.y; |
|
|
let clip_min_y = pixels_per_point * clip_rect.min.y; |
|
|