Merge pull request #206 from yshui/fix-blur-artifacts
Fix blur artifacts in experimental backends Closes #194 #50
This commit is contained in:
commit
04ae6934e1
|
@ -71,6 +71,32 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
static struct timespec last_paint = {0};
|
static struct timespec last_paint = {0};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
region_t reg_paint;
|
||||||
|
assert(ps->o.blur_method != BLUR_METHOD_INVALID);
|
||||||
|
if (ps->o.blur_method != BLUR_METHOD_NONE && ps->backend_data->ops->get_blur_size) {
|
||||||
|
int blur_width, blur_height;
|
||||||
|
ps->backend_data->ops->get_blur_size(ps->backend_blur_context,
|
||||||
|
&blur_width, &blur_height);
|
||||||
|
if (t) {
|
||||||
|
// The region of screen a given window influences will be smeared
|
||||||
|
// out by blur. With more windows on top of the given window, the
|
||||||
|
// influences region will be smeared out more.
|
||||||
|
//
|
||||||
|
// Instead of accurately calculate how much bigger the damage
|
||||||
|
// region will be because of blur, we assume the worst case here.
|
||||||
|
// That is, the damaged window is at the bottom of the stack, and
|
||||||
|
// all other windows have semi-transparent background
|
||||||
|
resize_region_in_place(®_damage, blur_width * t->stacking_rank,
|
||||||
|
blur_height * t->stacking_rank);
|
||||||
|
pixman_region32_intersect(®_damage, ®_damage, &ps->screen_reg);
|
||||||
|
}
|
||||||
|
reg_paint = resize_region(®_damage, blur_width, blur_height);
|
||||||
|
pixman_region32_intersect(®_paint, ®_paint, &ps->screen_reg);
|
||||||
|
} else {
|
||||||
|
pixman_region32_init(®_paint);
|
||||||
|
pixman_region32_copy(®_paint, ®_damage);
|
||||||
|
}
|
||||||
|
|
||||||
// A hint to backend, the region that will be visible on screen
|
// A hint to backend, the region that will be visible on screen
|
||||||
// backend can optimize based on this info
|
// backend can optimize based on this info
|
||||||
region_t reg_visible;
|
region_t reg_visible;
|
||||||
|
@ -85,12 +111,12 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
// TODO Bind root pixmap
|
// TODO Bind root pixmap
|
||||||
|
|
||||||
if (ps->backend_data->ops->prepare) {
|
if (ps->backend_data->ops->prepare) {
|
||||||
ps->backend_data->ops->prepare(ps->backend_data, ®_damage);
|
ps->backend_data->ops->prepare(ps->backend_data, ®_paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps->root_image) {
|
if (ps->root_image) {
|
||||||
ps->backend_data->ops->compose(ps->backend_data, ps->root_image, 0, 0,
|
ps->backend_data->ops->compose(ps->backend_data, ps->root_image, 0, 0,
|
||||||
®_damage, ®_visible);
|
®_paint, ®_visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Windows are sorted from bottom to top
|
// Windows are sorted from bottom to top
|
||||||
|
@ -109,9 +135,9 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
// Draw shadow on target
|
// Draw shadow on target
|
||||||
if (w->shadow) {
|
if (w->shadow) {
|
||||||
// Clip region for the shadow
|
// Clip region for the shadow
|
||||||
// reg_shadow \in reg_damage
|
// reg_shadow \in reg_paint
|
||||||
auto reg_shadow = win_extents_by_val(w);
|
auto reg_shadow = win_extents_by_val(w);
|
||||||
pixman_region32_intersect(®_shadow, ®_shadow, ®_damage);
|
pixman_region32_intersect(®_shadow, ®_shadow, ®_paint);
|
||||||
if (!ps->o.wintype_option[w->window_type].full_shadow) {
|
if (!ps->o.wintype_option[w->window_type].full_shadow) {
|
||||||
pixman_region32_subtract(®_shadow, ®_shadow, ®_bound);
|
pixman_region32_subtract(®_shadow, ®_shadow, ®_bound);
|
||||||
}
|
}
|
||||||
|
@ -156,10 +182,10 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The clip region for the current window, in global/target coordinates
|
// The clip region for the current window, in global/target coordinates
|
||||||
// reg_paint \in reg_damage
|
// reg_paint_in_bound \in reg_paint
|
||||||
region_t reg_paint;
|
region_t reg_paint_in_bound;
|
||||||
pixman_region32_init(®_paint);
|
pixman_region32_init(®_paint_in_bound);
|
||||||
pixman_region32_intersect(®_paint, ®_bound, ®_damage);
|
pixman_region32_intersect(®_paint_in_bound, ®_bound, ®_paint);
|
||||||
|
|
||||||
// Blur window background
|
// Blur window background
|
||||||
// TODO since the background might change the content of the window (e.g.
|
// TODO since the background might change the content of the window (e.g.
|
||||||
|
@ -176,10 +202,10 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
// TODO resize blur region to fix black line artifact
|
// TODO resize blur region to fix black line artifact
|
||||||
if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) {
|
if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) {
|
||||||
// We need to blur the bounding shape of the window
|
// We need to blur the bounding shape of the window
|
||||||
// (reg_paint = reg_bound \cap reg_damage)
|
// (reg_paint_in_bound = reg_bound \cap reg_paint)
|
||||||
ps->backend_data->ops->blur(ps->backend_data, w->opacity,
|
ps->backend_data->ops->blur(
|
||||||
ps->backend_blur_context,
|
ps->backend_data, w->opacity, ps->backend_blur_context,
|
||||||
®_paint, ®_visible);
|
®_paint_in_bound, ®_visible);
|
||||||
} else {
|
} else {
|
||||||
// Window itself is solid, we only need to blur the frame
|
// Window itself is solid, we only need to blur the frame
|
||||||
// region
|
// region
|
||||||
|
@ -190,8 +216,8 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
|
|
||||||
auto reg_blur = win_get_region_frame_local_by_val(w);
|
auto reg_blur = win_get_region_frame_local_by_val(w);
|
||||||
pixman_region32_translate(®_blur, w->g.x, w->g.y);
|
pixman_region32_translate(®_blur, w->g.x, w->g.y);
|
||||||
// make sure reg_blur \in reg_damage
|
// make sure reg_blur \in reg_paint
|
||||||
pixman_region32_intersect(®_blur, ®_blur, ®_damage);
|
pixman_region32_intersect(®_blur, ®_blur, ®_paint);
|
||||||
ps->backend_data->ops->blur(ps->backend_data, w->opacity,
|
ps->backend_data->ops->blur(ps->backend_data, w->opacity,
|
||||||
ps->backend_blur_context,
|
ps->backend_blur_context,
|
||||||
®_blur, ®_visible);
|
®_blur, ®_visible);
|
||||||
|
@ -200,8 +226,9 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
}
|
}
|
||||||
// Draw window on target
|
// Draw window on target
|
||||||
if (!w->invert_color && !w->dim && w->frame_opacity == 1 && w->opacity == 1) {
|
if (!w->invert_color && !w->dim && w->frame_opacity == 1 && w->opacity == 1) {
|
||||||
ps->backend_data->ops->compose(ps->backend_data, w->win_image, w->g.x,
|
ps->backend_data->ops->compose(ps->backend_data, w->win_image,
|
||||||
w->g.y, ®_paint, ®_visible);
|
w->g.x, w->g.y,
|
||||||
|
®_paint_in_bound, ®_visible);
|
||||||
} else {
|
} else {
|
||||||
// For window image processing, we don't need to limit the process
|
// For window image processing, we don't need to limit the process
|
||||||
// region to damage, since the window image data is independent
|
// region to damage, since the window image data is independent
|
||||||
|
@ -219,7 +246,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
// outside of the damage region won't be painted onto target
|
// outside of the damage region won't be painted onto target
|
||||||
region_t reg_visible_local;
|
region_t reg_visible_local;
|
||||||
pixman_region32_init(®_visible_local);
|
pixman_region32_init(®_visible_local);
|
||||||
pixman_region32_intersect(®_visible_local, ®_visible, ®_damage);
|
pixman_region32_intersect(®_visible_local, ®_visible, ®_paint);
|
||||||
pixman_region32_translate(®_visible_local, -w->g.x, -w->g.y);
|
pixman_region32_translate(®_visible_local, -w->g.x, -w->g.y);
|
||||||
// Data outside of the bounding shape won't be visible, but it is
|
// Data outside of the bounding shape won't be visible, but it is
|
||||||
// not necessary to limit the image operations to the bounding
|
// not necessary to limit the image operations to the bounding
|
||||||
|
@ -228,7 +255,6 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
pixman_region32_intersect(®_visible_local, ®_visible_local,
|
pixman_region32_intersect(®_visible_local, ®_visible_local,
|
||||||
®_bound_local);
|
®_bound_local);
|
||||||
|
|
||||||
// A region covers the entire window
|
|
||||||
auto new_img = ps->backend_data->ops->copy(
|
auto new_img = ps->backend_data->ops->copy(
|
||||||
ps->backend_data, w->win_image, ®_visible_local);
|
ps->backend_data, w->win_image, ®_visible_local);
|
||||||
if (w->invert_color) {
|
if (w->invert_color) {
|
||||||
|
@ -258,21 +284,22 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
NULL, ®_visible_local, (double[]){w->opacity});
|
NULL, ®_visible_local, (double[]){w->opacity});
|
||||||
}
|
}
|
||||||
ps->backend_data->ops->compose(ps->backend_data, new_img, w->g.x,
|
ps->backend_data->ops->compose(ps->backend_data, new_img, w->g.x,
|
||||||
w->g.y, ®_paint, ®_visible);
|
w->g.y, ®_paint_in_bound,
|
||||||
|
®_visible);
|
||||||
ps->backend_data->ops->release_image(ps->backend_data, new_img);
|
ps->backend_data->ops->release_image(ps->backend_data, new_img);
|
||||||
pixman_region32_fini(®_visible_local);
|
pixman_region32_fini(®_visible_local);
|
||||||
pixman_region32_fini(®_bound_local);
|
pixman_region32_fini(®_bound_local);
|
||||||
}
|
}
|
||||||
pixman_region32_fini(®_bound);
|
pixman_region32_fini(®_bound);
|
||||||
pixman_region32_fini(®_paint);
|
pixman_region32_fini(®_paint_in_bound);
|
||||||
}
|
}
|
||||||
pixman_region32_fini(®_damage);
|
pixman_region32_fini(®_paint);
|
||||||
|
|
||||||
if (ps->o.monitor_repaint) {
|
if (ps->o.monitor_repaint) {
|
||||||
reg_damage = get_damage(ps, false);
|
auto reg_damage_debug = get_damage(ps, false);
|
||||||
ps->backend_data->ops->fill(ps->backend_data,
|
ps->backend_data->ops->fill(
|
||||||
(struct color){0.5, 0, 0, 0.5}, ®_damage);
|
ps->backend_data, (struct color){0.5, 0, 0, 0.5}, ®_damage_debug);
|
||||||
pixman_region32_fini(®_damage);
|
pixman_region32_fini(®_damage_debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the head of the damage ring
|
// Move the head of the damage ring
|
||||||
|
@ -285,9 +312,11 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||||
if (ps->backend_data->ops->present) {
|
if (ps->backend_data->ops->present) {
|
||||||
// Present the rendered scene
|
// Present the rendered scene
|
||||||
// Vsync is done here
|
// Vsync is done here
|
||||||
ps->backend_data->ops->present(ps->backend_data);
|
ps->backend_data->ops->present(ps->backend_data, ®_damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pixman_region32_fini(®_damage);
|
||||||
|
|
||||||
#ifdef DEBUG_REPAINT
|
#ifdef DEBUG_REPAINT
|
||||||
struct timespec now = get_time_timespec();
|
struct timespec now = get_time_timespec();
|
||||||
struct timespec diff = {0};
|
struct timespec diff = {0};
|
||||||
|
|
|
@ -114,8 +114,7 @@ struct backend_operations {
|
||||||
void (*prepare)(backend_t *backend_data, const region_t *reg_damage);
|
void (*prepare)(backend_t *backend_data, const region_t *reg_damage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paint the content of an image onto the (possibly buffered)
|
* Paint the content of an image onto the back buffer
|
||||||
* target picture.
|
|
||||||
*
|
*
|
||||||
* @param backend_data the backend data
|
* @param backend_data the backend data
|
||||||
* @param image_data the image to paint
|
* @param image_data the image to paint
|
||||||
|
@ -134,10 +133,11 @@ struct backend_operations {
|
||||||
const region_t *reg_blur, const region_t *reg_visible)
|
const region_t *reg_blur, const region_t *reg_visible)
|
||||||
attr_nonnull(1, 3, 4, 5);
|
attr_nonnull(1, 3, 4, 5);
|
||||||
|
|
||||||
/// Present the back buffer onto the screen.
|
/// Present part of the back buffer onto the screen.
|
||||||
///
|
///
|
||||||
/// Optional if the screen is not buffered
|
/// @param region part of the screen that should be updated. if NULL, update the
|
||||||
void (*present)(backend_t *backend_data) attr_nonnull(1);
|
/// whole screen
|
||||||
|
void (*present)(backend_t *backend_data, const region_t *region) attr_nonnull(1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a X pixmap to the backend's internal image data structure.
|
* Bind a X pixmap to the backend's internal image data structure.
|
||||||
|
|
|
@ -254,6 +254,8 @@ static void _gl_compose(backend_t *base, struct gl_image *img, GLuint target,
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
glDrawBuffer(GL_BACK);
|
||||||
|
|
||||||
if (dual_texture) {
|
if (dual_texture) {
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
@ -276,16 +278,16 @@ static void _gl_compose(backend_t *base, struct gl_image *img, GLuint target,
|
||||||
/// @param[in] nrects, rects rectangles
|
/// @param[in] nrects, rects rectangles
|
||||||
/// @param[in] dst_x, dst_y origin of the OpenGL texture, affect the calculated texture
|
/// @param[in] dst_x, dst_y origin of the OpenGL texture, affect the calculated texture
|
||||||
/// coordinates
|
/// coordinates
|
||||||
/// @param[in] width, height size of the OpenGL texture
|
/// @param[in] texture_height height of the OpenGL texture
|
||||||
/// @param[in] root_height height of the back buffer
|
/// @param[in] root_height height of the back buffer
|
||||||
/// @param[in] y_inverted whether the texture is y inverted
|
/// @param[in] y_inverted whether the texture is y inverted
|
||||||
/// @param[out] coord, indices output
|
/// @param[out] coord, indices output
|
||||||
static void
|
static void
|
||||||
x_rect_to_coords(int nrects, const rect_t *rects, int dst_x, int dst_y, int height,
|
x_rect_to_coords(int nrects, const rect_t *rects, int dst_x, int dst_y, int texture_height,
|
||||||
int root_height, bool y_inverted, GLint *coord, GLuint *indices) {
|
int root_height, bool y_inverted, GLint *coord, GLuint *indices) {
|
||||||
dst_y = root_height - dst_y;
|
dst_y = root_height - dst_y;
|
||||||
if (y_inverted) {
|
if (y_inverted) {
|
||||||
dst_y -= height;
|
dst_y -= texture_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < nrects; i++) {
|
for (int i = 0; i < nrects; i++) {
|
||||||
|
@ -302,8 +304,8 @@ x_rect_to_coords(int nrects, const rect_t *rects, int dst_x, int dst_y, int heig
|
||||||
|
|
||||||
// X pixmaps might be Y inverted, invert the texture coordinates
|
// X pixmaps might be Y inverted, invert the texture coordinates
|
||||||
if (y_inverted) {
|
if (y_inverted) {
|
||||||
texture_y1 = height - texture_y1;
|
texture_y1 = texture_height - texture_y1;
|
||||||
texture_y2 = height - texture_y2;
|
texture_y2 = texture_height - texture_y2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertex coordinates
|
// Vertex coordinates
|
||||||
|
@ -360,7 +362,7 @@ void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y,
|
||||||
auto indices = ccalloc(nrects * 6, GLuint);
|
auto indices = ccalloc(nrects * 6, GLuint);
|
||||||
x_rect_to_coords(nrects, rects, dst_x, dst_y, img->inner->height, gd->height,
|
x_rect_to_coords(nrects, rects, dst_x, dst_y, img->inner->height, gd->height,
|
||||||
img->inner->y_inverted, coord, indices);
|
img->inner->y_inverted, coord, indices);
|
||||||
_gl_compose(base, img, 0, coord, indices, nrects);
|
_gl_compose(base, img, gd->back_fbo, coord, indices, nrects);
|
||||||
|
|
||||||
free(indices);
|
free(indices);
|
||||||
free(coord);
|
free(coord);
|
||||||
|
@ -421,9 +423,7 @@ bool gl_blur(backend_t *base, double opacity, void *ctx, const region_t *reg_blu
|
||||||
resize_region(reg_blur, bctx->resize_width, bctx->resize_height);
|
resize_region(reg_blur, bctx->resize_width, bctx->resize_height);
|
||||||
const rect_t *extent = pixman_region32_extents((region_t *)reg_blur),
|
const rect_t *extent = pixman_region32_extents((region_t *)reg_blur),
|
||||||
*extent_resized = pixman_region32_extents(®_blur_resized);
|
*extent_resized = pixman_region32_extents(®_blur_resized);
|
||||||
int width = extent->x2 - extent->x1, height = extent->y2 - extent->y1,
|
int width = extent->x2 - extent->x1, height = extent->y2 - extent->y1;
|
||||||
width_resized = extent_resized->x2 - extent_resized->x1,
|
|
||||||
height_resized = extent_resized->y2 - extent_resized->y1;
|
|
||||||
int dst_y_resized_screen_coord = gd->height - extent_resized->y2,
|
int dst_y_resized_screen_coord = gd->height - extent_resized->y2,
|
||||||
dst_y_resized_fb_coord = bctx->texture_height - extent_resized->y2;
|
dst_y_resized_fb_coord = bctx->texture_height - extent_resized->y2;
|
||||||
if (width == 0 || height == 0) {
|
if (width == 0 || height == 0) {
|
||||||
|
@ -483,22 +483,27 @@ bool gl_blur(backend_t *base, double opacity, void *ctx, const region_t *reg_blu
|
||||||
sizeof(GLint) * 4, (void *)(sizeof(GLint) * 2));
|
sizeof(GLint) * 4, (void *)(sizeof(GLint) * 2));
|
||||||
|
|
||||||
int curr = 0;
|
int curr = 0;
|
||||||
glReadBuffer(GL_BACK);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, bctx->blur_texture[0]);
|
|
||||||
// Copy the area to be blurred into tmp buffer
|
|
||||||
|
|
||||||
int copy_tex_xoffset = 0, copy_tex_yoffset = 0, copy_tex_x = extent_resized->x1,
|
|
||||||
copy_tex_y = dst_y_resized_screen_coord;
|
|
||||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, copy_tex_xoffset, copy_tex_yoffset,
|
|
||||||
copy_tex_x, copy_tex_y, width_resized, height_resized);
|
|
||||||
|
|
||||||
for (int i = 0; i < bctx->npasses; ++i) {
|
for (int i = 0; i < bctx->npasses; ++i) {
|
||||||
const gl_blur_shader_t *p = &bctx->blur_shader[i];
|
const gl_blur_shader_t *p = &bctx->blur_shader[i];
|
||||||
assert(p->prog);
|
assert(p->prog);
|
||||||
|
|
||||||
assert(bctx->blur_texture[curr]);
|
assert(bctx->blur_texture[curr]);
|
||||||
glBindTexture(GL_TEXTURE_2D, bctx->blur_texture[curr]);
|
|
||||||
|
|
||||||
|
// The origin to use when sampling from the source texture
|
||||||
|
GLint texorig_x, texorig_y;
|
||||||
|
GLuint src_texture;
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
texorig_x = extent_resized->x1;
|
||||||
|
texorig_y = dst_y_resized_screen_coord;
|
||||||
|
src_texture = gd->back_texture;
|
||||||
|
} else {
|
||||||
|
texorig_x = 0;
|
||||||
|
texorig_y = 0;
|
||||||
|
src_texture = bctx->blur_texture[curr];
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, src_texture);
|
||||||
glUseProgram(p->prog);
|
glUseProgram(p->prog);
|
||||||
if (i < bctx->npasses - 1) {
|
if (i < bctx->npasses - 1) {
|
||||||
// not last pass, draw into framebuffer, with resized regions
|
// not last pass, draw into framebuffer, with resized regions
|
||||||
|
@ -522,13 +527,13 @@ bool gl_blur(backend_t *base, double opacity, void *ctx, const region_t *reg_blu
|
||||||
// last pass, draw directly into the back buffer, with origin
|
// last pass, draw directly into the back buffer, with origin
|
||||||
// regions
|
// regions
|
||||||
glBindVertexArray(vao[0]);
|
glBindVertexArray(vao[0]);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, gd->back_fbo);
|
||||||
glDrawBuffer(GL_BACK);
|
|
||||||
glUniform1f(p->unifm_opacity, (float)opacity);
|
glUniform1f(p->unifm_opacity, (float)opacity);
|
||||||
glUniform2f(p->orig_loc, 0, 0);
|
glUniform2f(p->orig_loc, 0, 0);
|
||||||
glViewport(0, 0, gd->width, gd->height);
|
glViewport(0, 0, gd->width, gd->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glUniform2f(p->texorig_loc, (GLfloat)texorig_x, (GLfloat)texorig_y);
|
||||||
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
|
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
|
||||||
|
|
||||||
// XXX use multiple draw calls is probably going to be slow than
|
// XXX use multiple draw calls is probably going to be slow than
|
||||||
|
@ -562,12 +567,13 @@ end:
|
||||||
const char *vertex_shader = GLSL(330,
|
const char *vertex_shader = GLSL(330,
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
uniform vec2 orig;
|
uniform vec2 orig;
|
||||||
|
uniform vec2 texorig;
|
||||||
layout(location = 0) in vec2 coord;
|
layout(location = 0) in vec2 coord;
|
||||||
layout(location = 1) in vec2 in_texcoord;
|
layout(location = 1) in vec2 in_texcoord;
|
||||||
out vec2 texcoord;
|
out vec2 texcoord;
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = projection * vec4(coord + orig, 0, 1);
|
gl_Position = projection * vec4(coord + orig, 0, 1);
|
||||||
texcoord = in_texcoord;
|
texcoord = in_texcoord + texorig;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -623,6 +629,14 @@ void gl_resize(struct gl_data *gd, int width, int height) {
|
||||||
pml = glGetUniformLocationChecked(gd->fill_shader.prog, "projection");
|
pml = glGetUniformLocationChecked(gd->fill_shader.prog, "projection");
|
||||||
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
|
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
|
||||||
|
|
||||||
|
glUseProgram(gd->present_prog);
|
||||||
|
pml = glGetUniformLocationChecked(gd->present_prog, "projection");
|
||||||
|
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, gd->back_texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_BGR,
|
||||||
|
GL_UNSIGNED_BYTE, NULL);
|
||||||
|
|
||||||
gl_check_err();
|
gl_check_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,8 +667,8 @@ static const char fill_vert[] = GLSL(330,
|
||||||
|
|
||||||
/// Fill a given region in bound framebuffer.
|
/// Fill a given region in bound framebuffer.
|
||||||
/// @param[in] y_inverted whether the y coordinates in `clip` should be inverted
|
/// @param[in] y_inverted whether the y coordinates in `clip` should be inverted
|
||||||
static void
|
static void _gl_fill(backend_t *base, struct color c, const region_t *clip, GLuint target,
|
||||||
_gl_fill(backend_t *base, struct color c, const region_t *clip, int height, bool y_inverted) {
|
int height, bool y_inverted) {
|
||||||
static const GLuint fill_vert_in_coord_loc = 0;
|
static const GLuint fill_vert_in_coord_loc = 0;
|
||||||
int nrects;
|
int nrects;
|
||||||
const rect_t *rect = pixman_region32_rectangles((region_t *)clip, &nrects);
|
const rect_t *rect = pixman_region32_rectangles((region_t *)clip, &nrects);
|
||||||
|
@ -695,7 +709,9 @@ _gl_fill(backend_t *base, struct color c, const region_t *clip, int height, bool
|
||||||
|
|
||||||
glVertexAttribPointer(fill_vert_in_coord_loc, 2, GL_INT, GL_FALSE,
|
glVertexAttribPointer(fill_vert_in_coord_loc, 2, GL_INT, GL_FALSE,
|
||||||
sizeof(*coord) * 2, (void *)0);
|
sizeof(*coord) * 2, (void *)0);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target);
|
||||||
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
|
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
glDisableVertexAttribArray(fill_vert_in_coord_loc);
|
glDisableVertexAttribArray(fill_vert_in_coord_loc);
|
||||||
|
@ -707,7 +723,7 @@ _gl_fill(backend_t *base, struct color c, const region_t *clip, int height, bool
|
||||||
|
|
||||||
void gl_fill(backend_t *base, struct color c, const region_t *clip) {
|
void gl_fill(backend_t *base, struct color c, const region_t *clip) {
|
||||||
struct gl_data *gd = (void *)base;
|
struct gl_data *gd = (void *)base;
|
||||||
return _gl_fill(base, c, clip, gd->height, true);
|
return _gl_fill(base, c, clip, gd->back_fbo, gd->height, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl_release_image(backend_t *base, void *image_data) {
|
void gl_release_image(backend_t *base, void *image_data) {
|
||||||
|
@ -870,6 +886,7 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method, void *arg
|
||||||
// Get uniform addresses
|
// Get uniform addresses
|
||||||
pass->unifm_opacity = glGetUniformLocationChecked(pass->prog, "opacity");
|
pass->unifm_opacity = glGetUniformLocationChecked(pass->prog, "opacity");
|
||||||
pass->orig_loc = glGetUniformLocationChecked(pass->prog, "orig");
|
pass->orig_loc = glGetUniformLocationChecked(pass->prog, "orig");
|
||||||
|
pass->texorig_loc = glGetUniformLocationChecked(pass->prog, "texorig");
|
||||||
ctx->resize_width += kern->w / 2;
|
ctx->resize_width += kern->w / 2;
|
||||||
ctx->resize_height += kern->h / 2;
|
ctx->resize_height += kern->h / 2;
|
||||||
}
|
}
|
||||||
|
@ -881,6 +898,7 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method, void *arg
|
||||||
pass->prog = gl_create_program_from_str(vertex_shader, dummy_frag);
|
pass->prog = gl_create_program_from_str(vertex_shader, dummy_frag);
|
||||||
pass->unifm_opacity = glGetUniformLocationChecked(pass->prog, "opacity");
|
pass->unifm_opacity = glGetUniformLocationChecked(pass->prog, "opacity");
|
||||||
pass->orig_loc = glGetUniformLocationChecked(pass->prog, "orig");
|
pass->orig_loc = glGetUniformLocationChecked(pass->prog, "orig");
|
||||||
|
pass->texorig_loc = glGetUniformLocationChecked(pass->prog, "texorig");
|
||||||
ctx->npasses = 2;
|
ctx->npasses = 2;
|
||||||
} else {
|
} else {
|
||||||
ctx->npasses = nkernels;
|
ctx->npasses = nkernels;
|
||||||
|
@ -948,6 +966,16 @@ const char *win_shader_glsl = GLSL(330,
|
||||||
gl_FragColor = c;
|
gl_FragColor = c;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const char *present_vertex_shader = GLSL(330,
|
||||||
|
uniform mat4 projection;
|
||||||
|
layout(location = 0) in vec2 coord;
|
||||||
|
out vec2 texcoord;
|
||||||
|
void main() {
|
||||||
|
gl_Position = projection * vec4(coord, 0, 1);
|
||||||
|
texcoord = coord;
|
||||||
|
}
|
||||||
|
);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
bool gl_init(struct gl_data *gd, session_t *ps) {
|
bool gl_init(struct gl_data *gd, session_t *ps) {
|
||||||
|
@ -969,14 +997,41 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
glGenFramebuffers(1, &gd->back_fbo);
|
||||||
|
glGenTextures(1, &gd->back_texture);
|
||||||
|
if (!gd->back_fbo || !gd->back_texture) {
|
||||||
|
log_error("Failed to generate a framebuffer object");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, gd->back_texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
gl_win_shader_from_string(vertex_shader, win_shader_glsl, &gd->win_shader);
|
gl_win_shader_from_string(vertex_shader, win_shader_glsl, &gd->win_shader);
|
||||||
gd->fill_shader.prog = gl_create_program_from_str(fill_vert, fill_frag);
|
gd->fill_shader.prog = gl_create_program_from_str(fill_vert, fill_frag);
|
||||||
gd->fill_shader.color_loc = glGetUniformLocation(gd->fill_shader.prog, "color");
|
gd->fill_shader.color_loc = glGetUniformLocation(gd->fill_shader.prog, "color");
|
||||||
|
|
||||||
|
gd->present_prog = gl_create_program_from_str(present_vertex_shader, dummy_frag);
|
||||||
|
if (!gd->present_prog) {
|
||||||
|
log_error("Failed to create the present shader");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glUseProgram(gd->present_prog);
|
||||||
|
glUniform1i(glGetUniformLocationChecked(gd->present_prog, "tex"), 0);
|
||||||
|
glUseProgram(0);
|
||||||
|
|
||||||
// Set up the size of the viewport. We do this last because it expects the blur
|
// Set up the size of the viewport. We do this last because it expects the blur
|
||||||
// textures are already set up.
|
// textures are already set up.
|
||||||
gl_resize(gd, ps->root_width, ps->root_height);
|
gl_resize(gd, ps->root_width, ps->root_height);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gd->back_fbo);
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||||
|
gd->back_texture, 0);
|
||||||
|
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
gd->logger = gl_string_marker_logger_new();
|
gd->logger = gl_string_marker_logger_new();
|
||||||
if (gd->logger) {
|
if (gd->logger) {
|
||||||
log_add_target_tls(gd->logger);
|
log_add_target_tls(gd->logger);
|
||||||
|
@ -1098,12 +1153,64 @@ static void gl_image_apply_alpha(backend_t *base, struct gl_image *img,
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||||
img->inner->texture, 0);
|
img->inner->texture, 0);
|
||||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||||
_gl_fill(base, (struct color){0, 0, 0, 0}, reg_op, 0, false);
|
_gl_fill(base, (struct color){0, 0, 0, 0}, reg_op, 0, 0, false);
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
glDeleteFramebuffers(1, &fbo);
|
glDeleteFramebuffers(1, &fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gl_present(backend_t *base, const region_t *region) {
|
||||||
|
auto gd = (struct gl_data *)base;
|
||||||
|
|
||||||
|
int nrects;
|
||||||
|
const rect_t *rect = pixman_region32_rectangles((region_t *)region, &nrects);
|
||||||
|
auto coord = ccalloc(nrects * 8, GLint);
|
||||||
|
auto indices = ccalloc(nrects * 6, GLuint);
|
||||||
|
for (int i = 0; i < nrects; i++) {
|
||||||
|
// clang-format off
|
||||||
|
memcpy(&coord[i * 8],
|
||||||
|
(GLint[]){rect[i].x1, gd->height - rect[i].y2,
|
||||||
|
rect[i].x2, gd->height - rect[i].y2,
|
||||||
|
rect[i].x2, gd->height - rect[i].y1,
|
||||||
|
rect[i].x1, gd->height - rect[i].y1},
|
||||||
|
sizeof(GLint) * 8);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
GLuint u = (GLuint)(i * 4);
|
||||||
|
memcpy(&indices[i * 6], (GLuint[]){u + 0, u + 1, u + 2, u + 2, u + 3, u + 0},
|
||||||
|
sizeof(GLuint) * 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
glUseProgram(gd->present_prog);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, gd->back_texture);
|
||||||
|
|
||||||
|
GLuint vao;
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
GLuint bo[2];
|
||||||
|
glGenBuffers(2, bo);
|
||||||
|
glEnableVertexAttribArray(vert_coord_loc);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, bo[0]);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo[1]);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, (long)sizeof(GLint) * nrects * 8, coord, GL_STREAM_DRAW);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(GLuint) * nrects * 6, indices,
|
||||||
|
GL_STREAM_DRAW);
|
||||||
|
|
||||||
|
glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE,
|
||||||
|
sizeof(GLint) * 2, NULL);
|
||||||
|
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glDeleteBuffers(2, bo);
|
||||||
|
glDeleteVertexArrays(1, &vao);
|
||||||
|
|
||||||
|
free(coord);
|
||||||
|
free(indices);
|
||||||
|
}
|
||||||
|
|
||||||
/// stub for backend_operations::image_op
|
/// stub for backend_operations::image_op
|
||||||
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 attr_unused, void *arg) {
|
const region_t *reg_op, const region_t *reg_visible attr_unused, void *arg) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ typedef struct {
|
||||||
GLuint prog;
|
GLuint prog;
|
||||||
GLint unifm_opacity;
|
GLint unifm_opacity;
|
||||||
GLint orig_loc;
|
GLint orig_loc;
|
||||||
|
GLint texorig_loc;
|
||||||
} gl_blur_shader_t;
|
} gl_blur_shader_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -61,6 +62,8 @@ struct gl_data {
|
||||||
int height, width;
|
int height, width;
|
||||||
gl_win_shader_t win_shader;
|
gl_win_shader_t win_shader;
|
||||||
gl_fill_shader_t fill_shader;
|
gl_fill_shader_t fill_shader;
|
||||||
|
GLuint back_texture, back_fbo;
|
||||||
|
GLuint present_prog;
|
||||||
|
|
||||||
/// Called when an gl_texture is decoupled from the texture it refers. Returns
|
/// Called when an gl_texture is decoupled from the texture it refers. Returns
|
||||||
/// the decoupled user_data
|
/// the decoupled user_data
|
||||||
|
@ -110,6 +113,8 @@ void gl_get_blur_size(void *blur_context, int *width, int *height);
|
||||||
bool gl_is_image_transparent(backend_t *base, void *image_data);
|
bool gl_is_image_transparent(backend_t *base, void *image_data);
|
||||||
void gl_fill(backend_t *base, struct color, const region_t *clip);
|
void gl_fill(backend_t *base, struct color, const region_t *clip);
|
||||||
|
|
||||||
|
void gl_present(backend_t *base, const region_t *);
|
||||||
|
|
||||||
static inline void gl_delete_texture(GLuint texture) {
|
static inline void gl_delete_texture(GLuint texture) {
|
||||||
glDeleteTextures(1, &texture);
|
glDeleteTextures(1, &texture);
|
||||||
}
|
}
|
||||||
|
|
|
@ -436,8 +436,9 @@ err:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void glx_present(backend_t *base) {
|
static void glx_present(backend_t *base, const region_t *region attr_unused) {
|
||||||
struct _glx_data *gd = (void *)base;
|
struct _glx_data *gd = (void *)base;
|
||||||
|
gl_present(base, region);
|
||||||
glXSwapBuffers(gd->display, gd->target_win);
|
glXSwapBuffers(gd->display, gd->target_win);
|
||||||
// XXX there should be no need to block compton will wait for render to finish
|
// XXX there should be no need to block compton will wait for render to finish
|
||||||
if (!gd->gl.is_nvidia) {
|
if (!gd->gl.is_nvidia) {
|
||||||
|
|
|
@ -28,15 +28,14 @@ typedef struct _xrender_data {
|
||||||
/// If vsync is enabled and supported by the current system
|
/// If vsync is enabled and supported by the current system
|
||||||
bool vsync;
|
bool vsync;
|
||||||
xcb_visualid_t default_visual;
|
xcb_visualid_t default_visual;
|
||||||
/// The idle fence for the present extension
|
/// Target window
|
||||||
xcb_sync_fence_t idle_fence;
|
|
||||||
/// The target window
|
|
||||||
xcb_window_t target_win;
|
xcb_window_t target_win;
|
||||||
/// The painting target, it is either the root or the overlay
|
/// Painting target, it is either the root or the overlay
|
||||||
xcb_render_picture_t target;
|
xcb_render_picture_t target;
|
||||||
/// A back buffer
|
/// Back buffers. Double buffer, with 1 for temporary render use
|
||||||
xcb_render_picture_t back[2];
|
xcb_render_picture_t back[3];
|
||||||
/// Age of each back buffer
|
/// The back buffer that is for temporary use
|
||||||
|
/// Age of each back buffer.
|
||||||
int buffer_age[2];
|
int buffer_age[2];
|
||||||
/// The back buffer we should be painting into
|
/// The back buffer we should be painting into
|
||||||
int curr_back;
|
int curr_back;
|
||||||
|
@ -104,9 +103,9 @@ static void compose(backend_t *base, void *img_data, int dst_x, int dst_y,
|
||||||
// sure we get everything into the buffer
|
// sure we get everything into the buffer
|
||||||
x_clear_picture_clip_region(base->c, img->pict);
|
x_clear_picture_clip_region(base->c, img->pict);
|
||||||
|
|
||||||
x_set_picture_clip_region(base->c, xd->back[xd->curr_back], 0, 0, ®);
|
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, ®);
|
||||||
xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[xd->curr_back],
|
xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[2], 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, to_i16_checked(dst_x), to_i16_checked(dst_y),
|
to_i16_checked(dst_x), to_i16_checked(dst_y),
|
||||||
to_u16_checked(img->ewidth), to_u16_checked(img->eheight));
|
to_u16_checked(img->ewidth), to_u16_checked(img->eheight));
|
||||||
pixman_region32_fini(®);
|
pixman_region32_fini(®);
|
||||||
}
|
}
|
||||||
|
@ -114,10 +113,10 @@ static void compose(backend_t *base, void *img_data, int dst_x, int dst_y,
|
||||||
static void fill(backend_t *base, struct color c, const region_t *clip) {
|
static void fill(backend_t *base, struct color c, const region_t *clip) {
|
||||||
struct _xrender_data *xd = (void *)base;
|
struct _xrender_data *xd = (void *)base;
|
||||||
const rect_t *extent = pixman_region32_extents((region_t *)clip);
|
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);
|
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, clip);
|
||||||
// color is in X fixed point representation
|
// color is in X fixed point representation
|
||||||
xcb_render_fill_rectangles(
|
xcb_render_fill_rectangles(
|
||||||
base->c, XCB_RENDER_PICT_OP_OVER, xd->back[xd->curr_back],
|
base->c, XCB_RENDER_PICT_OP_OVER, xd->back[2],
|
||||||
(xcb_render_color_t){.red = (uint16_t)(c.red * 0xffff),
|
(xcb_render_color_t){.red = (uint16_t)(c.red * 0xffff),
|
||||||
.green = (uint16_t)(c.green * 0xffff),
|
.green = (uint16_t)(c.green * 0xffff),
|
||||||
.blue = (uint16_t)(c.blue * 0xffff),
|
.blue = (uint16_t)(c.blue * 0xffff),
|
||||||
|
@ -177,7 +176,7 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
|
||||||
x_set_picture_clip_region(c, tmp_picture[1], 0, 0, &clip);
|
x_set_picture_clip_region(c, tmp_picture[1], 0, 0, &clip);
|
||||||
pixman_region32_fini(&clip);
|
pixman_region32_fini(&clip);
|
||||||
|
|
||||||
xcb_render_picture_t src_pict = xd->back[xd->curr_back], dst_pict = tmp_picture[0];
|
xcb_render_picture_t src_pict = xd->back[2], dst_pict = tmp_picture[0];
|
||||||
auto alpha_pict = xd->alpha_pict[(int)(opacity * MAX_ALPHA)];
|
auto alpha_pict = xd->alpha_pict[(int)(opacity * MAX_ALPHA)];
|
||||||
int current = 0;
|
int current = 0;
|
||||||
x_set_picture_clip_region(c, src_pict, 0, 0, ®_op_resized);
|
x_set_picture_clip_region(c, src_pict, 0, 0, ®_op_resized);
|
||||||
|
@ -212,11 +211,11 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
|
||||||
XCB_NONE, dst_pict, 0, 0, 0, 0, 0, 0,
|
XCB_NONE, dst_pict, 0, 0, 0, 0, 0, 0,
|
||||||
width_resized, height_resized);
|
width_resized, height_resized);
|
||||||
} else {
|
} else {
|
||||||
x_set_picture_clip_region(c, xd->back[xd->curr_back], 0, 0, ®_op);
|
x_set_picture_clip_region(c, xd->back[2], 0, 0, ®_op);
|
||||||
// This is the last pass, and we are doing more than 1 pass
|
// This is the last pass, and we are doing more than 1 pass
|
||||||
xcb_render_composite(c, XCB_RENDER_PICT_OP_OVER, src_pict,
|
xcb_render_composite(c, XCB_RENDER_PICT_OP_OVER, src_pict,
|
||||||
alpha_pict, xd->back[xd->curr_back], 0, 0, 0,
|
alpha_pict, xd->back[2], 0, 0, 0, 0,
|
||||||
0, to_i16_checked(extent_resized->x1),
|
to_i16_checked(extent_resized->x1),
|
||||||
to_i16_checked(extent_resized->y1),
|
to_i16_checked(extent_resized->y1),
|
||||||
width_resized, height_resized);
|
width_resized, height_resized);
|
||||||
}
|
}
|
||||||
|
@ -232,10 +231,10 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
|
||||||
|
|
||||||
// There is only 1 pass
|
// There is only 1 pass
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
x_set_picture_clip_region(c, xd->back[xd->curr_back], 0, 0, ®_op);
|
x_set_picture_clip_region(c, xd->back[2], 0, 0, ®_op);
|
||||||
xcb_render_composite(
|
xcb_render_composite(
|
||||||
c, XCB_RENDER_PICT_OP_OVER, src_pict, alpha_pict,
|
c, XCB_RENDER_PICT_OP_OVER, src_pict, alpha_pict, xd->back[2], 0, 0,
|
||||||
xd->back[xd->curr_back], 0, 0, 0, 0, to_i16_checked(extent_resized->x1),
|
0, 0, to_i16_checked(extent_resized->x1),
|
||||||
to_i16_checked(extent_resized->y1), width_resized, height_resized);
|
to_i16_checked(extent_resized->y1), width_resized, height_resized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,10 +300,25 @@ static void deinit(backend_t *backend_data) {
|
||||||
free(xd);
|
free(xd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void present(backend_t *base) {
|
static void present(backend_t *base, const region_t *region) {
|
||||||
struct _xrender_data *xd = (void *)base;
|
struct _xrender_data *xd = (void *)base;
|
||||||
|
const rect_t *extent = pixman_region32_extents((region_t *)region);
|
||||||
|
int16_t orig_x = to_i16_checked(extent->x1), orig_y = to_i16_checked(extent->y1);
|
||||||
|
uint16_t region_width = to_u16_checked(extent->x2 - extent->x1),
|
||||||
|
region_height = to_u16_checked(extent->y2 - extent->y1);
|
||||||
|
|
||||||
|
// compose() sets clip region on the back buffer, so clear it first
|
||||||
|
x_clear_picture_clip_region(base->c, xd->back[xd->curr_back]);
|
||||||
|
|
||||||
|
// limit the region of update
|
||||||
|
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, region);
|
||||||
|
|
||||||
if (xd->vsync) {
|
if (xd->vsync) {
|
||||||
|
// Update the back buffer first, then present
|
||||||
|
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC, xd->back[2],
|
||||||
|
XCB_NONE, xd->back[xd->curr_back], orig_x, orig_y, 0,
|
||||||
|
0, orig_x, orig_y, region_width, region_height);
|
||||||
|
|
||||||
// Make sure we got reply from PresentPixmap before waiting for events,
|
// Make sure we got reply from PresentPixmap before waiting for events,
|
||||||
// to avoid deadlock
|
// to avoid deadlock
|
||||||
auto e = xcb_request_check(
|
auto e = xcb_request_check(
|
||||||
|
@ -342,16 +356,13 @@ static void present(backend_t *base) {
|
||||||
}
|
}
|
||||||
free(pev);
|
free(pev);
|
||||||
} else {
|
} else {
|
||||||
// compose() sets clip region, so clear it first to make
|
// No vsync needed, draw into the target picture directly
|
||||||
// sure we update the whole screen.
|
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC, xd->back[2],
|
||||||
x_clear_picture_clip_region(xd->base.c, xd->back[xd->curr_back]);
|
XCB_NONE, xd->target, orig_x, orig_y, 0, 0, orig_x,
|
||||||
|
orig_y, region_width, region_height);
|
||||||
|
|
||||||
// TODO buffer-age-like optimization might be possible here.
|
// Only the target picture really holds the screen content, and its
|
||||||
// but that will require a different backend API
|
// content is always up to date. So buffer age is always 1.
|
||||||
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC,
|
|
||||||
xd->back[xd->curr_back], XCB_NONE, xd->target, 0, 0,
|
|
||||||
0, 0, 0, 0, to_u16_checked(xd->target_width),
|
|
||||||
to_u16_checked(xd->target_height));
|
|
||||||
xd->buffer_age[xd->curr_back] = 1;
|
xd->buffer_age[xd->curr_back] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -589,9 +600,10 @@ backend_t *backend_xrender_init(session_t *ps) {
|
||||||
xd->vsync = false;
|
xd->vsync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We might need to do double buffering for vsync
|
// We might need to do double buffering for vsync, and buffer 0 and 1 are for
|
||||||
int pixmap_needed = xd->vsync ? 2 : 1;
|
// double buffering.
|
||||||
for (int i = 0; i < pixmap_needed; i++) {
|
int first_buffer_index = xd->vsync ? 0 : 2;
|
||||||
|
for (int i = first_buffer_index; i < 3; i++) {
|
||||||
xd->back_pixmap[i] = x_create_pixmap(ps->c, pictfmt->depth, ps->root,
|
xd->back_pixmap[i] = x_create_pixmap(ps->c, pictfmt->depth, ps->root,
|
||||||
to_u16_checked(ps->root_width),
|
to_u16_checked(ps->root_width),
|
||||||
to_u16_checked(ps->root_height));
|
to_u16_checked(ps->root_height));
|
||||||
|
|
|
@ -575,6 +575,11 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
|
||||||
}
|
}
|
||||||
|
|
||||||
w->prev_trans = bottom;
|
w->prev_trans = bottom;
|
||||||
|
if (bottom) {
|
||||||
|
w->stacking_rank = bottom->stacking_rank + 1;
|
||||||
|
} else {
|
||||||
|
w->stacking_rank = 0;
|
||||||
|
}
|
||||||
bottom = w;
|
bottom = w;
|
||||||
|
|
||||||
// If the screen is not redirected and the window has redir_ignore set,
|
// If the screen is not redirected and the window has redir_ignore set,
|
||||||
|
|
|
@ -169,6 +169,8 @@ struct managed_win {
|
||||||
void *shadow_image;
|
void *shadow_image;
|
||||||
/// Pointer to the next higher window to paint.
|
/// Pointer to the next higher window to paint.
|
||||||
struct managed_win *prev_trans;
|
struct managed_win *prev_trans;
|
||||||
|
/// Number of windows above this window
|
||||||
|
int stacking_rank;
|
||||||
// TODO rethink reg_ignore
|
// TODO rethink reg_ignore
|
||||||
|
|
||||||
// Core members
|
// Core members
|
||||||
|
|
Loading…
Reference in New Issue