diff --git a/crates/renderling-shader/src/bits.rs b/crates/renderling-shader/src/bits.rs index dc820623..8c10217b 100644 --- a/crates/renderling-shader/src/bits.rs +++ b/crates/renderling-shader/src/bits.rs @@ -34,3 +34,66 @@ pub fn insert(bits: &mut u32, (shift, mask): (u32, u32), value: u32) { pub fn extract(bits: u32, (shift, mask): (u32, u32)) -> u32 { (bits >> shift) & mask } + +/// The shift/mask range for the first 8 bits of a u32. +pub const U8_0_BITS: (u32, u32) = bits(0..=7); +/// The shift/mask range for the second 8 bits of a u32. +pub const U8_1_BITS: (u32, u32) = bits(8..=15); +/// The shift/mask range for the third 8 bits of a u32. +pub const U8_2_BITS: (u32, u32) = bits(16..=23); +/// The shift/mask range for the fourth 8 bits of a u32. +pub const U8_3_BITS: (u32, u32) = bits(24..=31); + +/// The shift/mask range for the first 16 bits of a u32. +pub const U16_0_BITS: (u32, u32) = bits(0..=15); +/// The shift/mask range for the second 16 bits of a u32. +pub const U16_1_BITS: (u32, u32) = bits(16..=31); + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn bits_sanity() { + let mut store = 0; + assert_eq!( + "00000000000000000000000000000000", + &format!("{:032b}", store) + ); + insert(&mut store, bits(0..=7), u8::MAX as u32); + assert_eq!( + "00000000000000000000000011111111", + &format!("{:032b}", store) + ); + store = 0; + insert(&mut store, bits(8..=15), u8::MAX as u32); + assert_eq!( + "00000000000000001111111100000000", + &format!("{:032b}", store) + ); + } + + #[test] + fn bits_u8_sanity() { + let mut bits = 0; + println!("bits: {:032b}", bits); + super::insert(&mut bits, super::U8_0_BITS, 6u8 as u32); + println!("bits: {:032b}", bits); + assert_eq!(super::extract(bits, super::U8_0_BITS), 6); + super::insert(&mut bits, super::U8_1_BITS, 5u8 as u32); + println!("bits: {:032b}", bits); + assert_eq!(super::extract(bits, super::U8_0_BITS), 6); + assert_eq!(super::extract(bits, super::U8_1_BITS), 5); + super::insert(&mut bits, super::U8_2_BITS, 4u8 as u32); + println!("bits: {:032b}", bits); + assert_eq!(super::extract(bits, super::U8_0_BITS), 6); + assert_eq!(super::extract(bits, super::U8_1_BITS), 5); + assert_eq!(super::extract(bits, super::U8_2_BITS), 4); + super::insert(&mut bits, super::U8_3_BITS, 3u8 as u32); + println!("bits: {:032b}", bits); + assert_eq!(super::extract(bits, super::U8_0_BITS), 6); + assert_eq!(super::extract(bits, super::U8_1_BITS), 5); + assert_eq!(super::extract(bits, super::U8_2_BITS), 4); + assert_eq!(super::extract(bits, super::U8_3_BITS), 3); + } +} diff --git a/crates/renderling-shader/src/gltf.rs b/crates/renderling-shader/src/gltf.rs index 7f4c0ed5..5f9cdf97 100644 --- a/crates/renderling-shader/src/gltf.rs +++ b/crates/renderling-shader/src/gltf.rs @@ -14,7 +14,7 @@ use crate::{ pub struct GltfBuffer(pub Array); #[repr(u32)] -#[derive(Default, Clone, Copy)] +#[derive(Default, Clone, Copy, PartialEq, Debug)] pub enum DataType { I8, U8, @@ -102,9 +102,27 @@ impl Slabbed for Dimensions { } } +/// Reads a u8 from the slab at the given **byte** offset. +fn get_u8_at_offset(offset: usize, slab: &[u32]) -> u8 { + let u32_offset = offset / 4; + let mut u32 = 0u32; + let _ = u32.read_slab(u32_offset, slab); + let byte_offset = offset % 4; + match byte_offset { + 0 => u32.to_le_bytes()[0], + 1 => u32.to_le_bytes()[1], + 2 => u32.to_le_bytes()[2], + 3 => u32.to_le_bytes()[3], + _ => 0, // unreachable + } +} + #[derive(Default, Clone, Copy, Slabbed)] pub struct GltfAccessor { - // The byte size of each component that this accessor describes. + // The byte size of each element that this accessor describes. + // + /// For example, if the accessor describes a `Vec3` of F32s, then + // the size is 3 * 4 = 12. pub size: u32, pub buffer: Id, // Returns the offset relative to the start of the parent buffer view in bytes. @@ -117,7 +135,7 @@ pub struct GltfAccessor { // number of bytes in the buffer view. pub count: u32, // The data type of components in the attribute. - pub component_type: DataType, + pub data_type: DataType, // Specifies if the attribute is a scalar, vector, or matrix. pub dimensions: Dimensions, // Whether or not the attribute is normalized. @@ -125,6 +143,34 @@ pub struct GltfAccessor { } impl GltfAccessor { + /// Retreive the nth element. + pub fn get1(&self, index: usize, slab: &[u32]) -> u32 { + let buffer = slab.read(self.buffer); + let buffer_start = buffer.0.at(0); + let byte_offset = + buffer_start.index() * 4 + self.view_offset as usize + index * self.size as usize; + let u32_offset = byte_offset / 4; + let mut t = 0u32; + t.read_slab(u32_offset, slab); + let byte_mod = byte_offset as u32 % 4; + let mask = match self.data_type { + DataType::I8 => 0xF, + DataType::U8 => 0xF, + DataType::I16 => 0xFF, + DataType::U16 => 0xFF, + DataType::U32 => 0xFFFF, + DataType::F32 => 0xFFFF, + }; + let shift = match byte_mod { + 0 => 0, + 1 => 8, + 2 => 16, + 3 => 24, + _ => 0, // unreachable + }; + crate::bits::extract(t, (shift, mask)) + } + pub fn get_scalar_u32(&self, index: usize, slab: &[u32]) -> u32 { let byte_offset = self.view_offset + index as u32 * self.view_stride; let u32_offset = byte_offset / 4; @@ -178,13 +224,13 @@ pub struct GltfPrimitive { } impl GltfPrimitive { - pub fn get_vertex(&self, index: usize, slab: &[u32]) -> crate::stage::Vertex { + pub fn get_vertex(&self, vertex_index: usize, slab: &[u32]) -> crate::stage::Vertex { let index = if self.indices.is_some() { let indices = slab.read(self.indices); - let index = indices.get_scalar_u32(index, slab); + let index = indices.get1(vertex_index, slab); index as usize } else { - index + vertex_index }; let positions = slab.read(self.positions); let position = positions.get_vec4(index, slab); diff --git a/crates/renderling/src/linkage/stage-new_stage_vertex.spv b/crates/renderling/src/linkage/stage-new_stage_vertex.spv index 07d94092..6e0a5642 100644 Binary files a/crates/renderling/src/linkage/stage-new_stage_vertex.spv and b/crates/renderling/src/linkage/stage-new_stage_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 c5e1e61d..5af1cf98 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/stage/gltf_support.rs b/crates/renderling/src/stage/gltf_support.rs index b976ab67..15f21347 100644 --- a/crates/renderling/src/stage/gltf_support.rs +++ b/crates/renderling/src/stage/gltf_support.rs @@ -4,7 +4,7 @@ use crate::{ shader::{ gltf::*, pbr::PbrMaterial, - stage::LightingModel, + stage::{Camera, GltfVertexData, LightingModel, VertexData}, texture::{GpuTexture, TextureAddressMode, TextureModes}, }, SceneImage, @@ -63,6 +63,45 @@ pub fn get_vertex_count(primitive: &gltf::Primitive<'_>) -> u32 { } } +pub fn make_accessor(accessor: gltf::Accessor<'_>, buffers: &Array) -> GltfAccessor { + let size = accessor.size() as u32; + let buffer_view = accessor.view().unwrap(); + let view_buffer = buffer_view.buffer(); + let buffer_index = view_buffer.index(); + let buffer = buffers.at(buffer_index); + let count = accessor.count() as u32; + let view_offset = buffer_view.offset() as u32; + let view_stride = buffer_view.stride().unwrap_or(0) as u32; + let component_type = match accessor.data_type() { + gltf::accessor::DataType::I8 => DataType::I8, + gltf::accessor::DataType::U8 => DataType::U8, + gltf::accessor::DataType::I16 => DataType::I16, + gltf::accessor::DataType::U16 => DataType::U16, + gltf::accessor::DataType::U32 => DataType::U32, + gltf::accessor::DataType::F32 => DataType::F32, + }; + let dimensions = match accessor.dimensions() { + gltf::accessor::Dimensions::Scalar => Dimensions::Scalar, + gltf::accessor::Dimensions::Vec2 => Dimensions::Vec2, + gltf::accessor::Dimensions::Vec3 => Dimensions::Vec3, + gltf::accessor::Dimensions::Vec4 => Dimensions::Vec4, + gltf::accessor::Dimensions::Mat2 => Dimensions::Mat2, + gltf::accessor::Dimensions::Mat3 => Dimensions::Mat3, + gltf::accessor::Dimensions::Mat4 => Dimensions::Mat4, + }; + let normalized = accessor.normalized(); + GltfAccessor { + size, + count, + buffer, + view_offset, + view_stride, + data_type: component_type, + dimensions, + normalized, + } +} + impl Stage { pub fn load_gltf_document( &self, @@ -100,45 +139,7 @@ impl Stage { log::trace!("Loading accessors into the GPU"); let accessors = document .accessors() - .map(|accessor| { - let size = accessor.size() as u32; - let buffer_view = accessor.view().unwrap(); - let view_buffer = buffer_view.buffer(); - let buffer_index = view_buffer.index(); - let buffer = buffers.at(buffer_index); - let count = accessor.count() as u32; - let view_offset = buffer_view.offset() as u32; - let view_stride = buffer_view.stride().unwrap_or(0) as u32; - let component_type = match accessor.data_type() { - gltf::accessor::DataType::I8 => DataType::I8, - gltf::accessor::DataType::U8 => DataType::U8, - gltf::accessor::DataType::I16 => DataType::I16, - gltf::accessor::DataType::U16 => DataType::U16, - gltf::accessor::DataType::U32 => DataType::U32, - gltf::accessor::DataType::F32 => DataType::F32, - }; - let dimensions = match accessor.dimensions() { - gltf::accessor::Dimensions::Scalar => Dimensions::Scalar, - gltf::accessor::Dimensions::Vec2 => Dimensions::Vec2, - gltf::accessor::Dimensions::Vec3 => Dimensions::Vec3, - gltf::accessor::Dimensions::Vec4 => Dimensions::Vec4, - gltf::accessor::Dimensions::Mat2 => Dimensions::Mat2, - gltf::accessor::Dimensions::Mat3 => Dimensions::Mat3, - gltf::accessor::Dimensions::Mat4 => Dimensions::Mat4, - }; - let normalized = accessor.normalized(); - let accessor = GltfAccessor { - size, - count, - buffer, - view_offset, - view_stride, - component_type, - dimensions, - normalized, - }; - accessor - }) + .map(|accessor| make_accessor(accessor, &buffers)) .collect::>(); let accessors = self.append_array(&accessors); @@ -382,11 +383,18 @@ impl Stage { *atlas = new_atlas; } + fn log_accessor(gltf_accessor: gltf::Accessor<'_>) { + log::trace!(" count: {}", gltf_accessor.count()); + log::trace!(" size: {}", gltf_accessor.size()); + log::trace!(" data_type: {:?}", gltf_accessor.data_type()); + log::trace!(" dimensions: {:?}", gltf_accessor.dimensions()); + } log::trace!("Loading meshes"); let meshes = self.allocate_array::(document.meshes().len()); for mesh in document.meshes() { let primitives = self.allocate_array::(mesh.primitives().len()); for (j, primitive) in mesh.primitives().enumerate() { + log::trace!(" primitive {j}"); debug_assert_eq!(j, primitive.index()); let vertex_count = get_vertex_count(&primitive); let material = primitive @@ -396,39 +404,84 @@ impl Stage { .unwrap_or(Id::NONE); let indices = primitive .indices() - .map(|acc| accessors.at(acc.index())) + .map(|acc| { + let gltf_accessor = document.accessors().nth(acc.index()).unwrap(); + log::trace!(" indices:"); + log_accessor(gltf_accessor); + accessors.at(acc.index()) + }) .unwrap_or_default(); let positions = primitive .get(&gltf::Semantic::Positions) - .map(|acc| accessors.at(acc.index())) + .map(|acc| { + let gltf_accessor = document.accessors().nth(acc.index()).unwrap(); + log::trace!(" positions:"); + log_accessor(gltf_accessor); + accessors.at(acc.index()) + }) .unwrap_or_default(); let normals = primitive .get(&gltf::Semantic::Normals) - .map(|acc| accessors.at(acc.index())) + .map(|acc| { + let gltf_accessor = document.accessors().nth(acc.index()).unwrap(); + log::trace!(" normals:"); + log_accessor(gltf_accessor); + accessors.at(acc.index()) + }) .unwrap_or_default(); let tangents = primitive .get(&gltf::Semantic::Tangents) - .map(|acc| accessors.at(acc.index())) + .map(|acc| { + let gltf_accessor = document.accessors().nth(acc.index()).unwrap(); + log::trace!(" tangents:"); + log_accessor(gltf_accessor); + accessors.at(acc.index()) + }) .unwrap_or_default(); let colors = primitive .get(&gltf::Semantic::Colors(0)) - .map(|acc| accessors.at(acc.index())) + .map(|acc| { + let gltf_accessor = document.accessors().nth(acc.index()).unwrap(); + log::trace!(" colors:"); + log_accessor(gltf_accessor); + accessors.at(acc.index()) + }) .unwrap_or_default(); let tex_coords0 = primitive .get(&gltf::Semantic::TexCoords(0)) - .map(|acc| accessors.at(acc.index())) + .map(|acc| { + let gltf_accessor = document.accessors().nth(acc.index()).unwrap(); + log::trace!(" tex_coords0:"); + log_accessor(gltf_accessor); + accessors.at(acc.index()) + }) .unwrap_or_default(); let tex_coords1 = primitive .get(&gltf::Semantic::TexCoords(1)) - .map(|acc| accessors.at(acc.index())) + .map(|acc| { + let gltf_accessor = document.accessors().nth(acc.index()).unwrap(); + log::trace!(" tex_coords1:"); + log_accessor(gltf_accessor); + accessors.at(acc.index()) + }) .unwrap_or_default(); let joints = primitive .get(&gltf::Semantic::Joints(0)) - .map(|acc| accessors.at(acc.index())) + .map(|acc| { + let gltf_accessor = document.accessors().nth(acc.index()).unwrap(); + log::trace!(" joints:"); + log_accessor(gltf_accessor); + accessors.at(acc.index()) + }) .unwrap_or_default(); let weights = primitive .get(&gltf::Semantic::Weights(0)) - .map(|acc| accessors.at(acc.index())) + .map(|acc| { + let gltf_accessor = document.accessors().nth(acc.index()).unwrap(); + log::trace!(" weights:"); + log_accessor(gltf_accessor); + accessors.at(acc.index()) + }) .unwrap_or_default(); self.write( @@ -660,6 +713,71 @@ impl Stage { views, }) } + + // For now we have to keep the original document around to figure out + // what to draw. + fn draw_gltf_node_with<'a>( + &self, + gpu_doc: &GltfDocument, + camera_id: Id, + node: gltf::Node<'a>, + parents: Vec>, + ) -> Vec> { + let mut units = if let Some(mesh) = node.mesh() { + let primitives = mesh.primitives(); + let mesh = gpu_doc.meshes.at(mesh.index()); + primitives + .map(|primitive| { + let parent_node_path = self.append_array(&parents); + let vertex_data_id = self.append(&GltfVertexData { + parent_node_path, + mesh, + primitive_index: primitive.index() as u32, + }); + let render_unit = RenderUnit { + vertex_data: VertexData::Gltf(vertex_data_id), + vertex_count: super::get_vertex_count(&primitive), + transform: Id::NONE, + camera: camera_id, + }; + self.draw_unit(&render_unit) + }) + .collect::>() + } else { + vec![] + }; + for child in node.children() { + let mut parents = parents.clone(); + parents.push(gpu_doc.nodes.at(child.index())); + units.extend(self.draw_gltf_node_with(gpu_doc, camera_id, child, parents)); + } + units + } + + /// Draw the given [`gltf::Node`] using the given [`Camera`] and return the ids of the + /// render units that were created. + pub fn draw_gltf_node( + &self, + gpu_doc: &GltfDocument, + camera_id: Id, + node: gltf::Node<'_>, + ) -> Vec> { + self.draw_gltf_node_with(gpu_doc, camera_id, node, vec![]) + } + + /// Draw the given [`gltf::Scene`] using the given [`Camera`] and return the ids of the + /// render units that were created. + pub fn draw_gltf_scene( + &self, + gpu_doc: &GltfDocument, + camera_id: Id, + scene: gltf::Scene<'_>, + ) -> Vec> { + scene + .nodes() + .flat_map(|node| self.draw_gltf_node(gpu_doc, camera_id, node)) + .collect() + } } #[cfg(test)] @@ -667,18 +785,67 @@ mod test { use glam::Vec3; use crate::{ - shader::{ - gltf::*, - id::Id, - pbr::PbrMaterial, - stage::{Camera, GltfVertexData, RenderUnit, VertexData}, - }, - Renderling, Stage, + shader::{array::Array, gltf::*, slab::Slab, stage::Camera}, + Id, Renderling, Stage, }; #[test] fn get_vertex_count_primitive_sanity() { - _ + let (document, _, _) = + gltf::import("../../gltf/gltfTutorial_008_SimpleMeshes.gltf").unwrap(); + let prim = document + .meshes() + .next() + .unwrap() + .primitives() + .next() + .unwrap(); + let vertex_count = super::get_vertex_count(&prim); + assert_eq!(3, vertex_count); + } + + #[test] + fn accessor_sanity() { + println!("{:08b}", 1u8); + println!("{:08b}", 1i8); + println!("{:08b}", -1i8); + println!("{} {}", u8::MAX, i8::MAX); + let u16buffer = [1u16, 1u16, 1u16, 1u16]; + for chunk in u16buffer.chunks(2) { + match chunk { + [a, b] => { + println!("{a:016b} {b:016b}"); + } + _ => panic!("bad chunk"), + } + } + let u32buffer = bytemuck::cast_slice::(&u16buffer).to_vec(); // + for u in u32buffer.iter() { + println!("{u:032b}"); + } + println!("u32buffer: {u32buffer:?}"); + assert_eq!(2, u32buffer.len()); + let mut data = [0u32; 256]; + let buffer_index = data.write_slice(&u32buffer, 0); + assert_eq!(2, buffer_index); + let buffer = GltfBuffer(Array::new(0, buffer_index as u32)); + let _ = data.write(&buffer, buffer_index); + let accessor = GltfAccessor { + size: 2, + count: 3, + buffer: Id::from(buffer_index), + view_offset: 0, + view_stride: 0, + data_type: DataType::U16, + dimensions: Dimensions::Scalar, + normalized: false, + }; + let i0 = accessor.get1(0, &data); + assert_eq!(1, i0); + let i1 = accessor.get1(1, &data); + assert_eq!(1, i1); + let i2 = accessor.get1(2, &data); + assert_eq!(1, i2); } #[test] @@ -687,7 +854,7 @@ mod test { // * support multiple nodes that reference the same mesh // * support primitives w/ positions and normal attributes // * support transforming nodes (T * R * S) - fn simple_meshes() { + fn stage_gltf_simple_meshes() { let mut r = Renderling::headless(100, 50).with_background_color(Vec3::splat(0.0).extend(1.0)); let (device, queue) = r.get_device_and_queue_owned(); @@ -707,71 +874,11 @@ mod test { position, }; let camera_id = stage.append(&camera); - // For now we have to keep the original document around to figure out - // what to draw. - fn draw_node<'a>( - stage: &Stage, - gpu_doc: &GltfDocument, - camera_id: Id, - node: gltf::Node<'a>, - parents: Vec>, - ) -> Vec> { - let mut units = if let Some(mesh) = node.mesh() { - let primitives = mesh.primitives(); - let mesh = gpu_doc.meshes.at(mesh.index()); - primitives - .map(|primitive| { - let parent_node_path = stage.append_array(&parents); - let vertex_data_id = stage.append(&GltfVertexData { - parent_node_path, - mesh, - primitive_index: primitive.index() as u32, - }); - let render_unit = RenderUnit { - vertex_data: VertexData::Gltf(vertex_data_id), - vertex_count: super::get_vertex_count(&primitive), - transform: Id::NONE, - camera: camera_id, - }; - stage.draw_unit(&render_unit) - }) - .collect::>() - } else { - vec![] - }; - for child in node.children() { - let mut parents = parents.clone(); - parents.push(gpu_doc.nodes.at(child.index())); - units.extend(draw_node(stage, gpu_doc, camera_id, child, parents)); - } - units - } - for scene in document.scenes() { - for node in scene.nodes() { - let _units = draw_node(&stage, &gpu_doc, camera_id, node, vec![]); - } - } + let default_scene = document.default_scene().unwrap(); + let _units = stage.draw_gltf_scene(&gpu_doc, camera_id, default_scene); let img = r.render_image().unwrap(); img_diff::assert_img_eq("gltf_simple_meshes.png", img); } - - //#[test] - //fn stage_normal_mapping_brick_sphere() { - // crate::init_logging(); - // let size = 600; - // let mut r = - // Renderling::headless(size, size).with_background_color(Vec3::splat(1.0).extend(1.0)); - // let (device, queue) = r.get_device_and_queue_owned(); - // let stage = Stage::new(device, queue); - // stage.configure_graph(&mut r, true); - - // log::trace!("Reading gltf"); - // let (document, buffers, images) = gltf::import("../../gltf/red_brick_03_1k.glb").unwrap(); - // log::trace!("Loading gltf"); - // let gpu_doc = stage - // .load_gltf_document(&document, buffers, images) - // .unwrap(); - //} }