diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 05:44:11 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:16 -0300 |
| commit | 4452a8f467765cbfa0dd0444a9bf416ac8bd0bf5 (patch) | |
| tree | 0806bb947d2a0d17dcb784d9fc017d66859186db /shaders/post/prefix.glsl | |
| parent | fde030a699b3d6667d1fa21ae192b5011e3f373f (diff) | |
| download | pardes-4452a8f467765cbfa0dd0444a9bf416ac8bd0bf5.tar.gz pardes-4452a8f467765cbfa0dd0444a9bf416ac8bd0bf5.zip | |
G4: bloom, vignette and grain in the post chain
Three bundled Shadertoy passes beside Crt, each `Bloom|Vignette|Grain
0..3` (off by default, nothing drawn while off), in shaders/post/:
- Bloom: what is brighter than the page (a channel's linear peak over
0.75/0.7/0.6 and over the page's own + 0.15, so a light page does not
bloom) glows, 2/3.5/5% (ยง8.2's budget). The glow is a dual Kawase blur
in RGBA16F textures at half size and down, 3/4/5 steps by level
(shaders/bloom-down, bloom-up; Post.bloomChain), composited in linear
light and dithered.
- Vignette: round, from halfway to a corner, 10/18/28% at the far corners,
in linear light, dithered.
- Grain: a still, triangular-spread grain of 1.5/3/5 of 255 on
page-coloured pixels only, a logical pixel big; still, so it asks for no
frames.
Focus rule: the shell passes every bundled pass the rectangles of the tags
with their grips, the column and workspace tags, the notices and the
cursor (pardesSpare, at most 32, neighbours on one row merged), and a
bundled pass leaves them as they are; and a per-theme ceiling (pardesCap,
Post.capsOf) keeps the page's text and the selection's text at min(their
contrast, 4.5) under each pass at its strongest. User files get no
ceiling and no spared rectangles.
Fix found on the way: SDL GPU binds at most 4 KiB of a uniform block, so
every Shadertoy colour after iPalette (iBackgroundColor, iForegroundColor,
the cursor and selection colours, iPalette[>=4]) read zero. The prefix's
block is cut in three (Globals, Palette, Colors) with ghostty's names and
order, each pushed as a slice of the one struct; pardes's own block moves
to binding 3.
Tests: the caps hold over every native theme; each uniform slice fits
4 KiB; the prefix's members in ghostty's order across its blocks.
Gates: tty/gui unit-test and core-test pass; snap fails only
nested-optout; GUI goldens 01-08 byte-identical (09-18 wait on
wkzlsqvy, as in somtrmsz); web builds. Feel review material:
.scratch/render/{bloom,vignette,grain}/ (levels on forge, dusk, acme,
crops, a levels mp4).
Diffstat (limited to 'shaders/post/prefix.glsl')
| -rw-r--r-- | shaders/post/prefix.glsl | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/shaders/post/prefix.glsl b/shaders/post/prefix.glsl index 7a50936e..44c5e0f8 100644 --- a/shaders/post/prefix.glsl +++ b/shaders/post/prefix.glsl @@ -30,7 +30,14 @@ layout(set = 3, binding = 0, std140) uniform Globals { uniform float iTimeCursorChange; uniform float iTimeFocus; uniform int iFocus; +}; +// ghostty's one block, cut in three: SDL GPU binds at most 4 KiB of a +// uniform block (Vulkan), and the palette alone is 4 KiB. The names and +// their order are ghostty's; each block is a slice of the same memory. +layout(set = 3, binding = 1, std140) uniform Palette { uniform vec3 iPalette[256]; +}; +layout(set = 3, binding = 2, std140) uniform Colors { uniform vec3 iBackgroundColor; uniform vec3 iForegroundColor; uniform vec3 iCursorColor; @@ -44,13 +51,29 @@ layout(set = 3, binding = 0, std140) uniform Globals { // pass's strength, 1 to 3 (`Crt 3`), and 0 for a user's file; pardesScale // is the display's density (2 on a 2x screen), for a pass whose pattern is // in logical pixels. iResolution, fragCoord and iMouse stay in the display's -// pixels, as ghostty's do. -layout(set = 3, binding = 1, std140) uniform PardesPost { +// pixels, as ghostty's do. pardesCap is the most a bundled pass may do on +// this theme and still leave its text, and its selection's, at their own +// contrast or 4.5 (docs/effects.md); pardesSpare holds pardesSpareCount +// rectangles (x0, y0, x1, y1 in fragCoord's pixels) a bundled pass leaves +// alone: every tag, grip and notice, and the cursor, so no pass ever touches +// a focus indicator. +layout(set = 3, binding = 3, std140) uniform PardesPost { float pardesOpaque; float pardesLevel; float pardesScale; + float pardesCap; + float pardesSpareCount; + vec4 pardesSpare[32]; }; +bool pardesSpared(vec2 p) { + for (int i = 0; i < int(pardesSpareCount); i++) { + vec4 r = pardesSpare[i]; + if (p.x >= r.x && p.y >= r.y && p.x < r.z && p.y < r.w) return true; + } + return false; +} + // A bundled pass's constant at levels 1, 2 and 3. float pardesByLevel(float one, float two, float three) { return pardesLevel < 1.5 ? one : (pardesLevel < 2.5 ? two : three); |
