]> git.nega.tv - josh/narcissus/commitdiff
shark: Split UI from display transform
authorJosh Simmons <josh@nega.tv>
Sat, 18 May 2024 17:08:02 +0000 (19:08 +0200)
committerJosh Simmons <josh@nega.tv>
Sat, 18 May 2024 17:08:02 +0000 (19:08 +0200)
title/shark-shaders/build.rs
title/shark-shaders/shaders/display_transform.comp.glsl
title/shark-shaders/shaders/primitive_2d_tiled.comp.glsl [new file with mode: 0644]
title/shark-shaders/shaders/primitive_2d_types.h [moved from title/shark-shaders/shaders/primitive_types.h with 64% similarity]
title/shark/src/main.rs
title/shark/src/pipelines/display_transform.rs
title/shark/src/pipelines/mod.rs
title/shark/src/pipelines/primitive_2d.rs [new file with mode: 0644]

index 6f1947fce466056e13583b675fb67912ab5d2420..8ed767ff0e61327f444bb1b432f8835f7a386f9e 100644 (file)
@@ -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::<Vec<_>>();
 
     let dst_path = std::path::Path::new(&out_dir).join("shaders.rs");
     let mut file = std::fs::File::create(dst_path).unwrap();
index bbefb7af11aa907e86258ee9ea5a821eb3419f29..7b5e9a80bac0b1d73bee158b103bb3d8a7c99e53 100644 (file)
@@ -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 (file)
index 0000000..4903ea5
--- /dev/null
@@ -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);
+}
similarity index 64%
rename from title/shark-shaders/shaders/primitive_types.h
rename to title/shark-shaders/shaders/primitive_2d_types.h
index 3b746bd95c2d040d5e7bde1a64f1635327088eaf..fd661a115803bab535f2563eec7fc37531ef7ba2 100644 (file)
@@ -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;
+};
index 39532b36f85187efef5ba230344c2724221f3711..341fa2cc68a4c51a94fd050a0bc26e52b85dac30 100644 (file)
@@ -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<PrimitiveInstance>,
+    primitive_instances: Vec<GlyphInstance>,
 }
 
 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);
     }
index 6c6bc2d0a03a2896a370e036082a20ece28a7808..09f34e3e86b8aa746799a869aee1f9ba554f0abe 100644 (file)
@@ -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 {
index 1e5732a60e398286be614d32d4d3452e109f3522..d6b57ecd68c0565a20a31678e3a1a2981028a2bf 100644 (file)
@@ -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 (file)
index 0000000..51f9841
--- /dev/null
@@ -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,
+        }
+    }
+}