From bf79653fa253d5c0f2e77c4c94aec445ffd2fbf9 Mon Sep 17 00:00:00 2001 From: Bernd Busse Date: Thu, 24 Jun 2021 18:47:40 +0200 Subject: [PATCH] backend: gl_common: Copy texture by explict rendering to framebuffer At least on nvidia, binding the textures from a glx pixmap to a framebuffer results in `GL_FRAMEBUFFER_UNSUPPORTED`. Instead of using binding the source texture to a framebuffer and using `glCopyTexImage2D()` to copy into a new texture, explicitly render the source texture to the new texture attached to a framebuffer. Fixes black/invisible windows on nvidia with `frame-opacity != 1`. see: #647 related: 2a60836a9bc30d92b4adb46d5f48684a5d2f1ecb --- src/backend/gl/gl_common.c | 82 ++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 8 deletions(-) diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index 1a19b0e..e0a7848 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -1765,18 +1765,84 @@ static inline void gl_image_decouple(backend_t *base, struct backend_image *img) new_tex->refcount = 1; new_tex->user_data = gd->decouple_texture_user_data(base, inner->user_data); + glBindTexture(GL_TEXTURE_2D, new_tex->texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, new_tex->width, new_tex->height, 0, + GL_BGRA, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + assert(gd->present_prog); + glUseProgram(gd->present_prog); + glBindTexture(GL_TEXTURE_2D, inner->texture); + GLuint fbo; glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - inner->texture, 0); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindTexture(GL_TEXTURE_2D, new_tex->texture); - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, new_tex->width, new_tex->height, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + new_tex->texture, 0); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + gl_check_fb_complete(GL_DRAW_FRAMEBUFFER); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + // clang-format off + GLint coord[] = { + // top left + 0, 0, // vertex coord + 0, 0, // texture coord + + // top right + new_tex->width, 0, // vertex coord + new_tex->width, 0, // texture coord + + // bottom right + new_tex->width, new_tex->height, + new_tex->width, new_tex->height, + + // bottom left + 0, new_tex->height, + 0, new_tex->height, + }; + // clang-format on + GLuint indices[] = {0, 1, 2, 2, 3, 0}; + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + GLuint bo[2]; + glGenBuffers(2, bo); + glBindBuffer(GL_ARRAY_BUFFER, bo[0]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo[1]); + glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * 16, coord, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * 6, indices, + GL_STATIC_DRAW); + + glEnableVertexAttribArray(vert_coord_loc); + glEnableVertexAttribArray(vert_in_texcoord_loc); + glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE, sizeof(GLint) * 4, NULL); + glVertexAttribPointer(vert_in_texcoord_loc, 2, GL_INT, GL_FALSE, + sizeof(GLint) * 4, (void *)(sizeof(GLint) * 2)); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL); + + glDisableVertexAttribArray(vert_coord_loc); + glDisableVertexAttribArray(vert_in_texcoord_loc); + glBindVertexArray(0); + glDeleteVertexArrays(1, &vao); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDeleteBuffers(2, bo); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fbo); + glBindTexture(GL_TEXTURE_2D, 0); + glUseProgram(0); + + gl_check_err(); + img->inner = (struct backend_image_inner_base *)new_tex; inner->refcount--; }