From 34254ff86e18ed10ee9a90ce60f16c32c052acda Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sun, 10 Mar 2019 01:51:21 +0000 Subject: [PATCH] new glx: implement fill for monitor-repaint Refine the API of fill_rectangle and rename it to fill. Extras: Keep GL_BLEND enabled; Fixed some texture/fbo leaks Signed-off-by: Yuxuan Shui --- src/backend/backend.c | 6 ++-- src/backend/backend.h | 4 +-- src/backend/gl/gl_common.c | 71 +++++++++++++++++--------------------- src/backend/gl/gl_common.h | 1 + src/backend/gl/glx.c | 1 + src/backend/xrender.c | 13 ++++--- src/compton.c | 2 +- 7 files changed, 48 insertions(+), 50 deletions(-) diff --git a/src/backend/backend.c b/src/backend/backend.c index 7febbe69..84ab62e5 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -244,10 +244,8 @@ void paint_all_new(session_t *ps, win *const t, bool ignore_damage) { if (ps->o.monitor_repaint) { reg_damage = get_damage(ps, false); - auto extent = pixman_region32_extents(®_damage); - ps->backend_data->ops->fill_rectangle( - ps->backend_data, 0.5, 0, 0, 0.5, extent->x1, extent->y1, - extent->x2 - extent->x1, extent->y2 - extent->y1, ®_damage); + ps->backend_data->ops->fill( + ps->backend_data, 0.5, 0, 0, 0.5, ®_damage); pixman_region32_fini(®_damage); } diff --git a/src/backend/backend.h b/src/backend/backend.h index c8151e16..9d7871a1 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -90,8 +90,8 @@ struct backend_operations { const region_t *reg_paint, const region_t *reg_visible); /// Fill rectangle of target, mostly for debug purposes, optional. - void (*fill_rectangle)(backend_t *backend_data, double r, double g, double b, double a, - int x, int y, int width, int height, const region_t *clip); + void (*fill)(backend_t *backend_data, double r, double g, double b, double a, + const region_t *clip); /// Blur a given region on of the target. bool (*blur)(backend_t *backend_data, double opacity, const region_t *reg_blur, diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index 49399aa7..84722472 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -205,18 +205,6 @@ void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y, // It's required by legacy versions of OpenGL to enable texture target // before specifying environment. Thanks to madsy for telling me. glEnable(ptex->target); - - // Enable blending if needed - if (ptex->opacity < 1.0 || ptex->has_alpha) { - - glEnable(GL_BLEND); - // X pixmap is in premultiplied ARGB format, so - // we need to do this to correct it. - // Thanks to derhass for help. - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glColor4f(ptex->opacity, ptex->opacity, ptex->opacity, ptex->opacity); - } - if (gd->win_shader.prog) { glUseProgram(gd->win_shader.prog); if (gd->win_shader.unifm_opacity >= 0) @@ -297,7 +285,6 @@ void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y, // Cleanup glBindTexture(ptex->target, 0); glColor4f(0.0f, 0.0f, 0.0f, 0.0f); - glDisable(GL_BLEND); glDisable(GL_COLOR_LOGIC_OP); glDisable(ptex->target); @@ -317,12 +304,7 @@ void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y, bool gl_dim_reg(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor, const region_t *reg_tgt) { - // It's possible to dim in glx_render(), but it would be over-complicated - // considering all those mess in color negation and modulation - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.0f, 0.0f, 0.0f, factor); - { P_PAINTREG_START(reg_tgt, crect) { glVertex3i(crect.x1, crect.y1, z); @@ -334,7 +316,6 @@ bool gl_dim_reg(session_t *ps, int dx, int dy, int width, int height, float z, } glColor4f(0.0f, 0.0f, 0.0f, 0.0f); - glDisable(GL_BLEND); gl_check_err(); @@ -523,11 +504,26 @@ void gl_resize(struct gl_data *gd, int width, int height) { GL_BGRA, GL_UNSIGNED_BYTE, NULL); if (gd->npasses > 1) { glBindTexture(gd->blur_texture_target, gd->blur_texture[1]); - glTexImage2D(gd->blur_texture_target, 0, GL_RGBA8, gd->width, gd->height, 0, - GL_BGRA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(gd->blur_texture_target, 0, GL_RGBA8, gd->width, gd->height, + 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); } } +void gl_fill(backend_t *base, double r, double g, double b, double a, const region_t *clip) { + int nrects; + const rect_t *rect = pixman_region32_rectangles((region_t *)clip, &nrects); + struct gl_data *gd = (void *)base; + glColor4f(r, g, b, a); + glBegin(GL_QUADS); + for (int i = 0; i < nrects; i++) { + glVertex2f(rect[i].x1, gd->height - rect[i].y2); + glVertex2f(rect[i].x2, gd->height - rect[i].y2); + glVertex2f(rect[i].x2, gd->height - rect[i].y1); + glVertex2f(rect[i].x1, gd->height - rect[i].y1); + } + glEnd(); +} + /** * Initialize GL blur filters. */ @@ -536,19 +532,6 @@ static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels) { return true; } - // Allocate PBO if more than one blur kernel is present - if (kernels[1]) { - // Try to generate a framebuffer - GLuint fbo = 0; - glGenFramebuffers(1, &fbo); - if (!fbo) { - log_error("Failed to generate Framebuffer. Cannot do " - "multi-pass blur with GL backends."); - return false; - } - glDeleteFramebuffers(1, &fbo); - } - char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL)); // Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane // Thanks to hiciu for reporting. @@ -645,19 +628,21 @@ static bool gl_init_blur(struct gl_data *gd, conv *const *const kernels) { if (gd->non_power_of_two_texture) { gd->blur_texture_target = GL_TEXTURE_2D; } + + // Texture size will be defined by gl_resize glGenTextures(gd->npasses > 1 ? 2 : 1, gd->blur_texture); glBindTexture(gd->blur_texture_target, gd->blur_texture[0]); glTexParameteri(gd->blur_texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(gd->blur_texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(gd->blur_texture_target, 0, GL_RGBA8, gd->width, gd->height, 0, - GL_BGRA, GL_UNSIGNED_BYTE, NULL); if (gd->npasses > 1) { glBindTexture(gd->blur_texture_target, gd->blur_texture[1]); glTexParameteri(gd->blur_texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(gd->blur_texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(gd->blur_texture_target, 0, GL_RGBA8, gd->width, gd->height, 0, - GL_BGRA, GL_UNSIGNED_BYTE, NULL); glGenFramebuffers(1, &gd->blur_fbo); + if (!gd->blur_fbo) { + log_error("Failed to generate framebuffer object for blur"); + return false; + } } // Restore LC_NUMERIC @@ -706,7 +691,10 @@ bool gl_init(struct gl_data *gd, session_t *ps) { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); - glDisable(GL_BLEND); + glEnable(GL_BLEND); + // X pixmap is in premultiplied alpha, so we might just as well use it too. + // Thanks to derhass for help. + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // Initialize stencil buffer glDisable(GL_STENCIL_TEST); @@ -745,6 +733,11 @@ void gl_deinit(struct gl_data *gd) { gl_free_prog_main(&gd->win_shader); + glDeleteTextures(gd->npasses > 1 ? 2 : 1, gd->blur_texture); + if (gd->npasses > 1) { + glDeleteFramebuffers(1, &gd->blur_fbo); + } + gl_check_err(); } diff --git a/src/backend/gl/gl_common.h b/src/backend/gl/gl_common.h index 48c1f6f6..99cb0027 100644 --- a/src/backend/gl/gl_common.h +++ b/src/backend/gl/gl_common.h @@ -109,6 +109,7 @@ bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur, const region_t *reg_visible); bool gl_is_image_transparent(backend_t *base, void *image_data); +void gl_fill(backend_t *base, double r, double g, double b, double a, const region_t *clip); static inline void gl_delete_texture(GLuint texture) { glDeleteTextures(1, &texture); diff --git a/src/backend/gl/glx.c b/src/backend/gl/glx.c index 3a9d5667..01b426d2 100644 --- a/src/backend/gl/glx.c +++ b/src/backend/gl/glx.c @@ -468,6 +468,7 @@ struct backend_operations glx_ops = { .present = glx_present, .buffer_age = glx_buffer_age, .render_shadow = default_backend_render_shadow, + .fill = gl_fill, .max_buffer_age = 5, // Why? }; diff --git a/src/backend/xrender.c b/src/backend/xrender.c index b3337a67..d7dd5722 100644 --- a/src/backend/xrender.c +++ b/src/backend/xrender.c @@ -105,16 +105,21 @@ static void compose(backend_t *base, void *img_data, int dst_x, int dst_y, pixman_region32_fini(®); } -static void fill_rectangle(backend_t *base, double r, double g, double b, double a, int x, - int y, int width, int height, const region_t *clip) { +static void +fill(backend_t *base, double r, double g, double b, double a, const region_t *clip) { struct _xrender_data *xd = (void *)base; + const rect_t *extent = pixman_region32_extents((region_t *)clip); x_set_picture_clip_region(base->c, xd->back[xd->curr_back], 0, 0, clip); // color is in X fixed point representation xcb_render_fill_rectangles( base->c, XCB_RENDER_PICT_OP_OVER, xd->back[xd->curr_back], (xcb_render_color_t){ .red = r * 0xffff, .green = g * 0xffff, .blue = b * 0xffff, .alpha = a * 0xffff}, - 1, (xcb_rectangle_t[]){{.x = x, .y = y, .width = width, .height = height}}); + 1, + (xcb_rectangle_t[]){{.x = extent->x1, + .y = extent->y1, + .width = extent->x2 - extent->x1, + .height = extent->y2 - extent->y1}}); } static bool blur(backend_t *backend_data, double opacity, const region_t *reg_blur, @@ -561,7 +566,7 @@ struct backend_operations xrender_ops = { .blur = blur, .present = present, .compose = compose, - .fill_rectangle = fill_rectangle, + .fill = fill, .bind_pixmap = bind_pixmap, .release_image = release_image, .render_shadow = default_backend_render_shadow, diff --git a/src/compton.c b/src/compton.c index 31d3f289..90f1e192 100644 --- a/src/compton.c +++ b/src/compton.c @@ -2727,7 +2727,7 @@ session_init(int argc, char **argv, Display *dpy, const char *config_file, } if (ps->o.experimental_backends) { - if (ps->o.monitor_repaint && !backend_list[ps->o.backend]->fill_rectangle) { + if (ps->o.monitor_repaint && !backend_list[ps->o.backend]->fill) { log_warn("--monitor-repaint is not supported by the backend, disabling"); ps->o.monitor_repaint = false; }