Migrate function to compile programs

This commit is contained in:
Kovid Goyal
2017-09-10 17:40:05 +05:30
parent d3f2620caf
commit 9c184c794a
4 changed files with 90 additions and 59 deletions

View File

@@ -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')

View File

@@ -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

View File

@@ -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 */
};

View File

@@ -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. '