diff --git a/Cargo.lock b/Cargo.lock index b1b6dad4..09aa4a8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -49,6 +58,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -127,6 +151,7 @@ dependencies = [ "libdeflater", "log", "maths-rs", + "meshopt", "notify-debouncer-full", "png", "polodb_core", @@ -197,7 +222,7 @@ name = "component_derive" version = "0.1.0" dependencies = [ "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -277,6 +302,28 @@ dependencies = [ "libc", ] +[[package]] +name = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure", +] + [[package]] name = "fdeflate" version = "0.3.0" @@ -317,6 +364,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75224bec9bfe1a65e2d34132933f2de7fe79900c96a0174307554244ece8150e" +dependencies = [ + "num-traits", +] + [[package]] name = "float-cmp" version = "0.9.0" @@ -406,7 +462,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -452,6 +508,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + [[package]] name = "gltf" version = "1.3.0" @@ -475,7 +537,7 @@ dependencies = [ "inflections", "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -764,6 +826,17 @@ dependencies = [ "libc", ] +[[package]] +name = "meshopt" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bc418147122ebbcbe3d26f486ebb4f186c24a6ee9ce8f4d53780e32b264ced" +dependencies = [ + "cc", + "failure", + "float-cmp 0.5.3", +] + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -876,7 +949,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -888,6 +961,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -1116,7 +1198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "272da9ec1e28b0ef17df4dcefad820b13f098ebe9c82697111fc57ccff621e12" dependencies = [ "bitflags 1.3.2", - "float-cmp", + "float-cmp 0.9.0", "libloading", "once_cell", "renderdoc-sys", @@ -1154,6 +1236,12 @@ dependencies = [ "xmlparser", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustix" version = "0.38.20" @@ -1257,7 +1345,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -1338,6 +1426,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.38" @@ -1349,6 +1448,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + [[package]] name = "tap" version = "1.0.1" @@ -1372,7 +1483,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -1468,6 +1579,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "untrusted" version = "0.7.1" @@ -1571,7 +1688,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -1605,7 +1722,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 4b59851f..7f3907eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ maths-rs = "0.2.4" serde = "1.0.187" log = "0.4.20" simple_logger = "4.2.0" +meshopt = "0.1.9" [profile.dev] incremental = true diff --git a/assets/Sphere.bin b/assets/Sphere.bin new file mode 100644 index 00000000..b44b03de Binary files /dev/null and b/assets/Sphere.bin differ diff --git a/assets/Sphere.gltf b/assets/Sphere.gltf new file mode 100644 index 00000000..d1aece50 --- /dev/null +++ b/assets/Sphere.gltf @@ -0,0 +1,212 @@ +{ + "accessors": [ + { + "bufferView": 2, + "componentType": 5126, + "count": 2399, + "max": [ + 1.0, + 2.0, + 1.0 + ], + "min": [ + -1.0, + 0.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 28788, + "componentType": 5126, + "count": 2399, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 2399, + "max": [ + 1.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "componentType": 5125, + "count": 13536, + "type": "SCALAR" + } + ], + "asset": { + "extras": { + "author": "rawwerks (https://sketchfab.com/rawwerks)", + "license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)", + "source": "https://sketchfab.com/3d-models/sphere-gltf-example-cd602a89287b4cf1a704c13e15cf48f8", + "title": "sphere-gltf-example" + }, + "generator": "Sketchfab-12.65.0", + "version": "2.0" + }, + "bufferViews": [ + { + "buffer": 0, + "byteLength": 54144, + "name": "floatBufferViews", + "target": 34963 + }, + { + "buffer": 0, + "byteLength": 19192, + "byteOffset": 54144, + "byteStride": 8, + "name": "floatBufferViews", + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 57576, + "byteOffset": 73336, + "byteStride": 12, + "name": "floatBufferViews", + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 130912, + "uri": "Sphere.bin" + } + ], + "extensionsUsed": [ + "KHR_materials_transmission" + ], + "materials": [ + { + "extensions": { + "KHR_materials_transmission": { + "transmissionFactor": 0.0 + } + }, + "name": "GLASS", + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.99, + 0.99, + 0.99, + 1.0 + ], + "metallicFactor": 0.0, + "roughnessFactor": 0.0 + } + } + ], + "meshes": [ + { + "name": "Object_0", + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 0, + "TEXCOORD_0": 2 + }, + "indices": 3, + "material": 0, + "mode": 4 + } + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 2.220446049250313e-16, + -1.0, + 0.0, + 0.0, + 1.0, + 2.220446049250313e-16, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ], + "name": "Sketchfab_model" + }, + { + "children": [ + 2 + ], + "name": "root" + }, + { + "children": [ + 3 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 2.220446049250313e-16, + 1.0, + 0.0, + 0.0, + -1.0, + 2.220446049250313e-16, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ], + "name": "GLTF_SceneRootNode" + }, + { + "children": [ + 4 + ], + "name": "Sphere_1" + }, + { + "mesh": 0, + "name": "Object_4" + } + ], + "scene": 0, + "scenes": [ + { + "name": "Sketchfab_Scene", + "nodes": [ + 0 + ] + } + ] +} diff --git a/src/render_domain.rs b/src/render_domain.rs index 04b62b29..37a61b87 100644 --- a/src/render_domain.rs +++ b/src/render_domain.rs @@ -29,10 +29,10 @@ struct MeshData { pub struct VisibilityWorldRenderDomain { pipeline_layout_handle: render_system::PipelineLayoutHandle, - vertex_positions_buffer: render_system::BufferHandle, - vertex_normals_buffer: render_system::BufferHandle, + vertex_positions_buffer: render_system::BaseBufferHandle, + vertex_normals_buffer: render_system::BaseBufferHandle, - indices_buffer: render_system::BufferHandle, + indices_buffer: render_system::BaseBufferHandle, albedo: render_system::ImageHandle, depth_target: render_system::ImageHandle, @@ -45,8 +45,8 @@ pub struct VisibilityWorldRenderDomain { render_command_buffer: render_system::CommandBufferHandle, current_frame: usize, - camera_data_buffer_handle: render_system::BufferHandle, - materials_data_buffer_handle: render_system::BufferHandle, + camera_data_buffer_handle: render_system::BaseBufferHandle, + materials_data_buffer_handle: render_system::BaseBufferHandle, descriptor_set_layout: render_system::DescriptorSetLayoutHandle, descriptor_set: render_system::DescriptorSetHandle, @@ -54,8 +54,8 @@ pub struct VisibilityWorldRenderDomain { transfer_synchronizer: render_system::SynchronizerHandle, transfer_command_buffer: render_system::CommandBufferHandle, - meshes_data_buffer: render_system::BufferHandle, - meshlets_data_buffer: render_system::BufferHandle, + meshes_data_buffer: render_system::BaseBufferHandle, + meshlets_data_buffer: render_system::BaseBufferHandle, camera: Option>, @@ -82,11 +82,11 @@ pub struct VisibilityWorldRenderDomain { instance_id: render_system::ImageHandle, primitive_index: render_system::ImageHandle, - material_count: render_system::BufferHandle, - material_offset: render_system::BufferHandle, - material_offset_scratch: render_system::BufferHandle, - material_evaluation_dispatches: render_system::BufferHandle, - material_xy: render_system::BufferHandle, + material_count: render_system::BaseBufferHandle, + material_offset: render_system::BaseBufferHandle, + material_offset_scratch: render_system::BaseBufferHandle, + material_evaluation_dispatches: render_system::BaseBufferHandle, + material_xy: render_system::BaseBufferHandle, material_evaluation_descriptor_set_layout: render_system::DescriptorSetLayoutHandle, material_evaluation_descriptor_set: render_system::DescriptorSetHandle, @@ -97,7 +97,7 @@ pub struct VisibilityWorldRenderDomain { tone_map_pass: ToneMapPass, debug_position: render_system::ImageHandle, debug_normal: render_system::ImageHandle, - light_data_buffer: render_system::BufferHandle, + light_data_buffer: render_system::BaseBufferHandle, pending_texture_loads: Vec, @@ -200,8 +200,8 @@ impl VisibilityWorldRenderDomain { let camera_data_buffer_handle = render_system.create_buffer(Some("Visibility Camera Data"), 16 * 4 * 4, render_system::Uses::Storage, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead, render_system::UseCases::DYNAMIC); - let meshes_data_buffer = render_system.create_buffer(Some("Visibility Meshes Data"), 16 * 4 * 4 * 16, render_system::Uses::Storage, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead, render_system::UseCases::DYNAMIC); - let meshlets_data_buffer = render_system.create_buffer(Some("Visibility Meshlets Data"), 16 * 4 * 4 * 16, render_system::Uses::Storage, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead, render_system::UseCases::DYNAMIC); + let meshes_data_buffer = render_system.create_buffer(Some("Visibility Meshes Data"), std::mem::size_of::() * 1024, render_system::Uses::Storage, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead, render_system::UseCases::STATIC); + let meshlets_data_buffer = render_system.create_buffer(Some("Visibility Meshlets Data"), std::mem::size_of::() * 1024, render_system::Uses::Storage, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead, render_system::UseCases::STATIC); render_system.write(&[ render_system::DescriptorWrite { @@ -252,6 +252,7 @@ impl VisibilityWorldRenderDomain { #extension GL_EXT_shader_16bit_storage: require #extension GL_EXT_shader_explicit_arithmetic_types: enable #extension GL_EXT_mesh_shader: require +#extension GL_EXT_debug_printf : enable layout(row_major) uniform; layout(row_major) buffer; @@ -275,6 +276,7 @@ struct Meshlet {{ uint16_t triangle_offset; uint8_t vertex_count; uint8_t triangle_count; + uint8_t padding[6]; }}; layout(set=0,binding=0,scalar) buffer readonly CameraBuffer {{ @@ -307,14 +309,15 @@ void main() {{ uint instance_index = meshlet.instance_index; SetMeshOutputsEXT(meshlet.vertex_count, meshlet.triangle_count); - - if (gl_LocalInvocationID.x < meshlet.vertex_count) {{ - uint vertex_index = meshlet.vertex_offset + gl_LocalInvocationID.x; + + if (gl_LocalInvocationID.x < uint(meshlet.vertex_count) && gl_LocalInvocationID.x < {VERTEX_COUNT}) {{ + uint vertex_index = uint(meshlet.vertex_offset) + gl_LocalInvocationID.x; gl_MeshVerticesEXT[gl_LocalInvocationID.x].gl_Position = camera.view_projection * meshes[instance_index].model * vec4(vertex_positions[vertex_index], 1.0); + // gl_MeshVerticesEXT[gl_LocalInvocationID.x].gl_Position = vec4(vertex_positions[vertex_index], 1.0); }} - if (gl_LocalInvocationID.x < meshlet.triangle_count) {{ - uint triangle_index = meshlet.triangle_offset + gl_LocalInvocationID.x; + if (gl_LocalInvocationID.x < uint(meshlet.triangle_count) && gl_LocalInvocationID.x < {TRIANGLE_COUNT}) {{ + uint triangle_index = uint(meshlet.triangle_offset) + gl_LocalInvocationID.x; uint triangle_indices[3] = uint[](indices[triangle_index * 3 + 0], indices[triangle_index * 3 + 1], indices[triangle_index * 3 + 2]); gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationID.x] = uvec3(triangle_indices[0], triangle_indices[1], triangle_indices[2]); out_instance_index[gl_LocalInvocationID.x] = instance_index; @@ -1324,7 +1327,7 @@ void main() { render_system.wait(self.render_finished_synchronizer); - //render_system.start_frame_capture(); + render_system.start_frame_capture(); let camera_data_buffer = render_system.get_mut_buffer_slice(self.camera_data_buffer_handle); @@ -1404,6 +1407,45 @@ void main() { command_buffer_recording.start_region("Visibility Pass"); + command_buffer_recording.consume_resources(&[ + render_system::Consumption { + handle: render_system::Handle::Buffer(self.camera_data_buffer_handle), + stages: render_system::Stages::MESH | render_system::Stages::FRAGMENT, + access: render_system::AccessPolicies::READ, + layout: render_system::Layouts::General, + }, + render_system::Consumption { + handle: render_system::Handle::Buffer(self.vertex_positions_buffer), + stages: render_system::Stages::MESH, + access: render_system::AccessPolicies::READ, + layout: render_system::Layouts::General, + }, + render_system::Consumption { + handle: render_system::Handle::Buffer(self.vertex_normals_buffer), + stages: render_system::Stages::MESH, + access: render_system::AccessPolicies::READ, + layout: render_system::Layouts::General, + }, + render_system::Consumption { + handle: render_system::Handle::Buffer(self.indices_buffer), + stages: render_system::Stages::MESH, + access: render_system::AccessPolicies::READ, + layout: render_system::Layouts::General, + }, + render_system::Consumption { + handle: render_system::Handle::Buffer(self.meshes_data_buffer), + stages: render_system::Stages::MESH | render_system::Stages::FRAGMENT, + access: render_system::AccessPolicies::READ, + layout: render_system::Layouts::General, + }, + render_system::Consumption { + handle: render_system::Handle::Buffer(self.meshlets_data_buffer), + stages: render_system::Stages::MESH | render_system::Stages::FRAGMENT, + access: render_system::AccessPolicies::READ, + layout: render_system::Layouts::General, + }, + ]); + command_buffer_recording.start_render_pass(Extent::new(1920, 1080, 1), &attachments); // Visibility pass @@ -1601,7 +1643,7 @@ void main() { command_buffer_recording.execute(&[self.transfer_synchronizer, self.image_ready], &[self.render_finished_synchronizer], self.render_finished_synchronizer); - //render_system.end_frame_capture(); + render_system.end_frame_capture(); render_system.present(image_index, &[swapchain_handle], self.render_finished_synchronizer); @@ -1617,14 +1659,15 @@ impl orchestrator::EntitySubscriber for VisibilityWorldRenderDom } } -#[repr(C)] #[derive(Copy, Clone)] +#[repr(C)] struct ShaderMeshletData { instance_index: u32, vertex_offset: u16, - primitive_offset: u16, + triangle_offset: u16, vertex_count: u8, triangle_count: u8, + pad: [u8; 6], } #[repr(C)] @@ -1686,9 +1729,9 @@ impl orchestrator::EntitySubscriber for VisibilityWorldRenderDomain { options.resources.push(resource_manager::OptionResource { url: resource.url.clone(), buffers: vec![ - resource_manager::Buffer{ buffer: vertex_positions_buffer, tag: "Vertex.Position".to_string() }, - resource_manager::Buffer{ buffer: vertex_normals_buffer, tag: "Vertex.Normal".to_string() }, - resource_manager::Buffer{ buffer: index_buffer, tag: "Index".to_string() } + resource_manager::Buffer{ buffer: &mut vertex_positions_buffer[(self.visiblity_info.vertex_count as usize * std::mem::size_of::())..], tag: "Vertex.Position".to_string() }, + resource_manager::Buffer{ buffer: &mut vertex_normals_buffer[(self.visiblity_info.vertex_count as usize * std::mem::size_of::())..], tag: "Vertex.Normal".to_string() }, + resource_manager::Buffer{ buffer: &mut index_buffer[(self.visiblity_info.triangle_count as usize * 3 * std::mem::size_of::())..], tag: "MeshletIndices".to_string() } ], }); } @@ -1709,25 +1752,30 @@ impl orchestrator::EntitySubscriber for VisibilityWorldRenderDomain { { let vertex_offset = self.visiblity_info.vertex_count; - let triangle_offset = self.visiblity_info.triangle_count / 3; + let triangle_offset = self.visiblity_info.triangle_count; - let meshlet_count = (mesh.index_count / 3).div_ceil(TRIANGLE_COUNT); + let meshlet_count = (mesh.vertex_count).div_ceil(63); let mut mesh_vertex_count = 0; let mut mesh_triangle_count = 0; let mut meshlets = Vec::with_capacity(meshlet_count as usize); + let meshlet_index_stream = mesh.index_streams.iter().find(|is| is.stream_type == mesh_resource_handler::IndexStreamTypes::Meshlets).unwrap(); + + assert_eq!(meshlet_index_stream.data_type, mesh_resource_handler::IntegralTypes::U16, "Meshlet index stream is not u16"); + for _ in 0..meshlet_count { - let meshlet_vertex_count = (mesh.vertex_count - mesh_vertex_count).min(TRIANGLE_COUNT) as u8; - let meshlet_triangle_count = (mesh.index_count / 3 - mesh_triangle_count).min(TRIANGLE_COUNT) as u8; + let meshlet_vertex_count = (mesh.vertex_count - mesh_vertex_count).min(63) as u8; + let meshlet_triangle_count = (meshlet_index_stream.count / 3 - mesh_triangle_count).min(21) as u8; let meshlet_data = ShaderMeshletData { instance_index: self.visiblity_info.instance_count, vertex_offset: vertex_offset as u16 + mesh_vertex_count as u16, - primitive_offset:triangle_offset as u16 + mesh_triangle_count as u16, + triangle_offset:triangle_offset as u16 + mesh_triangle_count as u16, vertex_count: meshlet_vertex_count, triangle_count: meshlet_triangle_count, + pad: [0u8; 6], }; meshlets.push(meshlet_data); @@ -1757,7 +1805,7 @@ impl orchestrator::EntitySubscriber for VisibilityWorldRenderDomain { let meshlets_data_slice = render_system.get_mut_buffer_slice(self.meshlets_data_buffer); - let meshlets_data_slice = unsafe { std::slice::from_raw_parts_mut(meshlets_data_slice.as_mut_ptr() as *mut ShaderMeshletData, 128) }; + let meshlets_data_slice = unsafe { std::slice::from_raw_parts_mut(meshlets_data_slice.as_mut_ptr() as *mut ShaderMeshletData, 256) }; let mesh = self.meshes.get(mesh.resource_id).expect("Mesh not loaded"); diff --git a/src/rendering/render_system.rs b/src/rendering/render_system.rs index 14bbd35a..e8cbdd3f 100644 --- a/src/rendering/render_system.rs +++ b/src/rendering/render_system.rs @@ -55,7 +55,10 @@ bitflags::bitflags! { // HANDLES #[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)] -pub struct BufferHandle(pub(super) u64); +pub struct BaseBufferHandle(pub(super) u64); + +#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)] +pub struct BufferHandle(pub(super) u64, std::marker::PhantomData); #[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)] pub struct AccelerationStructureHandle(pub(super) u64); @@ -104,7 +107,7 @@ pub struct TextureCopyHandle(pub(crate) u64); #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum Handle { - Buffer(BufferHandle), + Buffer(BaseBufferHandle), AccelerationStructure(AccelerationStructureHandle), CommandBuffer(CommandBufferHandle), Shader(ShaderHandle), @@ -132,9 +135,9 @@ pub struct Consumption { pub enum AccelerationStructureBuildAA { Mesh { - vertex_buffer: BufferHandle, - index_buffer: BufferHandle, - transform_buffer: BufferHandle, + vertex_buffer: BaseBufferHandle, + index_buffer: BaseBufferHandle, + transform_buffer: BaseBufferHandle, vertex_format: Formats, vertex_stride: u32, index_format: DataTypes, @@ -143,25 +146,25 @@ pub enum AccelerationStructureBuildAA { vertex_count: u32, }, AABB { - aabb_buffer: BufferHandle, - transform_buffer: BufferHandle, + aabb_buffer: BaseBufferHandle, + transform_buffer: BaseBufferHandle, transform_count: u32, }, Instance { acceleration_structure: AccelerationStructureHandle, - transform_buffer: BufferHandle, + transform_buffer: BaseBufferHandle, transform_count: u32, }, } pub struct AccelerationStructureBuild { pub acceleration_structure: AccelerationStructureHandle, - pub scratch_buffer: BufferHandle, + pub scratch_buffer: BaseBufferHandle, pub acceleration_structure_build_type: AccelerationStructureBuildAA, } pub struct BufferStridedRange { - pub buffer: BufferHandle, + pub buffer: BaseBufferHandle, pub offset: u64, pub stride: u64, pub size: u64, @@ -222,7 +225,7 @@ pub trait CommandBufferRecording { fn trace_rays(&mut self, binding_tables: BindingTables, x: u32, y: u32, z: u32); fn clear_textures(&mut self, textures: &[(ImageHandle, ClearValue)]); - fn clear_buffers(&mut self, buffer_handles: &[BufferHandle]); + fn clear_buffers(&mut self, buffer_handles: &[BaseBufferHandle]); fn transfer_textures(&mut self, texture_handles: &[ImageHandle]); @@ -254,7 +257,7 @@ pub enum Ranges { pub enum Descriptor { Buffer { - handle: BufferHandle, + handle: BaseBufferHandle, size: Ranges, }, Image { @@ -321,14 +324,14 @@ pub trait RenderSystem: orchestrator::System { /// # Returns /// /// The handle of the buffer. - fn create_buffer(&mut self, name: Option<&str>, size: usize, resource_uses: Uses, device_accesses: DeviceAccesses, use_case: UseCases) -> BufferHandle; + fn create_buffer(&mut self, name: Option<&str>, size: usize, resource_uses: Uses, device_accesses: DeviceAccesses, use_case: UseCases) -> BaseBufferHandle; - fn get_buffer_address(&self, buffer_handle: BufferHandle) -> u64; + fn get_buffer_address(&self, buffer_handle: BaseBufferHandle) -> u64; - fn get_buffer_slice(&mut self, buffer_handle: BufferHandle) -> &[u8]; + fn get_buffer_slice(&mut self, buffer_handle: BaseBufferHandle) -> &[u8]; // Return a mutable slice to the buffer data. - fn get_mut_buffer_slice(&self, buffer_handle: BufferHandle) -> &mut [u8]; + fn get_mut_buffer_slice(&self, buffer_handle: BaseBufferHandle) -> &mut [u8]; fn get_texture_slice_mut(&self, texture_handle: ImageHandle) -> &mut [u8]; @@ -337,7 +340,7 @@ pub trait RenderSystem: orchestrator::System { fn create_sampler(&mut self) -> SamplerHandle; - fn create_acceleration_structure_instance_buffer(&mut self, name: Option<&str>, max_instance_count: u32) -> BufferHandle; + fn create_acceleration_structure_instance_buffer(&mut self, name: Option<&str>, max_instance_count: u32) -> BaseBufferHandle; fn create_acceleration_structure(&mut self, name: Option<&str>, r#type: AccelerationStructureTypes, buffer_descriptor: BufferDescriptor,) -> AccelerationStructureHandle; fn bind_to_window(&mut self, window_os_handles: &window_system::WindowOsHandles) -> SwapchainHandle; @@ -1397,9 +1400,9 @@ pub struct ImageCopy { /// Stores the information of a buffer copy. pub struct BufferCopy { /// The source buffer. - pub(super) source: BufferHandle, + pub(super) source: BaseBufferHandle, /// The destination buffer. - pub(super) destination: BufferHandle, + pub(super) destination: BaseBufferHandle, /// The size of the copy. pub(super) size: usize, } @@ -1429,7 +1432,7 @@ pub enum Barrier { /// An image barrier. Image(ImageHandle), /// A buffer barrier. - Buffer(BufferHandle), + Buffer(BaseBufferHandle), /// A memory barrier. Memory, } @@ -1568,7 +1571,7 @@ pub enum DescriptorInfo { /// A buffer descriptor. Buffer { /// The buffer of the descriptor. - buffer: BufferHandle, + buffer: BaseBufferHandle, /// The offset to start reading from inside the buffer. offset: usize, /// How much to read from the buffer after `offset`. @@ -1634,7 +1637,7 @@ pub enum SwapchainStates { } pub struct BufferDescriptor { - pub buffer: BufferHandle, + pub buffer: BaseBufferHandle, pub offset: u64, pub range: u64, pub slot: u32, @@ -1736,7 +1739,7 @@ impl RenderSystem for RenderSystemImplementation { self.pointer.create_shader(shader_source_type, stage, shader) } - fn get_buffer_address(&self, buffer_handle: BufferHandle) -> u64 { + fn get_buffer_address(&self, buffer_handle: BaseBufferHandle) -> u64 { self.pointer.get_buffer_address(buffer_handle) } @@ -1744,11 +1747,11 @@ impl RenderSystem for RenderSystemImplementation { self.pointer.write(descriptor_set_writes) } - fn get_buffer_slice(&mut self, buffer_handle: BufferHandle) -> &[u8] { + fn get_buffer_slice(&mut self, buffer_handle: BaseBufferHandle) -> &[u8] { self.pointer.get_buffer_slice(buffer_handle) } - fn get_mut_buffer_slice(&self, buffer_handle: BufferHandle) -> &mut [u8] { + fn get_mut_buffer_slice(&self, buffer_handle: BaseBufferHandle) -> &mut [u8] { self.pointer.get_mut_buffer_slice(buffer_handle) } @@ -1784,7 +1787,7 @@ impl RenderSystem for RenderSystemImplementation { self.pointer.acquire_swapchain_image(swapchain_handle, synchronizer_handle) } - fn create_buffer(&mut self, name: Option<&str>, size: usize, uses: Uses, accesses: DeviceAccesses, use_case: UseCases) -> BufferHandle { + fn create_buffer(&mut self, name: Option<&str>, size: usize, uses: Uses, accesses: DeviceAccesses, use_case: UseCases) -> BaseBufferHandle { self.pointer.create_buffer(name, size, uses, accesses, use_case) } @@ -1828,7 +1831,7 @@ impl RenderSystem for RenderSystemImplementation { self.pointer.create_sampler() } - fn create_acceleration_structure_instance_buffer(&mut self, name: Option<&str>, max_instance_count: u32) -> BufferHandle { + fn create_acceleration_structure_instance_buffer(&mut self, name: Option<&str>, max_instance_count: u32) -> BaseBufferHandle { self.pointer.create_acceleration_structure_instance_buffer(name, max_instance_count) } diff --git a/src/rendering/vulkan_render_system.rs b/src/rendering/vulkan_render_system.rs index de59820a..a211f7cd 100644 --- a/src/rendering/vulkan_render_system.rs +++ b/src/rendering/vulkan_render_system.rs @@ -4,8 +4,11 @@ use ash::vk; use crate::{orchestrator, window_system, render_debugger::RenderDebugger, rendering::render_system}; +#[cfg(not(test))] +use log::{warn, error, debug}; + #[cfg(test)] -use std::{println as error, println as warn}; +use std::{println as error, println as warn, println as debug}; pub struct VulkanRenderSystem { entry: ash::Entry, @@ -112,9 +115,9 @@ impl render_system::RenderSystem for VulkanRenderSystem { let mut options = shaderc::CompileOptions::new().unwrap(); options.set_optimization_level(shaderc::OptimizationLevel::Performance); - options.set_target_env(shaderc::TargetEnv::Vulkan, shaderc::EnvVersion::Vulkan1_2 as u32); + options.set_target_env(shaderc::TargetEnv::Vulkan, (1 << 22) | (3 << 12)); options.set_generate_debug_info(); - options.set_target_spirv(shaderc::SpirvVersion::V1_5); + options.set_target_spirv(shaderc::SpirvVersion::V1_6); options.set_invert_y(true); let shader_text = std::str::from_utf8(shader).unwrap(); @@ -611,7 +614,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { /// # Returns /// /// The handle of the buffer. - fn create_buffer(&mut self, name: Option<&str>, size: usize, resource_uses: render_system::Uses, device_accesses: render_system::DeviceAccesses, use_case: render_system::UseCases) -> render_system::BufferHandle { + fn create_buffer(&mut self, name: Option<&str>, size: usize, resource_uses: render_system::Uses, device_accesses: render_system::DeviceAccesses, use_case: render_system::UseCases) -> render_system::BaseBufferHandle { if device_accesses.contains(render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead) { match use_case { render_system::UseCases::STATIC => { @@ -621,7 +624,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { let (device_address, pointer) = self.bind_vulkan_buffer_memory(&buffer_creation_result, allocation_handle, 0); - let buffer_handle = render_system::BufferHandle(self.buffers.len() as u64); + let buffer_handle = render_system::BaseBufferHandle(self.buffers.len() as u64); self.buffers.push(Buffer { buffer: buffer_creation_result.resource, @@ -639,7 +642,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { let (device_address, pointer) = self.bind_vulkan_buffer_memory(&buffer_creation_result, allocation_handle, 0); - let buffer_handle = render_system::BufferHandle(self.buffers.len() as u64); + let buffer_handle = render_system::BaseBufferHandle(self.buffers.len() as u64); self.buffers.push(Buffer { buffer: buffer_creation_result.resource, @@ -671,7 +674,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { let (device_address, pointer) = self.bind_vulkan_buffer_memory(&buffer_creation_result, allocation_handle, 0); - let buffer_handle = render_system::BufferHandle(self.buffers.len() as u64); + let buffer_handle = render_system::BaseBufferHandle(self.buffers.len() as u64); self.buffers.push(Buffer { buffer: buffer_creation_result.resource, @@ -686,11 +689,11 @@ impl render_system::RenderSystem for VulkanRenderSystem { } } - fn get_buffer_address(&self, buffer_handle: render_system::BufferHandle) -> u64 { + fn get_buffer_address(&self, buffer_handle: render_system::BaseBufferHandle) -> u64 { self.buffers[buffer_handle.0 as usize].device_address } - fn get_buffer_slice(&mut self, buffer_handle: render_system::BufferHandle) -> &[u8] { + fn get_buffer_slice(&mut self, buffer_handle: render_system::BaseBufferHandle) -> &[u8] { let buffer = self.buffers[buffer_handle.0 as usize]; unsafe { std::slice::from_raw_parts(buffer.pointer, buffer.size as usize) @@ -698,7 +701,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { } // Return a mutable slice to the buffer data. - fn get_mut_buffer_slice(&self, buffer_handle: render_system::BufferHandle) -> &mut [u8] { + fn get_mut_buffer_slice(&self, buffer_handle: render_system::BaseBufferHandle) -> &mut [u8] { let buffer = self.buffers[buffer_handle.0 as usize]; unsafe { std::slice::from_raw_parts_mut(buffer.pointer, buffer.size) @@ -746,7 +749,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { let (address, pointer) = self.bind_vulkan_buffer_memory(&staging_buffer_creation_result, allocation_handle, 0); - let staging_buffer_handle = render_system::BufferHandle(self.buffers.len() as u64); + let staging_buffer_handle = render_system::BaseBufferHandle(self.buffers.len() as u64); self.buffers.push(Buffer { buffer: staging_buffer_creation_result.resource, @@ -763,7 +766,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { let (address, pointer) = self.bind_vulkan_buffer_memory(&staging_buffer_creation_result, allocation_handle, 0); - let staging_buffer_handle = render_system::BufferHandle(self.buffers.len() as u64); + let staging_buffer_handle = render_system::BaseBufferHandle(self.buffers.len() as u64); self.buffers.push(Buffer { buffer: staging_buffer_creation_result.resource, @@ -805,7 +808,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { render_system::SamplerHandle(self.create_vulkan_sampler().as_raw()) } - fn create_acceleration_structure_instance_buffer(&mut self, name: Option<&str>, max_instance_count: u32) -> render_system::BufferHandle { + fn create_acceleration_structure_instance_buffer(&mut self, name: Option<&str>, max_instance_count: u32) -> render_system::BaseBufferHandle { let size = max_instance_count as usize * std::mem::size_of::(); let buffer_creation_result = self.create_vulkan_buffer(name, size, vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS); @@ -814,7 +817,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { let (address, pointer) = self.bind_vulkan_buffer_memory(&buffer_creation_result, allocation_handle, 0); - let buffer_handle = render_system::BufferHandle(self.buffers.len() as u64); + let buffer_handle = render_system::BaseBufferHandle(self.buffers.len() as u64); self.buffers.push(Buffer { buffer: buffer_creation_result.resource, @@ -1048,9 +1051,6 @@ impl render_system::RenderSystem for VulkanRenderSystem { use ash::{vk::{ValidationFeatureEnableEXT, Handle}, Entry}; -#[cfg(not(test))] -use log::{warn, error, debug}; - use super::render_system::{CommandBufferRecording, Formats, DispatchExtent}; #[derive(Clone)] @@ -1122,7 +1122,7 @@ pub(crate) struct Synchronizer { #[derive(Clone, Copy)] pub(crate) struct Texture { next: Option, - staging_buffer: Option, + staging_buffer: Option, allocation_handle: render_system::AllocationHandle, image: vk::Image, image_view: vk::ImageView, @@ -1145,6 +1145,9 @@ unsafe extern "system" fn vulkan_debug_utils_callback(message_severity: vk::Debu let message = std::ffi::CStr::from_ptr((*p_callback_data).p_message); match message_severity { + vk::DebugUtilsMessageSeverityFlagsEXT::INFO => { + debug!("{}", message.to_str().unwrap()); + } vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => { warn!("{}", message.to_str().unwrap()); } @@ -1521,6 +1524,9 @@ impl VulkanRenderSystem { let enabled_validation_features = [ ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION, ValidationFeatureEnableEXT::BEST_PRACTICES, + // ValidationFeatureEnableEXT::GPU_ASSISTED, + ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT, + ValidationFeatureEnableEXT::DEBUG_PRINTF, ]; let mut validation_features = vk::ValidationFeaturesEXT::default() @@ -2040,7 +2046,7 @@ impl VulkanRenderSystem { memory } - fn get_vulkan_buffer_address(&self, buffer: &render_system::BufferHandle, _allocation: &render_system::AllocationHandle) -> u64 { + fn get_vulkan_buffer_address(&self, buffer: &render_system::BaseBufferHandle, _allocation: &render_system::AllocationHandle) -> u64 { let buffer = self.buffers.get(buffer.0 as usize).expect("No buffer with that handle.").buffer.clone(); unsafe { self.device.get_buffer_device_address(&vk::BufferDeviceAddressInfo::default().buffer(buffer)) } } @@ -2448,7 +2454,7 @@ impl VulkanCommandBufferRecording<'_> { // } // } - fn get_buffer(&self, buffer_handle: render_system::BufferHandle) -> (render_system::BufferHandle, &Buffer) { + fn get_buffer(&self, buffer_handle: render_system::BaseBufferHandle) -> (render_system::BaseBufferHandle, &Buffer) { (buffer_handle, &self.render_system.buffers[buffer_handle.0 as usize]) } @@ -2922,7 +2928,7 @@ impl render_system::CommandBufferRecording for VulkanCommandBufferRecording<'_> unsafe { self.render_system.device.cmd_pipeline_barrier2(command_buffer.command_buffer, &dependency_info) }; } - fn clear_buffers(&mut self, buffer_handles: &[render_system::BufferHandle]) { + fn clear_buffers(&mut self, buffer_handles: &[render_system::BaseBufferHandle]) { self.consume_resources(&buffer_handles.iter().map(|buffer_handle| render_system::Consumption{ handle: render_system::Handle::Buffer(*buffer_handle), diff --git a/src/resource_manager/mesh_resource_handler.rs b/src/resource_manager/mesh_resource_handler.rs index f79a637c..f391b3b7 100644 --- a/src/resource_manager/mesh_resource_handler.rs +++ b/src/resource_manager/mesh_resource_handler.rs @@ -14,6 +14,15 @@ impl MeshResourceHandler { pub fn new() -> Self { Self {} } + + fn make_bounding_box(mesh: &gltf::Primitive) -> [[f32; 3]; 2] { + let bounds = mesh.bounding_box(); + + [ + [bounds.min[0], bounds.min[1], bounds.min[2],], + [bounds.max[0], bounds.max[1], bounds.max[2],], + ] + } } impl ResourceHandler for MeshResourceHandler { @@ -28,83 +37,103 @@ impl ResourceHandler for MeshResourceHandler { fn process(&self, resource_manager: &ResourceManager, asset_url: &str) -> Result, String> { let (gltf, buffers, _) = gltf::import(resource_manager.realize_asset_path(asset_url).unwrap()).unwrap(); - let mut buf: Vec = Vec::with_capacity(4096 * 1024 * 3); + const MESHLETIZE: bool = true; - // 'mesh_loop: for mesh in gltf.meshes() { - // for primitive in mesh.primitives() { - - let primitive = gltf.meshes().next().unwrap().primitives().next().unwrap(); + let mut resources = Vec::with_capacity(2); - let mut vertex_components = Vec::new(); - let index_type; - let bounding_box: [[f32; 3]; 2]; - let vertex_count = primitive.attributes().next().unwrap().1.count() as u32; - let index_count = primitive.indices().unwrap().count() as u32; + for mesh in gltf.meshes() { + for primitive in mesh.primitives() { + let mut vertex_components = Vec::new(); - let bounds = primitive.bounding_box(); + let bounding_box = Self::make_bounding_box(&primitive); - bounding_box = [ - [bounds.min[0], bounds.min[1], bounds.min[2],], - [bounds.max[0], bounds.max[1], bounds.max[2],], - ]; + let mut buffer = Vec::with_capacity(4096 * 1024 * 3); - let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()])); + let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()])); - if let Some(positions) = reader.read_positions() { - positions.for_each(|position| position.iter().for_each(|m| m.to_le_bytes().iter().for_each(|byte| buf.push(*byte)))); - vertex_components.push(VertexComponent { semantic: VertexSemantics::Position, format: "vec3f".to_string(), channel: 0 }); - } else { - return Err("Mesh does not have positions".to_string()); - } + let vertex_count = if let Some(positions) = reader.read_positions() { + let vertex_count = positions.clone().count(); + positions.for_each(|position| position.iter().for_each(|m| m.to_le_bytes().iter().for_each(|byte| buffer.push(*byte)))); + vertex_components.push(VertexComponent { semantic: VertexSemantics::Position, format: "vec3f".to_string(), channel: 0 }); + vertex_count + } else { + return Err("Mesh does not have positions".to_string()); + }; - if let Some(normals) = reader.read_normals() { - normals.for_each(|normal| normal.iter().for_each(|m| m.to_le_bytes().iter().for_each(|byte| buf.push(*byte)))); - vertex_components.push(VertexComponent { semantic: VertexSemantics::Normal, format: "vec3f".to_string(), channel: 1 }); - } + let indices = reader.read_indices().expect("Cannot create mesh which does not have indices").into_u32().collect::>(); - if let Some(tangents) = reader.read_tangents() { - tangents.for_each(|tangent| tangent.iter().for_each(|m| m.to_le_bytes().iter().for_each(|byte| buf.push(*byte)))); - vertex_components.push(VertexComponent { semantic: VertexSemantics::Tangent, format: "vec3f".to_string(), channel: 2 }); - } + let optimized_indices = meshopt::optimize::optimize_vertex_cache(&indices, vertex_count); + + if let Some(normals) = reader.read_normals() { + normals.for_each(|normal| normal.iter().for_each(|m| m.to_le_bytes().iter().for_each(|byte| buffer.push(*byte)))); + vertex_components.push(VertexComponent { semantic: VertexSemantics::Normal, format: "vec3f".to_string(), channel: 1 }); + } + + if let Some(tangents) = reader.read_tangents() { + tangents.for_each(|tangent| tangent.iter().for_each(|m| m.to_le_bytes().iter().for_each(|byte| buffer.push(*byte)))); + vertex_components.push(VertexComponent { semantic: VertexSemantics::Tangent, format: "vec3f".to_string(), channel: 2 }); + } + + if let Some(uv) = reader.read_tex_coords(0) { + uv.into_f32().for_each(|uv| uv.iter().for_each(|m| m.to_le_bytes().iter().for_each(|byte| buffer.push(*byte)))); + vertex_components.push(VertexComponent { semantic: VertexSemantics::Uv, format: "vec3f".to_string(), channel: 3 }); + } + + // align buffer to 16 bytes for indices + while buffer.len() % 16 != 0 { buffer.push(0); } - if let Some(uv) = reader.read_tex_coords(0) { - uv.into_f32().for_each(|uv| uv.iter().for_each(|m| m.to_le_bytes().iter().for_each(|byte| buf.push(*byte)))); - vertex_components.push(VertexComponent { semantic: VertexSemantics::Uv, format: "vec3f".to_string(), channel: 3 }); - } + let mut index_streams = Vec::with_capacity(2); + + let offset = buffer.len(); + + { + let index_type = IntegralTypes::U16; + + match index_type { + IntegralTypes::U16 => { + optimized_indices.iter().map(|i| *i as u16).for_each(|index| index.to_le_bytes().iter().for_each(|byte| buffer.push(*byte))); + index_streams.push(IndexStream{ data_type: IntegralTypes::U16, stream_type: IndexStreamTypes::Raw, offset, count: optimized_indices.len() as u32 }); + } + _ => panic!("Unsupported index type") + } + } + + let offset = buffer.len(); + + if MESHLETIZE { + let meshlets = meshopt::clusterize::build_meshlets(&optimized_indices, vertex_count, 64, 126); + + let mut index_count: usize = 0; + + for meshlet in meshlets { + index_count += meshlet.triangle_count as usize * 3; + for i in 0..meshlet.triangle_count as usize { + for x in meshlet.indices[i] { + (x as u16).to_le_bytes().iter().for_each(|byte| buffer.push(*byte)); + } + } + } + + assert_eq!(index_count, optimized_indices.len()); - // align buffer to 16 bytes for indices - while buf.len() % 16 != 0 { buf.push(0); } - - if let Some(indices) = reader.read_indices() { - match indices { - gltf::mesh::util::ReadIndices::U8(indices) => { - indices.for_each(|index| index.to_le_bytes().iter().for_each(|byte| buf.push(*byte))); - index_type = IntegralTypes::U8; - }, - gltf::mesh::util::ReadIndices::U16(indices) => { - indices.for_each(|index| index.to_le_bytes().iter().for_each(|byte| buf.push(*byte))); - index_type = IntegralTypes::U16; - }, - gltf::mesh::util::ReadIndices::U32(indices) => { - indices.for_each(|index| index.to_le_bytes().iter().for_each(|byte| buf.push(*byte))); - index_type = IntegralTypes::U32; - }, + index_streams.push(IndexStream{ data_type: IntegralTypes::U16, stream_type: IndexStreamTypes::Meshlets, offset, count: optimized_indices.len() as u32 }); + } + + let mesh = Mesh { + compression: CompressionSchemes::None, + bounding_box, + vertex_components, + vertex_count: vertex_count as u32, + index_streams, + }; + + let resource_document = GenericResourceSerialization::new(asset_url.to_string(), mesh); + + resources.push(ProcessedResources::Generated((resource_document, buffer))); } - } else { - return Err("Mesh does not have indices".to_string()); } - - let mesh = Mesh { - bounding_box, - vertex_components, - index_count, - vertex_count, - index_type - }; - let resource_document = GenericResourceSerialization::new(asset_url.to_string(), mesh); - - Ok(vec![ProcessedResources::Generated((resource_document, buf))]) + Ok(resources) } fn get_deserializers(&self) -> Vec<(&'static str, Box Box + Send>)> { @@ -128,14 +157,29 @@ impl ResourceHandler for MeshResourceHandler { file.read(&mut buffer.buffer[0..(mesh.vertex_count as usize * 12)]).unwrap(); } "Vertex.Normal" => { + #[cfg(debug_assertions)] + if !mesh.vertex_components.iter().any(|v| v.semantic == VertexSemantics::Normal) { error!("Requested Vertex.Normal stream but mesh does not have normals."); continue; } + file.seek(std::io::SeekFrom::Start(mesh.vertex_count as u64 * 12)).unwrap(); // 12 bytes per vertex file.read(&mut buffer.buffer[0..(mesh.vertex_count as usize * 12)]).unwrap(); } - "Index" => { - let base_offset = mesh.vertex_count as u64 * mesh.vertex_components.size() as u64; - let rounded_offset = base_offset.next_multiple_of(16); - file.seek(std::io::SeekFrom::Start(rounded_offset)).expect("Failed to seek to index buffer"); - file.read(&mut buffer.buffer[0..(mesh.index_count as usize * mesh.index_type.size())]).unwrap(); + "Indices" => { + #[cfg(debug_assertions)] + if !mesh.index_streams.iter().any(|stream| stream.stream_type == IndexStreamTypes::Raw) { error!("Requested Index stream but mesh does not have RAW indices."); continue; } + + let raw_index_stram = mesh.index_streams.iter().find(|stream| stream.stream_type == IndexStreamTypes::Raw).unwrap(); + + file.seek(std::io::SeekFrom::Start(raw_index_stram.offset as u64)).expect("Failed to seek to index buffer"); + file.read(&mut buffer.buffer[0..(raw_index_stram.count as usize * raw_index_stram.data_type.size())]).unwrap(); + } + "MeshletIndices" => { + #[cfg(debug_assertions)] + if !mesh.index_streams.iter().any(|stream| stream.stream_type == IndexStreamTypes::Meshlets) { error!("Requested MeshletIndices stream but mesh does not have meshlet indices indices."); continue; } + + let meshlet_indices_streams = mesh.index_streams.iter().find(|stream| stream.stream_type == IndexStreamTypes::Meshlets).unwrap(); + + file.seek(std::io::SeekFrom::Start(meshlet_indices_streams.offset as u64)).expect("Failed to seek to index buffer"); + file.read(&mut buffer.buffer[0..(meshlet_indices_streams.count as usize * meshlet_indices_streams.data_type.size())]).unwrap(); } _ => { error!("Unknown buffer tag: {}", buffer.tag); @@ -175,13 +219,35 @@ pub struct VertexComponent { pub channel: u32, } +#[derive(Debug, Serialize, Deserialize)] +pub enum CompressionSchemes { + None, + Quantization, + Octahedral, + OctahedralQuantization, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub enum IndexStreamTypes { + Raw, + Meshlets, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct IndexStream { + pub stream_type: IndexStreamTypes, + pub offset: usize, + pub count: u32, + pub data_type: IntegralTypes, +} + #[derive(Debug, Serialize, Deserialize)] pub struct Mesh { + pub compression: CompressionSchemes, pub bounding_box: [[f32; 3]; 2], pub vertex_components: Vec, - pub index_type: IntegralTypes, pub vertex_count: u32, - pub index_count: u32, + pub index_streams: Vec, } impl Resource for Mesh { @@ -197,7 +263,7 @@ impl Size for VertexSemantics { match self { VertexSemantics::Position => 3 * 4, VertexSemantics::Normal => 3 * 4, - VertexSemantics::Tangent => 3 * 4, + VertexSemantics::Tangent => 4 * 4, VertexSemantics::BiTangent => 3 * 4, VertexSemantics::Uv => 2 * 4, VertexSemantics::Color => 4 * 4, @@ -303,14 +369,12 @@ mod tests { assert_eq!(resource.type_id(), std::any::TypeId::of::()); - assert_eq!(buffer.len(), (24 /* vertices */ * (3 /* components per position */ * 4 /* float size */ + 3/*normals */ * 4) as usize).next_multiple_of(16) + 6/* cube faces */ * 2 /* triangles per face */ * 3 /* indices per triangle */ * 2 /* bytes per index */); - let mesh = resource.downcast_ref::().unwrap(); + let _offset = 0usize; + assert_eq!(mesh.bounding_box, [[-0.5f32, -0.5f32, -0.5f32], [0.5f32, 0.5f32, 0.5f32]]); assert_eq!(mesh.vertex_count, 24); - assert_eq!(mesh.index_count, 36); - assert_eq!(mesh.index_type, IntegralTypes::U16); assert_eq!(mesh.vertex_components.len(), 2); assert_eq!(mesh.vertex_components[0].semantic, VertexSemantics::Position); assert_eq!(mesh.vertex_components[0].format, "vec3f"); @@ -319,6 +383,22 @@ mod tests { assert_eq!(mesh.vertex_components[1].format, "vec3f"); assert_eq!(mesh.vertex_components[1].channel, 1); + assert_eq!(mesh.index_streams.len(), 2); + + let offset = ((mesh.vertex_count * mesh.vertex_components.size() as u32) as usize).next_multiple_of(16); + + assert_eq!(mesh.index_streams[0].stream_type, IndexStreamTypes::Raw); + assert_eq!(mesh.index_streams[0].offset, offset); + assert_eq!(mesh.index_streams[0].count, 36); + assert_eq!(mesh.index_streams[0].data_type, IntegralTypes::U16); + + let offset = offset + mesh.index_streams[0].count as usize * mesh.index_streams[0].data_type.size(); + + assert_eq!(mesh.index_streams[1].stream_type, IndexStreamTypes::Meshlets); + assert_eq!(mesh.index_streams[1].offset, offset); + assert_eq!(mesh.index_streams[1].count, 36); + assert_eq!(mesh.index_streams[1].data_type, IntegralTypes::U16); + let resource_request = resource_manager.request_resource("Box"); let resource_request = if let Some(resource_info) = resource_request { resource_info } else { return; }; @@ -334,7 +414,7 @@ mod tests { "Mesh" => { options.resources.push(OptionResource { url: resource.url.clone(), - buffers: vec![Buffer{ buffer: vertex_buffer.as_mut_slice(), tag: "Vertex".to_string() }, Buffer{ buffer: index_buffer.as_mut_slice(), tag: "Index".to_string() }], + buffers: vec![Buffer{ buffer: vertex_buffer.as_mut_slice(), tag: "Vertex".to_string() }, Buffer{ buffer: index_buffer.as_mut_slice(), tag: "Indices".to_string() }], }); } _ => {} @@ -351,7 +431,7 @@ mod tests { assert_eq!(buffer[0..(mesh.vertex_count * mesh.vertex_components.size() as u32) as usize], vertex_buffer[0..(mesh.vertex_count * mesh.vertex_components.size() as u32) as usize]); - assert_eq!(buffer[576..(576 + mesh.index_count * 2) as usize], index_buffer[0..(mesh.index_count * 2) as usize]); + assert_eq!(buffer[576..(576 + mesh.index_streams[0].count * 2) as usize], index_buffer[0..(mesh.index_streams[0].count * 2) as usize]); } _ => {} } @@ -362,7 +442,7 @@ mod tests { fn load_local_gltf_mesh_with_external_binaries() { let mut resource_manager = ResourceManager::new(); - let (response, _) = resource_manager.get("Suzanne").expect("Failed to get resource"); + let (response, buffer) = resource_manager.get("Suzanne").expect("Failed to get resource"); assert_eq!(response.resources.len(), 1); @@ -371,14 +451,12 @@ mod tests { assert_eq!(resource.type_id(), std::any::TypeId::of::()); - // assert_eq!(buffer.len(), (11808 /* vertices */ * (3 /* components per position */ * 4 /* float size */ + 3/*normals */ * 4) as usize).next_multiple_of(16) + 6/* cube faces */ * 2 /* triangles per face */ * 3 /* indices per triangle */ * 2 /* bytes per index */); - let mesh = resource.downcast_ref::().unwrap(); - // assert_eq!(mesh.bounding_box, [[-0.5f32, -0.5f32, -0.5f32], [0.5f32, 0.5f32, 0.5f32]]); + let _offset = 0usize; + + // assert_eq!(mesh.bounding_box, [[-2.674f32, -1.925f32, -1.626f32], [2.674f32, 1.925f32, 1.626f32]]); assert_eq!(mesh.vertex_count, 11808); - assert_eq!(mesh.index_count, 3936 * 3); - assert_eq!(mesh.index_type, IntegralTypes::U16); assert_eq!(mesh.vertex_components.len(), 4); assert_eq!(mesh.vertex_components[0].semantic, VertexSemantics::Position); assert_eq!(mesh.vertex_components[0].format, "vec3f"); @@ -386,6 +464,38 @@ mod tests { assert_eq!(mesh.vertex_components[1].semantic, VertexSemantics::Normal); assert_eq!(mesh.vertex_components[1].format, "vec3f"); assert_eq!(mesh.vertex_components[1].channel, 1); + + assert_eq!(mesh.index_streams.len(), 2); + + let offset = ((mesh.vertex_count * mesh.vertex_components.size() as u32) as usize).next_multiple_of(16); + + assert_eq!(mesh.index_streams[0].stream_type, IndexStreamTypes::Raw); + assert_eq!(mesh.index_streams[0].offset, offset); + assert_eq!(mesh.index_streams[0].count, 3936 * 3); + assert_eq!(mesh.index_streams[0].data_type, IntegralTypes::U16); + + let offset = offset + mesh.index_streams[0].count as usize * mesh.index_streams[0].data_type.size(); + + assert_eq!(mesh.index_streams[1].stream_type, IndexStreamTypes::Meshlets); + assert_eq!(mesh.index_streams[1].offset, offset); + assert_eq!(mesh.index_streams[1].count, 3936 * 3); + assert_eq!(mesh.index_streams[1].data_type, IntegralTypes::U16); + + let vertex_positions = unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const Vector3, mesh.vertex_count as usize) }; + + assert_eq!(vertex_positions.len(), 11808); + + assert_eq!(vertex_positions[0], Vector3::new(0.492188f32, 0.185547f32, 0.720703f32)); + assert_eq!(vertex_positions[1], Vector3::new(0.472656f32, 0.243042f32, 0.751221f32)); + assert_eq!(vertex_positions[2], Vector3::new(0.463867f32, 0.198242f32, 0.753418f32)); + + let vertex_normals = unsafe { std::slice::from_raw_parts((buffer.as_ptr() as *const Vector3).add(11808), mesh.vertex_count as usize) }; + + assert_eq!(vertex_normals.len(), 11808); + + assert_eq!(vertex_normals[0], Vector3::new(0.703351f32, -0.228379f32, 0.673156f32)); + assert_eq!(vertex_normals[1], Vector3::new(0.818977f32, -0.001884f32, 0.573824f32)); + assert_eq!(vertex_normals[2], Vector3::new(0.776439f32, -0.262265f32, 0.573027f32)); } #[test] @@ -401,21 +511,35 @@ mod tests { assert_eq!(resource.type_id(), std::any::TypeId::of::()); - assert_eq!(buffer.len(), (24 /* vertices */ * (3 /* components per position */ * 4 /* float size */ + 3/*normals */ * 4) as usize).next_multiple_of(16) + 6/* cube faces */ * 2 /* triangles per face */ * 3 /* indices per triangle */ * 2 /* bytes per index */); - let mesh = resource.downcast_ref::().unwrap(); + let offset = 0usize; + assert_eq!(mesh.bounding_box, [[-0.5f32, -0.5f32, -0.5f32], [0.5f32, 0.5f32, 0.5f32]]); assert_eq!(mesh.vertex_count, 24); - assert_eq!(mesh.index_count, 36); - assert_eq!(mesh.index_type, IntegralTypes::U16); assert_eq!(mesh.vertex_components.len(), 2); + assert_eq!(offset, 0); assert_eq!(mesh.vertex_components[0].semantic, VertexSemantics::Position); assert_eq!(mesh.vertex_components[0].format, "vec3f"); assert_eq!(mesh.vertex_components[0].channel, 0); assert_eq!(mesh.vertex_components[1].semantic, VertexSemantics::Normal); assert_eq!(mesh.vertex_components[1].format, "vec3f"); assert_eq!(mesh.vertex_components[1].channel, 1); + assert_eq!(mesh.index_streams.len(), 2); + + let offset = ((mesh.vertex_count * mesh.vertex_components.size() as u32) as usize).next_multiple_of(16); + + assert_eq!(mesh.index_streams[0].stream_type, IndexStreamTypes::Raw); + assert_eq!(mesh.index_streams[0].offset, offset); + assert_eq!(mesh.index_streams[0].count, 36); + assert_eq!(mesh.index_streams[0].data_type, IntegralTypes::U16); + + let offset = offset + mesh.index_streams[0].count as usize * mesh.index_streams[0].data_type.size(); + + assert_eq!(mesh.index_streams[1].stream_type, IndexStreamTypes::Meshlets); + assert_eq!(mesh.index_streams[1].offset, offset); + assert_eq!(mesh.index_streams[1].count, 36); + assert_eq!(mesh.index_streams[1].data_type, IntegralTypes::U16); // Cast buffer to Vector3 let vertex_positions = unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const Vector3, mesh.vertex_count as usize) }; @@ -426,7 +550,7 @@ mod tests { assert_eq!(vertex_positions[2], Vector3::new(-0.5f32, 0.5f32, 0.5f32)); // Cast buffer + 12 * 24 to Vector3 - let vertex_normals = unsafe { std::slice::from_raw_parts((buffer.as_ptr() as *const Vector3).add(24) as *const Vector3, mesh.vertex_count as usize) }; + let vertex_normals = unsafe { std::slice::from_raw_parts((buffer.as_ptr() as *const Vector3).add(24), mesh.vertex_count as usize) }; assert_eq!(vertex_normals.len(), 24); assert_eq!(vertex_normals[0], Vector3::new(0f32, 0f32, 1f32)); @@ -434,7 +558,7 @@ mod tests { assert_eq!(vertex_normals[2], Vector3::new(0f32, 0f32, 1f32)); // Cast buffer + 12 * 24 + 12 * 24 to u16 - let indeces = unsafe { std::slice::from_raw_parts((buffer.as_ptr().add(12 * 24 + 12 * 24)) as *const u16, mesh.index_count as usize) }; + let indeces = unsafe { std::slice::from_raw_parts((buffer.as_ptr().add(12 * 24 + 12 * 24)) as *const u16, mesh.index_streams[0].count as usize) }; assert_eq!(indeces.len(), 36); assert_eq!(indeces[0], 0); @@ -459,7 +583,7 @@ mod tests { "Mesh" => { options.resources.push(OptionResource { url: resource.url.clone(), - buffers: vec![Buffer{ buffer: vertex_buffer.as_mut_slice(), tag: "Vertex".to_string() }, Buffer{ buffer: index_buffer.as_mut_slice(), tag: "Index".to_string() }], + buffers: vec![Buffer{ buffer: vertex_buffer.as_mut_slice(), tag: "Vertex".to_string() }, Buffer{ buffer: index_buffer.as_mut_slice(), tag: "Indices".to_string() }], }); } _ => {} @@ -492,7 +616,7 @@ mod tests { // Cast index_buffer to u16 - let index_buffer = unsafe { std::slice::from_raw_parts(index_buffer.as_ptr() as *const u16, mesh.index_count as usize) }; + let index_buffer = unsafe { std::slice::from_raw_parts(index_buffer.as_ptr() as *const u16, mesh.index_streams[0].count as usize) }; assert_eq!(index_buffer.len(), 36); assert_eq!(index_buffer[0], 0); @@ -525,7 +649,7 @@ mod tests { buffers: vec![ Buffer{ buffer: vertex_positions_buffer.as_mut_slice(), tag: "Vertex.Position".to_string() }, Buffer{ buffer: vertex_normals_buffer.as_mut_slice(), tag: "Vertex.Normal".to_string() }, - Buffer{ buffer: index_buffer.as_mut_slice(), tag: "Index".to_string() } + Buffer{ buffer: index_buffer.as_mut_slice(), tag: "Indices".to_string() } ], }); } @@ -559,7 +683,7 @@ mod tests { // Cast index_buffer to u16 - let index_buffer = unsafe { std::slice::from_raw_parts(index_buffer.as_ptr() as *const u16, mesh.index_count as usize) }; + let index_buffer = unsafe { std::slice::from_raw_parts(index_buffer.as_ptr() as *const u16, mesh.index_streams[0].count as usize) }; assert_eq!(index_buffer.len(), 36); assert_eq!(index_buffer[0], 0); diff --git a/tests/gi.rs b/tests/gi.rs index 59c3b9ec..20f28c98 100644 --- a/tests/gi.rs +++ b/tests/gi.rs @@ -12,7 +12,7 @@ fn gi() { let orchestrator = app.get_mut_orchestrator(); orchestrator.spawn(byte_engine::camera::Camera { - position: Vec3f::new(0.0, 0.5, -2.0), + position: Vec3f::new(1.0, 0.5, -2.0), direction: Vec3f::new(0.0, 0.0, 1.0), fov: 90.0, aspect_ratio: 1.0, @@ -21,7 +21,7 @@ fn gi() { }); let _floor: EntityHandle = orchestrator.spawn(Mesh{ resource_id: "Box", material_id: "white_solid", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, -0.5, 0.0)) * maths_rs::Mat4f::from_scale(Vec3f::new(5.0, 1.0, 2.5)), }); - let _a: EntityHandle = orchestrator.spawn(Mesh{ resource_id: "Box", material_id: "white_solid", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, 0.25, 0.0)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.5, 0.5, 0.5)), }); + let _a: EntityHandle = orchestrator.spawn(Mesh{ resource_id: "Suzanne", material_id: "white_solid", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, 0.25, 0.0)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.5, 0.5, -0.5)), }); let _b: EntityHandle = orchestrator.spawn(Mesh{ resource_id: "Box", material_id: "red_solid", transform: maths_rs::Mat4f::from_translation(Vec3f::new(-0.6, 0.17, -0.1)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.34, 0.34, 0.34)), }); let _c: EntityHandle = orchestrator.spawn(Mesh{ resource_id: "Box", material_id: "green_solid", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.5, 0.13, -0.3)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.26, 0.26, 0.26)), });