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.
This commit is contained in:
parent
e3a15d5f94
commit
a053c0ac64
32
src/common.h
32
src/common.h
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
162
src/opengl.c
162
src/opengl.c
@ -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, ®_copy);
|
free_region(ps, ®_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, ®_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,17 +732,17 @@ 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);
|
||||||
@ -727,8 +760,8 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float 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);
|
||||||
@ -743,26 +776,28 @@ 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;
|
||||||
|
GLint rdye = rdy - crect.height;
|
||||||
|
|
||||||
glVertex3i(rdx, rdy, z);
|
glVertex3i(rdx, rdy, z);
|
||||||
glVertex3i(rdxe, rdy, z);
|
glVertex3i(rdxe, rdy, z);
|
||||||
glVertex3i(rdxe, rdye, z);
|
glVertex3i(rdxe, rdye, z);
|
||||||
glVertex3i(rdx, 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,33 +914,11 @@ 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
|
|
||||||
if (ps->o.glx_no_stencil && reg_tgt) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindTexture(ptex->target, ptex->texture);
|
glBindTexture(ptex->target, ptex->texture);
|
||||||
if (dual_texture) {
|
if (dual_texture) {
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
@ -912,17 +926,18 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
|||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
// Painting
|
||||||
|
{
|
||||||
for (int i = 0; i < nrects; ++i) {
|
P_PAINTREG_START();
|
||||||
GLfloat rx = (double) (rects[i].x - dx + x) / ptex->width;
|
{
|
||||||
GLfloat ry = (double) (rects[i].y - dy + y) / ptex->height;
|
GLfloat rx = (double) (crect.x - dx + x) / ptex->width;
|
||||||
GLfloat rxe = rx + (double) rects[i].width / ptex->width;
|
GLfloat ry = (double) (crect.y - dy + y) / ptex->height;
|
||||||
GLfloat rye = ry + (double) rects[i].height / ptex->height;
|
GLfloat rxe = rx + (double) crect.width / ptex->width;
|
||||||
GLint rdx = rects[i].x;
|
GLfloat rye = ry + (double) crect.height / ptex->height;
|
||||||
GLint rdy = ps->root_height - rects[i].y;
|
GLint rdx = crect.x;
|
||||||
GLint rdxe = rdx + rects[i].width;
|
GLint rdy = ps->root_height - crect.y;
|
||||||
GLint rdye = rdy - rects[i].height;
|
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, ®_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…
Reference in New Issue
Block a user