Convert XfixesRegion to pixman region
Re-did the painting logic, and document it. It is unclear to me what is the previous painting logic. But the current one is basically this: 1. Go through all windows top to bottom, and put visible windows (not unmapped, opacity > 0, etc) into a linked list, from bottom to top 2. Accumulate a region of ignore on each window, which is basically the region of screen that is obscured by all the windows above current one. 3. Paint all the visible windows from bottom to top. Subtract the region of ignore from the painting region. If we need to paint shadow, we subtract the body of the window from the shadow painting region too, because we don't want shadow behind the window. 4. region of ignore is invalidated when window stack change, an window on top moved or changed shape, when window changed between opaque and transparent, etc. Notes: It is unclear whether all the different shapes of a window (extents, noframe, border, bounding shape, etc) are calculated correctly or not. It is unclear if window shape related events are handled correctly or not. Need more testing. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
296
src/opengl.c
296
src/opengl.c
@ -900,7 +900,7 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
|
||||
* Preprocess function before start painting.
|
||||
*/
|
||||
void
|
||||
glx_paint_pre(session_t *ps, XserverRegion *preg) {
|
||||
glx_paint_pre(session_t *ps, region_t *preg) {
|
||||
ps->psglx->z = 0.0;
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
@ -908,107 +908,46 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) {
|
||||
bool trace_damage = (ps->o.glx_swap_method < 0 || ps->o.glx_swap_method > 1);
|
||||
|
||||
// Trace raw damage regions
|
||||
XserverRegion newdamage = None;
|
||||
if (trace_damage && *preg)
|
||||
newdamage = copy_region(ps, *preg);
|
||||
region_t newdamage;
|
||||
pixman_region32_init(&newdamage);
|
||||
if (trace_damage)
|
||||
copy_region(&newdamage, preg);
|
||||
|
||||
// OpenGL doesn't support partial repaint without GLX_MESA_copy_sub_buffer,
|
||||
// we could redraw the whole screen or copy unmodified pixels from
|
||||
// front buffer with --glx-copy-from-front.
|
||||
if (ps->o.glx_use_copysubbuffermesa || !*preg) {
|
||||
// We use GLX buffer_age extension to decide which pixels in
|
||||
// the back buffer is reusable, and limit our redrawing
|
||||
int buffer_age = 0;
|
||||
|
||||
// Query GLX_EXT_buffer_age for buffer age
|
||||
if (ps->o.glx_swap_method == SWAPM_BUFFER_AGE) {
|
||||
unsigned val = 0;
|
||||
glXQueryDrawable(ps->dpy, get_tgt_window(ps),
|
||||
GLX_BACK_BUFFER_AGE_EXT, &val);
|
||||
buffer_age = val;
|
||||
}
|
||||
else {
|
||||
int buffer_age = ps->o.glx_swap_method;
|
||||
|
||||
// Getting buffer age
|
||||
{
|
||||
// Query GLX_EXT_buffer_age for buffer age
|
||||
if (SWAPM_BUFFER_AGE == buffer_age) {
|
||||
unsigned val = 0;
|
||||
glXQueryDrawable(ps->dpy, get_tgt_window(ps),
|
||||
GLX_BACK_BUFFER_AGE_EXT, &val);
|
||||
buffer_age = val;
|
||||
}
|
||||
// Buffer age too high
|
||||
if (buffer_age > CGLX_MAX_BUFFER_AGE + 1)
|
||||
buffer_age = 0;
|
||||
|
||||
// Buffer age too high
|
||||
if (buffer_age > CGLX_MAX_BUFFER_AGE + 1)
|
||||
buffer_age = 0;
|
||||
assert(buffer_age >= 0);
|
||||
|
||||
// Make sure buffer age >= 0
|
||||
buffer_age = max_i(buffer_age, 0);
|
||||
|
||||
// Check if we have we have empty regions
|
||||
if (buffer_age > 1) {
|
||||
for (int i = 0; i < buffer_age - 1; ++i)
|
||||
if (!ps->all_damage_last[i]) { buffer_age = 0; break; }
|
||||
}
|
||||
}
|
||||
|
||||
// Do nothing for buffer_age 1 (copy)
|
||||
if (1 != buffer_age) {
|
||||
// Copy pixels
|
||||
if (ps->o.glx_copy_from_front) {
|
||||
// Determine copy area
|
||||
XserverRegion reg_copy = XFixesCreateRegion(ps->dpy, NULL, 0);
|
||||
if (!buffer_age) {
|
||||
XFixesSubtractRegion(ps->dpy, reg_copy, ps->screen_reg, *preg);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < buffer_age - 1; ++i)
|
||||
XFixesUnionRegion(ps->dpy, reg_copy, reg_copy,
|
||||
ps->all_damage_last[i]);
|
||||
XFixesSubtractRegion(ps->dpy, reg_copy, reg_copy, *preg);
|
||||
}
|
||||
|
||||
// Actually copy pixels
|
||||
{
|
||||
GLfloat raster_pos[4];
|
||||
GLfloat curx = 0.0f, cury = 0.0f;
|
||||
glGetFloatv(GL_CURRENT_RASTER_POSITION, raster_pos);
|
||||
glReadBuffer(GL_FRONT);
|
||||
glRasterPos2f(0.0, 0.0);
|
||||
{
|
||||
int nrects = 0;
|
||||
XRectangle *rects = XFixesFetchRegion(ps->dpy, reg_copy, &nrects);
|
||||
for (int i = 0; i < nrects; ++i) {
|
||||
const int x = rects[i].x;
|
||||
const int y = ps->root_height - rects[i].y - rects[i].height;
|
||||
// Kwin patch says glRasterPos2f() causes artifacts on bottom
|
||||
// screen edge with some drivers
|
||||
glBitmap(0, 0, 0, 0, x - curx, y - cury, NULL);
|
||||
curx = x;
|
||||
cury = y;
|
||||
glCopyPixels(x, y, rects[i].width, rects[i].height, GL_COLOR);
|
||||
}
|
||||
cxfree(rects);
|
||||
}
|
||||
glReadBuffer(GL_BACK);
|
||||
glRasterPos4fv(raster_pos);
|
||||
}
|
||||
|
||||
free_region(ps, ®_copy);
|
||||
}
|
||||
|
||||
// Determine paint area
|
||||
if (ps->o.glx_copy_from_front) { }
|
||||
else if (buffer_age) {
|
||||
for (int i = 0; i < buffer_age - 1; ++i)
|
||||
XFixesUnionRegion(ps->dpy, *preg, *preg, ps->all_damage_last[i]);
|
||||
}
|
||||
else {
|
||||
free_region(ps, preg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buffer_age) {
|
||||
// Determine paint area
|
||||
for (int i = 0; i < buffer_age - 1; ++i)
|
||||
pixman_region32_union(preg, preg, &ps->all_damage_last[i]);
|
||||
} else
|
||||
// buffer_age == 0 means buffer age is not available, paint everything
|
||||
copy_region(preg, &ps->screen_reg);
|
||||
|
||||
if (trace_damage) {
|
||||
free_region(ps, &ps->all_damage_last[CGLX_MAX_BUFFER_AGE - 1]);
|
||||
// XXX use a circular queue instead of memmove
|
||||
pixman_region32_fini(&ps->all_damage_last[CGLX_MAX_BUFFER_AGE - 1]);
|
||||
memmove(ps->all_damage_last + 1, ps->all_damage_last,
|
||||
(CGLX_MAX_BUFFER_AGE - 1) * sizeof(XserverRegion));
|
||||
(CGLX_MAX_BUFFER_AGE - 1) * sizeof(region_t *));
|
||||
ps->all_damage_last[0] = newdamage;
|
||||
}
|
||||
|
||||
glx_set_clip(ps, *preg, NULL);
|
||||
glx_set_clip(ps, preg);
|
||||
|
||||
#ifdef DEBUG_GLX_PAINTREG
|
||||
glx_render_color(ps, 0, 0, ps->root_width, ps->root_height, 0, *preg, NULL);
|
||||
@ -1021,118 +960,46 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) {
|
||||
* Set clipping region on the target window.
|
||||
*/
|
||||
void
|
||||
glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg) {
|
||||
glx_set_clip(session_t *ps, const region_t *reg) {
|
||||
// Quit if we aren't using stencils
|
||||
if (ps->o.glx_no_stencil)
|
||||
return;
|
||||
|
||||
static XRectangle rect_blank = { .x = 0, .y = 0, .width = 0, .height = 0 };
|
||||
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
int nrects = 0;
|
||||
XRectangle *rects_free = NULL;
|
||||
const XRectangle *rects = NULL;
|
||||
if (pcache_reg) {
|
||||
rects = pcache_reg->rects;
|
||||
nrects = pcache_reg->nrects;
|
||||
}
|
||||
if (!rects) {
|
||||
nrects = 0;
|
||||
rects = rects_free = XFixesFetchRegion(ps->dpy, reg, &nrects);
|
||||
}
|
||||
// Use one empty rectangle if the region is empty
|
||||
if (!nrects) {
|
||||
cxfree(rects_free);
|
||||
rects_free = NULL;
|
||||
nrects = 1;
|
||||
rects = &rect_blank;
|
||||
}
|
||||
int nrects;
|
||||
const rect_t *rects = pixman_region32_rectangles((region_t *)reg, &nrects);
|
||||
|
||||
assert(nrects);
|
||||
if (1 == nrects) {
|
||||
if (nrects == 1) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(rects[0].x, ps->root_height - rects[0].y - rects[0].height,
|
||||
rects[0].width, rects[0].height);
|
||||
glScissor(rects[0].x1, ps->root_height-rects[0].y2,
|
||||
rects[0].x2-rects[0].x1, rects[0].y2-rects[0].y1);
|
||||
}
|
||||
else {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
glDepthMask(GL_FALSE);
|
||||
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for (int i = 0; i < nrects; ++i) {
|
||||
GLint rx = rects[i].x;
|
||||
GLint ry = ps->root_height - rects[i].y;
|
||||
GLint rxe = rx + rects[i].width;
|
||||
GLint rye = ry - rects[i].height;
|
||||
GLint z = 0;
|
||||
|
||||
#ifdef DEBUG_GLX
|
||||
printf_dbgf("(): Rect %d: %d, %d, %d, %d\n", i, rx, ry, rxe, rye);
|
||||
#endif
|
||||
|
||||
glVertex3i(rx, ry, z);
|
||||
glVertex3i(rxe, ry, z);
|
||||
glVertex3i(rxe, rye, z);
|
||||
glVertex3i(rx, rye, z);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
// glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
cxfree(rects_free);
|
||||
|
||||
glx_check_err(ps);
|
||||
}
|
||||
|
||||
#define P_PAINTREG_START() \
|
||||
XserverRegion reg_new = None; \
|
||||
XRectangle rec_all = { .x = dx, .y = dy, .width = width, .height = height }; \
|
||||
XRectangle *rects = &rec_all; \
|
||||
int nrects = 1; \
|
||||
\
|
||||
if (ps->o.glx_no_stencil && reg_tgt) { \
|
||||
if (pcache_reg) { \
|
||||
rects = pcache_reg->rects; \
|
||||
nrects = pcache_reg->nrects; \
|
||||
} \
|
||||
else { \
|
||||
reg_new = XFixesCreateRegion(ps->dpy, &rec_all, 1); \
|
||||
XFixesIntersectRegion(ps->dpy, reg_new, reg_new, reg_tgt); \
|
||||
\
|
||||
nrects = 0; \
|
||||
rects = XFixesFetchRegion(ps->dpy, reg_new, &nrects); \
|
||||
} \
|
||||
} \
|
||||
#define P_PAINTREG_START(var) \
|
||||
region_t reg_new; \
|
||||
int nrects; \
|
||||
const rect_t *rects; \
|
||||
pixman_region32_init_rect(®_new, dx, dy, width, height); \
|
||||
pixman_region32_intersect(®_new, ®_new, (region_t *)reg_tgt); \
|
||||
rects = pixman_region32_rectangles(®_new, &nrects); \
|
||||
glBegin(GL_QUADS); \
|
||||
\
|
||||
for (int ri = 0; ri < nrects; ++ri) { \
|
||||
XRectangle crect; \
|
||||
rect_crop(&crect, &rects[ri], &rec_all); \
|
||||
\
|
||||
if (!crect.width || !crect.height) \
|
||||
continue; \
|
||||
rect_t var = rects[ri];
|
||||
|
||||
#define P_PAINTREG_END() \
|
||||
} \
|
||||
glEnd(); \
|
||||
\
|
||||
if (rects && rects != &rec_all && !(pcache_reg && pcache_reg->rects == rects)) \
|
||||
cxfree(rects); \
|
||||
free_region(ps, ®_new); \
|
||||
pixman_region32_fini(®_new);
|
||||
|
||||
static inline GLuint
|
||||
glx_gen_texture(session_t *ps, GLenum tex_tgt, int width, int height) {
|
||||
@ -1162,11 +1029,13 @@ glx_copy_region_to_tex(session_t *ps, GLenum tex_tgt, int basex, int basey,
|
||||
|
||||
/**
|
||||
* Blur contents in a particular region.
|
||||
*
|
||||
* XXX seems to be way to complex for what it does
|
||||
*/
|
||||
bool
|
||||
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||
GLfloat factor_center,
|
||||
XserverRegion reg_tgt, const reg_data_t *pcache_reg,
|
||||
const region_t *reg_tgt,
|
||||
glx_blur_cache_t *pbc) {
|
||||
assert(ps->psglx->blur_passes[0].prog);
|
||||
const bool more_passes = ps->psglx->blur_passes[1].prog;
|
||||
@ -1310,23 +1179,19 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||
glUniform1f(ppass->unifm_factor_center, factor_center);
|
||||
|
||||
{
|
||||
P_PAINTREG_START();
|
||||
{
|
||||
const GLfloat rx = (crect.x - mdx) * texfac_x;
|
||||
const GLfloat ry = (mheight - (crect.y - mdy)) * texfac_y;
|
||||
const GLfloat rxe = rx + crect.width * texfac_x;
|
||||
const GLfloat rye = ry - crect.height * texfac_y;
|
||||
GLfloat rdx = crect.x - mdx;
|
||||
GLfloat rdy = mheight - crect.y + mdy;
|
||||
GLfloat rdxe = rdx + crect.width;
|
||||
GLfloat rdye = rdy - crect.height;
|
||||
|
||||
P_PAINTREG_START(crect) {
|
||||
const GLfloat rx = (crect.x1 - mdx) * texfac_x;
|
||||
const GLfloat ry = (mheight - (crect.y1 - mdy)) * texfac_y;
|
||||
const GLfloat rxe = rx + (crect.x2 - crect.x1) * texfac_x;
|
||||
const GLfloat rye = ry - (crect.y2 - crect.y1) * texfac_y;
|
||||
GLfloat rdx = crect.x1 - mdx;
|
||||
GLfloat rdy = mheight - crect.y1 + mdy;
|
||||
if (last_pass) {
|
||||
rdx = crect.x;
|
||||
rdy = ps->root_height - crect.y;
|
||||
rdxe = rdx + crect.width;
|
||||
rdye = rdy - crect.height;
|
||||
rdx = crect.x1;
|
||||
rdy = ps->root_height - crect.y1;
|
||||
}
|
||||
GLfloat rdxe = rdx + (crect.x2 - crect.x1);
|
||||
GLfloat rdye = rdy - (crect.y2 - crect.y1);
|
||||
|
||||
#ifdef DEBUG_GLX
|
||||
printf_dbgf("(): %f, %f, %f, %f -> %f, %f, %f, %f\n", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
|
||||
@ -1343,8 +1208,7 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||
|
||||
glTexCoord2f(rx, rye);
|
||||
glVertex3f(rdx, rdye, z);
|
||||
}
|
||||
P_PAINTREG_END();
|
||||
} P_PAINTREG_END();
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
@ -1379,7 +1243,7 @@ glx_blur_dst_end:
|
||||
|
||||
bool
|
||||
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||
GLfloat factor, XserverRegion reg_tgt, const reg_data_t *pcache_reg) {
|
||||
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);
|
||||
@ -1387,12 +1251,12 @@ glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||
glColor4f(0.0f, 0.0f, 0.0f, factor);
|
||||
|
||||
{
|
||||
P_PAINTREG_START();
|
||||
{
|
||||
GLint rdx = crect.x;
|
||||
GLint rdy = ps->root_height - crect.y;
|
||||
GLint rdxe = rdx + crect.width;
|
||||
GLint rdye = rdy - crect.height;
|
||||
P_PAINTREG_START(crect) {
|
||||
// XXX what does all of these variables mean?
|
||||
GLint rdx = crect.x1;
|
||||
GLint rdy = ps->root_height - crect.y1;
|
||||
GLint rdxe = rdx + (crect.x2 - crect.x1);
|
||||
GLint rdye = rdy - (crect.y2 - crect.y1);
|
||||
|
||||
glVertex3i(rdx, rdy, z);
|
||||
glVertex3i(rdxe, rdy, z);
|
||||
@ -1419,8 +1283,7 @@ bool
|
||||
glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||
int x, int y, int dx, int dy, int width, int height, int z,
|
||||
double opacity, bool argb, bool neg,
|
||||
XserverRegion reg_tgt, const reg_data_t *pcache_reg
|
||||
, const glx_prog_main_t *pprogram
|
||||
const region_t *reg_tgt, const glx_prog_main_t *pprogram
|
||||
) {
|
||||
if (!ptex || !ptex->texture) {
|
||||
printf_errf("(): Missing texture.");
|
||||
@ -1551,12 +1414,12 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||
|
||||
// Painting
|
||||
{
|
||||
P_PAINTREG_START();
|
||||
{
|
||||
GLfloat rx = (double) (crect.x - dx + x);
|
||||
GLfloat ry = (double) (crect.y - dy + y);
|
||||
GLfloat rxe = rx + (double) crect.width;
|
||||
GLfloat rye = ry + (double) crect.height;
|
||||
P_PAINTREG_START(crect) {
|
||||
// XXX explain these variables
|
||||
GLfloat rx = (double) (crect.x1 - dx + x);
|
||||
GLfloat ry = (double) (crect.y1 - dy + y);
|
||||
GLfloat rxe = rx + (double) (crect.x2 - crect.x1);
|
||||
GLfloat rye = ry + (double) (crect.y2 - crect.y1);
|
||||
// Rectangle textures have [0-w] [0-h] while 2D texture has [0-1] [0-1]
|
||||
// Thanks to amonakov for pointing out!
|
||||
if (GL_TEXTURE_2D == ptex->target) {
|
||||
@ -1565,10 +1428,10 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||
rxe = rxe / ptex->width;
|
||||
rye = rye / ptex->height;
|
||||
}
|
||||
GLint rdx = crect.x;
|
||||
GLint rdy = ps->root_height - crect.y;
|
||||
GLint rdxe = rdx + crect.width;
|
||||
GLint rdye = rdy - crect.height;
|
||||
GLint rdx = crect.x1;
|
||||
GLint rdy = ps->root_height - crect.y1;
|
||||
GLint rdxe = rdx + (crect.x2 - crect.x1);
|
||||
GLint rdye = rdy - (crect.y2 - crect.y1);
|
||||
|
||||
// Invert Y if needed, this may not work as expected, though. I don't
|
||||
// have such a FBConfig to test with.
|
||||
@ -1599,8 +1462,7 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||
|
||||
P_TEXCOORD(rx, rye);
|
||||
glVertex3i(rdx, rdye, z);
|
||||
}
|
||||
P_PAINTREG_END();
|
||||
} P_PAINTREG_END();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
|
Reference in New Issue
Block a user