Use the glad provided facility for debugging OpenGL
This commit is contained in:
parent
6362499fc2
commit
7ed272e971
63
kitty/gl.h
63
kitty/gl.h
@ -22,19 +22,10 @@ static char glbuf[4096];
|
|||||||
#define REQUIRED_VERSION_MINOR 3
|
#define REQUIRED_VERSION_MINOR 3
|
||||||
#define GLSL_VERSION (REQUIRED_VERSION_MAJOR * 100 + REQUIRED_VERSION_MINOR * 10)
|
#define GLSL_VERSION (REQUIRED_VERSION_MAJOR * 100 + REQUIRED_VERSION_MINOR * 10)
|
||||||
|
|
||||||
#ifndef GL_STACK_UNDERFLOW
|
|
||||||
#define GL_STACK_UNDERFLOW 0x0504
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GL_STACK_OVERFLOW
|
|
||||||
#define GL_STACK_OVERFLOW 0x0503
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ENABLE_DEBUG_GL
|
|
||||||
static void
|
static void
|
||||||
check_for_gl_error(int line) {
|
check_for_gl_error(const char *name, void UNUSED *funcptr, int UNUSED len_args, ...) {
|
||||||
#define f(msg) fatal("%s (at line: %d)", msg, line); break;
|
#define f(msg) fatal("OpenGL error: %s (calling function: %s)", msg, name); break;
|
||||||
int code = glGetError();
|
GLenum code = glad_glGetError();
|
||||||
switch(code) {
|
switch(code) {
|
||||||
case GL_NO_ERROR: break;
|
case GL_NO_ERROR: break;
|
||||||
case GL_INVALID_ENUM:
|
case GL_INVALID_ENUM:
|
||||||
@ -52,16 +43,11 @@ check_for_gl_error(int line) {
|
|||||||
case GL_STACK_OVERFLOW:
|
case GL_STACK_OVERFLOW:
|
||||||
f("An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_OVERFLOW)");
|
f("An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_OVERFLOW)");
|
||||||
default:
|
default:
|
||||||
fatal("An unknown OpenGL error occurred with code: %d (at line: %d)", code, line);
|
fatal("An unknown OpenGL error occurred with code: %d (calling function: %s)", code, name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define check_gl() { check_for_gl_error(__LINE__); }
|
|
||||||
#else
|
|
||||||
#define check_gl() {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
gl_init(PyObject UNUSED *self, PyObject *args) {
|
gl_init(PyObject UNUSED *self, PyObject *args) {
|
||||||
int is_wayland, debug;
|
int is_wayland, debug;
|
||||||
@ -69,6 +55,7 @@ gl_init(PyObject UNUSED *self, PyObject *args) {
|
|||||||
if (!init_glad((GLADloadproc) glfwGetProcAddress, debug)) {
|
if (!init_glad((GLADloadproc) glfwGetProcAddress, debug)) {
|
||||||
fatal("Loading the OpenGL library failed");
|
fatal("Loading the OpenGL library failed");
|
||||||
}
|
}
|
||||||
|
glad_set_post_callback(check_for_gl_error);
|
||||||
#define ARB_TEST(name) \
|
#define ARB_TEST(name) \
|
||||||
if (!GLAD_GL_ARB_##name) { \
|
if (!GLAD_GL_ARB_##name) { \
|
||||||
fatal("The OpenGL driver on this system is missing the required extension: ARB_%s", #name); \
|
fatal("The OpenGL driver on this system is missing the required extension: ARB_%s", #name); \
|
||||||
@ -81,25 +68,25 @@ gl_init(PyObject UNUSED *self, PyObject *args) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
update_viewport_size_impl(int w, int h) {
|
update_viewport_size_impl(int w, int h) {
|
||||||
glViewport(0, 0, w, h); check_gl();
|
glViewport(0, 0, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_texture_impl(GLuint *tex_id) {
|
free_texture_impl(GLuint *tex_id) {
|
||||||
glDeleteTextures(1, tex_id); check_gl();
|
glDeleteTextures(1, tex_id);
|
||||||
*tex_id = 0;
|
*tex_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
send_image_to_gpu_impl(GLuint *tex_id, const void* data, GLsizei width, GLsizei height, bool is_opaque, bool is_4byte_aligned) {
|
send_image_to_gpu_impl(GLuint *tex_id, const void* data, GLsizei width, GLsizei height, bool is_opaque, bool is_4byte_aligned) {
|
||||||
if (!(*tex_id)) { glGenTextures(1, tex_id); check_gl(); }
|
if (!(*tex_id)) { glGenTextures(1, tex_id); }
|
||||||
glBindTexture(GL_TEXTURE_2D, *tex_id); check_gl();
|
glBindTexture(GL_TEXTURE_2D, *tex_id);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, is_4byte_aligned ? 4 : 1); check_gl();
|
glPixelStorei(GL_UNPACK_ALIGNMENT, is_4byte_aligned ? 4 : 1);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); check_gl();
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, is_opaque ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, data); check_gl();
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, is_opaque ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -132,11 +119,8 @@ static Program programs[64] = {{0}};
|
|||||||
static inline GLuint
|
static inline GLuint
|
||||||
compile_shader(GLenum shader_type, const char *source) {
|
compile_shader(GLenum shader_type, const char *source) {
|
||||||
GLuint shader_id = glCreateShader(shader_type);
|
GLuint shader_id = glCreateShader(shader_type);
|
||||||
check_gl();
|
|
||||||
glShaderSource(shader_id, 1, (const GLchar **)&source, NULL);
|
glShaderSource(shader_id, 1, (const GLchar **)&source, NULL);
|
||||||
check_gl();
|
|
||||||
glCompileShader(shader_id);
|
glCompileShader(shader_id);
|
||||||
check_gl();
|
|
||||||
GLint ret = GL_FALSE;
|
GLint ret = GL_FALSE;
|
||||||
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &ret);
|
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &ret);
|
||||||
if (ret != GL_TRUE) {
|
if (ret != GL_TRUE) {
|
||||||
@ -157,11 +141,9 @@ static inline void
|
|||||||
init_uniforms(int program) {
|
init_uniforms(int program) {
|
||||||
Program *p = programs + program;
|
Program *p = programs + program;
|
||||||
glGetProgramiv(p->id, GL_ACTIVE_UNIFORMS, &(p->num_of_uniforms));
|
glGetProgramiv(p->id, GL_ACTIVE_UNIFORMS, &(p->num_of_uniforms));
|
||||||
check_gl();
|
|
||||||
for (GLint i = 0; i < p->num_of_uniforms; i++) {
|
for (GLint i = 0; i < p->num_of_uniforms; i++) {
|
||||||
Uniform *u = p->uniforms + i;
|
Uniform *u = p->uniforms + i;
|
||||||
glGetActiveUniform(p->id, (GLuint)i, sizeof(u->name)/sizeof(u->name[0]), NULL, &(u->size), &(u->type), u->name);
|
glGetActiveUniform(p->id, (GLuint)i, sizeof(u->name)/sizeof(u->name[0]), NULL, &(u->size), &(u->type), u->name);
|
||||||
check_gl();
|
|
||||||
u->location = glGetUniformLocation(p->id, u->name);
|
u->location = glGetUniformLocation(p->id, u->name);
|
||||||
u->idx = i;
|
u->idx = i;
|
||||||
}
|
}
|
||||||
@ -181,14 +163,12 @@ get_uniform_information(int program, const char *name, GLenum information_type)
|
|||||||
static inline GLint
|
static inline GLint
|
||||||
attrib_location(int program, const char *name) {
|
attrib_location(int program, const char *name) {
|
||||||
GLint ans = glGetAttribLocation(programs[program].id, name);
|
GLint ans = glGetAttribLocation(programs[program].id, name);
|
||||||
check_gl();
|
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline GLuint
|
static inline GLuint
|
||||||
block_index(int program, const char *name) {
|
block_index(int program, const char *name) {
|
||||||
GLuint ans = glGetUniformBlockIndex(programs[program].id, name);
|
GLuint ans = glGetUniformBlockIndex(programs[program].id, name);
|
||||||
check_gl();
|
|
||||||
if (ans == GL_INVALID_INDEX) { fatal("Could not find block index"); }
|
if (ans == GL_INVALID_INDEX) { fatal("Could not find block index"); }
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
@ -198,20 +178,17 @@ static inline GLint
|
|||||||
block_size(int program, GLuint block_index) {
|
block_size(int program, GLuint block_index) {
|
||||||
GLint ans;
|
GLint ans;
|
||||||
glGetActiveUniformBlockiv(programs[program].id, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ans);
|
glGetActiveUniformBlockiv(programs[program].id, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ans);
|
||||||
check_gl();
|
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
bind_program(int program) {
|
bind_program(int program) {
|
||||||
glUseProgram(programs[program].id);
|
glUseProgram(programs[program].id);
|
||||||
check_gl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
unbind_program() {
|
unbind_program() {
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
check_gl();
|
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
@ -230,7 +207,6 @@ static ssize_t
|
|||||||
create_buffer(GLenum usage) {
|
create_buffer(GLenum usage) {
|
||||||
GLuint buffer_id;
|
GLuint buffer_id;
|
||||||
glGenBuffers(1, &buffer_id);
|
glGenBuffers(1, &buffer_id);
|
||||||
check_gl();
|
|
||||||
for (size_t i = 0; i < sizeof(buffers)/sizeof(buffers[0]); i++) {
|
for (size_t i = 0; i < sizeof(buffers)/sizeof(buffers[0]); i++) {
|
||||||
if (buffers[i].id == 0) {
|
if (buffers[i].id == 0) {
|
||||||
buffers[i].id = buffer_id;
|
buffers[i].id = buffer_id;
|
||||||
@ -247,7 +223,6 @@ create_buffer(GLenum usage) {
|
|||||||
static void
|
static void
|
||||||
delete_buffer(ssize_t buf_idx) {
|
delete_buffer(ssize_t buf_idx) {
|
||||||
glDeleteBuffers(1, &(buffers[buf_idx].id));
|
glDeleteBuffers(1, &(buffers[buf_idx].id));
|
||||||
check_gl();
|
|
||||||
buffers[buf_idx].id = 0;
|
buffers[buf_idx].id = 0;
|
||||||
buffers[buf_idx].size = 0;
|
buffers[buf_idx].size = 0;
|
||||||
}
|
}
|
||||||
@ -255,14 +230,12 @@ delete_buffer(ssize_t buf_idx) {
|
|||||||
static GLuint
|
static GLuint
|
||||||
bind_buffer(ssize_t buf_idx) {
|
bind_buffer(ssize_t buf_idx) {
|
||||||
glBindBuffer(buffers[buf_idx].usage, buffers[buf_idx].id);
|
glBindBuffer(buffers[buf_idx].usage, buffers[buf_idx].id);
|
||||||
check_gl();
|
|
||||||
return buffers[buf_idx].id;
|
return buffers[buf_idx].id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
unbind_buffer(ssize_t buf_idx) {
|
unbind_buffer(ssize_t buf_idx) {
|
||||||
glBindBuffer(buffers[buf_idx].usage, 0);
|
glBindBuffer(buffers[buf_idx].usage, 0);
|
||||||
check_gl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@ -271,20 +244,17 @@ alloc_buffer(ssize_t idx, GLsizeiptr size, GLenum usage) {
|
|||||||
if (b->size == size) return;
|
if (b->size == size) return;
|
||||||
b->size = size;
|
b->size = size;
|
||||||
glBufferData(b->usage, size, NULL, usage);
|
glBufferData(b->usage, size, NULL, usage);
|
||||||
check_gl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void*
|
static inline void*
|
||||||
map_buffer(ssize_t idx, GLenum access) {
|
map_buffer(ssize_t idx, GLenum access) {
|
||||||
void *ans = glMapBuffer(buffers[idx].usage, access);
|
void *ans = glMapBuffer(buffers[idx].usage, access);
|
||||||
check_gl();
|
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
unmap_buffer(ssize_t idx) {
|
unmap_buffer(ssize_t idx) {
|
||||||
glUnmapBuffer(buffers[idx].usage);
|
glUnmapBuffer(buffers[idx].usage);
|
||||||
check_gl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
@ -303,13 +273,11 @@ static ssize_t
|
|||||||
create_vao() {
|
create_vao() {
|
||||||
GLuint vao_id;
|
GLuint vao_id;
|
||||||
glGenVertexArrays(1, &vao_id);
|
glGenVertexArrays(1, &vao_id);
|
||||||
check_gl();
|
|
||||||
for (size_t i = 0; i < sizeof(vaos)/sizeof(vaos[0]); i++) {
|
for (size_t i = 0; i < sizeof(vaos)/sizeof(vaos[0]); i++) {
|
||||||
if (!vaos[i].id) {
|
if (!vaos[i].id) {
|
||||||
vaos[i].id = vao_id;
|
vaos[i].id = vao_id;
|
||||||
vaos[i].num_buffers = 0;
|
vaos[i].num_buffers = 0;
|
||||||
glBindVertexArray(vao_id);
|
glBindVertexArray(vao_id);
|
||||||
check_gl();
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -336,7 +304,6 @@ add_located_attribute_to_vao(ssize_t vao_idx, GLint aloc, GLint size, GLenum dat
|
|||||||
ssize_t buf = vao->buffers[vao->num_buffers - 1];
|
ssize_t buf = vao->buffers[vao->num_buffers - 1];
|
||||||
bind_buffer(buf);
|
bind_buffer(buf);
|
||||||
glEnableVertexAttribArray(aloc);
|
glEnableVertexAttribArray(aloc);
|
||||||
check_gl();
|
|
||||||
switch(data_type) {
|
switch(data_type) {
|
||||||
case GL_BYTE:
|
case GL_BYTE:
|
||||||
case GL_UNSIGNED_BYTE:
|
case GL_UNSIGNED_BYTE:
|
||||||
@ -350,10 +317,8 @@ add_located_attribute_to_vao(ssize_t vao_idx, GLint aloc, GLint size, GLenum dat
|
|||||||
glVertexAttribPointer(aloc, size, data_type, GL_FALSE, stride, offset);
|
glVertexAttribPointer(aloc, size, data_type, GL_FALSE, stride, offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
check_gl();
|
|
||||||
if (divisor) {
|
if (divisor) {
|
||||||
glVertexAttribDivisor(aloc, divisor);
|
glVertexAttribDivisor(aloc, divisor);
|
||||||
check_gl();
|
|
||||||
}
|
}
|
||||||
unbind_buffer(buf);
|
unbind_buffer(buf);
|
||||||
}
|
}
|
||||||
@ -374,20 +339,17 @@ remove_vao(ssize_t vao_idx) {
|
|||||||
delete_buffer(vao->buffers[vao->num_buffers]);
|
delete_buffer(vao->buffers[vao->num_buffers]);
|
||||||
}
|
}
|
||||||
glDeleteVertexArrays(1, &(vao->id));
|
glDeleteVertexArrays(1, &(vao->id));
|
||||||
check_gl();
|
|
||||||
vaos[vao_idx].id = 0;
|
vaos[vao_idx].id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bind_vertex_array(ssize_t vao_idx) {
|
bind_vertex_array(ssize_t vao_idx) {
|
||||||
glBindVertexArray(vaos[vao_idx].id);
|
glBindVertexArray(vaos[vao_idx].id);
|
||||||
check_gl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
unbind_vertex_array() {
|
unbind_vertex_array() {
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
check_gl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
@ -415,7 +377,6 @@ static void
|
|||||||
bind_vao_uniform_buffer(ssize_t vao_idx, size_t bufnum, GLuint block_index) {
|
bind_vao_uniform_buffer(ssize_t vao_idx, size_t bufnum, GLuint block_index) {
|
||||||
ssize_t buf_idx = vaos[vao_idx].buffers[bufnum];
|
ssize_t buf_idx = vaos[vao_idx].buffers[bufnum];
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, block_index, buffers[buf_idx].id);
|
glBindBufferBase(GL_UNIFORM_BUFFER, block_index, buffers[buf_idx].id);
|
||||||
check_gl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@ -36,15 +36,15 @@ copy_image_sub_data(GLuint src_texture_id, GLuint dest_texture_id, unsigned int
|
|||||||
uint8_t *src = malloc(5 * width * height * num_levels);
|
uint8_t *src = malloc(5 * width * height * num_levels);
|
||||||
if (src == NULL) { fatal("Out of memory."); }
|
if (src == NULL) { fatal("Out of memory."); }
|
||||||
uint8_t *dest = src + (4 * width * height * num_levels);
|
uint8_t *dest = src + (4 * width * height * num_levels);
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, src_texture_id); check_gl();
|
glBindTexture(GL_TEXTURE_2D_ARRAY, src_texture_id);
|
||||||
glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, src); check_gl();
|
glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, src);
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, dest_texture_id); check_gl();
|
glBindTexture(GL_TEXTURE_2D_ARRAY, dest_texture_id);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); check_gl();
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
for(size_t i = 0; i < width * height * num_levels; i++) dest[i] = src[4*i];
|
for(size_t i = 0; i < width * height * num_levels; i++) dest[i] = src[4*i];
|
||||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, num_levels, GL_RED, GL_UNSIGNED_BYTE, dest); check_gl();
|
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, num_levels, GL_RED, GL_UNSIGNED_BYTE, dest);
|
||||||
free(src);
|
free(src);
|
||||||
} else {
|
} else {
|
||||||
glCopyImageSubData(src_texture_id, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, dest_texture_id, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, num_levels); check_gl();
|
glCopyImageSubData(src_texture_id, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, dest_texture_id, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, num_levels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,24 +52,24 @@ copy_image_sub_data(GLuint src_texture_id, GLuint dest_texture_id, unsigned int
|
|||||||
static void
|
static void
|
||||||
realloc_sprite_texture() {
|
realloc_sprite_texture() {
|
||||||
GLuint tex;
|
GLuint tex;
|
||||||
glGenTextures(1, &tex); check_gl();
|
glGenTextures(1, &tex);
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, tex); check_gl();
|
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
|
||||||
// We use GL_NEAREST otherwise glyphs that touch the edge of the cell
|
// We use GL_NEAREST otherwise glyphs that touch the edge of the cell
|
||||||
// often show a border between cells
|
// often show a border between cells
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); check_gl();
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
unsigned int xnum, ynum, z, znum, width, height, src_ynum;
|
unsigned int xnum, ynum, z, znum, width, height, src_ynum;
|
||||||
sprite_map_current_layout(&xnum, &ynum, &z);
|
sprite_map_current_layout(&xnum, &ynum, &z);
|
||||||
znum = z + 1;
|
znum = z + 1;
|
||||||
width = xnum * sprite_map.cell_width; height = ynum * sprite_map.cell_height;
|
width = xnum * sprite_map.cell_width; height = ynum * sprite_map.cell_height;
|
||||||
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R8, width, height, znum); check_gl();
|
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R8, width, height, znum);
|
||||||
if (sprite_map.texture_id) {
|
if (sprite_map.texture_id) {
|
||||||
// need to re-alloc
|
// need to re-alloc
|
||||||
src_ynum = MAX(1, sprite_map.last_ynum);
|
src_ynum = MAX(1, sprite_map.last_ynum);
|
||||||
copy_image_sub_data(sprite_map.texture_id, tex, width, src_ynum * sprite_map.cell_height, sprite_map.last_num_of_layers);
|
copy_image_sub_data(sprite_map.texture_id, tex, width, src_ynum * sprite_map.cell_height, sprite_map.last_num_of_layers);
|
||||||
glDeleteTextures(1, &sprite_map.texture_id); check_gl();
|
glDeleteTextures(1, &sprite_map.texture_id);
|
||||||
}
|
}
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||||
sprite_map.last_num_of_layers = znum;
|
sprite_map.last_num_of_layers = znum;
|
||||||
@ -91,8 +91,8 @@ ensure_sprite_map() {
|
|||||||
static GLuint bound_texture_id = 0;
|
static GLuint bound_texture_id = 0;
|
||||||
if (!sprite_map.texture_id) realloc_sprite_texture();
|
if (!sprite_map.texture_id) realloc_sprite_texture();
|
||||||
if (bound_texture_id != sprite_map.texture_id) {
|
if (bound_texture_id != sprite_map.texture_id) {
|
||||||
glActiveTexture(GL_TEXTURE0 + SPRITE_MAP_UNIT); check_gl();
|
glActiveTexture(GL_TEXTURE0 + SPRITE_MAP_UNIT);
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map.texture_id); check_gl();
|
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map.texture_id);
|
||||||
bound_texture_id = sprite_map.texture_id;
|
bound_texture_id = sprite_map.texture_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,14 +102,14 @@ sprite_send_to_gpu(unsigned int x, unsigned int y, unsigned int z, PyObject *buf
|
|||||||
unsigned int xnum, ynum, znum;
|
unsigned int xnum, ynum, znum;
|
||||||
sprite_map_current_layout(&xnum, &ynum, &znum);
|
sprite_map_current_layout(&xnum, &ynum, &znum);
|
||||||
if ((int)znum >= sprite_map.last_num_of_layers || (znum == 0 && (int)ynum > sprite_map.last_ynum)) realloc_sprite_texture();
|
if ((int)znum >= sprite_map.last_num_of_layers || (znum == 0 && (int)ynum > sprite_map.last_ynum)) realloc_sprite_texture();
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map.texture_id); check_gl();
|
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map.texture_id);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); check_gl();
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
x *= sprite_map.cell_width; y *= sprite_map.cell_height;
|
x *= sprite_map.cell_width; y *= sprite_map.cell_height;
|
||||||
PyObject *ret = PyObject_CallObject(buf, NULL);
|
PyObject *ret = PyObject_CallObject(buf, NULL);
|
||||||
if (ret == NULL) { PyErr_Print(); fatal("Failed to get address of rendered cell buffer"); }
|
if (ret == NULL) { PyErr_Print(); fatal("Failed to get address of rendered cell buffer"); }
|
||||||
void *address = PyLong_AsVoidPtr(ret);
|
void *address = PyLong_AsVoidPtr(ret);
|
||||||
Py_DECREF(ret);
|
Py_DECREF(ret);
|
||||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, x, y, z, sprite_map.cell_width, sprite_map.cell_height, 1, GL_RED, GL_UNSIGNED_BYTE, address); check_gl();
|
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, x, y, z, sprite_map.cell_width, sprite_map.cell_height, 1, GL_RED, GL_UNSIGNED_BYTE, address);
|
||||||
Py_DECREF(buf);
|
Py_DECREF(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,8 +139,8 @@ layout_sprite_map(unsigned int cell_width, unsigned int cell_height, PyObject *r
|
|||||||
global_state.cell_width = sprite_map.cell_width;
|
global_state.cell_width = sprite_map.cell_width;
|
||||||
global_state.cell_height = sprite_map.cell_height;
|
global_state.cell_height = sprite_map.cell_height;
|
||||||
if (sprite_map.max_texture_size == 0) {
|
if (sprite_map.max_texture_size == 0) {
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &(sprite_map.max_texture_size)); check_gl();
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &(sprite_map.max_texture_size));
|
||||||
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &(sprite_map.max_array_texture_layers)); check_gl();
|
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &(sprite_map.max_array_texture_layers));
|
||||||
sprite_map_set_limits(sprite_map.max_texture_size, sprite_map.max_array_texture_layers);
|
sprite_map_set_limits(sprite_map.max_texture_size, sprite_map.max_array_texture_layers);
|
||||||
}
|
}
|
||||||
sprite_map_set_layout(sprite_map.cell_width, sprite_map.cell_height);
|
sprite_map_set_layout(sprite_map.cell_width, sprite_map.cell_height);
|
||||||
@ -161,7 +161,6 @@ destroy_sprite_map() {
|
|||||||
Py_CLEAR(sprite_map.render_cell);
|
Py_CLEAR(sprite_map.render_cell);
|
||||||
if (sprite_map.texture_id) {
|
if (sprite_map.texture_id) {
|
||||||
glDeleteTextures(1, &(sprite_map.texture_id));
|
glDeleteTextures(1, &(sprite_map.texture_id));
|
||||||
check_gl();
|
|
||||||
sprite_map.texture_id = 0;
|
sprite_map.texture_id = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,16 +313,16 @@ draw_graphics(ssize_t vao_idx, ssize_t gvao_idx, ImageRenderData *data, GLuint s
|
|||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
static bool graphics_constants_set = false;
|
static bool graphics_constants_set = false;
|
||||||
if (!graphics_constants_set) {
|
if (!graphics_constants_set) {
|
||||||
glUniform1i(glGetUniformLocation(program_id(GRAPHICS_PROGRAM), "image"), GRAPHICS_UNIT); check_gl();
|
glUniform1i(glGetUniformLocation(program_id(GRAPHICS_PROGRAM), "image"), GRAPHICS_UNIT);
|
||||||
graphics_constants_set = true;
|
graphics_constants_set = true;
|
||||||
}
|
}
|
||||||
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT); check_gl();
|
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
|
||||||
|
|
||||||
GLuint base = 4 * start;
|
GLuint base = 4 * start;
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
for (GLuint i=0; i < count;) {
|
for (GLuint i=0; i < count;) {
|
||||||
ImageRenderData *rd = data + start + i;
|
ImageRenderData *rd = data + start + i;
|
||||||
glBindTexture(GL_TEXTURE_2D, rd->texture_id); check_gl();
|
glBindTexture(GL_TEXTURE_2D, rd->texture_id);
|
||||||
// You could reduce the number of draw calls by using
|
// You could reduce the number of draw calls by using
|
||||||
// glDrawArraysInstancedBaseInstance but Apple chose to abandon OpenGL
|
// glDrawArraysInstancedBaseInstance but Apple chose to abandon OpenGL
|
||||||
// before implementing it.
|
// before implementing it.
|
||||||
@ -338,26 +337,26 @@ draw_all_cells(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) {
|
|||||||
bind_program(CELL_PROGRAM);
|
bind_program(CELL_PROGRAM);
|
||||||
static bool cell_constants_set = false;
|
static bool cell_constants_set = false;
|
||||||
if (!cell_constants_set) {
|
if (!cell_constants_set) {
|
||||||
glUniform1i(glGetUniformLocation(program_id(CELL_PROGRAM), "sprites"), SPRITE_MAP_UNIT); check_gl();
|
glUniform1i(glGetUniformLocation(program_id(CELL_PROGRAM), "sprites"), SPRITE_MAP_UNIT);
|
||||||
cell_constants_set = true;
|
cell_constants_set = true;
|
||||||
}
|
}
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); check_gl();
|
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||||
if (screen->grman->count) draw_graphics(vao_idx, gvao_idx, 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
|
static void
|
||||||
draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) {
|
draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) {
|
||||||
bind_program(CELL_BACKGROUND_PROGRAM);
|
bind_program(CELL_BACKGROUND_PROGRAM);
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); check_gl();
|
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||||
|
|
||||||
if (screen->grman->num_of_negative_refs) draw_graphics(vao_idx, gvao_idx, 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);
|
bind_program(CELL_SPECIAL_PROGRAM);
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); check_gl();
|
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||||
|
|
||||||
bind_program(CELL_FOREGROUND_PROGRAM);
|
bind_program(CELL_FOREGROUND_PROGRAM);
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); check_gl();
|
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||||
|
|
||||||
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);
|
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);
|
||||||
}
|
}
|
||||||
@ -401,10 +400,10 @@ init_cursor_program() {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
draw_cursor_impl(CursorRenderInfo *cursor) {
|
draw_cursor_impl(CursorRenderInfo *cursor) {
|
||||||
bind_program(CURSOR_PROGRAM); bind_vertex_array(cursor_vertex_array); check_gl();
|
bind_program(CURSOR_PROGRAM); bind_vertex_array(cursor_vertex_array);
|
||||||
glUniform3f(cursor_uniform_locations[CURSOR_color], ((cursor->color >> 16) & 0xff) / 255.0, ((cursor->color >> 8) & 0xff) / 255.0, (cursor->color & 0xff) / 255.0); check_gl();
|
glUniform3f(cursor_uniform_locations[CURSOR_color], ((cursor->color >> 16) & 0xff) / 255.0, ((cursor->color >> 8) & 0xff) / 255.0, (cursor->color & 0xff) / 255.0);
|
||||||
glUniform4f(cursor_uniform_locations[CURSOR_pos], cursor->left, cursor->top, cursor->right, cursor->bottom); check_gl();
|
glUniform4f(cursor_uniform_locations[CURSOR_pos], cursor->left, cursor->top, cursor->right, cursor->bottom);
|
||||||
glDrawArrays(global_state.application_focused ? GL_TRIANGLE_FAN : GL_LINE_LOOP, 0, 4); check_gl();
|
glDrawArrays(global_state.application_focused ? GL_TRIANGLE_FAN : GL_LINE_LOOP, 0, 4);
|
||||||
unbind_vertex_array(); unbind_program();
|
unbind_vertex_array(); unbind_program();
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
@ -442,7 +441,6 @@ draw_borders_impl() {
|
|||||||
bind_program(BORDERS_PROGRAM);
|
bind_program(BORDERS_PROGRAM);
|
||||||
bind_vertex_array(border_vertex_array);
|
bind_vertex_array(border_vertex_array);
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, num_border_rects);
|
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, num_border_rects);
|
||||||
check_gl();
|
|
||||||
unbind_vertex_array();
|
unbind_vertex_array();
|
||||||
unbind_program();
|
unbind_program();
|
||||||
}
|
}
|
||||||
@ -469,7 +467,6 @@ send_borders_rects(GLuint vw, GLuint vh) {
|
|||||||
}
|
}
|
||||||
bind_program(BORDERS_PROGRAM);
|
bind_program(BORDERS_PROGRAM);
|
||||||
glUniform2ui(border_uniform_locations[BORDER_viewport], vw, vh);
|
glUniform2ui(border_uniform_locations[BORDER_viewport], vw, vh);
|
||||||
check_gl();
|
|
||||||
unbind_program();
|
unbind_program();
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
@ -484,12 +481,11 @@ compile_program(PyObject UNUSED *self, PyObject *args) {
|
|||||||
if (which < 0 || which >= NUM_PROGRAMS) { PyErr_Format(PyExc_ValueError, "Unknown program: %d", which); return NULL; }
|
if (which < 0 || which >= NUM_PROGRAMS) { PyErr_Format(PyExc_ValueError, "Unknown program: %d", which); return NULL; }
|
||||||
if (programs[which].id != 0) { PyErr_SetString(PyExc_ValueError, "program already compiled"); return NULL; }
|
if (programs[which].id != 0) { PyErr_SetString(PyExc_ValueError, "program already compiled"); return NULL; }
|
||||||
programs[which].id = glCreateProgram();
|
programs[which].id = glCreateProgram();
|
||||||
check_gl();
|
vertex_shader_id = compile_shader(GL_VERTEX_SHADER, vertex_shader);
|
||||||
vertex_shader_id = compile_shader(GL_VERTEX_SHADER, vertex_shader); check_gl();
|
fragment_shader_id = compile_shader(GL_FRAGMENT_SHADER, fragment_shader);
|
||||||
fragment_shader_id = compile_shader(GL_FRAGMENT_SHADER, fragment_shader); check_gl();
|
glAttachShader(programs[which].id, vertex_shader_id);
|
||||||
glAttachShader(programs[which].id, vertex_shader_id); check_gl();
|
glAttachShader(programs[which].id, fragment_shader_id);
|
||||||
glAttachShader(programs[which].id, fragment_shader_id); check_gl();
|
glLinkProgram(programs[which].id);
|
||||||
glLinkProgram(programs[which].id); check_gl();
|
|
||||||
GLint ret = GL_FALSE;
|
GLint ret = GL_FALSE;
|
||||||
glGetProgramiv(programs[which].id, GL_LINK_STATUS, &ret);
|
glGetProgramiv(programs[which].id, GL_LINK_STATUS, &ret);
|
||||||
if (ret != GL_TRUE) {
|
if (ret != GL_TRUE) {
|
||||||
@ -504,7 +500,6 @@ compile_program(PyObject UNUSED *self, PyObject *args) {
|
|||||||
end:
|
end:
|
||||||
if (vertex_shader_id != 0) glDeleteShader(vertex_shader_id);
|
if (vertex_shader_id != 0) glDeleteShader(vertex_shader_id);
|
||||||
if (fragment_shader_id != 0) glDeleteShader(fragment_shader_id);
|
if (fragment_shader_id != 0) glDeleteShader(fragment_shader_id);
|
||||||
check_gl();
|
|
||||||
if (PyErr_Occurred()) { glDeleteProgram(programs[which].id); programs[which].id = 0; return NULL;}
|
if (PyErr_Occurred()) { glDeleteProgram(programs[which].id); programs[which].id = 0; return NULL;}
|
||||||
return Py_BuildValue("I", programs[which].id);
|
return Py_BuildValue("I", programs[which].id);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user