Load GLSL binding information at runtime rather than writing it to a generated C header

This commit is contained in:
Kovid Goyal 2026-07-07 16:47:31 +05:30
parent 91d39eba6c
commit 86bc2c952a
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
7 changed files with 233 additions and 360 deletions

1
.gitattributes vendored
View file

@ -11,7 +11,6 @@ kitty/rgb.py linguist-generated=true
kitty/srgb_gamma.* linguist-generated=true
kitty/gl-wrapper.* linguist-generated=true
kitty/glfw-wrapper.* linguist-generated=true
kitty/glsl-uniforms.h linguist-generated=true
kitty/color-names.h linguist-generated=true
kitty/parse-graphics-command.h linguist-generated=true
kitty/parse-multicell-command.h linguist-generated=true

View file

@ -551,7 +551,7 @@ def add_window(os_window_id: int, tab_id: int, title: str) -> int:
def compile_program(
which: int, vertex_shaders: Tuple[str, ...], fragment_shaders: Tuple[str, ...], allow_recompile: bool = False
which: int, vertex_shaders: Tuple[str, ...], fragment_shaders: Tuple[str, ...], metadata: Dict[str, Any], allow_recompile: bool = False
) -> int:
pass

View file

@ -337,6 +337,110 @@ block_size(int program, GLuint block_index) {
return ans;
}
// Program metadata (uniform/attribute locations and UBO/array info, looked up by name) {{{
#define NAME program_metadata_map
#define KEY_TY const char*
#define VAL_TY ProgramMetadataEntry
#include "kitty-verstable.h"
static program_metadata_map program_layouts[arraysz(programs)];
static bool program_layouts_initialized[arraysz(programs)] = {0};
static void
clear_program_layout(int program) {
if (!program_layouts_initialized[program]) return;
program_metadata_map *m = program_layouts + program;
vt_create_for_loop(program_metadata_map_itr, itr, m) free((void*)itr.data->key);
vt_cleanup(m);
program_layouts_initialized[program] = false;
}
void
free_program_layouts(void) {
for (size_t i = 0; i < arraysz(program_layouts); i++) clear_program_layout((int)i);
}
static void
insert_program_metadata(int program, const char *name, ProgramMetadataEntry entry) {
program_metadata_map_itr itr = vt_insert(program_layouts + program, strdup(name), entry);
if (vt_is_end(itr)) fatal("Out of memory adding program metadata entry: %s", name);
}
static ProgramMetadataEntry*
program_metadata_entry(int program, const char *name, ProgramMetadataKind expected) {
program_metadata_map_itr itr = vt_get(program_layouts + program, name);
if (vt_is_end(itr)) fatal("No metadata entry named: %s for program: %d", name, program);
if (itr.data->val.kind != expected) fatal("The metadata entry named: %s for program: %d is not of the expected kind", name, program);
return &itr.data->val;
}
void
set_program_layout(int program, PyObject *metadata) {
clear_program_layout(program);
vt_init(program_layouts + program);
program_layouts_initialized[program] = true;
PyObject *key, *val; Py_ssize_t pos;
PyObject *loose_uniforms = PyDict_GetItemString(metadata, "loose_uniforms");
pos = 0;
while (PyDict_Next(loose_uniforms, &pos, &key, &val)) {
const char *actual_name = PyUnicode_AsUTF8(val);
ProgramMetadataEntry e = {.kind=PROGRAM_UNIFORM, .location=get_uniform_location(program, actual_name)};
insert_program_metadata(program, PyUnicode_AsUTF8(key), e);
}
PyObject *input_locations = PyDict_GetItemString(metadata, "input_locations");
pos = 0;
while (PyDict_Next(input_locations, &pos, &key, &val)) {
ProgramMetadataEntry e = {.kind=PROGRAM_ATTRIBUTE, .location=(GLint)PyLong_AsLong(val)};
insert_program_metadata(program, PyUnicode_AsUTF8(key), e);
}
PyObject *uniform_structs = PyDict_GetItemString(metadata, "uniform_structs");
PyObject *uniform_struct_names = PyDict_GetItemString(metadata, "uniform_struct_names");
pos = 0;
while (PyDict_Next(uniform_structs, &pos, &key, &val)) {
const char *glsl_block_name = PyUnicode_AsUTF8(PyDict_GetItem(uniform_struct_names, key));
GLuint index = block_index(program, glsl_block_name);
ProgramMetadataEntry be = {.kind=PROGRAM_BLOCK, .block={.size=block_size(program, index), .index=(GLint)index}};
insert_program_metadata(program, PyUnicode_AsUTF8(key), be);
PyObject *mkey, *mval; Py_ssize_t mpos = 0;
while (PyDict_Next(val, &mpos, &mkey, &mval)) {
const char *decl = PyUnicode_AsUTF8(mval);
const char *bracket = strchr(decl, '[');
if (!bracket) continue; // scalar block members are hand-mirrored in C structs, not queried here
char actual_name[256];
size_t n = MIN(sizeof(actual_name) - 1, (size_t)(bracket - decl));
memcpy(actual_name, decl, n); actual_name[n] = 0;
ProgramMetadataEntry ae = {.kind=PROGRAM_ARRAY, .array=get_uniform_array_information(program, actual_name)};
insert_program_metadata(program, PyUnicode_AsUTF8(mkey), ae);
}
}
}
GLint
program_uniform_location(int program, const char *name) {
return program_metadata_entry(program, name, PROGRAM_UNIFORM)->location;
}
GLint
program_attribute_location(int program, const char *name) {
return program_metadata_entry(program, name, PROGRAM_ATTRIBUTE)->location;
}
UniformBlock
program_uniform_block(int program, const char *name) {
return program_metadata_entry(program, name, PROGRAM_BLOCK)->block;
}
ArrayInformation
program_uniform_array(int program, const char *name) {
return program_metadata_entry(program, name, PROGRAM_ARRAY)->array;
}
// }}}
void
bind_program(int program) {
glUseProgram(programs[program].id);

View file

@ -33,6 +33,12 @@ typedef struct {
typedef struct Viewport { unsigned left, top, width, height; } Viewport;
typedef enum { PROGRAM_UNIFORM, PROGRAM_ATTRIBUTE, PROGRAM_BLOCK, PROGRAM_ARRAY } ProgramMetadataKind;
typedef struct ProgramMetadataEntry {
ProgramMetadataKind kind;
union { GLint location; UniformBlock block; ArrayInformation array; };
} ProgramMetadataEntry;
void gl_init(void);
const char* gl_version_string(void);
void set_gpu_viewport(unsigned w, unsigned h);
@ -51,6 +57,12 @@ GLint get_uniform_location(int program, const char *name);
GLint get_uniform_information(int program, const char *name, GLenum information_type);
ArrayInformation get_uniform_array_information(int program, const char *name);
GLint attrib_location(int program, const char *name);
void set_program_layout(int program, PyObject *metadata);
void free_program_layouts(void);
GLint program_uniform_location(int program, const char *name);
GLint program_attribute_location(int program, const char *name);
UniformBlock program_uniform_block(int program, const char *name);
ArrayInformation program_uniform_array(int program, const char *name);
ssize_t create_vao(void);
size_t add_buffer_to_vao(ssize_t vao_idx, GLenum usage);
void add_attribute_to_vao(ssize_t vao_idx, int location, GLint size, GLenum data_type, GLsizei stride, void *offset, GLuint divisor);

View file

@ -1,166 +0,0 @@
// generated by slang.py DO NOT EDIT
#include "gl.h"
typedef struct BgimageUniforms {
int background;
int image;
int positions;
int sizes;
int tiled;
} BgimageUniforms;
static inline void get_uniform_locations_bgimage(int program, BgimageUniforms *ans) {
ans->background = get_uniform_location(program, "background_0");
ans->image = get_uniform_location(program, "image_0");
ans->positions = get_uniform_location(program, "positions_0");
ans->sizes = get_uniform_location(program, "sizes_0");
ans->tiled = get_uniform_location(program, "tiled_0");
}
typedef struct BlitUniforms {
int dest_rect;
int image;
int src_rect;
} BlitUniforms;
static inline void get_uniform_locations_blit(int program, BlitUniforms *ans) {
ans->dest_rect = get_uniform_location(program, "dest_rect_0");
ans->image = get_uniform_location(program, "image_0");
ans->src_rect = get_uniform_location(program, "src_rect_0");
}
typedef struct BorderUniforms {
int background_opacity;
// Vertex Input locations
int rect;
int rect_color;
// Uniform block locations
UniformBlock Colors;
ArrayInformation colors;
UniformBlock GammaLUT;
ArrayInformation gamma_lut;
} BorderUniforms;
static inline void get_uniform_locations_border(int program, BorderUniforms *ans) {
ans->background_opacity = get_uniform_location(program, "background_opacity_0");
ans->rect = 0;
ans->rect_color = 1;
ans->Colors.index = block_index(program, "block_Colors_0");
ans->Colors.size = block_size(program, ans->Colors.index);
ans->colors = get_uniform_array_information(program, "colors_0");
ans->GammaLUT.index = block_index(program, "block_GammaLUT_0");
ans->GammaLUT.size = block_size(program, ans->GammaLUT.index);
ans->gamma_lut = get_uniform_array_information(program, "gamma_lut_0");
}
typedef struct CellUniforms {
int draw_bg_bitfield;
int sprite_decorations_map;
int sprites;
int text_contrast;
int text_gamma_adjustment;
// Vertex Input locations
int colors;
int is_selected;
int sprite_idx;
// Uniform block locations
UniformBlock CellRenderData;
UniformBlock ColorTable;
ArrayInformation color_table;
UniformBlock GammaLUT;
ArrayInformation gamma_lut;
} CellUniforms;
static inline void get_uniform_locations_cell(int program, CellUniforms *ans) {
ans->draw_bg_bitfield = get_uniform_location(program, "draw_bg_bitfield_0");
ans->sprite_decorations_map = get_uniform_location(program, "sprite_decorations_map_0");
ans->sprites = get_uniform_location(program, "sprites_0");
ans->text_contrast = get_uniform_location(program, "text_contrast_0");
ans->text_gamma_adjustment = get_uniform_location(program, "text_gamma_adjustment_0");
ans->colors = 0;
ans->is_selected = 2;
ans->sprite_idx = 1;
ans->CellRenderData.index = block_index(program, "block_CellRenderData_0");
ans->CellRenderData.size = block_size(program, ans->CellRenderData.index);
ans->ColorTable.index = block_index(program, "block_ColorTable_0");
ans->ColorTable.size = block_size(program, ans->ColorTable.index);
ans->color_table = get_uniform_array_information(program, "color_table_0");
ans->GammaLUT.index = block_index(program, "block_GammaLUT_0");
ans->GammaLUT.size = block_size(program, ans->GammaLUT.index);
ans->gamma_lut = get_uniform_array_information(program, "gamma_lut_0");
}
typedef struct GraphicsUniforms {
int amask_bg_premult;
int amask_fg;
int dest_rect;
int extra_alpha;
int image;
int src_rect;
} GraphicsUniforms;
static inline void get_uniform_locations_graphics(int program, GraphicsUniforms *ans) {
ans->amask_bg_premult = get_uniform_location(program, "amask_bg_premult_0");
ans->amask_fg = get_uniform_location(program, "amask_fg_0");
ans->dest_rect = get_uniform_location(program, "dest_rect_0");
ans->extra_alpha = get_uniform_location(program, "extra_alpha_0");
ans->image = get_uniform_location(program, "image_0");
ans->src_rect = get_uniform_location(program, "src_rect_0");
}
typedef struct Rounded_rectUniforms {
int background_color;
int color;
int params;
int rect;
} Rounded_rectUniforms;
static inline void get_uniform_locations_rounded_rect(int program, Rounded_rectUniforms *ans) {
ans->background_color = get_uniform_location(program, "background_color_0");
ans->color = get_uniform_location(program, "color_0");
ans->params = get_uniform_location(program, "params_0");
ans->rect = get_uniform_location(program, "rect_0");
}
typedef struct ScreenshotUniforms {
int dest_rect;
int image;
int src_rect;
int src_size;
} ScreenshotUniforms;
static inline void get_uniform_locations_screenshot(int program, ScreenshotUniforms *ans) {
ans->dest_rect = get_uniform_location(program, "dest_rect_0");
ans->image = get_uniform_location(program, "image_0");
ans->src_rect = get_uniform_location(program, "src_rect_0");
ans->src_size = get_uniform_location(program, "src_size_0");
}
typedef struct TintUniforms {
int edges;
int tint_color;
} TintUniforms;
static inline void get_uniform_locations_tint(int program, TintUniforms *ans) {
ans->edges = get_uniform_location(program, "edges_0");
ans->tint_color = get_uniform_location(program, "tint_color_0");
}
typedef struct TrailUniforms {
int cursor_edge_x;
int cursor_edge_y;
int trail_color;
int trail_opacity;
int x_coords;
int y_coords;
} TrailUniforms;
static inline void get_uniform_locations_trail(int program, TrailUniforms *ans) {
ans->cursor_edge_x = get_uniform_location(program, "cursor_edge_x_0");
ans->cursor_edge_y = get_uniform_location(program, "cursor_edge_y_0");
ans->trail_color = get_uniform_location(program, "trail_color_0");
ans->trail_opacity = get_uniform_location(program, "trail_opacity_0");
ans->x_coords = get_uniform_location(program, "x_coords_0");
ans->y_coords = get_uniform_location(program, "y_coords_0");
}

View file

@ -14,7 +14,6 @@
#include "text-cache.h"
#include "window_logo.h"
#include "srgb_gamma.h"
#include "glsl-uniforms.h"
#include "state.h"
enum {
@ -296,11 +295,6 @@ send_image_to_gpu(GLuint *tex_id, const void* data, GLsizei width, GLsizei heigh
// }}}
// Rounded rect {{{
typedef struct {
Rounded_rectUniforms uniforms;
} RoundedRectProgramLayout;
static RoundedRectProgramLayout rounded_rect_program_layout;
static double
thickness_as_float(const OSWindow *os_window, unsigned level) {
level = MIN(level, arraysz(OPT(box_drawing_scale)));
@ -318,12 +312,12 @@ draw_rounded_rect(
) {
float thickness = (float)thickness_as_float(os_window, thickness_level);
bind_program(ROUNDED_RECT_PROGRAM);
color_vec4(rounded_rect_program_layout.uniforms.color, srgb_color, 1.f);
color_vec4(rounded_rect_program_layout.uniforms.background_color, srgb_background, bg_alpha);
color_vec4(program_uniform_location(ROUNDED_RECT_PROGRAM, "color"), srgb_color, 1.f);
color_vec4(program_uniform_location(ROUNDED_RECT_PROGRAM, "background_color"), srgb_background, bg_alpha);
// y co-ord has to be changed to co-ord system with origin at bottom left
float y = (float)framebuffer_height - (float)(rect.top + rect.height);
glUniform4f(rounded_rect_program_layout.uniforms.rect, rect.left, y, rect.width, rect.height);
glUniform2f(rounded_rect_program_layout.uniforms.params, thickness, corner_radius_px);
glUniform4f(program_uniform_location(ROUNDED_RECT_PROGRAM, "rect"), rect.left, y, rect.width, rect.height);
glUniform2f(program_uniform_location(ROUNDED_RECT_PROGRAM, "params"), thickness, corner_radius_px);
save_viewport_using_top_left_origin(rect.left, rect.top, rect.width, rect.height, framebuffer_height);
draw_quad(true, 0);
restore_viewport();
@ -338,46 +332,6 @@ enum { GAMMA_LUT_GLOBAL_BUFFER, BORDER_COLORS_GLOBAL_BUFFER };
// its vertex attribute/array facilities are unused.
static ssize_t shader_globals_vao_idx = -1;
typedef struct {
CellUniforms uniforms;
} CellProgramLayout;
static CellProgramLayout cell_program_layouts[NUM_PROGRAMS];
typedef struct {
GraphicsUniforms uniforms;
} GraphicsProgramLayout;
static GraphicsProgramLayout graphics_program_layouts[NUM_PROGRAMS];
typedef struct {
BgimageUniforms uniforms;
} BGImageProgramLayout;
static BGImageProgramLayout bgimage_program_layout;
typedef struct {
TintUniforms uniforms;
} TintProgramLayout;
static TintProgramLayout tint_program_layout;
typedef struct {
TrailUniforms uniforms;
} TrailProgramLayout;
static TrailProgramLayout trail_program_layout;
typedef struct {
BlitUniforms uniforms;
} BlitProgramLayout;
static BlitProgramLayout blit_program_layout;
typedef struct {
ScreenshotUniforms uniforms;
} ScreenshotProgramLayout;
static ScreenshotProgramLayout screenshot_program_layout;
typedef struct BorderProgramLayout {
BorderUniforms uniforms;
} BorderProgramLayout;
static BorderProgramLayout border_program_layout;
static void
write_float_array_to_ubo(void *dest, const GLfloat *src, size_t count, const ArrayInformation *ai) {
GLint stride = MAX((GLint)sizeof(GLfloat), ai->stride);
@ -396,11 +350,13 @@ static void
init_cell_program(void) {
GLint gamma_lut_buf_size = 0;
for (int i = CELL_PROGRAM; i < CELL_PROGRAM_SENTINEL; i++) {
get_uniform_locations_cell(i, &cell_program_layouts[i].uniforms);
glUniformBlockBinding(program_id(i), cell_program_layouts[i].uniforms.CellRenderData.index, CELL_RENDER_DATA_BINDING_POINT);
glUniformBlockBinding(program_id(i), cell_program_layouts[i].uniforms.ColorTable.index, COLOR_TABLE_BINDING_POINT);
glUniformBlockBinding(program_id(i), cell_program_layouts[i].uniforms.GammaLUT.index, GAMMA_LUT_BINDING_POINT);
gamma_lut_buf_size = MAX(gamma_lut_buf_size, cell_program_layouts[i].uniforms.GammaLUT.size);
UniformBlock crd = program_uniform_block(i, "CellRenderData");
glUniformBlockBinding(program_id(i), crd.index, CELL_RENDER_DATA_BINDING_POINT);
UniformBlock ct = program_uniform_block(i, "ColorTable");
glUniformBlockBinding(program_id(i), ct.index, COLOR_TABLE_BINDING_POINT);
UniformBlock glut = program_uniform_block(i, "GammaLUT");
glUniformBlockBinding(program_id(i), glut.index, GAMMA_LUT_BINDING_POINT);
gamma_lut_buf_size = MAX(gamma_lut_buf_size, glut.size);
}
// Sanity check to ensure the attribute location binding worked
@ -409,31 +365,23 @@ init_cell_program(void) {
C(p, colors, 0); C(p, sprite_idx, 1); C(p, is_selected, 2); C(p, decorations_sprite_map, 3);
}
#undef C
for (int i = GRAPHICS_PROGRAM; i <= GRAPHICS_ALPHA_MASK_PROGRAM; i++) {
get_uniform_locations_graphics(i, &graphics_program_layouts[i].uniforms);
}
get_uniform_locations_bgimage(BGIMAGE_PROGRAM, &bgimage_program_layout.uniforms);
get_uniform_locations_tint(TINT_PROGRAM, &tint_program_layout.uniforms);
get_uniform_locations_trail(TRAIL_PROGRAM, &trail_program_layout.uniforms);
get_uniform_locations_blit(BLIT_PROGRAM, &blit_program_layout.uniforms);
get_uniform_locations_screenshot(SCREENSHOT_PROGRAM, &screenshot_program_layout.uniforms);
get_uniform_locations_rounded_rect(ROUNDED_RECT_PROGRAM, &rounded_rect_program_layout.uniforms);
get_uniform_locations_border(BORDERS_PROGRAM, &border_program_layout.uniforms);
glUniformBlockBinding(program_id(BORDERS_PROGRAM), border_program_layout.uniforms.Colors.index, BORDER_COLORS_BINDING_POINT);
glUniformBlockBinding(program_id(BORDERS_PROGRAM), border_program_layout.uniforms.GammaLUT.index, GAMMA_LUT_BINDING_POINT);
UniformBlock border_colors = program_uniform_block(BORDERS_PROGRAM, "Colors");
glUniformBlockBinding(program_id(BORDERS_PROGRAM), border_colors.index, BORDER_COLORS_BINDING_POINT);
UniformBlock border_glut = program_uniform_block(BORDERS_PROGRAM, "GammaLUT");
glUniformBlockBinding(program_id(BORDERS_PROGRAM), border_glut.index, GAMMA_LUT_BINDING_POINT);
// The gamma LUT is a constant, shared amongst all the programs that use it via a single UBO.
if (shader_globals_vao_idx == -1) {
shader_globals_vao_idx = create_vao();
add_buffer_to_vao(shader_globals_vao_idx, GL_UNIFORM_BUFFER);
add_buffer_to_vao(shader_globals_vao_idx, GL_UNIFORM_BUFFER);
gamma_lut_buf_size = MAX(gamma_lut_buf_size, border_program_layout.uniforms.GammaLUT.size);
gamma_lut_buf_size = MAX(gamma_lut_buf_size, border_glut.size);
void *gamma_lut_buf = alloc_and_map_vao_buffer(shader_globals_vao_idx, gamma_lut_buf_size, GAMMA_LUT_GLOBAL_BUFFER, false);
const ArrayInformation *a = &cell_program_layouts[CELL_PROGRAM].uniforms.gamma_lut;
write_float_array_to_ubo(gamma_lut_buf, srgb_lut, arraysz(srgb_lut), a);
const ArrayInformation a = program_uniform_array(CELL_PROGRAM, "gamma_lut");
write_float_array_to_ubo(gamma_lut_buf, srgb_lut, arraysz(srgb_lut), &a);
unmap_vao_buffer(shader_globals_vao_idx, GAMMA_LUT_GLOBAL_BUFFER);
// The border colors change on every draw, but are shared amongst all border VAOs (only one is ever drawn at a time)
alloc_vao_buffer(shader_globals_vao_idx, border_program_layout.uniforms.Colors.size, BORDER_COLORS_GLOBAL_BUFFER, GL_STREAM_DRAW);
alloc_vao_buffer(shader_globals_vao_idx, border_colors.size, BORDER_COLORS_GLOBAL_BUFFER, GL_STREAM_DRAW);
bind_vao_uniform_buffer(shader_globals_vao_idx, GAMMA_LUT_GLOBAL_BUFFER, GAMMA_LUT_BINDING_POINT);
bind_vao_uniform_buffer(shader_globals_vao_idx, BORDER_COLORS_GLOBAL_BUFFER, BORDER_COLORS_BINDING_POINT);
}
@ -444,24 +392,23 @@ init_cell_program(void) {
ssize_t
create_cell_vao(void) {
ssize_t vao_idx = create_vao();
const struct CellUniforms *u = &cell_program_layouts[CELL_PROGRAM].uniforms;
#define A(name, size, dtype, offset, stride) \
add_attribute_to_vao(vao_idx, u->name, \
add_attribute_to_vao(vao_idx, program_attribute_location(CELL_PROGRAM, name), \
/*size=*/size, /*dtype=*/dtype, /*stride=*/stride, /*offset=*/offset, /*divisor=*/1);
#define A1(name, size, dtype, offset) A(name, size, dtype, (void*)(offsetof(GPUCell, offset)), sizeof(GPUCell))
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
A1(sprite_idx, 2, GL_UNSIGNED_INT, sprite_idx);
A1(colors, 3, GL_UNSIGNED_INT, fg);
A1("sprite_idx", 2, GL_UNSIGNED_INT, sprite_idx);
A1("colors", 3, GL_UNSIGNED_INT, fg);
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
A(is_selected, 1, GL_UNSIGNED_BYTE, NULL, 0);
A("is_selected", 1, GL_UNSIGNED_BYTE, NULL, 0);
size_t bufnum = add_buffer_to_vao(vao_idx, GL_UNIFORM_BUFFER);
alloc_vao_buffer(vao_idx, cell_program_layouts[CELL_PROGRAM].uniforms.CellRenderData.size, bufnum, GL_STREAM_DRAW);
alloc_vao_buffer(vao_idx, program_uniform_block(CELL_PROGRAM, "CellRenderData").size, bufnum, GL_STREAM_DRAW);
size_t ctbufnum = add_buffer_to_vao(vao_idx, GL_UNIFORM_BUFFER);
alloc_vao_buffer(vao_idx, cell_program_layouts[CELL_PROGRAM].uniforms.ColorTable.size, ctbufnum, GL_STATIC_DRAW);
alloc_vao_buffer(vao_idx, program_uniform_block(CELL_PROGRAM, "ColorTable").size, ctbufnum, GL_STATIC_DRAW);
return vao_idx;
#undef A
@ -506,13 +453,13 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, i
// Send the uniform data
ColorProfile *cp = screen->paused_rendering.expires_at ? &screen->paused_rendering.color_profile : screen->color_profile;
if (cp->dirty || screen->reload_all_gpu_data) {
const ArrayInformation *ai = &cell_program_layouts[CELL_PROGRAM].uniforms.color_table;
uint8_t *base = (uint8_t*)map_vao_buffer_for_write_only(vao_idx, color_table_buf, 0, cell_program_layouts[CELL_PROGRAM].uniforms.ColorTable.size);
GLuint *ct_buf = (GLuint*)(base + ai->offset);
copy_color_table_to_buffer(cp, ct_buf, 0, ai->stride / sizeof(GLuint));
const ArrayInformation ai = program_uniform_array(CELL_PROGRAM, "color_table");
uint8_t *base = (uint8_t*)map_vao_buffer_for_write_only(vao_idx, color_table_buf, 0, program_uniform_block(CELL_PROGRAM, "ColorTable").size);
GLuint *ct_buf = (GLuint*)(base + ai.offset);
copy_color_table_to_buffer(cp, ct_buf, 0, ai.stride / sizeof(GLuint));
unmap_vao_buffer(vao_idx, color_table_buf);
}
struct GPUCellRenderData *rd = (struct GPUCellRenderData*)map_vao_buffer_for_write_only(vao_idx, uniform_buffer, 0, cell_program_layouts[CELL_PROGRAM].uniforms.CellRenderData.size);
struct GPUCellRenderData *rd = (struct GPUCellRenderData*)map_vao_buffer_for_write_only(vao_idx, uniform_buffer, 0, program_uniform_block(CELL_PROGRAM, "CellRenderData").size);
#define COLOR(name) colorprofile_to_color(cp, cp->overridden.name, cp->configured.name).rgb
rd->default_fg = COLOR(default_fg);
rd->highlight_fg = COLOR(highlight_fg); rd->highlight_bg = COLOR(highlight_bg);
@ -682,17 +629,18 @@ cell_prepare_to_render(ssize_t vao_idx, Screen *screen, FONTS_DATA_HANDLE fonts_
static void
draw_graphics(int program, ImageRenderData *data, GLuint start, GLuint count, float extra_alpha) {
bind_program(program);
if (program != GRAPHICS_ALPHA_MASK_PROGRAM) glUniform1f(graphics_program_layouts[program].uniforms.extra_alpha, extra_alpha);
if (program != GRAPHICS_ALPHA_MASK_PROGRAM) glUniform1f(program_uniform_location(program, "extra_alpha"), extra_alpha);
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
GraphicsUniforms *u = &graphics_program_layouts[program].uniforms;
GLint src_rect_loc = program_uniform_location(program, "src_rect");
GLint dest_rect_loc = program_uniform_location(program, "dest_rect");
for (GLuint i=0; i < count;) {
ImageRenderData *group = data + start + i;
glBindTexture(GL_TEXTURE_2D, group->texture_id);
if (group->group_count == 0) { i++; continue; }
for (GLuint k=0; k < group->group_count; k++, i++) {
ImageRenderData *rd = data + start + i;
glUniform4f(u->src_rect, rd->src_rect.left, rd->src_rect.top, rd->src_rect.right, rd->src_rect.bottom);
glUniform4f(u->dest_rect, rd->dest_rect.left, rd->dest_rect.top, rd->dest_rect.right, rd->dest_rect.bottom);
glUniform4f(src_rect_loc, rd->src_rect.left, rd->src_rect.top, rd->src_rect.right, rd->src_rect.bottom);
glUniform4f(dest_rect_loc, rd->dest_rect.left, rd->dest_rect.top, rd->dest_rect.right, rd->dest_rect.bottom);
draw_quad(true, 0);
}
}
@ -754,17 +702,17 @@ set_cell_uniforms(bool force) {
float text_contrast = 1.0f + OPT(text_contrast) * 0.01f;
float text_gamma_adjustment = OPT(text_gamma_adjustment) < 0.01f ? 1.0f : 1.0f / OPT(text_gamma_adjustment);
for (int i = GRAPHICS_PROGRAM; i <= GRAPHICS_ALPHA_MASK_PROGRAM; i++) {
bind_program(i); glUniform1i(graphics_program_layouts[i].uniforms.image, GRAPHICS_UNIT);
bind_program(i); glUniform1i(program_uniform_location(i, "image"), GRAPHICS_UNIT);
}
for (int i = CELL_PROGRAM; i < CELL_PROGRAM_SENTINEL; i++) {
bind_program(i); const CellUniforms *cu = &cell_program_layouts[i].uniforms;
glUniform1i(cu->sprites, SPRITE_MAP_UNIT);
glUniform1i(cu->sprite_decorations_map, SPRITE_DECORATIONS_MAP_UNIT);
glUniform1f(cu->text_contrast, text_contrast);
glUniform1f(cu->text_gamma_adjustment, text_gamma_adjustment);
bind_program(i);
glUniform1i(program_uniform_location(i, "sprites"), SPRITE_MAP_UNIT);
glUniform1i(program_uniform_location(i, "sprite_decorations_map"), SPRITE_DECORATIONS_MAP_UNIT);
glUniform1f(program_uniform_location(i, "text_contrast"), text_contrast);
glUniform1f(program_uniform_location(i, "text_gamma_adjustment"), text_gamma_adjustment);
}
bind_program(BLIT_PROGRAM); glUniform1i(blit_program_layout.uniforms.image, GRAPHICS_UNIT);
bind_program(SCREENSHOT_PROGRAM); glUniform1i(screenshot_program_layout.uniforms.image, GRAPHICS_UNIT);
bind_program(BLIT_PROGRAM); glUniform1i(program_uniform_location(BLIT_PROGRAM, "image"), GRAPHICS_UNIT);
bind_program(SCREENSHOT_PROGRAM); glUniform1i(program_uniform_location(SCREENSHOT_PROGRAM, "image"), GRAPHICS_UNIT);
constants_set = true;
}
}
@ -803,9 +751,9 @@ draw_visual_bell_flash(GLfloat intensity, const color_type flash) {
#undef C
#define C(x) (x * intensity * attenuation)
if (max_channel > 0.45) attenuation = 0.6f; // light color
glUniform4f(tint_program_layout.uniforms.tint_color, C(r), C(g), C(b), C(1));
glUniform4f(program_uniform_location(TINT_PROGRAM, "tint_color"), C(r), C(g), C(b), C(1));
#undef C
glUniform4f(tint_program_layout.uniforms.edges, -1, 1, 1, -1);
glUniform4f(program_uniform_location(TINT_PROGRAM, "edges"), -1, 1, 1, -1);
draw_quad(true, 0);
}
@ -846,9 +794,9 @@ draw_drag_preview_overlay(const UIRenderData *ui) {
float a = intensity * 0.25f;
color_type hint = get_flash_color(screen);
#define C(shift) (srgb_color((hint >> shift) & 0xFF) * a)
glUniform4f(tint_program_layout.uniforms.tint_color, C(16), C(8), C(0), a);
glUniform4f(program_uniform_location(TINT_PROGRAM, "tint_color"), C(16), C(8), C(0), a);
#undef C
glUniform4f(tint_program_layout.uniforms.edges, left, top, right, bottom);
glUniform4f(program_uniform_location(TINT_PROGRAM, "edges"), left, top, right, bottom);
draw_quad(true, 0);
}
@ -992,10 +940,10 @@ draw_window_number(const UIRenderData *ui) {
bind_program(GRAPHICS_ALPHA_MASK_PROGRAM);
ImageRenderData *ird = load_alpha_mask_texture(lr.width_px, lr.height_px, lr.canvas);
gpu_data_for_image(ird, -1, 1, 1, -1);
glUniform1i(graphics_program_layouts[GRAPHICS_ALPHA_MASK_PROGRAM].uniforms.image, GRAPHICS_UNIT);
glUniform1i(program_uniform_location(GRAPHICS_ALPHA_MASK_PROGRAM, "image"), GRAPHICS_UNIT);
color_type digit_color = colorprofile_to_color_with_fallback(ui->screen->color_profile, ui->screen->color_profile->overridden.highlight_bg, ui->screen->color_profile->configured.highlight_bg, ui->screen->color_profile->overridden.default_fg, ui->screen->color_profile->configured.default_fg);
color_vec3(graphics_program_layouts[GRAPHICS_ALPHA_MASK_PROGRAM].uniforms.amask_fg, digit_color);
glUniform4f(graphics_program_layouts[GRAPHICS_ALPHA_MASK_PROGRAM].uniforms.amask_bg_premult, 0.f, 0.f, 0.f, 0.f);
color_vec3(program_uniform_location(GRAPHICS_ALPHA_MASK_PROGRAM, "amask_fg"), digit_color);
glUniform4f(program_uniform_location(GRAPHICS_ALPHA_MASK_PROGRAM, "amask_bg_premult"), 0.f, 0.f, 0.f, 0.f);
save_viewport_using_top_left_origin(
ui->screen_left + letter_x, ui->screen_top + letter_y, lr.width_px, lr.height_px, ui->full_framebuffer_height);
draw_graphics(GRAPHICS_ALPHA_MASK_PROGRAM, ird, 0, 1, 1.f);
@ -1009,7 +957,7 @@ set_color_uniform_with_opacity(color_type color, float opacity) {
float r = srgb_color((color >> 16) & 0xFF) * opacity;
float g = srgb_color((color >> 8) & 0xFF) * opacity;
float b = srgb_color(color & 0xFF) * opacity;
glUniform4f(tint_program_layout.uniforms.tint_color, r, g, b, opacity);
glUniform4f(program_uniform_location(TINT_PROGRAM, "tint_color"), r, g, b, opacity);
}
static color_type
@ -1080,7 +1028,7 @@ draw_scrollbar(const UIRenderData *ui) {
if (track_opacity > 0) {
bind_program(TINT_PROGRAM);
set_color_uniform_with_opacity(track_color, track_opacity);
glUniform4f(tint_program_layout.uniforms.edges, -1.f, 1.f, 1.f, -1.f);
glUniform4f(program_uniform_location(TINT_PROGRAM, "edges"), -1.f, 1.f, 1.f, -1.f);
draw_quad(true, 0);
}
@ -1093,16 +1041,16 @@ draw_scrollbar(const UIRenderData *ui) {
restore_viewport();
bind_program(ROUNDED_RECT_PROGRAM);
color_vec4(rounded_rect_program_layout.uniforms.color, bar_color, opacity);
color_vec4(rounded_rect_program_layout.uniforms.background_color, 0, 0.0f);
color_vec4(program_uniform_location(ROUNDED_RECT_PROGRAM, "color"), bar_color, opacity);
color_vec4(program_uniform_location(ROUNDED_RECT_PROGRAM, "background_color"), 0, 0.0f);
float y = (float)ui->full_framebuffer_height - (float)(thumb_top_px + thumb_height_px);
glUniform4f(rounded_rect_program_layout.uniforms.rect,
glUniform4f(program_uniform_location(ROUNDED_RECT_PROGRAM, "rect"),
(float)scrollbar_left, y,
(float)scrollbar_width_px, (float)thumb_height_px);
float thickness = (float)MAX(scrollbar_width_px, thumb_height_px);
glUniform2f(rounded_rect_program_layout.uniforms.params, thickness, (float)scrollbar_radius);
glUniform2f(program_uniform_location(ROUNDED_RECT_PROGRAM, "params"), thickness, (float)scrollbar_radius);
save_viewport_using_top_left_origin(scrollbar_left, thumb_top_px,
scrollbar_width_px, thumb_height_px,
@ -1111,7 +1059,7 @@ draw_scrollbar(const UIRenderData *ui) {
restore_viewport();
} else {
set_color_uniform_with_opacity(bar_color, opacity);
glUniform4f(tint_program_layout.uniforms.edges, -1.f, thumb_top_gl, 1.f, thumb_bottom_gl);
glUniform4f(program_uniform_location(TINT_PROGRAM, "edges"), -1.f, thumb_top_gl, 1.f, thumb_bottom_gl);
draw_quad(true, 0);
restore_viewport();
}
@ -1154,16 +1102,16 @@ draw_progress_handle(const UIRenderData *ui, color_type bar_color, float opacity
if (bar_radius > 0) {
bind_program(ROUNDED_RECT_PROGRAM);
color_vec4(rounded_rect_program_layout.uniforms.color, bar_color, opacity);
color_vec4(rounded_rect_program_layout.uniforms.background_color, 0, 0.0f);
color_vec4(program_uniform_location(ROUNDED_RECT_PROGRAM, "color"), bar_color, opacity);
color_vec4(program_uniform_location(ROUNDED_RECT_PROGRAM, "background_color"), 0, 0.0f);
float y = (float)ui->full_framebuffer_height - (float)(handle_top + handle_h);
glUniform4f(rounded_rect_program_layout.uniforms.rect,
glUniform4f(program_uniform_location(ROUNDED_RECT_PROGRAM, "rect"),
(float)handle_left, y,
(float)handle_w, (float)handle_h);
float thickness = (float)(is_horizontal ? handle_h : handle_w);
glUniform2f(rounded_rect_program_layout.uniforms.params, thickness, (float)bar_radius);
glUniform2f(program_uniform_location(ROUNDED_RECT_PROGRAM, "params"), thickness, (float)bar_radius);
save_viewport_using_top_left_origin(handle_left, handle_top, handle_w, handle_h, ui->full_framebuffer_height);
draw_quad(true, 0);
@ -1180,11 +1128,11 @@ draw_progress_handle(const UIRenderData *ui, color_type bar_color, float opacity
if (is_horizontal) {
// edges: left, top, right, bottom
save_viewport_using_top_left_origin(track_left, track_top, track_width, track_height, ui->full_framebuffer_height);
glUniform4f(tint_program_layout.uniforms.edges, start_gl, 1.f, end_gl, -1.f);
glUniform4f(program_uniform_location(TINT_PROGRAM, "edges"), start_gl, 1.f, end_gl, -1.f);
} else {
save_viewport_using_top_left_origin(track_left, track_top, track_width, track_height, ui->full_framebuffer_height);
// For vertical: start_gl is top in GL coords (inverted y), so bottom_gl = -end_gl, top_gl = -start_gl
glUniform4f(tint_program_layout.uniforms.edges, -1.f, -start_gl, 1.f, -end_gl);
glUniform4f(program_uniform_location(TINT_PROGRAM, "edges"), -1.f, -start_gl, 1.f, -end_gl);
}
draw_quad(true, 0);
restore_viewport();
@ -1269,7 +1217,7 @@ draw_progress_bar(const UIRenderData *ui) {
if (track_opacity > 0) {
bind_program(TINT_PROGRAM);
set_color_uniform_with_opacity(track_color, track_opacity);
glUniform4f(tint_program_layout.uniforms.edges, -1.f, 1.f, 1.f, -1.f);
glUniform4f(program_uniform_location(TINT_PROGRAM, "edges"), -1.f, 1.f, 1.f, -1.f);
draw_quad(true, 0);
}
restore_viewport();
@ -1366,7 +1314,7 @@ call_cell_program(int program, const UIRenderData *ui, ssize_t vao_idx, bool for
CELL_BUFFERS;
bind_vao_uniform_buffer(vao_idx, uniform_buffer, CELL_RENDER_DATA_BINDING_POINT);
bind_vao_uniform_buffer(vao_idx, color_table_buffer, COLOR_TABLE_BINDING_POINT);
glUniform1ui(cell_program_layouts[program].uniforms.draw_bg_bitfield, draw_bg_bitfield);
glUniform1ui(program_uniform_location(program, "draw_bg_bitfield"), draw_bg_bitfield);
if (for_final_output) glEnable(GL_FRAMEBUFFER_SRGB);
draw_quad(!for_final_output, render_lines_for_screen(ui->screen) * ui->screen->columns);
if (for_final_output) glDisable(GL_FRAMEBUFFER_SRGB);
@ -1380,8 +1328,8 @@ draw_cells_without_layers(const UIRenderData *ui, ssize_t vao_idx) {
static void
draw_tint(const UIRenderData *ui) {
bind_program(TINT_PROGRAM);
color_vec4_premult(tint_program_layout.uniforms.tint_color, ui->background_color, OPT(background_tint));
glUniform4f(tint_program_layout.uniforms.edges, -1, 1, 1, -1);
color_vec4_premult(program_uniform_location(TINT_PROGRAM, "tint_color"), ui->background_color, OPT(background_tint));
glUniform4f(program_uniform_location(TINT_PROGRAM, "edges"), -1, 1, 1, -1);
draw_quad(true, 0);
}
@ -1489,10 +1437,9 @@ create_border_vao(void) {
ssize_t vao_idx = create_vao();
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
const BorderUniforms *u = &border_program_layout.uniforms;
add_attribute_to_vao(vao_idx, u->rect,
add_attribute_to_vao(vao_idx, program_attribute_location(BORDERS_PROGRAM, "rect"),
/*size=*/4, /*dtype=*/GL_FLOAT, /*stride=*/sizeof(BorderRect), /*offset=*/(void*)offsetof(BorderRect, left), /*divisor=*/1);
add_attribute_to_vao(vao_idx, u->rect_color,
add_attribute_to_vao(vao_idx, program_attribute_location(BORDERS_PROGRAM, "rect_color"),
/*size=*/1, /*dtype=*/GL_UNSIGNED_INT, /*stride=*/sizeof(BorderRect), /*offset=*/(void*)(offsetof(BorderRect, color)), /*divisor=*/1);
return vao_idx;
@ -1517,10 +1464,11 @@ draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_bu
OPT(bell_border_color), OPT(tab_bar_background), OPT(tab_bar_margin_color),
w->tab_bar_edge_color.left, w->tab_bar_edge_color.right
};
void *colors_buf = map_vao_buffer_for_write_only(shader_globals_vao_idx, BORDER_COLORS_GLOBAL_BUFFER, 0, border_program_layout.uniforms.Colors.size);
write_uint_array_to_ubo(colors_buf, colors, arraysz(colors), &border_program_layout.uniforms.colors);
void *colors_buf = map_vao_buffer_for_write_only(shader_globals_vao_idx, BORDER_COLORS_GLOBAL_BUFFER, 0, program_uniform_block(BORDERS_PROGRAM, "Colors").size);
const ArrayInformation border_colors_array = program_uniform_array(BORDERS_PROGRAM, "colors");
write_uint_array_to_ubo(colors_buf, colors, arraysz(colors), &border_colors_array);
unmap_vao_buffer(shader_globals_vao_idx, BORDER_COLORS_GLOBAL_BUFFER);
glUniform1f(border_program_layout.uniforms.background_opacity, background_opacity);
glUniform1f(program_uniform_location(BORDERS_PROGRAM, "background_opacity"), background_opacity);
if (!w->needs_layers) glEnable(GL_FRAMEBUFFER_SRGB);
draw_quad(has_background_image, num_border_rects);
if (!w->needs_layers) glDisable(GL_FRAMEBUFFER_SRGB);
@ -1534,19 +1482,19 @@ void
draw_cursor_trail(CursorTrail *trail, Window *active_window) {
bind_program(TRAIL_PROGRAM);
glUniform4fv(trail_program_layout.uniforms.x_coords, 1, trail->corner_x);
glUniform4fv(trail_program_layout.uniforms.y_coords, 1, trail->corner_y);
glUniform4fv(program_uniform_location(TRAIL_PROGRAM, "x_coords"), 1, trail->corner_x);
glUniform4fv(program_uniform_location(TRAIL_PROGRAM, "y_coords"), 1, trail->corner_y);
glUniform2fv(trail_program_layout.uniforms.cursor_edge_x, 1, trail->cursor_edge_x);
glUniform2fv(trail_program_layout.uniforms.cursor_edge_y, 1, trail->cursor_edge_y);
glUniform2fv(program_uniform_location(TRAIL_PROGRAM, "cursor_edge_x"), 1, trail->cursor_edge_x);
glUniform2fv(program_uniform_location(TRAIL_PROGRAM, "cursor_edge_y"), 1, trail->cursor_edge_y);
color_type trail_color = OPT(cursor_trail_color);
if (trail_color == 0) { // 0 means "none" was specified
trail_color = active_window ? active_window->render_data.screen->last_rendered.cursor_bg : OPT(foreground);
}
color_vec3(trail_program_layout.uniforms.trail_color, trail_color);
color_vec3(program_uniform_location(TRAIL_PROGRAM, "trail_color"), trail_color);
glUniform1f(trail_program_layout.uniforms.trail_opacity, trail->opacity);
glUniform1f(program_uniform_location(TRAIL_PROGRAM, "trail_opacity"), trail->opacity);
draw_quad(true, 0);
unbind_program();
@ -1597,11 +1545,11 @@ draw_bg_image(OSWindow *os_window, Tab *tab) {
bind_program(BGIMAGE_PROGRAM);
// altough we dont use this VO we need to ensure *some* VAO is bound at this point.
bind_vertex_array(tab->border_rects.vao_idx);
glUniform4f(bgimage_program_layout.uniforms.sizes, vwidth, vheight, iwidth, iheight);
glUniform1f(bgimage_program_layout.uniforms.tiled, tiled);
glUniform4f(bgimage_program_layout.uniforms.positions, left, top, right, bottom);
glUniform1i(bgimage_program_layout.uniforms.image, GRAPHICS_UNIT);
color_vec4(bgimage_program_layout.uniforms.background, s.bgcolor, s.opacity);
glUniform4f(program_uniform_location(BGIMAGE_PROGRAM, "sizes"), vwidth, vheight, iwidth, iheight);
glUniform1f(program_uniform_location(BGIMAGE_PROGRAM, "tiled"), tiled);
glUniform4f(program_uniform_location(BGIMAGE_PROGRAM, "positions"), left, top, right, bottom);
glUniform1i(program_uniform_location(BGIMAGE_PROGRAM, "image"), GRAPHICS_UNIT);
color_vec4(program_uniform_location(BGIMAGE_PROGRAM, "background"), s.bgcolor, s.opacity);
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
glBindTexture(GL_TEXTURE_2D, bg->texture_id);
draw_quad(false, 0);
@ -1621,9 +1569,9 @@ draw_centered_alpha_mask(size_t screen_width, size_t screen_height, size_t width
ImageRenderData *data = load_alpha_mask_texture(width, height, canvas);
gpu_data_for_centered_image(data, screen_width, screen_height, width, height);
bind_program(GRAPHICS_ALPHA_MASK_PROGRAM);
glUniform1i(graphics_program_layouts[GRAPHICS_ALPHA_MASK_PROGRAM].uniforms.image, GRAPHICS_UNIT);
color_vec3(graphics_program_layouts[GRAPHICS_ALPHA_MASK_PROGRAM].uniforms.amask_fg, OPT(foreground));
color_vec4_premult(graphics_program_layouts[GRAPHICS_ALPHA_MASK_PROGRAM].uniforms.amask_bg_premult, OPT(background), background_opacity);
glUniform1i(program_uniform_location(GRAPHICS_ALPHA_MASK_PROGRAM, "image"), GRAPHICS_UNIT);
color_vec3(program_uniform_location(GRAPHICS_ALPHA_MASK_PROGRAM, "amask_fg"), OPT(foreground));
color_vec4_premult(program_uniform_location(GRAPHICS_ALPHA_MASK_PROGRAM, "amask_bg_premult"), OPT(background), background_opacity);
draw_graphics(GRAPHICS_ALPHA_MASK_PROGRAM, data, 0, 1, 1.0);
}
@ -1700,8 +1648,8 @@ stop_os_window_rendering(OSWindow *os_window, Tab *tab, Window *active_window) {
glBindTexture(GL_TEXTURE_2D, global_state.layers_render_texture.texture_id);
float sx = global_state.layers_render_texture.width > 0 ? (float)os_window->viewport_width / (float)global_state.layers_render_texture.width : 1.f;
float sy = global_state.layers_render_texture.height > 0 ? (float)os_window->viewport_height / (float)global_state.layers_render_texture.height : 1.f;
glUniform4f(blit_program_layout.uniforms.src_rect, 0, sy, sx, 0);
glUniform4f(blit_program_layout.uniforms.dest_rect, -1, 1, 1, -1);
glUniform4f(program_uniform_location(BLIT_PROGRAM, "src_rect"), 0, sy, sx, 0);
glUniform4f(program_uniform_location(BLIT_PROGRAM, "dest_rect"), -1, 1, 1, -1);
restore_viewport();
if (os_window->live_resize.in_progress) save_viewport_using_top_left_origin(
0, 0, os_window->viewport_width, os_window->viewport_height, os_window->live_resize.height);
@ -1776,13 +1724,13 @@ take_screenshot_of_rectangular_region(OSWindow *os_window, Region region, unsign
float src_right_norm = (float)region.right / (float)vw;
float src_bottom_norm = (float)(vh - region.bottom) / (float)vh;
float src_top_norm = (float)(vh - region.top) / (float)vh;
glUniform4f(screenshot_program_layout.uniforms.src_rect, src_left_norm, src_top_norm, src_right_norm, src_bottom_norm);
glUniform4f(program_uniform_location(SCREENSHOT_PROGRAM, "src_rect"), src_left_norm, src_top_norm, src_right_norm, src_bottom_norm);
// Set destination rectangle (NDC coordinates: -1 to 1)
glUniform4f(screenshot_program_layout.uniforms.dest_rect, -1.0f, -1.0f, 1.0f, 1.0f);
glUniform4f(program_uniform_location(SCREENSHOT_PROGRAM, "dest_rect"), -1.0f, -1.0f, 1.0f, 1.0f);
// Set the source texture size for proper downscaling
glUniform2f(screenshot_program_layout.uniforms.src_size, (float)vw, (float)vh);
glUniform2f(program_uniform_location(SCREENSHOT_PROGRAM, "src_size"), (float)vw, (float)vh);
// Bind the source texture
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
@ -1831,9 +1779,9 @@ attach_shaders(PyObject *sources, GLuint program_id, GLenum shader_type) {
static PyObject*
compile_program(PyObject UNUSED *self, PyObject *args) {
PyObject *vertex_shaders, *fragment_shaders;
PyObject *vertex_shaders, *fragment_shaders, *metadata;
int which, allow_recompile = 0;
if (!PyArg_ParseTuple(args, "iO!O!|p", &which, &PyTuple_Type, &vertex_shaders, &PyTuple_Type, &fragment_shaders, &allow_recompile)) return NULL;
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 < 0 || which >= NUM_PROGRAMS) { PyErr_Format(PyExc_ValueError, "Unknown program: %d", which); return NULL; }
Program *program = program_ptr(which);
if (program->id != 0) {
@ -1856,6 +1804,7 @@ compile_program(PyObject UNUSED *self, PyObject *args) {
}
#undef fail_compile
init_uniforms(which);
set_program_layout(which, metadata);
return Py_BuildValue("I", program->id);
}
@ -1911,6 +1860,7 @@ static PyMethodDef module_methods[] = {
static void
finalize(void) {
default_visual_bell_animation = free_animation(default_visual_bell_animation);
free_program_layouts();
}
bool

View file

@ -191,17 +191,18 @@ class LoadShaderPrograms:
opts = self.get_options()
self.text_old_gamma = opts.text_composition_strategy == 'legacy'
self.text_fg_override_threshold = opts.text_fg_override_threshold
metadata = load_glsl_metadata()
def cell(prog: int) -> None:
v = cell_variant(opts, program=prog)
vert, frag = glsl_shaders('cell', variant_name(v, default_cell_variant))
compile_program(prog, (vert,), (frag,), allow_recompile)
compile_program(prog, (vert,), (frag,), metadata['cell'], allow_recompile)
cell(CELL_PROGRAM), cell(CELL_BG_PROGRAM), cell(CELL_FG_PROGRAM)
for prog, vname in {
GRAPHICS_PROGRAM: '', GRAPHICS_ALPHA_MASK_PROGRAM: 'alpha_mask',
GRAPHICS_PREMULT_PROGRAM: 'premult',
}.items():
vert, frag = glsl_shaders('graphics', vname)
compile_program(prog, (vert,), (frag,), allow_recompile)
compile_program(prog, (vert,), (frag,), metadata['graphics'], allow_recompile)
for name, prog in {
'bgimage': BGIMAGE_PROGRAM,
'tint': TINT_PROGRAM,
@ -212,7 +213,7 @@ class LoadShaderPrograms:
'border': BORDERS_PROGRAM,
}.items():
vert, frag = glsl_shaders(name)
compile_program(prog, (vert,), (frag,), allow_recompile)
compile_program(prog, (vert,), (frag,), metadata[name], allow_recompile)
init_cell_program()
@ -719,55 +720,28 @@ def write_if_changed(dest: str, text: str) -> None:
f.write(text)
def write_glsl_header(dest_dir: str, dest: str = 'kitty/glsl-uniforms.h') -> None:
def write_glsl_metadata(dest_dir: str, dest: str = 'glsl-uniforms.json') -> None:
metadata_map = {}
for x in glob.glob(os.path.join(dest_dir, '*.glsl.json')):
shader_name = shader_name_from_path(x)
if '.' in shader_name:
continue
with open(x) as f:
d = json.load(f)
metadata_map[shader_name] = GLSLMetadata.fromdict(d)
m = GLSLMetadata.fromdict(d)
metadata_map[shader_name] = {
'loose_uniforms': m.loose_uniforms,
'uniform_structs': m.uniform_structs,
'input_locations': m.input_locations,
'uniform_struct_names': m.uniform_struct_names,
}
write_if_changed(os.path.join(dest_dir, dest), json.dumps(metadata_map, indent=2, sort_keys=True))
lines = ['// generated by slang.py DO NOT EDIT', '#include "gl.h"', '']
a = lines.append
for name in sorted(metadata_map):
if '.' in name:
continue
m = metadata_map[name]
struct_name = name.capitalize() + 'Uniforms'
a('')
a(f'typedef struct {struct_name} {{') # }}
for u in sorted(m.loose_uniforms):
a(f' int {u};')
if m.input_locations:
a(' // Vertex Input locations')
for u in sorted(m.input_locations):
a(f' int {u};')
if m.uniform_structs:
a(' // Uniform block locations')
for u in sorted(m.uniform_structs):
a(f' UniformBlock {u};')
for v in sorted(m.uniform_structs[u]):
vv = m.uniform_structs[u][v]
if ']' in vv:
a(f' ArrayInformation {v};')
a(f'}} {struct_name};')
a('')
a(f'static inline void get_uniform_locations_{name}(int program, {struct_name} *ans) {{') # }}
for u in sorted(m.loose_uniforms):
a(f' ans->{u} = get_uniform_location(program, "{m.loose_uniforms[u]}");')
for u in sorted(m.input_locations):
a(f' ans->{u} = {m.input_locations[u]};')
for u in sorted(m.uniform_structs):
a(f' ans->{u}.index = block_index(program, "{m.uniform_struct_names[u]}");')
a(f' ans->{u}.size = block_size(program, ans->{u}.index);')
for v in sorted(m.uniform_structs[u]):
vv = m.uniform_structs[u][v]
if ']' in vv:
vv = vv.partition('[')[0] # ]
a(f' ans->{v} = get_uniform_array_information(program, "{vv}");')
a('}')
write_if_changed(dest, '\n'.join(lines))
@lru_cache(maxsize=1)
def load_glsl_metadata() -> dict[str, dict[str, Any]]:
with open(os.path.join(shaders_dir, 'glsl-uniforms.json')) as f:
return dict(json.load(f))
# }}}
@ -844,7 +818,7 @@ def compile_builtin_shaders(build_dir: str, dest_dir: str, parallel_run: Paralle
if shutil.which('glslangValidator'):
from kitty.shaders.validate_shaders import validation_command_for_file
parallel_run((True, f'Validating |{os.path.basename(x)}| ...', validation_command_for_file(x)) for x in built_glsl_files)
write_glsl_header(dest_dir)
write_glsl_metadata(dest_dir)
def main() -> None: