From 252409d450bfa2e01e3c2fd645a2362270616f17 Mon Sep 17 00:00:00 2001 From: Josh Simmons Date: Thu, 22 Aug 2024 19:40:47 +0200 Subject: [PATCH] shark: Add support for ui rects --- .../shark-shaders/shaders/compute_bindings.h | 28 ++++---- .../shaders/display_transform.comp.glsl | 1 - title/shark-shaders/shaders/primitive_2d.h | 34 ++++++++-- .../shaders/primitive_2d_bin.comp.glsl | 32 ++++++++-- .../shaders/primitive_2d_bin_clear.comp.glsl | 1 - .../shaders/primitive_2d_rasterize.comp.glsl | 44 +++++++++---- title/shark/src/main.rs | 64 ++++++++++++++++--- title/shark/src/pipelines/mod.rs | 47 ++++++++++++-- 8 files changed, 193 insertions(+), 58 deletions(-) diff --git a/title/shark-shaders/shaders/compute_bindings.h b/title/shark-shaders/shaders/compute_bindings.h index 88498ed..bbf7cf6 100644 --- a/title/shark-shaders/shaders/compute_bindings.h +++ b/title/shark-shaders/shaders/compute_bindings.h @@ -1,16 +1,16 @@ +#ifndef COMPUTE_BINDINGS_INCLUDE +#define COMPUTE_BINDINGS_INCLUDE -struct Glyph { - ivec2 atlas_min; - ivec2 atlas_max; +#include "primitive_2d.h" - vec2 offset_min; - vec2 offset_max; +layout(buffer_reference, std430, buffer_reference_align = 16) readonly buffer PrimitiveInstances +{ + PrimitiveInstance values[]; }; -struct GlyphInstance { - vec2 position; - uint index; - uint color; +layout(buffer_reference, std430, buffer_reference_align = 16) readonly buffer Rects +{ + Rect values[]; }; layout(buffer_reference, std430, buffer_reference_align = 16) readonly buffer Glyphs @@ -18,11 +18,6 @@ layout(buffer_reference, std430, buffer_reference_align = 16) readonly buffer Gl Glyph values[]; }; -layout(buffer_reference, std430, buffer_reference_align = 16) readonly buffer GlyphInstances -{ - GlyphInstance values[]; -}; - layout(buffer_reference, std430, buffer_reference_align = 4) readonly buffer TilesRead { uint values[]; @@ -43,8 +38,9 @@ struct ComputeUniforms { uint num_primitives_1024; uint tile_stride; + PrimitiveInstances primitive_instances; + Rects rects; Glyphs glyphs; - GlyphInstances glyph_instances; TilesWrite tiles; }; @@ -59,3 +55,5 @@ layout (set = 0, binding = 3, rgba16f) uniform writeonly image2D ui_layer_write; layout (set = 0, binding = 3, rgba16f) uniform readonly image2D ui_layer_read; layout (set = 0, binding = 4, rgba16f) uniform readonly image2D color_layer; layout (set = 0, binding = 5, rgba16f) uniform writeonly image2D composited_output; + +#endif diff --git a/title/shark-shaders/shaders/display_transform.comp.glsl b/title/shark-shaders/shaders/display_transform.comp.glsl index 113d314..465f44a 100644 --- a/title/shark-shaders/shaders/display_transform.comp.glsl +++ b/title/shark-shaders/shaders/display_transform.comp.glsl @@ -7,7 +7,6 @@ #extension GL_EXT_scalar_block_layout : require #include "compute_bindings.h" -#include "primitive_2d.h" float srgb_oetf(float a) { return (.0031308f >= a) ? 12.92f * a : 1.055f * pow(a, .4166666666666667f) - .055f; diff --git a/title/shark-shaders/shaders/primitive_2d.h b/title/shark-shaders/shaders/primitive_2d.h index 010735d..ae6a2ec 100644 --- a/title/shark-shaders/shaders/primitive_2d.h +++ b/title/shark-shaders/shaders/primitive_2d.h @@ -1,3 +1,6 @@ +#ifndef PRIMITIVE_2D_INCLUDE +#define PRIMITIVE_2D_INCLUDE + const uint TILE_SIZE = 32; const uint MAX_PRIMS = 1 << 18; @@ -9,10 +12,27 @@ const uint TILE_BITMAP_RANGE_HI_OFFSET = (TILE_BITMAP_RANGE_LO_OFFSET + 1); const uint TILE_BITMAP_L1_OFFSET = (TILE_BITMAP_RANGE_HI_OFFSET + 1); const uint TILE_BITMAP_L0_OFFSET = (TILE_BITMAP_L1_OFFSET + TILE_BITMAP_L1_WORDS); -bool test_glyph(uint index, vec2 tile_min, vec2 tile_max) { - const GlyphInstance gi = uniforms.glyph_instances.values[index]; - const Glyph gl = uniforms.glyphs.values[gi.index]; - const vec2 glyph_min = gi.position + gl.offset_min; - const vec2 glyph_max = gi.position + gl.offset_max; - return !(any(lessThan(tile_max, glyph_min)) || any(greaterThan(tile_min, glyph_max))); -} +const uint PRIMITIVE_TYPE_RECT = 0; +const uint PRIMITIVE_TYPE_GLYPH = 1; + +struct PrimitiveInstance { + uint packed; + uint color; + vec2 position; +}; + +struct Rect { + vec2 half_extent; + float border_width; + float border_radius; +}; + +struct Glyph { + ivec2 atlas_min; + ivec2 atlas_max; + + vec2 offset_min; + vec2 offset_max; +}; + +#endif \ No newline at end of file diff --git a/title/shark-shaders/shaders/primitive_2d_bin.comp.glsl b/title/shark-shaders/shaders/primitive_2d_bin.comp.glsl index a826dae..6398615 100644 --- a/title/shark-shaders/shaders/primitive_2d_bin.comp.glsl +++ b/title/shark-shaders/shaders/primitive_2d_bin.comp.glsl @@ -12,7 +12,6 @@ #extension GL_KHR_shader_subgroup_vote : require #include "compute_bindings.h" -#include "primitive_2d.h" const uint SUBGROUP_SIZE = 64; const uint NUM_SUBGROUPS = 16; @@ -27,14 +26,34 @@ void main() { for (uint i = 0; i < NUM_PRIMITIVES_WG; i += gl_SubgroupSize.x) { const uint primitive_index = gl_WorkGroupID.x * NUM_PRIMITIVES_WG + i + gl_SubgroupInvocationID; + // Bounds for this primitive, any tiles which intersect this AABB will be written. vec2 primitive_min = vec2(99999.9); vec2 primitive_max = vec2(-99999.9); if (primitive_index < uniforms.num_primitives) { - const GlyphInstance gi = uniforms.glyph_instances.values[primitive_index]; - const Glyph gl = uniforms.glyphs.values[gi.index]; - primitive_min = gi.position + gl.offset_min; - primitive_max = gi.position + gl.offset_max; + const PrimitiveInstance primitive_instance = uniforms.primitive_instances.values[primitive_index]; + const uint type = bitfieldExtract(primitive_instance.packed, 30, 2); + const uint offset = bitfieldExtract(primitive_instance.packed, 0, 20); + + for (;;) { + const uint scalar_type = subgroupBroadcastFirst(type); + [[branch]] + if (scalar_type == type) { + switch (type) { + case PRIMITIVE_TYPE_RECT: + const Rect rect = uniforms.rects.values[offset]; + primitive_min = primitive_instance.position - rect.half_extent; + primitive_max = primitive_instance.position + rect.half_extent; + break; + case PRIMITIVE_TYPE_GLYPH: + const Glyph glyph = uniforms.glyphs.values[offset]; + primitive_min = primitive_instance.position + glyph.offset_min; + primitive_max = primitive_instance.position + glyph.offset_max; + break; + } + break; + } + } } const vec2 primitives_min = subgroupMin(primitive_min); @@ -51,7 +70,6 @@ void main() { for (int y = tile_start.y; y < tile_end.y; y++) { for (int x = tile_start.x; x < tile_end.x; x++) { const uvec2 tile_coord = uvec2(x, y); - const uint tile_index = tile_coord.y * uniforms.tile_stride + tile_coord.x; const vec2 tile_min = tile_coord * TILE_SIZE; const vec2 tile_max = min(tile_min + TILE_SIZE, uniforms.screen_resolution); @@ -62,6 +80,8 @@ void main() { continue; } + const uint tile_index = tile_coord.y * uniforms.tile_stride + tile_coord.x; + if (ballot.x != 0) { uniforms.tiles.values[tile_index * TILE_STRIDE + TILE_BITMAP_L0_OFFSET + gl_WorkGroupID.x * 32 + word_index + 0] = ballot.x; } diff --git a/title/shark-shaders/shaders/primitive_2d_bin_clear.comp.glsl b/title/shark-shaders/shaders/primitive_2d_bin_clear.comp.glsl index 8cfa4fb..8d443a2 100644 --- a/title/shark-shaders/shaders/primitive_2d_bin_clear.comp.glsl +++ b/title/shark-shaders/shaders/primitive_2d_bin_clear.comp.glsl @@ -11,7 +11,6 @@ #extension GL_KHR_shader_subgroup_ballot : require #include "compute_bindings.h" -#include "primitive_2d.h" // TODO: Spec constant support for different subgroup sizes. layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in; diff --git a/title/shark-shaders/shaders/primitive_2d_rasterize.comp.glsl b/title/shark-shaders/shaders/primitive_2d_rasterize.comp.glsl index 67f878c..c61ce61 100644 --- a/title/shark-shaders/shaders/primitive_2d_rasterize.comp.glsl +++ b/title/shark-shaders/shaders/primitive_2d_rasterize.comp.glsl @@ -102,20 +102,36 @@ void main() { // Set bits in the L0 bitmap indicate binned primitives for this tile. const uint primitive_index = index_l0 * 32 + j; - - const GlyphInstance gi = uniforms.glyph_instances.values[primitive_index]; - const Glyph gl = uniforms.glyphs.values[gi.index]; - const vec2 glyph_min = gi.position + gl.offset_min; - const vec2 glyph_max = gi.position + gl.offset_max; - - [[branch]] - if (all(greaterThanEqual(sample_center, glyph_min)) && all(lessThanEqual(sample_center, glyph_max))) { - const vec2 glyph_size = gl.offset_max - gl.offset_min; - const vec2 uv = mix(gl.atlas_min, gl.atlas_max, (sample_center - glyph_min) / glyph_size) / uniforms.atlas_resolution; - const vec4 color = unpackUnorm4x8(gi.color).bgra; - const float coverage = textureLod(sampler2D(glyph_atlas, bilinear_sampler), uv, 0.0).r * color.a; - accum.rgb = (coverage * color.rgb) + accum.rgb * (1.0 - coverage); - accum.a = coverage + accum.a * (1.0 - coverage); + const PrimitiveInstance primitive_instance = uniforms.primitive_instances.values[primitive_index]; + const uint type = bitfieldExtract(primitive_instance.packed, 30, 2); + const uint offset = bitfieldExtract(primitive_instance.packed, 0, 20); + + switch (type) { + case PRIMITIVE_TYPE_RECT: { + const Rect rect = uniforms.rects.values[offset]; + const vec2 rect_min = primitive_instance.position - rect.half_extent; + const vec2 rect_max = primitive_instance.position + rect.half_extent; + if (all(greaterThanEqual(sample_center, rect_min)) && all(lessThanEqual(sample_center, rect_max))) { + const vec4 color = unpackUnorm4x8(primitive_instance.color).bgra; + accum.rgb = color.rgb * color.a + accum.rgb * (1.0 - color.a); + accum.a = color.a + accum.a * (1.0 - color.a); + } + break; + } + case PRIMITIVE_TYPE_GLYPH: { + const Glyph glyph = uniforms.glyphs.values[offset]; + const vec2 glyph_min = primitive_instance.position + glyph.offset_min; + const vec2 glyph_max = primitive_instance.position + glyph.offset_max; + if (all(greaterThanEqual(sample_center, glyph_min)) && all(lessThanEqual(sample_center, glyph_max))) { + const vec2 glyph_size = glyph.offset_max - glyph.offset_min; + const vec2 uv = mix(glyph.atlas_min, glyph.atlas_max, (sample_center - glyph_min) / glyph_size) / uniforms.atlas_resolution; + const vec4 color = unpackUnorm4x8(primitive_instance.color).bgra; + const float coverage = textureLod(sampler2D(glyph_atlas, bilinear_sampler), uv, 0.0).r * color.a; + accum.rgb = color.rgb * coverage + accum.rgb * (1.0 - coverage); + accum.a = coverage + accum.a * (1.0 - coverage); + } + break; + } } } } diff --git a/title/shark/src/main.rs b/title/shark/src/main.rs index 1671a9e..1adfc5f 100644 --- a/title/shark/src/main.rs +++ b/title/shark/src/main.rs @@ -5,7 +5,7 @@ use std::time::{Duration, Instant}; use narcissus_core::{dds, Widen as _}; use pipelines::basic::BasicPipeline; -use pipelines::{GlyphInstance, PrimitiveUniforms, TILE_SIZE, TILE_STRIDE}; +use pipelines::{PrimitiveInstance, PrimitiveUniforms, Rect, TILE_SIZE, TILE_STRIDE}; use renderdoc_sys as rdoc; use fonts::{FontFamily, Fonts}; @@ -452,7 +452,8 @@ struct UiState<'a> { tmp_string: String, - primitive_instances: Vec, + primitive_instances: Vec, + rects: Vec, } impl<'a> UiState<'a> { @@ -465,9 +466,30 @@ impl<'a> UiState<'a> { glyph_cache, tmp_string: default(), primitive_instances: vec![], + rects: vec![], } } + fn rect(&mut self, x: f32, y: f32, width: f32, height: f32) { + let half_extent_x = width / 2.0; + let half_extent_y = height / 2.0; + let center_x = x + half_extent_x; + let center_y = y + half_extent_y; + + let rect_index = self.rects.len() as u32; + + self.rects.push(Rect { + half_extent_x, + half_extent_y, + border_width: 0.0, + border_radius: 0.0, + }); + + self.primitive_instances.push(PrimitiveInstance::rect( + rect_index, 0x4400ff00, center_x, center_y, + )) + } + fn text_fmt( &mut self, mut x: f32, @@ -508,12 +530,12 @@ impl<'a> UiState<'a> { x += advance * scale; - self.primitive_instances.push(GlyphInstance { + self.primitive_instances.push(PrimitiveInstance::glyph( + touched_glyph_index, + 0x880000ff, x, y, - touched_glyph_index, - color: 0x880000ff, - }); + )); x += advance_width * scale; } @@ -1389,17 +1411,23 @@ impl<'gpu> DrawState<'gpu> { microshades::PURPLE_RGBA_F32[3], ); + let primitive_instance_buffer = gpu.request_transient_buffer_with_data( + frame, + thread_token, + BufferUsageFlags::STORAGE, + ui_state.primitive_instances.as_slice(), + ); 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( + let rect_buffer = gpu.request_transient_buffer_with_data( frame, thread_token, BufferUsageFlags::STORAGE, - ui_state.primitive_instances.as_slice(), + ui_state.rects.as_slice(), ); let num_primitives = ui_state.primitive_instances.len() as u32; @@ -1474,9 +1502,10 @@ impl<'gpu> DrawState<'gpu> { tile_resolution_x: self.tile_resolution_x, tile_resolution_y: self.tile_resolution_y, tile_stride: self.tile_resolution_x, + primitives_instances_buffer: gpu + .get_buffer_address(primitive_instance_buffer.to_arg()), glyphs_buffer: gpu.get_buffer_address(glyph_buffer.to_arg()), - glyph_instances_buffer: gpu - .get_buffer_address(glyph_instance_buffer.to_arg()), + rects_buffer: gpu.get_buffer_address(rect_buffer.to_arg()), tiles_buffer: gpu.get_buffer_address(self.tiles_buffer.to_arg()), }, ); @@ -1730,6 +1759,10 @@ pub fn main() { let base_x = (base_x + 1.0) * 0.5; let base_y = (base_y + 1.0) * 0.5; + for _ in 0..100 { + ui_state.rect(0.0, 0.0, width as f32, height as f32); + } + for i in 0..80 { let i = i as f32; ui_state.text_fmt( @@ -1754,6 +1787,17 @@ pub fn main() { ); } + ui_state.rect(base_x * 60.0, base_y * 60.0, 120.0, 120.0); + ui_state.rect(base_x * 500.0, base_y * 100.0, 120.0, 120.0); + ui_state.rect(base_x * 90.0, base_y * 290.0, 140.0, 120.0); + ui_state.rect(base_x * 800.0, base_y * 320.0, 120.0, 120.0); + ui_state.rect(base_x * 200.0, base_y * 200.0, 120.0, 120.0); + ui_state.rect(base_x * 300.0, base_y * 120.0, 120.0, 170.0); + ui_state.rect(base_x * 1000.0, base_y * 30.0, 50.0, 120.0); + ui_state.rect(base_x * 340.0, base_y * 400.0, 120.0, 110.0); + ui_state.rect(base_x * 290.0, base_y * 80.0, 120.0, 10.0); + ui_state.rect(base_x * 310.0, base_y * 190.0, 10.0, 120.0); + draw_state.draw( thread_token, frame, diff --git a/title/shark/src/pipelines/mod.rs b/title/shark/src/pipelines/mod.rs index 4464b1a..d544f07 100644 --- a/title/shark/src/pipelines/mod.rs +++ b/title/shark/src/pipelines/mod.rs @@ -25,16 +25,55 @@ pub struct PrimitiveUniforms { pub num_primitives_1024: u32, pub tile_stride: u32, + pub primitives_instances_buffer: u64, + pub rects_buffer: u64, pub glyphs_buffer: u64, - pub glyph_instances_buffer: u64, pub tiles_buffer: u64, } +#[repr(u32)] +pub enum PrimitiveType { + Rect, + Glyph, +} + #[allow(unused)] #[repr(C)] -pub struct GlyphInstance { +pub struct PrimitiveInstance { + pub packed: u32, + pub color: u32, pub x: f32, pub y: f32, - pub touched_glyph_index: TouchedGlyphIndex, - pub color: u32, +} + +#[repr(C)] +pub struct Rect { + pub half_extent_x: f32, + pub half_extent_y: f32, + pub border_width: f32, + pub border_radius: f32, +} + +impl PrimitiveInstance { + #[inline(always)] + pub fn glyph(glyph_index: TouchedGlyphIndex, color: u32, x: f32, y: f32) -> Self { + let packed = glyph_index.as_u32() | ((PrimitiveType::Glyph as u32) << 30); + Self { + packed, + color, + x, + y, + } + } + + #[inline(always)] + pub fn rect(rect_index: u32, color: u32, x: f32, y: f32) -> Self { + let packed = rect_index | ((PrimitiveType::Rect as u32) << 30); + Self { + packed, + color, + x, + y, + } + } } -- 2.49.0