diff --git a/crates/eframe/src/epi.rs b/crates/eframe/src/epi.rs index 9ca952fd..720a65e8 100644 --- a/crates/eframe/src/epi.rs +++ b/crates/eframe/src/epi.rs @@ -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, diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 2f42151c..4a078bde 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -683,6 +683,12 @@ mod wgpu_integration { storage: Option>, 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 diff --git a/crates/egui-wgpu/src/renderer.rs b/crates/egui-wgpu/src/renderer.rs index d5c3711a..04ccd5c3 100644 --- a/crates/egui-wgpu/src/renderer.rs +++ b/crates/egui-wgpu/src/renderer.rs @@ -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, vertex_buffers: Vec, 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"); diff --git a/crates/egui-wgpu/src/winit.rs b/crates/egui-wgpu/src/winit.rs index 33518d89..3244cfd7 100644 --- a/crates/egui-wgpu/src/winit.rs +++ b/crates/egui-wgpu/src/winit.rs @@ -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, @@ -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`]