mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-08-03 22:25:57 +00:00
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:
parent
098a38a3a9
commit
248301f8b3
10 changed files with 254 additions and 221 deletions
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
11
kitty/gl.c
11
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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#extension GL_ARB_explicit_attrib_location : require
|
||||
#pragma kitty_include_shader <alpha_blend.glsl>
|
||||
#define ALPHA_TYPE
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
331
kitty/shaders.c
331
kitty/shaders.c
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
|
|
|||
52
setup.py
52
setup.py
|
|
@ -19,7 +19,7 @@ import time
|
|||
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
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue