Bug fix: GLX: Fix dim and blur with --glx-no-stencil

- GLX backend: Fix broken dim and blur with --glx-no-stencil when
  dealing with shaped windows.

- GLX backend: Cache region contents and do a local region intersection
  instead of using XFixesIntersectRegion(). Drastic reduction in CPU
  usage for --glx-no-stencil. Now --glx-no-stencil substantially
  outperforms (~15%) normal mode.

- Use macros to reuse paint-in-region code in opengl.c . Add new type
  "reg_data_t" to store XserverRegion cache.
pull/2/head
Richard Grenville 12 years ago
parent 53870fb7fe
commit b75d417c52

@ -341,6 +341,14 @@ typedef struct _latom {
struct _latom *next; struct _latom *next;
} latom_t; } latom_t;
/// A representation of raw region data
typedef struct {
XRectangle *rects;
int nrects;
} reg_data_t;
#define REG_DATA_INIT { NULL, 0 }
struct _timeout_t; struct _timeout_t;
struct _win; struct _win;
@ -1532,6 +1540,20 @@ free_region(session_t *ps, XserverRegion *p) {
} }
} }
/**
* Crop a rectangle by another rectangle.
*
* psrc and pdst cannot be the same.
*/
static inline void
rect_crop(XRectangle *pdst, const XRectangle *psrc, const XRectangle *pbound) {
assert(psrc != pdst);
pdst->x = max_i(psrc->x, pbound->x);
pdst->y = max_i(psrc->y, pbound->y);
pdst->width = max_i(0, min_i(psrc->x + psrc->width, pbound->x + pbound->width) - pdst->x);
pdst->height = max_i(0, min_i(psrc->y + psrc->height, pbound->y + pbound->height) - pdst->y);
}
/** /**
* Check if a rectangle includes the whole screen. * Check if a rectangle includes the whole screen.
*/ */
@ -1661,21 +1683,21 @@ glx_tex_binded(const glx_texture_t *ptex, Pixmap pixmap) {
} }
void void
glx_set_clip(session_t *ps, XserverRegion reg, glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg);
const XRectangle * const cache_rects, const int cache_nrects);
bool bool
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor_center); GLfloat factor_center, XserverRegion reg_tgt, const reg_data_t *pcache_reg);
bool bool
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z, glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor); GLfloat factor, XserverRegion reg_tgt, const reg_data_t *pcache_reg);
bool bool
glx_render(session_t *ps, const glx_texture_t *ptex, glx_render(session_t *ps, const glx_texture_t *ptex,
int x, int y, int dx, int dy, int width, int height, int z, int x, int y, int dx, int dy, int width, int height, int z,
double opacity, bool neg, XserverRegion reg_tgt); double opacity, bool neg,
XserverRegion reg_tgt, const reg_data_t *pcache_reg);
void void
glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg); glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg);

