diff --git a/shaders/voxel.wgsl b/shaders/voxel.wgsl index 1bfb5fd..e7b7ec4 100644 --- a/shaders/voxel.wgsl +++ b/shaders/voxel.wgsl @@ -73,6 +73,9 @@ fn unpack_color(color: u32) -> vec4 @group(0) @binding(5) var structure_table_pointer: array; @group(0) @binding(6) var structure_table_request_buffer: array>; +@group(1) @binding(0) var prepass_depth_sampler: sampler; +@group(1) @binding(1) var prepass_depth: texture_2d; + @vertex fn chunk(@builtin(vertex_index) index: u32, @location(0) position: vec3, @location(1) id: u32) -> VertexOutput { @@ -357,6 +360,7 @@ struct FragmentOutput { } struct FragmentPrepassOutput { + @location(0) depth_prepass: f32, // Equivalent to gl_FragDepth @builtin(frag_depth) depth: f32, // Equivalent to gl_FragDepth } @@ -377,6 +381,7 @@ fn fragment_prepass(in: VertexOutput) -> FragmentPrepassOutput //frag_out.color = result.color; frag_out.depth = depth; + frag_out.depth_prepass = depth; return frag_out; } diff --git a/src/main.rs b/src/main.rs index 0db87be..859747b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ use wgpu::BindGroupLayout; use wgpu::BlendState; use wgpu::Buffer; use wgpu::BufferUsages; +use wgpu::Color; use wgpu::ComputePipeline; use wgpu::Device; use wgpu::Extent3d; @@ -36,6 +37,7 @@ use wgpu::PipelineCompilationOptions; use wgpu::RenderPipeline; use wgpu::ShaderStages; use wgpu::Texture; +use wgpu::TextureFormat; use wgpu::TextureUsages; use wgpu::TextureView; use wgpu::util::BufferInitDescriptor; @@ -85,8 +87,10 @@ struct State queue: wgpu::Queue, size: winit::dpi::PhysicalSize, surface: wgpu::Surface<'static>, - depth_buffer: (wgpu::Texture, wgpu::TextureView, wgpu::TextureView), - prepass_depth_buffer: (wgpu::Texture, wgpu::TextureView, wgpu::TextureView), + depth_buffer: (wgpu::Texture, wgpu::TextureView), + prepass_depth_buffer: (wgpu::Texture, wgpu::TextureView), + prepass_depth: (wgpu::Texture, wgpu::TextureView), + upsampled_prepass_depth: (wgpu::Texture, wgpu::TextureView), prepass_downsampling: u32, upsample_pipeline: ComputePipeline, surface_format: wgpu::TextureFormat, @@ -95,6 +99,7 @@ struct State pipeline: RenderPipeline, prepass_pipeline: RenderPipeline, prepass_upsample_bg_layout: BindGroupLayout, + prepass_depth_bind_group_layout: BindGroupLayout, voxel_cache: Arc>>, cache_interface: Arc>, terrain_generator: Arc>, @@ -224,16 +229,17 @@ impl State ), }); - let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Voxel pipeline layout"), + let prepass_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Voxel pipeline layout"), - bind_group_layouts: &[Some(&voxel_cache.bind_group_layout())], - immediate_size: size_of::() as u32, - }); + bind_group_layouts: &[Some(&voxel_cache.bind_group_layout())], + immediate_size: size_of::() as u32, + }); let prepass_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("Render pipeline"), - layout: Some(&pipeline_layout), + layout: Some(&prepass_pipeline_layout), vertex: wgpu::VertexState { module: &shader_module, entry_point: Some("chunk"), @@ -277,7 +283,7 @@ impl State entry_point: Some("fragment_prepass"), compilation_options: wgpu::PipelineCompilationOptions::default(), targets: &[Some(wgpu::ColorTargetState { - format: surface_format, + format: TextureFormat::R32Float, blend: None, write_mask: wgpu::ColorWrites::default(), })], @@ -286,9 +292,43 @@ impl State cache: None, }); + let prepass_depth_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("prepass_upsample_bind_group_layout "), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering), + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: false }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + ], + }); + + let chunk_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Voxel pipeline layout"), + + bind_group_layouts: &[ + Some(&voxel_cache.bind_group_layout()), + Some(&prepass_depth_bind_group_layout), + ], + immediate_size: size_of::() as u32, + }); + let chunk_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("Render pipeline"), - layout: Some(&pipeline_layout), + layout: Some(&chunk_pipeline_layout), vertex: wgpu::VertexState { module: &shader_module, entry_point: Some("chunk"), @@ -350,7 +390,7 @@ impl State visibility: ShaderStages::COMPUTE, ty: wgpu::BindingType::StorageTexture { access: wgpu::StorageTextureAccess::ReadOnly, - format: wgpu::TextureFormat::Depth32Float, + format: wgpu::TextureFormat::R32Float, view_dimension: wgpu::TextureViewDimension::D2, }, count: None, @@ -360,7 +400,7 @@ impl State visibility: ShaderStages::COMPUTE, ty: wgpu::BindingType::StorageTexture { access: wgpu::StorageTextureAccess::WriteOnly, - format: wgpu::TextureFormat::Depth24PlusStencil8, + format: wgpu::TextureFormat::R32Float, view_dimension: wgpu::TextureViewDimension::D2, }, count: None, @@ -397,14 +437,14 @@ impl State {{ for(var oy = 0; oy < {prepass_downsampling}; oy ++) {{ - depth = min(depth, textureLoad(sp + vec(ox, oy), p, 0)); + depth = min(depth, textureLoad(input_tex, sp + vec2(ox, oy)).x); }} }} textureStore( output_tex, dp, - depth + vec4(depth) ); }} " @@ -430,6 +470,16 @@ impl State size.width / prepass_downsampling, size.height / prepass_downsampling, ), + prepass_depth: Self::create_prepass_depth_buffer( + &device, + size.width / prepass_downsampling, + size.height / prepass_downsampling, + ), + upsampled_prepass_depth: Self::create_prepass_depth_buffer( + &device, + size.width, + size.height, + ), prepass_downsampling, upsample_pipeline: prepass_upsample, queue, @@ -438,6 +488,7 @@ impl State pipeline: chunk_pipeline, prepass_pipeline, prepass_upsample_bg_layout, + prepass_depth_bind_group_layout, voxel_cache: Arc::new(Mutex::new(voxel_cache)), cache_interface: cache_interface.into(), insertion_debounce: true, @@ -494,11 +545,36 @@ impl State } } - fn create_depth_buffer( + fn create_prepass_depth_buffer( device: &Device, width: u32, height: u32, - ) -> (Texture, TextureView, TextureView) + ) -> (Texture, TextureView) + { + let texture = device.create_texture(&wgpu::wgt::TextureDescriptor { + label: Some("Prepass Depth buffer"), + size: Extent3d { + width, + height, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::R32Float, + usage: TextureUsages::RENDER_ATTACHMENT + | TextureUsages::TEXTURE_BINDING + | TextureUsages::STORAGE_BINDING, + view_formats: &[wgpu::TextureFormat::R32Float.add_srgb_suffix()], + }); + let texture_view = texture.create_view(&wgpu::wgt::TextureViewDescriptor { + label: Some("prepass depth view"), + ..Default::default() + }); + (texture, texture_view) + } + + fn create_depth_buffer(device: &Device, width: u32, height: u32) -> (Texture, TextureView) { let texture = device.create_texture(&wgpu::wgt::TextureDescriptor { label: Some("Depth buffer"), @@ -518,12 +594,7 @@ impl State label: Some("depth view"), ..Default::default() }); - let texture_view_upsample = texture.create_view(&wgpu::wgt::TextureViewDescriptor { - label: Some("prepass depth view upsample"), - aspect: wgpu::TextureAspect::DepthOnly, - ..Default::default() - }); - (texture, texture_view, texture_view_upsample) + (texture, texture_view) } fn configure_surface(&self) @@ -557,6 +628,13 @@ impl State new_size.width / self.prepass_downsampling, new_size.height / self.prepass_downsampling, ); + self.prepass_depth = Self::create_prepass_depth_buffer( + &self.device, + new_size.width / self.prepass_downsampling, + new_size.height / self.prepass_downsampling, + ); + self.upsampled_prepass_depth = + Self::create_prepass_depth_buffer(&self.device, new_size.width, new_size.height); } fn render(&mut self) @@ -592,6 +670,29 @@ impl State usage: BufferUsages::COPY_DST | BufferUsages::VERTEX, }); + let prepass_depth_sampler = self.device.create_sampler(&wgpu::SamplerDescriptor { + label: Some("prepass_depth_sampler"), + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + ..Default::default() + }); + + let prepass_depth_bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("prepass_depth_bind_group"), + layout: &self.prepass_depth_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Sampler(&prepass_depth_sampler), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(&self.upsampled_prepass_depth.1), + }, + ], + }); + // Create texture view. // NOTE: We must handle Timeout because the surface may be unavailable // (e.g., when the window is occluded on macOS). @@ -653,11 +754,11 @@ impl State entries: &[ wgpu::BindGroupEntry { binding: 0, - resource: wgpu::BindingResource::TextureView(&self.prepass_depth_buffer.2), + resource: wgpu::BindingResource::TextureView(&self.prepass_depth.1), }, wgpu::BindGroupEntry { binding: 1, - resource: wgpu::BindingResource::TextureView(&self.depth_buffer.2), + resource: wgpu::BindingResource::TextureView(&self.upsampled_prepass_depth.1), }, ], }); @@ -667,9 +768,22 @@ impl State { let mut renderpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: None, - color_attachments: &[], + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &self.prepass_depth.1, + depth_slice: None, + resolve_target: None, + ops: Operations { + load: wgpu::LoadOp::Clear(Color { + r: 1., + g: 1., + b: 1., + a: 1., + }), + store: wgpu::StoreOp::Store, + }, + })], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.prepass_depth_buffer.1, + view: &self.depth_buffer.1, depth_ops: Some(Operations { load: wgpu::LoadOp::Clear(1.), store: wgpu::StoreOp::Store, @@ -687,9 +801,9 @@ impl State cam_pos: self.camera.position, frame_timestamp: self.voxel_cache.lock().current_timestamp(), }]; - renderpass.set_immediates(0, unsafe { as_raw_bytes(&imm) }); renderpass.set_pipeline(&self.prepass_pipeline); + renderpass.set_immediates(0, unsafe { as_raw_bytes(&imm) }); renderpass.draw(0..36, 0..(self.instance_count as u32)); // End the renderpass. @@ -748,14 +862,15 @@ impl State }); renderpass.set_vertex_buffer(0, instance_buffer.slice(..)); renderpass.set_bind_group(0, Some(&self.voxel_cache.lock().bind_group()), &[]); + renderpass.set_bind_group(1, Some(&prepass_depth_bind_group), &[]); let imm = [Immediates { view_proj: self.camera.view_proj(), cam_pos: self.camera.position, frame_timestamp: self.voxel_cache.lock().current_timestamp(), }]; - renderpass.set_immediates(0, unsafe { as_raw_bytes(&imm) }); renderpass.set_pipeline(&self.pipeline); + renderpass.set_immediates(0, unsafe { as_raw_bytes(&imm) }); renderpass.draw(0..36, 0..(self.instance_count as u32)); // End the renderpass.