diff --git a/docs/changelog.rst b/docs/changelog.rst index 4f7a2da74..7b61e8a39 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -145,6 +145,8 @@ Detailed list of changes - Fix a regression in the previous release that broke ``goto_session -1`` +- Fix rendering broken on ancient GPU drivers that dont support rendering to 16 bit textures (:iss:`9068`) + 0.43.1 [2025-10-01] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/gl.c b/kitty/gl.c index 1032d623e..61c26c1da 100644 --- a/kitty/gl.c +++ b/kitty/gl.c @@ -84,7 +84,7 @@ gl_init(void) { } } -static const char* +const char* check_framebuffer_status(void) { GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); switch (status) { @@ -100,12 +100,6 @@ check_framebuffer_status(void) { } } -void -check_framebuffer_status_or_die(void) { - const char *err = check_framebuffer_status(); - if (err != NULL) fatal("Framebuffer not complete with error: %s", err); -} - void free_texture(GLuint *tex_id) { glDeleteTextures(1, tex_id); diff --git a/kitty/gl.h b/kitty/gl.h index 3ae2f1453..783e80964 100644 --- a/kitty/gl.h +++ b/kitty/gl.h @@ -63,7 +63,7 @@ void unbind_program(void); GLuint compile_shaders(GLenum shader_type, GLsizei count, const GLchar * const * string); void save_viewport_using_top_left_origin(GLsizei x, GLsizei y, GLsizei width, GLsizei height, GLsizei full_framebuffer_height); void save_viewport_using_bottom_left_origin(GLsizei x, GLsizei y, GLsizei width, GLsizei height); -void check_framebuffer_status_or_die(void); +const char* check_framebuffer_status(void); void restore_viewport(void); void bind_framebuffer_for_output(unsigned fbid); void set_framebuffer_to_use_for_output(unsigned fbid); diff --git a/kitty/shaders.c b/kitty/shaders.c index 6c04fd515..b6638b3b5 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -656,9 +656,28 @@ setup_texture_as_render_target(unsigned width, unsigned height, GLuint *texture_ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // We use GL_RGBA16 to avoid incorrect colors due to quantization loss when // blending, see https://github.com/kovidgoyal/kitty/issues/8953 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + static struct { bool ok; int fmt; } status = { false, GL_RGBA16}; + glTexImage2D(GL_TEXTURE_2D, 0, status.fmt, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); bind_framebuffer_for_output(*framebuffer_id); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture_id, 0); + if (!status.ok) { + if (check_framebuffer_status() == NULL) { + status.ok = true; + } else { + if (status.fmt == GL_RGBA16) { + // Driver does not support 16 bit FBO so let it choose the + // format. It will probably end up choosing 8 bit but + // inaccurate colors are better than completely broken rendering. + // See https://github.com/kovidgoyal/kitty/issues/9068 + status.fmt = GL_RGBA; + free_framebuffer(framebuffer_id); + free_texture(texture_id); + setup_texture_as_render_target(width, height, texture_id, framebuffer_id); + } else { + fatal("Your GPU driver does not support indirect rendering to a GL_RGBA texture via a framebuffer"); + } + } + } } static void