diff --git a/kitty/shaders/blit.slang b/kitty/shaders/blit.slang new file mode 100644 index 000000000..56cf96674 --- /dev/null +++ b/kitty/shaders/blit.slang @@ -0,0 +1,35 @@ +#language slang 2026 +// Copyright (C) 2026 Kovid Goyal +// Distributed under terms of the GPLv3 license. + +// Maps a vertex id to src and destination co-ordinates +module blit; + +public struct BlitOutput { + public float2 texcoord; + public float2 position; +}; + +#define left 0 +#define top 1 +#define right 2 +#define bottom 3 + +// Static constant array mapping vertex IDs +static const int2 vertex_pos_map[4] = +{ + int2(right, top), + int2(right, bottom), + int2(left, bottom), + int2(left, top) +}; + +public BlitOutput get_coords_for_blit(uint vertex_id, float4 src_rect, float4 dest_rect) { + BlitOutput output; + int2 pos = vertex_pos_map[vertex_id]; + // Indexing into the float4 vectors using pos.x and pos.y + output.texcoord = float2(src_rect[pos.x], src_rect[pos.y]); + output.position = float2(dest_rect[pos.x], dest_rect[pos.y]); + return output; +} + diff --git a/kitty/shaders/graphics.slang b/kitty/shaders/graphics.slang new file mode 100644 index 000000000..8497e8105 --- /dev/null +++ b/kitty/shaders/graphics.slang @@ -0,0 +1,27 @@ +#language slang 2026 +// Copyright (C) 2026 Kovid Goyal +// Distributed under terms of the GPLv3 license. + +import blit; + + +struct VSOutput +{ + float2 texcoord : TEXCOORD; + float4 position : SV_Position; +}; + + +[shader("vertex")] +VSOutput main( + uint vertex_id : SV_VertexID, + uniform float4 src_rect, + uniform float4 dest_rect, +) { + BlitOutput ans = get_coords_for_blit(vertex_id, src_rect, dest_rect); + VSOutput output; + output.texcoord = ans.texcoord; + output.position = float4(ans.position[0], ans.position[1], 0.0, 1.0); + return output; +} + diff --git a/kitty/shaders/slang.py b/kitty/shaders/slang.py index db52bcb63..67533dac4 100644 --- a/kitty/shaders/slang.py +++ b/kitty/shaders/slang.py @@ -157,7 +157,7 @@ def commands_to_compile_dir_to_ir(sources: dict[str, SlangFile], src_dir: str, o deps_file = f'{base_dest}.deps' module_mtime = safe_mtime(slang_module) needs_build = module_mtime < get_newest_dep_time(deps_file) - yield Command(needs_build, f'Compile {name} to slang IR', cmdbase + [ + yield Command(needs_build, f'Compiling |{name}.slang| ...', cmdbase + [ sfile.path, '-I', output_dirpath, '-I', src_dir, '-depfile', deps_file, '-target', 'none', '-o', slang_module ]) @@ -183,12 +183,28 @@ def commands_to_compile_to_glsl(sources: dict[str, SlangFile], build_dir: str, d needs_build = output_mtime < module_mtime if needs_build: built_glsl_files.extend(dest_files) - yield Command(needs_build, f'Link slang IR for {name} to GLSL', cmd) + yield Command(needs_build, f'Linking |{name}.slang-module| to GLSL ...', cmd) -def fixup_glsl_files(*paths: str) -> None: +def fixup_opengl_code(glsl_code: str) -> str: + lines = [] + for line in glsl_code.splitlines(): + if line.startswith('#version '): + line = '#version 330 core' + elif line.startswith('#extension ') or line in ('layout(row_major) buffer;', 'layout(push_constant)'): + line = '// ' + line + lines.append(line) + return '\n'.join(lines) + + +def fixup_opengl_files(*paths: str) -> None: ' Convert the GLSL output of slangc to something that will work with OpenGL 3.3 ' - pass + for path in paths: + with open(path, 'r+') as f: + glsl_code = f.read() + f.seek(0) + f.truncate() + f.write(fixup_opengl_code(glsl_code)) ParallelRun = Callable[[Iterable[tuple[bool, str, list[str]]]], None] @@ -227,4 +243,4 @@ def compile_builtin_shaders(build_dir: str, dest_dir: str, parallel_run: Paralle # Now run all commands parallel_run(glsl_commands) - fixup_glsl_files(*built_glsl_files) + fixup_opengl_files(*built_glsl_files) diff --git a/setup.py b/setup.py index 9e983c687..3c2e4077f 100755 --- a/setup.py +++ b/setup.py @@ -1218,6 +1218,7 @@ def build_shaders(args: Options) -> None: needed = [] for (needs_build, desc, cmd) in cmds: if needs_build: + desc = re.sub(r'\|(.+?)\|', lambda m: emphasis(m.group(1)), desc) needed.append(Command(desc, cmd, lambda: True)) parallel_run(needed)