diff --git a/Cargo.toml b/Cargo.toml index 90a708d3..f613c64f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,8 @@ members = [ "crates/renderling", "crates/renderling-shader", "crates/renderling-gpui", - "crates/sandbox", "crates/renderling-derive", + "crates/renderling-derive", + "crates/sandbox", ] exclude = ["./shaders"] diff --git a/NOTES.md b/NOTES.md index 2e8ec433..419d1e22 100644 --- a/NOTES.md +++ b/NOTES.md @@ -12,14 +12,15 @@ Just pro-cons on tech choices and little things I don't want to forget whil impl * sharing code on CPU and GPU - sanity testing GPU code on CPU using regular tests + - ability to run shaders on either CPU or GPU and profile * it's Rust - using cargo and Rust module system - expressions! ## cons / limititions -* can't use enums (but you can't in glsl or hlsl or msl or wgsl either) -* struct layout size/alignment errors can be really tricky +* ~~can't use enums (but you can't in glsl or hlsl or msl or wgsl either)~~ you _can_ but they must be simple +* ~~struct layout size/alignment errors can be really tricky~~ solved by using a slab * rust code must be no-std * don't use `while let` or `while` loops * for loops are hit or miss, sometimes they work and sometimes they don't @@ -46,8 +47,6 @@ Just pro-cons on tech choices and little things I don't want to forget whil impl ## cons * no support for arrays of textures on web, yet -* not yet 1.0 (on by default in chrome beta) -* ~~what happens if WebGPU the standard fails? (everyone doubts it will)~~ * atomics are not supported in the Naga SPIRV frontend, which limits the capabilities of compute - see [the related Naga issue](https://github.com/gfx-rs/naga/issues/2301) diff --git a/README.md b/README.md index a83273ad..1d92081d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # renderling 🍖 This aspires to be a modern "GPU-driven" renderer. It is alpha software. I'm still learning, but quickly! diff --git a/crates/renderling-derive/src/lib.rs b/crates/renderling-derive/src/lib.rs index 21927a63..9d9ecae1 100644 --- a/crates/renderling-derive/src/lib.rs +++ b/crates/renderling-derive/src/lib.rs @@ -1,13 +1,13 @@ //! Provides derive macros for `renderling`. use quote::quote; use syn::{ - spanned::Spanned, Data, DataStruct, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, - Ident, Type, WhereClause, WherePredicate, Index, + spanned::Spanned, Data, DataStruct, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, Ident, + Index, Type, WhereClause, WherePredicate, }; enum FieldName { Index(Index), - Ident(Ident) + Ident(Ident), } struct Params { @@ -54,7 +54,12 @@ fn get_params(input: &DeriveInput) -> syn::Result { .ident .clone() .map(FieldName::Ident) - .unwrap_or_else(|| FieldName::Index(Index{index:i as u32, span: field.span()})) + .unwrap_or_else(|| { + FieldName::Index(Index { + index: i as u32, + span: field.span(), + }) + }) }) .collect(); Ok(Params { @@ -72,7 +77,7 @@ pub fn derive_from_slab(input: proc_macro::TokenStream) -> proc_macro::TokenStre let Params { sizes, field_tys, - field_names + field_names, } = match get_params(&input) { Ok(c) => c, Err(e) => return e.into_compile_error().into(), @@ -93,17 +98,21 @@ pub fn derive_from_slab(input: proc_macro::TokenStream) -> proc_macro::TokenStre constrain_system_data_types(where_clause, &field_tys) } let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let set_index_field_names = field_names.iter().map(|name| match name { - FieldName::Index(i) => quote!{ - let index = self.#i.read_slab(index, slab); - }, - FieldName::Ident(field) => quote! { - let index = self.#field.read_slab(index, slab); - }, - }) - .collect::>(); - let write_index_field_names = field_names.into_iter().map(|name| match name { - FieldName::Index(i) => quote!{ + let set_index_field_names = field_names + .iter() + .map(|name| match name { + FieldName::Index(i) => quote! { + let index = self.#i.read_slab(index, slab); + }, + FieldName::Ident(field) => quote! { + let index = self.#field.read_slab(index, slab); + }, + }) + .collect::>(); + let write_index_field_names = field_names + .iter() + .map(|name| match name { + FieldName::Index(i) => quote! { let index = self.#i.write_slab(index, slab); }, FieldName::Ident(field) => quote! { @@ -111,7 +120,32 @@ pub fn derive_from_slab(input: proc_macro::TokenStream) -> proc_macro::TokenStre }, }) .collect::>(); + + let mut offset_tys = vec![]; + let mut offsets = vec![]; + for (name, ty) in field_names.iter().zip(field_tys.iter()) { + let ident = match name { + FieldName::Index(i) => Ident::new(&format!("offset_of_{}", i.index), i.span), + FieldName::Ident(field) => Ident::new(&format!("offset_of_{}", field), field.span()), + }; + offsets.push( + quote!{ + pub fn #ident() -> usize { + #(<#offset_tys as renderling_shader::slab::Slabbed>::slab_size()+)* + 0 + } + } + ); + offset_tys.push(ty.clone()); + } + let output = quote! { + #[automatically_derived] + /// Offsets into the slab buffer for each field. + impl #impl_generics #name #ty_generics { + #(#offsets)* + } + #[automatically_derived] impl #impl_generics renderling_shader::slab::Slabbed for #name #ty_generics #where_clause { diff --git a/crates/renderling-shader/src/array.rs b/crates/renderling-shader/src/array.rs index b79946c1..17911185 100644 --- a/crates/renderling-shader/src/array.rs +++ b/crates/renderling-shader/src/array.rs @@ -4,15 +4,30 @@ use core::marker::PhantomData; use crate::id::Id; use crate::slab::Slabbed; -#[cfg_attr(not(target_arch = "spirv"), derive(Debug))] #[repr(C)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy)] pub struct Array { index: u32, len: u32, _phantom: PhantomData, } +impl core::fmt::Debug for Array { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Array") + .field("index", &self.index) + .field("len", &self.len) + .field("_phantom", &self._phantom) + .finish() + } +} + +impl PartialEq for Array { + fn eq(&self, other: &Self) -> bool { + self.index == other.index && self.len == other.len + } +} + impl Slabbed for Array { fn slab_size() -> usize { 2 diff --git a/crates/renderling-shader/src/convolution.rs b/crates/renderling-shader/src/convolution.rs index a4475a1d..d84321f2 100644 --- a/crates/renderling-shader/src/convolution.rs +++ b/crates/renderling-shader/src/convolution.rs @@ -5,7 +5,7 @@ use glam::{UVec2, Vec2, Vec3, Vec4, Vec4Swizzles}; use spirv_std::{ image::{Cubemap, Image2d}, num_traits::Zero, - Sampler, + spirv, Sampler, }; #[cfg(target_arch = "spirv")] @@ -148,21 +148,23 @@ pub fn integrate_brdf_doesnt_work(mut n_dot_v: f32, roughness: f32) -> Vec2 { Vec2::new(a, b) } +#[spirv(vertex)] pub fn vertex_prefilter_environment_cubemap( - constants: &GpuConstants, + #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &GpuConstants, in_pos: Vec3, out_pos: &mut Vec3, - gl_pos: &mut Vec4, + #[spirv(position)] gl_pos: &mut Vec4, ) { *out_pos = in_pos; *gl_pos = constants.camera_projection * constants.camera_view * in_pos.extend(1.0); } /// Lambertian prefilter. +#[spirv(fragment)] pub fn fragment_prefilter_environment_cubemap( - roughness: &f32, - environment_cubemap: &Cubemap, - sampler: &Sampler, + #[spirv(uniform, descriptor_set = 0, binding = 1)] roughness: &f32, + #[spirv(descriptor_set = 0, binding = 2)] environment_cubemap: &Cubemap, + #[spirv(descriptor_set = 0, binding = 3)] sampler: &Sampler, in_pos: Vec3, frag_color: &mut Vec4, ) { @@ -222,29 +224,37 @@ pub fn calc_lod(n_dot_l: f32) -> f32 { .log2() } -pub fn vertex_generate_mipmap(vertex_id: u32, out_uv: &mut Vec2, gl_pos: &mut Vec4) { +#[spirv(vertex)] +pub fn vertex_generate_mipmap( + #[spirv(vertex_index)] vertex_id: u32, + out_uv: &mut Vec2, + #[spirv(position)] gl_pos: &mut Vec4, +) { let i = vertex_id as usize; *out_uv = crate::math::UV_COORD_QUAD_CCW[i]; *gl_pos = crate::math::CLIP_SPACE_COORD_QUAD_CCW[i]; } +#[spirv(fragment)] pub fn fragment_generate_mipmap( - texture: &Image2d, - sampler: &Sampler, + #[spirv(descriptor_set = 0, binding = 0)] texture: &Image2d, + #[spirv(descriptor_set = 0, binding = 1)] sampler: &Sampler, in_uv: Vec2, frag_color: &mut Vec4, ) { *frag_color = texture.sample(*sampler, in_uv); } +#[spirv(fragment)] pub fn fragment_bloom( - horizontal: bool, - UVec2{x, y}: &UVec2, - texture: &Image2d, - sampler: &Sampler, + #[spirv(uniform, descriptor_set = 0, binding = 0)] horizontal: &u32, + #[spirv(uniform, descriptor_set = 0, binding = 1)] UVec2 { x, y }: &UVec2, + #[spirv(descriptor_set = 0, binding = 2)] texture: &Image2d, + #[spirv(descriptor_set = 0, binding = 3)] sampler: &Sampler, in_uv: Vec2, frag_color: &mut Vec4, ) { + let horizontal = *horizontal != 0; let weight = [0.227027f32, 0.1945946, 0.1216216, 0.054054, 0.016216]; let texel_offset = 1.0 / Vec2::new(*x as f32, *y as f32); let mut result = texture.sample(*sampler, in_uv).xyz() * weight[0]; @@ -263,6 +273,22 @@ pub fn fragment_bloom( *frag_color = result.extend(1.0); } +#[spirv(vertex)] +pub fn vertex_brdf_lut_convolution( + in_pos: glam::Vec3, + in_uv: glam::Vec2, + out_uv: &mut glam::Vec2, + #[spirv(position)] gl_pos: &mut glam::Vec4, +) { + *out_uv = in_uv; + *gl_pos = in_pos.extend(1.0); +} + +#[spirv(fragment)] +pub fn fragment_brdf_lut_convolution(in_uv: glam::Vec2, out_color: &mut glam::Vec2) { + *out_color = integrate_brdf(in_uv.x, in_uv.y); +} + #[cfg(test)] mod test { use super::*; diff --git a/crates/renderling-shader/src/debug.rs b/crates/renderling-shader/src/debug.rs index cde5eea4..83fd6518 100644 --- a/crates/renderling-shader/src/debug.rs +++ b/crates/renderling-shader/src/debug.rs @@ -92,7 +92,7 @@ impl DebugChannel { Self::Emissive, Self::UvEmissive, Self::EmissiveFactor, - Self::EmissiveStrength + Self::EmissiveStrength, ] } } @@ -101,10 +101,15 @@ impl DebugChannel { /// /// Create one using `DebugChannel::into`. #[repr(transparent)] -#[cfg_attr(not(target_arch = "spirv"), derive(Debug))] #[derive(Default, Clone, Copy, PartialEq, Eq, bytemuck::Pod, bytemuck::Zeroable, Slabbed)] pub struct DebugMode(u32); +impl core::fmt::Debug for DebugMode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("DebugMode").field(&self.0).finish() + } +} + impl From for DebugMode { fn from(value: DebugChannel) -> Self { DebugMode(value as u32) diff --git a/crates/renderling-shader/src/id.rs b/crates/renderling-shader/src/id.rs index 69cc67bd..c36dff76 100644 --- a/crates/renderling-shader/src/id.rs +++ b/crates/renderling-shader/src/id.rs @@ -78,6 +78,38 @@ impl std::fmt::Debug for Id { } } +impl core::ops::Add for Id { + type Output = Self; + + fn add(self, rhs: usize) -> Self::Output { + Id::new(self.0 + rhs as u32) + } +} + +impl core::ops::Add> for usize { + type Output = Id; + + fn add(self, rhs: Id) -> Self::Output { + Id::new(self as u32 + rhs.0 as u32) + } +} + +impl core::ops::Add for Id { + type Output = Self; + + fn add(self, rhs: u32) -> Self::Output { + Id::new(self.0 + rhs) + } +} + +impl core::ops::Add> for u32 { + type Output = Id; + + fn add(self, rhs: Id) -> Self::Output { + Id::new(self + rhs.0) + } +} + impl Id { pub const NONE: Self = Id::new(ID_NONE); diff --git a/crates/renderling-shader/src/skybox.rs b/crates/renderling-shader/src/skybox.rs index b8329f35..210cb35a 100644 --- a/crates/renderling-shader/src/skybox.rs +++ b/crates/renderling-shader/src/skybox.rs @@ -1,7 +1,10 @@ //! Skybox shader. use glam::{Mat3, Mat4, Vec2, Vec3, Vec4, Vec4Swizzles}; -use spirv_std::{image::{Image2d, Cubemap}, Sampler}; +use spirv_std::{ + image::{Cubemap, Image2d}, + spirv, Sampler, +}; #[cfg(target_arch = "spirv")] use spirv_std::num_traits::Float; @@ -19,7 +22,13 @@ pub fn direction_to_equirectangular_uv(dir: Vec3) -> Vec2 { uv } -pub fn vertex(vertex_id: u32, constants: &GpuConstants, local_pos: &mut Vec3, gl_pos: &mut Vec4) { +#[spirv(vertex)] +pub fn vertex( + #[spirv(vertex_index)] vertex_id: u32, + #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &GpuConstants, + local_pos: &mut Vec3, + #[spirv(position)] gl_pos: &mut Vec4, +) { let point = math::CUBE[vertex_id as usize]; *local_pos = point; let camera_view_without_translation = Mat3::from_mat4(constants.camera_view); @@ -29,9 +38,10 @@ pub fn vertex(vertex_id: u32, constants: &GpuConstants, local_pos: &mut Vec3, gl } /// Colors a skybox using a cubemap texture. +#[spirv(fragment)] pub fn fragment_cubemap( - texture: &Cubemap, - sampler: &Sampler, + #[spirv(descriptor_set = 0, binding = 1)] texture: &Cubemap, + #[spirv(descriptor_set = 0, binding = 2)] sampler: &Sampler, local_pos: Vec3, out_color: &mut Vec4, ) { @@ -43,20 +53,22 @@ pub fn fragment_cubemap( /// while transforming `gl_pos` by the camera projection*view; /// /// Used to create a cubemap from an equirectangular image as well as cubemap convolutions. +#[spirv(vertex)] pub fn vertex_position_passthru( - constants: &GpuConstants, + #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &GpuConstants, in_pos: Vec3, local_pos: &mut Vec3, - gl_pos: &mut Vec4, + #[spirv(position)] gl_pos: &mut Vec4, ) { *local_pos = in_pos; *gl_pos = constants.camera_projection * constants.camera_view * in_pos.extend(1.0); } /// Colors a skybox using an equirectangular texture. +#[spirv(fragment)] pub fn fragment_equirectangular( - texture: &Image2d, - sampler: &Sampler, + #[spirv(descriptor_set = 0, binding = 1)] texture: &Image2d, + #[spirv(descriptor_set = 0, binding = 2)] sampler: &Sampler, local_pos: Vec3, out_color: &mut Vec4, ) { diff --git a/crates/renderling-shader/src/slab.rs b/crates/renderling-shader/src/slab.rs index a2a61a1b..bf9a918a 100644 --- a/crates/renderling-shader/src/slab.rs +++ b/crates/renderling-shader/src/slab.rs @@ -12,7 +12,7 @@ use crate::id::Id; /// so long as those types are relatively simple. So far, autoderiving /// fields with these types will **not compile** on one or more targets: /// * `PhantomData` - will not compile on `target_arch = "spirv"` -pub trait Slabbed: std::any::Any + std::fmt::Debug + Sized { +pub trait Slabbed: core::any::Any + Sized { /// The number of `u32`s this type occupies in a slab of `&[u32]`. fn slab_size() -> usize; @@ -34,6 +34,23 @@ pub trait Slabbed: std::any::Any + std::fmt::Debug + Sized { fn write_slab(&self, index: usize, slab: &mut [u32]) -> usize; } +impl Slabbed for bool { + fn slab_size() -> usize { + 1 + } + + fn read_slab(&mut self, index: usize, slab: &[u32]) -> usize { + let mut proxy = 0u32; + let index = proxy.read_slab(index, slab); + *self = proxy == 1; + index + } + + fn write_slab(&self, index: usize, slab: &mut [u32]) -> usize { + if *self { 1u32 } else { 0u32 }.write_slab(index, slab) + } +} + impl Slabbed for u32 { fn slab_size() -> usize { 1 @@ -245,7 +262,6 @@ impl Slabbed for glam::Quat { let index = z.write_slab(index, slab); w.write_slab(index, slab) } - } impl Slabbed for glam::UVec2 { @@ -326,7 +342,7 @@ impl Slabbed for glam::UVec4 { } } -impl Slabbed for PhantomData { +impl Slabbed for PhantomData { fn slab_size() -> usize { 0 } @@ -338,7 +354,6 @@ impl Slabbed for PhantomData { fn write_slab(&self, index: usize, _: &mut [u32]) -> usize { index } - } pub trait Slab { @@ -350,7 +365,6 @@ pub trait Slab { /// Return the next index, or the same index if writing would overlap the slab. fn write(&mut self, t: &T, index: usize) -> usize; - /// Write a slice of the type into the slab at the index. /// /// Return the next index, or the same index if writing would overlap the slab. diff --git a/crates/renderling-shader/src/stage.rs b/crates/renderling-shader/src/stage.rs index b99cd609..8f884387 100644 --- a/crates/renderling-shader/src/stage.rs +++ b/crates/renderling-shader/src/stage.rs @@ -8,7 +8,7 @@ use glam::{mat3, Mat4, Quat, UVec2, UVec3, Vec2, Vec3, Vec4, Vec4Swizzles}; use spirv_std::{ image::{Cubemap, Image2d}, - Sampler, + spirv, Sampler, }; #[cfg(target_arch = "spirv")] @@ -21,7 +21,7 @@ use crate::{ debug::*, id::{Id, ID_NONE}, pbr::{self, PbrMaterial}, - slab::{Slabbed, Slab}, + slab::{Slab, Slabbed}, IsMatrix, IsVector, }; @@ -545,18 +545,19 @@ fn stage_texture_color( } #[allow(clippy::too_many_arguments)] +#[spirv(vertex)] /// Scene vertex shader. pub fn main_vertex_scene( // which entity are we drawing - instance_index: u32, + #[spirv(instance_index)] instance_index: u32, // which vertex are we drawing - vertex_index: u32, + #[spirv(vertex_index)] vertex_index: u32, - constants: &GpuConstants, - vertices: &[Vertex], - entities: &[GpuEntity], + #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &GpuConstants, + #[spirv(storage_buffer, descriptor_set = 0, binding = 1)] vertices: &[Vertex], + #[spirv(storage_buffer, descriptor_set = 0, binding = 2)] entities: &[GpuEntity], - out_material: &mut u32, + #[spirv(flat)] out_material: &mut u32, out_color: &mut Vec4, out_uv0: &mut Vec2, out_uv1: &mut Vec2, @@ -566,7 +567,7 @@ pub fn main_vertex_scene( // position of the vertex/fragment in world space out_pos: &mut Vec3, - gl_pos: &mut Vec4, + #[spirv(position)] gl_pos: &mut Vec4, ) { let entity = entities[instance_index as usize]; let vertex = entity.get_vertex(vertex_index, vertices); @@ -604,24 +605,25 @@ pub fn main_vertex_scene( } #[allow(clippy::too_many_arguments)] +#[spirv(fragment)] /// Scene fragment shader. pub fn main_fragment_scene( - atlas: &Image2d, - atlas_sampler: &Sampler, - - irradiance: &Cubemap, - irradiance_sampler: &Sampler, - prefiltered: &Cubemap, - prefiltered_sampler: &Sampler, - brdf: &Image2d, - brdf_sampler: &Sampler, - - constants: &GpuConstants, - lights: &[GpuLight], - materials: &[pbr::PbrMaterial], - textures: &[GpuTexture], - - in_material: u32, + #[spirv(descriptor_set = 1, binding = 0)] atlas: &Image2d, + #[spirv(descriptor_set = 1, binding = 1)] atlas_sampler: &Sampler, + + #[spirv(descriptor_set = 0, binding = 5)] irradiance: &Cubemap, + #[spirv(descriptor_set = 0, binding = 6)] irradiance_sampler: &Sampler, + #[spirv(descriptor_set = 0, binding = 7)] prefiltered: &Cubemap, + #[spirv(descriptor_set = 0, binding = 8)] prefiltered_sampler: &Sampler, + #[spirv(descriptor_set = 0, binding = 9)] brdf: &Image2d, + #[spirv(descriptor_set = 0, binding = 10)] brdf_sampler: &Sampler, + + #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &GpuConstants, + #[spirv(storage_buffer, descriptor_set = 0, binding = 3)] lights: &[GpuLight], + #[spirv(storage_buffer, descriptor_set = 0, binding = 4)] materials: &[pbr::PbrMaterial], + #[spirv(storage_buffer, descriptor_set = 1, binding = 2)] textures: &[GpuTexture], + + #[spirv(flat)] in_material: u32, in_color: Vec4, in_uv0: Vec2, in_uv1: Vec2, @@ -867,6 +869,30 @@ pub fn main_fragment_scene( .extend(1.0); } +/// A camera used for transforming the stage during rendering. +#[cfg_attr(not(target_arch = "spirv"), derive(Debug))] +#[repr(C)] +#[derive(Default, Clone, Copy, PartialEq, Slabbed)] +pub struct Camera { + pub projection: Mat4, + pub view: Mat4, + pub position: Vec3, +} + +/// Holds important info about the stage. +/// +/// This should be the first struct in the stage's slab. +#[cfg_attr(not(target_arch = "spirv"), derive(Debug))] +#[repr(C)] +#[derive(Default, Clone, Copy, PartialEq, Slabbed)] +pub struct StageLegend { + pub atlas_size: UVec2, + pub debug_mode: DebugMode, + pub has_skybox: bool, + pub has_lighting: bool, + pub light_array: Array, +} + /// A fully-computed unit of rendering, roughly meaning a mesh with model matrix /// transformations. #[cfg_attr(not(target_arch = "spirv"), derive(Debug))] @@ -877,27 +903,26 @@ pub struct RenderUnit { pub id: Id, // Points to an array of `Vertex` in the stage's slab. pub vertices: Array, - // Points to a `PbrMaterial` the stage's slab. + // Points to a `PbrMaterial` in the stage's slab. pub material: Id, - // Points to a `Mat4` the stage's slab. - pub camera_projection: Id, - // Points to a `Mat4` the stage's slab. - pub camera_view: Id, + // Points to a `Camera` in the stage's slab. + pub camera: Id, pub position: Vec3, pub rotation: Quat, pub scale: Vec3, } -pub fn stage_vertex( +#[spirv(vertex)] +pub fn new_stage_vertex( // Which render unit are we rendering - instance_index: u32, + #[spirv(instance_index)] instance_index: u32, // Which vertex within the render unit are we rendering - vertex_index: u32, - unit_slab: &[u32], - stage_slab: &[u32], - - out_material: &mut u32, + #[spirv(vertex_index)] vertex_index: u32, + #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] unit_slab: &[u32], + #[spirv(storage_buffer, descriptor_set = 0, binding = 1)] stage_slab: &[u32], + #[spirv(flat)] out_camera: &mut u32, + #[spirv(flat)] out_material: &mut u32, out_color: &mut Vec4, out_uv0: &mut Vec2, out_uv1: &mut Vec2, @@ -906,8 +931,7 @@ pub fn stage_vertex( out_bitangent: &mut Vec3, // position of the vertex/fragment in world space out_pos: &mut Vec3, - - gl_pos: &mut Vec4, + #[spirv(position)] gl_pos: &mut Vec4, ) { let unit_id: Id = Id::from(instance_index); let unit = unit_slab.read(unit_id); @@ -933,17 +957,9 @@ pub fn stage_vertex( *out_norm = normal_w; let view_pos = model_matrix * vertex.position.xyz().extend(1.0); *out_pos = view_pos.xyz(); - let camera_projection = stage_slab.read(unit.camera_projection); - let camera_view = stage_slab.read(unit.camera_view); - *gl_pos = camera_projection * camera_view * view_pos; -} - -/// Represents a "legend" of various stage buffers. -#[cfg_attr(not(target_arch = "spirv"), derive(Debug))] -#[derive(Copy, Clone, Default, Slabbed)] -pub struct Legend { - pub constants: GpuConstants, - pub lights: Array, + let camera = stage_slab.read(unit.camera); + *out_camera = unit.camera.into(); + *gl_pos = camera.projection * camera.view * view_pos; } #[allow(clippy::too_many_arguments)] @@ -963,6 +979,7 @@ pub fn stage_fragment( slab: &[u32], + in_camera: u32, in_material: u32, in_color: Vec4, in_uv0: Vec2, @@ -975,8 +992,14 @@ pub fn stage_fragment( output: &mut Vec4, brigtness: &mut Vec4, ) { - let Legend { constants, lights } = slab.read(Id::new(0)); - let material = if in_material == ID_NONE || !constants.toggles.get_use_lighting() { + let StageLegend { + atlas_size, + debug_mode, + has_skybox: _, + has_lighting, + light_array, + } = slab.read(Id::new(0)); + let material = if in_material == ID_NONE || !has_lighting { // without an explicit material (or if the entire render has no lighting) // the entity will not participate in any lighting calculations pbr::PbrMaterial { @@ -997,7 +1020,7 @@ pub fn stage_fragment( albedo_tex_uv, atlas, atlas_sampler, - constants.atlas_size, + atlas_size, slab, ); @@ -1011,7 +1034,7 @@ pub fn stage_fragment( metallic_roughness_uv, atlas, atlas_sampler, - constants.atlas_size, + atlas_size, slab, ); @@ -1025,7 +1048,7 @@ pub fn stage_fragment( normal_tex_uv, atlas, atlas_sampler, - constants.atlas_size, + atlas_size, slab, ); @@ -1039,7 +1062,7 @@ pub fn stage_fragment( ao_tex_uv, atlas, atlas_sampler, - constants.atlas_size, + atlas_size, slab, ); @@ -1053,7 +1076,7 @@ pub fn stage_fragment( emissive_tex_uv, atlas, atlas_sampler, - constants.atlas_size, + atlas_size, slab, ); @@ -1081,28 +1104,22 @@ pub fn stage_fragment( let emissive = emissive_tex_color.xyz() * material.emissive_factor.xyz() * material.emissive_factor.w; let irradiance = pbr::sample_irradiance(irradiance, irradiance_sampler, n); + let camera = slab.read(Id::::new(in_camera)); let specular = pbr::sample_specular_reflection( prefiltered, prefiltered_sampler, - constants.camera_pos.xyz(), - in_pos, - n, - roughness, - ); - let brdf = pbr::sample_brdf( - brdf, - brdf_sampler, - constants.camera_pos.xyz(), + camera.position, in_pos, n, roughness, ); + let brdf = pbr::sample_brdf(brdf, brdf_sampler, camera.position, in_pos, n, roughness); fn colorize(u: Vec3) -> Vec4 { ((u.alt_norm_or_zero() + Vec3::splat(1.0)) / 2.0).extend(1.0) } - match constants.debug_mode.into() { + match debug_mode.into() { DebugChannel::None => {} DebugChannel::UvCoords0 => { *output = colorize(Vec3::new(in_uv0.x, in_uv0.y, 0.0)); @@ -1184,7 +1201,7 @@ pub fn stage_fragment( *output = match material.lighting_model { LightingModel::PBR_LIGHTING => pbr::stage_shade_fragment( - constants.camera_pos.xyz(), + camera.position, n, in_pos, albedo.xyz(), @@ -1195,7 +1212,7 @@ pub fn stage_fragment( irradiance, specular, brdf, - lights, + light_array, slab, ), _unlit => in_color * albedo_tex_color * material.albedo_factor, @@ -1211,10 +1228,15 @@ pub fn stage_fragment( .extend(1.0); } +#[spirv(compute(threads(32)))] /// Compute the draw calls for this frame. /// /// This should be called with `groupcount = (entities.len() / threads) + 1`. -pub fn compute_cull_entities(entities: &[GpuEntity], draws: &mut [DrawIndirect], global_id: UVec3) { +pub fn compute_cull_entities( + #[spirv(storage_buffer, descriptor_set = 0, binding = 2)] entities: &[GpuEntity], + #[spirv(storage_buffer, descriptor_set = 1, binding = 0)] draws: &mut [DrawIndirect], + #[spirv(global_invocation_id)] global_id: UVec3, +) { let i = global_id.x as usize; if i > entities.len() { @@ -1249,7 +1271,7 @@ pub fn compute_cull_entities(entities: &[GpuEntity], draws: &mut [DrawIndirect], #[cfg(test)] mod test { - use crate::{self as renderling_shader, slab::Slab, id::Id}; + use crate::{self as renderling_shader, id::Id, slab::Slab}; use renderling_shader::slab::Slabbed; #[derive(Default, Debug, PartialEq, Slabbed)] diff --git a/crates/renderling-shader/src/tonemapping.rs b/crates/renderling-shader/src/tonemapping.rs index c94647b7..7c5bff14 100644 --- a/crates/renderling-shader/src/tonemapping.rs +++ b/crates/renderling-shader/src/tonemapping.rs @@ -5,7 +5,7 @@ //! * https://64.github.io/tonemapping use glam::{mat3, Mat3, Vec2, Vec3, Vec4, Vec4Swizzles}; -use spirv_std::{image::Image2d, Sampler}; +use spirv_std::{image::Image2d, spirv, Sampler}; const GAMMA: f32 = 2.2; const INV_GAMMA: f32 = 1.0 / GAMMA; @@ -118,7 +118,7 @@ pub fn tonemap(mut color: Vec4, constants: &TonemapConstants) -> Vec4 { // Use Reinhard tone mapping color / (color + Vec4::ONE) } - _ => color + _ => color, } } @@ -130,18 +130,24 @@ const QUAD_2D_POINTS: [(Vec2, Vec2); 6] = { [tl, bl, br, tl, br, tr] }; -pub fn vertex(vertex_id: u32, out_uv: &mut glam::Vec2, gl_pos: &mut glam::Vec4) { +#[spirv(vertex)] +pub fn vertex( + #[spirv(vertex_index)] vertex_id: u32, + out_uv: &mut glam::Vec2, + #[spirv(position)] gl_pos: &mut glam::Vec4, +) { let (pos, uv) = QUAD_2D_POINTS[vertex_id as usize]; *out_uv = uv; *gl_pos = pos.extend(0.0).extend(1.0); } +#[spirv(fragment)] pub fn fragment( - texture: &Image2d, - sampler: &Sampler, - constants: &TonemapConstants, - bloom_texture: &Image2d, - bloom_sampler: &Sampler, + #[spirv(descriptor_set = 0, binding = 0)] texture: &Image2d, + #[spirv(descriptor_set = 0, binding = 1)] sampler: &Sampler, + #[spirv(uniform, descriptor_set = 1, binding = 0)] constants: &TonemapConstants, + #[spirv(descriptor_set = 2, binding = 0)] bloom_texture: &Image2d, + #[spirv(descriptor_set = 2, binding = 1)] bloom_sampler: &Sampler, in_uv: glam::Vec2, output: &mut glam::Vec4, ) { diff --git a/crates/renderling-shader/src/ui.rs b/crates/renderling-shader/src/ui.rs index 2968fdc1..ccd57968 100644 --- a/crates/renderling-shader/src/ui.rs +++ b/crates/renderling-shader/src/ui.rs @@ -3,7 +3,7 @@ //! This is mostly for rendering text. use glam::{Mat4, UVec2, Vec2, Vec4}; -use spirv_std::{image::Image2d, Sampler}; +use spirv_std::{image::Image2d, spirv, Sampler}; /// A vertex in a mesh. #[cfg_attr(not(target_arch = "spirv"), derive(Debug))] @@ -79,19 +79,20 @@ impl Default for UiDrawParams { } #[allow(clippy::too_many_arguments)] +#[spirv(vertex)] pub fn vertex( - constants: &UiConstants, - params: &UiDrawParams, + #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &UiConstants, + #[spirv(uniform, descriptor_set = 2, binding = 0)] params: &UiDrawParams, in_pos: Vec2, in_uv: Vec2, in_color: Vec4, - out_mode: &mut u32, + #[spirv(flat)] out_mode: &mut u32, out_color: &mut Vec4, out_uv: &mut Vec2, - gl_pos: &mut Vec4, + #[spirv(position)] gl_pos: &mut Vec4, ) { *out_mode = params.mode.0; *out_color = in_color; @@ -113,11 +114,12 @@ pub fn vertex( *gl_pos = proj * view * model * Vec4::new(in_pos.x, in_pos.y, 0.0, 1.0); } +#[spirv(fragment)] pub fn fragment( - texture: &Image2d, - sampler: &Sampler, + #[spirv(descriptor_set = 1, binding = 0)] texture: &Image2d, + #[spirv(descriptor_set = 1, binding = 1)] sampler: &Sampler, - in_mode: u32, + #[spirv(flat)] in_mode: u32, in_color: Vec4, in_uv: Vec2, diff --git a/crates/renderling/src/bloom.rs b/crates/renderling/src/bloom.rs index 165af143..cb5a1cdf 100644 --- a/crates/renderling/src/bloom.rs +++ b/crates/renderling/src/bloom.rs @@ -89,9 +89,10 @@ fn create_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline { label: Some("bloom filter"), layout: Some(&pp_layout), vertex: wgpu::VertexState { - module: &device - .create_shader_module(wgpu::include_spirv!("linkage/vertex_generate_mipmap.spv")), - entry_point: "vertex_generate_mipmap", + module: &device.create_shader_module(wgpu::include_spirv!( + "linkage/convolution-vertex_generate_mipmap.spv" + )), + entry_point: "convolution::vertex_generate_mipmap", buffers: &[], }, primitive: wgpu::PrimitiveState { @@ -105,9 +106,10 @@ fn create_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline { }, depth_stencil: None, fragment: Some(wgpu::FragmentState { - module: &device - .create_shader_module(wgpu::include_spirv!("linkage/fragment_bloom.spv")), - entry_point: "fragment_bloom", + module: &device.create_shader_module(wgpu::include_spirv!( + "linkage/convolution-fragment_bloom.spv" + )), + entry_point: "convolution::fragment_bloom", targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba16Float, blend: Some(wgpu::BlendState::ALPHA_BLENDING), @@ -395,7 +397,11 @@ mod test { img_diff::assert_img_eq("bloom/on.png", img); { - let bloom = renderling.graph.get_resource_mut::().unwrap().unwrap(); + let bloom = renderling + .graph + .get_resource_mut::() + .unwrap() + .unwrap(); bloom.on = false; } let img = renderling.render_image().unwrap(); diff --git a/crates/renderling/src/cubemap.rs b/crates/renderling/src/cubemap.rs index aaeb73b7..8eed46d7 100644 --- a/crates/renderling/src/cubemap.rs +++ b/crates/renderling/src/cubemap.rs @@ -74,10 +74,12 @@ impl CubemapMakingRenderPipeline { /// images. pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { log::trace!("creating cubemap-making render pipeline with format '{format:?}'"); - let vertex_shader = - device.create_shader_module(wgpu::include_spirv!("linkage/vertex_position_passthru.spv")); - let fragment_shader = device - .create_shader_module(wgpu::include_spirv!("linkage/fragment_equirectangular.spv")); + let vertex_shader = device.create_shader_module(wgpu::include_spirv!( + "linkage/skybox-vertex_position_passthru.spv" + )); + let fragment_shader = device.create_shader_module(wgpu::include_spirv!( + "linkage/skybox-fragment_equirectangular.spv" + )); let bg_layout = cubemap_making_bindgroup_layout(device); let pp_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("cubemap-making pipeline layout"), @@ -90,7 +92,7 @@ impl CubemapMakingRenderPipeline { layout: Some(&pp_layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "vertex_position_passthru", + entry_point: "skybox::vertex_position_passthru", buffers: &[wgpu::VertexBufferLayout { array_stride: { let position_size = std::mem::size_of::(); @@ -119,7 +121,7 @@ impl CubemapMakingRenderPipeline { }, fragment: Some(wgpu::FragmentState { module: &fragment_shader, - entry_point: "fragment_equirectangular", + entry_point: "skybox::fragment_equirectangular", targets: &[Some(wgpu::ColorTargetState { format, blend: Some(wgpu::BlendState::ALPHA_BLENDING), diff --git a/crates/renderling/src/diffuse_irradiance.rs b/crates/renderling/src/diffuse_irradiance.rs index c399489c..9c83bed6 100644 --- a/crates/renderling/src/diffuse_irradiance.rs +++ b/crates/renderling/src/diffuse_irradiance.rs @@ -3,7 +3,9 @@ use renderling_shader::scene::GpuConstants; use crate::Uniform; -pub fn diffuse_irradiance_convolution_bindgroup_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { +pub fn diffuse_irradiance_convolution_bindgroup_layout( + device: &wgpu::Device, +) -> wgpu::BindGroupLayout { device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some("convolution bindgroup"), entries: &[ @@ -92,7 +94,7 @@ impl DiffuseIrradianceConvolutionRenderPipeline { layout: Some(&pp_layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "vertex_position_passthru", + entry_point: "skybox::vertex_position_passthru", buffers: &[wgpu::VertexBufferLayout { array_stride: { let position_size = std::mem::size_of::(); diff --git a/crates/renderling/src/hdr.rs b/crates/renderling/src/hdr.rs index 599b616c..b0d833c9 100644 --- a/crates/renderling/src/hdr.rs +++ b/crates/renderling/src/hdr.rs @@ -160,9 +160,9 @@ pub fn create_hdr_render_surface( let hdr_texture = HdrSurface::create_texture(&device, &queue, size.width, size.height); let label = Some("hdr tonemapping"); let vertex_shader = - device.create_shader_module(wgpu::include_spirv!("linkage/vertex_tonemapping.spv")); + device.create_shader_module(wgpu::include_spirv!("linkage/tonemapping-vertex.spv")); let fragment_shader = - device.create_shader_module(wgpu::include_spirv!("linkage/fragment_tonemapping.spv")); + device.create_shader_module(wgpu::include_spirv!("linkage/tonemapping-fragment.spv")); let hdr_texture_layout = scene_hdr_surface_bindgroup_layout(&device); let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label, @@ -174,7 +174,7 @@ pub fn create_hdr_render_surface( layout: Some(&layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "vertex_tonemapping", + entry_point: "tonemapping::vertex", buffers: &[], }, primitive: wgpu::PrimitiveState { @@ -189,7 +189,7 @@ pub fn create_hdr_render_surface( depth_stencil: None, fragment: Some(wgpu::FragmentState { module: &fragment_shader, - entry_point: "fragment_tonemapping", + entry_point: "tonemapping::fragment", targets: &[Some(wgpu::ColorTargetState { format: target.format().add_srgb_suffix(), blend: Some(wgpu::BlendState::ALPHA_BLENDING), @@ -250,7 +250,11 @@ pub fn clear_surface_hdr_and_depth( &device, &queue, Some("clear_frame_and_depth"), - vec![&frame.view, &hdr.hdr_texture.view, &hdr.brightness_texture.view], + vec![ + &frame.view, + &hdr.hdr_texture.view, + &hdr.brightness_texture.view, + ], Some(&depth_view), color, ); diff --git a/crates/renderling/src/ibl/diffuse_irradiance.rs b/crates/renderling/src/ibl/diffuse_irradiance.rs index 9d32f4db..010395bf 100644 --- a/crates/renderling/src/ibl/diffuse_irradiance.rs +++ b/crates/renderling/src/ibl/diffuse_irradiance.rs @@ -75,10 +75,11 @@ impl DiffuseIrradianceConvolutionRenderPipeline { pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { log::trace!("creating convolution render pipeline with format '{format:?}'"); let vertex_shader = device.create_shader_module(wgpu::include_spirv!( - "../linkage/vertex_position_passthru.spv" + "../linkage/skybox-vertex_position_passthru.spv" )); log::trace!("creating fragment shader"); let fragment_shader = device.create_shader_module(wgpu::include_wgsl!( + // TODO: rewrite this shader in Rust after atomics are added to naga spv "../wgsl/diffuse_irradiance_convolution.wgsl" )); log::trace!(" done."); @@ -95,7 +96,7 @@ impl DiffuseIrradianceConvolutionRenderPipeline { layout: Some(&pp_layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "vertex_position_passthru", + entry_point: "skybox::vertex_position_passthru", buffers: &[wgpu::VertexBufferLayout { array_stride: { let position_size = std::mem::size_of::(); diff --git a/crates/renderling/src/ibl/prefiltered_environment.rs b/crates/renderling/src/ibl/prefiltered_environment.rs index c38bf3a3..117c8651 100644 --- a/crates/renderling/src/ibl/prefiltered_environment.rs +++ b/crates/renderling/src/ibl/prefiltered_environment.rs @@ -85,17 +85,17 @@ pub fn create_pipeline_and_bindgroup( push_constant_ranges: &[], }); let vertex_shader = device.create_shader_module(wgpu::include_spirv!( - "../linkage/vertex_prefilter_environment_cubemap.spv" + "../linkage/convolution-vertex_prefilter_environment_cubemap.spv" )); let fragment_shader = device.create_shader_module(wgpu::include_spirv!( - "../linkage/fragment_prefilter_environment_cubemap.spv" + "../linkage/convolution-fragment_prefilter_environment_cubemap.spv" )); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("prefiltered environment"), layout: Some(&pp_layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "vertex_prefilter_environment_cubemap", + entry_point: "convolution::vertex_prefilter_environment_cubemap", buffers: &[wgpu::VertexBufferLayout { array_stride: 3 * std::mem::size_of::() as u64, step_mode: wgpu::VertexStepMode::Vertex, @@ -121,7 +121,7 @@ pub fn create_pipeline_and_bindgroup( }, fragment: Some(wgpu::FragmentState { module: &fragment_shader, - entry_point: "fragment_prefilter_environment_cubemap", + entry_point: "convolution::fragment_prefilter_environment_cubemap", targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rgba16Float, blend: Some(wgpu::BlendState { diff --git a/crates/renderling/src/linkage/compute_cull_entities.spv b/crates/renderling/src/linkage/compute_cull_entities.spv deleted file mode 100644 index 8a7f5a1d..00000000 Binary files a/crates/renderling/src/linkage/compute_cull_entities.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/convolution-fragment_bloom.spv b/crates/renderling/src/linkage/convolution-fragment_bloom.spv new file mode 100644 index 00000000..2efb0137 Binary files /dev/null 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 new file mode 100644 index 00000000..c085089e Binary files /dev/null and b/crates/renderling/src/linkage/convolution-fragment_brdf_lut_convolution.spv differ diff --git a/crates/renderling/src/linkage/convolution-fragment_generate_mipmap.spv b/crates/renderling/src/linkage/convolution-fragment_generate_mipmap.spv new file mode 100644 index 00000000..ce759111 Binary files /dev/null and b/crates/renderling/src/linkage/convolution-fragment_generate_mipmap.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 new file mode 100644 index 00000000..37fc0096 Binary files /dev/null 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 new file mode 100644 index 00000000..6b37843c Binary files /dev/null and b/crates/renderling/src/linkage/convolution-vertex_brdf_lut_convolution.spv differ diff --git a/crates/renderling/src/linkage/convolution-vertex_generate_mipmap.spv b/crates/renderling/src/linkage/convolution-vertex_generate_mipmap.spv new file mode 100644 index 00000000..70f72ada Binary files /dev/null and b/crates/renderling/src/linkage/convolution-vertex_generate_mipmap.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 new file mode 100644 index 00000000..eb663fbf Binary files /dev/null and b/crates/renderling/src/linkage/convolution-vertex_prefilter_environment_cubemap.spv differ diff --git a/crates/renderling/src/linkage/fragment_bloom.spv b/crates/renderling/src/linkage/fragment_bloom.spv deleted file mode 100644 index 75dc3373..00000000 Binary files a/crates/renderling/src/linkage/fragment_bloom.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/fragment_brdf_lut_convolution.spv b/crates/renderling/src/linkage/fragment_brdf_lut_convolution.spv deleted file mode 100644 index c4d41b41..00000000 Binary files a/crates/renderling/src/linkage/fragment_brdf_lut_convolution.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/fragment_cubemap.spv b/crates/renderling/src/linkage/fragment_cubemap.spv deleted file mode 100644 index 71b56f74..00000000 Binary files a/crates/renderling/src/linkage/fragment_cubemap.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/fragment_equirectangular.spv b/crates/renderling/src/linkage/fragment_equirectangular.spv deleted file mode 100644 index d7d93d17..00000000 Binary files a/crates/renderling/src/linkage/fragment_equirectangular.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/fragment_equirectangular.spv.zip b/crates/renderling/src/linkage/fragment_equirectangular.spv.zip deleted file mode 100644 index e5df911b..00000000 Binary files a/crates/renderling/src/linkage/fragment_equirectangular.spv.zip and /dev/null differ diff --git a/crates/renderling/src/linkage/fragment_generate_mipmap.spv b/crates/renderling/src/linkage/fragment_generate_mipmap.spv deleted file mode 100644 index fba6e5e2..00000000 Binary files a/crates/renderling/src/linkage/fragment_generate_mipmap.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/fragment_prefilter_environment_cubemap.spv b/crates/renderling/src/linkage/fragment_prefilter_environment_cubemap.spv deleted file mode 100644 index 24a6e4d1..00000000 Binary files a/crates/renderling/src/linkage/fragment_prefilter_environment_cubemap.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/fragment_tonemapping.spv b/crates/renderling/src/linkage/fragment_tonemapping.spv deleted file mode 100644 index f146c675..00000000 Binary files a/crates/renderling/src/linkage/fragment_tonemapping.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/main_fragment_scene.spv b/crates/renderling/src/linkage/main_fragment_scene.spv deleted file mode 100644 index be20f747..00000000 Binary files a/crates/renderling/src/linkage/main_fragment_scene.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/main_vertex_scene.spv b/crates/renderling/src/linkage/main_vertex_scene.spv deleted file mode 100644 index 1467f551..00000000 Binary files a/crates/renderling/src/linkage/main_vertex_scene.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/skybox-fragment_cubemap.spv b/crates/renderling/src/linkage/skybox-fragment_cubemap.spv new file mode 100644 index 00000000..0642e9b6 Binary files /dev/null and b/crates/renderling/src/linkage/skybox-fragment_cubemap.spv differ diff --git a/crates/renderling/src/linkage/skybox-fragment_equirectangular.spv b/crates/renderling/src/linkage/skybox-fragment_equirectangular.spv new file mode 100644 index 00000000..3c64d09e Binary files /dev/null and b/crates/renderling/src/linkage/skybox-fragment_equirectangular.spv differ diff --git a/crates/renderling/src/linkage/skybox-vertex.spv b/crates/renderling/src/linkage/skybox-vertex.spv new file mode 100644 index 00000000..5a049b9f Binary files /dev/null and b/crates/renderling/src/linkage/skybox-vertex.spv differ diff --git a/crates/renderling/src/linkage/skybox-vertex_position_passthru.spv b/crates/renderling/src/linkage/skybox-vertex_position_passthru.spv new file mode 100644 index 00000000..94e7cdd3 Binary files /dev/null and b/crates/renderling/src/linkage/skybox-vertex_position_passthru.spv differ diff --git a/crates/renderling/src/linkage/stage-compute_cull_entities.spv b/crates/renderling/src/linkage/stage-compute_cull_entities.spv new file mode 100644 index 00000000..b09f4f66 Binary files /dev/null and b/crates/renderling/src/linkage/stage-compute_cull_entities.spv differ diff --git a/crates/renderling/src/linkage/stage-main_fragment_scene.spv b/crates/renderling/src/linkage/stage-main_fragment_scene.spv new file mode 100644 index 00000000..b616dd96 Binary files /dev/null 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 new file mode 100644 index 00000000..b18725f9 Binary files /dev/null and b/crates/renderling/src/linkage/stage-main_vertex_scene.spv differ diff --git a/crates/renderling/src/linkage/stage-new_stage_vertex.spv b/crates/renderling/src/linkage/stage-new_stage_vertex.spv new file mode 100644 index 00000000..8614ec38 Binary files /dev/null and b/crates/renderling/src/linkage/stage-new_stage_vertex.spv differ diff --git a/crates/renderling/src/linkage/stage_fragment.spv b/crates/renderling/src/linkage/stage_fragment.spv deleted file mode 100644 index 623e93f0..00000000 Binary files a/crates/renderling/src/linkage/stage_fragment.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/stage_vertex.spv b/crates/renderling/src/linkage/stage_vertex.spv deleted file mode 100644 index 65191522..00000000 Binary files a/crates/renderling/src/linkage/stage_vertex.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/tonemapping-fragment.spv b/crates/renderling/src/linkage/tonemapping-fragment.spv new file mode 100644 index 00000000..ac674150 Binary files /dev/null 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 new file mode 100644 index 00000000..9b866b93 Binary files /dev/null and b/crates/renderling/src/linkage/tonemapping-vertex.spv differ diff --git a/crates/renderling/src/linkage/ui-fragment.spv b/crates/renderling/src/linkage/ui-fragment.spv new file mode 100644 index 00000000..8a70212e Binary files /dev/null and b/crates/renderling/src/linkage/ui-fragment.spv differ diff --git a/crates/renderling/src/linkage/ui-vertex.spv b/crates/renderling/src/linkage/ui-vertex.spv new file mode 100644 index 00000000..2eb44998 Binary files /dev/null and b/crates/renderling/src/linkage/ui-vertex.spv differ diff --git a/crates/renderling/src/linkage/ui_fragment.spv b/crates/renderling/src/linkage/ui_fragment.spv deleted file mode 100644 index d1a6e30e..00000000 Binary files a/crates/renderling/src/linkage/ui_fragment.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/ui_vertex.spv b/crates/renderling/src/linkage/ui_vertex.spv deleted file mode 100644 index c3dc0804..00000000 Binary files a/crates/renderling/src/linkage/ui_vertex.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/vertex_brdf_lut_convolution.spv b/crates/renderling/src/linkage/vertex_brdf_lut_convolution.spv deleted file mode 100644 index b682afb6..00000000 Binary files a/crates/renderling/src/linkage/vertex_brdf_lut_convolution.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/vertex_generate_mipmap.spv b/crates/renderling/src/linkage/vertex_generate_mipmap.spv deleted file mode 100644 index 7f58708d..00000000 Binary files a/crates/renderling/src/linkage/vertex_generate_mipmap.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/vertex_position_passthru.spv b/crates/renderling/src/linkage/vertex_position_passthru.spv deleted file mode 100644 index df991d55..00000000 Binary files a/crates/renderling/src/linkage/vertex_position_passthru.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/vertex_prefilter_environment_cubemap.spv b/crates/renderling/src/linkage/vertex_prefilter_environment_cubemap.spv deleted file mode 100644 index 4d0b7fba..00000000 Binary files a/crates/renderling/src/linkage/vertex_prefilter_environment_cubemap.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/vertex_skybox.spv b/crates/renderling/src/linkage/vertex_skybox.spv deleted file mode 100644 index 5b13aa4f..00000000 Binary files a/crates/renderling/src/linkage/vertex_skybox.spv and /dev/null differ diff --git a/crates/renderling/src/linkage/vertex_tonemapping.spv b/crates/renderling/src/linkage/vertex_tonemapping.spv deleted file mode 100644 index 92268a70..00000000 Binary files a/crates/renderling/src/linkage/vertex_tonemapping.spv and /dev/null differ diff --git a/crates/renderling/src/prefiltered_environment.rs b/crates/renderling/src/prefiltered_environment.rs deleted file mode 100644 index 12cd8452..00000000 --- a/crates/renderling/src/prefiltered_environment.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! Pipeline for creating a prefiltered environment map from an existing -//! environment cubemap. - -use crate::Uniform; -use renderling_shader::scene::GpuConstants; - -pub fn prefiltered_environment_pipeline_and_bindgroup( - device: &wgpu::Device, - constants: &Uniform, - roughness: &Uniform, - environment_texture: &crate::Texture, -) -> (wgpu::RenderPipeline, wgpu::BindGroup) { - let label = Some("prefiltered environment"); - let bindgroup_layout_desc = wgpu::BindGroupLayoutDescriptor { - label, - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 2, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::Cube, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 3, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: None, - }, - ], - }; - let bg_layout = device.create_bind_group_layout(&bindgroup_layout_desc); - let bindgroup = device.create_bind_group(&wgpu::BindGroupDescriptor { - label, - layout: &bg_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::Buffer( - constants.buffer().as_entire_buffer_binding(), - ), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Buffer( - roughness.buffer().as_entire_buffer_binding(), - ), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: wgpu::BindingResource::TextureView(&environment_texture.view), - }, - wgpu::BindGroupEntry { - binding: 3, - resource: wgpu::BindingResource::Sampler(&environment_texture.sampler), - }, - ], - }); - let pp_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label, - bind_group_layouts: &[&bg_layout], - push_constant_ranges: &[], - }); - let vertex_shader = device.create_shader_module(wgpu::include_spirv!( - "linkage/vertex_prefilter_environment_cubemap.spv" - )); - let fragment_shader = device.create_shader_module(wgpu::include_spirv!( - "linkage/fragment_prefilter_environment_cubemap.spv" - )); - let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("prefiltered environment"), - layout: Some(&pp_layout), - vertex: wgpu::VertexState { - module: &vertex_shader, - entry_point: "vertex_prefilter_environment_cubemap", - buffers: &[wgpu::VertexBufferLayout { - array_stride: 3 * std::mem::size_of::() as u64, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &wgpu::vertex_attr_array![ - 0 => Float32x3 - ], - }], - }, - 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: None, - multisample: wgpu::MultisampleState { - mask: !0, - alpha_to_coverage_enabled: false, - count: 1, - }, - fragment: Some(wgpu::FragmentState { - module: &fragment_shader, - entry_point: "fragment_prefilter_environment_cubemap", - targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Rgba16Float, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent::REPLACE, - alpha: wgpu::BlendComponent::REPLACE, - }), - write_mask: wgpu::ColorWrites::ALL, - })], - }), - multiview: None, - }); - (pipeline, bindgroup) -} diff --git a/crates/renderling/src/scene.rs b/crates/renderling/src/scene.rs index 91bf559f..c63ee4cb 100644 --- a/crates/renderling/src/scene.rs +++ b/crates/renderling/src/scene.rs @@ -863,9 +863,10 @@ pub fn create_scene_render_pipeline( log::trace!("creating scene render pipeline with format '{format:?}'"); let label = Some("scene render pipeline"); let vertex_shader = - device.create_shader_module(wgpu::include_spirv!("linkage/main_vertex_scene.spv")); - let fragment_shader = - device.create_shader_module(wgpu::include_spirv!("linkage/main_fragment_scene.spv")); + device.create_shader_module(wgpu::include_spirv!("linkage/stage-main_vertex_scene.spv")); + let fragment_shader = device.create_shader_module(wgpu::include_spirv!( + "linkage/stage-main_fragment_scene.spv" + )); let scene_buffers_layout = scene_buffers_bindgroup_layout(device); let scene_atlas_layout = scene_atlas_bindgroup_layout(device); let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { @@ -878,7 +879,7 @@ pub fn create_scene_render_pipeline( layout: Some(&layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "main_vertex_scene", + entry_point: "stage::main_vertex_scene", buffers: &[], }, primitive: wgpu::PrimitiveState { @@ -904,7 +905,7 @@ pub fn create_scene_render_pipeline( }, fragment: Some(wgpu::FragmentState { module: &fragment_shader, - entry_point: "main_fragment_scene", + entry_point: "stage::main_fragment_scene", targets: &[ Some(wgpu::ColorTargetState { format, @@ -925,8 +926,9 @@ pub fn create_scene_render_pipeline( pub fn create_scene_compute_cull_pipeline(device: &wgpu::Device) -> wgpu::ComputePipeline { let label = Some("scene compute cull pipeline"); - let shader_crate = - device.create_shader_module(wgpu::include_spirv!("linkage/compute_cull_entities.spv")); + let shader_crate = device.create_shader_module(wgpu::include_spirv!( + "linkage/stage-compute_cull_entities.spv" + )); let scene_buffers_layout = scene_buffers_bindgroup_layout(device); let indirect_buffers_layout = scene_draw_indirect_bindgroup_layout(device); let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { @@ -938,7 +940,7 @@ pub fn create_scene_compute_cull_pipeline(device: &wgpu::Device) -> wgpu::Comput label, layout: Some(&layout), module: &shader_crate, - entry_point: "compute_cull_entities", + entry_point: "stage::compute_cull_entities", }); pipeline } diff --git a/crates/renderling/src/skybox.rs b/crates/renderling/src/skybox.rs index 7ab00bc0..fd0ac397 100644 --- a/crates/renderling/src/skybox.rs +++ b/crates/renderling/src/skybox.rs @@ -73,9 +73,9 @@ pub fn create_skybox_render_pipeline( ) -> SkyboxRenderPipeline { log::trace!("creating skybox render pipeline with format '{format:?}'"); let vertex_shader = - device.create_shader_module(wgpu::include_spirv!("linkage/vertex_skybox.spv")); + device.create_shader_module(wgpu::include_spirv!("linkage/skybox-vertex.spv")); let fragment_shader = - device.create_shader_module(wgpu::include_spirv!("linkage/fragment_cubemap.spv")); + device.create_shader_module(wgpu::include_spirv!("linkage/skybox-fragment_cubemap.spv")); let bg_layout = skybox_bindgroup_layout(device); let pp_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("skybox pipeline layout"), @@ -88,7 +88,7 @@ pub fn create_skybox_render_pipeline( layout: Some(&pp_layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "vertex_skybox", + entry_point: "skybox::vertex", buffers: &[], }, primitive: wgpu::PrimitiveState { @@ -114,7 +114,7 @@ pub fn create_skybox_render_pipeline( }, fragment: Some(wgpu::FragmentState { module: &fragment_shader, - entry_point: "fragment_cubemap", + entry_point: "skybox::fragment_cubemap", targets: &[Some(wgpu::ColorTargetState { format, blend: Some(wgpu::BlendState::ALPHA_BLENDING), @@ -621,17 +621,17 @@ impl Skybox { crate::mesh::Mesh::from_vertices(device, Some("brdf_lut"), vertices); let vertex_module = device.create_shader_module(wgpu::include_spirv!( - "linkage/vertex_brdf_lut_convolution.spv" + "linkage/convolution-vertex_brdf_lut_convolution.spv" )); let fragment_module = device.create_shader_module(wgpu::include_spirv!( - "linkage/fragment_brdf_lut_convolution.spv" + "linkage/convolution-fragment_brdf_lut_convolution.spv" )); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("brdf_lut_convolution"), layout: None, vertex: wgpu::VertexState { module: &vertex_module, - entry_point: "vertex_brdf_lut_convolution", + entry_point: "convolution::vertex_brdf_lut_convolution", buffers: &[wgpu::VertexBufferLayout { array_stride: (3 + 2) * std::mem::size_of::() as u64, step_mode: wgpu::VertexStepMode::Vertex, @@ -658,7 +658,7 @@ impl Skybox { }, fragment: Some(wgpu::FragmentState { module: &fragment_module, - entry_point: "fragment_brdf_lut_convolution", + entry_point: "convolution::fragment_brdf_lut_convolution", targets: &[Some(wgpu::ColorTargetState { format: wgpu::TextureFormat::Rg16Float, blend: Some(wgpu::BlendState { diff --git a/crates/renderling/src/slab.rs b/crates/renderling/src/slab.rs index 50cc1e56..698514ae 100644 --- a/crates/renderling/src/slab.rs +++ b/crates/renderling/src/slab.rs @@ -2,8 +2,9 @@ use std::ops::Deref; use renderling_shader::{ + array::Array, id::Id, - slab::{Slab, Slabbed}, array::Array, + slab::{Slab, Slabbed}, }; use snafu::{ResultExt, Snafu}; @@ -92,7 +93,7 @@ impl SlabBuffer { Ok(()) } - pub async fn read( + pub async fn read( &self, device: &wgpu::Device, queue: &wgpu::Queue, @@ -137,7 +138,7 @@ impl SlabBuffer { } /// Append to the end of the buffer. - pub fn append( + pub fn append( &mut self, device: &wgpu::Device, queue: &wgpu::Queue, @@ -154,7 +155,7 @@ impl SlabBuffer { } /// Append a slice to the end of the buffer, returning a slab array. - pub fn append_slice( + pub fn append_slice( &mut self, device: &wgpu::Device, queue: &wgpu::Queue, @@ -169,7 +170,8 @@ impl SlabBuffer { for t in ts.iter() { // UNWRAP: Safe because we just checked that there is enough capacity, // and added some if not. - self.write(device, queue, Id::::from(self.len), t).unwrap(); + self.write(device, queue, Id::::from(self.len), t) + .unwrap(); } self.len += size * len; Array::new(index, len as u32) diff --git a/crates/renderling/src/stage.rs b/crates/renderling/src/stage.rs index 187425a4..2bf080aa 100644 --- a/crates/renderling/src/stage.rs +++ b/crates/renderling/src/stage.rs @@ -2,13 +2,15 @@ //! //! Provides a `Stage` object that can be used to render a scene graph. use renderling_shader::{ + array::Array, + debug::DebugMode, id::Id, slab::Slabbed, - stage::GpuConstants, array::Array, + stage::{GpuLight, StageLegend}, }; use snafu::Snafu; -use crate::{SlabBuffer, Device, Queue}; +use crate::{Atlas, Device, Queue, SlabBuffer}; pub mod light; @@ -24,33 +26,71 @@ pub enum StageError { Async { source: wgpu::BufferAsyncError }, } -/// Builds the stage -pub struct StageSlab { - pub(crate) slab: SlabBuffer, +/// Represents an entire scene worth of rendering data. +pub struct Stage { + pub(crate) stage_slab: SlabBuffer, + pub(crate) render_unit_slab: SlabBuffer, + //pub(crate) atlas: Atlas, pub(crate) device: Device, pub(crate) queue: Queue, } -impl StageSlab { +impl Stage { /// Create a new stage slab with `capacity`, which is - pub fn new(device: Device, queue: Queue, constants: GpuConstants) -> Self { + pub fn new(device: Device, queue: Queue, legend: StageLegend) -> Self { let mut s = Self { - slab: SlabBuffer::new(&device, 256), + stage_slab: SlabBuffer::new(&device, 256), + render_unit_slab: SlabBuffer::new(&device, 256), + //atlas: Atlas::new(&device, &queue, 0, 0), device, queue, }; - let _ = s.append(&constants); + let _ = s.append(&legend); s } /// Add an object to the slab and return its ID. - pub fn append(&mut self, object: &T) -> Id { - self.slab.append(&self.device, &self.queue, object) + pub fn append(&mut self, object: &T) -> Id { + self.stage_slab.append(&self.device, &self.queue, object) } /// Add a slice of objects to the slab and return an [`Array`]. - pub fn append_slice(&mut self, objects: &[T]) -> Array { - self.slab.append_slice(&self.device, &self.queue, objects) + pub fn append_slice( + &mut self, + objects: &[T], + ) -> Array { + self.stage_slab + .append_slice(&self.device, &self.queue, objects) + } + + /// Set the debug mode. + pub fn set_debug_mode(&mut self, debug_mode: DebugMode) { + let id = Id::::from(StageLegend::offset_of_debug_mode()); + // UNWRAP: safe because the debug mode offset is guaranteed to be valid. + self.stage_slab + .write(&self.device, &self.queue, id, &debug_mode) + .unwrap(); + } + + /// Set the debug mode. + pub fn with_debug_mode(mut self, debug_mode: DebugMode) -> Self { + self.set_debug_mode(debug_mode); + self + } + + /// Set whether the stage uses lighting. + pub fn set_has_lighting(&mut self, use_lighting: bool) { + let id = Id::::from(StageLegend::offset_of_has_lighting()); + // UNWRAP: safe because the has lighting offset is guaranteed to be valid. + self.stage_slab + .write(&self.device, &self.queue, id, &use_lighting) + .unwrap(); + } + + /// Set whether the stage uses lighting. + pub fn with_lighting(mut self, use_lighting: bool) -> Self { + self.set_has_lighting(use_lighting); + self } /// Create a new spot light and return its builder. @@ -67,4 +107,44 @@ impl StageSlab { pub fn new_point_light(&mut self) -> light::GpuPointLightBuilder { light::GpuPointLightBuilder::new(self) } + + /// Set the light array. + /// + /// This should be an iterator over the ids of all the lights on the stage. + pub fn set_light_array( + &mut self, + lights: impl IntoIterator>, + ) -> Array> { + let lights = lights.into_iter().collect::>(); + let light_array = self.append_slice(&lights); + let id = Id::>>::from(StageLegend::offset_of_light_array()); + // UNWRAP: safe because we just appended the array, and the light array offset is + // guaranteed to be valid. + self.stage_slab + .write(&self.device, &self.queue, id, &light_array) + .unwrap(); + light_array + } + + /// Set the light array. + /// + /// This should be an iterator over the ids of all the lights on the stage. + pub fn with_light_array(mut self, lights: impl IntoIterator>) -> Self { + self.set_light_array(lights); + self + } +} + +#[cfg(test)] +mod test { + use crate::Renderling; + + use super::*; + + #[test] + fn stage_new() { + let r = Renderling::headless(10, 10).unwrap(); + let (device, queue) = r.get_device_and_queue_owned(); + let _stage = Stage::new(device, queue, StageLegend::default()); + } } diff --git a/crates/renderling/src/stage/light.rs b/crates/renderling/src/stage/light.rs index 0aac300d..217ae0b1 100644 --- a/crates/renderling/src/stage/light.rs +++ b/crates/renderling/src/stage/light.rs @@ -3,7 +3,7 @@ use renderling_shader::id::Id; use renderling_shader::stage::{GpuLight, LightType}; use glam::{Vec3, Vec4}; -use crate::StageSlab; +use crate::Stage; #[cfg(feature = "gltf")] pub fn from_gltf_light_kind(kind: gltf::khr_lights_punctual::Kind) -> LightType { @@ -26,11 +26,11 @@ pub fn gltf_light_intensity_units(kind: gltf::khr_lights_punctual::Kind) -> &'st /// A builder for a spot light. pub struct GpuSpotLightBuilder<'a> { inner: GpuLight, - stage: &'a mut StageSlab, + stage: &'a mut Stage, } impl<'a> GpuSpotLightBuilder<'a> { - pub fn new(stage: &'a mut StageSlab) -> GpuSpotLightBuilder<'a> { + pub fn new(stage: &'a mut Stage) -> GpuSpotLightBuilder<'a> { let inner = GpuLight { light_type: LightType::SPOT_LIGHT, ..Default::default() @@ -91,11 +91,11 @@ impl<'a> GpuSpotLightBuilder<'a> { /// This is like the sun, or the moon. pub struct GpuDirectionalLightBuilder<'a> { inner: GpuLight, - stage: &'a mut StageSlab, + stage: &'a mut Stage, } impl<'a> GpuDirectionalLightBuilder<'a> { - pub fn new(stage: &'a mut StageSlab) -> GpuDirectionalLightBuilder<'a> { + pub fn new(stage: &'a mut Stage) -> GpuDirectionalLightBuilder<'a> { let inner = GpuLight { light_type: LightType::DIRECTIONAL_LIGHT, ..Default::default() @@ -131,11 +131,11 @@ impl<'a> GpuDirectionalLightBuilder<'a> { pub struct GpuPointLightBuilder<'a> { inner: GpuLight, - stage: &'a mut StageSlab, + stage: &'a mut Stage, } impl<'a> GpuPointLightBuilder<'a> { - pub fn new(stage: &mut StageSlab) -> GpuPointLightBuilder<'_> { + pub fn new(stage: &mut Stage) -> GpuPointLightBuilder<'_> { let inner = GpuLight { light_type: LightType::POINT_LIGHT, ..Default::default() diff --git a/crates/renderling/src/texture.rs b/crates/renderling/src/texture.rs index 8ce37373..9b0a1427 100644 --- a/crates/renderling/src/texture.rs +++ b/crates/renderling/src/texture.rs @@ -595,9 +595,9 @@ impl Texture { layout: Some(&pp_layout), vertex: wgpu::VertexState { module: &device.create_shader_module(wgpu::include_spirv!( - "linkage/vertex_generate_mipmap.spv" + "linkage/convolution-vertex_generate_mipmap.spv" )), - entry_point: "vertex_generate_mipmap", + entry_point: "convolution::vertex_generate_mipmap", buffers: &[], }, primitive: wgpu::PrimitiveState { @@ -608,9 +608,9 @@ impl Texture { }, fragment: Some(wgpu::FragmentState { module: &device.create_shader_module(wgpu::include_spirv!( - "linkage/fragment_generate_mipmap.spv" + "linkage/convolution-fragment_generate_mipmap.spv" )), - entry_point: "fragment_generate_mipmap", + entry_point: "convolution::fragment_generate_mipmap", targets: &[Some(wgpu::ColorTargetState { format: self.texture.format(), blend: None, diff --git a/crates/renderling/src/ui.rs b/crates/renderling/src/ui.rs index a537802b..485bc0f2 100644 --- a/crates/renderling/src/ui.rs +++ b/crates/renderling/src/ui.rs @@ -11,7 +11,7 @@ use glam::{UVec2, Vec2, Vec4}; use snafu::prelude::*; use crate::{ - mesh::Mesh, frame::FrameTextureView, Device, Queue, RenderTarget, Renderling, Texture, Uniform, + frame::FrameTextureView, mesh::Mesh, Device, Queue, RenderTarget, Renderling, Texture, Uniform, View, ViewMut, }; @@ -101,9 +101,9 @@ pub fn create_ui_pipeline( format: wgpu::TextureFormat, ) -> wgpu::RenderPipeline { let label = Some("ui render pipeline"); - let vertex_shader = device.create_shader_module(wgpu::include_spirv!("linkage/ui_vertex.spv")); + let vertex_shader = device.create_shader_module(wgpu::include_spirv!("linkage/ui-vertex.spv")); let fragment_shader = - device.create_shader_module(wgpu::include_spirv!("linkage/ui_fragment.spv")); + device.create_shader_module(wgpu::include_spirv!("linkage/ui-fragment.spv")); let constants_bindgroup_layout = constants_bindgroup_layout(device); let draw_params_bindgroup_layout = draw_params_bindgroup_layout(device); let texture_bindgroup_layout = ui_texture_bindgroup_layout(device); @@ -121,7 +121,7 @@ pub fn create_ui_pipeline( layout: Some(&layout), vertex: wgpu::VertexState { module: &vertex_shader, - entry_point: "ui_vertex", + entry_point: "ui::vertex", buffers: &[wgpu::VertexBufferLayout { array_stride: { let position_size = std::mem::size_of::(); @@ -154,7 +154,7 @@ pub fn create_ui_pipeline( }, fragment: Some(wgpu::FragmentState { module: &fragment_shader, - entry_point: "ui_fragment", + entry_point: "ui::fragment", targets: &[Some(wgpu::ColorTargetState { format: format.add_srgb_suffix(), blend: Some(wgpu::BlendState::ALPHA_BLENDING), @@ -453,7 +453,7 @@ impl<'a> UiSceneBuilder<'a> { img, Some("UiSceneBuilder::new_texture_from_dynamic_image"), None, - 1 + 1, ) } @@ -568,9 +568,8 @@ pub fn setup_ui_render_graph( r.graph.add_resource(pipeline); use crate::{ - graph, frame::{clear_frame_and_depth, create_frame, present}, - Graph, + graph, Graph, }; let pre_render = crate::graph!(create_frame, clear_frame_and_depth, ui_scene_update).with_barrier(); diff --git a/shaders/Cargo.toml b/shaders/Cargo.toml index f5093c0b..551b2b4e 100644 --- a/shaders/Cargo.toml +++ b/shaders/Cargo.toml @@ -2,11 +2,12 @@ name = "shaders" version = "0.1.0" edition = "2021" -description = "Generates the shader .spv files for the renderling project" +description = "Generates shader .spv files from rust-gpu shader crates" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +clap = { version = "4.4.8", features = ["derive"] } env_logger = "^0.10" log = "^0.4" spirv-builder = "^0.9" diff --git a/shaders/rust-toolchain b/shaders/rust-toolchain.toml similarity index 100% rename from shaders/rust-toolchain rename to shaders/rust-toolchain.toml diff --git a/shaders/shader-crate/src/lib.rs b/shaders/shader-crate/src/lib.rs index 63eb70c4..0fb9a7a2 100644 --- a/shaders/shader-crate/src/lib.rs +++ b/shaders/shader-crate/src/lib.rs @@ -1,404 +1,4 @@ //! Shader entry points. #![no_std] #![feature(lang_items)] -use renderling_shader::{convolution, pbr, skybox, stage, tonemapping, ui}; -use spirv_std::{ - glam, - image::{Cubemap, Image2d}, - spirv, Sampler, -}; - -#[spirv(vertex)] -pub fn ui_vertex( - #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &ui::UiConstants, - #[spirv(uniform, descriptor_set = 2, binding = 0)] params: &ui::UiDrawParams, - - in_pos: glam::Vec2, - in_uv: glam::Vec2, - in_color: glam::Vec4, - - #[spirv(flat)] out_mode: &mut u32, - out_color: &mut glam::Vec4, - out_uv: &mut glam::Vec2, - #[spirv(position)] gl_pos: &mut glam::Vec4, -) { - ui::vertex( - constants, params, in_pos, in_uv, in_color, out_mode, out_color, out_uv, gl_pos, - ) -} - -#[spirv(fragment)] -pub fn ui_fragment( - #[spirv(descriptor_set = 1, binding = 0)] texture: &Image2d, - #[spirv(descriptor_set = 1, binding = 1)] sampler: &Sampler, - - #[spirv(flat)] in_mode: u32, - in_color: glam::Vec4, - in_uv: glam::Vec2, - - output: &mut glam::Vec4, -) { - ui::fragment(texture, sampler, in_mode, in_color, in_uv, output) -} - -#[spirv(vertex)] -pub fn main_vertex_scene( - #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &stage::GpuConstants, - #[spirv(storage_buffer, descriptor_set = 0, binding = 1)] vertices: &[stage::Vertex], - #[spirv(storage_buffer, descriptor_set = 0, binding = 2)] entities: &[stage::GpuEntity], - - //// which entity are we drawing - #[spirv(instance_index)] instance_id: u32, - // which vertex on that entity - #[spirv(vertex_index)] vertex_id: u32, - - #[spirv(flat)] out_material: &mut u32, - out_color: &mut glam::Vec4, - out_uv0: &mut glam::Vec2, - out_uv1: &mut glam::Vec2, - out_norm: &mut glam::Vec3, - out_tangent: &mut glam::Vec3, - out_bitangent: &mut glam::Vec3, - out_pos: &mut glam::Vec3, - #[spirv(position)] gl_pos: &mut glam::Vec4, -) { - stage::main_vertex_scene( - instance_id, - vertex_id, - constants, - vertices, - entities, - out_material, - out_color, - out_uv0, - out_uv1, - out_norm, - out_tangent, - out_bitangent, - out_pos, - gl_pos, - ) -} - -#[spirv(fragment)] -pub fn main_fragment_scene( - #[spirv(descriptor_set = 1, binding = 0)] atlas: &Image2d, - #[spirv(descriptor_set = 1, binding = 1)] sampler: &Sampler, - - #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &stage::GpuConstants, - #[spirv(storage_buffer, descriptor_set = 0, binding = 3)] lights: &[stage::GpuLight], - #[spirv(storage_buffer, descriptor_set = 0, binding = 4)] materials: &[pbr::PbrMaterial], - #[spirv(storage_buffer, descriptor_set = 1, binding = 2)] textures: &[stage::GpuTexture], - - #[spirv(descriptor_set = 0, binding = 5)] irradiance: &Cubemap, - #[spirv(descriptor_set = 0, binding = 6)] irradiance_sampler: &Sampler, - #[spirv(descriptor_set = 0, binding = 7)] prefiltered: &Cubemap, - #[spirv(descriptor_set = 0, binding = 8)] prefiltered_sampler: &Sampler, - #[spirv(descriptor_set = 0, binding = 9)] brdf: &Image2d, - #[spirv(descriptor_set = 0, binding = 10)] brdf_sampler: &Sampler, - - //// which entity are we drawing - #[spirv(flat)] in_material: u32, - in_color: glam::Vec4, - in_uv0: glam::Vec2, - in_uv1: glam::Vec2, - in_norm: glam::Vec3, - in_tangent: glam::Vec3, - in_bitangent: glam::Vec3, - in_pos: glam::Vec3, - - output: &mut glam::Vec4, - brightness: &mut glam::Vec4, -) { - stage::main_fragment_scene( - atlas, - sampler, - irradiance, - irradiance_sampler, - prefiltered, - prefiltered_sampler, - brdf, - brdf_sampler, - constants, - lights, - materials, - textures, - in_material, - in_color, - in_uv0, - in_uv1, - in_norm, - in_tangent, - in_bitangent, - in_pos, - output, - brightness, - ) -} - -#[spirv(compute(threads(32)))] -pub fn compute_cull_entities( - #[spirv(storage_buffer, descriptor_set = 0, binding = 2)] entities: &[stage::GpuEntity], - - #[spirv(storage_buffer, descriptor_set = 1, binding = 0)] draws: &mut [stage::DrawIndirect], - - #[spirv(global_invocation_id)] global_id: glam::UVec3, -) { - stage::compute_cull_entities(entities, draws, global_id) -} - -#[spirv(vertex)] -pub fn vertex_tonemapping( - #[spirv(vertex_index)] vertex_id: u32, - out_uv: &mut glam::Vec2, - #[spirv(position)] gl_pos: &mut glam::Vec4, -) { - tonemapping::vertex(vertex_id, out_uv, gl_pos) -} - -#[spirv(fragment)] -pub fn fragment_tonemapping( - #[spirv(descriptor_set = 0, binding = 0)] texture: &Image2d, - #[spirv(descriptor_set = 0, binding = 1)] sampler: &Sampler, - #[spirv(uniform, descriptor_set = 1, binding = 0)] constants: &tonemapping::TonemapConstants, - #[spirv(descriptor_set = 2, binding = 0)] bloom_texture: &Image2d, - #[spirv(descriptor_set = 2, binding = 1)] bloom_sampler: &Sampler, - in_uv: glam::Vec2, - - output: &mut glam::Vec4, -) { - tonemapping::fragment( - texture, - sampler, - constants, - bloom_texture, - bloom_sampler, - in_uv, - output, - ) -} - -#[spirv(vertex)] -pub fn vertex_skybox( - #[spirv(vertex_index)] vertex_id: u32, - #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &stage::GpuConstants, - local_pos: &mut glam::Vec3, - #[spirv(position)] gl_pos: &mut glam::Vec4, -) { - skybox::vertex(vertex_id, constants, local_pos, gl_pos) -} - -#[spirv(vertex)] -pub fn vertex_position_passthru( - #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &stage::GpuConstants, - in_pos: glam::Vec3, - local_pos: &mut glam::Vec3, - #[spirv(position)] gl_pos: &mut glam::Vec4, -) { - skybox::vertex_position_passthru(constants, in_pos, local_pos, gl_pos) -} - -#[spirv(fragment)] -pub fn fragment_equirectangular( - #[spirv(descriptor_set = 0, binding = 1)] texture: &Image2d, - #[spirv(descriptor_set = 0, binding = 2)] sampler: &Sampler, - in_local_pos: glam::Vec3, - out_color: &mut glam::Vec4, -) { - skybox::fragment_equirectangular(texture, sampler, in_local_pos, out_color) -} - -#[spirv(fragment)] -pub fn fragment_cubemap( - #[spirv(descriptor_set = 0, binding = 1)] texture: &Cubemap, - #[spirv(descriptor_set = 0, binding = 2)] sampler: &Sampler, - in_local_pos: glam::Vec3, - out_color: &mut glam::Vec4, -) { - skybox::fragment_cubemap(texture, sampler, in_local_pos, out_color) -} - -#[spirv(vertex)] -pub fn vertex_brdf_lut_convolution( - in_pos: glam::Vec3, - in_uv: glam::Vec2, - out_uv: &mut glam::Vec2, - #[spirv(position)] gl_pos: &mut glam::Vec4, -) { - *out_uv = in_uv; - *gl_pos = in_pos.extend(1.0); -} - -#[spirv(fragment)] -pub fn fragment_brdf_lut_convolution(in_uv: glam::Vec2, out_color: &mut glam::Vec2) { - *out_color = convolution::integrate_brdf(in_uv.x, in_uv.y); -} - -#[spirv(vertex)] -pub fn vertex_prefilter_environment_cubemap( - #[spirv(uniform, descriptor_set = 0, binding = 0)] constants: &stage::GpuConstants, - in_pos: glam::Vec3, - out_pos: &mut glam::Vec3, - #[spirv(position)] gl_pos: &mut glam::Vec4, -) { - convolution::vertex_prefilter_environment_cubemap(constants, in_pos, out_pos, gl_pos) -} - -#[spirv(fragment)] -pub fn fragment_prefilter_environment_cubemap( - #[spirv(uniform, descriptor_set = 0, binding = 1)] roughness: &f32, - #[spirv(descriptor_set = 0, binding = 2)] environment_cubemap: &Cubemap, - #[spirv(descriptor_set = 0, binding = 3)] sampler: &Sampler, - in_pos: glam::Vec3, - frag_color: &mut glam::Vec4, -) { - convolution::fragment_prefilter_environment_cubemap( - roughness, - environment_cubemap, - sampler, - in_pos, - frag_color, - ) -} - -#[spirv(vertex)] -pub fn vertex_generate_mipmap( - #[spirv(vertex_index)] vertex_id: u32, - out_uv: &mut glam::Vec2, - #[spirv(position)] gl_pos: &mut glam::Vec4, -) { - convolution::vertex_generate_mipmap(vertex_id, out_uv, gl_pos) -} - -#[spirv(fragment)] -pub fn fragment_generate_mipmap( - #[spirv(descriptor_set = 0, binding = 0)] texture: &Image2d, - #[spirv(descriptor_set = 0, binding = 1)] sampler: &Sampler, - in_uv: glam::Vec2, - frag_color: &mut glam::Vec4, -) { - convolution::fragment_generate_mipmap(texture, sampler, in_uv, frag_color) -} - -//#[spirv(fragment)] -// pub fn fragment_convolve_diffuse_irradiance( -// #[spirv(descriptor_set = 0, binding = 1)] texture: &Cubemap, -// #[spirv(descriptor_set = 0, binding = 2)] sampler: &Sampler, -// in_local_pos: glam::Vec3, -// out_color: &mut glam::Vec4, -//) { -// convolution::fragment_convolve_diffuse_irradiance(texture, sampler, -// in_local_pos, out_color) -//} - -#[spirv(fragment)] -pub fn fragment_bloom( - #[spirv(uniform, descriptor_set = 0, binding = 0)] horizontal: &u32, - #[spirv(uniform, descriptor_set = 0, binding = 1)] size: &glam::UVec2, - #[spirv(descriptor_set = 0, binding = 2)] texture: &Image2d, - #[spirv(descriptor_set = 0, binding = 3)] sampler: &Sampler, - in_uv: glam::Vec2, - frag_color: &mut glam::Vec4, -) { - convolution::fragment_bloom(*horizontal == 0, size, texture, sampler, in_uv, frag_color) -} - -#[spirv(vertex)] -pub fn stage_vertex( - // Which render unit are we rendering - #[spirv(instance_index)] instance_index: u32, - // Which vertex within the render unit are we rendering - #[spirv(vertex_index)] vertex_index: u32, - #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] unit_slab: &[u32], - #[spirv(storage_buffer, descriptor_set = 0, binding = 1)] stage_slab: &[u32], - - #[spirv(flat)] out_material: &mut u32, - out_color: &mut glam::Vec4, - out_uv0: &mut glam::Vec2, - out_uv1: &mut glam::Vec2, - out_norm: &mut glam::Vec3, - out_tangent: &mut glam::Vec3, - out_bitangent: &mut glam::Vec3, - - // position of the vertex/fragment in world space - out_pos: &mut glam::Vec3, - - #[spirv(position)] gl_pos: &mut glam::Vec4, -) { - renderling_shader::stage::stage_vertex( - instance_index, - vertex_index, - unit_slab, - stage_slab, - out_material, - out_color, - out_uv0, - out_uv1, - out_norm, - out_tangent, - out_bitangent, - out_pos, - gl_pos, - ) -} - -#[spirv(fragment)] -pub fn stage_fragment( - #[spirv(descriptor_set = 1, binding = 0)] - atlas: &Image2d, - #[spirv(descriptor_set = 1, binding = 1)] - atlas_sampler: &Sampler, - - #[spirv(descriptor_set = 1, binding = 2)] - irradiance: &Cubemap, - #[spirv(descriptor_set = 1, binding = 3)] - irradiance_sampler: &Sampler, - - #[spirv(descriptor_set = 1, binding = 4)] - prefiltered: &Cubemap, - #[spirv(descriptor_set = 1, binding = 5)] - prefiltered_sampler: &Sampler, - - #[spirv(descriptor_set = 1, binding = 6)] - brdf: &Image2d, - #[spirv(descriptor_set = 1, binding = 7)] - brdf_sampler: &Sampler, - - #[spirv(storage_buffer, descriptor_set = 0, binding = 8)] - slab: &[u32], - - #[spirv(flat)] - in_material: u32, - in_color: glam::Vec4, - in_uv0: glam::Vec2, - in_uv1: glam::Vec2, - in_norm: glam::Vec3, - in_tangent: glam::Vec3, - in_bitangent: glam::Vec3, - in_pos: glam::Vec3, - - output: &mut glam::Vec4, - brigtness: &mut glam::Vec4, -) { - renderling_shader::stage::stage_fragment( - atlas, - atlas_sampler, - irradiance, - irradiance_sampler, - prefiltered, - prefiltered_sampler, - brdf, - brdf_sampler, - slab, - in_material, - in_color, - in_uv0, - in_uv1, - in_norm, - in_tangent, - in_bitangent, - in_pos, - output, - brigtness, - ) -} +pub use renderling_shader::*; diff --git a/shaders/src/main.rs b/shaders/src/main.rs index 2d9b5781..f39af2e9 100644 --- a/shaders/src/main.rs +++ b/shaders/src/main.rs @@ -1,15 +1,38 @@ //! This program builds the rust-gpu shaders and writes the spv files into the //! main source repo. -//! -//! See the crates/renderling/src/shaders/mod.rs for more info. +use clap::Parser; use spirv_builder::{CompileResult, MetadataPrintout, ModuleResult, SpirvBuilder}; +#[derive(Parser)] +#[clap(author, version, about)] +struct Cli { + /// Sets the verbosity level + #[clap(short, action = clap::ArgAction::Count)] + verbosity: u8, + + /// Path to the output directory for the compiled shaders. + #[clap(long, short, default_value = "shaders")] + output_dir: std::path::PathBuf, +} + fn main() -> Result<(), Box> { + let Cli { + verbosity, + output_dir, + } = Cli::parse(); + let level = match verbosity { + 0 => log::LevelFilter::Warn, + 1 => log::LevelFilter::Info, + 2 => log::LevelFilter::Debug, + _ => log::LevelFilter::Trace, + }; env_logger::builder() - .filter_level(log::LevelFilter::Trace) + .filter_level(level) .try_init() .unwrap(); + std::fs::create_dir_all(&output_dir).unwrap(); + let CompileResult { entry_points, module, @@ -18,7 +41,7 @@ fn main() -> Result<(), Box> { .multimodule(true) .build()?; - let dir = std::path::PathBuf::from("../crates/renderling/src/linkage"); + let dir = output_dir; match module { ModuleResult::MultiModule(modules) => { for (entry, filepath) in modules.into_iter() {