diff --git a/kitty/gl.h b/kitty/gl.h index 16fb584ff..a4434066f 100644 --- a/kitty/gl.h +++ b/kitty/gl.h @@ -214,6 +214,13 @@ GetShaderInfoLog(PyObject UNUSED *self, PyObject *val) { return ans; } +static PyObject* +ActiveTexture(PyObject UNUSED *self, PyObject *val) { + long tex_id = PyLong_AsLong(val); + glActiveTexture(tex_id); + CHECK_ERROR; + Py_RETURN_NONE; +} static PyObject* DeleteProgram(PyObject UNUSED *self, PyObject *val) { @@ -249,6 +256,43 @@ GenVertexArrays(PyObject UNUSED *self, PyObject *val) { return ans; } +static PyObject* +GenTextures(PyObject UNUSED *self, PyObject *val) { + GLuint arrays[256] = {0}; + unsigned long n = PyLong_AsUnsignedLong(val); + if (n > 256) { PyErr_SetString(PyExc_ValueError, "Generating more than 256 textures in a single call is not supported"); return NULL; } + glGenTextures(n, arrays); + CHECK_ERROR; + if (n == 1) return PyLong_FromUnsignedLong((unsigned long)arrays[0]); + PyObject *ans = PyTuple_New(n); + if (ans == NULL) return PyErr_NoMemory(); + for (size_t i = 0; i < n; i++) { + PyObject *t = PyLong_FromUnsignedLong((unsigned long)arrays[i]); + if (t == NULL) { Py_DECREF(ans); return PyErr_NoMemory(); } + PyTuple_SET_ITEM(ans, i, t); + } + return ans; +} + +static PyObject* +GenBuffers(PyObject UNUSED *self, PyObject *val) { + GLuint arrays[256] = {0}; + unsigned long n = PyLong_AsUnsignedLong(val); + if (n > 256) { PyErr_SetString(PyExc_ValueError, "Generating more than 256 buffers in a single call is not supported"); return NULL; } + glGenBuffers(n, arrays); + CHECK_ERROR; + if (n == 1) return PyLong_FromUnsignedLong((unsigned long)arrays[0]); + PyObject *ans = PyTuple_New(n); + if (ans == NULL) return PyErr_NoMemory(); + for (size_t i = 0; i < n; i++) { + PyObject *t = PyLong_FromUnsignedLong((unsigned long)arrays[i]); + if (t == NULL) { Py_DECREF(ans); return PyErr_NoMemory(); } + PyTuple_SET_ITEM(ans, i, t); + } + return ans; +} + + static PyObject* CreateShader(PyObject UNUSED *self, PyObject *val) { long shader_type = PyLong_AsLong(val); @@ -321,6 +365,68 @@ BindVertexArray(PyObject UNUSED *self, PyObject *val) { Py_RETURN_NONE; } +static PyObject* +GetIntegerv(PyObject UNUSED *self, PyObject *val) { + unsigned long program_id = PyLong_AsUnsignedLong(val); + GLint ans = 0; + glGetIntegerv(program_id, &ans); + CHECK_ERROR; + return PyLong_FromLong((long)ans); +} + +static PyObject* +BindTexture(PyObject UNUSED *self, PyObject *args) { + unsigned int tex_id; int target; + if (!PyArg_ParseTuple(args, "iI", &target, &tex_id)) return NULL; + glBindTexture(target, tex_id); + CHECK_ERROR; + Py_RETURN_NONE; +} + +static PyObject* +TexParameteri(PyObject UNUSED *self, PyObject *args) { + int target, name, param; + if (!PyArg_ParseTuple(args, "iii", &target, &name, ¶m)) return NULL; + glTexParameteri(target, name, param); + CHECK_ERROR; + Py_RETURN_NONE; +} + +static PyObject* +PixelStorei(PyObject UNUSED *self, PyObject *args) { + int name, param; + if (!PyArg_ParseTuple(args, "ii", &name, ¶m)) return NULL; + glPixelStorei(name, param); + CHECK_ERROR; + Py_RETURN_NONE; +} + +static PyObject* +BindBuffer(PyObject UNUSED *self, PyObject *args) { + int tgt; unsigned int buf_id; + if (!PyArg_ParseTuple(args, "iI", &tgt, &buf_id)) return NULL; + glBindBuffer(tgt, buf_id); + CHECK_ERROR; + Py_RETURN_NONE; +} + +static PyObject* +TexBuffer(PyObject UNUSED *self, PyObject *args) { + int tgt, fmt; unsigned int buf_id; + if (!PyArg_ParseTuple(args, "iiI", &tgt, &fmt, &buf_id)) return NULL; + glTexBuffer(tgt, fmt, buf_id); + CHECK_ERROR; + Py_RETURN_NONE; +} + +static PyObject* +DeleteTexture(PyObject UNUSED *self, PyObject *val) { + GLuint tex_id = (GLuint)PyLong_AsUnsignedLong(val); + glDeleteTextures(1, &tex_id); + CHECK_ERROR; + Py_RETURN_NONE; +} + int add_module_gl_constants(PyObject *module) { #define GLC(x) if (PyModule_AddIntConstant(module, #x, x) != 0) { PyErr_NoMemory(); return 0; } GLC(GL_VERSION); @@ -335,6 +441,16 @@ int add_module_gl_constants(PyObject *module) { GLC(GL_FALSE); GLC(GL_COMPILE_STATUS); GLC(GL_LINK_STATUS); + GLC(GL_TEXTURE0); GLC(GL_TEXTURE1); GLC(GL_TEXTURE2); GLC(GL_TEXTURE3); GLC(GL_TEXTURE4); GLC(GL_TEXTURE5); GLC(GL_TEXTURE6); GLC(GL_TEXTURE7); GLC(GL_TEXTURE8); + GLC(GL_MAX_ARRAY_TEXTURE_LAYERS); + GLC(GL_MAX_TEXTURE_SIZE); + GLC(GL_TEXTURE_2D_ARRAY); + GLC(GL_LINEAR); GLC(GL_CLAMP_TO_EDGE); + GLC(GL_TEXTURE_MIN_FILTER); GLC(GL_TEXTURE_MAG_FILTER); + GLC(GL_TEXTURE_WRAP_S); GLC(GL_TEXTURE_WRAP_T); + GLC(GL_UNPACK_ALIGNMENT); + GLC(GL_R8); GLC(GL_RED); GLC(GL_UNSIGNED_BYTE); GLC(GL_RGB32UI); + GLC(GL_TEXTURE_BUFFER); GLC(GL_STATIC_DRAW); return 1; } @@ -355,10 +471,14 @@ int add_module_gl_constants(PyObject *module) { METH(GetAttribLocation, METH_VARARGS) \ METH(ShaderSource, METH_VARARGS) \ METH(CompileShader, METH_O) \ + METH(DeleteTexture, METH_O) \ METH(GetString, METH_O) \ + METH(GetIntegerv, METH_O) \ METH(Clear, METH_O) \ METH(CreateShader, METH_O) \ METH(GenVertexArrays, METH_O) \ + METH(GenTextures, METH_O) \ + METH(GenBuffers, METH_O) \ METH(LinkProgram, METH_O) \ METH(UseProgram, METH_O) \ METH(BindVertexArray, METH_O) \ @@ -366,7 +486,13 @@ int add_module_gl_constants(PyObject *module) { METH(DeleteShader, METH_O) \ METH(GetProgramInfoLog, METH_O) \ METH(GetShaderInfoLog, METH_O) \ + METH(ActiveTexture, METH_O) \ METH(DrawArraysInstanced, METH_VARARGS) \ METH(CreateProgram, METH_NOARGS) \ METH(AttachShader, METH_VARARGS) \ + METH(BindTexture, METH_VARARGS) \ + METH(TexParameteri, METH_VARARGS) \ + METH(PixelStorei, METH_VARARGS) \ + METH(BindBuffer, METH_VARARGS) \ + METH(TexBuffer, METH_VARARGS) \ diff --git a/kitty/shaders.py b/kitty/shaders.py index 4f15b93ff..23964fd4e 100644 --- a/kitty/shaders.py +++ b/kitty/shaders.py @@ -4,18 +4,27 @@ from functools import lru_cache -from OpenGL.arrays import ArrayDatatype import OpenGL.GL as gl +from OpenGL.arrays import ArrayDatatype from OpenGL.GL.ARB.copy_image import glCopyImageSubData # only present in opengl core >= 4.3 from OpenGL.GL.ARB.texture_storage import glTexStorage3D # only present in opengl core >= 4.2 from .fonts import render_cell from .data_types import ITALIC_MASK, BOLD_MASK from .fast_data_types import ( - glCreateProgram, glAttachShader, GL_FRAGMENT_SHADER, GL_VERTEX_SHADER, glLinkProgram, - GL_TRUE, GL_LINK_STATUS, glGetProgramiv, glGetProgramInfoLog, glDeleteShader, glDeleteProgram, - glGenVertexArrays, glCreateShader, glShaderSource, glCompileShader, glGetShaderiv, GL_COMPILE_STATUS, - glGetShaderInfoLog, glGetUniformLocation, glGetAttribLocation, glUseProgram, glBindVertexArray, + glCreateProgram, glAttachShader, GL_FRAGMENT_SHADER, GL_VERTEX_SHADER, + glLinkProgram, GL_TRUE, GL_LINK_STATUS, glGetProgramiv, + glGetProgramInfoLog, glDeleteShader, glDeleteProgram, glGenVertexArrays, + glCreateShader, glShaderSource, glCompileShader, glGetShaderiv, + GL_COMPILE_STATUS, glGetShaderInfoLog, glGetUniformLocation, + glGetAttribLocation, glUseProgram, glBindVertexArray, GL_TEXTURE0, + GL_TEXTURE1, glGetIntegerv, GL_MAX_ARRAY_TEXTURE_LAYERS, + GL_MAX_TEXTURE_SIZE, glDeleteTexture, GL_TEXTURE_2D_ARRAY, glGenTextures, + glBindTexture, glTexParameteri, GL_LINEAR, GL_CLAMP_TO_EDGE, + GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_WRAP_S, + GL_TEXTURE_WRAP_T, glGenBuffers, GL_R8, GL_RED, GL_UNPACK_ALIGNMENT, GL_UNSIGNED_BYTE, + GL_STATIC_DRAW, GL_TEXTURE_BUFFER, GL_RGB32UI, glBindBuffer, glPixelStorei, + glTexBuffer, glActiveTexture ) GL_VERSION = (3, 3) @@ -29,10 +38,10 @@ class Sprites: # TODO: Rewrite this class using the ARB_shader_image_load_store and ARB_shader_storage_buffer_object # extensions one they become available. - def __init__(self, texture_unit=0): + def __init__(self): self.xnum = self.ynum = 1 - self.sampler_num = texture_unit - self.buffer_sampler_num = texture_unit + 1 + self.sampler_num = 0 + self.buffer_sampler_num = 1 self.first_cell_cache = {} self.second_cell_cache = {} self.x = self.y = self.z = 0 @@ -40,9 +49,9 @@ class Sprites: self.last_num_of_layers = 1 def initialize(self): - self.texture_unit = getattr(gl, 'GL_TEXTURE%d' % self.sampler_num) - self.max_array_len = gl.glGetIntegerv(gl.GL_MAX_ARRAY_TEXTURE_LAYERS) - self.max_texture_size = gl.glGetIntegerv(gl.GL_MAX_TEXTURE_SIZE) + self.texture_unit = GL_TEXTURE0 + self.max_array_len = glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS) + self.max_texture_size = glGetIntegerv(GL_MAX_TEXTURE_SIZE) self.do_layout(getattr(self, 'cell_width', 1), getattr(self, 'cell_height', 1)) def do_layout(self, cell_width=1, cell_height=1): @@ -53,7 +62,7 @@ class Sprites: self.max_y = max(1, self.max_texture_size // self.cell_height) self.ynum = 1 if self.texture_id is not None: - gl.glDeleteTextures([self.texture_id]) + glDeleteTexture(self.texture_id) self.texture_id = None @property @@ -63,41 +72,41 @@ class Sprites: def realloc_texture(self): if self.texture_id is None: self.initialize() - tgt = gl.GL_TEXTURE_2D_ARRAY - tex = gl.glGenTextures(1) - gl.glBindTexture(tgt, tex) - gl.glTexParameteri(tgt, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR) - gl.glTexParameteri(tgt, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) - gl.glTexParameteri(tgt, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE) - gl.glTexParameteri(tgt, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE) + tgt = GL_TEXTURE_2D_ARRAY + tex = glGenTextures(1) + glBindTexture(tgt, tex) + glTexParameteri(tgt, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + glTexParameteri(tgt, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + glTexParameteri(tgt, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) + glTexParameteri(tgt, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) znum = self.z + 1 width, height = self.xnum * self.cell_width, self.ynum * self.cell_height - glTexStorage3D(tgt, 1, gl.GL_R8, width, height, znum) + glTexStorage3D(tgt, 1, GL_R8, width, height, znum) if self.texture_id is not None: ynum = self.ynum if self.z == 0: ynum -= 1 # Only copy the previous rows glCopyImageSubData(self.texture_id, tgt, 0, 0, 0, 0, tex, tgt, 0, 0, 0, 0, width, ynum * self.cell_height, self.last_num_of_layers) - gl.glDeleteTextures([self.texture_id]) + glDeleteTexture(self.texture_id) self.last_num_of_layers = znum self.texture_id = tex - gl.glBindTexture(tgt, 0) + glBindTexture(tgt, 0) def ensure_state(self): if self.texture_id is None: self.realloc_texture() - self.buffer_id = gl.glGenBuffers(1) - self.buffer_texture_id = gl.glGenTextures(1) - self.buffer_texture_unit = getattr(gl, 'GL_TEXTURE%d' % self.buffer_sampler_num) + self.buffer_id = glGenBuffers(1) + self.buffer_texture_id = glGenTextures(1) + self.buffer_texture_unit = GL_TEXTURE1 def add_sprite(self, buf): - tgt = gl.GL_TEXTURE_2D_ARRAY - gl.glBindTexture(tgt, self.texture_id) - gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) + tgt = GL_TEXTURE_2D_ARRAY + glBindTexture(tgt, self.texture_id) + glPixelStorei(GL_UNPACK_ALIGNMENT, 1) x, y = self.x * self.cell_width, self.y * self.cell_height - gl.glTexSubImage3D(tgt, 0, x, y, self.z, self.cell_width, self.cell_height, 1, gl.GL_RED, gl.GL_UNSIGNED_BYTE, buf) - gl.glBindTexture(tgt, 0) + gl.glTexSubImage3D(tgt, 0, x, y, self.z, self.cell_width, self.cell_height, 1, GL_RED, GL_UNSIGNED_BYTE, buf) + glBindTexture(tgt, 0) # co-ordinates for this sprite in the sprite sheet x, y, z = self.x, self.y, self.z @@ -115,10 +124,10 @@ class Sprites: return x, y, z def set_sprite_map(self, data): - tgt = gl.GL_TEXTURE_BUFFER - gl.glBindBuffer(tgt, self.buffer_id) - gl.glBufferData(tgt, ArrayDatatype.arrayByteCount(data), data, gl.GL_STATIC_DRAW) - gl.glBindBuffer(tgt, 0) + tgt = GL_TEXTURE_BUFFER + glBindBuffer(tgt, self.buffer_id) + gl.glBufferData(tgt, ArrayDatatype.arrayByteCount(data), data, GL_STATIC_DRAW) + glBindBuffer(tgt, 0) def primary_sprite_position(self, key): ' Return a 3-tuple (x, y, z) giving the position of this sprite on the sprite sheet ' @@ -145,16 +154,16 @@ class Sprites: def __enter__(self): self.ensure_state() - gl.glActiveTexture(self.texture_unit) - gl.glBindTexture(gl.GL_TEXTURE_2D_ARRAY, self.texture_id) + glActiveTexture(self.texture_unit) + glBindTexture(GL_TEXTURE_2D_ARRAY, self.texture_id) - gl.glActiveTexture(self.buffer_texture_unit) - gl.glBindTexture(gl.GL_TEXTURE_BUFFER, self.buffer_texture_id) - gl.glTexBuffer(gl.GL_TEXTURE_BUFFER, gl.GL_RGB32UI, self.buffer_id) + glActiveTexture(self.buffer_texture_unit) + glBindTexture(GL_TEXTURE_BUFFER, self.buffer_texture_id) + glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32UI, self.buffer_id) def __exit__(self, *a): - gl.glBindTexture(gl.GL_TEXTURE_2D_ARRAY, 0) - gl.glBindTexture(gl.GL_TEXTURE_BUFFER, 0) + glBindTexture(GL_TEXTURE_2D_ARRAY, 0) + glBindTexture(GL_TEXTURE_BUFFER, 0) class ShaderProgram: