Use vertex buffers instead of texture buffers
Apparently, integer samplers for textFetch() are broken on some macOS Intel drivers. Fixes #101
This commit is contained in:
parent
4364163ceb
commit
03e0b9de04
7 changed files with 121 additions and 113 deletions
|
|
@ -145,12 +145,12 @@ def render(self, program):
|
|||
if not self.can_render:
|
||||
return
|
||||
with program:
|
||||
program.bind_vertex_array(program.vao_id)
|
||||
if self.is_dirty:
|
||||
program.send_data(self.rects)
|
||||
program.set_colors(self.color_buf)
|
||||
self.is_dirty = False
|
||||
glMultiDrawArrays(
|
||||
GL_TRIANGLE_FAN,
|
||||
addressof(self.starts),
|
||||
addressof(self.counts), self.num_of_rects)
|
||||
with program.bound_vertex_array(program.vao_id):
|
||||
glMultiDrawArrays(
|
||||
GL_TRIANGLE_FAN,
|
||||
addressof(self.starts),
|
||||
addressof(self.counts), self.num_of_rects)
|
||||
|
|
|
|||
|
|
@ -422,7 +422,8 @@ def render(self):
|
|||
with self.sprites:
|
||||
self.sprites.render_dirty_cells()
|
||||
tab.render()
|
||||
render_data = {window: window.char_grid.prepare_for_render(self.sprites) for window in tab.visible_windows() if not window.needs_layout}
|
||||
render_data = {window: window.char_grid.prepare_for_render(self.cell_program)
|
||||
for window in tab.visible_windows() if not window.needs_layout}
|
||||
with self.cell_program:
|
||||
self.tab_manager.render(self.cell_program, self.sprites)
|
||||
for window, rd in render_data.items():
|
||||
|
|
@ -444,9 +445,7 @@ def render(self):
|
|||
active.char_grid.render_cursor(rd, self.cursor_program, self.window_is_focused)
|
||||
|
||||
def gui_close_window(self, window):
|
||||
if window.char_grid.buffer_id is not None:
|
||||
self.sprites.destroy_sprite_map(window.char_grid.buffer_id)
|
||||
window.char_grid.buffer_id = None
|
||||
window.char_grid.destroy(self.cell_program)
|
||||
for tab in self.tab_manager:
|
||||
if window in tab:
|
||||
break
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
uniform uvec2 dimensions; // xnum, ynum
|
||||
uniform vec4 steps; // xstart, ystart, dx, dy
|
||||
uniform vec2 sprite_layout; // dx, dy
|
||||
uniform usamplerBuffer sprite_map; // gl_InstanceID -> x, y, z
|
||||
uniform ivec2 color_indices; // which color to use as fg and which as bg
|
||||
in uvec3 sprite_coords;
|
||||
in uvec3 colors;
|
||||
out vec3 sprite_pos;
|
||||
out vec3 underline_pos;
|
||||
out vec3 strike_pos;
|
||||
|
|
@ -46,15 +47,10 @@ void main() {
|
|||
uvec2 pos = pos_map[gl_VertexID];
|
||||
gl_Position = vec4(xpos[pos[0]], ypos[pos[1]], 0, 1);
|
||||
|
||||
int sprite_id = gl_InstanceID * STRIDE;
|
||||
uint x = texelFetch(sprite_map, sprite_id).r;
|
||||
uint y = texelFetch(sprite_map, sprite_id + 1).r;
|
||||
uint z = texelFetch(sprite_map, sprite_id + 2).r;
|
||||
sprite_pos = to_sprite_pos(pos, x, y, z);
|
||||
sprite_id += 3;
|
||||
uint fg = texelFetch(sprite_map, sprite_id + color_indices[0]).r;
|
||||
uint bg = texelFetch(sprite_map, sprite_id + color_indices[1]).r;
|
||||
uint decoration = texelFetch(sprite_map, sprite_id + 2).r;
|
||||
sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z);
|
||||
uint fg = colors[color_indices[0]];
|
||||
uint bg = colors[color_indices[1]];
|
||||
uint decoration = colors[2];
|
||||
foreground = to_color(fg);
|
||||
background = to_color(bg);
|
||||
decoration_fg = to_color(decoration);
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
import re
|
||||
import sys
|
||||
from enum import Enum
|
||||
from collections import namedtuple
|
||||
from ctypes import addressof, memmove, sizeof
|
||||
from enum import Enum
|
||||
from threading import Lock
|
||||
|
||||
from .config import build_ansi_color_table, defaults
|
||||
|
|
@ -15,12 +15,12 @@
|
|||
)
|
||||
from .fast_data_types import (
|
||||
CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, DATA_CELL_SIZE, GL_BLEND,
|
||||
GL_LINE_LOOP, GL_TRIANGLE_FAN, ColorProfile, glDisable, glDrawArrays,
|
||||
glDrawArraysInstanced, glEnable, glUniform1i, glUniform2f, glUniform2ui,
|
||||
glUniform4f, glUniform2i
|
||||
GL_LINE_LOOP, GL_STREAM_DRAW, GL_TRIANGLE_FAN, GL_UNSIGNED_INT,
|
||||
ColorProfile, glDisable, glDrawArrays, glDrawArraysInstanced, glEnable,
|
||||
glUniform1i, glUniform2f, glUniform2i, glUniform2ui, glUniform4f
|
||||
)
|
||||
from .rgb import to_color
|
||||
from .shaders import load_shaders, ShaderProgram
|
||||
from .shaders import ShaderProgram, load_shaders
|
||||
from .utils import (
|
||||
color_as_int, color_from_int, get_logical_dpi, open_url, safe_print,
|
||||
set_primary_selection
|
||||
|
|
@ -33,12 +33,22 @@ class DynamicColor(Enum):
|
|||
default_fg, default_bg, cursor_color, highlight_fg, highlight_bg = range(1, 6)
|
||||
|
||||
|
||||
class CellProgram(ShaderProgram):
|
||||
|
||||
def create_sprite_map(self):
|
||||
stride = DATA_CELL_SIZE * sizeof(GLuint)
|
||||
size = DATA_CELL_SIZE // 2
|
||||
return self.add_vertex_arrays(
|
||||
self.vertex_array('sprite_coords', size=size, dtype=GL_UNSIGNED_INT, stride=stride, divisor=1),
|
||||
self.vertex_array('colors', size=size, dtype=GL_UNSIGNED_INT, stride=stride, offset=stride // 2, divisor=1),
|
||||
)
|
||||
|
||||
|
||||
def load_shader_programs():
|
||||
vert, frag = load_shaders('cell')
|
||||
vert = vert.replace('STRIDE', str(DATA_CELL_SIZE))
|
||||
cell = ShaderProgram(vert, frag)
|
||||
cell = CellProgram(vert, frag)
|
||||
cursor = ShaderProgram(*load_shaders('cursor'))
|
||||
cell.vao_id = cell.add_vertex_arrays()
|
||||
cursor.vao_id = cursor.add_vertex_arrays()
|
||||
return cell, cursor
|
||||
|
||||
|
|
@ -112,17 +122,15 @@ def calculate_gl_geometry(window_geometry):
|
|||
return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy)
|
||||
|
||||
|
||||
def render_cells(buffer_id, sg, cell_program, sprites, invert_colors=False):
|
||||
sprites.bind_sprite_map(buffer_id)
|
||||
def render_cells(vao_id, sg, cell_program, sprites, invert_colors=False):
|
||||
ul = cell_program.uniform_location
|
||||
glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
|
||||
glUniform2i(ul('color_indices'), 1 if invert_colors else 0, 0 if invert_colors else 1)
|
||||
glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy)
|
||||
glUniform1i(ul('sprites'), sprites.sampler_num)
|
||||
glUniform1i(ul('sprite_map'), sprites.buffer_sampler_num)
|
||||
glUniform2f(ul('sprite_layout'), *(sprites.layout))
|
||||
cell_program.bind_vertex_array(cell_program.vao_id)
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum)
|
||||
with cell_program.bound_vertex_array(vao_id):
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum)
|
||||
|
||||
|
||||
class CharGrid:
|
||||
|
|
@ -131,7 +139,7 @@ class CharGrid:
|
|||
|
||||
def __init__(self, screen, opts):
|
||||
self.buffer_lock = Lock()
|
||||
self.buffer_id = None
|
||||
self.vao_id = None
|
||||
self.current_selection = Selection()
|
||||
self.last_rendered_selection = self.current_selection.limits(0, screen.lines, screen.columns)
|
||||
self.render_buf_is_dirty = True
|
||||
|
|
@ -159,6 +167,11 @@ def escape(chars):
|
|||
safe_print('Invalid characters in select_by_word_characters, ignoring', file=sys.stderr)
|
||||
self.word_pat = re.compile(r'[\w{}]'.format(escape(defaults.select_by_word_characters)), re.UNICODE)
|
||||
|
||||
def destroy(self, cell_program):
|
||||
if self.vao_id is not None:
|
||||
cell_program.remove_vertex_array(self.vao_id)
|
||||
self.vao_id = None
|
||||
|
||||
def update_position(self, window_geometry):
|
||||
self.screen_geometry = calculate_gl_geometry(window_geometry)
|
||||
|
||||
|
|
@ -343,13 +356,13 @@ def text_for_selection(self, sel=None):
|
|||
s = sel or self.current_selection
|
||||
return s.text(self.screen.linebuf, self.screen.historybuf)
|
||||
|
||||
def prepare_for_render(self, sprites):
|
||||
def prepare_for_render(self, cell_program):
|
||||
with self.buffer_lock:
|
||||
sg = self.render_data
|
||||
if sg is None:
|
||||
return
|
||||
if self.buffer_id is None:
|
||||
self.buffer_id = sprites.add_sprite_map()
|
||||
if self.vao_id is None:
|
||||
self.vao_id = cell_program.create_sprite_map()
|
||||
buf = self.render_buf
|
||||
start, end = sel = self.current_selection.limits(self.scrolled_by, self.screen.lines, self.screen.columns)
|
||||
if start != end:
|
||||
|
|
@ -362,13 +375,13 @@ def prepare_for_render(self, sprites):
|
|||
bg = bg >> 8 if bg & 2 else self.highlight_bg
|
||||
self.screen.apply_selection(addressof(buf), start[0], start[1], end[0], end[1], fg, bg)
|
||||
if self.render_buf_is_dirty or self.last_rendered_selection != sel:
|
||||
sprites.set_sprite_map(self.buffer_id, buf)
|
||||
cell_program.send_vertex_data(self.vao_id, buf, usage=GL_STREAM_DRAW)
|
||||
self.render_buf_is_dirty = False
|
||||
self.last_rendered_selection = sel
|
||||
return sg
|
||||
|
||||
def render_cells(self, sg, cell_program, sprites, invert_colors=False):
|
||||
render_cells(self.buffer_id, sg, cell_program, sprites, invert_colors=invert_colors)
|
||||
render_cells(self.vao_id, sg, cell_program, sprites, invert_colors=invert_colors)
|
||||
|
||||
def render_cursor(self, sg, cursor_program, is_focused):
|
||||
cursor = self.current_cursor
|
||||
|
|
@ -398,6 +411,6 @@ def width(w=2, vert=True):
|
|||
glUniform4f(ul('color'), col[0] / 255.0, col[1] / 255.0, col[2] / 255.0, alpha)
|
||||
glUniform2f(ul('xpos'), left, right)
|
||||
glUniform2f(ul('ypos'), top, bottom)
|
||||
cursor_program.bind_vertex_array(cursor_program.vao_id)
|
||||
glDrawArrays(GL_TRIANGLE_FAN if is_focused else GL_LINE_LOOP, 0, 4)
|
||||
with cursor_program.bound_vertex_array(cursor_program.vao_id):
|
||||
glDrawArrays(GL_TRIANGLE_FAN if is_focused else GL_LINE_LOOP, 0, 4)
|
||||
glDisable(GL_BLEND)
|
||||
|
|
|
|||
26
kitty/gl.h
26
kitty/gl.h
|
|
@ -665,13 +665,23 @@ EnableVertexAttribArray(PyObject UNUSED *self, PyObject *val) {
|
|||
|
||||
static PyObject*
|
||||
VertexAttribPointer(PyObject UNUSED *self, PyObject *args) {
|
||||
unsigned int index, stride;
|
||||
int type=GL_FLOAT, normalized, size;
|
||||
void *offset;
|
||||
PyObject *l;
|
||||
if (!PyArg_ParseTuple(args, "IiipIO!", &index, &size, &type, &normalized, &stride, &PyLong_Type, &l)) return NULL;
|
||||
offset = PyLong_AsVoidPtr(l);
|
||||
glVertexAttribPointer(index, size, type, normalized, stride, offset);
|
||||
unsigned int index;
|
||||
int type, normalized, size, stride;
|
||||
unsigned long offset;
|
||||
if (!PyArg_ParseTuple(args, "Iiipik", &index, &size, &type, &normalized, &stride, &offset)) return NULL;
|
||||
switch(type) {
|
||||
case GL_BYTE:
|
||||
case GL_UNSIGNED_BYTE:
|
||||
case GL_SHORT:
|
||||
case GL_UNSIGNED_SHORT:
|
||||
case GL_INT:
|
||||
case GL_UNSIGNED_INT:
|
||||
glVertexAttribIPointer(index, size, type, stride, (GLvoid*)offset);
|
||||
break;
|
||||
default:
|
||||
glVertexAttribPointer(index, size, type, normalized ? GL_TRUE : GL_FALSE, stride, (GLvoid*)offset);
|
||||
break;
|
||||
}
|
||||
CHECK_ERROR;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
|
@ -744,7 +754,7 @@ int add_module_gl_constants(PyObject *module) {
|
|||
GLC(GL_R8); GLC(GL_RED); GLC(GL_UNSIGNED_BYTE); GLC(GL_R32UI); GLC(GL_RGB32UI); GLC(GL_RGBA);
|
||||
GLC(GL_TEXTURE_BUFFER); GLC(GL_STATIC_DRAW); GLC(GL_STREAM_DRAW);
|
||||
GLC(GL_SRC_ALPHA); GLC(GL_ONE_MINUS_SRC_ALPHA);
|
||||
GLC(GL_BLEND); GLC(GL_FLOAT); GLC(GL_ARRAY_BUFFER);
|
||||
GLC(GL_BLEND); GLC(GL_FLOAT); GLC(GL_UNSIGNED_INT); GLC(GL_ARRAY_BUFFER);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
import os
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from contextlib import contextmanager
|
||||
from ctypes import addressof, sizeof
|
||||
from functools import lru_cache
|
||||
from threading import Lock
|
||||
|
|
@ -12,22 +13,21 @@
|
|||
from .fast_data_types import (
|
||||
BOLD, GL_ARRAY_BUFFER, GL_CLAMP_TO_EDGE, GL_COMPILE_STATUS, GL_FLOAT,
|
||||
GL_FRAGMENT_SHADER, GL_LINK_STATUS, GL_MAX_ARRAY_TEXTURE_LAYERS,
|
||||
GL_MAX_TEXTURE_BUFFER_SIZE, GL_MAX_TEXTURE_SIZE, GL_NEAREST, GL_R8,
|
||||
GL_R32UI, GL_RED, GL_STATIC_DRAW, GL_STREAM_DRAW, GL_TEXTURE0,
|
||||
GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BUFFER, GL_TEXTURE_MAG_FILTER,
|
||||
GL_TEXTURE_MIN_FILTER, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_TRUE,
|
||||
GL_UNPACK_ALIGNMENT, GL_UNSIGNED_BYTE, GL_VERTEX_SHADER, ITALIC, SpriteMap,
|
||||
copy_image_sub_data, glActiveTexture, glAttachShader, glBindBuffer,
|
||||
glBindTexture, glBindVertexArray, glCompileShader, glCopyImageSubData,
|
||||
glCreateProgram, glCreateShader, glDeleteBuffer, glDeleteProgram,
|
||||
glDeleteShader, glDeleteTexture, glDeleteVertexArray,
|
||||
glEnableVertexAttribArray, glGenBuffers, glGenTextures, glGenVertexArrays,
|
||||
glGetAttribLocation, glGetBufferSubData, glGetIntegerv,
|
||||
glGetProgramInfoLog, glGetProgramiv, glGetShaderInfoLog, glGetShaderiv,
|
||||
glGetUniformLocation, glLinkProgram, glPixelStorei, glShaderSource,
|
||||
glTexBuffer, glTexParameteri, glTexStorage3D, glTexSubImage3D,
|
||||
glUseProgram, glVertexAttribDivisor, glVertexAttribPointer,
|
||||
replace_or_create_buffer
|
||||
GL_MAX_TEXTURE_SIZE, GL_NEAREST, GL_R8, GL_R32UI, GL_RED, GL_STATIC_DRAW,
|
||||
GL_STREAM_DRAW, GL_TEXTURE0, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BUFFER,
|
||||
GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_WRAP_S,
|
||||
GL_TEXTURE_WRAP_T, GL_TRUE, GL_UNPACK_ALIGNMENT, GL_UNSIGNED_BYTE,
|
||||
GL_VERTEX_SHADER, ITALIC, SpriteMap, copy_image_sub_data, glActiveTexture,
|
||||
glAttachShader, glBindBuffer, glBindTexture, glBindVertexArray,
|
||||
glCompileShader, glCopyImageSubData, glCreateProgram, glCreateShader,
|
||||
glDeleteBuffer, glDeleteProgram, glDeleteShader, glDeleteTexture,
|
||||
glDeleteVertexArray, glEnableVertexAttribArray, glGenBuffers,
|
||||
glGenTextures, glGenVertexArrays, glGetAttribLocation, glGetBufferSubData,
|
||||
glGetIntegerv, glGetProgramInfoLog, glGetProgramiv, glGetShaderInfoLog,
|
||||
glGetShaderiv, glGetUniformLocation, glLinkProgram, glPixelStorei,
|
||||
glShaderSource, glTexBuffer, glTexParameteri, glTexStorage3D,
|
||||
glTexSubImage3D, glUseProgram, glVertexAttribDivisor,
|
||||
glVertexAttribPointer, replace_or_create_buffer
|
||||
)
|
||||
from .fonts.render import render_cell
|
||||
from .utils import safe_print
|
||||
|
|
@ -83,6 +83,12 @@ def bind(self, buf_id):
|
|||
def unbind(self, buf_id):
|
||||
glBindBuffer(self.types[buf_id], 0)
|
||||
|
||||
@contextmanager
|
||||
def bound_buffer(self, buf_id):
|
||||
self.bind(buf_id)
|
||||
yield
|
||||
self.unbind(buf_id)
|
||||
|
||||
|
||||
buffer_manager = BufferManager()
|
||||
# }}}
|
||||
|
|
@ -104,11 +110,8 @@ def __init__(self):
|
|||
self.last_num_of_layers = 1
|
||||
self.last_ynum = -1
|
||||
self.sampler_num = 0
|
||||
self.buffer_sampler_num = 1
|
||||
self.texture_unit = GL_TEXTURE0 + self.sampler_num
|
||||
self.buffer_texture_unit = GL_TEXTURE0 + self.buffer_sampler_num
|
||||
self.backend = SpriteMap(glGetIntegerv(GL_MAX_TEXTURE_SIZE), glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS))
|
||||
self.max_texture_buffer_size = glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE)
|
||||
self.lock = Lock()
|
||||
|
||||
def do_layout(self, cell_width=1, cell_height=1):
|
||||
|
|
@ -210,31 +213,11 @@ def ensure_state(self):
|
|||
if self.buffer_texture_id is None:
|
||||
self.buffer_texture_id = glGenTextures(1)
|
||||
|
||||
def add_sprite_map(self):
|
||||
return buffer_manager.create()
|
||||
|
||||
def set_sprite_map(self, buf_id, data, usage=GL_STREAM_DRAW):
|
||||
new_sz = sizeof(data)
|
||||
if new_sz // 4 > self.max_texture_buffer_size:
|
||||
raise RuntimeError(('The OpenGL implementation on your system has a max_texture_buffer_size of {} which'
|
||||
' is insufficient for the sprite_map').format(self.max_texture_buffer_size))
|
||||
buffer_manager.set_data(buf_id, data, usage)
|
||||
|
||||
def bind_sprite_map(self, buf_id):
|
||||
buffer_manager.bind(buf_id)
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, buf_id)
|
||||
|
||||
def destroy_sprite_map(self, buf_id):
|
||||
buffer_manager.delete(buf_id)
|
||||
|
||||
def __enter__(self):
|
||||
self.ensure_state()
|
||||
glActiveTexture(self.texture_unit)
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, self.texture_id)
|
||||
|
||||
glActiveTexture(self.buffer_texture_unit)
|
||||
glBindTexture(GL_TEXTURE_BUFFER, self.buffer_texture_id)
|
||||
|
||||
def __exit__(self, *a):
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, 0)
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0)
|
||||
|
|
@ -243,7 +226,7 @@ def __exit__(self, *a):
|
|||
# }}}
|
||||
|
||||
|
||||
class ShaderProgram:
|
||||
class ShaderProgram: # {{{
|
||||
""" Helper class for using GLSL shader programs """
|
||||
|
||||
def __init__(self, vertex, fragment):
|
||||
|
|
@ -275,20 +258,21 @@ def vertex_array(self, name, size=3, dtype=GL_FLOAT, normalized=False, stride=0,
|
|||
def add_vertex_arrays(self, *arrays):
|
||||
vao_id = glGenVertexArrays(1)
|
||||
self.vertex_arrays[vao_id] = buf_id = buffer_manager.create(for_use=GL_ARRAY_BUFFER)
|
||||
glBindVertexArray(vao_id)
|
||||
buffer_manager.bind(buf_id)
|
||||
for x in arrays:
|
||||
aid = self.attribute_location(x.name)
|
||||
glEnableVertexAttribArray(aid)
|
||||
glVertexAttribPointer(aid, x.size, x.dtype, x.normalized, x.stride, x.offset)
|
||||
if x.divisor > 0:
|
||||
glVertexAttribDivisor(aid, x.divisor)
|
||||
buffer_manager.unbind(buf_id)
|
||||
glBindVertexArray(0)
|
||||
return vao_id
|
||||
with self.bound_vertex_array(vao_id), buffer_manager.bound_buffer(buf_id):
|
||||
for x in arrays:
|
||||
aid = self.attribute_location(x.name)
|
||||
if aid > -1:
|
||||
glEnableVertexAttribArray(aid)
|
||||
glVertexAttribPointer(aid, x.size, x.dtype, x.normalized, x.stride, x.offset)
|
||||
if x.divisor > 0:
|
||||
glVertexAttribDivisor(aid, x.divisor)
|
||||
return vao_id
|
||||
|
||||
def bind_vertex_array(self, vao_id):
|
||||
@contextmanager
|
||||
def bound_vertex_array(self, vao_id):
|
||||
glBindVertexArray(vao_id)
|
||||
yield
|
||||
glBindVertexArray(0)
|
||||
|
||||
def remove_vertex_array(self, vao_id):
|
||||
buf_id = self.vertex_arrays.pop(vao_id, None)
|
||||
|
|
@ -339,4 +323,4 @@ def __enter__(self):
|
|||
|
||||
def __exit__(self, *args):
|
||||
glUseProgram(0)
|
||||
glBindVertexArray(0)
|
||||
# }}}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,24 @@
|
|||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from collections import deque
|
||||
from ctypes import addressof
|
||||
from functools import partial
|
||||
from threading import Lock
|
||||
from ctypes import addressof
|
||||
|
||||
from .borders import Borders
|
||||
from .char_grid import calculate_gl_geometry, render_cells
|
||||
from .child import Child
|
||||
from .config import build_ansi_color_table
|
||||
from .constants import get_boss, appname, shell_path, cell_size, queue_action, viewport_size, WindowGeometry, GLuint
|
||||
from .fast_data_types import glfw_post_empty_event, Screen, DECAWM, DATA_CELL_SIZE, ColorProfile
|
||||
from .char_grid import calculate_gl_geometry, render_cells
|
||||
from .layout import all_layouts, Rect
|
||||
from .constants import (
|
||||
GLuint, WindowGeometry, appname, cell_size, get_boss, queue_action,
|
||||
shell_path, viewport_size
|
||||
)
|
||||
from .fast_data_types import (
|
||||
DATA_CELL_SIZE, DECAWM, GL_STREAM_DRAW, ColorProfile, Screen,
|
||||
glfw_post_empty_event
|
||||
)
|
||||
from .layout import Rect, all_layouts
|
||||
from .utils import color_as_int
|
||||
from .borders import Borders
|
||||
from .window import Window
|
||||
|
||||
|
||||
|
|
@ -202,7 +208,7 @@ class TabManager:
|
|||
|
||||
def __init__(self, opts, args, startup_session):
|
||||
self.opts, self.args = opts, args
|
||||
self.buffer_id = None
|
||||
self.vao_id = None
|
||||
self.tabbar_lock = Lock()
|
||||
self.tabs = [Tab(opts, args, self.title_changed, t) for t in startup_session.tabs]
|
||||
self.cell_ranges = []
|
||||
|
|
@ -306,7 +312,7 @@ def remove(self, tab):
|
|||
if needs_resize:
|
||||
queue_action(get_boss().tabbar_visibility_changed)
|
||||
|
||||
def update_tab_bar_data(self, sprites):
|
||||
def update_tab_bar_data(self, sprites, cell_program):
|
||||
s = self.tab_bar_screen
|
||||
s.cursor.x = 0
|
||||
s.erase_in_line(2, False)
|
||||
|
|
@ -336,9 +342,9 @@ def update_tab_bar_data(self, sprites):
|
|||
s.update_cell_data(
|
||||
sprites.backend, self.color_profile, addressof(self.sprite_map), self.default_fg, self.default_bg, True)
|
||||
sprites.render_dirty_cells()
|
||||
if self.buffer_id is None:
|
||||
self.buffer_id = sprites.add_sprite_map()
|
||||
sprites.set_sprite_map(self.buffer_id, self.sprite_map)
|
||||
if self.vao_id is None:
|
||||
self.vao_id = cell_program.create_sprite_map()
|
||||
cell_program.send_vertex_data(self.vao_id, self.sprite_map, usage=GL_STREAM_DRAW)
|
||||
|
||||
def activate_tab_at(self, x):
|
||||
x = (x - self.window_geometry.left) // cell_size.width
|
||||
|
|
@ -358,5 +364,5 @@ def render(self, cell_program, sprites):
|
|||
return
|
||||
with self.tabbar_lock:
|
||||
if self.tabbar_dirty:
|
||||
self.update_tab_bar_data(sprites)
|
||||
render_cells(self.buffer_id, self.screen_geometry, cell_program, sprites)
|
||||
self.update_tab_bar_data(sprites, cell_program)
|
||||
render_cells(self.vao_id, self.screen_geometry, cell_program, sprites)
|
||||
|
|
|
|||
Loading…
Reference in a new issue