From: Josh Simmons Date: Sat, 18 May 2024 17:08:02 +0000 (+0200) Subject: shark: Split UI from display transform X-Git-Url: https://git.nega.tv//gitweb.cgi?a=commitdiff_plain;h=912071707d680bbc7c7ca7727ee5d3934040dd7f;p=josh%2Fnarcissus shark: Split UI from display transform --- diff --git a/title/shark-shaders/build.rs b/title/shark-shaders/build.rs index 6f1947f..8ed767f 100644 --- a/title/shark-shaders/build.rs +++ b/title/shark-shaders/build.rs @@ -9,7 +9,7 @@ struct Shader { name: &'static str, } -const SHADERS: [Shader; 3] = [ +const SHADERS: &[Shader] = &[ Shader { stage: "vert", name: "basic", @@ -18,6 +18,10 @@ const SHADERS: [Shader; 3] = [ stage: "frag", name: "basic", }, + Shader { + stage: "comp", + name: "primitive_2d_tiled", + }, Shader { stage: "comp", name: "display_transform", @@ -31,17 +35,20 @@ fn main() { _ => "0", }; - let commands = SHADERS.map(|Shader { stage, name }| { - Command::new("glslangValidator") - .args(["--target-env", "vulkan1.3"]) - .arg("--quiet") - .arg(&format!("-g{debug}")) - .args(["--depfile", &format!("{out_dir}/{name}.{stage}.d")]) - .args(["-o", &format!("{out_dir}/{name}.{stage}.spv")]) - .arg(&format!("{SHADER_ROOT}/{name}.{stage}.glsl")) - .spawn() - .unwrap() - }); + let commands = SHADERS + .iter() + .map(|Shader { stage, name }| { + Command::new("glslangValidator") + .args(["--target-env", "vulkan1.3"]) + .arg("--quiet") + .arg(&format!("-g{debug}")) + .args(["--depfile", &format!("{out_dir}/{name}.{stage}.d")]) + .args(["-o", &format!("{out_dir}/{name}.{stage}.spv")]) + .arg(&format!("{SHADER_ROOT}/{name}.{stage}.glsl")) + .spawn() + .unwrap() + }) + .collect::>(); let dst_path = std::path::Path::new(&out_dir).join("shaders.rs"); let mut file = std::fs::File::create(dst_path).unwrap(); diff --git a/title/shark-shaders/shaders/display_transform.comp.glsl b/title/shark-shaders/shaders/display_transform.comp.glsl index bbefb7a..7b5e9a8 100644 --- a/title/shark-shaders/shaders/display_transform.comp.glsl +++ b/title/shark-shaders/shaders/display_transform.comp.glsl @@ -1,35 +1,13 @@ #version 460 -#extension GL_GOOGLE_include_directive : require +layout (set = 0, binding = 0) uniform sampler bilinear_sampler; -#extension GL_EXT_scalar_block_layout : require -#extension GL_EXT_control_flow_attributes : require +layout (set = 0, binding = 1) uniform texture3D tony_mc_mapface_lut; -#include "primitive_types.h" +layout (set = 0, binding = 2, rgba16f) uniform readonly image2D layer_rt; +layout (set = 0, binding = 3, rgba16f) uniform readonly image2D layer_ui; -layout(std430, set = 0, binding = 0) uniform uniformBuffer { - uint screen_width; - uint screen_height; - uint atlas_width; - uint atlas_height; - uint num_primitives; -}; - -layout (set = 0, binding = 1) uniform sampler bilinear_sampler; - -layout (set = 0, binding = 2, rgba16f) uniform readonly image2D render_target; -layout (set = 0, binding = 3, rgba16f) uniform writeonly image2D swapchain_image; - -layout (set = 0, binding = 4) uniform texture2D glyph_atlas; -layout (set = 0, binding = 5) uniform texture3D tony_mc_mapface_lut; - -layout(std430, set = 0, binding = 6) readonly buffer glyphBuffer { - CachedGlyph cached_glyphs[]; -}; - -layout(std430, set = 0, binding = 7) readonly buffer glyphInstanceBuffer { - GlyphInstance glyph_instances[]; -}; +layout (set = 0, binding = 4, rgba16f) uniform writeonly image2D composited_output; float srgb_oetf(float a) { return (.0031308f >= a) ? 12.92f * a : 1.055f * pow(a, .4166666666666667f) - .055f; @@ -49,31 +27,10 @@ vec3 tony_mc_mapface(vec3 stimulus) { layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; void main() { - vec4 accum = vec4(0.0); - - for (int i = 0; i < num_primitives; i++) { - const GlyphInstance gi = glyph_instances[i]; - const CachedGlyph cg = cached_glyphs[gi.index]; - const vec4 color = unpackUnorm4x8(gi.color).bgra; - const vec2 glyph_top_left = vec2(gi.x + cg.offset_x0, gi.y + cg.offset_y0); - const vec2 glyph_bottom_right = vec2(gi.x + cg.offset_x1, gi.y + cg.offset_y1); - const vec2 glyph_size = vec2(cg.offset_x1 - cg.offset_x0, cg.offset_y1 - cg.offset_y0); - const vec2 sample_center = gl_GlobalInvocationID.xy; // half pixel offset goes here? - if (sample_center.x >= glyph_top_left.x && - sample_center.x <= glyph_bottom_right.x && - sample_center.y >= glyph_top_left.y && - sample_center.y <= glyph_bottom_right.y) { - const vec2 uv = mix(vec2(cg.x0, cg.y0), vec2(cg.x1, cg.y1), (sample_center - glyph_top_left) / glyph_size) / vec2(atlas_width, atlas_height); - const float coverage = textureLod(sampler2D(glyph_atlas, bilinear_sampler), uv, 0.0).r; - accum = coverage * color; - accum.a = coverage; - break; - } - } - - const vec3 stimulus = imageLoad(render_target, ivec2(gl_GlobalInvocationID.xy)).rgb; + const vec3 stimulus = imageLoad(layer_rt, ivec2(gl_GlobalInvocationID.xy)).rgb; const vec3 transformed = tony_mc_mapface(stimulus); const vec3 srgb = srgb_oetf(transformed); - const vec3 composited = accum.rgb + (srgb * (1.0 - accum.a)); - imageStore(swapchain_image, ivec2(gl_GlobalInvocationID.xy), vec4(composited, 1.0)); + const vec4 ui = imageLoad(layer_ui, ivec2(gl_GlobalInvocationID.xy)).rgba; + const vec3 composited = ui.rgb + (srgb * (1.0 - ui.a)); + imageStore(composited_output, ivec2(gl_GlobalInvocationID.xy), vec4(composited, 1.0)); } diff --git a/title/shark-shaders/shaders/primitive_2d_tiled.comp.glsl b/title/shark-shaders/shaders/primitive_2d_tiled.comp.glsl new file mode 100644 index 0000000..4903ea5 --- /dev/null +++ b/title/shark-shaders/shaders/primitive_2d_tiled.comp.glsl @@ -0,0 +1,65 @@ +#version 460 + +#extension GL_GOOGLE_include_directive : require + +#extension GL_EXT_scalar_block_layout : require +#extension GL_EXT_control_flow_attributes : require + +#include "primitive_2d_types.h" + +layout(std430, set = 0, binding = 0) uniform uniformBuffer { + uint screen_width; + uint screen_height; + uint atlas_width; + uint atlas_height; + uint num_primitives; +}; + +layout (set = 0, binding = 1) uniform sampler bilinear_sampler; +layout (set = 0, binding = 2) uniform texture2D glyph_atlas; + +layout(std430, set = 0, binding = 3) readonly buffer glyphBuffer { + Glyph glyphs[]; +}; + +layout(std430, set = 0, binding = 4) readonly buffer glyphInstanceBuffer { + GlyphInstance glyph_instances[]; +}; + +layout(std430, set = 0, binding = 5) readonly buffer primitiveInstanceBuffer { + PrimitiveInstance primitive_instances[]; +}; + +layout(std430, set = 0, binding = 6) readonly buffer tileBuffer { + Tile tiles[]; +}; + +layout (set = 0, binding = 7, rgba16f) uniform writeonly image2D ui_image; + +layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main() { + vec4 accum = vec4(0.0); + + for (int i = 0; i < num_primitives; i++) { + const GlyphInstance gi = glyph_instances[i]; + const Glyph gl = glyphs[gi.index]; + const vec4 color = unpackUnorm4x8(gi.color).bgra; + const vec2 glyph_top_left = vec2(gi.x + gl.offset_x0, gi.y + gl.offset_y0); + const vec2 glyph_bottom_right = vec2(gi.x + gl.offset_x1, gi.y + gl.offset_y1); + const vec2 glyph_size = vec2(gl.offset_x1 - gl.offset_x0, gl.offset_y1 - gl.offset_y0); + const vec2 sample_center = gl_GlobalInvocationID.xy; // half pixel offset goes here? + if (sample_center.x >= glyph_top_left.x && + sample_center.x <= glyph_bottom_right.x && + sample_center.y >= glyph_top_left.y && + sample_center.y <= glyph_bottom_right.y) { + const vec2 uv = mix(vec2(gl.x0, gl.y0), vec2(gl.x1, gl.y1), (sample_center - glyph_top_left) / glyph_size) / vec2(atlas_width, atlas_height); + const float coverage = textureLod(sampler2D(glyph_atlas, bilinear_sampler), uv, 0.0).r; + accum = coverage * color; + accum.a = coverage; + break; + } + } + + imageStore(ui_image, ivec2(gl_GlobalInvocationID.xy), accum); +} diff --git a/title/shark-shaders/shaders/primitive_types.h b/title/shark-shaders/shaders/primitive_2d_types.h similarity index 64% rename from title/shark-shaders/shaders/primitive_types.h rename to title/shark-shaders/shaders/primitive_2d_types.h index 3b746bd..fd661a1 100644 --- a/title/shark-shaders/shaders/primitive_types.h +++ b/title/shark-shaders/shaders/primitive_2d_types.h @@ -1,5 +1,5 @@ -struct CachedGlyph { +struct Glyph { uint x0; uint x1; uint y0; @@ -17,3 +17,13 @@ struct GlyphInstance { uint index; uint color; }; + +struct PrimitiveInstance { + uint type; + uint index; +}; + +struct Tile { + uint index; + uint count; +}; diff --git a/title/shark/src/main.rs b/title/shark/src/main.rs index 39532b3..341fa2c 100644 --- a/title/shark/src/main.rs +++ b/title/shark/src/main.rs @@ -24,10 +24,12 @@ use narcissus_image as image; use narcissus_maths::{ clamp, perlin_noise3, sin_pi_f32, vec3, Affine3, Deg, HalfTurn, Mat3, Mat4, Point3, Vec3, }; -use pipelines::{BasicPipeline, BasicUniforms, DisplayTransformPipeline, PrimitiveInstance}; +use pipelines::{ + BasicPipeline, BasicUniforms, DisplayTransformPipeline, GlyphInstance, Primitive2dPipeline, +}; use spring::simple_spring_damper_exact; -use crate::pipelines::DisplayTransformUniforms; +use crate::pipelines::PrimitiveUniforms; mod fonts; mod helpers; @@ -448,7 +450,7 @@ struct UiState<'a> { tmp_string: String, - primitive_instances: Vec, + primitive_instances: Vec, } impl<'a> UiState<'a> { @@ -504,7 +506,7 @@ impl<'a> UiState<'a> { x += advance * scale; - self.primitive_instances.push(PrimitiveInstance { + self.primitive_instances.push(GlyphInstance { x, y, touched_glyph_index, @@ -840,13 +842,15 @@ struct DrawState<'gpu> { gpu: &'gpu Gpu, basic_pipeline: BasicPipeline, + primitive_2d_pipeline: Primitive2dPipeline, display_transform_pipeline: DisplayTransformPipeline, width: u32, height: u32, depth_image: Image, - render_target_image: Image, + rt_image: Image, + ui_image: Image, glyph_atlas_image: Image, @@ -860,6 +864,7 @@ struct DrawState<'gpu> { impl<'gpu> DrawState<'gpu> { fn new(gpu: &'gpu Gpu, thread_token: &ThreadToken) -> Self { let basic_pipeline = BasicPipeline::new(gpu); + let primitive_2d_pipeline = Primitive2dPipeline::new(gpu); let display_transform_pipeline = DisplayTransformPipeline::new(gpu); let samplers = Samplers::load(gpu); @@ -869,11 +874,13 @@ impl<'gpu> DrawState<'gpu> { Self { gpu, basic_pipeline, + primitive_2d_pipeline, display_transform_pipeline, width: 0, height: 0, depth_image: default(), - render_target_image: default(), + rt_image: default(), + ui_image: default(), glyph_atlas_image: default(), samplers, models, @@ -981,7 +988,8 @@ impl<'gpu> DrawState<'gpu> { if width != self.width || height != self.height { gpu.destroy_image(frame, self.depth_image); - gpu.destroy_image(frame, self.render_target_image); + gpu.destroy_image(frame, self.rt_image); + gpu.destroy_image(frame, self.ui_image); self.depth_image = gpu.create_image(&ImageDesc { memory_location: MemoryLocation::Device, @@ -997,7 +1005,7 @@ impl<'gpu> DrawState<'gpu> { mip_levels: 1, }); - self.render_target_image = gpu.create_image(&ImageDesc { + self.rt_image = gpu.create_image(&ImageDesc { memory_location: MemoryLocation::Device, host_mapped: false, usage: ImageUsageFlags::COLOR_ATTACHMENT | ImageUsageFlags::STORAGE, @@ -1011,6 +1019,20 @@ impl<'gpu> DrawState<'gpu> { mip_levels: 1, }); + self.ui_image = gpu.create_image(&ImageDesc { + memory_location: MemoryLocation::Device, + host_mapped: false, + usage: ImageUsageFlags::STORAGE, + dimension: ImageDimension::Type2d, + format: ImageFormat::RGBA16_FLOAT, + tiling: ImageTiling::Optimal, + width, + height, + depth: 1, + layer_count: 1, + mip_levels: 1, + }); + gpu.cmd_barrier( cmd_encoder, None, @@ -1078,12 +1100,22 @@ impl<'gpu> DrawState<'gpu> { gpu.cmd_barrier( cmd_encoder, None, - &[ImageBarrier::layout_optimal( - &[Access::None], - &[Access::ColorAttachmentWrite], - self.render_target_image, - ImageAspectFlags::COLOR, - )], + &[ + ImageBarrier::layout_optimal( + &[Access::None], + &[Access::ColorAttachmentWrite], + self.rt_image, + ImageAspectFlags::COLOR, + ), + ImageBarrier { + prev_access: &[Access::None], + next_access: &[Access::ShaderWrite], + prev_layout: ImageLayout::Optimal, + next_layout: ImageLayout::General, + image: self.ui_image, + subresource_range: default(), + }, + ], ); gpu.cmd_begin_rendering( @@ -1094,7 +1126,7 @@ impl<'gpu> DrawState<'gpu> { width, height, color_attachments: &[RenderingAttachment { - image: self.render_target_image, + image: self.rt_image, load_op: LoadOp::Clear(ClearValue::ColorF32([1.0, 1.0, 1.0, 1.0])), store_op: StoreOp::Store, }], @@ -1220,109 +1252,184 @@ impl<'gpu> DrawState<'gpu> { gpu.cmd_end_rendering(cmd_encoder); - gpu.cmd_barrier( - cmd_encoder, - None, - &[ImageBarrier { - prev_access: &[Access::ColorAttachmentWrite], - prev_layout: ImageLayout::Optimal, - next_access: &[Access::ShaderOtherRead], - next_layout: ImageLayout::General, - image: self.render_target_image, - subresource_range: ImageSubresourceRange::default(), - }], - ); + // Render UI + { + gpu.cmd_set_pipeline(cmd_encoder, self.primitive_2d_pipeline.pipeline); - gpu.cmd_compute_touch_swapchain(cmd_encoder, swapchain_image); + let uniforms_buffer = gpu.request_transient_buffer_with_data( + frame, + thread_token, + BufferUsageFlags::UNIFORM, + &PrimitiveUniforms { + screen_width: width, + screen_height: height, + atlas_width, + atlas_height, + num_primitives: ui_state.primitive_instances.len() as u32, + }, + ); + let glyph_buffer = gpu.request_transient_buffer_with_data( + frame, + thread_token, + BufferUsageFlags::STORAGE, + touched_glyphs, + ); + let glyph_instance_buffer = gpu.request_transient_buffer_with_data( + frame, + thread_token, + BufferUsageFlags::STORAGE, + ui_state.primitive_instances.as_slice(), + ); + let primitive_instance_buffer = gpu.request_transient_buffer_with_data( + frame, + thread_token, + BufferUsageFlags::STORAGE, + &[0u32], + ); + let tile_buffer = gpu.request_transient_buffer_with_data( + frame, + thread_token, + BufferUsageFlags::STORAGE, + &[0u32], + ); - gpu.cmd_set_pipeline(cmd_encoder, self.display_transform_pipeline.pipeline); + ui_state.primitive_instances.clear(); - let uniforms_buffer = gpu.request_transient_buffer_with_data( - frame, - thread_token, - BufferUsageFlags::UNIFORM, - &DisplayTransformUniforms { - screen_width: width, - screen_height: height, - atlas_width, - atlas_height, - num_primitives: ui_state.primitive_instances.len() as u32, - }, - ); - let cached_glyphs_buffer = gpu.request_transient_buffer_with_data( - frame, - thread_token, - BufferUsageFlags::STORAGE, - touched_glyphs, - ); - let glyph_instance_buffer = gpu.request_transient_buffer_with_data( - frame, - thread_token, - BufferUsageFlags::STORAGE, - ui_state.primitive_instances.as_slice(), - ); + gpu.cmd_set_bind_group( + frame, + cmd_encoder, + self.primitive_2d_pipeline.bind_group_layout, + 0, + &[ + Bind { + binding: 0, + array_element: 0, + typed: TypedBind::UniformBuffer(&[uniforms_buffer.to_arg()]), + }, + Bind { + binding: 1, + array_element: 0, + typed: TypedBind::Sampler(&[self.samplers[SamplerRes::Bilinear]]), + }, + Bind { + binding: 2, + array_element: 0, + typed: TypedBind::SampledImage(&[( + ImageLayout::Optimal, + self.glyph_atlas_image, + )]), + }, + Bind { + binding: 3, + array_element: 0, + typed: TypedBind::StorageBuffer(&[glyph_buffer.to_arg()]), + }, + Bind { + binding: 4, + array_element: 0, + typed: TypedBind::StorageBuffer(&[glyph_instance_buffer.to_arg()]), + }, + Bind { + binding: 5, + array_element: 0, + typed: TypedBind::StorageBuffer(&[primitive_instance_buffer.to_arg()]), + }, + Bind { + binding: 6, + array_element: 0, + typed: TypedBind::StorageBuffer(&[tile_buffer.to_arg()]), + }, + Bind { + binding: 7, + array_element: 0, + typed: TypedBind::StorageImage(&[( + ImageLayout::General, + self.ui_image, + )]), + }, + ], + ); - ui_state.primitive_instances.clear(); + gpu.cmd_dispatch(cmd_encoder, (self.width + 7) / 8, (self.height + 7) / 8, 1); + } - gpu.cmd_set_bind_group( - frame, - cmd_encoder, - self.display_transform_pipeline.bind_group_layout, - 0, - &[ - Bind { - binding: 0, - array_element: 0, - typed: TypedBind::UniformBuffer(&[uniforms_buffer.to_arg()]), - }, - Bind { - binding: 1, - array_element: 0, - typed: TypedBind::Sampler(&[self.samplers[SamplerRes::Bilinear]]), - }, - Bind { - binding: 2, - array_element: 0, - typed: TypedBind::StorageImage(&[( - ImageLayout::General, - self.render_target_image, - )]), - }, - Bind { - binding: 3, - array_element: 0, - typed: TypedBind::StorageImage(&[(ImageLayout::General, swapchain_image)]), - }, - Bind { - binding: 4, - array_element: 0, - typed: TypedBind::SampledImage(&[( - ImageLayout::Optimal, - self.glyph_atlas_image, - )]), - }, - Bind { - binding: 5, - array_element: 0, - typed: TypedBind::SampledImage(&[( - ImageLayout::Optimal, - self.images[ImageRes::TonyMcMapfaceLut], - )]), - }, - Bind { - binding: 6, - array_element: 0, - typed: TypedBind::StorageBuffer(&[cached_glyphs_buffer.to_arg()]), - }, - Bind { - binding: 7, - array_element: 0, - typed: TypedBind::StorageBuffer(&[glyph_instance_buffer.to_arg()]), - }, - ], - ); + // Display transform and composite + { + gpu.cmd_barrier( + cmd_encoder, + None, + &[ + ImageBarrier { + prev_access: &[Access::ColorAttachmentWrite], + prev_layout: ImageLayout::Optimal, + next_access: &[Access::ShaderOtherRead], + next_layout: ImageLayout::General, + image: self.rt_image, + subresource_range: ImageSubresourceRange::default(), + }, + ImageBarrier { + prev_access: &[Access::ShaderWrite], + prev_layout: ImageLayout::General, + next_access: &[Access::ShaderOtherRead], + next_layout: ImageLayout::General, + image: self.ui_image, + subresource_range: ImageSubresourceRange::default(), + }, + ], + ); + + gpu.cmd_compute_touch_swapchain(cmd_encoder, swapchain_image); + + gpu.cmd_set_pipeline(cmd_encoder, self.display_transform_pipeline.pipeline); + + gpu.cmd_set_bind_group( + frame, + cmd_encoder, + self.display_transform_pipeline.bind_group_layout, + 0, + &[ + Bind { + binding: 0, + array_element: 0, + typed: TypedBind::Sampler(&[self.samplers[SamplerRes::Bilinear]]), + }, + Bind { + binding: 1, + array_element: 0, + typed: TypedBind::SampledImage(&[( + ImageLayout::Optimal, + self.images[ImageRes::TonyMcMapfaceLut], + )]), + }, + Bind { + binding: 2, + array_element: 0, + typed: TypedBind::StorageImage(&[( + ImageLayout::General, + self.rt_image, + )]), + }, + Bind { + binding: 3, + array_element: 0, + typed: TypedBind::StorageImage(&[( + ImageLayout::General, + self.ui_image, + )]), + }, + Bind { + binding: 4, + array_element: 0, + typed: TypedBind::StorageImage(&[( + ImageLayout::General, + swapchain_image, + )]), + }, + ], + ); - gpu.cmd_dispatch(cmd_encoder, (self.width + 7) / 8, (self.height + 7) / 8, 1); + gpu.cmd_dispatch(cmd_encoder, (self.width + 7) / 8, (self.height + 7) / 8, 1); + } } gpu.submit(frame, cmd_encoder); } diff --git a/title/shark/src/pipelines/display_transform.rs b/title/shark/src/pipelines/display_transform.rs index 6c6bc2d..09f34e3 100644 --- a/title/shark/src/pipelines/display_transform.rs +++ b/title/shark/src/pipelines/display_transform.rs @@ -1,4 +1,3 @@ -use narcissus_font::TouchedGlyphIndex; use narcissus_gpu::{ BindDesc, BindGroupLayout, BindingType, ComputePipelineDesc, Pipeline, ShaderDesc, ShaderStageFlags, @@ -6,25 +5,6 @@ use narcissus_gpu::{ use crate::Gpu; -#[allow(unused)] -#[repr(C)] -pub struct DisplayTransformUniforms { - pub screen_width: u32, - pub screen_height: u32, - pub atlas_width: u32, - pub atlas_height: u32, - pub num_primitives: u32, -} - -#[allow(unused)] -#[repr(C)] -pub struct PrimitiveInstance { - pub x: f32, - pub y: f32, - pub touched_glyph_index: TouchedGlyphIndex, - pub color: u32, -} - pub struct DisplayTransformPipeline { pub bind_group_layout: BindGroupLayout, pub pipeline: Pipeline, @@ -33,22 +13,16 @@ pub struct DisplayTransformPipeline { impl DisplayTransformPipeline { pub fn new(gpu: &Gpu) -> Self { let bind_group_layout = gpu.create_bind_group_layout(&[ - // Uniforms - BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::UniformBuffer), // Sampler BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::Sampler), - // RT - BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageImage), - // Swapchain - BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageImage), - // Glyph Atlas - BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::SampledImage), // Tony Mc'mapface LUT BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::SampledImage), - // Glyphs - BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageBuffer), - // Glyph Instances - BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageBuffer), + // Layer RT + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageImage), + // Layer UI + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageImage), + // Composited Output + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageImage), ]); let pipeline = gpu.create_compute_pipeline(&ComputePipelineDesc { diff --git a/title/shark/src/pipelines/mod.rs b/title/shark/src/pipelines/mod.rs index 1e5732a..d6b57ec 100644 --- a/title/shark/src/pipelines/mod.rs +++ b/title/shark/src/pipelines/mod.rs @@ -1,8 +1,7 @@ mod basic; mod display_transform; +mod primitive_2d; pub use basic::{BasicPipeline, BasicUniforms, Vertex}; - -pub use display_transform::{ - DisplayTransformPipeline, DisplayTransformUniforms, PrimitiveInstance, -}; +pub use display_transform::DisplayTransformPipeline; +pub use primitive_2d::{GlyphInstance, Primitive2dPipeline, PrimitiveUniforms}; diff --git a/title/shark/src/pipelines/primitive_2d.rs b/title/shark/src/pipelines/primitive_2d.rs new file mode 100644 index 0000000..51f9841 --- /dev/null +++ b/title/shark/src/pipelines/primitive_2d.rs @@ -0,0 +1,67 @@ +use narcissus_font::TouchedGlyphIndex; +use narcissus_gpu::{ + BindDesc, BindGroupLayout, BindingType, ComputePipelineDesc, Pipeline, ShaderDesc, + ShaderStageFlags, +}; + +use crate::Gpu; + +#[allow(unused)] +#[repr(C)] +pub struct PrimitiveUniforms { + pub screen_width: u32, + pub screen_height: u32, + pub atlas_width: u32, + pub atlas_height: u32, + pub num_primitives: u32, +} + +#[allow(unused)] +#[repr(C)] +pub struct GlyphInstance { + pub x: f32, + pub y: f32, + pub touched_glyph_index: TouchedGlyphIndex, + pub color: u32, +} + +pub struct Primitive2dPipeline { + pub bind_group_layout: BindGroupLayout, + pub pipeline: Pipeline, +} + +impl Primitive2dPipeline { + pub fn new(gpu: &Gpu) -> Self { + let bind_group_layout = gpu.create_bind_group_layout(&[ + // Uniforms + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::UniformBuffer), + // Sampler + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::Sampler), + // Glyph Atlas + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::SampledImage), + // Glyphs + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageBuffer), + // Glyph Instances + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageBuffer), + // Primitive Instances + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageBuffer), + // Tiles + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageBuffer), + // UI + BindDesc::new(ShaderStageFlags::COMPUTE, BindingType::StorageImage), + ]); + + let pipeline = gpu.create_compute_pipeline(&ComputePipelineDesc { + shader: ShaderDesc { + entry: c"main", + code: shark_shaders::PRIMITIVE_2D_TILED_COMP_SPV, + }, + bind_group_layouts: &[bind_group_layout], + }); + + Self { + bind_group_layout, + pipeline, + } + } +}