new backend: gl_common: add support for decoupling lazy copied images
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
b91888b0a3
commit
86f4d73c22
|
@ -42,7 +42,7 @@ enum image_operations {
|
||||||
IMAGE_OP_APPLY_ALPHA_ALL,
|
IMAGE_OP_APPLY_ALPHA_ALL,
|
||||||
// Change the effective size of the image, without touching the backing image
|
// Change the effective size of the image, without touching the backing image
|
||||||
// itself. When the image is used, the backing image should be tiled to fill its
|
// itself. When the image is used, the backing image should be tiled to fill its
|
||||||
// effective size. `reg_op` and `reg_visibile` is ignored. `arg` is two integers,
|
// effective size. `reg_op` and `reg_visible` is ignored. `arg` is two integers,
|
||||||
// width and height, in that order.
|
// width and height, in that order.
|
||||||
IMAGE_OP_RESIZE_TILE,
|
IMAGE_OP_RESIZE_TILE,
|
||||||
};
|
};
|
||||||
|
@ -80,6 +80,11 @@ struct backend_operations {
|
||||||
|
|
||||||
// =========== Rendering ============
|
// =========== Rendering ============
|
||||||
|
|
||||||
|
// NOTE: general idea about reg_paint/reg_op vs reg_visible is that reg_visible is
|
||||||
|
// merely a hint. Ignoring reg_visible entirely don't affect the correctness of
|
||||||
|
// the operation performed. OTOH reg_paint/reg_op is part of the parameters of the
|
||||||
|
// operation, and must be honored in order to complete the operation correctly.
|
||||||
|
|
||||||
/// Called before when a new frame starts.
|
/// Called before when a new frame starts.
|
||||||
///
|
///
|
||||||
/// Optional
|
/// Optional
|
||||||
|
@ -93,7 +98,7 @@ struct backend_operations {
|
||||||
* @param image_data the image to paint
|
* @param image_data the image to paint
|
||||||
* @param dst_x, dst_y the top left corner of the image in the target
|
* @param dst_x, dst_y the top left corner of the image in the target
|
||||||
* @param reg_paint the clip region, in target coordinates
|
* @param reg_paint the clip region, in target coordinates
|
||||||
* @param reg_visibile the visible region, in target coordinates
|
* @param reg_visible the visible region, in target coordinates
|
||||||
*/
|
*/
|
||||||
void (*compose)(backend_t *backend_data, void *image_data, int dst_x, int dst_y,
|
void (*compose)(backend_t *backend_data, void *image_data, int dst_x, int dst_y,
|
||||||
const region_t *reg_paint, const region_t *reg_visible);
|
const region_t *reg_paint, const region_t *reg_visible);
|
||||||
|
|
|
@ -152,15 +152,15 @@ static void gl_free_prog_main(gl_win_shader_t *pprogram) {
|
||||||
* Render a region with texture data.
|
* Render a region with texture data.
|
||||||
*
|
*
|
||||||
* @param ptex the texture
|
* @param ptex the texture
|
||||||
|
* @param target the framebuffer to render into
|
||||||
* @param dst_x,dst_y the top left corner of region where this texture
|
* @param dst_x,dst_y the top left corner of region where this texture
|
||||||
* should go. In Xorg coordinate system (important!).
|
* should go. In OpenGL coordinate system (important!).
|
||||||
* @param reg_tgt the clip region, also in Xorg coordinate system
|
* @param reg_tgt the clip region, in Xorg coordinate system
|
||||||
* @param reg_visible ignored
|
* @param reg_visible ignored
|
||||||
*/
|
*/
|
||||||
void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y,
|
static void _gl_compose(backend_t *base, struct gl_image *img, GLuint target, int dst_x,
|
||||||
const region_t *reg_tgt, const region_t *reg_visible) {
|
int dst_y, GLfloat *coord, GLuint *indices, int nrects) {
|
||||||
|
|
||||||
struct gl_image *ptex = image_data;
|
|
||||||
struct gl_data *gd = (void *)base;
|
struct gl_data *gd = (void *)base;
|
||||||
|
|
||||||
// Until we start to use glClipControl, reg_tgt, dst_x and dst_y and
|
// Until we start to use glClipControl, reg_tgt, dst_x and dst_y and
|
||||||
|
@ -169,11 +169,89 @@ void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y,
|
||||||
// screen, with y axis pointing up; Xorg has the origin at the upper left of the
|
// screen, with y axis pointing up; Xorg has the origin at the upper left of the
|
||||||
// screen, with y axis pointing down. We have to do some coordinate conversion in
|
// screen, with y axis pointing down. We have to do some coordinate conversion in
|
||||||
// this function
|
// this function
|
||||||
if (!ptex || !ptex->inner->texture) {
|
if (!img || !img->inner->texture) {
|
||||||
log_error("Missing texture.");
|
log_error("Missing texture.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool dual_texture = false;
|
||||||
|
|
||||||
|
assert(gd->win_shader.prog);
|
||||||
|
glUseProgram(gd->win_shader.prog);
|
||||||
|
if (gd->win_shader.unifm_opacity >= 0) {
|
||||||
|
glUniform1f(gd->win_shader.unifm_opacity, (float)img->opacity);
|
||||||
|
}
|
||||||
|
if (gd->win_shader.unifm_invert_color >= 0) {
|
||||||
|
glUniform1i(gd->win_shader.unifm_invert_color, img->color_inverted);
|
||||||
|
}
|
||||||
|
if (gd->win_shader.unifm_tex >= 0) {
|
||||||
|
glUniform1i(gd->win_shader.unifm_tex, 0);
|
||||||
|
}
|
||||||
|
if (gd->win_shader.unifm_dim >= 0) {
|
||||||
|
glUniform1f(gd->win_shader.unifm_dim, (float)img->dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
// log_trace("Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n",
|
||||||
|
// x, y, width, height, dx, dy, ptex->width, ptex->height, z);
|
||||||
|
|
||||||
|
// Bind texture
|
||||||
|
glBindTexture(GL_TEXTURE_2D, img->inner->texture);
|
||||||
|
if (dual_texture) {
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, img->inner->texture);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) * nrects * 16, coord, GL_STATIC_DRAW);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * nrects * 6,
|
||||||
|
indices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray((GLuint)gd->win_shader.coord_loc);
|
||||||
|
glEnableVertexAttribArray((GLuint)gd->win_shader.in_texcoord);
|
||||||
|
glVertexAttribPointer((GLuint)gd->win_shader.coord_loc, 2, GL_FLOAT, GL_FALSE,
|
||||||
|
sizeof(GLfloat) * 4, NULL);
|
||||||
|
glVertexAttribPointer((GLuint)gd->win_shader.in_texcoord, 2, GL_FLOAT, GL_FALSE,
|
||||||
|
sizeof(GLfloat) * 4, (void *)(sizeof(GLfloat) * 2));
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target);
|
||||||
|
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
|
||||||
|
glDisableVertexAttribArray((GLuint)gd->win_shader.coord_loc);
|
||||||
|
glDisableVertexAttribArray((GLuint)gd->win_shader.in_texcoord);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glDeleteVertexArrays(1, &vao);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
if (dual_texture) {
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
glDeleteBuffers(2, bo);
|
||||||
|
|
||||||
|
glUseProgram(0);
|
||||||
|
|
||||||
|
gl_check_err();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y,
|
||||||
|
const region_t *reg_tgt, const region_t *reg_visible) {
|
||||||
|
struct gl_data *gd = (void *)base;
|
||||||
|
struct gl_image *img = image_data;
|
||||||
|
|
||||||
// Painting
|
// Painting
|
||||||
int nrects;
|
int nrects;
|
||||||
const rect_t *rects;
|
const rect_t *rects;
|
||||||
|
@ -183,41 +261,9 @@ void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dst_y is the top coordinate, in OpenGL, it is the upper bound of the y
|
|
||||||
// coordinate.
|
|
||||||
dst_y = gd->height - dst_y;
|
|
||||||
auto dst_y2 = dst_y - ptex->inner->height;
|
|
||||||
|
|
||||||
bool dual_texture = false;
|
|
||||||
|
|
||||||
assert(gd->win_shader.prog);
|
|
||||||
glUseProgram(gd->win_shader.prog);
|
|
||||||
if (gd->win_shader.unifm_opacity >= 0) {
|
|
||||||
glUniform1f(gd->win_shader.unifm_opacity, (float)ptex->opacity);
|
|
||||||
}
|
|
||||||
if (gd->win_shader.unifm_invert_color >= 0) {
|
|
||||||
glUniform1i(gd->win_shader.unifm_invert_color, ptex->color_inverted);
|
|
||||||
}
|
|
||||||
if (gd->win_shader.unifm_tex >= 0) {
|
|
||||||
glUniform1i(gd->win_shader.unifm_tex, 0);
|
|
||||||
}
|
|
||||||
if (gd->win_shader.unifm_dim >= 0) {
|
|
||||||
glUniform1f(gd->win_shader.unifm_dim, (float)ptex->dim);
|
|
||||||
}
|
|
||||||
|
|
||||||
// log_trace("Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n",
|
|
||||||
// x, y, width, height, dx, dy, ptex->width, ptex->height, z);
|
|
||||||
|
|
||||||
// Bind texture
|
|
||||||
glBindTexture(GL_TEXTURE_2D, ptex->inner->texture);
|
|
||||||
if (dual_texture) {
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, ptex->inner->texture);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
}
|
|
||||||
auto coord = ccalloc(nrects * 16, GLfloat);
|
auto coord = ccalloc(nrects * 16, GLfloat);
|
||||||
auto indices = ccalloc(nrects * 6, GLuint);
|
auto indices = ccalloc(nrects * 6, GLuint);
|
||||||
|
dst_y = gd->height - dst_y - img->inner->height;
|
||||||
for (int i = 0; i < nrects; ++i) {
|
for (int i = 0; i < nrects; ++i) {
|
||||||
// Y-flip. Note after this, crect.y1 > crect.y2
|
// Y-flip. Note after this, crect.y1 > crect.y2
|
||||||
rect_t crect = rects[i];
|
rect_t crect = rects[i];
|
||||||
|
@ -227,22 +273,22 @@ void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y,
|
||||||
// Calculate texture coordinates
|
// Calculate texture coordinates
|
||||||
// (texture_x1, texture_y1), texture coord for the _bottom left_ corner
|
// (texture_x1, texture_y1), texture coord for the _bottom left_ corner
|
||||||
auto texture_x1 = (GLfloat)(crect.x1 - dst_x);
|
auto texture_x1 = (GLfloat)(crect.x1 - dst_x);
|
||||||
auto texture_y1 = (GLfloat)(crect.y2 - dst_y2);
|
auto texture_y1 = (GLfloat)(crect.y2 - dst_y);
|
||||||
auto texture_x2 = texture_x1 + (GLfloat)(crect.x2 - crect.x1);
|
auto texture_x2 = texture_x1 + (GLfloat)(crect.x2 - crect.x1);
|
||||||
auto texture_y2 = texture_y1 + (GLfloat)(crect.y1 - crect.y2);
|
auto texture_y2 = texture_y1 + (GLfloat)(crect.y1 - crect.y2);
|
||||||
|
|
||||||
// X pixmaps might be Y inverted, invert the texture coordinates
|
// X pixmaps might be Y inverted, invert the texture coordinates
|
||||||
if (ptex->inner->y_inverted) {
|
if (img->inner->y_inverted) {
|
||||||
texture_y1 = (GLfloat)ptex->inner->height - texture_y1;
|
texture_y1 = (GLfloat)img->inner->height - texture_y1;
|
||||||
texture_y2 = (GLfloat)ptex->inner->height - texture_y2;
|
texture_y2 = (GLfloat)img->inner->height - texture_y2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GL_TEXTURE_2D coordinates are normalized
|
// GL_TEXTURE_2D coordinates are normalized
|
||||||
// TODO use texelFetch
|
// TODO use texelFetch
|
||||||
texture_x1 /= (GLfloat)ptex->inner->width;
|
texture_x1 /= (GLfloat)img->inner->width;
|
||||||
texture_y1 /= (GLfloat)ptex->inner->height;
|
texture_y1 /= (GLfloat)img->inner->height;
|
||||||
texture_x2 /= (GLfloat)ptex->inner->width;
|
texture_x2 /= (GLfloat)img->inner->width;
|
||||||
texture_y2 /= (GLfloat)ptex->inner->height;
|
texture_y2 /= (GLfloat)img->inner->height;
|
||||||
|
|
||||||
// Vertex coordinates
|
// Vertex coordinates
|
||||||
auto vx1 = (GLfloat)crect.x1;
|
auto vx1 = (GLfloat)crect.x1;
|
||||||
|
@ -270,52 +316,10 @@ void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y,
|
||||||
memcpy(&indices[i * 6], (GLuint[]){u + 0, u + 1, u + 2, u + 2, u + 3, u + 0},
|
memcpy(&indices[i * 6], (GLuint[]){u + 0, u + 1, u + 2, u + 2, u + 3, u + 0},
|
||||||
sizeof(GLuint) * 6);
|
sizeof(GLuint) * 6);
|
||||||
}
|
}
|
||||||
|
_gl_compose(base, img, 0, dst_x, dst_y, coord, indices, nrects);
|
||||||
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) * nrects * 16, coord, GL_STATIC_DRAW);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * nrects * 6,
|
|
||||||
indices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
glEnableVertexAttribArray((GLuint)gd->win_shader.coord_loc);
|
|
||||||
glEnableVertexAttribArray((GLuint)gd->win_shader.in_texcoord);
|
|
||||||
glVertexAttribPointer((GLuint)gd->win_shader.coord_loc, 2, GL_FLOAT, GL_FALSE,
|
|
||||||
sizeof(GLfloat) * 4, NULL);
|
|
||||||
glVertexAttribPointer((GLuint)gd->win_shader.in_texcoord, 2, GL_FLOAT, GL_FALSE,
|
|
||||||
sizeof(GLfloat) * 4, (void *)(sizeof(GLfloat) * 2));
|
|
||||||
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
|
|
||||||
glDisableVertexAttribArray((GLuint)gd->win_shader.coord_loc);
|
|
||||||
glDisableVertexAttribArray((GLuint)gd->win_shader.in_texcoord);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
glDeleteVertexArrays(1, &vao);
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
|
|
||||||
if (dual_texture) {
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
||||||
glDeleteBuffers(2, bo);
|
|
||||||
|
|
||||||
free(indices);
|
free(indices);
|
||||||
free(coord);
|
free(coord);
|
||||||
|
|
||||||
glUseProgram(0);
|
|
||||||
|
|
||||||
gl_check_err();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -642,6 +646,33 @@ void gl_fill(backend_t *base, double r, double g, double b, double a, const regi
|
||||||
glDeleteBuffers(2, bo);
|
glDeleteBuffers(2, bo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gl_release_image(backend_t *base, void *image_data) {
|
||||||
|
struct gl_image *wd = image_data;
|
||||||
|
struct gl_data *gl = (void *)base;
|
||||||
|
wd->inner->refcount--;
|
||||||
|
assert(wd->inner->refcount >= 0);
|
||||||
|
if (wd->inner->refcount > 0) {
|
||||||
|
free(wd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl->release_user_data(base, wd->inner);
|
||||||
|
assert(wd->inner->user_data == NULL);
|
||||||
|
|
||||||
|
glDeleteTextures(1, &wd->inner->texture);
|
||||||
|
free(wd->inner);
|
||||||
|
free(wd);
|
||||||
|
gl_check_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *gl_copy(backend_t *base, const void *image_data, const region_t *reg_visible) {
|
||||||
|
const struct gl_image *img = image_data;
|
||||||
|
auto new_img = ccalloc(1, struct gl_image);
|
||||||
|
*new_img = *img;
|
||||||
|
new_img->inner->refcount++;
|
||||||
|
return new_img;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize GL blur filters.
|
* Initialize GL blur filters.
|
||||||
*/
|
*/
|
||||||
|
@ -894,10 +925,68 @@ GLuint gl_new_texture(GLenum target) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decouple `img` from the image it references, also applies all the lazy operations
|
/// Decouple `img` from the image it references, also applies all the lazy operations
|
||||||
static inline void gl_image_decouple(struct gl_image *img) {
|
static inline void gl_image_decouple(backend_t *base, struct gl_image *img) {
|
||||||
if (img->inner->refcount == 1) {
|
if (img->inner->refcount == 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct gl_data *gl = (void *)base;
|
||||||
|
auto new_tex = cmalloc(struct gl_texture);
|
||||||
|
|
||||||
|
glGenTextures(1, &new_tex->texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, new_tex->texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, img->inner->width, img->inner->height, 0,
|
||||||
|
GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
new_tex->y_inverted = true;
|
||||||
|
new_tex->height = img->inner->height;
|
||||||
|
new_tex->width = img->inner->width;
|
||||||
|
new_tex->refcount = 1;
|
||||||
|
new_tex->user_data = gl->decouple_texture_user_data(base, img->inner->user_data);
|
||||||
|
|
||||||
|
GLuint fbo;
|
||||||
|
glGenFramebuffers(1, &fbo);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||||
|
new_tex->texture, 0);
|
||||||
|
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||||
|
glClearColor(0, 0, 0, 0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
GLfloat coord[] = {
|
||||||
|
// top left
|
||||||
|
0, 0, // vertex coord
|
||||||
|
0, 0, // texture coord
|
||||||
|
|
||||||
|
// top right
|
||||||
|
(GLfloat)img->inner->width, 0, // vertex coord
|
||||||
|
1, 0, // texture coord
|
||||||
|
|
||||||
|
// bottom right
|
||||||
|
(GLfloat)img->inner->width, (GLfloat)img->inner->height,
|
||||||
|
1, 1,
|
||||||
|
|
||||||
|
// bottom left
|
||||||
|
0, (GLfloat)img->inner->height,
|
||||||
|
0, 1
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
_gl_compose(base, img, fbo, 0, 0, coord, (GLuint[]){0, 1, 2, 2, 3, 0}, 1);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
glDeleteFramebuffers(1, &fbo);
|
||||||
|
|
||||||
|
img->inner->refcount--;
|
||||||
|
img->inner = new_tex;
|
||||||
|
|
||||||
|
// Clear lazy operation flags
|
||||||
|
img->color_inverted = false;
|
||||||
|
img->dim = 0;
|
||||||
|
img->opacity = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// stub for backend_operations::image_op
|
/// stub for backend_operations::image_op
|
||||||
|
@ -912,7 +1001,7 @@ bool gl_image_op(backend_t *base, enum image_operations op, void *image_data,
|
||||||
break;
|
break;
|
||||||
case IMAGE_OP_APPLY_ALPHA_ALL: tex->opacity *= *(double *)arg; break;
|
case IMAGE_OP_APPLY_ALPHA_ALL: tex->opacity *= *(double *)arg; break;
|
||||||
case IMAGE_OP_APPLY_ALPHA:
|
case IMAGE_OP_APPLY_ALPHA:
|
||||||
gl_image_decouple(tex);
|
gl_image_decouple(base, tex);
|
||||||
log_warn("IMAGE_OP_APPLY_ALPHA not implemented yet");
|
log_warn("IMAGE_OP_APPLY_ALPHA not implemented yet");
|
||||||
break;
|
break;
|
||||||
case IMAGE_OP_RESIZE_TILE:
|
case IMAGE_OP_RESIZE_TILE:
|
||||||
|
|
|
@ -47,7 +47,7 @@ struct gl_texture {
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
int width, height;
|
int width, height;
|
||||||
bool y_inverted;
|
bool y_inverted;
|
||||||
unsigned depth;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Wrapper of a binded GLX texture.
|
/// @brief Wrapper of a binded GLX texture.
|
||||||
|
@ -78,6 +78,13 @@ struct gl_data {
|
||||||
// Temporary fbo used for blurring
|
// Temporary fbo used for blurring
|
||||||
GLuint blur_fbo;
|
GLuint blur_fbo;
|
||||||
|
|
||||||
|
/// Called when an gl_texture is decoupled from the texture it refers. Returns
|
||||||
|
/// the decoupled user_data
|
||||||
|
void *(*decouple_texture_user_data)(backend_t *base, void *user_data);
|
||||||
|
|
||||||
|
/// Release the user data attached to a gl_texture
|
||||||
|
void (*release_user_data)(backend_t *base, struct gl_texture *);
|
||||||
|
|
||||||
struct log_target *logger;
|
struct log_target *logger;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,6 +124,10 @@ GLuint gl_new_texture(GLenum target);
|
||||||
bool gl_image_op(backend_t *base, enum image_operations op, void *image_data,
|
bool gl_image_op(backend_t *base, enum image_operations op, void *image_data,
|
||||||
const region_t *reg_op, const region_t *reg_visible, void *arg);
|
const region_t *reg_op, const region_t *reg_visible, void *arg);
|
||||||
|
|
||||||
|
void gl_release_image(backend_t *base, void *image_data);
|
||||||
|
|
||||||
|
void *gl_copy(backend_t *base, const void *image_data, const region_t *reg_visible);
|
||||||
|
|
||||||
bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
|
bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
|
||||||
const region_t *reg_visible);
|
const region_t *reg_visible);
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,7 @@
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "x.h"
|
#include "x.h"
|
||||||
|
|
||||||
struct _glx_image_data {
|
struct _glx_pixmap {
|
||||||
struct gl_image gl;
|
|
||||||
GLXPixmap glpixmap;
|
GLXPixmap glpixmap;
|
||||||
xcb_pixmap_t pixmap;
|
xcb_pixmap_t pixmap;
|
||||||
bool owned;
|
bool owned;
|
||||||
|
@ -160,38 +159,30 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi
|
||||||
/**
|
/**
|
||||||
* Free a glx_texture_t.
|
* Free a glx_texture_t.
|
||||||
*/
|
*/
|
||||||
void glx_release_image(backend_t *base, void *image_data) {
|
static void glx_release_image(backend_t *base, struct gl_texture *tex) {
|
||||||
struct _glx_image_data *wd = image_data;
|
|
||||||
struct _glx_data *gd = (void *)base;
|
struct _glx_data *gd = (void *)base;
|
||||||
wd->gl.inner->refcount--;
|
|
||||||
if (wd->gl.inner->refcount != 0) {
|
struct _glx_pixmap *p = tex->user_data;
|
||||||
free(wd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Release binding
|
// Release binding
|
||||||
if (wd->glpixmap && wd->gl.inner->texture) {
|
if (p->glpixmap && tex->texture) {
|
||||||
glBindTexture(GL_TEXTURE_2D, wd->gl.inner->texture);
|
glBindTexture(GL_TEXTURE_2D, tex->texture);
|
||||||
glXReleaseTexImageEXT(gd->display, wd->glpixmap, GLX_FRONT_LEFT_EXT);
|
glXReleaseTexImageEXT(gd->display, p->glpixmap, GLX_FRONT_LEFT_EXT);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free GLX Pixmap
|
// Free GLX Pixmap
|
||||||
if (wd->glpixmap) {
|
if (p->glpixmap) {
|
||||||
glXDestroyPixmap(gd->display, wd->glpixmap);
|
glXDestroyPixmap(gd->display, p->glpixmap);
|
||||||
wd->glpixmap = 0;
|
p->glpixmap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wd->owned) {
|
if (p->owned) {
|
||||||
xcb_free_pixmap(base->c, wd->pixmap);
|
xcb_free_pixmap(base->c, p->pixmap);
|
||||||
wd->pixmap = XCB_NONE;
|
p->pixmap = XCB_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
glDeleteTextures(1, &wd->gl.inner->texture);
|
free(p);
|
||||||
free(wd->gl.inner);
|
tex->user_data = NULL;
|
||||||
|
|
||||||
// Free structure itself
|
|
||||||
free(wd);
|
|
||||||
gl_check_err();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -211,6 +202,14 @@ void glx_deinit(backend_t *base) {
|
||||||
free(gd);
|
free(gd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *glx_decouple_user_data(backend_t * attr_unused base, void * attr_unused ud) {
|
||||||
|
auto ret = cmalloc(struct _glx_pixmap);
|
||||||
|
ret->owned = false;
|
||||||
|
ret->glpixmap = 0;
|
||||||
|
ret->pixmap = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize OpenGL.
|
* Initialize OpenGL.
|
||||||
*/
|
*/
|
||||||
|
@ -325,6 +324,9 @@ static backend_t *glx_init(session_t *ps) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gd->gl.decouple_texture_user_data = glx_decouple_user_data;
|
||||||
|
gd->gl.release_user_data = glx_release_image;
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
@ -343,6 +345,7 @@ end:
|
||||||
static void *
|
static void *
|
||||||
glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) {
|
glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) {
|
||||||
struct _glx_data *gd = (void *)base;
|
struct _glx_data *gd = (void *)base;
|
||||||
|
struct _glx_pixmap *glxpixmap = NULL;
|
||||||
// Retrieve pixmap parameters, if they aren't provided
|
// Retrieve pixmap parameters, if they aren't provided
|
||||||
if (fmt.visual_depth > OPENGL_MAX_DEPTH) {
|
if (fmt.visual_depth > OPENGL_MAX_DEPTH) {
|
||||||
log_error("Requested depth %d higher than max possible depth %d.",
|
log_error("Requested depth %d higher than max possible depth %d.",
|
||||||
|
@ -362,11 +365,10 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
|
||||||
}
|
}
|
||||||
|
|
||||||
log_trace("Binding pixmap %#010x", pixmap);
|
log_trace("Binding pixmap %#010x", pixmap);
|
||||||
auto wd = ccalloc(1, struct _glx_image_data);
|
auto wd = ccalloc(1, struct gl_image);
|
||||||
wd->pixmap = pixmap;
|
wd->inner = ccalloc(1, struct gl_texture);
|
||||||
wd->gl.inner = ccalloc(1, struct gl_texture);
|
wd->inner->width = wd->ewidth = r->width;
|
||||||
wd->gl.inner->width = wd->gl.ewidth = r->width;
|
wd->inner->height = wd->eheight = r->height;
|
||||||
wd->gl.inner->height = wd->gl.eheight = r->height;
|
|
||||||
free(r);
|
free(r);
|
||||||
|
|
||||||
auto fbcfg = glx_find_fbconfig(gd->display, gd->screen, fmt);
|
auto fbcfg = glx_find_fbconfig(gd->display, gd->screen, fmt);
|
||||||
|
@ -394,37 +396,41 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
wd->gl.inner->y_inverted = fbcfg->y_inverted;
|
wd->inner->y_inverted = fbcfg->y_inverted;
|
||||||
|
|
||||||
wd->glpixmap = glXCreatePixmap(gd->display, fbcfg->cfg, wd->pixmap, attrs);
|
glxpixmap = cmalloc(struct _glx_pixmap);
|
||||||
|
glxpixmap->pixmap = pixmap;
|
||||||
|
glxpixmap->glpixmap = glXCreatePixmap(gd->display, fbcfg->cfg, pixmap, attrs);
|
||||||
|
glxpixmap->owned = owned;
|
||||||
free(fbcfg);
|
free(fbcfg);
|
||||||
|
|
||||||
if (!wd->glpixmap) {
|
if (!glxpixmap->glpixmap) {
|
||||||
log_error("Failed to create glpixmap for pixmap %#010x", pixmap);
|
log_error("Failed to create glpixmap for pixmap %#010x", pixmap);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_trace("GLXPixmap %#010lx", wd->glpixmap);
|
log_trace("GLXPixmap %#010lx", glxpixmap->glpixmap);
|
||||||
|
|
||||||
// Create texture
|
// Create texture
|
||||||
wd->gl.inner->texture = gl_new_texture(GL_TEXTURE_2D);
|
wd->inner->user_data = glxpixmap;
|
||||||
wd->gl.inner->depth = (unsigned int)fmt.visual_depth;
|
wd->inner->texture = gl_new_texture(GL_TEXTURE_2D);
|
||||||
wd->gl.opacity = 1;
|
wd->opacity = 1;
|
||||||
wd->gl.color_inverted = false;
|
wd->color_inverted = false;
|
||||||
wd->gl.dim = 0;
|
wd->dim = 0;
|
||||||
wd->gl.has_alpha = fmt.alpha_size != 0;
|
wd->has_alpha = fmt.alpha_size != 0;
|
||||||
wd->gl.inner->refcount = 1;
|
wd->inner->refcount = 1;
|
||||||
wd->owned = owned;
|
glBindTexture(GL_TEXTURE_2D, wd->inner->texture);
|
||||||
glBindTexture(GL_TEXTURE_2D, wd->gl.inner->texture);
|
glXBindTexImageEXT(gd->display, glxpixmap->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
|
||||||
glXBindTexImageEXT(gd->display, wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
gl_check_err();
|
gl_check_err();
|
||||||
return wd;
|
return wd;
|
||||||
err:
|
err:
|
||||||
if (wd->glpixmap) {
|
if (glxpixmap && glxpixmap->glpixmap) {
|
||||||
glXDestroyPixmap(gd->display, wd->glpixmap);
|
glXDestroyPixmap(gd->display, glxpixmap->glpixmap);
|
||||||
}
|
}
|
||||||
|
free(glxpixmap);
|
||||||
|
|
||||||
if (owned) {
|
if (owned) {
|
||||||
xcb_free_pixmap(base->c, pixmap);
|
xcb_free_pixmap(base->c, pixmap);
|
||||||
}
|
}
|
||||||
|
@ -452,22 +458,14 @@ static int glx_buffer_age(backend_t *base) {
|
||||||
return (int)val ?: -1;
|
return (int)val ?: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *glx_copy(backend_t *base, const void *image_data, const region_t *reg_visible) {
|
|
||||||
const struct _glx_image_data *img = image_data;
|
|
||||||
auto new_img = ccalloc(1, struct _glx_image_data);
|
|
||||||
*new_img = *img;
|
|
||||||
new_img->gl.inner->refcount++;
|
|
||||||
return new_img;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct backend_operations glx_ops = {
|
struct backend_operations glx_ops = {
|
||||||
.init = glx_init,
|
.init = glx_init,
|
||||||
.deinit = glx_deinit,
|
.deinit = glx_deinit,
|
||||||
.bind_pixmap = glx_bind_pixmap,
|
.bind_pixmap = glx_bind_pixmap,
|
||||||
.release_image = glx_release_image,
|
.release_image = gl_release_image,
|
||||||
.compose = gl_compose,
|
.compose = gl_compose,
|
||||||
.image_op = gl_image_op,
|
.image_op = gl_image_op,
|
||||||
.copy = glx_copy,
|
.copy = gl_copy,
|
||||||
.blur = gl_blur,
|
.blur = gl_blur,
|
||||||
.is_image_transparent = gl_is_image_transparent,
|
.is_image_transparent = gl_is_image_transparent,
|
||||||
.present = glx_present,
|
.present = glx_present,
|
||||||
|
|
Loading…
Reference in New Issue