diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 7a2332390..9f3821a3c 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -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)); } diff --git a/kitty/gl.c b/kitty/gl.c index c8874d797..188f4562f 100644 --- a/kitty/gl.c +++ b/kitty/gl.c @@ -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); diff --git a/kitty/graphics.c b/kitty/graphics.c index dbfa0ae4a..7aac385eb 100644 --- a/kitty/graphics.c +++ b/kitty/graphics.c @@ -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 } diff --git a/kitty/graphics.h b/kitty/graphics.h index 845c94156..2e4ca6a36 100644 --- a/kitty/graphics.h +++ b/kitty/graphics.h @@ -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; diff --git a/kitty/graphics_fragment.glsl b/kitty/graphics_fragment.glsl index d4d1cd94f..95ce0cbbb 100644 --- a/kitty/graphics_fragment.glsl +++ b/kitty/graphics_fragment.glsl @@ -1,4 +1,3 @@ -#extension GL_ARB_explicit_attrib_location : require #pragma kitty_include_shader #define ALPHA_TYPE diff --git a/kitty/graphics_vertex.glsl b/kitty/graphics_vertex.glsl index 3319f841a..ec782a3ec 100644 --- a/kitty/graphics_vertex.glsl +++ b/kitty/graphics_vertex.glsl @@ -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); } diff --git a/kitty/shaders.c b/kitty/shaders.c index d312da9dd..686922765 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -11,6 +11,7 @@ #include #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; } diff --git a/kitty/state.c b/kitty/state.c index 61dfeef15..c8ad740d7 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -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; diff --git a/kitty/state.h b/kitty/state.h index 8924e996b..1e87f1e2e 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -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*); diff --git a/setup.py b/setup.py index 69cf12b32..f0604c369 100755 --- a/setup.py +++ b/setup.py @@ -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 )