Major reorg
This commit is contained in:
+22
-22
@@ -5,7 +5,7 @@ Clay UI integration.
|
||||
|
||||
## Current state
|
||||
|
||||
The renderer uses a single unified `Pipeline_2D_Base` (`TRIANGLELIST` pipeline) with two submission
|
||||
The renderer uses a single unified `Core_2D` (`TRIANGLELIST` pipeline) with two submission
|
||||
modes dispatched by a push constant:
|
||||
|
||||
- **Mode 0 (Tessellated):** Vertex buffer contains real geometry. Used for text (indexed draws into
|
||||
@@ -15,10 +15,10 @@ modes dispatched by a push constant:
|
||||
shader premultiplies the texture sample (`t.rgb *= t.a`) and computes `out = color * t`.
|
||||
|
||||
- **Mode 1 (SDF):** A static 6-vertex unit-quad buffer is drawn instanced, with per-primitive
|
||||
`Base_2D_Primitive` structs (96 bytes each) uploaded each frame to a GPU storage buffer. The vertex
|
||||
`Core_2D_Primitive` structs (96 bytes each) uploaded each frame to a GPU storage buffer. The vertex
|
||||
shader reads `primitives[gl_InstanceIndex]`, computes world-space position from unit quad corners +
|
||||
primitive bounds. The fragment shader dispatches on `Shape_Kind` (encoded in the low byte of
|
||||
`Base_2D_Primitive.flags`) to evaluate one of four signed distance functions:
|
||||
`Core_2D_Primitive.flags`) to evaluate one of four signed distance functions:
|
||||
- **RRect** (kind 1) — `sdRoundedBox` with per-corner radii. Covers rectangles (sharp or rounded),
|
||||
circles (uniform radii = half-size), and line segments / capsules (rotated RRect with uniform
|
||||
radii = half-thickness). Covers filled, outlined, textured, and gradient-filled variants.
|
||||
@@ -28,9 +28,9 @@ modes dispatched by a push constant:
|
||||
normals. Covers full rings, partial arcs, and pie slices (`inner_radius = 0`).
|
||||
|
||||
All SDF shapes support fill, outline, solid color, 2-color linear gradients, 2-color radial
|
||||
gradients, and texture fills via `Shape_Flags` (see `pipeline_2d_base.odin`). The texture UV rect
|
||||
gradients, and texture fills via `Shape_Flags` (see `core_2d.odin`). The texture UV rect
|
||||
(`uv_rect: [4]f32`) and the gradient/outline parameters (`effects: Gradient_Outline`) live in their
|
||||
own 16-byte slots in `Base_2D_Primitive`, so a primitive can carry texture and outline simultaneously.
|
||||
own 16-byte slots in `Core_2D_Primitive`, so a primitive can carry texture and outline simultaneously.
|
||||
Gradient and texture remain mutually exclusive at the fill-source level (a Brush variant chooses one
|
||||
or the other) since they share the worst-case fragment-shader register path.
|
||||
|
||||
@@ -433,19 +433,19 @@ our design:
|
||||
### Main pipeline: SDF + tessellated (unified)
|
||||
|
||||
The main pipeline serves two submission modes through a single `TRIANGLELIST` pipeline and a single
|
||||
vertex input layout, distinguished by a `mode` field in the `Vertex_Uniforms` push constant
|
||||
(`Draw_Mode.Tessellated = 0`, `Draw_Mode.SDF = 1`), pushed per draw call via `push_globals`. The
|
||||
vertex input layout, distinguished by a `mode` field in the `Vertex_Uniforms_2D` push constant
|
||||
(`Core_2D_Mode.Tessellated = 0`, `Core_2D_Mode.SDF = 1`), pushed per draw call via `push_globals`. The
|
||||
vertex shader branches on this uniform to select the tessellated or SDF code path.
|
||||
|
||||
- **Tessellated mode** (`mode = 0`): direct vertex buffer with explicit geometry. Used for text
|
||||
(SDL_ttf atlas sampling), triangles, triangle fans/strips, single-pixel points, and any
|
||||
user-provided raw vertex geometry.
|
||||
- **SDF mode** (`mode = 1`): shared unit-quad vertex buffer + GPU storage buffer of
|
||||
`Base_2D_Primitive` structs, drawn instanced. Used for all shapes with closed-form signed distance
|
||||
`Core_2D_Primitive` structs, drawn instanced. Used for all shapes with closed-form signed distance
|
||||
functions.
|
||||
|
||||
Both modes use the same fragment shader. The fragment shader checks `Shape_Kind` (low byte of
|
||||
`Base_2D_Primitive.flags`): kind 0 (`Solid`) is the tessellated path, which premultiplies the texture
|
||||
`Core_2D_Primitive.flags`): kind 0 (`Solid`) is the tessellated path, which premultiplies the texture
|
||||
sample and computes `out = color * t`; kinds 1–4 dispatch to one of four SDF functions (RRect, NGon,
|
||||
Ellipse, Ring_Arc) and apply gradient/texture/outline/solid color based on `Shape_Flags` bits.
|
||||
|
||||
@@ -454,7 +454,7 @@ Ellipse, Ring_Arc) and apply gradient/texture/outline/solid color based on `Shap
|
||||
CPU-side adaptive tessellation for curved shapes (the current approach) has three problems:
|
||||
|
||||
1. **Vertex bandwidth.** A rounded rectangle with four corner arcs produces ~250 vertices × 20 bytes
|
||||
= 5 KB. An SDF rounded rectangle is one `Base_2D_Primitive` struct (96 bytes) plus 4 shared
|
||||
= 5 KB. An SDF rounded rectangle is one `Core_2D_Primitive` struct (96 bytes) plus 4 shared
|
||||
unit-quad vertices. That is roughly a 50× reduction per shape.
|
||||
|
||||
2. **Quality.** Tessellated curves are piecewise-linear approximations. At high DPI or under
|
||||
@@ -486,7 +486,7 @@ SDF primitives are submitted via a GPU storage buffer indexed by `gl_InstanceInd
|
||||
shader, rather than encoding per-primitive data redundantly in vertex attributes. This follows the
|
||||
pattern used by both Zed GPUI and vger-rs.
|
||||
|
||||
Each SDF shape is described by a single `Base_2D_Primitive` struct (96 bytes) in the storage
|
||||
Each SDF shape is described by a single `Core_2D_Primitive` struct (96 bytes) in the storage
|
||||
buffer. The vertex shader reads `primitives[gl_InstanceIndex]`, computes the quad corner position
|
||||
from the unit vertex and the primitive's bounds, and passes shape parameters to the fragment shader
|
||||
via `flat` interpolated varyings.
|
||||
@@ -501,10 +501,10 @@ in a draw call has the same mode — so it is effectively free on all modern GPU
|
||||
|
||||
#### Shape kinds and SDF dispatch
|
||||
|
||||
The fragment shader dispatches on `Shape_Kind` (low byte of `Base_2D_Primitive.flags`) to evaluate
|
||||
one of four signed distance functions. The `Shape_Kind` enum and per-kind `*_Params` structs are
|
||||
defined in `pipeline_2d_base.odin`. CPU-side drawing procs in `shapes.odin` build the appropriate
|
||||
`Base_2D_Primitive` and set the kind automatically:
|
||||
The fragment shader dispatches on `Shape_Kind` (low byte of `Core_2D_Primitive.flags`) to evaluate
|
||||
one of four signed distance functions. The `Shape_Kind` enum, per-kind `*_Params` structs, and
|
||||
CPU-side drawing procs all live in `core_2d.odin`. The drawing procs build the appropriate
|
||||
`Core_2D_Primitive` and set the kind automatically:
|
||||
|
||||
Each user-facing shape proc accepts a `Brush` union (color, linear gradient, radial gradient,
|
||||
or textured fill) as its fill source, plus optional outline parameters. The procs map to SDF
|
||||
@@ -522,7 +522,7 @@ kinds as follows:
|
||||
| `ring` (pie slice) | `Ring_Arc` | Annular radial SDF | `inner_radius = 0`, angular clipping via `start/end_angle` |
|
||||
|
||||
The `Shape_Flags` bit set controls per-primitive rendering mode (outline, gradient, texture, rotation,
|
||||
arc geometry). See the `Shape_Flag` enum in `pipeline_2d_base.odin` for the authoritative flag
|
||||
arc geometry). See the `Shape_Flag` enum in `core_2d.odin` for the authoritative flag
|
||||
definitions and bit assignments.
|
||||
|
||||
**What stays tessellated:**
|
||||
@@ -662,7 +662,7 @@ for the factor-selection table and rationale).
|
||||
#### Submission-order trade-off
|
||||
|
||||
Within Pass A and Pass B, sub-batches render in the user's submission order. What the bracket model
|
||||
sacrifices is *interleaved* ordering between backdrop and non-backdrop content within a single
|
||||
sacrifices is _interleaved_ ordering between backdrop and non-backdrop content within a single
|
||||
layer. A non-backdrop sub-batch submitted between two backdrops still renders in Pass B (after the
|
||||
bracket), not at its submission position. Worked example:
|
||||
|
||||
@@ -675,7 +675,7 @@ draw.gaussian_blur(layer, panelB, sigma=12) // 4 Backdrop → Bracket
|
||||
draw.text(layer, "label", ...) // 5 Text → Pass B (drawn ON TOP of both panels)
|
||||
```
|
||||
|
||||
In this layer, panelB does *not* see card_red — even though card_red was submitted before panelB —
|
||||
In this layer, panelB does _not_ see card_red — even though card_red was submitted before panelB —
|
||||
because both backdrops sample `source_texture` as it stood at the bracket entry, which is after
|
||||
Pass A and before card_red has rendered. card_red ends up on top of panelA, not underneath it.
|
||||
|
||||
@@ -709,7 +709,7 @@ abstraction. This matches the cost/complexity envelope of iOS `UIVisualEffectVie
|
||||
The vertex struct is unchanged from the current 20-byte layout:
|
||||
|
||||
```
|
||||
Vertex :: struct {
|
||||
Vertex_2D :: struct {
|
||||
position: [2]f32, // 0: screen-space position
|
||||
uv: [2]f32, // 8: atlas UV (text) or unused (shapes)
|
||||
color: Color, // 16: u8x4, GPU-normalized to float
|
||||
@@ -721,10 +721,10 @@ draws, `position` carries actual world-space geometry. For SDF draws, `position`
|
||||
corners (0,0 to 1,1) and the vertex shader computes world-space position from the storage-buffer
|
||||
primitive's bounds.
|
||||
|
||||
The `Base_2D_Primitive` struct for SDF shapes lives in the storage buffer, not in vertex attributes:
|
||||
The `Core_2D_Primitive` struct for SDF shapes lives in the storage buffer, not in vertex attributes:
|
||||
|
||||
```
|
||||
Base_2D_Primitive :: struct {
|
||||
Core_2D_Primitive :: struct {
|
||||
bounds: [4]f32, // 0: min_x, min_y, max_x, max_y
|
||||
color: Color, // 16: u8x4, unpacked in shader via unpackUnorm4x8
|
||||
flags: u32, // 20: low byte = Shape_Kind, bits 8+ = Shape_Flags
|
||||
@@ -738,7 +738,7 @@ Base_2D_Primitive :: struct {
|
||||
```
|
||||
|
||||
`Shape_Params` is a `#raw_union` over `RRect_Params`, `NGon_Params`, `Ellipse_Params`, and
|
||||
`Ring_Arc_Params` (plus a `raw: [8]f32` view), defined in `pipeline_2d_base.odin`. Each SDF kind
|
||||
`Ring_Arc_Params` (plus a `raw: [8]f32` view), defined in `core_2d.odin`. Each SDF kind
|
||||
writes its own params variant; the fragment shader reads the appropriate fields based on `Shape_Kind`.
|
||||
`Gradient_Outline` is a 16-byte struct containing `gradient_color: Color`, `outline_color: Color`,
|
||||
`gradient_dir_sc: u32` (packed f16 cos/sin pair), and `outline_packed: u32` (packed f16 outline
|
||||
|
||||
Reference in New Issue
Block a user