mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-09 05:35:19 +02:00
Migrate function to compile programs
This commit is contained in:
@@ -8,7 +8,8 @@ from itertools import chain
|
||||
|
||||
from .constants import GLfloat, GLint, GLuint, viewport_size
|
||||
from .fast_data_types import (
|
||||
GL_STATIC_DRAW, GL_TRIANGLE_FAN, glMultiDrawArrays, glUniform3fv
|
||||
GL_STATIC_DRAW, GL_TRIANGLE_FAN, glMultiDrawArrays, glUniform3fv,
|
||||
BORDERS_PROGRAM
|
||||
)
|
||||
from .shaders import ShaderProgram, load_shaders
|
||||
from .utils import pt_to_px
|
||||
@@ -33,7 +34,7 @@ def as_rect(left, top, right, bottom, color=0):
|
||||
class BordersProgram(ShaderProgram):
|
||||
|
||||
def __init__(self):
|
||||
ShaderProgram.__init__(self, *load_shaders('border'))
|
||||
ShaderProgram.__init__(self, BORDERS_PROGRAM, *load_shaders('border'))
|
||||
with self.array_object_creator() as add_attribute:
|
||||
self.vao_id = add_attribute.vao_id
|
||||
add_attribute('rect')
|
||||
|
||||
@@ -12,11 +12,11 @@ from .constants import (
|
||||
GLfloat, GLuint, ScreenGeometry, cell_size, viewport_size
|
||||
)
|
||||
from .fast_data_types import (
|
||||
CELL, CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, GL_BLEND, GL_FLOAT,
|
||||
GL_LINE_LOOP, GL_STATIC_DRAW, GL_TRIANGLE_FAN, GL_UNSIGNED_INT,
|
||||
GL_UNSIGNED_SHORT, glDisable, glDrawArrays, glDrawArraysInstanced,
|
||||
glEnable, glUniform1i, glUniform2f, glUniform2i, glUniform2ui, glUniform4f,
|
||||
glUniform4ui
|
||||
CELL, CELL_PROGRAM, CURSOR_BEAM, CURSOR_BLOCK, CURSOR_PROGRAM,
|
||||
CURSOR_UNDERLINE, GL_BLEND, GL_FLOAT, GL_LINE_LOOP, GL_STATIC_DRAW,
|
||||
GL_TRIANGLE_FAN, GL_UNSIGNED_INT, GL_UNSIGNED_SHORT, glDisable,
|
||||
glDrawArrays, glDrawArraysInstanced, glEnable, glUniform1i, glUniform2f,
|
||||
glUniform2i, glUniform2ui, glUniform4f, glUniform4ui
|
||||
)
|
||||
from .rgb import to_color
|
||||
from .shaders import ShaderProgram, load_shaders
|
||||
@@ -55,8 +55,8 @@ class CellProgram(ShaderProgram): # {{{
|
||||
|
||||
|
||||
def load_shader_programs():
|
||||
cell = CellProgram(*load_shaders('cell'))
|
||||
cursor = ShaderProgram(*load_shaders('cursor'))
|
||||
cell = CellProgram(CELL_PROGRAM, *load_shaders('cell'))
|
||||
cursor = ShaderProgram(CURSOR_PROGRAM, *load_shaders('cursor'))
|
||||
with cursor.array_object_creator() as add_attribute:
|
||||
cursor.vao_id = add_attribute.vao_id
|
||||
return cell, cursor
|
||||
|
||||
@@ -71,19 +71,79 @@ glew_init(PyObject UNUSED *self) {
|
||||
|
||||
enum Program { CELL_PROGRAM, CURSOR_PROGRAM, BORDERS_PROGRAM, NUM_PROGRAMS };
|
||||
|
||||
/* static GLuint program_ids[NUM_PROGRAMS] = {0}; */
|
||||
static GLuint program_ids[NUM_PROGRAMS] = {0};
|
||||
static char glbuf[4096];
|
||||
|
||||
static inline GLuint
|
||||
compile_shader(GLenum shader_type, const char *source) {
|
||||
GLuint shader_id = glCreateShader(shader_type);
|
||||
if (!shader_id) { set_error_from_gl(); return 0; }
|
||||
glShaderSource(shader_id, 1, (const GLchar **)&source, NULL);
|
||||
if (set_error_from_gl()) { glDeleteShader(shader_id); return 0; }
|
||||
glCompileShader(shader_id);
|
||||
if (set_error_from_gl()) { glDeleteShader(shader_id); return 0; }
|
||||
GLint ret = GL_FALSE;
|
||||
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &ret);
|
||||
if (ret != GL_TRUE) {
|
||||
GLsizei len;
|
||||
glGetShaderInfoLog(shader_id, sizeof(glbuf), &len, glbuf);
|
||||
fprintf(stderr, "Failed to compile GLSL shader!\n%s", glbuf);
|
||||
glDeleteShader(shader_id);
|
||||
PyErr_SetString(PyExc_ValueError, "Failed to compile shader");
|
||||
return 0;
|
||||
}
|
||||
return shader_id;
|
||||
}
|
||||
|
||||
// Python API {{{
|
||||
static PyObject*
|
||||
enable_automatic_error_checking(PyObject UNUSED *self, PyObject *val) {
|
||||
enable_automatic_opengl_error_checking(PyObject UNUSED *self, PyObject *val) {
|
||||
_enable_error_checking = PyObject_IsTrue(val) ? true : false;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
compile_program(PyObject UNUSED *self, PyObject *args) {
|
||||
const char *vertex_shader, *fragment_shader;
|
||||
int which;
|
||||
GLuint vertex_shader_id = 0, fragment_shader_id = 0;
|
||||
if (!PyArg_ParseTuple(args, "iss", &which, &vertex_shader, &fragment_shader)) return NULL;
|
||||
if (which < CELL_PROGRAM || which >= NUM_PROGRAMS) { PyErr_Format(PyExc_ValueError, "Unknown program: %d", which); return NULL; }
|
||||
if (program_ids[which] != 0) { PyErr_SetString(PyExc_ValueError, "program already compiled"); return NULL; }
|
||||
program_ids[which] = glCreateProgram();
|
||||
if (program_ids[which] == 0) { set_error_from_gl(); return NULL; }
|
||||
vertex_shader_id = compile_shader(GL_VERTEX_SHADER, vertex_shader);
|
||||
if (vertex_shader_id == 0) goto end;
|
||||
fragment_shader_id = compile_shader(GL_FRAGMENT_SHADER, fragment_shader);
|
||||
if (vertex_shader_id == 0) goto end;
|
||||
glAttachShader(program_ids[which], vertex_shader_id);
|
||||
if (set_error_from_gl()) goto end;
|
||||
glAttachShader(program_ids[which], fragment_shader_id);
|
||||
glLinkProgram(program_ids[which]);
|
||||
GLint ret = GL_FALSE;
|
||||
glGetProgramiv(program_ids[which], GL_LINK_STATUS, &ret);
|
||||
if (ret != GL_TRUE) {
|
||||
GLsizei len;
|
||||
glGetProgramInfoLog(program_ids[which], sizeof(glbuf), &len, glbuf);
|
||||
fprintf(stderr, "Failed to compile GLSL shader!\n%s", glbuf);
|
||||
PyErr_SetString(PyExc_ValueError, "Failed to compile shader");
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
if (vertex_shader_id != 0) glDeleteShader(vertex_shader_id);
|
||||
if (fragment_shader_id != 0) glDeleteShader(fragment_shader_id);
|
||||
if (PyErr_Occurred()) { glDeleteProgram(program_ids[which]); program_ids[which] = 0; return NULL;}
|
||||
return Py_BuildValue("I", program_ids[which]);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#define M(name, arg_type) {#name, (PyCFunction)name, arg_type, ""}
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"enable_automatic_opengl_error_checking", (PyCFunction)enable_automatic_error_checking, METH_O, NULL},
|
||||
M(enable_automatic_opengl_error_checking, METH_O),
|
||||
{"glewInit", (PyCFunction)glew_init, METH_NOARGS, NULL},
|
||||
M(compile_program, METH_VARARGS),
|
||||
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
@@ -10,24 +10,20 @@ from ctypes import addressof, c_char, sizeof
|
||||
from functools import lru_cache
|
||||
|
||||
from .fast_data_types import (
|
||||
GL_ARRAY_BUFFER, GL_CLAMP_TO_EDGE, GL_COMPILE_STATUS, GL_FLOAT,
|
||||
GL_FRAGMENT_SHADER, GL_LINK_STATUS, GL_MAX_ARRAY_TEXTURE_LAYERS,
|
||||
GL_ARRAY_BUFFER, GL_CLAMP_TO_EDGE, GL_FLOAT, GL_MAX_ARRAY_TEXTURE_LAYERS,
|
||||
GL_MAX_TEXTURE_SIZE, GL_NEAREST, GL_R8, GL_RED, GL_STREAM_DRAW,
|
||||
GL_TEXTURE0, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER,
|
||||
GL_TEXTURE_MIN_FILTER, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_TRUE,
|
||||
GL_UNIFORM_BUFFER, GL_UNPACK_ALIGNMENT, GL_UNSIGNED_BYTE, GL_VERTEX_SHADER,
|
||||
GL_WRITE_ONLY, GLSL_VERSION, copy_image_sub_data,
|
||||
GL_TEXTURE_MIN_FILTER, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T,
|
||||
GL_UNIFORM_BUFFER, GL_UNPACK_ALIGNMENT, GL_UNSIGNED_BYTE, GL_WRITE_ONLY,
|
||||
GLSL_VERSION, compile_program, copy_image_sub_data,
|
||||
get_uniform_block_offsets, get_uniform_block_size, glActiveTexture,
|
||||
glAttachShader, glBindBuffer, glBindBufferBase, glBindTexture,
|
||||
glBindVertexArray, glCompileShader, glCopyImageSubData, glCreateProgram,
|
||||
glCreateShader, glDeleteBuffer, glDeleteProgram, glDeleteShader,
|
||||
glDeleteTexture, glDeleteVertexArray, glEnableVertexAttribArray,
|
||||
glGenBuffers, glGenTextures, glGenVertexArrays, glGetAttribLocation,
|
||||
glGetBufferSubData, glGetIntegerv, glGetProgramInfoLog, glGetProgramiv,
|
||||
glGetShaderInfoLog, glGetShaderiv, glGetUniformBlockIndex,
|
||||
glGetUniformLocation, glLinkProgram, glMapBuffer, glPixelStorei,
|
||||
glShaderSource, glTexParameteri, glTexStorage3D, glTexSubImage3D,
|
||||
glUnmapBuffer, glUseProgram, glVertexAttribDivisor, glVertexAttribPointer,
|
||||
glBindBuffer, glBindBufferBase, glBindTexture, glBindVertexArray,
|
||||
glCopyImageSubData, glDeleteBuffer, glDeleteTexture, glDeleteVertexArray,
|
||||
glEnableVertexAttribArray, glGenBuffers, glGenTextures, glGenVertexArrays,
|
||||
glGetAttribLocation, glGetBufferSubData, glGetIntegerv,
|
||||
glGetUniformBlockIndex, glGetUniformLocation, glMapBuffer, glPixelStorei,
|
||||
glTexParameteri, glTexStorage3D, glTexSubImage3D, glUnmapBuffer,
|
||||
glUseProgram, glVertexAttribDivisor, glVertexAttribPointer,
|
||||
render_dirty_sprites, replace_or_create_buffer, sprite_map_current_layout,
|
||||
sprite_map_free, sprite_map_increment, sprite_map_set_layout,
|
||||
sprite_map_set_limits
|
||||
@@ -243,27 +239,16 @@ class Sprites: # {{{
|
||||
class ShaderProgram: # {{{
|
||||
""" Helper class for using GLSL shader programs """
|
||||
|
||||
def __init__(self, vertex, fragment):
|
||||
def __init__(self, which, vertex, fragment):
|
||||
"""
|
||||
Create a shader program.
|
||||
|
||||
"""
|
||||
self.program_id = glCreateProgram()
|
||||
vs_id = self.add_shader(vertex, GL_VERTEX_SHADER)
|
||||
glAttachShader(self.program_id, vs_id)
|
||||
|
||||
frag_id = self.add_shader(fragment, GL_FRAGMENT_SHADER)
|
||||
glAttachShader(self.program_id, frag_id)
|
||||
|
||||
glLinkProgram(self.program_id)
|
||||
if glGetProgramiv(self.program_id, GL_LINK_STATUS) != GL_TRUE:
|
||||
info = glGetProgramInfoLog(self.program_id)
|
||||
glDeleteProgram(self.program_id)
|
||||
glDeleteShader(vs_id)
|
||||
glDeleteShader(frag_id)
|
||||
raise ValueError('Error linking shader program: \n%s' % info.decode('utf-8'))
|
||||
glDeleteShader(vs_id)
|
||||
glDeleteShader(frag_id)
|
||||
self.program_id = compile_program(
|
||||
which,
|
||||
vertex.replace('GLSL_VERSION', str(GLSL_VERSION), 1),
|
||||
fragment.replace('GLSL_VERSION', str(GLSL_VERSION), 1)
|
||||
)
|
||||
self.vertex_arrays = {}
|
||||
|
||||
@contextmanager
|
||||
@@ -329,21 +314,6 @@ class ShaderProgram: # {{{
|
||||
def __ne__(self, other) -> bool:
|
||||
return not self.__eq__(other)
|
||||
|
||||
def add_shader(self, source: str, shader_type: int) -> int:
|
||||
' Compile a shader and return its id, or raise an exception if compilation fails '
|
||||
shader_id = glCreateShader(shader_type)
|
||||
source = source.replace('GLSL_VERSION', str(GLSL_VERSION), 1)
|
||||
try:
|
||||
glShaderSource(shader_id, source)
|
||||
glCompileShader(shader_id)
|
||||
if glGetShaderiv(shader_id, GL_COMPILE_STATUS) != GL_TRUE:
|
||||
info = glGetShaderInfoLog(shader_id)
|
||||
raise ValueError('GLSL {} compilation failed: \n{}'.format(shader_type, info.decode('utf-8')))
|
||||
return shader_id
|
||||
except Exception:
|
||||
glDeleteShader(shader_id)
|
||||
raise
|
||||
|
||||
@lru_cache(maxsize=2**6)
|
||||
def uniform_location(self, name: str) -> int:
|
||||
' Return the id for the uniform variable `name` or -1 if not found. '
|
||||
|
||||
Reference in New Issue
Block a user