diff --git a/crates/renderling-shader/src/convolution.rs b/crates/renderling-shader/src/convolution.rs index 70161a6f..9f89cd93 100644 --- a/crates/renderling-shader/src/convolution.rs +++ b/crates/renderling-shader/src/convolution.rs @@ -12,7 +12,7 @@ use spirv_std::{ #[cfg(target_arch = "spirv")] use spirv_std::num_traits::Float; -use crate::{pbr, IsVector}; +use crate::{pbr, stage::Camera, IsVector}; fn radical_inverse_vdc(mut bits: u32) -> f32 { bits = (bits << 16u32) | (bits >> 16u32); @@ -149,40 +149,46 @@ pub fn integrate_brdf_doesnt_work(mut n_dot_v: f32, roughness: f32) -> Vec2 { Vec2::new(a, b) } -/// Expects a slab to contain a [`crate::stage::Camera`] followed by a `f32` +/// Used by [`vertex_prefilter_environment_cubemap`] to read the camera and +/// roughness values from the slab. +#[derive(Default, SlabItem)] +pub struct VertexPrefilterEnvironmentCubemapIds { + pub camera: Id, + pub roughness: Id, +} + +/// Uses the `instance_index` as the [`Id`] of a [`PrefilterEnvironmentIds`]. /// roughness value. -// TODO: merge this with the standard pass-thru cubemap vertex shader. #[spirv(vertex)] pub fn vertex_prefilter_environment_cubemap( + #[spirv(instance_index)] instance_index: u32, #[spirv(vertex_index)] vertex_id: u32, #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] slab: &[u32], out_pos: &mut Vec3, + out_roughness: &mut f32, #[spirv(position)] gl_pos: &mut Vec4, ) { let in_pos = crate::math::CUBE[vertex_id as usize]; - let camera = slab.read::(0u32.into()); + let VertexPrefilterEnvironmentCubemapIds { camera, roughness } = + slab.read(Id::new(instance_index)); + let camera = slab.read(camera); + *out_roughness = slab.read(roughness); *out_pos = in_pos; *gl_pos = camera.projection * camera.view * in_pos.extend(1.0); } /// Lambertian prefilter. -/// -/// Expects a slab to contain a [`crate::stage::Camera`] followed by a `f32` -/// roughness value. #[spirv(fragment)] pub fn fragment_prefilter_environment_cubemap( - #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] slab: &[u32], #[spirv(descriptor_set = 0, binding = 1)] environment_cubemap: &Cubemap, #[spirv(descriptor_set = 0, binding = 2)] sampler: &Sampler, in_pos: Vec3, + in_roughness: f32, frag_color: &mut Vec4, ) { - let roughness = slab.read(Id::::from(crate::stage::Camera::slab_size())); let mut n = in_pos.alt_norm_or_zero(); // `wgpu` and vulkan's y coords are flipped from opengl n.y *= -1.0; - // These moves are redundant but the names have connections to the PBR - // equations. let r = n; let v = r; @@ -191,12 +197,12 @@ pub fn fragment_prefilter_environment_cubemap( for i in 0..SAMPLE_COUNT { let xi = hammersley(i, SAMPLE_COUNT); - let h = importance_sample_ggx(xi, n, roughness); + let h = importance_sample_ggx(xi, n, in_roughness); let l = (2.0 * v.dot(h) * h - v).alt_norm_or_zero(); let n_dot_l = n.dot(l).max(0.0); if n_dot_l > 0.0 { - let mip_level = if roughness == 0.0 { + let mip_level = if in_roughness == 0.0 { 0.0 } else { calc_lod(n_dot_l) diff --git a/crates/renderling-shader/src/skybox.rs b/crates/renderling-shader/src/skybox.rs index e75d9c4a..6adeda62 100644 --- a/crates/renderling-shader/src/skybox.rs +++ b/crates/renderling-shader/src/skybox.rs @@ -56,18 +56,19 @@ pub fn fragment_cubemap( /// Draws a cubemap. /// -/// Expects there to be a [`Camera`] in the slab at index 0. +/// Uses the `instance_index` as the [`Id`] for a [`Camera`]. /// /// Used to create a cubemap from an equirectangular image as well as cubemap /// convolutions. #[spirv(vertex)] pub fn vertex_cubemap( + #[spirv(instance_index)] camera_index: u32, #[spirv(vertex_index)] vertex_index: u32, #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] slab: &[u32], local_pos: &mut Vec3, #[spirv(position)] gl_pos: &mut Vec4, ) { - let camera = slab.read(Id::::new(0)); + let camera = slab.read(Id::::new(camera_index)); let pos = crate::math::CUBE[vertex_index as usize]; *local_pos = pos; *gl_pos = camera.projection * camera.view * pos.extend(1.0); diff --git a/crates/renderling/src/linkage/convolution-fragment_bloom.spv b/crates/renderling/src/linkage/convolution-fragment_bloom.spv index d38905e1..a9709123 100644 Binary files a/crates/renderling/src/linkage/convolution-fragment_bloom.spv and b/crates/renderling/src/linkage/convolution-fragment_bloom.spv differ diff --git a/crates/renderling/src/linkage/convolution-fragment_brdf_lut_convolution.spv b/crates/renderling/src/linkage/convolution-fragment_brdf_lut_convolution.spv index 3e02830b..a9c0d3ff 100644 Binary files a/crates/renderling/src/linkage/convolution-fragment_brdf_lut_convolution.spv and b/crates/renderling/src/linkage/convolution-fragment_brdf_lut_convolution.spv differ diff --git a/crates/renderling/src/linkage/convolution-fragment_prefilter_environment_cubemap.spv b/crates/renderling/src/linkage/convolution-fragment_prefilter_environment_cubemap.spv index 271f3206..16dadac5 100644 Binary files a/crates/renderling/src/linkage/convolution-fragment_prefilter_environment_cubemap.spv and b/crates/renderling/src/linkage/convolution-fragment_prefilter_environment_cubemap.spv differ diff --git a/crates/renderling/src/linkage/convolution-vertex_brdf_lut_convolution.spv b/crates/renderling/src/linkage/convolution-vertex_brdf_lut_convolution.spv index f93f0442..062f70b4 100644 Binary files a/crates/renderling/src/linkage/convolution-vertex_brdf_lut_convolution.spv and b/crates/renderling/src/linkage/convolution-vertex_brdf_lut_convolution.spv differ diff --git a/crates/renderling/src/linkage/convolution-vertex_prefilter_environment_cubemap.spv b/crates/renderling/src/linkage/convolution-vertex_prefilter_environment_cubemap.spv index e3ddb416..2c24629b 100644 Binary files a/crates/renderling/src/linkage/convolution-vertex_prefilter_environment_cubemap.spv and b/crates/renderling/src/linkage/convolution-vertex_prefilter_environment_cubemap.spv differ diff --git a/crates/renderling/src/linkage/skybox-slabbed_vertex.spv b/crates/renderling/src/linkage/skybox-slabbed_vertex.spv deleted file mode 100644 index 500025ce..00000000 Binary files a/crates/renderling/src/linkage/skybox-slabbed_vertex.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/skybox-stage_skybox_cubemap.spv b/crates/renderling/src/linkage/skybox-stage_skybox_cubemap.spv deleted file mode 100644 index c025bede..00000000 Binary files a/crates/renderling/src/linkage/skybox-stage_skybox_cubemap.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/skybox-vertex.spv b/crates/renderling/src/linkage/skybox-vertex.spv index 7415300b..1283523f 100644 Binary files a/crates/renderling/src/linkage/skybox-vertex.spv and b/crates/renderling/src/linkage/skybox-vertex.spv differ diff --git a/crates/renderling/src/linkage/skybox-vertex_cubemap.spv b/crates/renderling/src/linkage/skybox-vertex_cubemap.spv index 59f35a06..f7054025 100644 Binary files a/crates/renderling/src/linkage/skybox-vertex_cubemap.spv and b/crates/renderling/src/linkage/skybox-vertex_cubemap.spv differ diff --git a/crates/renderling/src/linkage/skybox-vertex_position_passthru.spv b/crates/renderling/src/linkage/skybox-vertex_position_passthru.spv deleted file mode 100644 index 1f63bae5..00000000 Binary files a/crates/renderling/src/linkage/skybox-vertex_position_passthru.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/stage-compute_cull_entities.spv b/crates/renderling/src/linkage/stage-compute_cull_entities.spv index 8f6199b2..902bca54 100644 Binary files a/crates/renderling/src/linkage/stage-compute_cull_entities.spv and b/crates/renderling/src/linkage/stage-compute_cull_entities.spv differ diff --git a/crates/renderling/src/linkage/stage-gltf_fragment.spv b/crates/renderling/src/linkage/stage-gltf_fragment.spv index 7c00fe26..84ab130f 100644 Binary files a/crates/renderling/src/linkage/stage-gltf_fragment.spv and b/crates/renderling/src/linkage/stage-gltf_fragment.spv differ diff --git a/crates/renderling/src/linkage/stage-gltf_vertex.spv b/crates/renderling/src/linkage/stage-gltf_vertex.spv index 2d13d2b9..3ddefd49 100644 Binary files a/crates/renderling/src/linkage/stage-gltf_vertex.spv and b/crates/renderling/src/linkage/stage-gltf_vertex.spv differ diff --git a/crates/renderling/src/linkage/stage-main_fragment_scene.spv b/crates/renderling/src/linkage/stage-main_fragment_scene.spv index ce093851..0a63c106 100644 Binary files a/crates/renderling/src/linkage/stage-main_fragment_scene.spv and b/crates/renderling/src/linkage/stage-main_fragment_scene.spv differ diff --git a/crates/renderling/src/linkage/stage-main_vertex_scene.spv b/crates/renderling/src/linkage/stage-main_vertex_scene.spv index ee38b8ff..df2b7b0b 100644 Binary files a/crates/renderling/src/linkage/stage-main_vertex_scene.spv and b/crates/renderling/src/linkage/stage-main_vertex_scene.spv differ diff --git a/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv b/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv index a81e163e..1fad7572 100644 Binary files a/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv and b/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv differ diff --git a/crates/renderling/src/linkage/tonemapping-fragment.spv b/crates/renderling/src/linkage/tonemapping-fragment.spv index 3881f7e5..4a8c61aa 100644 Binary files a/crates/renderling/src/linkage/tonemapping-fragment.spv and b/crates/renderling/src/linkage/tonemapping-fragment.spv differ diff --git a/crates/renderling/src/linkage/tonemapping-vertex.spv b/crates/renderling/src/linkage/tonemapping-vertex.spv index e312c4df..35d63094 100644 Binary files a/crates/renderling/src/linkage/tonemapping-vertex.spv and b/crates/renderling/src/linkage/tonemapping-vertex.spv differ diff --git a/crates/renderling/src/linkage/tutorial-implicit_isosceles_vertex.spv b/crates/renderling/src/linkage/tutorial-implicit_isosceles_vertex.spv index 78e2fa49..1b706e6c 100644 Binary files a/crates/renderling/src/linkage/tutorial-implicit_isosceles_vertex.spv and b/crates/renderling/src/linkage/tutorial-implicit_isosceles_vertex.spv differ diff --git a/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv b/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv index 84a57594..8ce4c700 100644 Binary files a/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv and b/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv differ diff --git a/crates/renderling/src/linkage/tutorial-slabbed_vertices.spv b/crates/renderling/src/linkage/tutorial-slabbed_vertices.spv index c3ca3bd5..9001018d 100644 Binary files a/crates/renderling/src/linkage/tutorial-slabbed_vertices.spv and b/crates/renderling/src/linkage/tutorial-slabbed_vertices.spv differ diff --git a/crates/renderling/src/linkage/tutorial-slabbed_vertices_no_instance.spv b/crates/renderling/src/linkage/tutorial-slabbed_vertices_no_instance.spv index cd9b6ef4..f6ab41b9 100644 Binary files a/crates/renderling/src/linkage/tutorial-slabbed_vertices_no_instance.spv and b/crates/renderling/src/linkage/tutorial-slabbed_vertices_no_instance.spv differ diff --git a/crates/renderling/src/linkage/ui-vertex.spv b/crates/renderling/src/linkage/ui-vertex.spv index 61f7ecf6..e6374f92 100644 Binary files a/crates/renderling/src/linkage/ui-vertex.spv and b/crates/renderling/src/linkage/ui-vertex.spv differ diff --git a/crates/renderling/src/skybox.rs b/crates/renderling/src/skybox.rs index 99976cee..d4822998 100644 --- a/crates/renderling/src/skybox.rs +++ b/crates/renderling/src/skybox.rs @@ -1,10 +1,13 @@ //! An HDR skybox. use std::sync::Arc; -use crabslab::{CpuSlab, Slab, SlabItem, WgpuBuffer}; +use crabslab::{CpuSlab, GrowableSlab, Slab, SlabItem, WgpuBuffer}; use glam::{Mat4, Vec3}; -use crate::{atlas::AtlasImage, shader::stage::Camera}; +use crate::{ + atlas::AtlasImage, + shader::{convolution::VertexPrefilterEnvironmentCubemapIds, stage::Camera}, +}; /// Render pipeline used to draw a skybox. pub struct SkyboxRenderPipeline(pub wgpu::RenderPipeline); @@ -17,7 +20,7 @@ pub fn skybox_bindgroup_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { binding: 0, visibility: wgpu::ShaderStages::VERTEX, ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, + ty: wgpu::BufferBindingType::Storage { read_only: true }, has_dynamic_offset: false, min_binding_size: None, }, @@ -86,7 +89,7 @@ pub fn create_skybox_render_pipeline( }); SkyboxRenderPipeline( device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("skybox pipeline"), + label: Some("skybox render pipeline"), layout: Some(&pp_layout), vertex: wgpu::VertexState { module: &vertex_shader, @@ -468,8 +471,9 @@ impl Skybox { ); let mut slab = CpuSlab::new(buffer); // Write the camera at 0 and then the roughness - slab.write(0u32.into(), &Camera::default().with_projection(proj)); - slab.write(Camera::slab_size().into(), &0.0f32); + let camera = slab.append(&Camera::default().with_projection(proj)); + let roughness = slab.append(&0.0f32); + let id = slab.append(&VertexPrefilterEnvironmentCubemapIds { camera, roughness }); let (pipeline, bindgroup) = crate::ibl::prefiltered_environment::create_pipeline_and_bindgroup( &device, @@ -485,8 +489,7 @@ impl Skybox { let mip_height: u32 = 128 >> mip_level; // update the roughness for these mips - let roughness = mip_level as f32 / 4.0; - slab.write(Camera::slab_size().into(), &roughness); + slab.write(roughness, &(mip_level as f32 / 4.0)); let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("specular convolution"), @@ -508,7 +511,7 @@ impl Skybox { ); // update the view to point at one of the cube faces - slab.write(0u32.into(), &Camera::new(proj, views[i])); + slab.write(camera, &Camera::new(proj, views[i])); { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { @@ -526,7 +529,7 @@ impl Skybox { render_pass.set_pipeline(&pipeline); render_pass.set_bind_group(0, &bindgroup, &[]); - render_pass.draw(0..36, 0..1); + render_pass.draw(0..36, id.inner()..id.inner() + 1); } queue.submit([encoder.finish()]); @@ -639,7 +642,6 @@ impl Skybox { mod test { use crabslab::GrowableSlab; use glam::Vec3; - use img_diff::DiffCfg; use super::*; use crate::Renderling; diff --git a/crates/renderling/src/stage.rs b/crates/renderling/src/stage.rs index 87a6b325..faea6e4b 100644 --- a/crates/renderling/src/stage.rs +++ b/crates/renderling/src/stage.rs @@ -56,6 +56,7 @@ pub struct Stage { pub(crate) slab: Arc>>, pub(crate) atlas: Arc>, pub(crate) skybox: Arc>, + pub(crate) skybox_bindgroup: Arc>>>, pub(crate) pipeline: Arc>>>, pub(crate) skybox_pipeline: Arc>>>, pub(crate) has_skybox: Arc, @@ -123,6 +124,7 @@ impl Stage { pipeline: Default::default(), atlas: Arc::new(RwLock::new(atlas)), skybox: Arc::new(RwLock::new(Skybox::empty(device.clone(), queue.clone()))), + skybox_bindgroup: Default::default(), skybox_pipeline: Default::default(), has_skybox: Arc::new(AtomicBool::new(false)), has_bloom: Arc::new(AtomicBool::new(false)), @@ -305,76 +307,39 @@ impl Stage { } /// Return the skybox render pipeline, creating it if necessary. - pub fn get_skybox_pipeline(&self) -> Arc { - fn create_skybox_render_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline { - log::trace!("creating stage's skybox render pipeline"); - let vertex_shader = device - .create_shader_module(wgpu::include_spirv!("linkage/skybox-slabbed_vertex.spv")); - let fragment_shader = device.create_shader_module(wgpu::include_spirv!( - "linkage/skybox-stage_skybox_cubemap.spv" - )); - let stage_slab_buffers_layout = Stage::buffers_bindgroup_layout(&device); - let textures_layout = Stage::textures_bindgroup_layout(&device); - let label = Some("stage skybox"); - let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label, - bind_group_layouts: &[&stage_slab_buffers_layout, &textures_layout], - push_constant_ranges: &[], - }); - - device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("skybox pipeline"), - layout: Some(&layout), - vertex: wgpu::VertexState { - module: &vertex_shader, - entry_point: "skybox::slabbed_vertex", - buffers: &[], - }, - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: None, - unclipped_depth: false, - polygon_mode: wgpu::PolygonMode::Fill, - conservative: false, - }, - depth_stencil: Some(wgpu::DepthStencilState { - format: wgpu::TextureFormat::Depth32Float, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::LessEqual, - stencil: wgpu::StencilState::default(), - bias: wgpu::DepthBiasState::default(), - }), - multisample: wgpu::MultisampleState { - mask: !0, - alpha_to_coverage_enabled: false, - count: 1, - }, - fragment: Some(wgpu::FragmentState { - module: &fragment_shader, - // TODO: remove renderling_shader::skybox::fragment_cubemap after porting - // to GLTF - entry_point: "skybox::stage_skybox_cubemap", - targets: &[Some(wgpu::ColorTargetState { - format: crate::hdr::HdrSurface::TEXTURE_FORMAT, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - })], - }), - multiview: None, - }) - } - + pub fn get_skybox_pipeline_and_bindgroup( + &self, + ) -> (Arc, Arc) { // UNWRAP: safe because we're only ever called from the render thread. let mut pipeline = self.skybox_pipeline.write().unwrap(); - if let Some(pipeline) = pipeline.as_ref() { + let pipeline = if let Some(pipeline) = pipeline.as_ref() { pipeline.clone() } else { - let p = Arc::new(create_skybox_render_pipeline(&self.device)); + let p = Arc::new( + crate::skybox::create_skybox_render_pipeline( + &self.device, + crate::hdr::HdrSurface::TEXTURE_FORMAT, + ) + .0, + ); *pipeline = Some(p.clone()); p - } + }; + // UNWRAP: safe because we're only ever called from the render thread. + let mut bindgroup = self.skybox_bindgroup.lock().unwrap(); + let bindgroup = if let Some(bindgroup) = bindgroup.as_ref() { + bindgroup.clone() + } else { + let slab = self.slab.read().unwrap(); + let bg = Arc::new(crate::skybox::create_skybox_bindgroup( + &self.device, + slab.as_ref().get_buffer(), + &self.skybox.read().unwrap().environment_cubemap, + )); + *bindgroup = Some(bg.clone()); + bg + }; + (pipeline, bindgroup) } /// Return the main render pipeline, creating it if necessary. @@ -734,8 +699,9 @@ pub fn stage_render( let pipeline = stage.get_pipeline(); let slab_buffers_bindgroup = stage.get_slab_buffers_bindgroup(); let textures_bindgroup = stage.get_textures_bindgroup(); - let may_skybox_pipeline = if stage.has_skybox.load(std::sync::atomic::Ordering::Relaxed) { - Some(stage.get_skybox_pipeline()) + let has_skybox = stage.has_skybox.load(std::sync::atomic::Ordering::Relaxed); + let may_skybox_pipeline_and_bindgroup = if has_skybox { + Some(stage.get_skybox_pipeline_and_bindgroup()) } else { None }; @@ -780,11 +746,12 @@ pub fn stage_render( * stage.number_of_indirect_draws()); */ } - if let Some(pipeline) = may_skybox_pipeline.as_ref() { + if let Some((pipeline, bindgroup)) = may_skybox_pipeline_and_bindgroup.as_ref() { log::trace!("rendering skybox"); // UNWRAP: if we can't acquire the lock we want to panic. let skybox = stage.skybox.read().unwrap(); render_pass.set_pipeline(pipeline); + render_pass.set_bind_group(0, bindgroup, &[]); render_pass.draw(0..36, skybox.camera.inner()..skybox.camera.inner() + 1); } }