From 7d99c617ef37357ed67977fedcae3f7c9fe20178 Mon Sep 17 00:00:00 2001 From: klemek Date: Mon, 11 May 2026 08:30:21 +0200 Subject: [PATCH] refactor: check every gl error --- src/shaders.c | 327 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 231 insertions(+), 96 deletions(-) diff --git a/src/shaders.c b/src/shaders.c index 7b66158..72df2f0 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -26,34 +26,49 @@ static const GLuint unused_uniform = (GLuint)-1; -bool check_glerror(ShaderProgram *program) { +bool check_glerror_ro(const char *context) { unsigned int code; code = glGetError(); if (code > 0) { - log_warn("GL Error: %04x", code); - program->error = true; - } - - return code > 0; -} - -bool check_eglerror(ShaderProgram *program, const char *context) { - unsigned int code; - - code = eglGetError(); - - if (code > 0 && code != EGL_SUCCESS) { - log_warn("(%s) EGL Error: %04x", context, code); - program->error = true; + log_warn("GL Error: %04x (%s)", code, context); return true; } return false; } -static void init_gl(ShaderProgram *program) { +bool check_glerror(ShaderProgram *program, const char *context) { + if (check_glerror_ro(context)) { + program->error = true; + return true; + } + return false; +} + +bool check_eglerror_ro(const char *context) { + unsigned int code; + + code = eglGetError(); + + if (code > 0 && code != EGL_SUCCESS) { + log_warn("EGL Error: %04x (%s)", code, context); + return true; + } + + return false; +} + +bool check_eglerror(ShaderProgram *program, const char *context) { + if (check_eglerror_ro(context)) { + program->error = true; + return true; + } + return false; +} + +static bool init_gl(ShaderProgram *program) { gladLoadGL(glfwGetProcAddress); #ifdef VIDEO_IN @@ -61,54 +76,86 @@ static void init_gl(ShaderProgram *program) { if (program->egl_display == EGL_NO_DISPLAY) { log_error("error: glfwGetEGLDisplay no EGLDisplay returned"); program->error = true; - return; + return false; } gladLoadEGL(program->egl_display, glfwGetProcAddress); #endif /* VIDEO_IN */ + + return !check_glerror(program, "init_gl") && + !check_eglerror(program, "init_gl"); } -static void init_textures(ShaderProgram *program, +static bool init_textures(ShaderProgram *program, const SharedContext *context) { glGenTextures(program->tex_count, program->textures); + if (check_glerror(program, "init_textures/glGenTextures")) { + return false; + } for (unsigned int i = 0; i < program->tex_count; i++) { // selects which texture unit subsequent texture state calls will affect glActiveTexture(GL_TEXTURE0 + i); + if (check_glerror(program, "init_textures/glActiveTexture")) { + return false; + } glBindTexture(GL_TEXTURE_2D, program->textures[i]); + if (check_glerror(program, "init_textures/glBindTexture")) { + return false; + } glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); + if (check_glerror(program, "init_textures/glDisable")) { + return false; + } // define texture image as empty glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0], context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + if (check_glerror(program, "init_textures/glTexImage2D")) { + return false; + } // setup mipmap context glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (check_glerror(program, "init_textures/glTexParameteri")) { + return false; + } log_info("Texture %d initialized", i); } + + return true; } static void rebind_textures(const ShaderProgram *program) { for (unsigned int i = 0; i < program->tex_count; i++) { glActiveTexture(GL_TEXTURE0 + i); + check_glerror_ro("rebind_textures/glActiveTexture"); + glBindTexture(GL_TEXTURE_2D, program->textures[i]); + check_glerror_ro("rebind_textures/glBindTexture"); } } #ifdef VIDEO_IN -static void link_input_to_texture(ShaderProgram *program, VideoCapture *input, +static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input, unsigned int input_index, unsigned int texture_index, bool swap, bool reload) { if (reload) { glDeleteTextures(1, program->textures + texture_index); + if (check_glerror(program, "link_input_to_texture/glDeleteTextures")) { + return false; + } glGenTextures(1, program->textures + texture_index); + if (check_glerror(program, "link_input_to_texture/glGenTextures")) { + return false; + } } EGLImageKHR dma_image; @@ -132,9 +179,8 @@ static void link_input_to_texture(ShaderProgram *program, VideoCapture *input, dma_image = eglCreateImageKHR(program->egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrib_list); - - if (check_eglerror(program, "eglCreateImageKHR")) { - return; + if (check_eglerror(program, "link_input_to_texture/eglCreateImageKHR")) { + return false; } if (swap) { @@ -144,23 +190,34 @@ static void link_input_to_texture(ShaderProgram *program, VideoCapture *input, } glActiveTexture(GL_TEXTURE0 + texture_index); + if (check_glerror(program, "link_input_to_texture/glActiveTexture")) { + return false; + } glBindTexture(GL_TEXTURE_2D, program->textures[texture_index]); + if (check_glerror(program, "link_input_to_texture/glBindTexture")) { + return false; + } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, input->width, input->height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + if (check_glerror(program, "link_input_to_texture/glTexImage2D")) { + return false; + } // https://registry.khronos.org/OpenGL/extensions/EXT/EXT_EGL_image_storage.txt glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, dma_image, NULL); - - if (check_eglerror(program, "glEGLImageTargetTexStorageEXT")) { - return; + if (check_eglerror(program, + "link_input_to_texture/glEGLImageTargetTexStorageEXT")) { + return false; } log_info("Texture %d linked to %s", texture_index, input->name); + + return true; } -static void init_input(ShaderProgram *program, const ConfigFile *config, +static bool init_input(ShaderProgram *program, const ConfigFile *config, VideoCaptureArray *inputs, unsigned int i, bool reload) { unsigned int tex_i; char name[STR_LEN]; @@ -168,27 +225,35 @@ static void init_input(ShaderProgram *program, const ConfigFile *config, if (i < inputs->length && !inputs->values[i].error) { snprintf(name, STR_LEN, "IN_%d_OUT", i + 1); tex_i = config_file_get_int(config, name, 0); - link_input_to_texture(program, &inputs->values[i], i, tex_i, false, reload); + if (!link_input_to_texture(program, &inputs->values[i], i, tex_i, false, + reload)) { + return false; + } if (inputs->values[i].with_swap) { snprintf(name, STR_LEN, "IN_%d_SWAP_OUT", i + 1); tex_i = config_file_get_int(config, name, 0); - link_input_to_texture(program, &inputs->values[i], i, tex_i, true, - reload); + if (!link_input_to_texture(program, &inputs->values[i], i, tex_i, true, + reload)) { + return false; + } } } else { log_warn("Cannot link input %d", i + 1); } - - check_glerror(program); + return true; } #endif /* VIDEO_IN */ -static void init_framebuffers(ShaderProgram *program, +static bool init_framebuffers(ShaderProgram *program, const ConfigFile *config) { unsigned int tex_i; char name[STR_LEN]; + GLenum framebuffer_status; glGenFramebuffers(program->frag_count, program->frame_buffers); + if (check_glerror(program, "init_framebuffers/glGenFramebuffers")) { + return false; + } for (unsigned int i = 0; i < program->frag_count; i++) { if (i == program->frag_output_index || i == program->frag_monitor_index) { @@ -196,48 +261,87 @@ static void init_framebuffers(ShaderProgram *program, } glBindFramebuffer(GL_FRAMEBUFFER, program->frame_buffers[i]); + if (check_glerror(program, "init_framebuffers/glBindFramebuffer")) { + return false; + } snprintf(name, STR_LEN, "FRAG_%d_OUT", i + 1); tex_i = config_file_get_int(config, name, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, program->textures[tex_i], 0); + if (check_glerror(program, "init_framebuffers/glFramebufferTexture2D")) { + return false; + } // check framebuffer status - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - log_error("Framebuffer %d is KO: %x", i + 1, - glCheckFramebufferStatus(GL_FRAMEBUFFER)); - + framebuffer_status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (check_glerror(program, "init_framebuffers/glCheckFramebufferStatus")) { + return false; + } + if (framebuffer_status != GL_FRAMEBUFFER_COMPLETE) { + log_error("Framebuffer %d is KO: %x", i + 1, framebuffer_status); program->error = true; - - return; + return false; } log_info("Framebuffer %d initialized", i); } - return; + return true; } -static void init_vertices(ShaderProgram *program) { +static bool init_vertices(ShaderProgram *program) { glGenBuffers(1, &program->vertex_buffer); + if (check_glerror(program, "init_vertices/glGenBuffers")) { + return false; + } + glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer); + if (check_glerror(program, "init_vertices/glBindBuffer")) { + return false; + } + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + if (check_glerror(program, "init_vertices/glBufferData")) { + return false; + } + + return true; } -static void bind_vertices(ShaderProgram *program, unsigned int index) { +static bool bind_vertices(ShaderProgram *program, unsigned int index) { glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer); + if (check_glerror(program, "bind_vertices/glBindBuffer")) { + return false; + } glGenVertexArrays(1, &program->vertex_array[index]); + if (check_glerror(program, "bind_vertices/glGenVertexArrays")) { + return false; + } + glBindVertexArray(program->vertex_array[index]); + if (check_glerror(program, "bind_vertices/glBindVertexArray")) { + return false; + } for (unsigned int i = 0; i < program->frag_count; i++) { // enable attribute pointer glEnableVertexAttribArray(program->vpos_locations[i]); + if (check_glerror(program, "bind_vertices/glEnableVertexAttribArray")) { + return false; + } + // specify the location and data format of the array of generic vertex // attributes to use when rendering glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, pos)); + if (check_glerror(program, "bind_vertices/glVertexAttribPointer")) { + return false; + } } + + return true; } static bool compile_shader(GLuint shader_id, const char *name, @@ -249,13 +353,18 @@ static bool compile_shader(GLuint shader_id, const char *name, // update shader source code glShaderSource(shader_id, 1, &source_code, NULL); + check_glerror_ro("compile_shader/glShaderSource"); // compile shader glCompileShader(shader_id); + check_glerror_ro("compile_shader/glCompileShader"); // get compilation status glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params); + check_glerror_ro("compile_shader/glGetShaderiv"); + glGetShaderInfoLog(shader_id, 1024, NULL, (GLchar *)&log); + check_glerror_ro("compile_shader/glGetShaderInfoLog"); if (status_params == GL_FALSE) { log_error("Failed to compile\n%s", log); @@ -267,9 +376,13 @@ static bool compile_shader(GLuint shader_id, const char *name, return status_params == GL_TRUE; } -static void init_shaders(ShaderProgram *program, const Project *project) { +static bool init_shaders(ShaderProgram *program, const Project *project) { // compile vertex shader program->vertex_shader = glCreateShader(GL_VERTEX_SHADER); + if (check_glerror(program, "init_shaders/glCreateShader")) { + return false; + } + program->error = program->error || !compile_shader(program->vertex_shader, "internal vertex shader", vertex_shader_text); @@ -277,18 +390,24 @@ static void init_shaders(ShaderProgram *program, const Project *project) { // compile fragment shaders for (unsigned int i = 0; i < program->frag_count; i++) { program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER); + if (check_glerror(program, "init_shaders/glCreateShader")) { + return false; + } + program->error = program->error || !compile_shader(program->fragment_shaders[i], project->fragment_shaders[i][0].path, project->fragment_shaders[i][0].content); if (program->error) { - return; + return false; } } + + return true; } -static void init_single_program(ShaderProgram *program, unsigned int i, +static bool init_single_program(ShaderProgram *program, unsigned int i, const ConfigFile *config, const StateConfig *state_config) { unsigned int index1; @@ -297,10 +416,20 @@ static void init_single_program(ShaderProgram *program, unsigned int i, const char *prefix; program->programs[i] = glCreateProgram(); + if (check_glerror(program, "init_single_program/glCreateProgram")) { + return false; + } glAttachShader(program->programs[i], program->vertex_shader); glAttachShader(program->programs[i], program->fragment_shaders[i]); + if (check_glerror(program, "init_single_program/glAttachShader")) { + return false; + } + glLinkProgram(program->programs[i]); + if (check_glerror(program, "init_single_program/glLinkProgram")) { + return false; + } // create uniforms pointers program->itime_locations[i] = glGetUniformLocation( @@ -380,18 +509,6 @@ static void init_single_program(ShaderProgram *program, unsigned int i, glGetUniformLocation(program->programs[i], name); } - for (unsigned int j = 0; j < program->sub_type_count; j++) { - snprintf(name, STR_LEN, "SUB_%d_PREFIX", j + 1); - prefix = config_file_get_str(config, name, 0); - for (unsigned int k = 0; k < program->sub_variant_count; k++) { - snprintf(name, STR_LEN, "%s%d", prefix, k + 1); - program->sub_locations[i * program->sub_variant_count * - program->sub_type_count + - j * program->sub_variant_count + k] = - glGetSubroutineIndex(program->programs[i], GL_FRAGMENT_SHADER, name); - } - } - prefix = config_file_get_str(config, "UNIFORM_ACTIVE_PREFIX", "iActive"); for (unsigned int j = 0; j < program->active_count; j++) { snprintf(name, STR_LEN, "%s%d", prefix, j + 1); @@ -430,18 +547,48 @@ static void init_single_program(ShaderProgram *program, unsigned int i, glGetUniformLocation(program->programs[i], name); } + if (check_glerror(program, "init_single_program/glGetUniformLocation")) { + return false; + } + + for (unsigned int j = 0; j < program->sub_type_count; j++) { + snprintf(name, STR_LEN, "SUB_%d_PREFIX", j + 1); + prefix = config_file_get_str(config, name, 0); + for (unsigned int k = 0; k < program->sub_variant_count; k++) { + snprintf(name, STR_LEN, "%s%d", prefix, k + 1); + program->sub_locations[i * program->sub_variant_count * + program->sub_type_count + + j * program->sub_variant_count + k] = + glGetSubroutineIndex(program->programs[i], GL_FRAGMENT_SHADER, name); + } + } + + if (check_glerror(program, "init_single_program/glGetSubroutineIndex")) { + return false; + } + // create attribute pointer program->vpos_locations[i] = glGetAttribLocation(program->programs[i], "vPos"); + if (check_glerror(program, "init_single_program/glGetAttribLocation")) { + return false; + } + log_info("Program %d initialized", i + 1); + + return true; } -static void init_programs(ShaderProgram *program, const ConfigFile *config, +static bool init_programs(ShaderProgram *program, const ConfigFile *config, const StateConfig *state_config) { for (unsigned int i = 0; i < program->frag_count; i++) { - init_single_program(program, i, config, state_config); + if (!init_single_program(program, i, config, state_config)) { + return false; + } } + + return true; } static void update_viewport(ShaderProgram *program, @@ -452,10 +599,12 @@ static void update_viewport(ShaderProgram *program, // clean and resize all textures for (unsigned int i = 0; i < program->tex_count; i++) { glActiveTexture(GL_TEXTURE0 + i); - // TODO dont remap input textures + check_glerror_ro("update_viewport/glActiveTexture"); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0], context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - check_glerror(program); + check_glerror_ro( + "update_viewport/glTexImage2D"); // TODO dont remap input textures } program->last_resolution[0] = context->resolution[0]; program->last_resolution[1] = context->resolution[1]; @@ -614,46 +763,32 @@ void shaders_init(ShaderProgram *program, const Project *project, memset(program->dma_images_swap, 0, sizeof(program->dma_images_swap)); #endif /* VIDEO_IN */ - init_gl(program); - - if (check_glerror(program)) { + if (!init_gl(program)) { return; } - init_shaders(program, project); - - if (program->error || check_glerror(program)) { + if (!init_shaders(program, project)) { return; } - init_textures(program, context); - - if (check_glerror(program)) { + if (!init_textures(program, context)) { return; } - init_framebuffers(program, &project->config); - - if (check_glerror(program)) { + if (!init_framebuffers(program, &project->config)) { return; } - init_programs(program, &project->config, &project->state_config); - - if (check_glerror(program)) { + if (!init_programs(program, &project->config, &project->state_config)) { return; } - init_vertices(program); - - if (check_glerror(program)) { + if (!init_vertices(program)) { return; } } - bind_vertices(program, rebind ? 1 : 0); - - if (check_glerror(program)) { + if (!bind_vertices(program, rebind ? 1 : 0)) { return; } } @@ -677,14 +812,10 @@ void shaders_link_inputs(ShaderProgram *program, const Project *project, void shaders_update(ShaderProgram *program, const File *fragment_shader, unsigned int i, const Project *project) { - bool result; - - result = compile_shader(program->fragment_shaders[i], fragment_shader->path, - fragment_shader->content); - - if (result) { - init_single_program(program, i, &project->config, &project->state_config); - + if (compile_shader(program->fragment_shaders[i], fragment_shader->path, + fragment_shader->content) && + init_single_program(program, i, &project->config, + &project->state_config)) { log_info("Program %d updated", i + 1); } } @@ -711,38 +842,42 @@ void shaders_compute(ShaderProgram *program, const SharedContext *context, monitor ? program->frag_monitor_index : program->frag_output_index, true, context); + + check_glerror(program, "shaders_compute"); } void shaders_free(const ShaderProgram *program) { for (unsigned int i = 0; i < program->frag_count; i++) { glDeleteProgram(program->programs[i]); } + check_glerror_ro("shaders_free/glDeleteProgram"); glDeleteFramebuffers(program->frag_count, program->frame_buffers); + check_glerror_ro("shaders_free/glDeleteFramebuffers"); + glDeleteTextures(program->tex_count, program->textures); + check_glerror_ro("shaders_free/glDeleteTextures"); + glDeleteBuffers(1, &program->vertex_buffer); + check_glerror_ro("shaders_free/glDeleteBuffers"); } void shaders_free_window(const ShaderProgram *program, bool secondary) { glDeleteVertexArrays(1, &program->vertex_array[secondary ? 1 : 0]); + check_glerror_ro("shaders_free_window/glDeleteVertexArrays"); } void shaders_free_input(ShaderProgram *program, unsigned int input_index) { #ifdef VIDEO_IN if (program->dma_images[input_index] != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(program->egl_display, program->dma_images[input_index]); - program->dma_images[input_index] = EGL_NO_IMAGE_KHR; - - check_eglerror(program, "eglDestroyImageKHR"); } if (program->dma_images_swap[input_index] != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(program->egl_display, program->dma_images_swap[input_index]); - program->dma_images_swap[input_index] = EGL_NO_IMAGE_KHR; - - check_eglerror(program, "eglDestroyImageKHR"); } + check_eglerror_ro("shaders_free_input/eglDestroyImageKHR"); #endif /* VIDEO_IN */ }