Cleanup a bunch of shader infrastructure

1) No longer us glScissor. It's an awful API and is not available in
   Vulkan. Instead the graphics drawing code ensures the graphic is
   drawn within the current viewport

2) Use generated code to automatically get the locations of uniforms
   from shaders. Greatly simplifies adding new uniforms to a shader.

3) Dont use a VAO for loading graphics vertices. Greatly simplifies
   a bunch of book keeping code.
This commit is contained in:
Kovid Goyal 2023-06-22 19:26:36 +05:30
parent 098a38a3a9
commit 248301f8b3
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
10 changed files with 254 additions and 221 deletions

View file

@ -675,7 +675,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *
call_boss(update_tab_bar_data, "K", os_window->id);
os_window->tab_bar_data_updated = true;
}
if (send_cell_data_to_gpu(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, os_window)) needs_render = true;
if (send_cell_data_to_gpu(TD.vao_idx, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, os_window)) needs_render = true;
}
if (OPT(mouse_hide_wait) > 0 && !is_mouse_hidden(os_window)) {
if (now - os_window->last_mouse_activity_at >= OPT(mouse_hide_wait)) hide_mouse(os_window);
@ -726,7 +726,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *
set_maximum_wait(min_gap);
}
}
if (send_cell_data_to_gpu(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window)) needs_render = true;
if (send_cell_data_to_gpu(WD.vao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window)) needs_render = true;
if (WD.screen->start_visual_bell_at != 0) needs_render = true;
}
}
@ -753,12 +753,12 @@ render_os_window(OSWindow *os_window, unsigned int active_window_id, color_type
BorderRects *br = &tab->border_rects;
draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, os_window->viewport_width, os_window->viewport_height, active_window_bg, num_visible_windows, all_windows_have_same_bg, os_window);
br->is_dirty = false;
if (TD.screen && os_window->num_tabs >= OPT(tab_bar_min_tabs)) draw_cells(TD.vao_idx, 0, &TD, os_window, true, false, NULL);
if (TD.screen && os_window->num_tabs >= OPT(tab_bar_min_tabs)) draw_cells(TD.vao_idx, &TD, os_window, true, false, NULL);
for (unsigned int i = 0; i < tab->num_windows; i++) {
Window *w = tab->windows + i;
if (w->visible && WD.screen) {
bool is_active_window = i == tab->active_window;
draw_cells(WD.vao_idx, WD.gvao_idx, &WD, os_window, is_active_window, true, w);
draw_cells(WD.vao_idx, &WD, os_window, is_active_window, true, w);
if (WD.screen->start_visual_bell_at != 0) {
set_maximum_wait(OPT(repaint_delay));
}

View file

@ -132,6 +132,8 @@ init_uniforms(int program) {
for (GLint i = 0; i < p->num_of_uniforms; i++) {
Uniform *u = p->uniforms + i;
glGetActiveUniform(p->id, (GLuint)i, sizeof(u->name)/sizeof(u->name[0]), NULL, &(u->size), &(u->type), u->name);
char *l = strchr(u->name, '[');
if (l) *l = 0;
u->location = glGetUniformLocation(p->id, u->name);
u->idx = i;
}
@ -140,13 +142,18 @@ init_uniforms(int program) {
GLint
get_uniform_location(int program, const char *name) {
Program *p = programs + program;
return glGetUniformLocation(p->id, name);
const size_t n = strlen(name) + 1;
for (GLint i = 0; i < p->num_of_uniforms; i++) {
Uniform *u = p->uniforms + i;
if (strncmp(u->name, name, n) == 0) return u->location;
}
return -1;
}
GLint
get_uniform_information(int program, const char *name, GLenum information_type) {
GLint q; GLuint t;
static const char* names[] = {""};
const char* names[] = {""};
names[0] = name;
GLuint pid = program_id(program);
glGetUniformIndices(pid, 1, (void*)names, &t);

View file

@ -899,35 +899,21 @@ handle_put_command(GraphicsManager *self, const GraphicsCommand *g, Cursor *c, b
return img->client_id;
}
static void
set_vertex_data(ImageRenderData *rd, const ImageRef *ref, const ImageRect *dest_rect) {
unsigned n = 0;
#define R(a, b) rd->vertices[n*4] = ref->src_rect.a; rd->vertices[n*4 + 1] = ref->src_rect.b; rd->vertices[n*4 + 2] = dest_rect->a; rd->vertices[n*4 + 3] = dest_rect->b; n++;
R(right, top); R(right, bottom); R(left, bottom); R(left, top);
#undef R
}
void
scale_rendered_graphic(ImageRenderData *rd, float xstart, float ystart, float x_scale, float y_scale) {
float right = rd->vertices[2], left = rd->vertices[8 + 2], top = rd->vertices[3], bottom = rd->vertices[4 + 3];
float width = right - left, height = bottom - top;
left = xstart + (left - xstart) * x_scale;
right = left + width * x_scale;
top = ystart + (top - ystart) * y_scale;
bottom = top + height * y_scale;
rd->vertices[0+2] = right; rd->vertices[4+2] = right;
rd->vertices[8+2] = left; rd->vertices[12+2] = left;
rd->vertices[0+3] = top; rd->vertices[12+3] = top;
rd->vertices[4+3] = bottom; rd->vertices[8+3] = bottom;
float width = rd->dest_rect.right - rd->dest_rect.left, height = rd->dest_rect.bottom - rd->dest_rect.top;
rd->dest_rect.left = xstart + (rd->dest_rect.left - xstart) * x_scale;
rd->dest_rect.right = rd->dest_rect.left + width * x_scale;
rd->dest_rect.top = ystart + (rd->dest_rect.top - ystart) * y_scale;
rd->dest_rect.bottom = rd->dest_rect.top + height * y_scale;
}
void
gpu_data_for_image(ImageRenderData *ans, float left, float top, float right, float bottom) {
// For dest rect: x-axis is from -1 to 1, y axis is from 1 to -1
static const ImageRef source_rect = { .src_rect = { .left=0, .top=0, .bottom=1, .right=1 }};
const ImageRef *ref = &source_rect;
const ImageRect r = { .left = left, .right = right, .top = top, .bottom = bottom };
set_vertex_data(ans, ref, &r);
ans->src_rect = source_rect.src_rect;
ans->dest_rect = (ImageRect){ .left = left, .right = right, .top = top, .bottom = bottom };
ans->group_count = 1;
}
@ -976,7 +962,7 @@ grman_update_layers(GraphicsManager *self, unsigned int scrolled_by, float scree
ensure_space_for(self, render_data, ImageRenderData, self->count + 1, capacity, 64, true);
ImageRenderData *rd = self->render_data + self->count;
zero_at_ptr(rd);
set_vertex_data(rd, ref, &r);
rd->dest_rect = r; rd->src_rect = ref->src_rect;
self->count++;
rd->z_index = ref->z_index; rd->image_id = img->internal_id;
rd->texture_id = img->texture_id;
@ -2026,9 +2012,9 @@ W(update_layers) {
PyObject *ans = PyTuple_New(self->count);
for (size_t i = 0; i < self->count; i++) {
ImageRenderData *r = self->render_data + i;
#define R(offset) Py_BuildValue("{sf sf sf sf}", "left", r->vertices[offset + 8], "top", r->vertices[offset + 1], "right", r->vertices[offset], "bottom", r->vertices[offset + 5])
#define R(which) Py_BuildValue("{sf sf sf sf}", "left", r->which.left, "top", r->which.top, "right", r->which.right, "bottom", r->which.bottom)
PyTuple_SET_ITEM(ans, i,
Py_BuildValue("{sN sN sI si sK}", "src_rect", R(0), "dest_rect", R(2), "group_count", r->group_count, "z_index", r->z_index, "image_id", r->image_id)
Py_BuildValue("{sN sN sI si sK}", "src_rect", R(src_rect), "dest_rect", R(dest_rect), "group_count", r->group_count, "z_index", r->z_index, "image_id", r->image_id)
);
#undef R
}

View file

@ -76,7 +76,7 @@ typedef struct {
} BackgroundImage;
typedef struct {
float vertices[16];
ImageRect src_rect, dest_rect;
uint32_t texture_id, group_count;
int z_index;
id_type image_id;

View file

@ -1,4 +1,3 @@
#extension GL_ARB_explicit_attrib_location : require
#pragma kitty_include_shader <alpha_blend.glsl>
#define ALPHA_TYPE

View file

@ -1,10 +1,20 @@
#extension GL_ARB_explicit_attrib_location : require
// Have to use fixed locations here as all variants of the program share the same VAO
layout(location=0) in vec4 src;
out vec2 texcoord;
uniform vec4 src_rect, dest_rect;
#define left 0
#define top 1
#define right 2
#define bottom 3
const ivec2 vertex_pos_map[4] = ivec2[4](
ivec2(right, top),
ivec2(right, bottom),
ivec2(left, bottom),
ivec2(left, top)
);
void main() {
texcoord = vec2(src[0], src[1]);
gl_Position = vec4(src[2], src[3], 0, 1);
ivec2 pos = vertex_pos_map[gl_VertexID];
texcoord = vec2(src_rect[pos.x], src_rect[pos.y]);
gl_Position = vec4(dest_rect[pos.x], dest_rect[pos.y], 0, 1);
}

View file

@ -11,6 +11,7 @@
#include <stddef.h>
#include "window_logo.h"
#include "srgb_gamma.h"
#include "uniforms_generated.h"
#define BLEND_ONTO_OPAQUE glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // blending onto opaque colors
#define BLEND_ONTO_OPAQUE_WITH_OPAQUE_OUTPUT glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); // blending onto opaque colors with final color having alpha 1
@ -187,28 +188,30 @@ typedef struct CellRenderData {
struct {
GLfloat xstart, ystart, dx, dy, width, height;
} gl;
struct {
GLint xstart, ystart;
GLsizei width, height;
} px;
float x_ratio, y_ratio;
} CellRenderData;
typedef struct {
UniformBlock render_data;
ArrayInformation color_table;
GLint draw_bg_bitfield_location;
CellUniforms uniforms;
} CellProgramLayout;
static CellProgramLayout cell_program_layouts[NUM_PROGRAMS];
typedef struct {
GLint image_location, tiled_location, sizes_location, positions_location, opacity_location, premult_location;
GraphicsUniforms uniforms;
} GraphicsProgramLayout;
static GraphicsProgramLayout graphics_program_layouts[NUM_PROGRAMS];
typedef struct {
BgimageUniforms uniforms;
} BGImageProgramLayout;
static BGImageProgramLayout bgimage_program_layout = {0};
static BGImageProgramLayout bgimage_program_layout;
typedef struct {
GLint tint_color_location, edges_location;
TintUniforms uniforms;
} TintProgramLayout;
static TintProgramLayout tint_program_layout = {0};
static TintProgramLayout tint_program_layout;
static void
init_cell_program(void) {
@ -218,22 +221,20 @@ init_cell_program(void) {
cell_program_layouts[i].color_table.size = get_uniform_information(i, "color_table[0]", GL_UNIFORM_SIZE);
cell_program_layouts[i].color_table.offset = get_uniform_information(i, "color_table[0]", GL_UNIFORM_OFFSET);
cell_program_layouts[i].color_table.stride = get_uniform_information(i, "color_table[0]", GL_UNIFORM_ARRAY_STRIDE);
get_uniform_locations_cell(i, &cell_program_layouts[i].uniforms);
}
cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location = get_uniform_location(CELL_BG_PROGRAM, "draw_bg_bitfield");
// Sanity check to ensure the attribute location binding worked
#define C(p, name, expected) { int aloc = attrib_location(p, #name); if (aloc != expected && aloc != -1) fatal("The attribute location for %s is %d != %d in program: %d", #name, aloc, expected, p); }
for (int p = CELL_PROGRAM; p < BORDERS_PROGRAM; p++) {
C(p, colors, 0); C(p, sprite_coords, 1); C(p, is_selected, 2);
}
#undef C
bgimage_program_layout.image_location = get_uniform_location(BGIMAGE_PROGRAM, "image");
bgimage_program_layout.opacity_location = get_uniform_location(BGIMAGE_PROGRAM, "opacity");
bgimage_program_layout.sizes_location = get_uniform_location(BGIMAGE_PROGRAM, "sizes");
bgimage_program_layout.positions_location = get_uniform_location(BGIMAGE_PROGRAM, "positions");
bgimage_program_layout.tiled_location = get_uniform_location(BGIMAGE_PROGRAM, "tiled");
bgimage_program_layout.premult_location = get_uniform_location(BGIMAGE_PROGRAM, "premult");
tint_program_layout.tint_color_location = get_uniform_location(TINT_PROGRAM, "tint_color");
tint_program_layout.edges_location = get_uniform_location(TINT_PROGRAM, "edges");
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);
}
#define CELL_BUFFERS enum { cell_data_buffer, selection_buffer, uniform_buffer };
@ -269,23 +270,6 @@ create_graphics_vao(void) {
return vao_idx;
}
struct CellUniformData {
bool constants_set;
GLint gploc, gpploc, cploc, cfploc, fg_loc, amask_bg_premult_loc, amask_fg_loc, amask_image_loc;
GLfloat prev_inactive_text_alpha;
};
static struct CellUniformData cell_uniform_data = {0, .prev_inactive_text_alpha=-1};
static void
send_graphics_data_to_gpu(size_t image_count, ssize_t gvao_idx, const ImageRenderData *render_data) {
const size_t num_of_floats_per_image = arraysz(render_data[0].vertices);
size_t sz = sizeof(GLfloat) * num_of_floats_per_image * image_count;
GLfloat *a = alloc_and_map_vao_buffer(gvao_idx, sz, 0, GL_STREAM_DRAW, GL_WRITE_ONLY);
for (size_t i = 0; i < image_count; i++, a += num_of_floats_per_image) memcpy(a, render_data[i].vertices, sizeof(render_data[0].vertices));
unmap_vao_buffer(gvao_idx, 0); a = NULL;
}
#define IS_SPECIAL_COLOR(name) (screen->color_profile->overridden.name.type == COLOR_IS_SPECIAL || (screen->color_profile->overridden.name.type == COLOR_NOT_SET && screen->color_profile->configured.name.type == COLOR_IS_SPECIAL))
static void
@ -388,7 +372,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
}
static bool
cell_prepare_to_render(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, FONTS_DATA_HANDLE fonts_data) {
cell_prepare_to_render(ssize_t vao_idx, Screen *screen, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, FONTS_DATA_HANDLE fonts_data) {
size_t sz;
CELL_BUFFERS;
void *address;
@ -422,8 +406,7 @@ cell_prepare_to_render(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, GLfloa
changed = true;
}
if (gvao_idx && grman_update_layers(screen->grman, screen->scrolled_by, xstart, ystart, dx, dy, screen->columns, screen->lines, screen->cell_size)) {
send_graphics_data_to_gpu(screen->grman->count, gvao_idx, screen->grman->render_data);
if (grman_update_layers(screen->grman, screen->scrolled_by, xstart, ystart, dx, dy, screen->columns, screen->lines, screen->cell_size)) {
changed = true;
}
screen->last_rendered.scrolled_by = screen->scrolled_by;
@ -437,16 +420,16 @@ draw_background_image(OSWindow *w) {
blank_canvas(w->is_semi_transparent ? OPT(background_opacity) : 1.0f, OPT(background));
bind_program(BGIMAGE_PROGRAM);
glUniform1i(bgimage_program_layout.image_location, BGIMAGE_UNIT);
glUniform1f(bgimage_program_layout.opacity_location, OPT(background_opacity));
glUniform1i(bgimage_program_layout.uniforms.image, BGIMAGE_UNIT);
glUniform1f(bgimage_program_layout.uniforms.opacity, OPT(background_opacity));
#ifdef __APPLE__
int window_width = w->window_width, window_height = w->window_height;
#else
int window_width = w->viewport_width, window_height = w->viewport_height;
#endif
glUniform4f(bgimage_program_layout.sizes_location,
glUniform4f(bgimage_program_layout.uniforms.sizes,
(GLfloat)window_width, (GLfloat)window_height, (GLfloat)w->bgimage->width, (GLfloat)w->bgimage->height);
glUniform1f(bgimage_program_layout.premult_location, w->is_semi_transparent ? 1.f : 0.f);
glUniform1f(bgimage_program_layout.uniforms.premult, w->is_semi_transparent ? 1.f : 0.f);
GLfloat tiled = 0.f;;
GLfloat left = -1.0, top = 1.0, right = 1.0, bottom = -1.0;
switch (OPT(background_image_layout)) {
@ -466,8 +449,8 @@ draw_background_image(OSWindow *w) {
}
break;
}
glUniform1f(bgimage_program_layout.tiled_location, tiled);
glUniform4f(bgimage_program_layout.positions_location, left, top, right, bottom);
glUniform1f(bgimage_program_layout.uniforms.tiled, tiled);
glUniform4f(bgimage_program_layout.uniforms.positions, left, top, right, bottom);
glActiveTexture(GL_TEXTURE0 + BGIMAGE_UNIT);
glBindTexture(GL_TEXTURE_2D, w->bgimage->texture_id);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@ -475,22 +458,48 @@ draw_background_image(OSWindow *w) {
}
static void
draw_graphics(int program, ssize_t vao_idx, ssize_t gvao_idx, ImageRenderData *data, GLuint start, GLuint count) {
bind_program(program);
bind_vertex_array(gvao_idx);
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
fit_image_in_viewport(GraphicsUniforms *u, ImageRenderData *rd, ImageRect viewport) {
// dest_rect: x: -1 to 1, y: 1 to -1. src_rect: x: 0 to 1 for both axes
ImageRect src_rect = rd->src_rect, dest_rect = rd->dest_rect;
const float img_width = dest_rect.right - dest_rect.left;
if (viewport.left > dest_rect.left) {
float frac = 1.f - (dest_rect.right - viewport.left) / img_width;
dest_rect.left = viewport.left;
src_rect.left += frac; // src_rect: left is 0 right is 1
}
if (viewport.right < dest_rect.right) {
float frac = 1.f - (viewport.right - dest_rect.left) / img_width;
dest_rect.right = viewport.right;
src_rect.right -= frac; // src_rect: left is 0 right is 1
}
const float img_height = dest_rect.top - dest_rect.bottom;
if (viewport.top < dest_rect.top) {
float frac = 1.f - (viewport.top - dest_rect.bottom) / img_height;
dest_rect.top = viewport.top;
src_rect.top += frac; // src_rect.bottom is 1 top is 0
}
if (viewport.bottom > dest_rect.bottom) {
float frac = 1.f - (dest_rect.top - viewport.bottom) / img_height;
dest_rect.bottom = viewport.bottom;
src_rect.bottom -= frac; // src_rect.bottom is 1 top is 0
}
glUniform4f(u->src_rect, src_rect.left, src_rect.top, src_rect.right, src_rect.bottom);
glUniform4f(u->dest_rect, dest_rect.left, dest_rect.top, dest_rect.right, dest_rect.bottom);
}
GLuint base = 4 * start;
glEnable(GL_SCISSOR_TEST);
static void
draw_graphics(int program, ssize_t vao_idx, ImageRenderData *data, GLuint start, GLuint count, ImageRect viewport) {
bind_program(program);
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
GraphicsUniforms *u = &graphics_program_layouts[program].uniforms;
for (GLuint i=0; i < count;) {
ImageRenderData *rd = data + start + i;
glBindTexture(GL_TEXTURE_2D, rd->texture_id);
// You could reduce the number of draw calls by using
// glDrawArraysInstancedBaseInstance but Apple chose to abandon OpenGL
// before implementing it.
for (GLuint k=0; k < rd->group_count; k++, base += 4, i++) glDrawArrays(GL_TRIANGLE_FAN, base, 4);
for (GLuint k=0; k < rd->group_count; k++, i++) {
fit_image_in_viewport(u, rd, viewport);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
}
glDisable(GL_SCISSOR_TEST);
bind_vertex_array(vao_idx);
}
@ -522,29 +531,32 @@ draw_centered_alpha_mask(OSWindow *os_window, size_t screen_width, size_t screen
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(cell_uniform_data.amask_image_loc, GRAPHICS_UNIT);
color_vec3(cell_uniform_data.amask_fg_loc, OPT(foreground));
color_vec4_premult(cell_uniform_data.amask_bg_premult_loc, OPT(background), 1);
send_graphics_data_to_gpu(1, os_window->gvao_idx, data);
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), 1);
glEnable(GL_BLEND);
if (os_window->is_semi_transparent) {
BLEND_PREMULT;
} else {
BLEND_ONTO_OPAQUE;
}
glScissor(0, 0, screen_width, screen_height);
draw_graphics(GRAPHICS_ALPHA_MASK_PROGRAM, 0, os_window->gvao_idx, data, 0, 1);
draw_graphics(GRAPHICS_ALPHA_MASK_PROGRAM, 0, data, 0, 1, (ImageRect){-1, 1, 1, -1});
glDisable(GL_BLEND);
}
static ImageRect
viewport_for_cells(const CellRenderData *crd) {
return (ImageRect){crd->gl.xstart, crd->gl.ystart, crd->gl.xstart + crd->gl.width, crd->gl.ystart - crd->gl.height};
}
static void
draw_cells_simple(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) {
draw_cells_simple(ssize_t vao_idx, Screen *screen, const CellRenderData *crd) {
bind_program(CELL_PROGRAM);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
if (screen->grman->count) {
glEnable(GL_BLEND);
BLEND_ONTO_OPAQUE;
draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->count);
draw_graphics(GRAPHICS_PROGRAM, vao_idx, screen->grman->render_data, 0, screen->grman->count, viewport_for_cells(crd));
glDisable(GL_BLEND);
}
}
@ -561,43 +573,45 @@ draw_tint(bool premult, Screen *screen, const CellRenderData *crd) {
color_type window_bg = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.default_bg, screen->color_profile->configured.default_bg).rgb;
#define C(shift) srgb_color((window_bg >> shift) & 0xFF) * premult_factor
GLfloat premult_factor = premult ? OPT(background_tint) : 1.0f;
glUniform4f(tint_program_layout.tint_color_location, C(16), C(8), C(0), OPT(background_tint));
glUniform4f(tint_program_layout.uniforms.tint_color, C(16), C(8), C(0), OPT(background_tint));
#undef C
glUniform4f(tint_program_layout.edges_location, crd->gl.xstart, crd->gl.ystart - crd->gl.height, crd->gl.xstart + crd->gl.width, crd->gl.ystart);
glUniform4f(tint_program_layout.uniforms.edges, crd->gl.xstart, crd->gl.ystart - crd->gl.height, crd->gl.xstart + crd->gl.width, crd->gl.ystart);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
static float prev_inactive_text_alpha = -1;
static void
set_cell_uniforms(float current_inactive_text_alpha, bool force) {
if (!cell_uniform_data.constants_set || force) {
cell_uniform_data.gploc = glGetUniformLocation(program_id(GRAPHICS_PROGRAM), "inactive_text_alpha");
cell_uniform_data.gpploc = glGetUniformLocation(program_id(GRAPHICS_PREMULT_PROGRAM), "inactive_text_alpha");
cell_uniform_data.cploc = glGetUniformLocation(program_id(CELL_PROGRAM), "inactive_text_alpha");
cell_uniform_data.cfploc = glGetUniformLocation(program_id(CELL_FG_PROGRAM), "inactive_text_alpha");
cell_uniform_data.amask_bg_premult_loc = glGetUniformLocation(program_id(GRAPHICS_ALPHA_MASK_PROGRAM), "amask_bg_premult");
cell_uniform_data.amask_fg_loc = glGetUniformLocation(program_id(GRAPHICS_ALPHA_MASK_PROGRAM), "amask_fg");
cell_uniform_data.amask_image_loc = glGetUniformLocation(program_id(GRAPHICS_ALPHA_MASK_PROGRAM), "image");
#define S(prog, name, val, type) { bind_program(prog); glUniform##type(glGetUniformLocation(program_id(prog), #name), val); }
S(GRAPHICS_PROGRAM, image, GRAPHICS_UNIT, 1i);
S(GRAPHICS_PREMULT_PROGRAM, image, GRAPHICS_UNIT, 1i);
S(CELL_PROGRAM, sprites, SPRITE_MAP_UNIT, 1i); S(CELL_FG_PROGRAM, sprites, SPRITE_MAP_UNIT, 1i);
S(CELL_PROGRAM, dim_opacity, OPT(dim_opacity), 1f); S(CELL_FG_PROGRAM, dim_opacity, OPT(dim_opacity), 1f);
S(CELL_BG_PROGRAM, defaultbg, OPT(background), 1f);
static bool constants_set = false;
if (!constants_set || force) {
float text_contrast = 1.0f + OPT(text_contrast) * 0.01f;
S(CELL_PROGRAM, text_contrast, text_contrast, 1f); S(CELL_FG_PROGRAM, text_contrast, text_contrast, 1f);
float text_gamma_adjustment = OPT(text_gamma_adjustment) < 0.01f ? 1.0f : 1.0f / OPT(text_gamma_adjustment);
S(CELL_PROGRAM, text_gamma_adjustment, text_gamma_adjustment, 1f); S(CELL_FG_PROGRAM, text_gamma_adjustment, text_gamma_adjustment, 1f);
#undef S
#define SV(prog, name, num, val, type) { bind_program(prog); glUniform##type(glGetUniformLocation(program_id(prog), #name), num, val); }
SV(CELL_PROGRAM, gamma_lut, 256, srgb_lut, 1fv); SV(CELL_FG_PROGRAM, gamma_lut, 256, srgb_lut, 1fv);
SV(CELL_BG_PROGRAM, gamma_lut, 256, srgb_lut, 1fv); SV(CELL_SPECIAL_PROGRAM, gamma_lut, 256, srgb_lut, 1fv);
#undef SV
cell_uniform_data.constants_set = true;
for (int i = GRAPHICS_PROGRAM; i <= GRAPHICS_PREMULT_PROGRAM; i++) {
bind_program(i); glUniform1i(graphics_program_layouts[i].uniforms.image, GRAPHICS_UNIT);
}
for (int i = CELL_PROGRAM; i <= CELL_FG_PROGRAM; i++) {
bind_program(i); const CellUniforms *cu = &cell_program_layouts[i].uniforms;
glUniform1fv(cu->gamma_lut, arraysz(srgb_lut), srgb_lut);
switch(i) {
case CELL_PROGRAM: case CELL_FG_PROGRAM:
glUniform1i(cu->sprites, SPRITE_MAP_UNIT);
glUniform1f(cu->dim_opacity, OPT(dim_opacity));
glUniform1f(cu->text_contrast, text_contrast);
glUniform1f(cu->text_gamma_adjustment, text_gamma_adjustment);
break;
}
}
constants_set = true;
}
if (current_inactive_text_alpha != cell_uniform_data.prev_inactive_text_alpha || force) {
cell_uniform_data.prev_inactive_text_alpha = current_inactive_text_alpha;
#define S(prog, loc) { bind_program(prog); glUniform1f(cell_uniform_data.loc, current_inactive_text_alpha); }
S(CELL_PROGRAM, cploc); S(CELL_FG_PROGRAM, cfploc); S(GRAPHICS_PROGRAM, gploc); S(GRAPHICS_PREMULT_PROGRAM, gpploc);
if (current_inactive_text_alpha != prev_inactive_text_alpha || force) {
prev_inactive_text_alpha = current_inactive_text_alpha;
for (int i = GRAPHICS_PROGRAM; i <= GRAPHICS_PREMULT_PROGRAM; i++) {
bind_program(i); glUniform1f(graphics_program_layouts[i].uniforms.inactive_text_alpha, current_inactive_text_alpha);
}
#define S(prog, loc) bind_program(prog); glUniform1f(cell_program_layouts[prog].uniforms.inactive_text_alpha, current_inactive_text_alpha);
S(CELL_PROGRAM, cploc); S(CELL_FG_PROGRAM, cfploc);
#undef S
}
}
@ -646,10 +660,9 @@ render_a_bar(OSWindow *os_window, Screen *screen, const CellRenderData *crd, Win
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA, bar_width, bar_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bar->buf);
set_cell_uniforms(1.f, false);
bind_program(GRAPHICS_PROGRAM);
send_graphics_data_to_gpu(1, os_window->gvao_idx, &data);
glEnable(GL_BLEND);
if (os_window->is_semi_transparent) { BLEND_PREMULT; } else { BLEND_ONTO_OPAQUE; }
draw_graphics(GRAPHICS_PROGRAM, 0, os_window->gvao_idx, &data, 0, 1);
draw_graphics(GRAPHICS_PROGRAM, 0, &data, 0, 1, viewport_for_cells(crd));
glDisable(GL_BLEND);
return height_gl;
}
@ -687,11 +700,10 @@ draw_window_logo(ssize_t vao_idx, OSWindow *os_window, const WindowLogoRenderDat
static ImageRenderData ird = {.group_count=1};
ird.texture_id = wl->instance->texture_id;
gpu_data_for_image(&ird, logo_left_gl, logo_top_gl, logo_left_gl + logo_width_gl, logo_top_gl - logo_height_gl);
send_graphics_data_to_gpu(1, os_window->gvao_idx, &ird);
bind_program(GRAPHICS_PREMULT_PROGRAM);
glUniform1f(cell_uniform_data.gpploc, cell_uniform_data.prev_inactive_text_alpha * wl->alpha);
draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, os_window->gvao_idx, &ird, 0, 1);
glUniform1f(cell_uniform_data.gpploc, cell_uniform_data.prev_inactive_text_alpha);
glUniform1f(graphics_program_layouts[GRAPHICS_PREMULT_PROGRAM].uniforms.inactive_text_alpha, prev_inactive_text_alpha * wl->alpha);
draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, &ird, 0, 1, viewport_for_cells(crd));
glUniform1f(graphics_program_layouts[GRAPHICS_PREMULT_PROGRAM].uniforms.inactive_text_alpha, prev_inactive_text_alpha);
}
static void
@ -736,12 +748,11 @@ draw_window_number(OSWindow *os_window, Screen *screen, const CellRenderData *cr
gpu_data_for_image(ird, left, top, right, bottom);
glEnable(GL_BLEND);
BLEND_PREMULT;
glUniform1i(cell_uniform_data.amask_image_loc, GRAPHICS_UNIT);
glUniform1i(graphics_program_layouts[GRAPHICS_ALPHA_MASK_PROGRAM].uniforms.image, GRAPHICS_UNIT);
color_type digit_color = colorprofile_to_color_with_fallback(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg, screen->color_profile->overridden.default_fg, screen->color_profile->configured.default_fg);
color_vec3(cell_uniform_data.amask_fg_loc, digit_color);
glUniform4f(cell_uniform_data.amask_bg_premult_loc, 0.f, 0.f, 0.f, 0.f);
send_graphics_data_to_gpu(1, os_window->gvao_idx, ird);
draw_graphics(GRAPHICS_ALPHA_MASK_PROGRAM, 0, os_window->gvao_idx, ird, 0, 1);
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);
draw_graphics(GRAPHICS_ALPHA_MASK_PROGRAM, 0, ird, 0, 1, viewport_for_cells(crd));
glDisable(GL_BLEND);
}
@ -761,22 +772,22 @@ draw_visual_bell_flash(GLfloat intensity, const CellRenderData *crd, Screen *scr
#undef C
#define C(x) (x * intensity * attenuation)
if (max_channel > 0.45) attenuation = 0.6f; // light color
glUniform4f(tint_program_layout.tint_color_location, C(r), C(g), C(b), C(1));
glUniform4f(tint_program_layout.uniforms.tint_color, C(r), C(g), C(b), C(1));
#undef C
glUniform4f(tint_program_layout.edges_location, crd->gl.xstart, crd->gl.ystart - crd->gl.height, crd->gl.xstart + crd->gl.width, crd->gl.ystart);
glUniform4f(tint_program_layout.uniforms.edges, crd->gl.xstart, crd->gl.ystart - crd->gl.height, crd->gl.xstart + crd->gl.width, crd->gl.ystart);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisable(GL_BLEND);
}
static void
draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *w, const CellRenderData *crd, const WindowLogoRenderData *wl) {
draw_cells_interleaved(ssize_t vao_idx, Screen *screen, OSWindow *w, const CellRenderData *crd, const WindowLogoRenderData *wl) {
glEnable(GL_BLEND);
BLEND_ONTO_OPAQUE;
// draw background for all cells
if (!has_bgimage(w)) {
bind_program(CELL_BG_PROGRAM);
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location, 3);
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].uniforms.draw_bg_bitfield, 3);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
} else if (OPT(background_tint) > 0) {
draw_tint(false, screen, crd);
@ -789,14 +800,14 @@ draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWind
BLEND_ONTO_OPAQUE;
}
if (screen->grman->num_of_below_refs) draw_graphics(
GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_below_refs);
GRAPHICS_PROGRAM, vao_idx, screen->grman->render_data, 0, screen->grman->num_of_below_refs, viewport_for_cells(crd));
bind_program(CELL_BG_PROGRAM);
// draw background for non-default bg cells
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location, 2);
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].uniforms.draw_bg_bitfield, 2);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
}
if (screen->grman->num_of_negative_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_below_refs, screen->grman->num_of_negative_refs);
if (screen->grman->num_of_negative_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, screen->grman->render_data, screen->grman->num_of_below_refs, screen->grman->num_of_negative_refs, viewport_for_cells(crd));
bind_program(CELL_SPECIAL_PROGRAM);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
@ -806,13 +817,13 @@ draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWind
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
BLEND_ONTO_OPAQUE;
if (screen->grman->num_of_positive_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs + screen->grman->num_of_below_refs, screen->grman->num_of_positive_refs);
if (screen->grman->num_of_positive_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs + screen->grman->num_of_below_refs, screen->grman->num_of_positive_refs, viewport_for_cells(crd));
glDisable(GL_BLEND);
}
static void
draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *os_window, const CellRenderData *crd, const WindowLogoRenderData *wl) {
draw_cells_interleaved_premult(ssize_t vao_idx, Screen *screen, OSWindow *os_window, const CellRenderData *crd, const WindowLogoRenderData *wl) {
if (OPT(background_tint) > 0.f) {
glEnable(GL_BLEND);
draw_tint(true, screen, crd);
@ -821,7 +832,7 @@ draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen
bind_program(CELL_BG_PROGRAM);
if (!has_bgimage(os_window)) {
// draw background for all cells
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location, 3);
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].uniforms.draw_bg_bitfield, 3);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
}
glEnable(GL_BLEND);
@ -833,19 +844,19 @@ draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen
BLEND_PREMULT;
}
if (screen->grman->num_of_below_refs) draw_graphics(
GRAPHICS_PREMULT_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_below_refs);
GRAPHICS_PREMULT_PROGRAM, vao_idx, screen->grman->render_data, 0, screen->grman->num_of_below_refs, viewport_for_cells(crd));
bind_program(CELL_BG_PROGRAM);
// Draw background for non-default bg cells
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location, 2);
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].uniforms.draw_bg_bitfield, 2);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
} else {
// Apply background_opacity
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location, 0);
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].uniforms.draw_bg_bitfield, 0);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
}
if (screen->grman->num_of_negative_refs) {
draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_below_refs, screen->grman->num_of_negative_refs);
draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, screen->grman->render_data, screen->grman->num_of_below_refs, screen->grman->num_of_negative_refs, viewport_for_cells(crd));
}
bind_program(CELL_SPECIAL_PROGRAM);
@ -854,7 +865,7 @@ draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen
bind_program(CELL_FG_PROGRAM);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
if (screen->grman->num_of_positive_refs) draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs + screen->grman->num_of_below_refs, screen->grman->num_of_positive_refs);
if (screen->grman->num_of_positive_refs) draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs + screen->grman->num_of_below_refs, screen->grman->num_of_positive_refs, viewport_for_cells(crd));
if (!has_bgimage(os_window)) glDisable(GL_BLEND);
}
@ -869,10 +880,10 @@ blank_canvas(float background_opacity, color_type color) {
}
bool
send_cell_data_to_gpu(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window) {
send_cell_data_to_gpu(ssize_t vao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window) {
bool changed = false;
if (os_window->fonts_data) {
if (cell_prepare_to_render(vao_idx, gvao_idx, screen, xstart, ystart, dx, dy, os_window->fonts_data)) changed = true;
if (cell_prepare_to_render(vao_idx, screen, xstart, ystart, dx, dy, os_window->fonts_data)) changed = true;
}
return changed;
}
@ -907,18 +918,8 @@ get_visual_bell_intensity(Screen *screen) {
return 0.0f;
}
static void
scale_graphics_for_live_resize(Screen *screen, float xstart, float ystart, CellRenderData *crd, ssize_t gvao_idx) {
const size_t sz = screen->grman->count * sizeof(screen->grman->render_data[0]);
FREE_AFTER_FUNCTION ImageRenderData *changed = malloc(sz);
if (changed == NULL) fatal("Out of memory allocating temporary ImageRenderData* for live resize");
memcpy(changed, screen->grman->render_data, sz);
for (size_t i = 0; i < screen->grman->count; i++) scale_rendered_graphic(changed + i, xstart, ystart, crd->x_ratio, crd->y_ratio);
send_graphics_data_to_gpu(screen->grman->count, gvao_idx, changed);
}
void
draw_cells(ssize_t vao_idx, ssize_t gvao_idx, const ScreenRenderData *srd, OSWindow *os_window, bool is_active_window, bool can_be_focused, Window *window) {
draw_cells(ssize_t vao_idx, const ScreenRenderData *srd, OSWindow *os_window, bool is_active_window, bool can_be_focused, Window *window) {
float x_ratio = 1., y_ratio = 1.;
if (os_window->live_resize.in_progress) {
x_ratio = (float) os_window->viewport_width / (float) os_window->live_resize.width;
@ -932,21 +933,6 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, const ScreenRenderData *srd, OSWin
.x_ratio=x_ratio, .y_ratio=y_ratio
};
crd.gl.width = crd.gl.dx * screen->columns; crd.gl.height = crd.gl.dy * screen->lines;
// The scissor limits below are calculated to ensure that they do not
// overlap with the pixels outside the draw area. We can't use the actual pixel window dimensions
// because of the mapping of opengl's float based co-ord system to pixels.
unsigned scissor_base_width = os_window->live_resize.in_progress ? os_window->live_resize.width : (unsigned)os_window->viewport_width;
unsigned scissor_base_height = os_window->live_resize.in_progress ? os_window->live_resize.height: (unsigned)os_window->viewport_height;
#define SCALE(w, x) ((GLfloat)(scissor_base_##w) * (GLfloat)(x))
/* printf("columns=%d dx=%f w=%f vw=%d vh=%d left=%f width=%f\n", screen->columns, dx, w, os_window->viewport_width, os_window->viewport_height, SCALE(width, (xstart + 1.f)/2.f), SCALE(width, w / 2.f)); */
crd.px.xstart = (GLint)roundf(SCALE(width, (crd.gl.xstart + 1.f)/2.f));
crd.px.ystart = (GLint)roundf(SCALE(height, (crd.gl.ystart - crd.gl.height + 1.f)/2.f));
crd.px.width = (GLsizei)roundf(SCALE(width, crd.gl.width / 2.f));
crd.px.height = (GLsizei)roundf(SCALE(height, crd.gl.height / 2.f));
#undef SCALE
glScissor(crd.px.xstart, crd.px.ystart, crd.px.width, crd.px.height);
cell_update_uniform_block(vao_idx, screen, uniform_buffer, &crd, &screen->cursor_render_info, inverted, os_window);
bind_vao_uniform_buffer(vao_idx, uniform_buffer, cell_program_layouts[CELL_PROGRAM].render_data.index);
@ -961,19 +947,23 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, const ScreenRenderData *srd, OSWin
has_underlying_image = true;
set_on_gpu_state(window->window_logo.instance, true);
} else wl = NULL;
bool restore_graphics_render_data = false;
if (os_window->live_resize.in_progress && window->render_data.gvao_idx && screen->grman->count && (crd.x_ratio != 1 || crd.y_ratio != 1)) {
restore_graphics_render_data = true;
scale_graphics_for_live_resize(screen, srd->xstart, srd->ystart, &crd, window->render_data.gvao_idx);
ImageRenderData *previous_graphics_render_data = NULL;
if (os_window->live_resize.in_progress && screen->grman->count && (crd.x_ratio != 1 || crd.y_ratio != 1)) {
previous_graphics_render_data = malloc(sizeof(previous_graphics_render_data[0]) * screen->grman->count);
if (previous_graphics_render_data) {
memcpy(previous_graphics_render_data, screen->grman->render_data, sizeof(previous_graphics_render_data[0]) * screen->grman->count);
for (size_t i = 0; i < screen->grman->count; i++)
scale_rendered_graphic(screen->grman->render_data + i, srd->xstart, srd->ystart, crd.x_ratio, crd.y_ratio);
}
}
if (os_window->is_semi_transparent) {
if (screen->grman->count || has_underlying_image) draw_cells_interleaved_premult(
vao_idx, gvao_idx, screen, os_window, &crd, wl);
else draw_cells_simple(vao_idx, gvao_idx, screen);
vao_idx, screen, os_window, &crd, wl);
else draw_cells_simple(vao_idx, screen, &crd);
} else {
if (screen->grman->num_of_negative_refs || screen->grman->num_of_below_refs || has_underlying_image) draw_cells_interleaved(
vao_idx, gvao_idx, screen, os_window, &crd, wl);
else draw_cells_simple(vao_idx, gvao_idx, screen);
vao_idx, screen, os_window, &crd, wl);
else draw_cells_simple(vao_idx, screen, &crd);
}
if (screen->start_visual_bell_at) {
@ -983,24 +973,23 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, const ScreenRenderData *srd, OSWin
if (window && screen->display_window_char) draw_window_number(os_window, screen, &crd, window);
if (OPT(show_hyperlink_targets) && window && screen->current_hyperlink_under_mouse.id && !is_mouse_hidden(os_window)) draw_hyperlink_target(os_window, screen, &crd, window);
if (restore_graphics_render_data) send_graphics_data_to_gpu(screen->grman->count, window->render_data.gvao_idx, screen->grman->render_data);
if (previous_graphics_render_data) {
free(screen->grman->render_data);
screen->grman->render_data = previous_graphics_render_data;
}
}
// }}}
// Borders {{{
enum BorderUniforms { BORDER_viewport, BORDER_background_opacity, BORDER_tint_opacity, BORDER_tint_premult, BORDER_colors, BORDER_gamma_lut, NUM_BORDER_UNIFORMS };
static GLint border_uniform_locations[NUM_BORDER_UNIFORMS] = {0};
typedef struct BorderProgramLayout {
BorderUniforms uniforms;
} BorderProgramLayout;
static BorderProgramLayout border_program_layout;
static void
init_borders_program(void) {
#define SET_LOC(which) border_uniform_locations[BORDER_##which] = get_uniform_location(BORDERS_PROGRAM, #which);
SET_LOC(viewport)
SET_LOC(background_opacity)
SET_LOC(tint_opacity)
SET_LOC(tint_premult)
SET_LOC(colors)
SET_LOC(gamma_lut)
#undef SET_LOC
get_uniform_locations_border(BORDERS_PROGRAM, &border_program_layout.uniforms);
}
ssize_t
@ -1046,12 +1035,12 @@ 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
};
glUniform1uiv(border_uniform_locations[BORDER_colors], arraysz(colors), colors);
glUniform1f(border_uniform_locations[BORDER_background_opacity], background_opacity);
glUniform1f(border_uniform_locations[BORDER_tint_opacity], tint_opacity);
glUniform1f(border_uniform_locations[BORDER_tint_premult], tint_premult);
glUniform2ui(border_uniform_locations[BORDER_viewport], viewport_width, viewport_height);
glUniform1fv(border_uniform_locations[BORDER_gamma_lut], 256, srgb_lut);
glUniform1uiv(border_program_layout.uniforms.colors, arraysz(colors), colors);
glUniform1f(border_program_layout.uniforms.background_opacity, background_opacity);
glUniform1f(border_program_layout.uniforms.tint_opacity, tint_opacity);
glUniform1f(border_program_layout.uniforms.tint_premult, tint_premult);
glUniform2ui(border_program_layout.uniforms.viewport, viewport_width, viewport_height);
glUniform1fv(border_program_layout.uniforms.gamma_lut, 256, srgb_lut);
if (has_bgimage(w)) {
if (w->is_semi_transparent) { BLEND_PREMULT; }
else { BLEND_ONTO_OPAQUE_WITH_OPAQUE_OUTPUT; }

View file

@ -203,7 +203,6 @@ add_os_window(void) {
zero_at_ptr(ans);
ans->id = ++global_state.os_window_id_counter;
ans->tab_bar_render_data.vao_idx = create_cell_vao();
ans->gvao_idx = create_graphics_vao();
ans->background_opacity = OPT(background_opacity);
bool wants_bg = OPT(background_image) && OPT(background_image)[0] != 0;
@ -244,15 +243,12 @@ add_tab(id_type os_window_id) {
static void
create_gpu_resources_for_window(Window *w) {
w->render_data.vao_idx = create_cell_vao();
w->render_data.gvao_idx = create_graphics_vao();
}
static void
release_gpu_resources_for_window(Window *w) {
if (w->render_data.vao_idx > -1) remove_vao(w->render_data.vao_idx);
w->render_data.vao_idx = -1;
if (w->render_data.gvao_idx > -1) remove_vao(w->render_data.gvao_idx);
w->render_data.gvao_idx = -1;
}
static bool
@ -292,7 +288,6 @@ initialize_window(Window *w, PyObject *title, bool init_gpu_resources) {
if (init_gpu_resources) create_gpu_resources_for_window(w);
else {
w->render_data.vao_idx = -1;
w->render_data.gvao_idx = -1;
}
}
@ -478,7 +473,6 @@ destroy_os_window_item(OSWindow *w) {
}
Py_CLEAR(w->window_title); Py_CLEAR(w->tab_bar_render_data.screen);
remove_vao(w->tab_bar_render_data.vao_idx);
remove_vao(w->gvao_idx);
free(w->tabs); w->tabs = NULL;
free_bgimage(&w->bgimage, true);
w->bgimage = NULL;
@ -944,7 +938,6 @@ PYWRAP1(set_window_render_data) {
WITH_WINDOW(os_window_id, tab_id, window_id);
Py_CLEAR(window->render_data.screen);
d.vao_idx = window->render_data.vao_idx;
d.gvao_idx = window->render_data.gvao_idx;
init_screen_render_data(osw, &g, &d);
window->render_data = d;
window->geometry = g;

View file

@ -100,7 +100,7 @@ typedef struct WindowLogoRenderData {
} WindowLogoRenderData;
typedef struct {
ssize_t vao_idx, gvao_idx;
ssize_t vao_idx;
float xstart, ystart, dx, dy;
Screen *screen;
} ScreenRenderData;
@ -224,7 +224,6 @@ typedef struct {
monotonic_t last_render_frame_received_at;
uint64_t render_calls;
id_type last_focused_counter;
ssize_t gvao_idx;
CloseRequest close_request;
} OSWindow;
@ -290,8 +289,8 @@ void draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *re
ssize_t create_cell_vao(void);
ssize_t create_graphics_vao(void);
ssize_t create_border_vao(void);
bool send_cell_data_to_gpu(ssize_t, ssize_t, float, float, float, float, Screen *, OSWindow *);
void draw_cells(ssize_t, ssize_t, const ScreenRenderData*, OSWindow *, bool, bool, Window*);
bool send_cell_data_to_gpu(ssize_t, float, float, float, float, Screen *, OSWindow *);
void draw_cells(ssize_t, const ScreenRenderData*, OSWindow *, bool, bool, Window*);
void draw_centered_alpha_mask(OSWindow *w, size_t screen_width, size_t screen_height, size_t width, size_t height, uint8_t *canvas);
void update_surface_size(int, int, uint32_t);
void free_texture(uint32_t*);

View file

@ -19,7 +19,7 @@
from contextlib import suppress
from functools import lru_cache, partial
from pathlib import Path
from typing import Callable, Dict, FrozenSet, Iterable, List, Optional, Sequence, Set, Tuple, Union, cast
from typing import Callable, Dict, FrozenSet, Iterable, Iterator, List, Optional, Sequence, Set, Tuple, Union, cast
from glfw import glfw
from glfw.glfw import Command, CompileKey
@ -864,6 +864,55 @@ def build_ref_map(skip_generation: bool = False) -> str:
return dest
def build_uniforms_header(skip_generation: bool = False) -> str:
dest = 'kitty/uniforms_generated.h'
if skip_generation:
return dest
lines = ['#include "gl.h"', '']
a = lines.append
uniform_names = {}
class_names = {}
function_names = {}
def find_uniform_names(raw: str) -> Iterator[str]:
for m in re.finditer(r'^uniform\s+\S+\s+(.+?);', raw, flags=re.MULTILINE):
for x in m.group(1).split(','):
yield x.strip().partition('[')[0]
for x in glob.glob('kitty/*.glsl'):
name = os.path.basename(x).partition('.')[0]
name, sep, shader_type = name.partition('_')
if not sep or shader_type not in ('fragment', 'vertex'):
continue
class_names[name] = f'{name.capitalize()}Uniforms'
function_names[name] = f'get_uniform_locations_{name}'
with open(x) as f:
raw = f.read()
uniform_names[name] = uniform_names.setdefault(name, ()) + tuple(find_uniform_names(raw))
for name in sorted(class_names):
class_name, function_name, uniforms = class_names[name], function_names[name], uniform_names[name]
a(f'typedef struct {class_name} ''{')
for n in uniforms:
a(f' GLint {n};')
a('}'f' {class_name};')
a('')
a(f'static inline void\n{function_name}(int program, {class_name} *ans) ''{')
for n in uniforms:
a(f' ans->{n} = get_uniform_location(program, "{n}");')
a('}')
a('')
src = '\n'.join(lines)
try:
with open(dest) as f:
current = f.read()
except FileNotFoundError:
current = ''
if src != current:
with open(dest, 'w') as f:
f.write(src)
return dest
@lru_cache
def wrapped_kittens() -> str:
with open('shell-integration/ssh/kitty') as f:
@ -879,6 +928,7 @@ def build(args: Options, native_optimizations: bool = True, call_init: bool = Tr
init_env_from_args(args, native_optimizations)
sources, headers = find_c_files()
headers.append(build_ref_map(args.skip_code_generation))
headers.append(build_uniforms_header(args.skip_code_generation))
compile_c_extension(
kitty_env(args), 'kitty/fast_data_types', args.compilation_database, sources, headers
)