From de36058da857abbbe7b9a04c243aeb41596cb247 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 10 Aug 2026 12:25:06 +0530 Subject: [PATCH] Pass varying data in KittyTextures rather than as function paramters The function signatures will be set in stone post release so pass all data via structs so that future additions to the structs will t break third party shaders --- kitty/shaders/custom/bloom.slang | 4 +--- kitty/shaders/custom/crt.slang | 8 +++----- kitty/shaders/custom/cursor-trail-blaze.slang | 6 ++---- kitty/shaders/custom/cursor-trail-default.slang | 4 +--- kitty/shaders/custom/cursor-trail-lightning.slang | 6 ++---- kitty/shaders/custom/fireworks-rockets.slang | 6 ++---- kitty/shaders/custom/fireworks.slang | 6 ++---- kitty/shaders/custom/focus-highlight.slang | 6 ++---- kitty/shaders/custom/inside-the-matrix.slang | 4 +--- kitty/shaders/custom/negative.slang | 4 +--- kitty/shaders/custom/pipeline.slang | 2 +- kitty/shaders/custom/pond-ripple.slang | 12 +++++------- kitty/shaders/custom/sample.slang | 13 +------------ kitty/shaders/custom/spotlight.slang | 6 ++---- kitty/shaders/custom/tab-change.slang | 6 ++---- kitty/shaders/custom/tft.slang | 4 +--- kitty/shaders/custom/types.slang | 12 ++++++++++-- kitty/shaders/custom/underwater.slang | 6 ++---- kitty/shaders/custom/water.slang | 4 +--- kitty/shaders/slang.py | 2 +- 20 files changed, 43 insertions(+), 78 deletions(-) diff --git a/kitty/shaders/custom/bloom.slang b/kitty/shaders/custom/bloom.slang index 1a65881d7..68e5d42f3 100644 --- a/kitty/shaders/custom/bloom.slang +++ b/kitty/shaders/custom/bloom.slang @@ -48,9 +48,7 @@ float lum(float4 c) { public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { float2 uv = t.pos; diff --git a/kitty/shaders/custom/crt.slang b/kitty/shaders/custom/crt.slang index cd7dcad96..e38ab095d 100644 --- a/kitty/shaders/custom/crt.slang +++ b/kitty/shaders/custom/crt.slang @@ -16,9 +16,7 @@ static const float4 TINT = float4(0, 0.8, 0.6, 0); // tint color set the fourth public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { // UV within the current viewport (0..1) float2 uv = t.pos; @@ -32,13 +30,13 @@ public float4 fragment_main( uv.y -= 0.5f; uv.y *= 1.0f + (dc.x * (0.4f * WARP)); uv.y += 0.5f; // Original Y pixel coordinate within the viewport (for scanline phase) - float fragCoordY = (t.pos.y - viewport.y) * float(d.viewport_size_pixels.y); + float fragCoordY = (t.pos.y - t.viewport.y) * float(d.viewport_size_pixels.y); // Scanline darkness at this pixel row float apply = abs(sin(fragCoordY) * 0.25f * SCAN); // Sample the backbuffer at the warped viewport UV - float2 sample_uv = viewport.xy + uv * viewport.zw; + float2 sample_uv = t.viewport.xy + uv * t.viewport.zw; float3 col = t.backbuffer.Sample(sample_uv).rgb; // apply the tint col = lerp(col, col * TINT.rgb, TINT.a); diff --git a/kitty/shaders/custom/cursor-trail-blaze.slang b/kitty/shaders/custom/cursor-trail-blaze.slang index db64b4dbc..1dcff5c3c 100644 --- a/kitty/shaders/custom/cursor-trail-blaze.slang +++ b/kitty/shaders/custom/cursor-trail-blaze.slang @@ -72,9 +72,7 @@ static float movementVertexFactor(float2 a, float2 b) { public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { if (d.cursor_trail_color.a <= 0.0) return color; @@ -85,7 +83,7 @@ public float4 fragment_main( if (easedProgress <= 0.0) return color; // Work in pixel space for correct aspect-ratio distance measurements. - float2 pixelDims = float2(d.viewport_size_pixels) * viewport.zw; + float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw; float2 px = t.pos * pixelDims; // Current cursor rect in pixel space (edge: .x=left .y=right .z=top .w=bottom, y-up). diff --git a/kitty/shaders/custom/cursor-trail-default.slang b/kitty/shaders/custom/cursor-trail-default.slang index f94ec18c5..bc07738b6 100644 --- a/kitty/shaders/custom/cursor-trail-default.slang +++ b/kitty/shaders/custom/cursor-trail-default.slang @@ -32,9 +32,7 @@ bool inside_trail_quad(float2 uv, float2 c0, float2 c1, float2 c2, float2 c3) { public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { float opacity = d.cursor_trail_color.a; if (opacity <= 0.0) return color; diff --git a/kitty/shaders/custom/cursor-trail-lightning.slang b/kitty/shaders/custom/cursor-trail-lightning.slang index c05363fc1..29c79f91e 100644 --- a/kitty/shaders/custom/cursor-trail-lightning.slang +++ b/kitty/shaders/custom/cursor-trail-lightning.slang @@ -87,14 +87,12 @@ static float forkDist(float2 p, float2 a, float2 b, float seed) { public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { float age = clamp((d.timestamp - d.cursor_trail_change_time) / DURATION, 0.0, 1.0); if (age >= 1.0) return color; - float2 pixelDims = float2(d.viewport_size_pixels) * viewport.zw; + float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw; // Cursor centres in pixel space (edge: .x=left .y=right .z=top .w=bottom, y-up). float2 curCenter = float2( diff --git a/kitty/shaders/custom/fireworks-rockets.slang b/kitty/shaders/custom/fireworks-rockets.slang index 55cb62a14..6ce46cddb 100644 --- a/kitty/shaders/custom/fireworks-rockets.slang +++ b/kitty/shaders/custom/fireworks-rockets.slang @@ -100,11 +100,9 @@ float3 drawFireworks(float time, float2 uv, float3 particolor, float seed) { public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { - float2 pixelDims = float2(d.viewport_size_pixels) * viewport.zw; + float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw; float aspect = pixelDims.x / pixelDims.y; // Map to [-aspect, aspect] × [-1, 1] with y=1 at top (matching the original) diff --git a/kitty/shaders/custom/fireworks.slang b/kitty/shaders/custom/fireworks.slang index 10583c39a..d750b99d7 100644 --- a/kitty/shaders/custom/fireworks.slang +++ b/kitty/shaders/custom/fireworks.slang @@ -78,11 +78,9 @@ float3 rainbow(float3 c, float time) { public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { - float2 pixelDims = float2(d.viewport_size_pixels) * viewport.zw; + float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw; float aspect = pixelDims.x / pixelDims.y; float time = fmod(d.timestamp, 3600.0f) * TIME_SCALE; diff --git a/kitty/shaders/custom/focus-highlight.slang b/kitty/shaders/custom/focus-highlight.slang index 0a3d3dbcb..031519f45 100644 --- a/kitty/shaders/custom/focus-highlight.slang +++ b/kitty/shaders/custom/focus-highlight.slang @@ -22,9 +22,7 @@ static const float INACTIVE_DIM = 0.3; public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { float4 g = d.active_window_geometry; // Pass through unchanged if no active window geometry is known. @@ -35,7 +33,7 @@ public float4 fragment_main( float2 winMax = g.xy + g.zw; // Effect strength decays from 1 at animation start to 0 at the end. - float strength = 1.0 - animation_progress; + float strength = 1.0 - t.animation_progress; bool inWindow = all(uv >= winMin) && all(uv <= winMax); diff --git a/kitty/shaders/custom/inside-the-matrix.slang b/kitty/shaders/custom/inside-the-matrix.slang index a6858db3f..02ee7b74e 100644 --- a/kitty/shaders/custom/inside-the-matrix.slang +++ b/kitty/shaders/custom/inside-the-matrix.slang @@ -237,9 +237,7 @@ float smoothstep1(float x) { return smoothstep(0.0f, 1.0f, x); } public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { float2 uv = t.pos; float time = fmod(d.timestamp, 300.0f) * SPEED; diff --git a/kitty/shaders/custom/negative.slang b/kitty/shaders/custom/negative.slang index e1fdf99b4..4f0224a5c 100644 --- a/kitty/shaders/custom/negative.slang +++ b/kitty/shaders/custom/negative.slang @@ -9,9 +9,7 @@ import kitty_custom_shader_types; public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { return float4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, color.a); } diff --git a/kitty/shaders/custom/pipeline.slang b/kitty/shaders/custom/pipeline.slang index 9e48828dd..801ce5f0d 100644 --- a/kitty/shaders/custom/pipeline.slang +++ b/kitty/shaders/custom/pipeline.slang @@ -64,7 +64,7 @@ uniform Sampler2D backbuffer, a, b, persist; public float4 pipeline_fragment_main(float2 backbuffer_pos, int group, float4 viewport, float animation_progress, bool convert_to_srgb) { float4 color = backbuffer.Sample(backbuffer_pos); // pre multiplied linear RGB color = float4(color.rgb / color.a, color.a); // un pre multiplied color passed through pipeline - KittyTextures t = {backbuffer, a, b, persist, backbuffer_pos}; + KittyTextures t = {backbuffer, a, b, persist, backbuffer_pos, viewport, animation_progress}; // PIPELINE return vec4_premul(color.rgb, color.a); } diff --git a/kitty/shaders/custom/pond-ripple.slang b/kitty/shaders/custom/pond-ripple.slang index c22805374..cef48c99e 100644 --- a/kitty/shaders/custom/pond-ripple.slang +++ b/kitty/shaders/custom/pond-ripple.slang @@ -28,11 +28,9 @@ static const float DIFFUSE_STRENGTH = 0.10; public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { - float2 pixelDims = float2(d.viewport_size_pixels) * viewport.zw; + float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw; float aspect = pixelDims.x / pixelDims.y; // d.mouse_pos.zw is the UV position of the last left-button press (y=0 at bottom). @@ -44,20 +42,20 @@ public float4 fragment_main( float2 dir = delta / max(dist, 1e-5); // Wavefront radius advances linearly with animation_progress. - float front = WAVE_SPEED * animation_progress; + float front = WAVE_SPEED * t.animation_progress; // Signed distance from the wavefront (negative = wave has passed, positive = not yet reached). float behind = dist - front; // Gaussian spatial envelope centered at the wavefront; grows in width over time. - float sigma = WAVE_WIDTH * (1.0 + animation_progress); + float sigma = WAVE_WIDTH * (1.0 + t.animation_progress); float env = exp(-behind * behind / (2.0 * sigma * sigma)); // Causality: suppress any energy ahead of the wavefront. env *= 1.0 - smoothstep(-0.01, 0.02, behind); // Temporal amplitude decay as the wave expands outward. - float decay = pow(1.0 - animation_progress, 0.7); + float decay = pow(1.0 - t.animation_progress, 0.7); float k = WAVE_FREQUENCY * 6.28318530718; float wave = sin(behind * k); diff --git a/kitty/shaders/custom/sample.slang b/kitty/shaders/custom/sample.slang index 51a4fb709..b6446c8af 100644 --- a/kitty/shaders/custom/sample.slang +++ b/kitty/shaders/custom/sample.slang @@ -13,18 +13,7 @@ public float4 fragment_main( KittyTextures t, // See types.slang for details on the data in this structure - KittyCustomShaderData d, - - // The viewport used for this group. In the form (x, y, width, height) - // where (x, y) is the bottom-left corner of the viewport, with (0, 0) at - // the bottom-left of the screen and y increasing upwards (standard UV - // coordinates). All numbers are unit floats. If no viewport is defined for - // the group defaults to (0, 0, 1, 1) that is, the full backbuffer. - float4 viewport, - - // The value after applying the animation easing curve to time since - // animation start. - float animation_progress + KittyCustomShaderData d ) { // END_FUNCTION_SIGNATURE return float4(color.r, min(max(0.1, color.g) * 2, 1), color.b, color.a); diff --git a/kitty/shaders/custom/spotlight.slang b/kitty/shaders/custom/spotlight.slang index 61d3493cb..d283f8a0a 100644 --- a/kitty/shaders/custom/spotlight.slang +++ b/kitty/shaders/custom/spotlight.slang @@ -24,15 +24,13 @@ static const int HIDE_WHEN_POINTER_HIDDEN = 1; public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { if (HIDE_WHEN_POINTER_HIDDEN == 1 && d.mouse_pointer_hidden != 0.0) return color; float2 uv = t.pos; // Viewport pixel dimensions for aspect-ratio correction - float2 pixelDims = float2(d.viewport_size_pixels) * viewport.zw; + float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw; float aspectRatio = pixelDims.x / pixelDims.y; // Random oscillating center (different frequencies and phases on each axis) diff --git a/kitty/shaders/custom/tab-change.slang b/kitty/shaders/custom/tab-change.slang index d60c4e00d..a5532bba0 100644 --- a/kitty/shaders/custom/tab-change.slang +++ b/kitty/shaders/custom/tab-change.slang @@ -54,14 +54,12 @@ float wipe_pixel_pos(float2 uv, float4 ca) { public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { float4 ca = d.central_area; if (ca.z <= 0.0 || ca.w <= 0.0) return color; - float p = animation_progress; + float p = t.animation_progress; float brightness; if (ANIMATION_TYPE == 0) { diff --git a/kitty/shaders/custom/tft.slang b/kitty/shaders/custom/tft.slang index 9b62cff99..eae38713f 100644 --- a/kitty/shaders/custom/tft.slang +++ b/kitty/shaders/custom/tft.slang @@ -21,9 +21,7 @@ void scanline(inout float3 color, float2 pixel_pos) { public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { float2 pixel_pos = t.pos * float2(d.viewport_size_pixels); float3 c = color.rgb; diff --git a/kitty/shaders/custom/types.slang b/kitty/shaders/custom/types.slang index c86a709f5..d9d8c8bf1 100644 --- a/kitty/shaders/custom/types.slang +++ b/kitty/shaders/custom/types.slang @@ -52,8 +52,8 @@ public struct KittyCustomShaderData { // the size in pixels of the full underlying viewport we are rendering too, // before applying any viewport transforms from the current group. - // You can use the viewport vector passed to fragment_main to derive the - // actual size and position of the viewport currently being rendered too. + // You can use t.viewport to derive the actual size and position of the + // viewport currently being rendered too. public uint2 viewport_size_pixels; public float mouse_pointer_hidden; // 1.0 if the mouse pointer is currently hidden, 0.0 if visible @@ -80,5 +80,13 @@ public struct KittyTextures { public Sampler2D persist; public float2 pos; // the position of this pixel in the textures (UV coordinates) + + // The viewport for this group in the form (x, y, width, height) where (x, y) is the + // bottom-left corner, with (0, 0) at the bottom-left of the screen and y increasing upwards + // (UV coordinates). Defaults to (0, 0, 1, 1) when no viewport is defined for the group. + public float4 viewport; + // The value after applying the animation easing curve to time since animation start. + // Zero when no animation is active. + public float animation_progress; } // END_TYPES_DEFINITION diff --git a/kitty/shaders/custom/underwater.slang b/kitty/shaders/custom/underwater.slang index 427a253fa..d1f8fe7de 100644 --- a/kitty/shaders/custom/underwater.slang +++ b/kitty/shaders/custom/underwater.slang @@ -65,11 +65,9 @@ float rayStrength( public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { - float2 iResolution = float2(d.viewport_size_pixels) * viewport.zw; + float2 iResolution = float2(d.viewport_size_pixels) * t.viewport.zw; float iTime = d.timestamp; // Convert kitty UV (y=0 at bottom) to a top-left-origin pixel coordinate, diff --git a/kitty/shaders/custom/water.slang b/kitty/shaders/custom/water.slang index d0e219757..5a0ba4dd1 100644 --- a/kitty/shaders/custom/water.slang +++ b/kitty/shaders/custom/water.slang @@ -15,9 +15,7 @@ static const float UV_DISPLACEMENT = 0.04; // UV warp magnitu public float4 fragment_main( float4 color, KittyTextures t, - KittyCustomShaderData d, - float4 viewport, - float animation_progress + KittyCustomShaderData d ) { float wtime = d.timestamp * 0.5 + 23.0; float2 uv = t.pos; diff --git a/kitty/shaders/slang.py b/kitty/shaders/slang.py index fb2dbe9a4..70f7bef5e 100644 --- a/kitty/shaders/slang.py +++ b/kitty/shaders/slang.py @@ -1410,7 +1410,7 @@ def build_custom_shader_pipeline_ir(pipeline: Pipeline, cache_dir: str, invocati # inactive animated groups do not cause an extra blit draw call. pipeline_parts: list[str] = [] for g_idx, group in enumerate(pipeline['groups']): - calls = '\n'.join(f' color = {entry_point(g_idx, j)}(color, t, csd, viewport, animation_progress);' for j in range(len(group['shaders']))) + calls = '\n'.join(f' color = {entry_point(g_idx, j)}(color, t, csd);' for j in range(len(group['shaders']))) calls += '\n if (convert_to_srgb) color = float4(linear2srgb(color.rgb), color.a);' prefix = '} else ' if g_idx else '' pipeline_parts.append(f' {prefix}if (group == {g_idx}) {{\n{calls}')