@ -881,7 +881,7 @@ paint_root(session_t *ps, XserverRegion reg_paint) {
get_root_tile(ps); get_root_tile(ps);
win_render(ps, NULL, 0, 0, ps->root_width, ps->root_height, 1.0, reg_paint, win_render(ps, NULL, 0, 0, ps->root_width, ps->root_height, 1.0, reg_paint,
ps->root_tile_paint.pict); NULL, ps->root_tile_paint.pict);
} }
/** /**
@ -1280,7 +1280,8 @@ paint_preprocess(session_t *ps, win *list) {
* Paint the shadow of a window. * Paint the shadow of a window.
*/ */
static inline void static inline void
win_paint_shadow(session_t *ps, win *w, XserverRegion reg_paint) { win_paint_shadow(session_t *ps, win *w,
XserverRegion reg_paint, const reg_data_t *pcache_reg) {
if (!paint_isvalid(ps, &w->shadow_paint)) { if (!paint_isvalid(ps, &w->shadow_paint)) {
printf_errf("(%#010lx): Missing painting data. This is a bad sign.", w->id); printf_errf("(%#010lx): Missing painting data. This is a bad sign.", w->id);
return; return;
@ -1288,7 +1289,7 @@ win_paint_shadow(session_t *ps, win *w, XserverRegion reg_paint) {
render(ps, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, render(ps, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy,
w->shadow_width, w->shadow_height, w->shadow_opacity, true, false, w->shadow_width, w->shadow_height, w->shadow_opacity, true, false,
w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint); w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, pcache_reg);
} }
/** /**
@ -1320,7 +1321,7 @@ win_build_picture(session_t *ps, win *w, XRenderPictFormat *pictfmt) {
*/ */
static inline void static inline void
win_blur_background(session_t *ps, win *w, Picture tgt_buffer, win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
XserverRegion reg_paint) { XserverRegion reg_paint, const reg_data_t *pcache_reg) {
const int x = w->a.x; const int x = w->a.x;
const int y = w->a.y; const int y = w->a.y;
const int wid = w->widthb; const int wid = w->widthb;
@ -1385,7 +1386,8 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
break; break;
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX: case BKEND_GLX:
glx_blur_dst(ps, x, y, wid, hei, ps->glx_z - 0.5, factor_center); glx_blur_dst(ps, x, y, wid, hei, ps->glx_z - 0.5, factor_center,
reg_paint, pcache_reg);
break; break;
#endif #endif
default: default:
@ -1396,7 +1398,8 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
static void static void
render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
double opacity, bool argb, bool neg, double opacity, bool argb, bool neg,
Picture pict, glx_texture_t *ptex, XserverRegion reg_paint) { Picture pict, glx_texture_t *ptex,
XserverRegion reg_paint, const reg_data_t *pcache_reg) {
switch (ps->o.backend) { switch (ps->o.backend) {
case BKEND_XRENDER: case BKEND_XRENDER:
{ {
@ -1411,7 +1414,7 @@ render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX: case BKEND_GLX:
glx_render(ps, ptex, x, y, dx, dy, wid, hei, glx_render(ps, ptex, x, y, dx, dy, wid, hei,
ps->glx_z, opacity, neg, reg_paint); ps->glx_z, opacity, neg, reg_paint, pcache_reg);
ps->glx_z += 1; ps->glx_z += 1;
break; break;
#endif #endif
@ -1424,7 +1427,8 @@ render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
* Paint a window itself and dim it if asked. * Paint a window itself and dim it if asked.
*/ */
static inline void static inline void
win_paint_win(session_t *ps, win *w, XserverRegion reg_paint) { win_paint_win(session_t *ps, win *w, XserverRegion reg_paint,
const reg_data_t *pcache_reg) {
// Fetch Pixmap // Fetch Pixmap
if (!w->paint.pixmap && ps->has_name_pixmap) { if (!w->paint.pixmap && ps->has_name_pixmap) {
set_ignore_next(ps); set_ignore_next(ps);
@ -1494,7 +1498,7 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint) {
double dopacity = get_opacity_percent(w);; double dopacity = get_opacity_percent(w);;
if (!w->frame_opacity) { if (!w->frame_opacity) {
win_render(ps, w, 0, 0, wid, hei, dopacity, reg_paint, pict); win_render(ps, w, 0, 0, wid, hei, dopacity, reg_paint, pcache_reg, pict);
} }
else { else {
// Painting parameters // Painting parameters
@ -1505,7 +1509,7 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint) {
#define COMP_BDR(cx, cy, cwid, chei) \ #define COMP_BDR(cx, cy, cwid, chei) \
win_render(ps, w, (cx), (cy), (cwid), (chei), w->frame_opacity, \ win_render(ps, w, (cx), (cy), (cwid), (chei), w->frame_opacity, \
reg_paint, pict) reg_paint, pcache_reg, pict)
// The following complicated logic is required because some broken // The following complicated logic is required because some broken
// window managers (I'm talking about you, Openbox!) that makes // window managers (I'm talking about you, Openbox!) that makes
@ -1540,7 +1544,7 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint) {
pwid = wid - l - pwid; pwid = wid - l - pwid;
if (pwid > 0) { if (pwid > 0) {
// body // body
win_render(ps, w, l, t, pwid, phei, dopacity, reg_paint, pict); win_render(ps, w, l, t, pwid, phei, dopacity, reg_paint, pcache_reg, pict);
} }
} }
} }
@ -1581,7 +1585,8 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint) {
break; break;
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX: case BKEND_GLX:
glx_dim_dst(ps, x, y, wid, hei, ps->glx_z - 0.7, dim_opacity); glx_dim_dst(ps, x, y, wid, hei, ps->glx_z - 0.7, dim_opacity,
reg_paint, pcache_reg);
break; break;
#endif #endif
} }
@ -1666,7 +1671,7 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
reg_paint = region; reg_paint = region;
} }
set_tgt_clip(ps, reg_paint, NULL, 0); set_tgt_clip(ps, reg_paint, NULL);
paint_root(ps, reg_paint); paint_root(ps, reg_paint);
// Create temporary regions for use during painting // Create temporary regions for use during painting
@ -1718,15 +1723,14 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
// Detect if the region is empty before painting // Detect if the region is empty before painting
{ {
int nrects = 0; reg_data_t cache_reg = REG_DATA_INIT;
XRectangle *rects = NULL;
if (region == reg_paint if (region == reg_paint
|| !is_region_empty(ps, reg_paint, &rects, &nrects)) { || !is_region_empty(ps, reg_paint, &cache_reg)) {
set_tgt_clip(ps, reg_paint, rects, nrects); set_tgt_clip(ps, reg_paint, &cache_reg);
win_paint_shadow(ps, w, reg_paint); win_paint_shadow(ps, w, reg_paint, &cache_reg);
} }
cxfree(rects); free_reg_data(&cache_reg);
} }
} }
@ -1751,20 +1755,19 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
} }
{ {
int nrects = 0; reg_data_t cache_reg = REG_DATA_INIT;
XRectangle *rects = NULL; if (!is_region_empty(ps, reg_paint, &cache_reg)) {
if (!is_region_empty(ps, reg_paint, &rects, &nrects)) { set_tgt_clip(ps, reg_paint, &cache_reg);
set_tgt_clip(ps, reg_paint, rects, nrects);
// Blur window background // Blur window background
if (w->blur_background && (WMODE_SOLID != w->mode if (w->blur_background && (WMODE_SOLID != w->mode
|| (ps->o.blur_background_frame && w->frame_opacity))) { || (ps->o.blur_background_frame && w->frame_opacity))) {
win_blur_background(ps, w, ps->tgt_buffer, reg_paint); win_blur_background(ps, w, ps->tgt_buffer, reg_paint, &cache_reg);
} }
// Painting the window // Painting the window
win_paint_win(ps, w, reg_paint); win_paint_win(ps, w, reg_paint, &cache_reg);
} }
cxfree(rects); free_reg_data(&cache_reg);
} }
} }
@ -1774,7 +1777,7 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
// Do this as early as possible // Do this as early as possible
if (!ps->o.dbe) if (!ps->o.dbe)
set_tgt_clip(ps, None, NULL, 0); set_tgt_clip(ps, None, NULL);
if (ps->o.vsync) { if (ps->o.vsync) {
// Make sure all previous requests are processed to achieve best // Make sure all previous requests are processed to achieve best
@ -4227,8 +4230,8 @@ usage(void) {
" Choose backend. Possible choices are xrender and glx" WARNING ".\n" " Choose backend. Possible choices are xrender and glx" WARNING ".\n"
"--glx-no-stencil\n" "--glx-no-stencil\n"
" GLX backend: Avoid using stencil buffer. Might cause issues\n" " GLX backend: Avoid using stencil buffer. Might cause issues\n"
" when rendering transparent content. May have a positive or\n" " when rendering transparent content. My tests show a 15% performance\n"
" negative effect on performance. (My test shows a 10% slowdown.)\n" " boost.\n"
"--glx-copy-from-front\n" "--glx-copy-from-front\n"
" GLX backend: Copy unmodified regions from front buffer instead of\n" " GLX backend: Copy unmodified regions from front buffer instead of\n"
" redrawing them all. My tests with nvidia-drivers show a 10% decrease\n" " redrawing them all. My tests with nvidia-drivers show a 10% decrease\n"
@ -6386,7 +6389,7 @@ session_run(session_t *ps) {
if (!ps->redirected) if (!ps->redirected)
free_region(ps, &ps->all_damage); free_region(ps, &ps->all_damage);
if (ps->all_damage && !is_region_empty(ps, ps->all_damage, NULL, NULL)) { if (ps->all_damage && !is_region_empty(ps, ps->all_damage, NULL)) {
static int paint = 0; static int paint = 0;
paint_all(ps, ps->all_damage, t); paint_all(ps, ps->all_damage, t);
ps->reg_ignore_expire = false; ps->reg_ignore_expire = false;

@ -196,6 +196,16 @@ paint_bind_tex(session_t *ps, paint_t *ppaint,
return true; return true;
} }
/**
* Free data in a reg_data_t.
*/
static inline void
free_reg_data(reg_data_t *pregd) {
cxfree(pregd->rects);
pregd->rects = NULL;
pregd->nrects = 0;
}
/** /**
* Free paint_t. * Free paint_t.
*/ */
@ -532,29 +542,29 @@ paint_preprocess(session_t *ps, win *list);
static void static void
render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
double opacity, bool argb, bool neg, double opacity, bool argb, bool neg,
Picture pict, glx_texture_t *ptex, XserverRegion reg_paint); Picture pict, glx_texture_t *ptex,
XserverRegion reg_paint, const reg_data_t *pcache_reg);
static inline void static inline void
win_render(session_t *ps, win *w, int x, int y, int wid, int hei, double opacity, XserverRegion reg_paint, Picture pict) { win_render(session_t *ps, win *w, int x, int y, int wid, int hei, double opacity, XserverRegion reg_paint, const reg_data_t *pcache_reg, Picture pict) {
const int dx = (w ? w->a.x: 0) + x; const int dx = (w ? w->a.x: 0) + x;
const int dy = (w ? w->a.y: 0) + y; const int dy = (w ? w->a.y: 0) + y;
const bool argb = (w && w->mode == WMODE_ARGB); const bool argb = (w && w->mode == WMODE_ARGB);
const bool neg = (w && w->invert_color); const bool neg = (w && w->invert_color);
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg,
pict, (w ? w->paint.ptex: ps->root_tile_paint.ptex), reg_paint); pict, (w ? w->paint.ptex: ps->root_tile_paint.ptex), reg_paint, pcache_reg);
} }
static inline void static inline void
set_tgt_clip(session_t *ps, XserverRegion reg, set_tgt_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg) {
const XRectangle * const cache_rects, const int cache_nrects) {
switch (ps->o.backend) { switch (ps->o.backend) {
case BKEND_XRENDER: case BKEND_XRENDER:
XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg); XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg);
break; break;
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX: case BKEND_GLX:
glx_set_clip(ps, reg, cache_rects, cache_nrects); glx_set_clip(ps, reg, pcache_reg);
break; break;
#endif #endif
} }
@ -870,18 +880,17 @@ dump_region(const session_t *ps, XserverRegion region) {
*/ */
static inline bool static inline bool
is_region_empty(const session_t *ps, XserverRegion region, is_region_empty(const session_t *ps, XserverRegion region,
XRectangle **pcache_rects, int *pcache_nrects) { reg_data_t *pcache_reg) {
int nrects = 0; int nrects = 0;
XRectangle *rects = XFixesFetchRegion(ps->dpy, region, &nrects); XRectangle *rects = XFixesFetchRegion(ps->dpy, region, &nrects);
if (pcache_rects) if (pcache_reg) {
*pcache_rects = rects; pcache_reg->rects = rects;
pcache_reg->nrects = nrects;
}
else else
cxfree(rects); cxfree(rects);
if (pcache_nrects)
*pcache_nrects = nrects;
return !nrects; return !nrects;
} }

@ -190,11 +190,6 @@ glx_on_root_change(session_t *ps) {
bool bool
glx_init_blur(session_t *ps) { glx_init_blur(session_t *ps) {
#ifdef CONFIG_VSYNC_OPENGL_GLSL #ifdef CONFIG_VSYNC_OPENGL_GLSL
if (ps->o.glx_no_stencil) {
printf_errf("(): I'm afraid blur background won't work so well without "
"stencil buffer support.");
}
// Build shader // Build shader
static const char *FRAG_SHADER_BLUR = static const char *FRAG_SHADER_BLUR =
"#version 110\n" "#version 110\n"
@ -562,7 +557,7 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) {
{ {
XserverRegion reg_copy = XFixesCreateRegion(ps->dpy, NULL, 0); XserverRegion reg_copy = XFixesCreateRegion(ps->dpy, NULL, 0);
XFixesSubtractRegion(ps->dpy, reg_copy, ps->screen_reg, *preg); XFixesSubtractRegion(ps->dpy, reg_copy, ps->screen_reg, *preg);
glx_set_clip(ps, reg_copy, NULL, 0); glx_set_clip(ps, reg_copy, NULL);
free_region(ps, &reg_copy); free_region(ps, &reg_copy);
} }
@ -577,22 +572,19 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) {
} }
} }
glx_set_clip(ps, *preg, NULL, 0); glx_set_clip(ps, *preg, NULL);
} }
/** /**
* Set clipping region on the target window. * Set clipping region on the target window.
*/ */
void void
glx_set_clip(session_t *ps, XserverRegion reg, glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg) {
const XRectangle * const cache_rects, const int cache_nrects) {
// Quit if we aren't using stencils // Quit if we aren't using stencils
if (ps->o.glx_no_stencil) if (ps->o.glx_no_stencil)
return; return;
static XRectangle rect_blank = { static XRectangle rect_blank = { .x = 0, .y = 0, .width = 0, .height = 0 };
.x = 0, .y = 0, .width = 0, .height = 0
};
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
@ -600,13 +592,18 @@ glx_set_clip(session_t *ps, XserverRegion reg,
if (!reg) if (!reg)
return; return;
int nrects = cache_nrects; int nrects = 0;
XRectangle *rects_free = NULL; XRectangle *rects_free = NULL;
const XRectangle *rects = cache_rects; const XRectangle *rects = NULL;
if (pcache_reg) {
rects = pcache_reg->rects;
nrects = pcache_reg->nrects;
}
if (!rects) { if (!rects) {
nrects = 0; nrects = 0;
rects = rects_free = XFixesFetchRegion(ps->dpy, reg, &nrects); rects = rects_free = XFixesFetchRegion(ps->dpy, reg, &nrects);
} }
// Use one empty rectangle if the region is empty
if (!nrects) { if (!nrects) {
cxfree(rects_free); cxfree(rects_free);
rects_free = NULL; rects_free = NULL;
@ -657,9 +654,45 @@ glx_set_clip(session_t *ps, XserverRegion reg,
cxfree(rects_free); cxfree(rects_free);
} }
#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); \
} \
} \
glBegin(GL_QUADS); \
\
for (int i = 0; i < nrects; ++i) { \
XRectangle crect; \
rect_crop(&crect, &rects[i], &rec_all); \
\
if (!crect.width || !crect.height) \
continue; \
#define P_PAINTREG_END() \
} \
glEnd(); \
\
if (rects && rects != &rec_all && !(pcache_reg && pcache_reg->rects == rects)) \
cxfree(rects); \
free_region(ps, &reg_new); \
bool bool
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor_center) { GLfloat factor_center, XserverRegion reg_tgt, const reg_data_t *pcache_reg) {
// Read destination pixels into a texture // Read destination pixels into a texture
GLuint tex_scr = 0; GLuint tex_scr = 0;
glGenTextures(1, &tex_scr); glGenTextures(1, &tex_scr);
@ -699,37 +732,37 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
glUniform1f(ps->glx_prog_blur_unifm_factor_center, factor_center); glUniform1f(ps->glx_prog_blur_unifm_factor_center, factor_center);
#endif #endif
glBegin(GL_QUADS);
{ {
const GLfloat rx = 0.0; P_PAINTREG_START();
const GLfloat ry = 1.0; {
const GLfloat rxe = 1.0; const GLfloat rx = (double) (crect.x - dx) / width;
const GLfloat rye = 0.0; const GLfloat ry = 1.0 - (double) (crect.y - dy) / height;
const GLint rdx = dx; const GLfloat rxe = rx + (double) crect.width / width;
const GLint rdy = ps->root_height - dy; const GLfloat rye = ry - (double) crect.height / height;
const GLint rdxe = rdx + width; const GLfloat rdx = crect.x;
const GLint rdye = rdy - height; const GLfloat rdy = ps->root_height - crect.y;
const GLfloat rdxe = rdx + crect.width;
const GLfloat rdye = rdy - crect.height;
#ifdef DEBUG_GLX #ifdef DEBUG_GLX
printf_dbgf("(): %f, %f, %f, %f -> %d, %d, %d, %d\n", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); printf_dbgf("(): %f, %f, %f, %f -> %d, %d, %d, %d\n", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
#endif #endif
glTexCoord2f(rx, ry); glTexCoord2f(rx, ry);
glVertex3f(rdx, rdy, z); glVertex3f(rdx, rdy, z);
glTexCoord2f(rxe, ry); glTexCoord2f(rxe, ry);
glVertex3f(rdxe, rdy, z); glVertex3f(rdxe, rdy, z);
glTexCoord2f(rxe, rye); glTexCoord2f(rxe, rye);
glVertex3f(rdxe, rdye, z); glVertex3f(rdxe, rdye, z);
glTexCoord2f(rx, rye); glTexCoord2f(rx, rye);
glVertex3f(rdx, rdye, z); glVertex3f(rdx, rdye, z);
}
P_PAINTREG_END();
} }
glEnd();
#ifdef CONFIG_VSYNC_OPENGL_GLSL #ifdef CONFIG_VSYNC_OPENGL_GLSL
glUseProgram(0); glUseProgram(0);
#endif #endif
@ -743,25 +776,27 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
bool bool
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z, glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor) { GLfloat factor, XserverRegion reg_tgt, const reg_data_t *pcache_reg) {
// It's possible to dim in glx_render(), but it would be over-complicated // It's possible to dim in glx_render(), but it would be over-complicated
// considering all those mess in color negation and modulation // considering all those mess in color negation and modulation
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.0f, 0.0f, 0.0f, factor); glColor4f(0.0f, 0.0f, 0.0f, factor);
glBegin(GL_QUADS);
{ {
GLint rdx = dx; P_PAINTREG_START();
GLint rdy = ps->root_height - dy; {
GLint rdxe = rdx + width; GLint rdx = crect.x;
GLint rdye = rdy - height; GLint rdy = ps->root_height - crect.y;
GLint rdxe = rdx + crect.width;
glVertex3i(rdx, rdy, z); GLint rdye = rdy - crect.height;
glVertex3i(rdxe, rdy, z);
glVertex3i(rdxe, rdye, z); glVertex3i(rdx, rdy, z);
glVertex3i(rdx, rdye, z); glVertex3i(rdxe, rdy, z);
glVertex3i(rdxe, rdye, z);
glVertex3i(rdx, rdye, z);
}
P_PAINTREG_END();
} }
glEnd(); glEnd();
@ -778,7 +813,8 @@ glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
bool bool
glx_render(session_t *ps, const glx_texture_t *ptex, glx_render(session_t *ps, const glx_texture_t *ptex,
int x, int y, int dx, int dy, int width, int height, int z, int x, int y, int dx, int dy, int width, int height, int z,
double opacity, bool neg, XserverRegion reg_tgt) { double opacity, bool neg,
XserverRegion reg_tgt, const reg_data_t *pcache_reg) {
if (!ptex || !ptex->texture) { if (!ptex || !ptex->texture) {
printf_errf("(): Missing texture."); printf_errf("(): Missing texture.");
return false; return false;
@ -878,51 +914,30 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
} }
} }
{
XserverRegion reg_new = None;
XRectangle rec_all = {
.x = dx,
.y = dy,
.width = width,
.height = height
};
XRectangle *rects = &rec_all;
int nrects = 1;
#ifdef DEBUG_GLX #ifdef DEBUG_GLX
printf_dbgf("(): Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n", x, y, width, height, dx, dy, ptex->width, ptex->height, z); printf_dbgf("(): Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n", x, y, width, height, dx, dy, ptex->width, ptex->height, z);
#endif #endif
// On no-stencil mode, calculate painting region here instead of relying // Bind texture
// on stencil buffer glBindTexture(ptex->target, ptex->texture);
if (ps->o.glx_no_stencil && reg_tgt) { if (dual_texture) {
reg_new = XFixesCreateRegion(ps->dpy, &rec_all, 1); glActiveTexture(GL_TEXTURE1);
XFixesIntersectRegion(ps->dpy, reg_new, reg_new, reg_tgt);
nrects = 0;
rects = XFixesFetchRegion(ps->dpy, reg_new, &nrects);
}
glBindTexture(ptex->target, ptex->texture); glBindTexture(ptex->target, ptex->texture);
if (dual_texture) { glActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE1); }
glBindTexture(ptex->target, ptex->texture);
glActiveTexture(GL_TEXTURE0);
}
glBegin(GL_QUADS);
for (int i = 0; i < nrects; ++i) { // Painting
GLfloat rx = (double) (rects[i].x - dx + x) / ptex->width; {
GLfloat ry = (double) (rects[i].y - dy + y) / ptex->height; P_PAINTREG_START();
GLfloat rxe = rx + (double) rects[i].width / ptex->width; {
GLfloat rye = ry + (double) rects[i].height / ptex->height; GLfloat rx = (double) (crect.x - dx + x) / ptex->width;
GLint rdx = rects[i].x; GLfloat ry = (double) (crect.y - dy + y) / ptex->height;
GLint rdy = ps->root_height - rects[i].y; GLfloat rxe = rx + (double) crect.width / ptex->width;
GLint rdxe = rdx + rects[i].width; GLfloat rye = ry + (double) crect.height / ptex->height;
GLint rdye = rdy - rects[i].height; GLint rdx = crect.x;
GLint rdy = ps->root_height - crect.y;
GLint rdxe = rdx + crect.width;
GLint rdye = rdy - crect.height;
// Invert Y if needed, this may not work as expected, though. I don't // Invert Y if needed, this may not work as expected, though. I don't
// have such a FBConfig to test with. // have such a FBConfig to test with.
@ -954,12 +969,7 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
P_TEXCOORD(rx, rye); P_TEXCOORD(rx, rye);
glVertex3i(rdx, rdye, z); glVertex3i(rdx, rdye, z);
} }
P_PAINTREG_END();
glEnd();
if (rects && rects != &rec_all)
cxfree(rects);
free_region(ps, &reg_new);
} }
// Cleanup // Cleanup
@ -993,7 +1003,7 @@ glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg) {
glXSwapBuffers(ps->dpy, get_tgt_window(ps)); glXSwapBuffers(ps->dpy, get_tgt_window(ps));
} }
else { else {
glx_set_clip(ps, None, NULL, 0); glx_set_clip(ps, None, NULL);
for (int i = 0; i < nrects; ++i) { for (int i = 0; i < nrects; ++i) {
const int x = rects[i].x; const int x = rects[i].x;
const int y = ps->root_height - rects[i].y - rects[i].height; const int y = ps->root_height - rects[i].y - rects[i].height;

Loading…
Cancel
Save