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.
|
||||
///
|
||||
/// `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,
|
||||
|
||||
/// 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.
|
||||
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`].
|
||||
pub hardware_acceleration: HardwareAcceleration,
|
||||
|
|
|
@ -683,6 +683,12 @@ mod wgpu_integration {
|
|||
storage: Option<Box<dyn epi::Storage>>,
|
||||
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)]
|
||||
let painter = unsafe {
|
||||
let mut painter = egui_wgpu::winit::Painter::new(
|
||||
|
@ -691,10 +697,11 @@ mod wgpu_integration {
|
|||
wgpu::DeviceDescriptor {
|
||||
label: None,
|
||||
features: wgpu::Features::default(),
|
||||
limits: wgpu::Limits::downlevel_webgl2_defaults(),
|
||||
limits,
|
||||
},
|
||||
wgpu::PresentMode::Fifo,
|
||||
self.native_options.multisampling.max(1) as _,
|
||||
self.native_options.depth_buffer,
|
||||
);
|
||||
painter.set_window(Some(&window));
|
||||
painter
|
||||
|
|
|
@ -121,6 +121,7 @@ struct SizedBuffer {
|
|||
/// Render pass to render a egui based GUI.
|
||||
pub struct RenderPass {
|
||||
render_pipeline: wgpu::RenderPipeline,
|
||||
depth_texture: Option<(wgpu::Texture, wgpu::TextureView)>,
|
||||
index_buffers: Vec<SizedBuffer>,
|
||||
vertex_buffers: Vec<SizedBuffer>,
|
||||
uniform_buffer: SizedBuffer,
|
||||
|
@ -144,6 +145,7 @@ impl RenderPass {
|
|||
device: &wgpu::Device,
|
||||
output_format: wgpu::TextureFormat,
|
||||
msaa_samples: u32,
|
||||
depth_bits: u8,
|
||||
) -> Self {
|
||||
let shader = wgpu::ShaderModuleDescriptor {
|
||||
label: Some("egui_shader"),
|
||||
|
@ -221,6 +223,14 @@ impl RenderPass {
|
|||
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 {
|
||||
label: Some("egui_pipeline"),
|
||||
layout: Some(&pipeline_layout),
|
||||
|
@ -249,7 +259,7 @@ impl RenderPass {
|
|||
polygon_mode: wgpu::PolygonMode::default(),
|
||||
strip_index_format: None,
|
||||
},
|
||||
depth_stencil: None,
|
||||
depth_stencil,
|
||||
multisample: wgpu::MultisampleState {
|
||||
alpha_to_coverage_enabled: false,
|
||||
count: msaa_samples,
|
||||
|
@ -289,9 +299,30 @@ impl RenderPass {
|
|||
textures: HashMap::new(),
|
||||
next_user_texture_id: 0,
|
||||
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.
|
||||
pub fn execute(
|
||||
&self,
|
||||
|
@ -307,6 +338,17 @@ impl RenderPass {
|
|||
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 {
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: color_attachment,
|
||||
|
@ -316,7 +358,7 @@ impl RenderPass {
|
|||
store: true,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
depth_stencil_attachment,
|
||||
label: Some("egui main render pass"),
|
||||
});
|
||||
rpass.push_debug_group("egui_pass");
|
||||
|
|
|
@ -30,6 +30,7 @@ pub struct Painter<'a> {
|
|||
device_descriptor: wgpu::DeviceDescriptor<'a>,
|
||||
present_mode: wgpu::PresentMode,
|
||||
msaa_samples: u32,
|
||||
depth_bits: u8,
|
||||
|
||||
instance: Instance,
|
||||
adapter: Option<Adapter>,
|
||||
|
@ -56,6 +57,7 @@ impl<'a> Painter<'a> {
|
|||
device_descriptor: wgpu::DeviceDescriptor<'a>,
|
||||
present_mode: wgpu::PresentMode,
|
||||
msaa_samples: u32,
|
||||
depth_bits: u8,
|
||||
) -> Self {
|
||||
let instance = wgpu::Instance::new(backends);
|
||||
|
||||
|
@ -64,6 +66,7 @@ impl<'a> Painter<'a> {
|
|||
device_descriptor,
|
||||
present_mode,
|
||||
msaa_samples,
|
||||
depth_bits,
|
||||
|
||||
instance,
|
||||
adapter: None,
|
||||
|
@ -87,7 +90,8 @@ impl<'a> Painter<'a> {
|
|||
let (device, queue) =
|
||||
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 {
|
||||
device: Arc::new(device),
|
||||
|
@ -145,6 +149,14 @@ impl<'a> Painter<'a> {
|
|||
.configure(&render_state.device, &config);
|
||||
surface_state.width = width_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`]
|
||||
|
|
Loading…
Reference in a new issue