More work on custom shaders

This commit is contained in:
Kovid Goyal 2026-07-29 09:06:45 +05:30
parent bfac604d6d
commit ad7043bc20
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
5 changed files with 47 additions and 11 deletions

View file

@ -3460,9 +3460,9 @@ class Boss:
clear_caches()
from .shaders.slang import custom_shader
from .shaders.slang import clear_caches
custom_shader.cache_clear()
clear_caches()
def safe_delete_temp_file(self, path: str) -> None:
if is_path_in_temp_dir(path):

View file

@ -283,6 +283,7 @@ LNM: int
BGIMAGE_PROGRAM: int
CELL_PROGRAM: int
PADDING_PROGRAM: int
AFTER_WINDOW_BG_PROGRAM: int
CELL_FG_PROGRAM: int
CELL_BG_PROGRAM: int
BLIT_PROGRAM: int
@ -521,9 +522,6 @@ def compile_program(
) -> int:
pass
def init_cell_program() -> None:
pass
def set_os_window_chrome(os_window_id: int) -> bool:
pass

View file

@ -12,6 +12,7 @@
#include <stddef.h>
#include <string.h>
#include "text-cache.h"
#include "tupleobject.h"
#include "window_logo.h"
#include "srgb_gamma.h"
#include "state.h"
@ -27,6 +28,7 @@ enum {
SCREENSHOT_PROGRAM,
ROUNDED_RECT_PROGRAM,
PADDING_PROGRAM,
AFTER_WINDOW_BG_PROGRAM,
NUM_PROGRAMS
};
enum { SPRITE_MAP_UNIT, GRAPHICS_UNIT, SPRITE_DECORATIONS_MAP_UNIT };
@ -401,6 +403,10 @@ init_cell_program(void) {
bind_shader_globals_to_current_context();
}
static void
init_custom_programs(void) {
}
void
bind_shader_globals_to_current_context(void) {
if (shader_globals_vao_idx == -1) return;
@ -1994,8 +2000,16 @@ compile_program(PyObject UNUSED *self, PyObject *args) {
PyObject *vertex_shaders, *fragment_shaders, *metadata;
int which, allow_recompile = 0;
if (!PyArg_ParseTuple(args, "iO!O!O!|p", &which, &PyTuple_Type, &vertex_shaders, &PyTuple_Type, &fragment_shaders, &PyDict_Type, &metadata, &allow_recompile)) return NULL;
if (which == -1) { init_cell_program(); Py_RETURN_NONE; }
if (which == -2) { init_custom_programs(); Py_RETURN_NONE; }
if (which < 0 || which >= NUM_PROGRAMS) { PyErr_Format(PyExc_ValueError, "Unknown program: %d", which); return NULL; }
Program *program = program_ptr(which);
if (!PyTuple_GET_SIZE(vertex_shaders)) {
if (program->id != 0) {
glDeleteProgram(program->id); program->id = 0;
}
Py_RETURN_NONE;
}
if (program->id != 0) {
if (allow_recompile) { glDeleteProgram(program->id); program->id = 0; }
else { PyErr_SetString(PyExc_ValueError, "program already compiled"); return NULL; }
@ -2041,8 +2055,6 @@ ONE_INT(bind_vertex_array)
NO_ARG(unbind_vertex_array)
TWO_INT(unmap_vao_buffer)
NO_ARG(init_cell_program)
static PyObject*
sprite_map_set_limits(PyObject UNUSED *self, PyObject *args) {
unsigned int w, h;
@ -2064,7 +2076,6 @@ static PyMethodDef module_methods[] = {
MW(unmap_vao_buffer, METH_VARARGS),
MW(bind_program, METH_O),
MW(unbind_program, METH_NOARGS),
MW(init_cell_program, METH_NOARGS),
{NULL, NULL, 0, NULL} /* Sentinel */
};
@ -2099,7 +2110,7 @@ init_shaders(PyObject *module) {
C(CELL_PROGRAM); C(CELL_FG_PROGRAM); C(CELL_BG_PROGRAM); C(BORDERS_PROGRAM);
C(GRAPHICS_PROGRAM); C(GRAPHICS_PREMULT_PROGRAM); C(GRAPHICS_ALPHA_MASK_PROGRAM);
C(BGIMAGE_PROGRAM); C(TINT_PROGRAM); C(TRAIL_PROGRAM); C(BLIT_PROGRAM); C(SCREENSHOT_PROGRAM); C(ROUNDED_RECT_PROGRAM);
C(PADDING_PROGRAM);
C(PADDING_PROGRAM); C(AFTER_WINDOW_BG_PROGRAM);
C(GLSL_VERSION);
C(GL_VERSION);
C(GL_VENDOR);

View file

@ -36,12 +36,14 @@ public float4 pipeline_vertex_main(float4 src_rect, float4 dest_rect, uint verte
}
uniform Sampler2D backbuffer;
uniform uint timestamp;
public float4 pipeline_fragment_main(float2 texcoord) {
KittyCustomShaderData d;
d.backbuffer = backbuffer;
d.texcoord = texcoord;
d.backbuffer = backbuffer;
d.timestamp = timestamp;
float4 color = backbuffer.Sample(texcoord);
// PIPELINE
return color;

View file

@ -25,6 +25,7 @@ from typing import Any, Callable, Iterable, Iterator, Literal, NamedTuple
from kitty.constants import read_kitty_resource, shaders_dir, slangc
from kitty.fast_data_types import (
AFTER_WINDOW_BG_PROGRAM,
BGIMAGE_PROGRAM,
BLINK,
BLIT_PROGRAM,
@ -54,7 +55,6 @@ from kitty.fast_data_types import (
TRAIL_PROGRAM,
compile_program,
get_options,
init_cell_program,
)
from kitty.options.types import Options, defaults
from kitty.utils import lock_with_file, resolve_custom_file
@ -175,6 +175,7 @@ def glsl_shaders(name: str, variant_name: str = '') -> tuple[str, str]:
class LoadShaderPrograms:
text_fg_override_threshold: tuple[float, Literal['%', 'ratio']] = 0, '%'
text_old_gamma: bool = False
custom_shaders: dict[str, tuple[str, ...]] = {}
opts: Options | None = None
@ -196,6 +197,10 @@ class LoadShaderPrograms:
def recompile_if_needed(self) -> None:
if self.needs_recompile:
self(allow_recompile=True)
else:
opts = self.get_options()
if opts.custom_shader != self.custom_shaders:
self.compile_custom_shaders(allow_recompile=True)
def __call__(self, allow_recompile: bool = False) -> None:
default_cell_variant = cell_variant()
@ -229,7 +234,22 @@ class LoadShaderPrograms:
}.items():
vert, frag = glsl_shaders(name)
compile_program(prog, (vert,), (frag,), metadata[name], allow_recompile)
init_cell_program()
compile_program(-1, (), (), {}) # initialize programs
self.compile_custom_shaders(allow_recompile)
def compile_custom_shaders(self, allow_recompile: bool = False) -> None:
self.custom_shaders = {str(k): v for k, v in self.get_options().custom_shader.items()}
def do(prog: int, slot: str) -> None:
shaders = self.custom_shaders.get(slot, ())
if shaders:
vert, frag, metadata = build_custom_shader_pipeline_glsl(slot, shaders)
compile_program(prog, (vert,), (frag,), metadata, allow_recompile)
else:
compile_program(prog, (), (), {}, allow_recompile)
do(AFTER_WINDOW_BG_PROGRAM, 'after-window-background')
compile_program(-2, (), (), {}) # initialize programs
load_shader_programs = LoadShaderPrograms()
@ -1117,6 +1137,11 @@ def build_custom_shader_pipeline_glsl(
return vf.read(), ff.read(), glsl_metadata_for_shader(metadata)
def clear_caches() -> None:
custom_shader.cache_clear()
build_custom_shader_pipeline_glsl.cache_clear()
def test_slang_build() -> None:
if shutil.which(slangc()[0]) is None: