From: Joshua Simmons Date: Tue, 21 Oct 2025 21:19:31 +0000 (+0200) Subject: shark: Render a square with mesh shaders X-Git-Url: https://git.nega.tv//gitweb.cgi?a=commitdiff_plain;h=66b91ddab198d96febe21b2e7e1a7b95d672ea3a;p=josh%2Fnarcissus shark: Render a square with mesh shaders --- diff --git a/title/shark-shaders/build.rs b/title/shark-shaders/build.rs index fdf5832..cea4a21 100644 --- a/title/shark-shaders/build.rs +++ b/title/shark-shaders/build.rs @@ -78,6 +78,7 @@ struct SlangShader { const SLANG_SHADERS: &[SlangShader] = &[ SlangShader { name: "basic" }, + SlangShader { name: "block" }, SlangShader { name: "draw_2d" }, SlangShader { name: "composite" }, SlangShader { name: "radix_sort" }, diff --git a/title/shark-shaders/shaders/block.slang b/title/shark-shaders/shaders/block.slang new file mode 100644 index 0000000..017b705 --- /dev/null +++ b/title/shark-shaders/shaders/block.slang @@ -0,0 +1,51 @@ +struct BlockConstants { + float4x4 clip_from_camera; +} + +struct VertexAttributes { + float4 position : SV_Position; +} + +struct PrimitiveAttributes { + float3 normal; + float3 color; +} + +[shader("mesh")] +[outputtopology("triangle")] +[numthreads(32, 1, 1)] +void mesh(uniform BlockConstants constants, OutputVertices vertices, OutputPrimitives primitives, OutputIndices indices, uint thread_id_in_group: SV_GroupThreadID) { + SetMeshOutputCounts(4, 2); + + static const float4 positions[4] = { + float4(-0.5, 0.0, -0.5, 1.0), + float4(-0.5, 0.0, 0.5, 1.0), + float4(0.5, 0.0, 0.5, 1.0), + float4(0.5, 0.0, -0.5, 1.0), + }; + + if (thread_id_in_group < 4) { + vertices[thread_id_in_group].position = mul(constants.clip_from_camera, positions[thread_id_in_group]); + } + + if (thread_id_in_group < 2) { + primitives[thread_id_in_group].color = float3(0x9b / 255.0, 0x61 / 255.0, 0x56 / 255.0); + primitives[thread_id_in_group].normal = float3(0.0, 1.0, 0.0); + } + + indices[0] = uint3(0, 1, 2); + indices[1] = uint3(2, 3, 0); +} + +struct Fragment { + float4 color : SV_Target0; +} + +[shader("fragment")] +Fragment fragment(PrimitiveAttributes primitive, VertexAttributes vertex) { + let n_dot_l = max(dot(primitive.normal, float3(0.0, 1.0, 0.0)), 0.1); + + Fragment output; + output.color = float4(primitive.color * n_dot_l, 1.0); + return output; +} diff --git a/title/shark-shaders/src/pipelines.rs b/title/shark-shaders/src/pipelines.rs index 0ae7369..ff16084 100644 --- a/title/shark-shaders/src/pipelines.rs +++ b/title/shark-shaders/src/pipelines.rs @@ -5,7 +5,7 @@ use narcissus_gpu::{ ComputePipelineDesc, CullingMode, FrontFace, Gpu, GraphicsPipelineAttachments, GraphicsPipelineDesc, ImageFormat, Pipeline, PipelineLayout, PolygonMode, PushConstantRange, Sampler, SamplerAddressMode, SamplerDesc, SamplerFilter, ShaderDesc, ShaderStageFlags, - SpecConstant, Topology, + SpecConstant, Topology, VertexOrMeshShader, }; use narcissus_maths::{Mat4, Vec2}; @@ -174,6 +174,11 @@ pub struct BasicConstants<'a> { pub transform_buffer_address: BufferAddress<'a>, } +#[repr(C)] +pub struct BlockConstants { + pub clip_from_model: Mat4, +} + #[repr(C)] pub struct Draw2dClearConstants<'a> { pub tile_resolution_x: u32, @@ -280,6 +285,7 @@ pub struct Pipelines { pub compute_bind_group_layout: BindGroupLayout, pub basic_pipeline: Pipeline, + pub block_pipeline: Pipeline, pub draw_2d_bin_0_clear_pipeline: Pipeline, pub draw_2d_bin_1_scatter_pipeline_workgroup_size: u32, @@ -326,11 +332,11 @@ impl Pipelines { gpu.debug_name_bind_group_layout(compute_bind_group_layout, "compute"); let basic_pipeline = gpu.create_graphics_pipeline(&GraphicsPipelineDesc { - vertex_shader: ShaderDesc { + vertex_or_mesh_shader: VertexOrMeshShader::Vertex(ShaderDesc { code: crate::BASIC_SPV, entry: c"vertex", ..default() - }, + }), fragment_shader: ShaderDesc { code: crate::BASIC_SPV, entry: c"fragment", @@ -366,6 +372,47 @@ impl Pipelines { gpu.debug_name_pipeline(basic_pipeline, "basic"); + let block_pipeline = gpu.create_graphics_pipeline(&GraphicsPipelineDesc { + vertex_or_mesh_shader: VertexOrMeshShader::Mesh(ShaderDesc { + code: crate::BLOCK_SPV, + entry: c"mesh", + ..default() + }), + fragment_shader: ShaderDesc { + code: crate::BLOCK_SPV, + entry: c"fragment", + ..default() + }, + layout: PipelineLayout { + bind_group_layouts: &[graphics_bind_group_layout], + push_constant_ranges: &[PushConstantRange { + stage_flags: ShaderStageFlags::MESH, + offset: 0, + size: std::mem::size_of::() as u32, + }], + }, + attachments: GraphicsPipelineAttachments { + color_attachment_formats: &[ImageFormat::RGBA16_FLOAT], + depth_attachment_format: Some(ImageFormat::DEPTH_F32), + stencil_attachment_format: None, + }, + topology: Topology::Triangles, + primitive_restart: false, + polygon_mode: PolygonMode::Fill, + culling_mode: CullingMode::Back, + front_face: FrontFace::CounterClockwise, + blend_mode: BlendMode::Opaque, + depth_bias: None, + depth_compare_op: CompareOp::GreaterOrEqual, + depth_test_enable: true, + depth_write_enable: true, + stencil_test_enable: false, + stencil_back: default(), + stencil_front: default(), + }); + + gpu.debug_name_pipeline(block_pipeline, "block"); + let create_compute_pipeline_with_entry = |code, entry, name, workgroup_size, require_full_subgroups, push_constant_size| { let push_constant_range = PushConstantRange { @@ -503,6 +550,7 @@ impl Pipelines { compute_bind_group_layout, basic_pipeline, + block_pipeline, draw_2d_bin_0_clear_pipeline, draw_2d_bin_1_scatter_pipeline_workgroup_size, diff --git a/title/shark/src/draw.rs b/title/shark/src/draw.rs index dad79a2..bca0e41 100644 --- a/title/shark/src/draw.rs +++ b/title/shark/src/draw.rs @@ -6,10 +6,10 @@ use crate::{UiState, microshades}; use narcissus_core::dds; use shark_shaders::pipelines::{ - BasicConstants, CompositeConstants, ComputeBinds, DRAW_2D_TILE_SIZE, Draw2dClearConstants, - Draw2dRasterizeConstants, Draw2dResolveConstants, Draw2dScatterConstants, Draw2dSortConstants, - GraphicsBinds, Pipelines, RadixSortDownsweepConstants, RadixSortUpsweepConstants, - calculate_spine_size, + BasicConstants, BlockConstants, CompositeConstants, ComputeBinds, DRAW_2D_TILE_SIZE, + Draw2dClearConstants, Draw2dRasterizeConstants, Draw2dResolveConstants, Draw2dScatterConstants, + Draw2dSortConstants, GraphicsBinds, Pipelines, RadixSortDownsweepConstants, + RadixSortUpsweepConstants, calculate_spine_size, }; use crate::helpers::load_obj; @@ -684,6 +684,17 @@ impl<'gpu> DrawState<'gpu> { }], ); + // Render blocks. + gpu.cmd_set_pipeline(cmd_encoder, self.pipelines.block_pipeline); + gpu.cmd_set_bind_group(cmd_encoder, 0, &graphics_bind_group); + gpu.cmd_push_constants_with_data( + cmd_encoder, + ShaderStageFlags::MESH, + 0, + &BlockConstants { clip_from_model }, + ); + gpu.cmd_draw_mesh_tasks(cmd_encoder, 1, 1, 1); + gpu.cmd_set_pipeline(cmd_encoder, self.pipelines.basic_pipeline); gpu.cmd_set_bind_group(cmd_encoder, 0, &graphics_bind_group); gpu.cmd_push_constants_with_data(