Add depth buffer support for egui-wgpu's render pass (#2002)
* add a depth texture for wgpu callbacks * egui-wgpu: use depth from native_options * add wgpu caveat to depth_buffer docstring
This commit is contained in:
parent
162210f90e
commit
64aac30f36
4 changed files with 70 additions and 5 deletions
|
@ -259,6 +259,10 @@ pub struct NativeOptions {
|
||||||
/// Sets the number of bits in the depth buffer.
|
/// Sets the number of bits in the depth buffer.
|
||||||
///
|
///
|
||||||
/// `egui` doesn't need the depth buffer, so the default value is 0.
|
/// `egui` doesn't need the depth buffer, so the default value is 0.
|
||||||
|
///
|
||||||
|
/// On `wgpu` backends, due to limited depth texture format options, this
|
||||||
|
/// will be interpreted as a boolean (non-zero = true) for whether or not
|
||||||
|
/// specifically a `Depth32Float` buffer is used.
|
||||||
pub depth_buffer: u8,
|
pub depth_buffer: u8,
|
||||||
|
|
||||||
/// Sets the number of bits in the stencil buffer.
|
/// Sets the number of bits in the stencil buffer.
|
||||||
|
@ -266,7 +270,7 @@ pub struct NativeOptions {
|
||||||
/// `egui` doesn't need the stencil buffer, so the default value is 0.
|
/// `egui` doesn't need the stencil buffer, so the default value is 0.
|
||||||
pub stencil_buffer: u8,
|
pub stencil_buffer: u8,
|
||||||
|
|
||||||
/// Specify wether or not hardware acceleration is preferred, required, or not.
|
/// Specify whether or not hardware acceleration is preferred, required, or not.
|
||||||
///
|
///
|
||||||
/// Default: [`HardwareAcceleration::Preferred`].
|
/// Default: [`HardwareAcceleration::Preferred`].
|
||||||
pub hardware_acceleration: HardwareAcceleration,
|
pub hardware_acceleration: HardwareAcceleration,
|
||||||
|
|
|
@ -683,6 +683,12 @@ mod wgpu_integration {
|
||||||
storage: Option<Box<dyn epi::Storage>>,
|
storage: Option<Box<dyn epi::Storage>>,
|
||||||
window: winit::window::Window,
|
window: winit::window::Window,
|
||||||
) {
|
) {
|
||||||
|
let mut limits = wgpu::Limits::downlevel_webgl2_defaults();
|
||||||
|
if self.native_options.depth_buffer > 0 {
|
||||||
|
// When using a depth buffer, we have to be able to create a texture large enough for the entire surface.
|
||||||
|
limits.max_texture_dimension_2d = 8192;
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code, unused_mut, unused_unsafe)]
|
#[allow(unsafe_code, unused_mut, unused_unsafe)]
|
||||||
let painter = unsafe {
|
let painter = unsafe {
|
||||||
let mut painter = egui_wgpu::winit::Painter::new(
|
let mut painter = egui_wgpu::winit::Painter::new(
|
||||||
|
@ -691,10 +697,11 @@ mod wgpu_integration {
|
||||||
wgpu::DeviceDescriptor {
|
wgpu::DeviceDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
features: wgpu::Features::default(),
|
features: wgpu::Features::default(),
|
||||||
limits: wgpu::Limits::downlevel_webgl2_defaults(),
|
limits,
|
||||||
},
|
},
|
||||||
wgpu::PresentMode::Fifo,
|
wgpu::PresentMode::Fifo,
|
||||||
self.native_options.multisampling.max(1) as _,
|
self.native_options.multisampling.max(1) as _,
|
||||||
|
self.native_options.depth_buffer,
|
||||||
);
|
);
|
||||||
painter.set_window(Some(&window));
|
painter.set_window(Some(&window));
|
||||||
painter
|
painter
|
||||||
|
|
|
@ -121,6 +121,7 @@ struct SizedBuffer {
|
||||||
/// Render pass to render a egui based GUI.
|
/// Render pass to render a egui based GUI.
|
||||||
pub struct RenderPass {
|
pub struct RenderPass {
|
||||||
render_pipeline: wgpu::RenderPipeline,
|
render_pipeline: wgpu::RenderPipeline,
|
||||||
|
depth_texture: Option<(wgpu::Texture, wgpu::TextureView)>,
|
||||||
index_buffers: Vec<SizedBuffer>,
|
index_buffers: Vec<SizedBuffer>,
|
||||||
vertex_buffers: Vec<SizedBuffer>,
|
vertex_buffers: Vec<SizedBuffer>,
|
||||||
uniform_buffer: SizedBuffer,
|
uniform_buffer: SizedBuffer,
|
||||||
|
@ -144,6 +145,7 @@ impl RenderPass {
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
output_format: wgpu::TextureFormat,
|
output_format: wgpu::TextureFormat,
|
||||||
msaa_samples: u32,
|
msaa_samples: u32,
|
||||||
|
depth_bits: u8,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let shader = wgpu::ShaderModuleDescriptor {
|
let shader = wgpu::ShaderModuleDescriptor {
|
||||||
label: Some("egui_shader"),
|
label: Some("egui_shader"),
|
||||||
|
@ -221,6 +223,14 @@ impl RenderPass {
|
||||||
push_constant_ranges: &[],
|
push_constant_ranges: &[],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let depth_stencil = (depth_bits > 0).then(|| wgpu::DepthStencilState {
|
||||||
|
format: wgpu::TextureFormat::Depth32Float,
|
||||||
|
depth_write_enabled: false,
|
||||||
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
|
stencil: wgpu::StencilState::default(),
|
||||||
|
bias: wgpu::DepthBiasState::default(),
|
||||||
|
});
|
||||||
|
|
||||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
label: Some("egui_pipeline"),
|
label: Some("egui_pipeline"),
|
||||||
layout: Some(&pipeline_layout),
|
layout: Some(&pipeline_layout),
|
||||||
|
@ -249,7 +259,7 @@ impl RenderPass {
|
||||||
polygon_mode: wgpu::PolygonMode::default(),
|
polygon_mode: wgpu::PolygonMode::default(),
|
||||||
strip_index_format: None,
|
strip_index_format: None,
|
||||||
},
|
},
|
||||||
depth_stencil: None,
|
depth_stencil,
|
||||||
multisample: wgpu::MultisampleState {
|
multisample: wgpu::MultisampleState {
|
||||||
alpha_to_coverage_enabled: false,
|
alpha_to_coverage_enabled: false,
|
||||||
count: msaa_samples,
|
count: msaa_samples,
|
||||||
|
@ -289,9 +299,30 @@ impl RenderPass {
|
||||||
textures: HashMap::new(),
|
textures: HashMap::new(),
|
||||||
next_user_texture_id: 0,
|
next_user_texture_id: 0,
|
||||||
paint_callback_resources: TypeMap::default(),
|
paint_callback_resources: TypeMap::default(),
|
||||||
|
depth_texture: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_depth_texture(&mut self, device: &wgpu::Device, width: u32, height: u32) {
|
||||||
|
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu::TextureFormat::Depth32Float,
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
|
||||||
|
});
|
||||||
|
|
||||||
|
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
|
self.depth_texture = Some((texture, view));
|
||||||
|
}
|
||||||
|
|
||||||
/// Executes the egui render pass.
|
/// Executes the egui render pass.
|
||||||
pub fn execute(
|
pub fn execute(
|
||||||
&self,
|
&self,
|
||||||
|
@ -307,6 +338,17 @@ impl RenderPass {
|
||||||
wgpu::LoadOp::Load
|
wgpu::LoadOp::Load
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let depth_stencil_attachment = self.depth_texture.as_ref().map(|(_texture, view)| {
|
||||||
|
wgpu::RenderPassDepthStencilAttachment {
|
||||||
|
view,
|
||||||
|
depth_ops: Some(wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(1.0),
|
||||||
|
store: true,
|
||||||
|
}),
|
||||||
|
stencil_ops: None,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
view: color_attachment,
|
view: color_attachment,
|
||||||
|
@ -316,7 +358,7 @@ impl RenderPass {
|
||||||
store: true,
|
store: true,
|
||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment,
|
||||||
label: Some("egui main render pass"),
|
label: Some("egui main render pass"),
|
||||||
});
|
});
|
||||||
rpass.push_debug_group("egui_pass");
|
rpass.push_debug_group("egui_pass");
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub struct Painter<'a> {
|
||||||
device_descriptor: wgpu::DeviceDescriptor<'a>,
|
device_descriptor: wgpu::DeviceDescriptor<'a>,
|
||||||
present_mode: wgpu::PresentMode,
|
present_mode: wgpu::PresentMode,
|
||||||
msaa_samples: u32,
|
msaa_samples: u32,
|
||||||
|
depth_bits: u8,
|
||||||
|
|
||||||
instance: Instance,
|
instance: Instance,
|
||||||
adapter: Option<Adapter>,
|
adapter: Option<Adapter>,
|
||||||
|
@ -56,6 +57,7 @@ impl<'a> Painter<'a> {
|
||||||
device_descriptor: wgpu::DeviceDescriptor<'a>,
|
device_descriptor: wgpu::DeviceDescriptor<'a>,
|
||||||
present_mode: wgpu::PresentMode,
|
present_mode: wgpu::PresentMode,
|
||||||
msaa_samples: u32,
|
msaa_samples: u32,
|
||||||
|
depth_bits: u8,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let instance = wgpu::Instance::new(backends);
|
let instance = wgpu::Instance::new(backends);
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ impl<'a> Painter<'a> {
|
||||||
device_descriptor,
|
device_descriptor,
|
||||||
present_mode,
|
present_mode,
|
||||||
msaa_samples,
|
msaa_samples,
|
||||||
|
depth_bits,
|
||||||
|
|
||||||
instance,
|
instance,
|
||||||
adapter: None,
|
adapter: None,
|
||||||
|
@ -87,7 +90,8 @@ impl<'a> Painter<'a> {
|
||||||
let (device, queue) =
|
let (device, queue) =
|
||||||
pollster::block_on(adapter.request_device(&self.device_descriptor, None)).unwrap();
|
pollster::block_on(adapter.request_device(&self.device_descriptor, None)).unwrap();
|
||||||
|
|
||||||
let rpass = renderer::RenderPass::new(&device, target_format, self.msaa_samples);
|
let rpass =
|
||||||
|
renderer::RenderPass::new(&device, target_format, self.msaa_samples, self.depth_bits);
|
||||||
|
|
||||||
RenderState {
|
RenderState {
|
||||||
device: Arc::new(device),
|
device: Arc::new(device),
|
||||||
|
@ -145,6 +149,14 @@ impl<'a> Painter<'a> {
|
||||||
.configure(&render_state.device, &config);
|
.configure(&render_state.device, &config);
|
||||||
surface_state.width = width_in_pixels;
|
surface_state.width = width_in_pixels;
|
||||||
surface_state.height = height_in_pixels;
|
surface_state.height = height_in_pixels;
|
||||||
|
|
||||||
|
if self.depth_bits > 0 {
|
||||||
|
render_state.egui_rpass.write().update_depth_texture(
|
||||||
|
&render_state.device,
|
||||||
|
width_in_pixels,
|
||||||
|
height_in_pixels,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates (or clears) the [`winit::window::Window`] associated with the [`Painter`]
|
/// Updates (or clears) the [`winit::window::Window`] associated with the [`Painter`]
|
||||||
|
|
Loading…
Reference in a new issue