diff --git a/kitty/gl.c b/kitty/gl.c new file mode 100644 index 000000000..a6f6b961d --- /dev/null +++ b/kitty/gl.c @@ -0,0 +1,366 @@ +/* + * gl.c + * Copyright (C) 2019 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#include "gl.h" +#include +#include +#include "glfw-wrapper.h" +#include "state.h" + +// GL setup and error handling {{{ +static void +check_for_gl_error(void UNUSED *ret, const char *name, GLADapiproc UNUSED funcptr, int UNUSED len_args, ...) { +#define f(msg) fatal("OpenGL error: %s (calling function: %s)", msg, name); break; + GLenum code = glad_glGetError(); + switch(code) { + case GL_NO_ERROR: break; + case GL_INVALID_ENUM: + f("An enum value is invalid (GL_INVALID_ENUM)"); + case GL_INVALID_VALUE: + f("An numeric value is invalid (GL_INVALID_VALUE)"); + case GL_INVALID_OPERATION: + f("This operation is invalid (GL_INVALID_OPERATION)"); + case GL_INVALID_FRAMEBUFFER_OPERATION: + f("The framebuffer object is not complete (GL_INVALID_FRAMEBUFFER_OPERATION)"); + case GL_OUT_OF_MEMORY: + f("There is not enough memory left to execute the command. (GL_OUT_OF_MEMORY)"); + case GL_STACK_UNDERFLOW: + f("An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_UNDERFLOW)"); + case GL_STACK_OVERFLOW: + f("An attempt has been made to perform an operation that would cause an internal stack to overflow. (GL_STACK_OVERFLOW)"); + default: + fatal("An unknown OpenGL error occurred with code: %d (calling function: %s)", code, name); + break; + } +} + +void +gl_init() { + static bool glad_loaded = false; + if (!glad_loaded) { + int gl_version = gladLoadGL(glfwGetProcAddress); + if (!gl_version) { + fatal("Loading the OpenGL library failed"); + } + if (!global_state.debug_gl) { + gladUninstallGLDebug(); + } + gladSetGLPostCallback(check_for_gl_error); +#define ARB_TEST(name) \ + if (!GLAD_GL_ARB_##name) { \ + fatal("The OpenGL driver on this system is missing the required extension: ARB_%s", #name); \ + } + ARB_TEST(texture_storage); +#undef ARB_TEST + glad_loaded = true; + int gl_major = GLAD_VERSION_MAJOR(gl_version); + int gl_minor = GLAD_VERSION_MINOR(gl_version); + if (global_state.debug_gl) printf("GL version string: '%s' Detected version: %d.%d\n", glGetString(GL_VERSION), gl_major, gl_minor); + if (gl_major < OPENGL_REQUIRED_VERSION_MAJOR || (gl_major == OPENGL_REQUIRED_VERSION_MAJOR && gl_minor < OPENGL_REQUIRED_VERSION_MINOR)) { + fatal("OpenGL version is %d.%d, version >= 3.3 required for kitty", gl_major, gl_minor); + } + } +} + +void +update_surface_size(int w, int h, GLuint offscreen_texture_id) { + glViewport(0, 0, w, h); + if (offscreen_texture_id) { + glBindTexture(GL_TEXTURE_2D, offscreen_texture_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + } +} + +void +free_texture(GLuint *tex_id) { + glDeleteTextures(1, tex_id); + *tex_id = 0; +} + + +// }}} + +// Programs {{{ + +static Program programs[64] = {{0}}; + +GLuint +compile_shader(GLenum shader_type, const char *source) { + GLuint shader_id = glCreateShader(shader_type); + glShaderSource(shader_id, 1, (const GLchar **)&source, NULL); + glCompileShader(shader_id); + GLint ret = GL_FALSE; + glGetShaderiv(shader_id, GL_COMPILE_STATUS, &ret); + if (ret != GL_TRUE) { + GLsizei len; + static char glbuf[4096]; + glGetShaderInfoLog(shader_id, sizeof(glbuf), &len, glbuf); + log_error("Failed to compile GLSL shader!\n%s", glbuf); + glDeleteShader(shader_id); + PyErr_SetString(PyExc_ValueError, "Failed to compile shader"); + return 0; + } + return shader_id; +} + +Program* +program_ptr(int program) { return programs + (size_t)program; } + +GLuint +program_id(int program) { return programs[program].id; } + + +void +init_uniforms(int program) { + Program *p = programs + program; + glGetProgramiv(p->id, GL_ACTIVE_UNIFORMS, &(p->num_of_uniforms)); + for (GLint i = 0; i < p->num_of_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); + u->location = glGetUniformLocation(p->id, u->name); + u->idx = i; + } +} + +GLint +get_uniform_information(int program, const char *name, GLenum information_type) { + GLint q; GLuint t; + static const char* names[] = {""}; + names[0] = name; + GLuint pid = program_id(program); + glGetUniformIndices(pid, 1, (void*)names, &t); + glGetActiveUniformsiv(pid, 1, &t, information_type, &q); + return q; +} + +GLint +attrib_location(int program, const char *name) { + GLint ans = glGetAttribLocation(programs[program].id, name); + return ans; +} + +GLuint +block_index(int program, const char *name) { + GLuint ans = glGetUniformBlockIndex(programs[program].id, name); + if (ans == GL_INVALID_INDEX) { fatal("Could not find block index"); } + return ans; +} + + +GLint +block_size(int program, GLuint block_index) { + GLint ans; + glGetActiveUniformBlockiv(programs[program].id, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ans); + return ans; +} + +void +bind_program(int program) { + glUseProgram(programs[program].id); +} + +void +unbind_program(void) { + glUseProgram(0); +} +// }}} + +// Buffers {{{ + +typedef struct { + GLuint id; + GLsizeiptr size; + GLenum usage; +} Buffer; + + +static Buffer buffers[MAX_CHILDREN * 6 + 4] = {{0}}; + +static ssize_t +create_buffer(GLenum usage) { + GLuint buffer_id; + glGenBuffers(1, &buffer_id); + for (size_t i = 0; i < sizeof(buffers)/sizeof(buffers[0]); i++) { + if (buffers[i].id == 0) { + buffers[i].id = buffer_id; + buffers[i].size = 0; + buffers[i].usage = usage; + return i; + } + } + glDeleteBuffers(1, &buffer_id); + fatal("Too many buffers"); + return -1; +} + +static void +delete_buffer(ssize_t buf_idx) { + glDeleteBuffers(1, &(buffers[buf_idx].id)); + buffers[buf_idx].id = 0; + buffers[buf_idx].size = 0; +} + +static GLuint +bind_buffer(ssize_t buf_idx) { + glBindBuffer(buffers[buf_idx].usage, buffers[buf_idx].id); + return buffers[buf_idx].id; +} + +static void +unbind_buffer(ssize_t buf_idx) { + glBindBuffer(buffers[buf_idx].usage, 0); +} + +static inline void +alloc_buffer(ssize_t idx, GLsizeiptr size, GLenum usage) { + Buffer *b = buffers + idx; + if (b->size == size) return; + b->size = size; + glBufferData(b->usage, size, NULL, usage); +} + +static inline void* +map_buffer(ssize_t idx, GLenum access) { + void *ans = glMapBuffer(buffers[idx].usage, access); + return ans; +} + +static inline void +unmap_buffer(ssize_t idx) { + glUnmapBuffer(buffers[idx].usage); +} + +// }}} + +// Vertex Array Objects (VAO) {{{ + +typedef struct { + GLuint id; + size_t num_buffers; + ssize_t buffers[10]; +} VAO; + +static VAO vaos[4*MAX_CHILDREN + 10] = {{0}}; + +ssize_t +create_vao(void) { + GLuint vao_id; + glGenVertexArrays(1, &vao_id); + for (size_t i = 0; i < sizeof(vaos)/sizeof(vaos[0]); i++) { + if (!vaos[i].id) { + vaos[i].id = vao_id; + vaos[i].num_buffers = 0; + glBindVertexArray(vao_id); + return i; + } + } + glDeleteVertexArrays(1, &vao_id); + fatal("Too many VAOs"); + return -1; +} + +size_t +add_buffer_to_vao(ssize_t vao_idx, GLenum usage) { + VAO* vao = vaos + vao_idx; + if (vao->num_buffers >= sizeof(vao->buffers) / sizeof(vao->buffers[0])) { + fatal("Too many buffers in a single VAO"); + } + ssize_t buf = create_buffer(usage); + vao->buffers[vao->num_buffers++] = buf; + return vao->num_buffers - 1; +} + +static void +add_located_attribute_to_vao(ssize_t vao_idx, GLint aloc, GLint size, GLenum data_type, GLsizei stride, void *offset, GLuint divisor) { + VAO *vao = vaos + vao_idx; + if (!vao->num_buffers) fatal("You must create a buffer for this attribute first"); + ssize_t buf = vao->buffers[vao->num_buffers - 1]; + bind_buffer(buf); + glEnableVertexAttribArray(aloc); + switch(data_type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + glVertexAttribIPointer(aloc, size, data_type, stride, offset); + break; + default: + glVertexAttribPointer(aloc, size, data_type, GL_FALSE, stride, offset); + break; + } + if (divisor) { + glVertexAttribDivisor(aloc, divisor); + } + unbind_buffer(buf); +} + + +void +add_attribute_to_vao(int p, ssize_t vao_idx, const char *name, GLint size, GLenum data_type, GLsizei stride, void *offset, GLuint divisor) { + GLint aloc = attrib_location(p, name); + if (aloc == -1) fatal("No attribute named: %s found in this program", name); + add_located_attribute_to_vao(vao_idx, aloc, size, data_type, stride, offset, divisor); +} + +void +remove_vao(ssize_t vao_idx) { + VAO *vao = vaos + vao_idx; + while (vao->num_buffers) { + vao->num_buffers--; + delete_buffer(vao->buffers[vao->num_buffers]); + } + glDeleteVertexArrays(1, &(vao->id)); + vaos[vao_idx].id = 0; +} + +void +bind_vertex_array(ssize_t vao_idx) { + glBindVertexArray(vaos[vao_idx].id); +} + +void +unbind_vertex_array(void) { + glBindVertexArray(0); +} + +ssize_t +alloc_vao_buffer(ssize_t vao_idx, GLsizeiptr size, size_t bufnum, GLenum usage) { + ssize_t buf_idx = vaos[vao_idx].buffers[bufnum]; + bind_buffer(buf_idx); + alloc_buffer(buf_idx, size, usage); + return buf_idx; +} + +void* +map_vao_buffer(ssize_t vao_idx, size_t bufnum, GLenum access) { + ssize_t buf_idx = vaos[vao_idx].buffers[bufnum]; + bind_buffer(buf_idx); + return map_buffer(buf_idx, access); +} + +void* +alloc_and_map_vao_buffer(ssize_t vao_idx, GLsizeiptr size, size_t bufnum, GLenum usage, GLenum access) { + ssize_t buf_idx = alloc_vao_buffer(vao_idx, size, bufnum, usage); + return map_buffer(buf_idx, access); +} + +void +bind_vao_uniform_buffer(ssize_t vao_idx, size_t bufnum, GLuint block_index) { + ssize_t buf_idx = vaos[vao_idx].buffers[bufnum]; + glBindBufferBase(GL_UNIFORM_BUFFER, block_index, buffers[buf_idx].id); +} + +void +unmap_vao_buffer(ssize_t vao_idx, size_t bufnum) { + ssize_t buf_idx = vaos[vao_idx].buffers[bufnum]; + unmap_buffer(buf_idx); + unbind_buffer(buf_idx); +} + +// }}} diff --git a/kitty/gl.h b/kitty/gl.h index d126f9558..49a9447f4 100644 --- a/kitty/gl.h +++ b/kitty/gl.h @@ -6,92 +6,11 @@ #pragma once +#include "data-types.h" #include "gl-wrapper.h" -#include "state.h" -#include "screen.h" -#include -#include -#include "glfw-wrapper.h" -static char glbuf[4096]; - -// GL setup and error handling {{{ #define GLSL_VERSION (OPENGL_REQUIRED_VERSION_MAJOR * 100 + OPENGL_REQUIRED_VERSION_MINOR * 10) -static void -check_for_gl_error(void UNUSED *ret, const char *name, GLADapiproc UNUSED funcptr, int UNUSED len_args, ...) { -#define f(msg) fatal("OpenGL error: %s (calling function: %s)", msg, name); break; - GLenum code = glad_glGetError(); - switch(code) { - case GL_NO_ERROR: break; - case GL_INVALID_ENUM: - f("An enum value is invalid (GL_INVALID_ENUM)"); - case GL_INVALID_VALUE: - f("An numeric value is invalid (GL_INVALID_VALUE)"); - case GL_INVALID_OPERATION: - f("This operation is invalid (GL_INVALID_OPERATION)"); - case GL_INVALID_FRAMEBUFFER_OPERATION: - f("The framebuffer object is not complete (GL_INVALID_FRAMEBUFFER_OPERATION)"); - case GL_OUT_OF_MEMORY: - f("There is not enough memory left to execute the command. (GL_OUT_OF_MEMORY)"); - case GL_STACK_UNDERFLOW: - f("An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_UNDERFLOW)"); - case GL_STACK_OVERFLOW: - f("An attempt has been made to perform an operation that would cause an internal stack to overflow. (GL_STACK_OVERFLOW)"); - default: - fatal("An unknown OpenGL error occurred with code: %d (calling function: %s)", code, name); - break; - } -} - -void -gl_init() { - static bool glad_loaded = false; - if (!glad_loaded) { - int gl_version = gladLoadGL(glfwGetProcAddress); - if (!gl_version) { - fatal("Loading the OpenGL library failed"); - } - if (!global_state.debug_gl) { - gladUninstallGLDebug(); - } - gladSetGLPostCallback(check_for_gl_error); -#define ARB_TEST(name) \ - if (!GLAD_GL_ARB_##name) { \ - fatal("The OpenGL driver on this system is missing the required extension: ARB_%s", #name); \ - } - ARB_TEST(texture_storage); -#undef ARB_TEST - glad_loaded = true; - int gl_major = GLAD_VERSION_MAJOR(gl_version); - int gl_minor = GLAD_VERSION_MINOR(gl_version); - if (global_state.debug_gl) printf("GL version string: '%s' Detected version: %d.%d\n", glGetString(GL_VERSION), gl_major, gl_minor); - if (gl_major < OPENGL_REQUIRED_VERSION_MAJOR || (gl_major == OPENGL_REQUIRED_VERSION_MAJOR && gl_minor < OPENGL_REQUIRED_VERSION_MINOR)) { - fatal("OpenGL version is %d.%d, version >= 3.3 required for kitty", gl_major, gl_minor); - } - } -} - -void -update_surface_size(int w, int h, GLuint offscreen_texture_id) { - glViewport(0, 0, w, h); - if (offscreen_texture_id) { - glBindTexture(GL_TEXTURE_2D, offscreen_texture_id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - } -} - -void -free_texture(GLuint *tex_id) { - glDeleteTextures(1, tex_id); - *tex_id = 0; -} - - -// }}} - -// Programs {{{ - typedef struct { GLint size, index; } UniformBlock; @@ -112,276 +31,28 @@ typedef struct { GLint num_of_uniforms; } Program; -static Program programs[64] = {{0}}; -static inline GLuint -compile_shader(GLenum shader_type, const char *source) { - GLuint shader_id = glCreateShader(shader_type); - glShaderSource(shader_id, 1, (const GLchar **)&source, NULL); - glCompileShader(shader_id); - GLint ret = GL_FALSE; - glGetShaderiv(shader_id, GL_COMPILE_STATUS, &ret); - if (ret != GL_TRUE) { - GLsizei len; - glGetShaderInfoLog(shader_id, sizeof(glbuf), &len, glbuf); - log_error("Failed to compile GLSL shader!\n%s", glbuf); - glDeleteShader(shader_id); - PyErr_SetString(PyExc_ValueError, "Failed to compile shader"); - return 0; - } - return shader_id; -} - -static inline GLuint -program_id(int program) { return programs[program].id; } - -static inline void -init_uniforms(int program) { - Program *p = programs + program; - glGetProgramiv(p->id, GL_ACTIVE_UNIFORMS, &(p->num_of_uniforms)); - for (GLint i = 0; i < p->num_of_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); - u->location = glGetUniformLocation(p->id, u->name); - u->idx = i; - } -} - -static inline GLint -get_uniform_information(int program, const char *name, GLenum information_type) { - GLint q; GLuint t; - static const char* names[] = {""}; - names[0] = name; - GLuint pid = program_id(program); - glGetUniformIndices(pid, 1, (void*)names, &t); - glGetActiveUniformsiv(pid, 1, &t, information_type, &q); - return q; -} - -static inline GLint -attrib_location(int program, const char *name) { - GLint ans = glGetAttribLocation(programs[program].id, name); - return ans; -} - -static inline GLuint -block_index(int program, const char *name) { - GLuint ans = glGetUniformBlockIndex(programs[program].id, name); - if (ans == GL_INVALID_INDEX) { fatal("Could not find block index"); } - return ans; -} - - -static inline GLint -block_size(int program, GLuint block_index) { - GLint ans; - glGetActiveUniformBlockiv(programs[program].id, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ans); - return ans; -} - -static inline void -bind_program(int program) { - glUseProgram(programs[program].id); -} - -static inline void -unbind_program(void) { - glUseProgram(0); -} -// }}} - -// Buffers {{{ - -typedef struct { - GLuint id; - GLsizeiptr size; - GLenum usage; -} Buffer; - - -static Buffer buffers[MAX_CHILDREN * 6 + 4] = {{0}}; - -static ssize_t -create_buffer(GLenum usage) { - GLuint buffer_id; - glGenBuffers(1, &buffer_id); - for (size_t i = 0; i < sizeof(buffers)/sizeof(buffers[0]); i++) { - if (buffers[i].id == 0) { - buffers[i].id = buffer_id; - buffers[i].size = 0; - buffers[i].usage = usage; - return i; - } - } - glDeleteBuffers(1, &buffer_id); - fatal("Too many buffers"); - return -1; -} - -static void -delete_buffer(ssize_t buf_idx) { - glDeleteBuffers(1, &(buffers[buf_idx].id)); - buffers[buf_idx].id = 0; - buffers[buf_idx].size = 0; -} - -static GLuint -bind_buffer(ssize_t buf_idx) { - glBindBuffer(buffers[buf_idx].usage, buffers[buf_idx].id); - return buffers[buf_idx].id; -} - -static void -unbind_buffer(ssize_t buf_idx) { - glBindBuffer(buffers[buf_idx].usage, 0); -} - -static inline void -alloc_buffer(ssize_t idx, GLsizeiptr size, GLenum usage) { - Buffer *b = buffers + idx; - if (b->size == size) return; - b->size = size; - glBufferData(b->usage, size, NULL, usage); -} - -static inline void* -map_buffer(ssize_t idx, GLenum access) { - void *ans = glMapBuffer(buffers[idx].usage, access); - return ans; -} - -static inline void -unmap_buffer(ssize_t idx) { - glUnmapBuffer(buffers[idx].usage); -} - -// }}} - -// Vertex Array Objects (VAO) {{{ - -typedef struct { - GLuint id; - size_t num_buffers; - ssize_t buffers[10]; -} VAO; - -static VAO vaos[4*MAX_CHILDREN + 10] = {{0}}; - -static ssize_t -create_vao(void) { - GLuint vao_id; - glGenVertexArrays(1, &vao_id); - for (size_t i = 0; i < sizeof(vaos)/sizeof(vaos[0]); i++) { - if (!vaos[i].id) { - vaos[i].id = vao_id; - vaos[i].num_buffers = 0; - glBindVertexArray(vao_id); - return i; - } - } - glDeleteVertexArrays(1, &vao_id); - fatal("Too many VAOs"); - return -1; -} - -static size_t -add_buffer_to_vao(ssize_t vao_idx, GLenum usage) { - VAO* vao = vaos + vao_idx; - if (vao->num_buffers >= sizeof(vao->buffers) / sizeof(vao->buffers[0])) { - fatal("Too many buffers in a single VAO"); - } - ssize_t buf = create_buffer(usage); - vao->buffers[vao->num_buffers++] = buf; - return vao->num_buffers - 1; -} - -static void -add_located_attribute_to_vao(ssize_t vao_idx, GLint aloc, GLint size, GLenum data_type, GLsizei stride, void *offset, GLuint divisor) { - VAO *vao = vaos + vao_idx; - if (!vao->num_buffers) fatal("You must create a buffer for this attribute first"); - ssize_t buf = vao->buffers[vao->num_buffers - 1]; - bind_buffer(buf); - glEnableVertexAttribArray(aloc); - switch(data_type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - glVertexAttribIPointer(aloc, size, data_type, stride, offset); - break; - default: - glVertexAttribPointer(aloc, size, data_type, GL_FALSE, stride, offset); - break; - } - if (divisor) { - glVertexAttribDivisor(aloc, divisor); - } - unbind_buffer(buf); -} - - -static inline void -add_attribute_to_vao(int p, ssize_t vao_idx, const char *name, GLint size, GLenum data_type, GLsizei stride, void *offset, GLuint divisor) { - GLint aloc = attrib_location(p, name); - if (aloc == -1) fatal("No attribute named: %s found in this program", name); - add_located_attribute_to_vao(vao_idx, aloc, size, data_type, stride, offset, divisor); -} - -void -remove_vao(ssize_t vao_idx) { - VAO *vao = vaos + vao_idx; - while (vao->num_buffers) { - vao->num_buffers--; - delete_buffer(vao->buffers[vao->num_buffers]); - } - glDeleteVertexArrays(1, &(vao->id)); - vaos[vao_idx].id = 0; -} - -static void -bind_vertex_array(ssize_t vao_idx) { - glBindVertexArray(vaos[vao_idx].id); -} - -static void -unbind_vertex_array(void) { - glBindVertexArray(0); -} - -static ssize_t -alloc_vao_buffer(ssize_t vao_idx, GLsizeiptr size, size_t bufnum, GLenum usage) { - ssize_t buf_idx = vaos[vao_idx].buffers[bufnum]; - bind_buffer(buf_idx); - alloc_buffer(buf_idx, size, usage); - return buf_idx; -} - -static void* -map_vao_buffer(ssize_t vao_idx, size_t bufnum, GLenum access) { - ssize_t buf_idx = vaos[vao_idx].buffers[bufnum]; - bind_buffer(buf_idx); - return map_buffer(buf_idx, access); -} - -static void* -alloc_and_map_vao_buffer(ssize_t vao_idx, GLsizeiptr size, size_t bufnum, GLenum usage, GLenum access) { - ssize_t buf_idx = alloc_vao_buffer(vao_idx, size, bufnum, usage); - return map_buffer(buf_idx, access); -} - -static void -bind_vao_uniform_buffer(ssize_t vao_idx, size_t bufnum, GLuint block_index) { - ssize_t buf_idx = vaos[vao_idx].buffers[bufnum]; - glBindBufferBase(GL_UNIFORM_BUFFER, block_index, buffers[buf_idx].id); -} - -static void -unmap_vao_buffer(ssize_t vao_idx, size_t bufnum) { - ssize_t buf_idx = vaos[vao_idx].buffers[bufnum]; - unmap_buffer(buf_idx); - unbind_buffer(buf_idx); -} - -// }}} +void gl_init(void); +void update_surface_size(int w, int h, GLuint offscreen_texture_id); +void free_texture(GLuint *tex_id); +void remove_vao(ssize_t vao_idx); +void init_uniforms(int program); +GLuint program_id(int program); +Program* program_ptr(int program); +GLuint block_index(int program, const char *name); +GLint block_size(int program, GLuint block_index); +GLint get_uniform_information(int program, const char *name, GLenum information_type); +GLint attrib_location(int program, const char *name); +ssize_t create_vao(void); +size_t add_buffer_to_vao(ssize_t vao_idx, GLenum usage); +void add_attribute_to_vao(int p, ssize_t vao_idx, const char *name, GLint size, GLenum data_type, GLsizei stride, void *offset, GLuint divisor); +ssize_t alloc_vao_buffer(ssize_t vao_idx, GLsizeiptr size, size_t bufnum, GLenum usage); +void* alloc_and_map_vao_buffer(ssize_t vao_idx, GLsizeiptr size, size_t bufnum, GLenum usage, GLenum access); +void unmap_vao_buffer(ssize_t vao_idx, size_t bufnum); +void* map_vao_buffer(ssize_t vao_idx, size_t bufnum, GLenum access); +void bind_program(int program); +void bind_vertex_array(ssize_t vao_idx); +void bind_vao_uniform_buffer(ssize_t vao_idx, size_t bufnum, GLuint block_index); +void unbind_vertex_array(void); +void unbind_program(void); +GLuint compile_shader(GLenum shader_type, const char *source); diff --git a/kitty/shaders.c b/kitty/shaders.c index acb94b6a8..2d56fc685 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -7,6 +7,7 @@ #include "fonts.h" #include "gl.h" +#include enum { CELL_PROGRAM, CELL_BG_PROGRAM, CELL_SPECIAL_PROGRAM, CELL_FG_PROGRAM, BORDERS_PROGRAM, GRAPHICS_PROGRAM, GRAPHICS_PREMULT_PROGRAM, GRAPHICS_ALPHA_MASK_PROGRAM, BLIT_PROGRAM, NUM_PROGRAMS }; enum { SPRITE_MAP_UNIT, GRAPHICS_UNIT, BLIT_UNIT }; @@ -533,7 +534,7 @@ static GLint border_uniform_locations[NUM_BORDER_UNIFORMS] = {0}; static void init_borders_program(void) { - Program *p = programs + BORDERS_PROGRAM; + Program *p = program_ptr(BORDERS_PROGRAM); int left = NUM_BORDER_UNIFORMS; for (int i = 0; i < p->num_of_uniforms; i++, left--) { #define SET_LOC(which) (strcmp(p->uniforms[i].name, #which) == 0) border_uniform_locations[BORDER_##which] = p->uniforms[i].location @@ -598,18 +599,20 @@ compile_program(PyObject UNUSED *self, PyObject *args) { GLuint vertex_shader_id = 0, fragment_shader_id = 0; if (!PyArg_ParseTuple(args, "iss", &which, &vertex_shader, &fragment_shader)) 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; } - programs[which].id = glCreateProgram(); + Program *program = program_ptr(which); + if (program->id != 0) { PyErr_SetString(PyExc_ValueError, "program already compiled"); return NULL; } + program->id = glCreateProgram(); vertex_shader_id = compile_shader(GL_VERTEX_SHADER, vertex_shader); fragment_shader_id = compile_shader(GL_FRAGMENT_SHADER, fragment_shader); - glAttachShader(programs[which].id, vertex_shader_id); - glAttachShader(programs[which].id, fragment_shader_id); - glLinkProgram(programs[which].id); + glAttachShader(program->id, vertex_shader_id); + glAttachShader(program->id, fragment_shader_id); + glLinkProgram(program->id); GLint ret = GL_FALSE; - glGetProgramiv(programs[which].id, GL_LINK_STATUS, &ret); + glGetProgramiv(program->id, GL_LINK_STATUS, &ret); if (ret != GL_TRUE) { GLsizei len; - glGetProgramInfoLog(programs[which].id, sizeof(glbuf), &len, glbuf); + static char glbuf[4096]; + glGetProgramInfoLog(program->id, sizeof(glbuf), &len, glbuf); log_error("Failed to compile GLSL shader!\n%s", glbuf); PyErr_SetString(PyExc_ValueError, "Failed to compile shader"); goto end; @@ -619,8 +622,8 @@ compile_program(PyObject UNUSED *self, PyObject *args) { end: if (vertex_shader_id != 0) glDeleteShader(vertex_shader_id); if (fragment_shader_id != 0) glDeleteShader(fragment_shader_id); - if (PyErr_Occurred()) { glDeleteProgram(programs[which].id); programs[which].id = 0; return NULL;} - return Py_BuildValue("I", programs[which].id); + if (PyErr_Occurred()) { glDeleteProgram(program->id); program->id = 0; return NULL;} + return Py_BuildValue("I", program->id); Py_RETURN_NONE; }