Workaround to get graphics working on Apple's buggy products

Apparently some macOS OpenGL drivers cannot handle using a VAO with
attributes that have different divisors/apply to different shaders. So
use a separate VAO for graphics rendering. This is a small performance hit,
but is the price of supporting substandard computers.
This commit is contained in:
Kovid Goyal 2017-10-17 12:15:52 +05:30
parent 40722f42d3
commit 66803e6873
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 41 additions and 58 deletions

View File

@ -13,7 +13,6 @@ layout(std140) uniform CellRenderData {
};
// Have to use fixed locations here as all variants of the cell program share the same VAO
// location 3 is used in the graphics program which uses the same VAO
layout(location=0) in uvec3 colors;
layout(location=1) in uvec4 sprite_coords;
layout(location=2) in float is_selected;

View File

@ -508,7 +508,7 @@ render(double now) {
draw_borders();
cursor_info.is_visible = false;
#define TD global_state.tab_bar_render_data
if (TD.screen && global_state.num_tabs > 1) draw_cells(TD.vao_idx, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, &cursor_info);
if (TD.screen && global_state.num_tabs > 1) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, &cursor_info);
#undef TD
if (global_state.num_tabs) {
Tab *tab = global_state.tabs + global_state.active_tab;
@ -529,7 +529,7 @@ render(double now) {
collect_cursor_info(&cursor_info, w, now);
update_window_title(w);
} else cursor_info.is_visible = false;
draw_cells(WD.vao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, &cursor_info);
draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, &cursor_info);
if (is_active_window && cursor_info.is_visible && cursor_info.shape != CURSOR_BLOCK) draw_cursor(&cursor_info);
if (WD.screen->start_visual_bell_at != 0) {
double bell_left = global_state.opts.visual_bell_duration - (now - WD.screen->start_visual_bell_at);

View File

@ -1,6 +1,6 @@
#version GLSL_VERSION
layout(location=3) in vec4 src;
in vec4 src;
out vec2 texcoord;
void main() {

View File

@ -11,25 +11,6 @@
enum { CELL_PROGRAM, CELL_BACKGROUND_PROGRAM, CELL_SPECIAL_PROGRAM, CELL_FOREGROUND_PROGRAM, CURSOR_PROGRAM, BORDERS_PROGRAM, GRAPHICS_PROGRAM, NUM_PROGRAMS };
enum { SPRITE_MAP_UNIT, GRAPHICS_UNIT };
static bool broken_multi_vao = false;
static inline void
detect_broken_multi_vao() {
#ifdef __APPLE__
char str[256] = {0};
size_t size = sizeof(str);
int mv = 0;
if (sysctlbyname("kern.osrelease", str, &size, NULL, 0) != 0) broken_multi_vao = true;
else {
mv = atoi(str);
broken_multi_vao = mv < 17;
}
if (broken_multi_vao) {
fprintf(stderr, "WARNING: Old macOS version: %d detected, disabling graphics support!\n", mv);
}
#endif
}
// Sprites {{{
typedef struct {
int xnum, ynum, x, y, z, last_num_of_layers, last_ynum;
@ -215,12 +196,11 @@ init_cell_program() {
for (int p = CELL_PROGRAM; p <= CELL_FOREGROUND_PROGRAM; p++) {
C(p, colors, 0); C(p, sprite_coords, 1); C(p, is_selected, 2);
}
C(GRAPHICS_PROGRAM, src, 3);
#undef C
}
#define CELL_BUFFERS enum { cell_data_buffer, selection_buffer, uniform_buffer, graphics_buffer };
#define CELL_BUFFERS enum { cell_data_buffer, selection_buffer, uniform_buffer };
static ssize_t
create_cell_vao() {
@ -229,7 +209,6 @@ create_cell_vao() {
add_attribute_to_vao(CELL_PROGRAM, vao_idx, #name, \
/*size=*/size, /*dtype=*/dtype, /*stride=*/stride, /*offset=*/offset, /*divisor=*/1);
#define A1(name, size, dtype, offset) A(name, size, dtype, (void*)(offsetof(Cell, offset)), sizeof(Cell))
#define AL(p, name, size, dtype, offset, stride) { GLint aloc = attrib_location(p, #name); if (aloc == -1 ) fatal("No attribute named: %s found in this program", #name); add_located_attribute_to_vao(vao_idx, aloc, size, dtype, stride, offset, 0); }
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
A1(sprite_coords, 4, GL_UNSIGNED_SHORT, sprite_x);
@ -241,15 +220,17 @@ create_cell_vao() {
size_t bufnum = add_buffer_to_vao(vao_idx, GL_UNIFORM_BUFFER);
alloc_vao_buffer(vao_idx, cell_program_layouts[CELL_PROGRAM].render_data.size, bufnum, GL_STREAM_DRAW);
if (!broken_multi_vao) {
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
AL(GRAPHICS_PROGRAM, src, 4, GL_FLOAT, NULL, 0);
}
return vao_idx;
#undef A
#undef A1
#undef AL
}
static ssize_t
create_graphics_vao() {
ssize_t vao_idx = create_vao();
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
add_attribute_to_vao(GRAPHICS_PROGRAM, vao_idx, "src", 4, GL_FLOAT, 0, NULL, 0);
return vao_idx;
}
static inline void
@ -297,7 +278,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
}
static inline void
cell_prepare_to_render(ssize_t vao_idx, Screen *screen, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, CursorRenderInfo *cursor) {
cell_prepare_to_render(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, CursorRenderInfo *cursor) {
size_t sz;
CELL_BUFFERS;
void *address;
@ -315,11 +296,11 @@ cell_prepare_to_render(ssize_t vao_idx, Screen *screen, GLfloat xstart, GLfloat
unmap_vao_buffer(vao_idx, selection_buffer); address = NULL;
}
if (grman_update_layers(screen->grman, screen->scrolled_by, xstart, ystart, dx, dy, screen->columns, screen->lines)) {
if (gvao_idx && grman_update_layers(screen->grman, screen->scrolled_by, xstart, ystart, dx, dy, screen->columns, screen->lines)) {
sz = sizeof(GLfloat) * 16 * screen->grman->count;
GLfloat *a = alloc_and_map_vao_buffer(vao_idx, sz, graphics_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY);
GLfloat *a = alloc_and_map_vao_buffer(gvao_idx, sz, 0, GL_STREAM_DRAW, GL_WRITE_ONLY);
for (size_t i = 0; i < screen->grman->count; i++, a += 16) memcpy(a, screen->grman->render_data[i].vertices, sizeof(screen->grman->render_data[0].vertices));
unmap_vao_buffer(vao_idx, graphics_buffer); a = NULL;
unmap_vao_buffer(gvao_idx, 0); a = NULL;
}
cell_update_uniform_block(vao_idx, screen, uniform_buffer, xstart, ystart, dx, dy, cursor);
@ -332,7 +313,8 @@ cell_prepare_to_render(ssize_t vao_idx, Screen *screen, GLfloat xstart, GLfloat
}
static void
draw_graphics(ImageRenderData *data, GLuint start, GLuint count) {
draw_graphics(ssize_t vao_idx, ssize_t gvao_idx, ImageRenderData *data, GLuint start, GLuint count) {
bind_vertex_array(gvao_idx);
bind_program(GRAPHICS_PROGRAM);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
static bool graphics_constants_set = false;
@ -353,11 +335,11 @@ draw_graphics(ImageRenderData *data, GLuint start, GLuint count) {
for (GLuint k=0; k < rd->group_count; k++, base += 4, i++) glDrawArrays(GL_TRIANGLE_FAN, base, 4);
}
glDisable(GL_SCISSOR_TEST);
bind_vertex_array(vao_idx);
}
static void
draw_all_cells(Screen *screen) {
draw_all_cells(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) {
bind_program(CELL_PROGRAM);
static bool cell_constants_set = false;
if (!cell_constants_set) {
@ -365,15 +347,15 @@ draw_all_cells(Screen *screen) {
cell_constants_set = true;
}
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); check_gl();
if (screen->grman->count) draw_graphics(screen->grman->render_data, 0, screen->grman->count);
if (screen->grman->count) draw_graphics(vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->count);
}
static void
draw_cells_interleaved(Screen *screen) {
draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) {
bind_program(CELL_BACKGROUND_PROGRAM);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); check_gl();
if (screen->grman->num_of_negative_refs) draw_graphics(screen->grman->render_data, 0, screen->grman->num_of_negative_refs);
if (screen->grman->num_of_negative_refs) draw_graphics(vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_negative_refs);
bind_program(CELL_SPECIAL_PROGRAM);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); check_gl();
@ -382,11 +364,11 @@ draw_cells_interleaved(Screen *screen) {
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); check_gl();
if (screen->grman->num_of_positive_refs) draw_graphics(screen->grman->render_data, screen->grman->num_of_negative_refs, screen->grman->num_of_positive_refs);
if (screen->grman->num_of_positive_refs) draw_graphics(vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs, screen->grman->num_of_positive_refs);
}
static void
draw_cells_impl(ssize_t vao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, CursorRenderInfo *cursor) {
draw_cells_impl(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, CursorRenderInfo *cursor) {
GLfloat h = (GLfloat)screen->lines * dy;
#define SCALE(w, x) ((GLfloat)(global_state.viewport_##w) * (GLfloat)(x))
glScissor(
@ -396,10 +378,9 @@ draw_cells_impl(ssize_t vao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLf
(GLsizei)(ceilf(SCALE(height, h / 2.0f)))
);
#undef SCALE
cell_prepare_to_render(vao_idx, screen, xstart, ystart, dx, dy, cursor);
if (screen->grman->num_of_negative_refs) draw_cells_interleaved(screen);
else draw_all_cells(screen);
cell_prepare_to_render(vao_idx, gvao_idx, screen, xstart, ystart, dx, dy, cursor);
if (screen->grman->num_of_negative_refs) draw_cells_interleaved(vao_idx, gvao_idx, screen);
else draw_all_cells(vao_idx, gvao_idx, screen);
}
// }}}
@ -566,6 +547,7 @@ TWO_INT(send_borders_rects)
NO_ARG(init_cell_program)
NO_ARG_INT(create_cell_vao)
NO_ARG_INT(create_graphics_vao)
NO_ARG(destroy_sprite_map)
PYWRAP1(layout_sprite_map) {
unsigned int cell_width, cell_height;
@ -630,6 +612,7 @@ static PyMethodDef module_methods[] = {
MW(send_borders_rects, METH_VARARGS),
MW(init_cell_program, METH_NOARGS),
MW(create_cell_vao, METH_NOARGS),
MW(create_graphics_vao, METH_NOARGS),
MW(layout_sprite_map, METH_VARARGS),
MW(destroy_sprite_map, METH_NOARGS),
MW(clear_buffers, METH_VARARGS),
@ -681,7 +664,6 @@ init_shaders(PyObject *module) {
draw_cursor = &draw_cursor_impl;
free_texture = &free_texture_impl;
send_image_to_gpu = &send_image_to_gpu_impl;
detect_broken_multi_vao();
return true;
}
// }}}

View File

@ -197,7 +197,7 @@ PYWRAP1(set_window_render_data) {
unsigned int window_idx, tab_id;
static ScreenRenderData d = {0};
static WindowGeometry g = {0};
PA("IIiffffOIIII", &tab_id, &window_idx, A(vao_idx), A(xstart), A(ystart), A(dx), A(dy), A(screen), B(left), B(top), B(right), B(bottom));
PA("IIiiffffOIIII", &tab_id, &window_idx, A(vao_idx), A(gvao_idx), A(xstart), A(ystart), A(dx), A(dy), A(screen), B(left), B(top), B(right), B(bottom));
WITH_TAB(tab_id);
Py_CLEAR(tab->windows[window_idx].render_data.screen);

View File

@ -21,7 +21,7 @@ typedef struct {
} Options;
typedef struct {
ssize_t vao_idx;
ssize_t vao_idx, gvao_idx;
float xstart, ystart, dx, dy;
Screen *screen;
} ScreenRenderData;
@ -98,7 +98,7 @@ bool drag_scroll(Window *);
#define EXTERNAL_FUNC(name, ret, ...) typedef ret (*name##_func)(__VA_ARGS__); extern name##_func name
#define EXTERNAL_FUNC0(name, ret) typedef ret (*name##_func)(); extern name##_func name
EXTERNAL_FUNC0(draw_borders, void);
EXTERNAL_FUNC(draw_cells, void, ssize_t, float, float, float, float, Screen *, CursorRenderInfo *);
EXTERNAL_FUNC(draw_cells, void, ssize_t, ssize_t, float, float, float, float, Screen *, CursorRenderInfo *);
EXTERNAL_FUNC(draw_cursor, void, CursorRenderInfo *);
EXTERNAL_FUNC(update_viewport_size, void, int, int);
EXTERNAL_FUNC(free_texture, void, uint32_t*);

View File

@ -17,9 +17,9 @@ from .fast_data_types import (
BRACKETED_PASTE_END, BRACKETED_PASTE_START, CELL_BACKGROUND_PROGRAM,
CELL_FOREGROUND_PROGRAM, CELL_PROGRAM, CELL_SPECIAL_PROGRAM,
CURSOR_PROGRAM, GRAPHICS_PROGRAM, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE,
Screen, compile_program, create_cell_vao, glfw_post_empty_event,
init_cell_program, init_cursor_program, remove_vao, set_window_render_data,
update_window_title, update_window_visibility
Screen, compile_program, create_cell_vao, create_graphics_vao,
glfw_post_empty_event, init_cell_program, init_cursor_program, remove_vao,
set_window_render_data, update_window_title, update_window_visibility
)
from .rgb import to_color
from .terminfo import get_capabilities
@ -70,6 +70,7 @@ class Window:
def __init__(self, tab, child, opts, args):
self.id = next(window_counter)
self.vao_id = create_cell_vao()
self.gvao_id = create_graphics_vao()
self.tab_id = tab.id
self.tabref = weakref.ref(tab)
self.override_title = None
@ -120,7 +121,7 @@ class Window:
else:
sg = self.update_position(new_geometry)
self.geometry = g = new_geometry
set_window_render_data(self.tab_id, window_idx, self.vao_id, sg.xstart, sg.ystart, sg.dx, sg.dy, self.screen, *g[:4])
set_window_render_data(self.tab_id, window_idx, self.vao_id, self.gvao_id, sg.xstart, sg.ystart, sg.dx, sg.dy, self.screen, *g[:4])
def contains(self, x, y):
g = self.geometry
@ -230,7 +231,8 @@ class Window:
def destroy(self):
if self.vao_id is not None:
remove_vao(self.vao_id)
self.vao_id = None
remove_vao(self.gvao_id)
self.vao_id = self.gvao_id = None
# actions {{{