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: 2a60836a9b
This commit is contained in:
Bernd Busse 2021-06-24 18:47:40 +02:00
parent f11710a885
commit bf79653fa2
No known key found for this signature in database
GPG Key ID: 6DD2A3C48E63A5AB
1 changed files with 74 additions and 8 deletions

View File

@ -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--;
}