You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3252 lines
73 KiB
3252 lines
73 KiB
/*
|
|
* Copyright © 2007 Novell, Inc.
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software
|
|
* and its documentation for any purpose is hereby granted without
|
|
* fee, provided that the above copyright notice appear in all copies
|
|
* and that both that copyright notice and this permission notice
|
|
* appear in supporting documentation, and that the name of
|
|
* Novell, Inc. not be used in advertising or publicity pertaining to
|
|
* distribution of the software without specific, written prior permission.
|
|
* Novell, Inc. makes no representations about the suitability of this
|
|
* software for any purpose. It is provided "as is" without express or
|
|
* implied warranty.
|
|
*
|
|
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
|
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* Author: David Reveman <davidr@novell.com>
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include <compiz-core.h>
|
|
#include <decoration.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
#include <GL/glu.h>
|
|
|
|
static CompMetadata blurMetadata;
|
|
|
|
#define BLUR_GAUSSIAN_RADIUS_MAX 15
|
|
|
|
#define BLUR_FILTER_4X_BILINEAR 0
|
|
#define BLUR_FILTER_GAUSSIAN 1
|
|
#define BLUR_FILTER_MIPMAP 2
|
|
#define BLUR_FILTER_LAST BLUR_FILTER_MIPMAP
|
|
|
|
typedef struct _BlurFunction {
|
|
struct _BlurFunction *next;
|
|
|
|
int handle;
|
|
int target;
|
|
int param;
|
|
int unit;
|
|
int startTC;
|
|
int numITC;
|
|
} BlurFunction;
|
|
|
|
typedef struct _BlurBox {
|
|
decor_point_t p1;
|
|
decor_point_t p2;
|
|
} BlurBox;
|
|
|
|
#define BLUR_STATE_CLIENT 0
|
|
#define BLUR_STATE_DECOR 1
|
|
#define BLUR_STATE_NUM 2
|
|
|
|
typedef struct _BlurState {
|
|
int threshold;
|
|
BlurBox *box;
|
|
int nBox;
|
|
Bool active;
|
|
Bool clipped;
|
|
} BlurState;
|
|
|
|
static int corePrivateIndex;
|
|
|
|
typedef struct _BlurCore {
|
|
ObjectAddProc objectAdd;
|
|
} BlurCore;
|
|
|
|
static int displayPrivateIndex;
|
|
|
|
#define BLUR_DISPLAY_OPTION_PULSE 0
|
|
#define BLUR_DISPLAY_OPTION_NUM 1
|
|
|
|
typedef struct _BlurDisplay {
|
|
int screenPrivateIndex;
|
|
HandleEventProc handleEvent;
|
|
MatchExpHandlerChangedProc matchExpHandlerChanged;
|
|
MatchPropertyChangedProc matchPropertyChanged;
|
|
|
|
CompOption opt[BLUR_DISPLAY_OPTION_NUM];
|
|
|
|
Atom blurAtom[BLUR_STATE_NUM];
|
|
} BlurDisplay;
|
|
|
|
#define BLUR_SCREEN_OPTION_BLUR_SPEED 0
|
|
#define BLUR_SCREEN_OPTION_FOCUS_BLUR_MATCH 1
|
|
#define BLUR_SCREEN_OPTION_FOCUS_BLUR 2
|
|
#define BLUR_SCREEN_OPTION_ALPHA_BLUR_MATCH 3
|
|
#define BLUR_SCREEN_OPTION_ALPHA_BLUR 4
|
|
#define BLUR_SCREEN_OPTION_FILTER 5
|
|
#define BLUR_SCREEN_OPTION_GAUSSIAN_RADIUS 6
|
|
#define BLUR_SCREEN_OPTION_GAUSSIAN_STRENGTH 7
|
|
#define BLUR_SCREEN_OPTION_MIPMAP_LOD 8
|
|
#define BLUR_SCREEN_OPTION_SATURATION 9
|
|
#define BLUR_SCREEN_OPTION_BLUR_OCCLUSION 10
|
|
#define BLUR_SCREEN_OPTION_INDEPENDENT_TEX 11
|
|
#define BLUR_SCREEN_OPTION_NUM 12
|
|
|
|
typedef struct _BlurScreen {
|
|
int windowPrivateIndex;
|
|
|
|
CompOption opt[BLUR_SCREEN_OPTION_NUM];
|
|
|
|
PreparePaintScreenProc preparePaintScreen;
|
|
DonePaintScreenProc donePaintScreen;
|
|
PaintOutputProc paintOutput;
|
|
PaintTransformedOutputProc paintTransformedOutput;
|
|
PaintWindowProc paintWindow;
|
|
DrawWindowProc drawWindow;
|
|
DrawWindowTextureProc drawWindowTexture;
|
|
|
|
WindowResizeNotifyProc windowResizeNotify;
|
|
WindowMoveNotifyProc windowMoveNotify;
|
|
|
|
Bool alphaBlur;
|
|
|
|
int blurTime;
|
|
Bool moreBlur;
|
|
|
|
Bool blurOcclusion;
|
|
|
|
int filterRadius;
|
|
|
|
BlurFunction *srcBlurFunctions;
|
|
BlurFunction *dstBlurFunctions;
|
|
|
|
Region region;
|
|
Region tmpRegion;
|
|
Region tmpRegion2;
|
|
Region tmpRegion3;
|
|
Region occlusion;
|
|
|
|
BoxRec stencilBox;
|
|
GLint stencilBits;
|
|
|
|
CompOutput *output;
|
|
int count;
|
|
|
|
GLuint texture[2];
|
|
|
|
GLenum target;
|
|
float tx;
|
|
float ty;
|
|
int width;
|
|
int height;
|
|
|
|
GLuint program;
|
|
int maxTemp;
|
|
GLuint fbo;
|
|
Bool fboStatus;
|
|
|
|
float amp[BLUR_GAUSSIAN_RADIUS_MAX];
|
|
float pos[BLUR_GAUSSIAN_RADIUS_MAX];
|
|
int numTexop;
|
|
|
|
CompTransform mvp;
|
|
} BlurScreen;
|
|
|
|
typedef struct _BlurWindow {
|
|
int blur;
|
|
Bool pulse;
|
|
Bool focusBlur;
|
|
|
|
BlurState state[BLUR_STATE_NUM];
|
|
Bool propSet[BLUR_STATE_NUM];
|
|
|
|
Region region;
|
|
Region clip;
|
|
} BlurWindow;
|
|
|
|
#define GET_BLUR_CORE(c) \
|
|
((BlurCore *) (c)->base.privates[corePrivateIndex].ptr)
|
|
|
|
#define BLUR_CORE(c) \
|
|
BlurCore *bc = GET_BLUR_CORE (c)
|
|
|
|
#define GET_BLUR_DISPLAY(d) \
|
|
((BlurDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
|
|
|
|
#define BLUR_DISPLAY(d) \
|
|
BlurDisplay *bd = GET_BLUR_DISPLAY (d)
|
|
|
|
#define GET_BLUR_SCREEN(s, bd) \
|
|
((BlurScreen *) (s)->base.privates[(bd)->screenPrivateIndex].ptr)
|
|
|
|
#define BLUR_SCREEN(s) \
|
|
BlurScreen *bs = GET_BLUR_SCREEN (s, GET_BLUR_DISPLAY (s->display))
|
|
|
|
#define GET_BLUR_WINDOW(w, bs) \
|
|
((BlurWindow *) (w)->base.privates[(bs)->windowPrivateIndex].ptr)
|
|
|
|
#define BLUR_WINDOW(w) \
|
|
BlurWindow *bw = GET_BLUR_WINDOW (w, \
|
|
GET_BLUR_SCREEN (w->screen, \
|
|
GET_BLUR_DISPLAY (w->screen->display)))
|
|
|
|
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
|
|
|
|
/* pascal triangle based kernel generator */
|
|
static int
|
|
blurCreateGaussianLinearKernel (int radius,
|
|
float strength,
|
|
float *amp,
|
|
float *pos,
|
|
int *optSize)
|
|
{
|
|
float factor = 0.5f + (strength / 2.0f);
|
|
float buffer1[BLUR_GAUSSIAN_RADIUS_MAX * 3];
|
|
float buffer2[BLUR_GAUSSIAN_RADIUS_MAX * 3];
|
|
float *ar1 = buffer1;
|
|
float *ar2 = buffer2;
|
|
float *tmp;
|
|
float sum = 0;
|
|
int size = (radius * 2) + 1;
|
|
int mySize = ceil (radius / 2.0f);
|
|
int i, j;
|
|
|
|
ar1[0] = 1.0;
|
|
ar1[1] = 1.0;
|
|
|
|
for (i = 3; i <= size; i++)
|
|
{
|
|
ar2[0] = 1;
|
|
|
|
for (j = 1; j < i - 1; j++)
|
|
ar2[j] = (ar1[j - 1] + ar1[j]) * factor;
|
|
|
|
ar2[i - 1] = 1;
|
|
|
|
tmp = ar1;
|
|
ar1 = ar2;
|
|
ar2 = tmp;
|
|
}
|
|
|
|
/* normalize */
|
|
for (i = 0; i < size; i++)
|
|
sum += ar1[i];
|
|
|
|
if (sum != 0.0f)
|
|
sum = 1.0f / sum;
|
|
|
|
for (i = 0; i < size; i++)
|
|
ar1[i] *= sum;
|
|
|
|
i = 0;
|
|
j = 0;
|
|
|
|
if (radius & 1)
|
|
{
|
|
pos[i] = radius;
|
|
amp[i] = ar1[i];
|
|
i = 1;
|
|
j = 1;
|
|
}
|
|
|
|
for (; i < mySize; i++)
|
|
{
|
|
pos[i] = radius - j;
|
|
pos[i] -= ar1[j + 1] / (ar1[j] + ar1[j + 1]);
|
|
amp[i] = ar1[j] + ar1[j + 1];
|
|
|
|
j += 2;
|
|
}
|
|
|
|
pos[mySize] = 0.0;
|
|
amp[mySize] = ar1[radius];
|
|
|
|
*optSize = mySize;
|
|
|
|
return radius;
|
|
}
|
|
|
|
static void
|
|
blurUpdateFilterRadius (CompScreen *s)
|
|
{
|
|
BLUR_SCREEN (s);
|
|
|
|
switch (bs->opt[BLUR_SCREEN_OPTION_FILTER].value.i) {
|
|
case BLUR_FILTER_4X_BILINEAR:
|
|
bs->filterRadius = 2;
|
|
break;
|
|
case BLUR_FILTER_GAUSSIAN: {
|
|
int radius = bs->opt[BLUR_SCREEN_OPTION_GAUSSIAN_RADIUS].value.i;
|
|
float strength = bs->opt[BLUR_SCREEN_OPTION_GAUSSIAN_STRENGTH].value.f;
|
|
|
|
blurCreateGaussianLinearKernel (radius, strength, bs->amp, bs->pos,
|
|
&bs->numTexop);
|
|
|
|
bs->filterRadius = radius;
|
|
} break;
|
|
case BLUR_FILTER_MIPMAP: {
|
|
float lod = bs->opt[BLUR_SCREEN_OPTION_MIPMAP_LOD].value.f;
|
|
|
|
bs->filterRadius = powf (2.0f, ceilf (lod));
|
|
} break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
blurDestroyFragmentFunctions (CompScreen *s,
|
|
BlurFunction **blurFunctions)
|
|
{
|
|
BlurFunction *function, *next;
|
|
|
|
function = *blurFunctions;
|
|
while (function)
|
|
{
|
|
destroyFragmentFunction (s, function->handle);
|
|
|
|
next = function->next;
|
|
free (function);
|
|
function = next;
|
|
}
|
|
|
|
*blurFunctions = NULL;
|
|
}
|
|
|
|
static void
|
|
blurReset (CompScreen *s)
|
|
{
|
|
BLUR_SCREEN (s);
|
|
|
|
blurUpdateFilterRadius (s);
|
|
blurDestroyFragmentFunctions (s, &bs->srcBlurFunctions);
|
|
blurDestroyFragmentFunctions (s, &bs->dstBlurFunctions);
|
|
|
|
bs->width = bs->height = 0;
|
|
|
|
if (bs->program)
|
|
{
|
|
(*s->deletePrograms) (1, &bs->program);
|
|
bs->program = 0;
|
|
}
|
|
}
|
|
|
|
static Region
|
|
regionFromBoxes (BlurBox *box,
|
|
int nBox,
|
|
int width,
|
|
int height)
|
|
{
|
|
Region region;
|
|
REGION r;
|
|
int x, y;
|
|
|
|
region = XCreateRegion ();
|
|
if (!region)
|
|
return NULL;
|
|
|
|
r.rects = &r.extents;
|
|
r.numRects = r.size = 1;
|
|
|
|
while (nBox--)
|
|
{
|
|
decor_apply_gravity (box->p1.gravity, box->p1.x, box->p1.y,
|
|
width, height,
|
|
&x, &y);
|
|
|
|
r.extents.x1 = x;
|
|
r.extents.y1 = y;
|
|
|
|
decor_apply_gravity (box->p2.gravity, box->p2.x, box->p2.y,
|
|
width, height,
|
|
&x, &y);
|
|
|
|
r.extents.x2 = x;
|
|
r.extents.y2 = y;
|
|
|
|
if (r.extents.x2 > r.extents.x1 && r.extents.y2 > r.extents.y1)
|
|
XUnionRegion (region, &r, region);
|
|
|
|
box++;
|
|
}
|
|
|
|
return region;
|
|
}
|
|
|
|
static void
|
|
blurWindowUpdateRegion (CompWindow *w)
|
|
{
|
|
Region region, q;
|
|
REGION r;
|
|
|
|
BLUR_WINDOW (w);
|
|
|
|
region = XCreateRegion ();
|
|
if (!region)
|
|
return;
|
|
|
|
r.rects = &r.extents;
|
|
r.numRects = r.size = 1;
|
|
|
|
if (bw->state[BLUR_STATE_DECOR].threshold)
|
|
{
|
|
r.extents.x1 = -w->output.left;
|
|
r.extents.y1 = -w->output.top;
|
|
r.extents.x2 = w->width + w->output.right;
|
|
r.extents.y2 = w->height + w->output.bottom;
|
|
|
|
XUnionRegion (&r, region, region);
|
|
|
|
r.extents.x1 = 0;
|
|
r.extents.y1 = 0;
|
|
r.extents.x2 = w->width;
|
|
r.extents.y2 = w->height;
|
|
|
|
XSubtractRegion (region, &r, region);
|
|
|
|
bw->state[BLUR_STATE_DECOR].clipped = FALSE;
|
|
|
|
if (bw->state[BLUR_STATE_DECOR].nBox)
|
|
{
|
|
q = regionFromBoxes (bw->state[BLUR_STATE_DECOR].box,
|
|
bw->state[BLUR_STATE_DECOR].nBox,
|
|
w->width, w->height);
|
|
if (q)
|
|
{
|
|
XIntersectRegion (q, region, q);
|
|
if (!XEqualRegion (q, region))
|
|
{
|
|
XSubtractRegion (q, &emptyRegion, region);
|
|
bw->state[BLUR_STATE_DECOR].clipped = TRUE;
|
|
}
|
|
|
|
XDestroyRegion (q);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bw->state[BLUR_STATE_CLIENT].threshold)
|
|
{
|
|
r.extents.x1 = 0;
|
|
r.extents.y1 = 0;
|
|
r.extents.x2 = w->width;
|
|
r.extents.y2 = w->height;
|
|
|
|
bw->state[BLUR_STATE_CLIENT].clipped = FALSE;
|
|
|
|
if (bw->state[BLUR_STATE_CLIENT].nBox)
|
|
{
|
|
q = regionFromBoxes (bw->state[BLUR_STATE_CLIENT].box,
|
|
bw->state[BLUR_STATE_CLIENT].nBox,
|
|
w->width, w->height);
|
|
if (q)
|
|
{
|
|
XIntersectRegion (q, &r, q);
|
|
if (!XEqualRegion (q, &r))
|
|
bw->state[BLUR_STATE_CLIENT].clipped = TRUE;
|
|
|
|
XUnionRegion (q, region, region);
|
|
XDestroyRegion (q);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XUnionRegion (&r, region, region);
|
|
}
|
|
}
|
|
|
|
if (bw->region)
|
|
XDestroyRegion (bw->region);
|
|
|
|
if (XEmptyRegion (region))
|
|
{
|
|
bw->region = NULL;
|
|
XDestroyRegion (region);
|
|
}
|
|
else
|
|
{
|
|
bw->region = region;
|
|
XOffsetRegion (bw->region, w->attrib.x, w->attrib.y);
|
|
}
|
|
}
|
|
|
|
static void
|
|
blurSetWindowBlur (CompWindow *w,
|
|
int state,
|
|
int threshold,
|
|
BlurBox *box,
|
|
int nBox)
|
|
{
|
|
BLUR_WINDOW (w);
|
|
|
|
if (bw->state[state].box)
|
|
free (bw->state[state].box);
|
|
|
|
bw->state[state].threshold = threshold;
|
|
bw->state[state].box = box;
|
|
bw->state[state].nBox = nBox;
|
|
|
|
blurWindowUpdateRegion (w);
|
|
|
|
addWindowDamage (w);
|
|
}
|
|
|
|
static void
|
|
blurUpdateAlphaWindowMatch (BlurScreen *bs,
|
|
CompWindow *w)
|
|
{
|
|
BLUR_WINDOW (w);
|
|
|
|
if (!bw->propSet[BLUR_STATE_CLIENT])
|
|
{
|
|
CompMatch *match;
|
|
|
|
match = &bs->opt[BLUR_SCREEN_OPTION_ALPHA_BLUR_MATCH].value.match;
|
|
if (matchEval (match, w))
|
|
{
|
|
if (!bw->state[BLUR_STATE_CLIENT].threshold)
|
|
blurSetWindowBlur (w, BLUR_STATE_CLIENT, 4, NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
if (bw->state[BLUR_STATE_CLIENT].threshold)
|
|
blurSetWindowBlur (w, BLUR_STATE_CLIENT, 0, NULL, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
blurUpdateWindowMatch (BlurScreen *bs,
|
|
CompWindow *w)
|
|
{
|
|
CompMatch *match;
|
|
Bool focus;
|
|
|
|
BLUR_WINDOW (w);
|
|
|
|
blurUpdateAlphaWindowMatch (bs, w);
|
|
|
|
match = &bs->opt[BLUR_SCREEN_OPTION_FOCUS_BLUR_MATCH].value.match;
|
|
|
|
focus = w->screen->fragmentProgram && matchEval (match, w);
|
|
if (focus != bw->focusBlur)
|
|
{
|
|
bw->focusBlur = focus;
|
|
addWindowDamage (w);
|
|
}
|
|
}
|
|
|
|
static CompOption *
|
|
blurGetScreenOptions (CompPlugin *plugin,
|
|
CompScreen *screen,
|
|
int *count)
|
|
{
|
|
BLUR_SCREEN (screen);
|
|
|
|
*count = NUM_OPTIONS (bs);
|
|
return bs->opt;
|
|
}
|
|
|
|
static Bool
|
|
blurSetScreenOption (CompPlugin *plugin,
|
|
CompScreen *screen,
|
|
const char *name,
|
|
CompOptionValue *value)
|
|
{
|
|
CompOption *o;
|
|
int index, filter;
|
|
|
|
BLUR_SCREEN (screen);
|
|
|
|
o = compFindOption (bs->opt, NUM_OPTIONS (bs), name, &index);
|
|
if (!o)
|
|
return FALSE;
|
|
|
|
switch (index) {
|
|
case BLUR_SCREEN_OPTION_BLUR_SPEED:
|
|
if (compSetFloatOption (o, value))
|
|
{
|
|
bs->blurTime = 1000.0f / o->value.f;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case BLUR_SCREEN_OPTION_FOCUS_BLUR_MATCH:
|
|
case BLUR_SCREEN_OPTION_ALPHA_BLUR_MATCH:
|
|
if (compSetMatchOption (o, value))
|
|
{
|
|
CompWindow *w;
|
|
|
|
for (w = screen->windows; w; w = w->next)
|
|
blurUpdateWindowMatch (bs, w);
|
|
|
|
bs->moreBlur = TRUE;
|
|
damageScreen (screen);
|
|
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case BLUR_SCREEN_OPTION_FOCUS_BLUR:
|
|
if (compSetBoolOption (o, value))
|
|
{
|
|
bs->moreBlur = TRUE;
|
|
damageScreen (screen);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case BLUR_SCREEN_OPTION_ALPHA_BLUR:
|
|
if (compSetBoolOption (o, value))
|
|
{
|
|
if (screen->fragmentProgram && o->value.b)
|
|
bs->alphaBlur = TRUE;
|
|
else
|
|
bs->alphaBlur = FALSE;
|
|
|
|
damageScreen (screen);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case BLUR_SCREEN_OPTION_FILTER:
|
|
if (compSetIntOption (o, value))
|
|
{
|
|
blurReset (screen);
|
|
damageScreen (screen);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case BLUR_SCREEN_OPTION_GAUSSIAN_RADIUS:
|
|
if (compSetIntOption (o, value))
|
|
{
|
|
filter = bs->opt[BLUR_SCREEN_OPTION_FILTER].value.i;
|
|
if (filter == BLUR_FILTER_GAUSSIAN)
|
|
{
|
|
blurReset (screen);
|
|
damageScreen (screen);
|
|
}
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case BLUR_SCREEN_OPTION_GAUSSIAN_STRENGTH:
|
|
if (compSetFloatOption (o, value))
|
|
{
|
|
filter = bs->opt[BLUR_SCREEN_OPTION_FILTER].value.i;
|
|
if (filter == BLUR_FILTER_GAUSSIAN)
|
|
{
|
|
blurReset (screen);
|
|
damageScreen (screen);
|
|
}
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case BLUR_SCREEN_OPTION_MIPMAP_LOD:
|
|
if (compSetFloatOption (o, value))
|
|
{
|
|
filter = bs->opt[BLUR_SCREEN_OPTION_FILTER].value.i;
|
|
if (filter == BLUR_FILTER_MIPMAP)
|
|
{
|
|
blurReset (screen);
|
|
damageScreen (screen);
|
|
}
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case BLUR_SCREEN_OPTION_SATURATION:
|
|
if (compSetIntOption (o, value))
|
|
{
|
|
blurReset (screen);
|
|
damageScreen (screen);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case BLUR_SCREEN_OPTION_BLUR_OCCLUSION:
|
|
if (compSetBoolOption (o, value))
|
|
{
|
|
bs->blurOcclusion = o->value.b;
|
|
blurReset (screen);
|
|
damageScreen (screen);
|
|
return TRUE;
|
|
}
|
|
case BLUR_SCREEN_OPTION_INDEPENDENT_TEX:
|
|
if (compSetBoolOption (o, value))
|
|
{
|
|
filter = bs->opt[BLUR_SCREEN_OPTION_FILTER].value.i;
|
|
if (filter == BLUR_FILTER_GAUSSIAN)
|
|
{
|
|
blurReset (screen);
|
|
damageScreen (screen);
|
|
}
|
|
return TRUE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
blurWindowUpdate (CompWindow *w,
|
|
int state)
|
|
{
|
|
Atom actual;
|
|
int result, format;
|
|
unsigned long n, left;
|
|
unsigned char *propData;
|
|
int threshold = 0;
|
|
BlurBox *box = NULL;
|
|
int nBox = 0;
|
|
|
|
BLUR_DISPLAY (w->screen->display);
|
|
BLUR_SCREEN (w->screen);
|
|
BLUR_WINDOW (w);
|
|
|
|
result = XGetWindowProperty (w->screen->display->display, w->id,
|
|
bd->blurAtom[state], 0L, 8192L, FALSE,
|
|
XA_INTEGER, &actual, &format,
|
|
&n, &left, &propData);
|
|
|
|
if (result == Success && propData)
|
|
{
|
|
bw->propSet[state] = TRUE;
|
|
|
|
if (n >= 2)
|
|
{
|
|
long *data = (long *) propData;
|
|
|
|
threshold = data[0];
|
|
|
|
nBox = (n - 2) / 6;
|
|
if (nBox)
|
|
{
|
|
box = malloc (sizeof (BlurBox) * nBox);
|
|
if (box)
|
|
{
|
|
int i;
|
|
|
|
data += 2;
|
|
|
|
for (i = 0; i < nBox; i++)
|
|
{
|
|
box[i].p1.gravity = *data++;
|
|
box[i].p1.x = *data++;
|
|
box[i].p1.y = *data++;
|
|
box[i].p2.gravity = *data++;
|
|
box[i].p2.x = *data++;
|
|
box[i].p2.y = *data++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
XFree (propData);
|
|
}
|
|
else
|
|
{
|
|
bw->propSet[state] = FALSE;
|
|
}
|
|
|
|
blurSetWindowBlur (w,
|
|
state,
|
|
threshold,
|
|
box,
|
|
nBox);
|
|
|
|
blurUpdateAlphaWindowMatch (bs, w);
|
|
}
|
|
|
|
static void
|
|
blurPreparePaintScreen (CompScreen *s,
|
|
int msSinceLastPaint)
|
|
{
|
|
BLUR_SCREEN (s);
|
|
|
|
if (bs->moreBlur)
|
|
{
|
|
CompWindow *w;
|
|
int steps;
|
|
Bool focus = bs->opt[BLUR_SCREEN_OPTION_FOCUS_BLUR].value.b;
|
|
Bool focusBlur;
|
|
|
|
steps = (msSinceLastPaint * 0xffff) / bs->blurTime;
|
|
if (steps < 12)
|
|
steps = 12;
|
|
|
|
bs->moreBlur = FALSE;
|
|
|
|
for (w = s->windows; w; w = w->next)
|
|
{
|
|
BLUR_WINDOW (w);
|
|
|
|
focusBlur = bw->focusBlur && focus;
|
|
|
|
if (!bw->pulse && (!focusBlur || w->id == s->display->activeWindow))
|
|
{
|
|
if (bw->blur)
|
|
{
|
|
bw->blur -= steps;
|
|
if (bw->blur > 0)
|
|
bs->moreBlur = TRUE;
|
|
else
|
|
bw->blur = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bw->blur < 0xffff)
|
|
{
|
|
if (bw->pulse)
|
|
{
|
|
bw->blur += steps * 2;
|
|
|
|
if (bw->blur >= 0xffff)
|
|
{
|
|
bw->blur = 0xffff - 1;
|
|
bw->pulse = FALSE;
|
|
}
|
|
|
|
bs->moreBlur = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bw->blur += steps;
|
|
if (bw->blur < 0xffff)
|
|
bs->moreBlur = TRUE;
|
|
else
|
|
bw->blur = 0xffff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
UNWRAP (bs, s, preparePaintScreen);
|
|
(*s->preparePaintScreen) (s, msSinceLastPaint);
|
|
WRAP (bs, s, preparePaintScreen, blurPreparePaintScreen);
|
|
|
|
if (s->damageMask & COMP_SCREEN_DAMAGE_REGION_MASK)
|
|
{
|
|
/* walk from bottom to top and expand damage */
|
|
if (bs->alphaBlur)
|
|
{
|
|
CompWindow *w;
|
|
int x1, y1, x2, y2;
|
|
int count = 0;
|
|
|
|
for (w = s->windows; w; w = w->next)
|
|
{
|
|
BLUR_WINDOW (w);
|
|
|
|
if (w->attrib.map_state != IsViewable || !w->damaged)
|
|
continue;
|
|
|
|
if (bw->region)
|
|
{
|
|
x1 = bw->region->extents.x1 - bs->filterRadius;
|
|
y1 = bw->region->extents.y1 - bs->filterRadius;
|
|
x2 = bw->region->extents.x2 + bs->filterRadius;
|
|
y2 = bw->region->extents.y2 + bs->filterRadius;
|
|
|
|
if (x1 < s->damage->extents.x2 &&
|
|
y1 < s->damage->extents.y2 &&
|
|
x2 > s->damage->extents.x1 &&
|
|
y2 > s->damage->extents.y1)
|
|
{
|
|
XShrinkRegion (s->damage,
|
|
-bs->filterRadius,
|
|
-bs->filterRadius);
|
|
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
bs->count = count;
|
|
}
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
blurPaintOutput (CompScreen *s,
|
|
const ScreenPaintAttrib *sAttrib,
|
|
const CompTransform *transform,
|
|
Region region,
|
|
CompOutput *output,
|
|
unsigned int mask)
|
|
{
|
|
Bool status;
|
|
|
|
BLUR_SCREEN (s);
|
|
|
|
if (bs->alphaBlur)
|
|
{
|
|
bs->stencilBox = region->extents;
|
|
XSubtractRegion (region, &emptyRegion, bs->region);
|
|
|
|
if (mask & PAINT_SCREEN_REGION_MASK)
|
|
{
|
|
/* we need to redraw more than the screen region being updated */
|
|
if (bs->count)
|
|
{
|
|
XShrinkRegion (bs->region,
|
|
-bs->filterRadius * 2,
|
|
-bs->filterRadius * 2);
|
|
XIntersectRegion (bs->region, &s->region, bs->region);
|
|
|
|
region = bs->region;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bs->blurOcclusion)
|
|
{
|
|
CompWindow *w;
|
|
|
|
XSubtractRegion (&emptyRegion, &emptyRegion, bs->occlusion);
|
|
|
|
for (w = s->windows; w; w = w->next)
|
|
XSubtractRegion (&emptyRegion, &emptyRegion,
|
|
GET_BLUR_WINDOW (w, bs)->clip);
|
|
}
|
|
|
|
bs->output = output;
|
|
|
|
UNWRAP (bs, s, paintOutput);
|
|
status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
|
|
WRAP (bs, s, paintOutput, blurPaintOutput);
|
|
|
|
return status;
|
|
}
|
|
|
|
static void
|
|
blurPaintTransformedOutput (CompScreen *s,
|
|
const ScreenPaintAttrib *sAttrib,
|
|
const CompTransform *transform,
|
|
Region region,
|
|
CompOutput *output,
|
|
unsigned int mask)
|
|
{
|
|
BLUR_SCREEN (s);
|
|
|
|
if (!bs->blurOcclusion)
|
|
{
|
|
CompWindow *w;
|
|
|
|
XSubtractRegion (&emptyRegion, &emptyRegion, bs->occlusion);
|
|
|
|
for (w = s->windows; w; w = w->next)
|
|
XSubtractRegion (&emptyRegion, &emptyRegion,
|
|
GET_BLUR_WINDOW (w, bs)->clip);
|
|
}
|
|
|
|
UNWRAP (bs, s, paintTransformedOutput);
|
|
(*s->paintTransformedOutput) (s, sAttrib, transform,
|
|
region, output, mask);
|
|
WRAP (bs, s, paintTransformedOutput, blurPaintTransformedOutput);
|
|
}
|
|
|
|
static void
|
|
blurDonePaintScreen (CompScreen *s)
|
|
{
|
|
BLUR_SCREEN (s);
|
|
|
|
if (bs->moreBlur)
|
|
{
|
|
CompWindow *w;
|
|
|
|
for (w = s->windows; w; w = w->next)
|
|
{
|
|
BLUR_WINDOW (w);
|
|
|
|
if (bw->blur > 0 && bw->blur < 0xffff)
|
|
addWindowDamage (w);
|
|
}
|
|
}
|
|
|
|
UNWRAP (bs, s, donePaintScreen);
|
|
(*s->donePaintScreen) (s);
|
|
WRAP (bs, s, donePaintScreen, blurDonePaintScreen);
|
|
}
|
|
|
|
static Bool
|
|
blurPaintWindow (CompWindow *w,
|
|
const WindowPaintAttrib *attrib,
|
|
const CompTransform *transform,
|
|
Region region,
|
|
unsigned int mask)
|
|
{
|
|
CompScreen *s = w->screen;
|
|
Bool status;
|
|
|
|
BLUR_SCREEN (s);
|
|
BLUR_WINDOW (w);
|
|
|
|
UNWRAP (bs, s, paintWindow);
|
|
status = (*s->paintWindow) (w, attrib, transform, region, mask);
|
|
WRAP (bs, s, paintWindow, blurPaintWindow);
|
|
|
|
if (!bs->blurOcclusion && (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK))
|
|
{
|
|
XSubtractRegion (bs->occlusion, &emptyRegion, bw->clip);
|
|
|
|
if (!(w->lastMask & PAINT_WINDOW_NO_CORE_INSTANCE_MASK) &&
|
|
!(w->lastMask & PAINT_WINDOW_TRANSFORMED_MASK) && bw->region)
|
|
XUnionRegion (bs->occlusion, bw->region, bs->occlusion);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static int
|
|
getSrcBlurFragmentFunction (CompScreen *s,
|
|
CompTexture *texture,
|
|
int param)
|
|
{
|
|
BlurFunction *function;
|
|
CompFunctionData *data;
|
|
int target;
|
|
|
|
BLUR_SCREEN (s);
|
|
|
|
if (texture->target == GL_TEXTURE_2D)
|
|
target = COMP_FETCH_TARGET_2D;
|
|
else
|
|
target = COMP_FETCH_TARGET_RECT;
|
|
|
|
for (function = bs->srcBlurFunctions; function; function = function->next)
|
|
if (function->param == param && function->target == target)
|
|
return function->handle;
|
|
|
|
data = createFunctionData ();
|
|
if (data)
|
|
{
|
|
static char *temp[] = { "offset0", "offset1", "sum" };
|
|
int i, handle = 0;
|
|
char str[1024];
|
|
Bool ok = TRUE;
|
|
|
|
for (i = 0; i < sizeof (temp) / sizeof (temp[0]); i++)
|
|
ok &= addTempHeaderOpToFunctionData (data, temp[i]);
|
|
|
|
snprintf (str, 1024,
|
|
"MUL offset0, program.env[%d].xyzw, { 1.0, 1.0, 0.0, 0.0 };"
|
|
"MUL offset1, program.env[%d].zwww, { 1.0, 1.0, 0.0, 0.0 };",
|
|
param, param);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
switch (bs->opt[BLUR_SCREEN_OPTION_FILTER].value.i) {
|
|
case BLUR_FILTER_4X_BILINEAR:
|
|
default:
|
|
ok &= addFetchOpToFunctionData (data, "output", "offset0", target);
|
|
ok &= addDataOpToFunctionData (data, "MUL sum, output, 0.25;");
|
|
ok &= addFetchOpToFunctionData (data, "output", "-offset0", target);
|
|
ok &= addDataOpToFunctionData (data, "MAD sum, output, 0.25, sum;");
|
|
ok &= addFetchOpToFunctionData (data, "output", "offset1", target);
|
|
ok &= addDataOpToFunctionData (data, "MAD sum, output, 0.25, sum;");
|
|
ok &= addFetchOpToFunctionData (data, "output", "-offset1", target);
|
|
ok &= addDataOpToFunctionData (data,
|
|
"MAD output, output, 0.25, sum;");
|
|
break;
|
|
}
|
|
|
|
if (!ok)
|
|
{
|
|
destroyFunctionData (data);
|
|
return 0;
|
|
}
|
|
|
|
function = malloc (sizeof (BlurFunction));
|
|
if (function)
|
|
{
|
|
handle = createFragmentFunction (s, "blur", data);
|
|
|
|
function->handle = handle;
|
|
function->target = target;
|
|
function->param = param;
|
|
function->unit = 0;
|
|
|
|
function->next = bs->srcBlurFunctions;
|
|
bs->srcBlurFunctions = function;
|
|
}
|
|
|
|
destroyFunctionData (data);
|
|
|
|
return handle;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
getDstBlurFragmentFunction (CompScreen *s,
|
|
CompTexture *texture,
|
|
int param,
|
|
int unit,
|
|
int numITC,
|
|
int startTC)
|
|
{
|
|
BlurFunction *function;
|
|
CompFunctionData *data;
|
|
int target;
|
|
char *targetString;
|
|
|
|
BLUR_SCREEN (s);
|
|
|
|
if (texture->target == GL_TEXTURE_2D)
|
|
{
|
|
target = COMP_FETCH_TARGET_2D;
|
|
targetString = "2D";
|
|
}
|
|
else
|
|
{
|
|
target = COMP_FETCH_TARGET_RECT;
|
|
targetString = "RECT";
|
|
}
|
|
|
|
for (function = bs->dstBlurFunctions; function; function = function->next)
|
|
if (function->param == param &&
|
|
function->target == target &&
|
|
function->unit == unit &&
|
|
function->numITC == numITC &&
|
|
function->startTC == startTC)
|
|
return function->handle;
|
|
|
|
data = createFunctionData ();
|
|
if (data)
|
|
{
|
|
static char *temp[] = { "fCoord", "mask", "sum", "dst" };
|
|
int i, j, handle = 0;
|
|
char str[1024];
|
|
int saturation = bs->opt[BLUR_SCREEN_OPTION_SATURATION].value.i;
|
|
Bool ok = TRUE;
|
|
int numIndirect;
|
|
int numIndirectOp;
|
|
int base, end, ITCbase;
|
|
|
|
for (i = 0; i < sizeof (temp) / sizeof (temp[0]); i++)
|
|
ok &= addTempHeaderOpToFunctionData (data, temp[i]);
|
|
|
|
if (saturation < 100)
|
|
ok &= addTempHeaderOpToFunctionData (data, "sat");
|
|
|
|
switch (bs->opt[BLUR_SCREEN_OPTION_FILTER].value.i) {
|
|
case BLUR_FILTER_4X_BILINEAR: {
|
|
static char *filterTemp[] = {
|
|
"t0", "t1", "t2", "t3",
|
|
"s0", "s1", "s2", "s3"
|
|
};
|
|
|
|
for (i = 0; i < sizeof (filterTemp) / sizeof (filterTemp[0]); i++)
|
|
ok &= addTempHeaderOpToFunctionData (data, filterTemp[i]);
|
|
|
|
ok &= addFetchOpToFunctionData (data, "output", NULL, target);
|
|
ok &= addColorOpToFunctionData (data, "output", "output");
|
|
|
|
snprintf (str, 1024,
|
|
"MUL fCoord, fragment.position, program.env[%d];",
|
|
param);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
snprintf (str, 1024,
|
|
"ADD t0, fCoord, program.env[%d];"
|
|
"TEX s0, t0, texture[%d], %s;"
|
|
|
|
"SUB t1, fCoord, program.env[%d];"
|
|
"TEX s1, t1, texture[%d], %s;"
|
|
|
|
"MAD t2, program.env[%d], { -1.0, 1.0, 0.0, 0.0 }, fCoord;"
|
|
"TEX s2, t2, texture[%d], %s;"
|
|
|
|
"MAD t3, program.env[%d], { 1.0, -1.0, 0.0, 0.0 }, fCoord;"
|
|
"TEX s3, t3, texture[%d], %s;"
|
|
|
|
"MUL_SAT mask, output.a, program.env[%d];"
|
|
|
|
"MUL sum, s0, 0.25;"
|
|
"MAD sum, s1, 0.25, sum;"
|
|
"MAD sum, s2, 0.25, sum;"
|
|
"MAD sum, s3, 0.25, sum;",
|
|
|
|
param + 2, unit, targetString,
|
|
param + 2, unit, targetString,
|
|
param + 2, unit, targetString,
|
|
param + 2, unit, targetString,
|
|
param + 1);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
} break;
|
|
case BLUR_FILTER_GAUSSIAN: {
|
|
|
|
/* try to use only half of the available temporaries to keep
|
|
other plugins working */
|
|
if ((bs->maxTemp / 2) - 4 >
|
|
(bs->numTexop + (bs->numTexop - numITC)) * 2)
|
|
{
|
|
numIndirect = 1;
|
|
numIndirectOp = bs->numTexop;
|
|
}
|
|
else
|
|
{
|
|
i = MAX(((bs->maxTemp / 2) - 4) / 4, 1);
|
|
numIndirect = ceil ((float)bs->numTexop / (float)i);
|
|
numIndirectOp = ceil ((float)bs->numTexop / (float)numIndirect);
|
|
}
|
|
|
|
/* we need to define all coordinate temporaries if we have
|
|
multiple indirection steps */
|
|
j = (numIndirect > 1) ? 0 : numITC;
|
|
|
|
for (i = 0; i < numIndirectOp * 2; i++)
|
|
{
|
|
snprintf (str, 1024, "pix_%d", i);
|
|
ok &= addTempHeaderOpToFunctionData (data, str);
|
|
}
|
|
|
|
for (i = j * 2; i < numIndirectOp * 2; i++)
|
|
{
|
|
snprintf (str, 1024, "coord_%d", i);
|
|
ok &= addTempHeaderOpToFunctionData (data, str);
|
|
}
|
|
|
|
ok &= addFetchOpToFunctionData (data, "output", NULL, target);
|
|
ok &= addColorOpToFunctionData (data, "output", "output");
|
|
|
|
snprintf (str, 1024,
|
|
"MUL fCoord, fragment.position, program.env[%d];",
|
|
param);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
snprintf (str, 1024,
|
|
"TEX sum, fCoord, texture[%d], %s;",
|
|
unit + 1, targetString);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
snprintf (str, 1024,
|
|
"MUL_SAT mask, output.a, program.env[%d];"
|
|
"MUL sum, sum, %f;",
|
|
param + 1, bs->amp[bs->numTexop]);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
for (j = 0; j < numIndirect; j++)
|
|
{
|
|
base = j * numIndirectOp;
|
|
end = MIN ((j + 1) * numIndirectOp, bs->numTexop) - base;
|
|
|
|
ITCbase = MAX (numITC - base, 0);
|
|
|
|
for (i = ITCbase; i < end; i++)
|
|
{
|
|
snprintf (str, 1024,
|
|
"ADD coord_%d, fCoord, {0.0, %g, 0.0, 0.0};"
|
|
"SUB coord_%d, fCoord, {0.0, %g, 0.0, 0.0};",
|
|
i * 2, bs->pos[base + i] * bs->ty,
|
|
(i * 2) + 1, bs->pos[base + i] * bs->ty);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
}
|
|
|
|
for (i = 0; i < ITCbase; i++)
|
|
{
|
|
snprintf (str, 1024,
|
|
"TXP pix_%d, fragment.texcoord[%d], texture[%d], %s;"
|
|
"TXP pix_%d, fragment.texcoord[%d], texture[%d], %s;",
|
|
i * 2, startTC + ((i + base) * 2),
|
|
unit + 1, targetString,
|
|
(i * 2) + 1, startTC + 1 + ((i + base) * 2),
|
|
unit + 1, targetString);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
}
|
|
|
|
for (i = ITCbase; i < end; i++)
|
|
{
|
|
snprintf (str, 1024,
|
|
"TEX pix_%d, coord_%d, texture[%d], %s;"
|
|
"TEX pix_%d, coord_%d, texture[%d], %s;",
|
|
i * 2, i * 2,
|
|
unit + 1, targetString,
|
|
(i * 2) + 1, (i * 2) + 1,
|
|
unit + 1, targetString);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
}
|
|
|
|
for (i = 0; i < end * 2; i++)
|
|
{
|
|
snprintf (str, 1024,
|
|
"MAD sum, pix_%d, %f, sum;",
|
|
i, bs->amp[base + (i / 2)]);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
}
|
|
}
|
|
|
|
} break;
|
|
case BLUR_FILTER_MIPMAP:
|
|
ok &= addFetchOpToFunctionData (data, "output", NULL, target);
|
|
ok &= addColorOpToFunctionData (data, "output", "output");
|
|
|
|
snprintf (str, 1024,
|
|
"MUL fCoord, fragment.position, program.env[%d].xyzz;"
|
|
"MOV fCoord.w, program.env[%d].w;"
|
|
"TXB sum, fCoord, texture[%d], %s;"
|
|
"MUL_SAT mask, output.a, program.env[%d];",
|
|
param, param, unit, targetString,
|
|
param + 1);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
break;
|
|
}
|
|
|
|
if (saturation < 100)
|
|
{
|
|
snprintf (str, 1024,
|
|
"MUL sat, sum, { 1.0, 1.0, 1.0, 0.0 };"
|
|
"DP3 sat, sat, { %f, %f, %f, %f };"
|
|
"LRP sum.xyz, %f, sum, sat;",
|
|
RED_SATURATION_WEIGHT, GREEN_SATURATION_WEIGHT,
|
|
BLUE_SATURATION_WEIGHT, 0.0f, saturation / 100.0f);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
}
|
|
|
|
snprintf (str, 1024,
|
|
"MAD dst, mask, -output.a, mask;"
|
|
"MAD output.rgb, sum, dst.a, output;"
|
|
"ADD output.a, output.a, dst.a;");
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
if (!ok)
|
|
{
|
|
destroyFunctionData (data);
|
|
return 0;
|
|
}
|
|
|
|
function = malloc (sizeof (BlurFunction));
|
|
if (function)
|
|
{
|
|
handle = createFragmentFunction (s, "blur", data);
|
|
|
|
function->handle = handle;
|
|
function->target = target;
|
|
function->param = param;
|
|
function->unit = unit;
|
|
function->numITC = numITC;
|
|
function->startTC = startTC;
|
|
|
|
function->next = bs->dstBlurFunctions;
|
|
bs->dstBlurFunctions = function;
|
|
}
|
|
|
|
destroyFunctionData (data);
|
|
|
|
return handle;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Bool
|
|
projectVertices (CompScreen *s,
|
|
CompOutput *output,
|
|
const CompTransform *transform,
|
|
const float *object,
|
|
float *screen,
|
|
int n)
|
|
{
|
|
GLdouble dProjection[16];
|
|
GLdouble dModel[16];
|
|
GLint viewport[4];
|
|
double x, y, z;
|
|
int i;
|
|
|
|
viewport[0] = output->region.extents.x1;
|
|
viewport[1] = s->height - output->region.extents.y2;
|
|
viewport[2] = output->width;
|
|
viewport[3] = output->height;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
dModel[i] = transform->m[i];
|
|
dProjection[i] = s->projection[i];
|
|
}
|
|
|
|
while (n--)
|
|
{
|
|
if (!gluProject (object[0], object[1], object[2],
|
|
dModel, dProjection, viewport,
|
|
&x, &y, &z))
|
|
return FALSE;
|
|
|
|
screen[0] = x;
|
|
screen[1] = y;
|
|
|
|
object += 3;
|
|
screen += 2;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
loadFragmentProgram (CompScreen *s,
|
|
GLuint *program,
|
|
const char *string)
|
|
{
|
|
GLint errorPos;
|
|
|
|
/* clear errors */
|
|
glGetError ();
|
|
|
|
if (!*program)
|
|
(*s->genPrograms) (1, program);
|
|
|
|
(*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, *program);
|
|
(*s->programString) (GL_FRAGMENT_PROGRAM_ARB,
|
|
GL_PROGRAM_FORMAT_ASCII_ARB,
|
|
strlen (string), string);
|
|
|
|
glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
|
|
if (glGetError () != GL_NO_ERROR || errorPos != -1)
|
|
{
|
|
compLogMessage ("blur", CompLogLevelError,
|
|
"Failed to load blur program %s", string);
|
|
|
|
(*s->deletePrograms) (1, program);
|
|
*program = 0;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
loadFilterProgram (CompScreen *s, int numITC)
|
|
{
|
|
char buffer[4096];
|
|
char *targetString;
|
|
char *str = buffer;
|
|
int i, j;
|
|
int numIndirect;
|
|
int numIndirectOp;
|
|
int base, end, ITCbase;
|
|
|
|
BLUR_SCREEN (s);
|
|
|
|
if (bs->target == GL_TEXTURE_2D)
|
|
targetString = "2D";
|
|
else
|
|
targetString = "RECT";
|
|
|
|
str += sprintf (str,
|
|
"!!ARBfp1.0"
|
|
"ATTRIB texcoord = fragment.texcoord[0];"
|
|
"TEMP sum;");
|
|
|
|
if (bs->maxTemp - 1 > (bs->numTexop + (bs->numTexop - numITC)) * 2)
|
|
{
|
|
numIndirect = 1;
|
|
numIndirectOp = bs->numTexop;
|
|
}
|
|
else
|
|
{
|
|
i = (bs->maxTemp - 1) / 4;
|
|
numIndirect = ceil ((float)bs->numTexop / (float)i);
|
|
numIndirectOp = ceil ((float)bs->numTexop / (float)numIndirect);
|
|
}
|
|
|
|
/* we need to define all coordinate temporaries if we have
|
|
multiple indirection steps */
|
|
j = (numIndirect > 1) ? 0 : numITC;
|
|
|
|
for (i = 0; i < numIndirectOp; i++)
|
|
str += sprintf (str,"TEMP pix_%d, pix_%d;", i * 2, (i * 2) + 1);
|
|
|
|
for (i = j; i < numIndirectOp; i++)
|
|
str += sprintf (str,"TEMP coord_%d, coord_%d;", i * 2, (i * 2) + 1);
|
|
|
|
str += sprintf (str,
|
|
"TEX sum, texcoord, texture[0], %s;",
|
|
targetString);
|
|
|
|
str += sprintf (str,
|
|
"MUL sum, sum, %f;",
|
|
bs->amp[bs->numTexop]);
|
|
|
|
for (j = 0; j < numIndirect; j++)
|
|
{
|
|
base = j * numIndirectOp;
|
|
end = MIN ((j + 1) * numIndirectOp, bs->numTexop) - base;
|
|
|
|
ITCbase = MAX (numITC - base, 0);
|
|
|
|
for (i = ITCbase; i < end; i++)
|
|
str += sprintf (str,
|
|
"ADD coord_%d, texcoord, {%g, 0.0, 0.0, 0.0};"
|
|
"SUB coord_%d, texcoord, {%g, 0.0, 0.0, 0.0};",
|
|
i * 2, bs->pos[base + i] * bs->tx,
|
|
(i * 2) + 1, bs->pos[base + i] * bs->tx);
|
|
|
|
for (i = 0; i < ITCbase; i++)
|
|
str += sprintf (str,
|
|
"TEX pix_%d, fragment.texcoord[%d], texture[0], %s;"
|
|
"TEX pix_%d, fragment.texcoord[%d], texture[0], %s;",
|
|
i * 2, ((i + base) * 2) + 1, targetString,
|
|
(i * 2) + 1, ((i + base) * 2) + 2, targetString);
|
|
|
|
for (i = ITCbase; i < end; i++)
|
|
str += sprintf (str,
|
|
"TEX pix_%d, coord_%d, texture[0], %s;"
|
|
"TEX pix_%d, coord_%d, texture[0], %s;",
|
|
i * 2, i * 2, targetString,
|
|
(i * 2) + 1, (i * 2) + 1, targetString);
|
|
|
|
for (i = 0; i < end * 2; i++)
|
|
str += sprintf (str,
|
|
"MAD sum, pix_%d, %f, sum;",
|
|
i, bs->amp[base + (i / 2)]);
|
|
}
|
|
|
|
str += sprintf (str,
|
|
"MOV result.color, sum;"
|
|
"END");
|
|
|
|
return loadFragmentProgram (s, &bs->program, buffer);
|
|
}
|
|
|
|
static int
|
|
fboPrologue (CompScreen *s)
|
|
{
|
|
BLUR_SCREEN (s);
|
|
|
|
if (!bs->fbo)
|
|
return FALSE;
|
|
|
|
(*s->bindFramebuffer) (GL_FRAMEBUFFER_EXT, bs->fbo);
|
|
|
|
/* bind texture and check status the first time */
|
|
if (!bs->fboStatus)
|
|
{
|
|
(*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
|
|
GL_COLOR_ATTACHMENT0_EXT,
|
|
bs->target, bs->texture[1],
|
|
0);
|
|
|
|
bs->fboStatus = (*s->checkFramebufferStatus) (GL_FRAMEBUFFER_EXT);
|
|
if (bs->fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
|
|
{
|
|
compLogMessage ("blur", CompLogLevelError,
|
|
"Framebuffer incomplete");
|
|
|
|
(*s->bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
|
|
(*s->deleteFramebuffers) (1, &bs->fbo);
|
|
|
|
bs->fbo = 0;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
glPushAttrib (GL_VIEWPORT_BIT | GL_ENABLE_BIT);
|
|
|
|
glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
|
|
glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
|
|
|
|
glDisable (GL_CLIP_PLANE0);
|
|
glDisable (GL_CLIP_PLANE1);
|
|
glDisable (GL_CLIP_PLANE2);
|
|
glDisable (GL_CLIP_PLANE3);
|
|
|
|
glViewport (0, 0, bs->width, bs->height);
|
|
glMatrixMode (GL_PROJECTION);
|
|
glPushMatrix ();
|
|
glLoadIdentity ();
|
|
glOrtho (0.0, bs->width, 0.0, bs->height, -1.0, 1.0);
|
|
glMatrixMode (GL_MODELVIEW);
|
|
glPushMatrix ();
|
|
glLoadIdentity ();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
fboEpilogue (CompScreen *s)
|
|
{
|
|
(*s->bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
|
|
|
|
glMatrixMode (GL_PROJECTION);
|
|
glLoadIdentity ();
|
|
glMatrixMode (GL_MODELVIEW);
|
|
glLoadIdentity ();
|
|
glDepthRange (0, 1);
|
|
glViewport (-1, -1, 2, 2);
|
|
glRasterPos2f (0, 0);
|
|
|
|
s->rasterX = s->rasterY = 0;
|
|
|
|
glMatrixMode (GL_PROJECTION);
|
|
glPopMatrix ();
|
|
glMatrixMode (GL_MODELVIEW);
|
|
glPopMatrix ();
|
|
|
|
glDrawBuffer (GL_BACK);
|
|
glReadBuffer (GL_BACK);
|
|
|
|
glPopAttrib ();
|
|
}
|
|
|
|
static Bool
|
|
fboUpdate (CompScreen *s,
|
|
BoxPtr pBox,
|
|
int nBox)
|
|
{
|
|
int i, y, iTC = 0;
|
|
Bool wasCulled = glIsEnabled (GL_CULL_FACE);
|
|
|
|
BLUR_SCREEN (s);
|
|
|
|
if (s->maxTextureUnits &&
|
|
bs->opt[BLUR_SCREEN_OPTION_INDEPENDENT_TEX].value.b)
|
|
iTC = MIN ((s->maxTextureUnits - 1) / 2, bs->numTexop);
|
|
|
|
if (!bs->program)
|
|
if (!loadFilterProgram (s, iTC))
|
|
return FALSE;
|
|
|
|
if (!fboPrologue (s))
|
|
return FALSE;
|
|
|
|
glDisable (GL_CULL_FACE);
|
|
|
|
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
|
|
|
|
glBindTexture (bs->target, bs->texture[0]);
|
|
|
|
glEnable (GL_FRAGMENT_PROGRAM_ARB);
|
|
(*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, bs->program);
|
|
|
|
glBegin (GL_QUADS);
|
|
|
|
while (nBox--)
|
|
{
|
|
y = s->height - pBox->y2;
|
|
|
|
for (i = 0; i < iTC; i++)
|
|
{
|
|
(*s->multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
|
|
bs->tx * (pBox->x1 + bs->pos[i]),
|
|
bs->ty * y);
|
|
(*s->multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
|
|
bs->tx * (pBox->x1 - bs->pos[i]),
|
|
bs->ty * y);
|
|
}
|
|
|
|
glTexCoord2f (bs->tx * pBox->x1, bs->ty * y);
|
|
glVertex2i (pBox->x1, y);
|
|
|
|
for (i = 0; i < iTC; i++)
|
|
{
|
|
(*s->multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
|
|
bs->tx * (pBox->x2 + bs->pos[i]),
|
|
bs->ty * y);
|
|
(*s->multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
|
|
bs->tx * (pBox->x2 - bs->pos[i]),
|
|
bs->ty * y);
|
|
}
|
|
|
|
glTexCoord2f (bs->tx * pBox->x2, bs->ty * y);
|
|
glVertex2i (pBox->x2, y);
|
|
|
|
y = s->height - pBox->y1;
|
|
|
|
for (i = 0; i < iTC; i++)
|
|
{
|
|
(*s->multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
|
|
bs->tx * (pBox->x2 + bs->pos[i]),
|
|
bs->ty * y);
|
|
(*s->multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
|
|
bs->tx * (pBox->x2 - bs->pos[i]),
|
|
bs->ty * y);
|
|
}
|
|
|
|
glTexCoord2f (bs->tx * pBox->x2, bs->ty * y);
|
|
glVertex2i (pBox->x2, y);
|
|
|
|
for (i = 0; i < iTC; i++)
|
|
{
|
|
(*s->multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
|
|
bs->tx * (pBox->x1 + bs->pos[i]),
|
|
bs->ty * y);
|
|
(*s->multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
|
|
bs->tx * (pBox->x1 - bs->pos[i]),
|
|
bs->ty * y);
|
|
}
|
|
|
|
glTexCoord2f (bs->tx * pBox->x1, bs->ty * y);
|
|
glVertex2i (pBox->x1, y);
|
|
|
|
pBox++;
|
|
}
|
|
|
|
glEnd ();
|
|
|
|
glDisable (GL_FRAGMENT_PROGRAM_ARB);
|
|
|
|
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
|
|
|
|
if (wasCulled)
|
|
glEnable (GL_CULL_FACE);
|
|
|
|
fboEpilogue (s);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#define MAX_VERTEX_PROJECT_COUNT 20
|
|
|
|
static void
|
|
blurProjectRegion (CompWindow *w,
|
|
CompOutput *output,
|
|
const CompTransform *transform)
|
|
{
|
|
CompScreen *s = w->screen;
|
|
float screen[MAX_VERTEX_PROJECT_COUNT * 2];
|
|
float vertices[MAX_VERTEX_PROJECT_COUNT * 3];
|
|
int nVertices, nQuadCombine;
|
|
int i, j, stride;
|
|
float *v, *vert;
|
|
float minX, maxX, minY, maxY, minZ, maxZ;
|
|
float *scr;
|
|
REGION region;
|
|
|
|
BLUR_SCREEN(s);
|
|
|
|
w->vCount = w->indexCount = 0;
|
|
(*w->screen->addWindowGeometry) (w, NULL, 0, bs->tmpRegion2,
|
|
&infiniteRegion);
|
|
|
|
if (!w->vCount)
|
|
return;
|
|
|
|
nVertices = (w->indexCount) ? w->indexCount: w->vCount;
|
|
nQuadCombine = 1;
|
|
|
|
stride = w->vertexStride;
|
|
vert = w->vertices + (stride - 3);
|
|
|
|
/* we need to find the best value here */
|
|
if (nVertices <= MAX_VERTEX_PROJECT_COUNT)
|
|
{
|
|
for (i = 0; i < nVertices; i++)
|
|
{
|
|
if (w->indexCount)
|
|
{
|
|
v = vert + (stride * w->indices[i]);
|
|
}
|
|
else
|
|
{
|
|
v = vert + (stride * i);
|
|
}
|
|
|
|
vertices[i * 3] = v[0];
|
|
vertices[(i * 3) + 1] = v[1];
|
|
vertices[(i * 3) + 2] = v[2];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
minX = s->width;
|
|
maxX = 0;
|
|
minY = s->height;
|
|
maxY = 0;
|
|
minZ = 1000000;
|
|
maxZ = -1000000;
|
|
|
|
for (i = 0; i < w->vCount; i++)
|
|
{
|
|
v = vert + (stride * i);
|
|
|
|
if (v[0] < minX)
|
|
minX = v[0];
|
|
|
|
if (v[0] > maxX)
|
|
maxX = v[0];
|
|
|
|
if (v[1] < minY)
|
|
minY = v[1];
|
|
|
|
if (v[1] > maxY)
|
|
maxY = v[1];
|
|
|
|
if (v[2] < minZ)
|
|
minZ = v[2];
|
|
|
|
if (v[2] > maxZ)
|
|
maxZ = v[2];
|
|
}
|
|
|
|
vertices[0] = vertices[9] = minX;
|
|
vertices[1] = vertices[4] = minY;
|
|
vertices[3] = vertices[6] = maxX;
|
|
vertices[7] = vertices[10] = maxY;
|
|
vertices[2] = vertices[5] = maxZ;
|
|
vertices[8] = vertices[11] = maxZ;
|
|
|
|
nVertices = 4;
|
|
|
|
if (maxZ != minZ)
|
|
{
|
|
vertices[12] = vertices[21] = minX;
|
|
vertices[13] = vertices[16] = minY;
|
|
vertices[15] = vertices[18] = maxX;
|
|
vertices[19] = vertices[22] = maxY;
|
|
vertices[14] = vertices[17] = minZ;
|
|
vertices[20] = vertices[23] = minZ;
|
|
nQuadCombine = 2;
|
|
}
|
|
}
|
|
|
|
|
|
if (!projectVertices (w->screen, output, transform, vertices, screen,
|
|
nVertices * nQuadCombine))
|
|
return;
|
|
|
|
region.rects = ®ion.extents;
|
|
region.numRects = 1;
|
|
|
|
for (i = 0; i < nVertices / 4; i++)
|
|
{
|
|
scr = screen + (i * 4 * 2);
|
|
|
|
minX = s->width;
|
|
maxX = 0;
|
|
minY = s->height;
|
|
maxY = 0;
|
|
|
|
for (j = 0; j < 8 * nQuadCombine; j += 2)
|
|
{
|
|
if (scr[j] < minX)
|
|
minX = scr[j];
|
|
|
|
if (scr[j] > maxX)
|
|
maxX = scr[j];
|
|
|
|
if (scr[j + 1] < minY)
|
|
minY = scr[j + 1];
|
|
|
|
if (scr[j + 1] > maxY)
|
|
maxY = scr[j + 1];
|
|
}
|
|
|
|
region.extents.x1 = minX - bs->filterRadius;
|
|
region.extents.y1 = (s->height - maxY - bs->filterRadius);
|
|
region.extents.x2 = maxX + bs->filterRadius + 0.5f;
|
|
region.extents.y2 = (s->height - minY + bs->filterRadius + 0.5f);
|
|
|
|
XUnionRegion (®ion, bs->tmpRegion3, bs->tmpRegion3);
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
blurUpdateDstTexture (CompWindow *w,
|
|
const CompTransform *transform,
|
|
BoxPtr pExtents,
|
|
int clientThreshold)
|
|
{
|
|
CompScreen *s = w->screen;
|
|
BoxPtr pBox;
|
|
int nBox;
|
|
int y;
|
|
int filter;
|
|
|
|
BLUR_SCREEN (s);
|
|
BLUR_WINDOW (w);
|
|
|
|
filter = bs->opt[BLUR_SCREEN_OPTION_FILTER].value.i;
|
|
|
|
/* create empty region */
|
|
XSubtractRegion (&emptyRegion, &emptyRegion, bs->tmpRegion3);
|
|
|
|
if (filter == BLUR_FILTER_GAUSSIAN)
|
|
{
|
|
REGION region;
|
|
|
|
region.rects = ®ion.extents;
|
|
region.numRects = 1;
|
|
|
|
if (bw->state[BLUR_STATE_DECOR].threshold)
|
|
{
|
|
/* top */
|
|
region.extents.x1 = w->attrib.x - w->output.left;
|
|
region.extents.y1 = w->attrib.y - w->output.top;
|
|
region.extents.x2 = w->attrib.x + w->width + w->output.right;
|
|
region.extents.y2 = w->attrib.y;
|
|
|
|
XIntersectRegion (bs->tmpRegion, ®ion, bs->tmpRegion2);
|
|
if (bs->tmpRegion2->numRects)
|
|
blurProjectRegion (w, bs->output, transform);
|
|
|
|
/* bottom */
|
|
region.extents.x1 = w->attrib.x - w->output.left;
|
|
region.extents.y1 = w->attrib.y + w->height;
|
|
region.extents.x2 = w->attrib.x + w->width + w->output.right;
|
|
region.extents.y2 = w->attrib.y + w->height + w->output.bottom;
|
|
|
|
XIntersectRegion (bs->tmpRegion, ®ion, bs->tmpRegion2);
|
|
if (bs->tmpRegion2->numRects)
|
|
blurProjectRegion (w, bs->output, transform);
|
|
|
|
/* left */
|
|
region.extents.x1 = w->attrib.x - w->output.left;
|
|
region.extents.y1 = w->attrib.y;
|
|
region.extents.x2 = w->attrib.x;
|
|
region.extents.y2 = w->attrib.y + w->height;
|
|
|
|
XIntersectRegion (bs->tmpRegion, ®ion, bs->tmpRegion2);
|
|
if (bs->tmpRegion2->numRects)
|
|
blurProjectRegion (w, bs->output, transform);
|
|
|
|
/* right */
|
|
region.extents.x1 = w->attrib.x + w->width;
|
|
region.extents.y1 = w->attrib.y;
|
|
region.extents.x2 = w->attrib.x + w->width + w->output.right;
|
|
region.extents.y2 = w->attrib.y + w->height;
|
|
|
|
XIntersectRegion (bs->tmpRegion, ®ion, bs->tmpRegion2);
|
|
if (bs->tmpRegion2->numRects)
|
|
blurProjectRegion (w, bs->output, transform);
|
|
}
|
|
|
|
if (clientThreshold)
|
|
{
|
|
/* center */
|
|
region.extents.x1 = w->attrib.x;
|
|
region.extents.y1 = w->attrib.y;
|
|
region.extents.x2 = w->attrib.x + w->width;
|
|
region.extents.y2 = w->attrib.y + w->height;
|
|
|
|
XIntersectRegion (bs->tmpRegion, ®ion, bs->tmpRegion2);
|
|
if (bs->tmpRegion2->numRects)
|
|
blurProjectRegion (w, bs->output, transform);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* get region that needs blur */
|
|
XSubtractRegion (bs->tmpRegion, &emptyRegion, bs->tmpRegion2);
|
|
|
|
if (bs->tmpRegion2->numRects)
|
|
blurProjectRegion (w, bs->output, transform);
|
|
}
|
|
|
|
XIntersectRegion (bs->tmpRegion3, bs->region, bs->tmpRegion);
|
|
|
|
if (XEmptyRegion (bs->tmpRegion))
|
|
return FALSE;
|
|
|
|
pBox = &bs->tmpRegion->extents;
|
|
nBox = 1;
|
|
|
|
*pExtents = bs->tmpRegion->extents;
|
|
|
|
if (!bs->texture[0] || bs->width != s->width || bs->height != s->height)
|
|
{
|
|
int i, textures = 1;
|
|
|
|
bs->width = s->width;
|
|
bs->height = s->height;
|
|
|
|
if (s->textureNonPowerOfTwo ||
|
|
(POWER_OF_TWO (bs->width) && POWER_OF_TWO (bs->height)))
|
|
{
|
|
bs->target = GL_TEXTURE_2D;
|
|
bs->tx = 1.0f / bs->width;
|
|
bs->ty = 1.0f / bs->height;
|
|
}
|
|
else
|
|
{
|
|
bs->target = GL_TEXTURE_RECTANGLE_NV;
|
|
bs->tx = 1;
|
|
bs->ty = 1;
|
|
}
|
|
|
|
if (filter == BLUR_FILTER_GAUSSIAN)
|
|
{
|
|
if (s->fbo && !bs->fbo)
|
|
(*s->genFramebuffers) (1, &bs->fbo);
|
|
|
|
if (!bs->fbo)
|
|
compLogMessage ("blur", CompLogLevelError,
|
|
"Failed to create framebuffer object");
|
|
|
|
textures = 2;
|
|
}
|
|
|
|
bs->fboStatus = FALSE;
|
|
|
|
for (i = 0; i < textures; i++)
|
|
{
|
|
if (!bs->texture[i])
|
|
glGenTextures (1, &bs->texture[i]);
|
|
|
|
glBindTexture (bs->target, bs->texture[i]);
|
|
|
|
glTexImage2D (bs->target, 0, GL_RGB,
|
|
bs->width,
|
|
bs->height,
|
|
0, GL_BGRA,
|
|
|
|
#if IMAGE_BYTE_ORDER == MSBFirst
|
|
GL_UNSIGNED_INT_8_8_8_8_REV,
|
|
#else
|
|
GL_UNSIGNED_BYTE,
|
|
#endif
|
|
|
|
NULL);
|
|
|
|
glTexParameteri (bs->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri (bs->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
if (filter == BLUR_FILTER_MIPMAP)
|
|
{
|
|
if (!s->fbo)
|
|
{
|
|
compLogMessage ("blur", CompLogLevelWarn,
|
|
"GL_EXT_framebuffer_object extension "
|
|
"is required for mipmap filter");
|
|
}
|
|
else if (bs->target != GL_TEXTURE_2D)
|
|
{
|
|
compLogMessage ("blur", CompLogLevelWarn,
|
|
"GL_ARB_texture_non_power_of_two "
|
|
"extension is required for mipmap filter");
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri (bs->target, GL_TEXTURE_MIN_FILTER,
|
|
GL_LINEAR_MIPMAP_LINEAR);
|
|
glTexParameteri (bs->target, GL_TEXTURE_MAG_FILTER,
|
|
GL_LINEAR_MIPMAP_LINEAR);
|
|
}
|
|
}
|
|
|
|
glTexParameteri (bs->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri (bs->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glCopyTexSubImage2D (bs->target, 0, 0, 0, 0, 0,
|
|
bs->width, bs->height);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
glBindTexture (bs->target, bs->texture[0]);
|
|
|
|
while (nBox--)
|
|
{
|
|
y = s->height - pBox->y2;
|
|
|
|
glCopyTexSubImage2D (bs->target, 0,
|
|
pBox->x1, y,
|
|
pBox->x1, y,
|
|
pBox->x2 - pBox->x1,
|
|
pBox->y2 - pBox->y1);
|
|
|
|
pBox++;
|
|
}
|
|
}
|
|
|
|
switch (filter) {
|
|
case BLUR_FILTER_GAUSSIAN:
|
|
return fboUpdate (s, bs->tmpRegion->rects, bs->tmpRegion->numRects);
|
|
case BLUR_FILTER_MIPMAP:
|
|
if (s->generateMipmap)
|
|
(*s->generateMipmap) (bs->target);
|
|
break;
|
|
case BLUR_FILTER_4X_BILINEAR:
|
|
break;
|
|
}
|
|
|
|
glBindTexture (bs->target, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
blurDrawWindow (CompWindow *w,
|
|
const CompTransform *transform,
|
|
const FragmentAttrib *attrib,
|
|
Region region,
|
|
unsigned int mask)
|
|
{
|
|
CompScreen *s = w->screen;
|
|
Bool status;
|
|
|
|
BLUR_SCREEN (s);
|
|
BLUR_WINDOW (w);
|
|
|
|
if (bs->alphaBlur && bw->region)
|
|
{
|
|
int clientThreshold;
|
|
|
|
/* only care about client window blurring when it's translucent */
|
|
if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
|
|
clientThreshold = bw->state[BLUR_STATE_CLIENT].threshold;
|
|
else
|
|
clientThreshold = 0;
|
|
|
|
if (bw->state[BLUR_STATE_DECOR].threshold || clientThreshold)
|
|
{
|
|
Bool clipped = FALSE;
|
|
BoxRec box = { 0, 0, 0, 0 };
|
|
Region reg;
|
|
int i;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
bs->mvp.m[i] = s->projection[i];
|
|
|
|
matrixMultiply (&bs->mvp, &bs->mvp, transform);
|
|
|
|
if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
|
|
reg = &infiniteRegion;
|
|
else
|
|
reg = region;
|
|
|
|
XIntersectRegion (bw->region, reg, bs->tmpRegion);
|
|
if (!bs->blurOcclusion && !(mask & PAINT_WINDOW_TRANSFORMED_MASK))
|
|
XSubtractRegion(bs->tmpRegion, bw->clip, bs->tmpRegion);
|
|
|
|
if (blurUpdateDstTexture (w, transform, &box, clientThreshold))
|
|
{
|
|
if (clientThreshold)
|
|
{
|
|
if (bw->state[BLUR_STATE_CLIENT].clipped)
|
|
{
|
|
if (bs->stencilBits)
|
|
{
|
|
bw->state[BLUR_STATE_CLIENT].active = TRUE;
|
|
clipped = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bw->state[BLUR_STATE_CLIENT].active = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bw->state[BLUR_STATE_DECOR].threshold)
|
|
{
|
|
if (bw->state[BLUR_STATE_DECOR].clipped)
|
|
{
|
|
if (bs->stencilBits)
|
|
{
|
|
bw->state[BLUR_STATE_DECOR].active = TRUE;
|
|
clipped = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bw->state[BLUR_STATE_DECOR].active = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bs->blurOcclusion && bw->clip->numRects)
|
|
clipped = TRUE;
|
|
}
|
|
|
|
if (!bs->blurOcclusion)
|
|
XSubtractRegion (bw->region, bw->clip, bs->tmpRegion);
|
|
else
|
|
XSubtractRegion (bw->region, &emptyRegion, bs->tmpRegion);
|
|
|
|
if (!clientThreshold)
|
|
{
|
|
REGION wRegion;
|
|
wRegion.numRects = 1;
|
|
wRegion.rects = &wRegion.extents;
|
|
wRegion.extents.x1 = w->attrib.x;
|
|
wRegion.extents.y1 = w->attrib.y;
|
|
wRegion.extents.x2 = w->attrib.x + w->width;
|
|
wRegion.extents.y2 = w->attrib.y + w->height;
|
|
XSubtractRegion (bs->tmpRegion, &wRegion, bs->tmpRegion);
|
|
}
|
|
|
|
if (clipped)
|
|
{
|
|
w->vCount = w->indexCount = 0;
|
|
(*w->screen->addWindowGeometry) (w, NULL, 0, bs->tmpRegion, reg);
|
|
if (w->vCount)
|
|
{
|
|
BoxRec clearBox = bs->stencilBox;
|
|
|
|
bs->stencilBox = box;
|
|
|
|
glEnable (GL_STENCIL_TEST);
|
|
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
|
|
if (clearBox.x2 > clearBox.x1 && clearBox.y2 > clearBox.y1)
|
|
{
|
|
glPushAttrib (GL_SCISSOR_BIT);
|
|
glEnable (GL_SCISSOR_TEST);
|
|
glScissor (clearBox.x1,
|
|
s->height - clearBox.y2,
|
|
clearBox.x2 - clearBox.x1,
|
|
clearBox.y2 - clearBox.y1);
|
|
glClear (GL_STENCIL_BUFFER_BIT);
|
|
glPopAttrib ();
|
|
}
|
|
|
|
glStencilFunc (GL_ALWAYS, 0x1, ~0);
|
|
glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
|
|
|
|
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
|
|
(*w->drawWindowGeometry) (w);
|
|
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
|
|
|
|
glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
glDisable (GL_STENCIL_TEST);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
UNWRAP (bs, s, drawWindow);
|
|
status = (*s->drawWindow) (w, transform, attrib, region, mask);
|
|
WRAP (bs, s, drawWindow, blurDrawWindow);
|
|
|
|
bw->state[BLUR_STATE_CLIENT].active = FALSE;
|
|
bw->state[BLUR_STATE_DECOR].active = FALSE;
|
|
|
|
return status;
|
|
}
|
|
|
|
static void
|
|
blurDrawWindowTexture (CompWindow *w,
|
|
CompTexture *texture,
|
|
const FragmentAttrib *attrib,
|
|
unsigned int mask)
|
|
{
|
|
CompScreen *s = w->screen;
|
|
int state;
|
|
|
|
BLUR_SCREEN (s);
|
|
BLUR_WINDOW (w);
|
|
|
|
if (texture == w->texture)
|
|
state = BLUR_STATE_CLIENT;
|
|
else
|
|
state = BLUR_STATE_DECOR;
|
|
|
|
if (bw->blur || bw->state[state].active)
|
|
{
|
|
FragmentAttrib fa = *attrib;
|
|
int param, function;
|
|
int unit = 0;
|
|
GLfloat dx, dy;
|
|
int iTC = 0;
|
|
|
|
if (bw->blur)
|
|
{
|
|
param = allocFragmentParameters (&fa, 1);
|
|
|
|
function = getSrcBlurFragmentFunction (s, texture, param);
|
|
if (function)
|
|
{
|
|
addFragmentFunction (&fa, function);
|
|
|
|
dx = ((texture->matrix.xx / 2.1f) * bw->blur) / 65535.0f;
|
|
dy = ((texture->matrix.yy / 2.1f) * bw->blur) / 65535.0f;
|
|
|
|
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
|
|
param, dx, dy, dx, -dy);
|
|
|
|
/* bi-linear filtering is required */
|
|
mask |= PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
|
|
}
|
|
}
|
|
|
|
if (bw->state[state].active)
|
|
{
|
|
FragmentAttrib dstFa = fa;
|
|
float threshold = (float) bw->state[state].threshold;
|
|
|
|
switch (bs->opt[BLUR_SCREEN_OPTION_FILTER].value.i) {
|
|
case BLUR_FILTER_4X_BILINEAR:
|
|
dx = bs->tx / 2.1f;
|
|
dy = bs->ty / 2.1f;
|
|
|
|
param = allocFragmentParameters (&dstFa, 3);
|
|
unit = allocFragmentTextureUnits (&dstFa, 1);
|
|
|
|
function =
|
|
getDstBlurFragmentFunction (s, texture, param, unit, 0, 0);
|
|
if (function)
|
|
{
|
|
addFragmentFunction (&dstFa, function);
|
|
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB + unit);
|
|
glBindTexture (bs->target, bs->texture[0]);
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB);
|
|
|
|
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB, param,
|
|
bs->tx, bs->ty, 0.0f, 0.0f);
|
|
|
|
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
|
|
param + 1,
|
|
threshold, threshold,
|
|
threshold, threshold);
|
|
|
|
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
|
|
param + 2,
|
|
dx, dy, 0.0f, 0.0f);
|
|
}
|
|
break;
|
|
case BLUR_FILTER_GAUSSIAN:
|
|
if (bs->opt[BLUR_SCREEN_OPTION_INDEPENDENT_TEX].value.b)
|
|
{
|
|
/* leave one free texture unit for fragment position */
|
|
iTC = MAX (0, s->maxTextureUnits - (w->texUnits + 1));
|
|
if (iTC)
|
|
iTC = MIN (iTC / 2, bs->numTexop);
|
|
}
|
|
|
|
param = allocFragmentParameters (&dstFa, 2);
|
|
unit = allocFragmentTextureUnits (&dstFa, 2);
|
|
|
|
function =
|
|
getDstBlurFragmentFunction (s, texture, param, unit,
|
|
iTC, w->texUnits);
|
|
if (function)
|
|
{
|
|
int i;
|
|
|
|
addFragmentFunction (&dstFa, function);
|
|
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB + unit);
|
|
glBindTexture (bs->target, bs->texture[0]);
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB + unit + 1);
|
|
glBindTexture (bs->target, bs->texture[1]);
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB);
|
|
|
|
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
|
|
param,
|
|
bs->tx, bs->ty,
|
|
0.0f, 0.0f);
|
|
|
|
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
|
|
param + 1,
|
|
threshold, threshold,
|
|
threshold, threshold);
|
|
|
|
if (iTC)
|
|
{
|
|
CompTransform tm, rm;
|
|
float s_gen[4], t_gen[4], q_gen[4];
|
|
|
|
for (i = 0; i < 16; i++)
|
|
tm.m[i] = 0;
|
|
tm.m[0] = (bs->output->width / 2.0) * bs->tx;
|
|
tm.m[5] = (bs->output->height / 2.0) * bs->ty;
|
|
tm.m[10] = 1;
|
|
|
|
tm.m[12] = (bs->output->width / 2.0 +
|
|
bs->output->region.extents.x1) * bs->tx;
|
|
tm.m[13] = (bs->output->height / 2.0 + s->height -
|
|
bs->output->region.extents.y2) * bs->ty;
|
|
tm.m[14] = 1;
|
|
tm.m[15] = 1;
|
|
|
|
matrixMultiply (&tm, &tm, &bs->mvp);
|
|
|
|
for (i = 0; i < iTC; i++)
|
|
{
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB + w->texUnits
|
|
+ (i * 2));
|
|
|
|
matrixGetIdentity (&rm);
|
|
rm.m[13] = bs->ty * bs->pos[i];
|
|
matrixMultiply (&rm, &rm, &tm);
|
|
s_gen[0] = rm.m[0];
|
|
s_gen[1] = rm.m[4];
|
|
s_gen[2] = rm.m[8];
|
|
s_gen[3] = rm.m[12];
|
|
t_gen[0] = rm.m[1];
|
|
t_gen[1] = rm.m[5];
|
|
t_gen[2] = rm.m[9];
|
|
t_gen[3] = rm.m[13];
|
|
q_gen[0] = rm.m[3];
|
|
q_gen[1] = rm.m[7];
|
|
q_gen[2] = rm.m[11];
|
|
q_gen[3] = rm.m[15];
|
|
|
|
glTexGenfv(GL_T, GL_OBJECT_PLANE, t_gen);
|
|
glTexGenfv(GL_S, GL_OBJECT_PLANE, s_gen);
|
|
glTexGenfv(GL_Q, GL_OBJECT_PLANE, q_gen);
|
|
|
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE,
|
|
GL_OBJECT_LINEAR);
|
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE,
|
|
GL_OBJECT_LINEAR);
|
|
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE,
|
|
GL_OBJECT_LINEAR);
|
|
|
|
glEnable(GL_TEXTURE_GEN_S);
|
|
glEnable(GL_TEXTURE_GEN_T);
|
|
glEnable(GL_TEXTURE_GEN_Q);
|
|
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB + w->texUnits
|
|
+ 1 + (i * 2));
|
|
|
|
matrixGetIdentity (&rm);
|
|
rm.m[13] = -bs->ty * bs->pos[i];
|
|
matrixMultiply (&rm, &rm, &tm);
|
|
s_gen[0] = rm.m[0];
|
|
s_gen[1] = rm.m[4];
|
|
s_gen[2] = rm.m[8];
|
|
s_gen[3] = rm.m[12];
|
|
t_gen[0] = rm.m[1];
|
|
t_gen[1] = rm.m[5];
|
|
t_gen[2] = rm.m[9];
|
|
t_gen[3] = rm.m[13];
|
|
q_gen[0] = rm.m[3];
|
|
q_gen[1] = rm.m[7];
|
|
q_gen[2] = rm.m[11];
|
|
q_gen[3] = rm.m[15];
|
|
|
|
glTexGenfv(GL_T, GL_OBJECT_PLANE, t_gen);
|
|
glTexGenfv(GL_S, GL_OBJECT_PLANE, s_gen);
|
|
glTexGenfv(GL_Q, GL_OBJECT_PLANE, q_gen);
|
|
|
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE,
|
|
GL_OBJECT_LINEAR);
|
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE,
|
|
GL_OBJECT_LINEAR);
|
|
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE,
|
|
GL_OBJECT_LINEAR);
|
|
|
|
glEnable(GL_TEXTURE_GEN_S);
|
|
glEnable(GL_TEXTURE_GEN_T);
|
|
glEnable(GL_TEXTURE_GEN_Q);
|
|
}
|
|
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB);
|
|
}
|
|
|
|
}
|
|
break;
|
|
case BLUR_FILTER_MIPMAP:
|
|
param = allocFragmentParameters (&dstFa, 2);
|
|
unit = allocFragmentTextureUnits (&dstFa, 1);
|
|
|
|
function =
|
|
getDstBlurFragmentFunction (s, texture, param, unit, 0, 0);
|
|
if (function)
|
|
{
|
|
float lod = bs->opt[BLUR_SCREEN_OPTION_MIPMAP_LOD].value.f;
|
|
|
|
addFragmentFunction (&dstFa, function);
|
|
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB + unit);
|
|
glBindTexture (bs->target, bs->texture[0]);
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB);
|
|
|
|
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
|
|
param,
|
|
bs->tx, bs->ty,
|
|
0.0f, lod);
|
|
|
|
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
|
|
param + 1,
|
|
threshold, threshold,
|
|
threshold, threshold);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (bw->state[state].clipped ||
|
|
(!bs->blurOcclusion && bw->clip->numRects))
|
|
{
|
|
glEnable (GL_STENCIL_TEST);
|
|
|
|
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
|
|
glStencilFunc (GL_EQUAL, 0x1, ~0);
|
|
|
|
/* draw region with destination blur */
|
|
UNWRAP (bs, s, drawWindowTexture);
|
|
(*s->drawWindowTexture) (w, texture, &dstFa, mask);
|
|
|
|
glStencilFunc (GL_EQUAL, 0, ~0);
|
|
|
|
/* draw region without destination blur */
|
|
(*s->drawWindowTexture) (w, texture, &fa, mask);
|
|
WRAP (bs, s, drawWindowTexture, blurDrawWindowTexture);
|
|
|
|
glDisable (GL_STENCIL_TEST);
|
|
}
|
|
else
|
|
{
|
|
/* draw with destination blur */
|
|
UNWRAP (bs, s, drawWindowTexture);
|
|
(*s->drawWindowTexture) (w, texture, &dstFa, mask);
|
|
WRAP (bs, s, drawWindowTexture, blurDrawWindowTexture);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UNWRAP (bs, s, drawWindowTexture);
|
|
(*s->drawWindowTexture) (w, texture, &fa, mask);
|
|
WRAP (bs, s, drawWindowTexture, blurDrawWindowTexture);
|
|
}
|
|
|
|
if (unit)
|
|
{
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB + unit);
|
|
glBindTexture (bs->target, 0);
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB + unit + 1);
|
|
glBindTexture (bs->target, 0);
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB);
|
|
}
|
|
|
|
if (iTC)
|
|
{
|
|
int i;
|
|
for (i = w->texUnits; i < w->texUnits + (2 * iTC); i++)
|
|
{
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB + i);
|
|
glDisable(GL_TEXTURE_GEN_S);
|
|
glDisable(GL_TEXTURE_GEN_T);
|
|
glDisable(GL_TEXTURE_GEN_Q);
|
|
}
|
|
(*s->activeTexture) (GL_TEXTURE0_ARB);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UNWRAP (bs, s, drawWindowTexture);
|
|
(*s->drawWindowTexture) (w, texture, attrib, mask);
|
|
WRAP (bs, s, drawWindowTexture, blurDrawWindowTexture);
|
|
}
|
|
}
|
|
|
|
static void
|
|
blurHandleEvent (CompDisplay *d,
|
|
XEvent *event)
|
|
{
|
|
Window activeWindow = d->activeWindow;
|
|
|
|
BLUR_DISPLAY (d);
|
|
|
|
UNWRAP (bd, d, handleEvent);
|
|
(*d->handleEvent) (d, event);
|
|
WRAP (bd, d, handleEvent, blurHandleEvent);
|
|
|
|
if (d->activeWindow != activeWindow)
|
|
{
|
|
CompWindow *w;
|
|
|
|
w = findWindowAtDisplay (d, activeWindow);
|
|
if (w)
|
|
{
|
|
BLUR_SCREEN (w->screen);
|
|
|
|
if (bs->opt[BLUR_SCREEN_OPTION_FOCUS_BLUR].value.b)
|
|
{
|
|
addWindowDamage (w);
|
|
bs->moreBlur = TRUE;
|
|
}
|
|
}
|
|
|
|
w = findWindowAtDisplay (d, d->activeWindow);
|
|
if (w)
|
|
{
|
|
BLUR_SCREEN (w->screen);
|
|
|
|
if (bs->opt[BLUR_SCREEN_OPTION_FOCUS_BLUR].value.b)
|
|
{
|
|
addWindowDamage (w);
|
|
bs->moreBlur = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (event->type == PropertyNotify)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < BLUR_STATE_NUM; i++)
|
|
{
|
|
if (event->xproperty.atom == bd->blurAtom[i])
|
|
{
|
|
CompWindow *w;
|
|
|
|
w = findWindowAtDisplay (d, event->xproperty.window);
|
|
if (w)
|
|
blurWindowUpdate (w, i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
blurWindowResizeNotify (CompWindow *w,
|
|
int dx,
|
|
int dy,
|
|
int dwidth,
|
|
int dheight)
|
|
{
|
|
BLUR_SCREEN (w->screen);
|
|
|
|
if (bs->alphaBlur)
|
|
{
|
|
BLUR_WINDOW (w);
|
|
|
|
if (bw->state[BLUR_STATE_CLIENT].threshold ||
|
|
bw->state[BLUR_STATE_DECOR].threshold)
|
|
blurWindowUpdateRegion (w);
|
|
}
|
|
|
|
UNWRAP (bs, w->screen, windowResizeNotify);
|
|
(*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight);
|
|
WRAP (bs, w->screen, windowResizeNotify, blurWindowResizeNotify);
|
|
}
|
|
|
|
static void
|
|
blurWindowMoveNotify (CompWindow *w,
|
|
int dx,
|
|
int dy,
|
|
Bool immediate)
|
|
{
|
|
BLUR_SCREEN (w->screen);
|
|
BLUR_WINDOW (w);
|
|
|
|
if (bw->region)
|
|
XOffsetRegion (bw->region, dx, dy);
|
|
|
|
UNWRAP (bs, w->screen, windowMoveNotify);
|
|
(*w->screen->windowMoveNotify) (w, dx, dy, immediate);
|
|
WRAP (bs, w->screen, windowMoveNotify, blurWindowMoveNotify);
|
|
}
|
|
|
|
static CompOption *
|
|
blurGetDisplayOptions (CompPlugin *plugin,
|
|
CompDisplay *display,
|
|
int *count)
|
|
{
|
|
BLUR_DISPLAY (display);
|
|
|
|
*count = NUM_OPTIONS (bd);
|
|
return bd->opt;
|
|
}
|
|
|
|
static Bool
|
|
blurSetDisplayOption (CompPlugin *plugin,
|
|
CompDisplay *display,
|
|
const char *name,
|
|
CompOptionValue *value)
|
|
{
|
|
CompOption *o;
|
|
|
|
BLUR_DISPLAY (display);
|
|
|
|
o = compFindOption (bd->opt, NUM_OPTIONS (bd), name, NULL);
|
|
if (!o)
|
|
return FALSE;
|
|
|
|
return compSetDisplayOption (display, o, value);
|
|
}
|
|
|
|
static Bool
|
|
blurPulse (CompDisplay *d,
|
|
CompAction *action,
|
|
CompActionState state,
|
|
CompOption *option,
|
|
int nOption)
|
|
{
|
|
CompWindow *w;
|
|
int xid;
|
|
|
|
xid = getIntOptionNamed (option, nOption, "window", d->activeWindow);
|
|
|
|
w = findWindowAtDisplay (d, xid);
|
|
if (w && w->screen->fragmentProgram)
|
|
{
|
|
BLUR_SCREEN (w->screen);
|
|
BLUR_WINDOW (w);
|
|
|
|
bw->pulse = TRUE;
|
|
bs->moreBlur = TRUE;
|
|
|
|
addWindowDamage (w);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
blurMatchExpHandlerChanged (CompDisplay *d)
|
|
{
|
|
CompScreen *s;
|
|
CompWindow *w;
|
|
|
|
BLUR_DISPLAY (d);
|
|
|
|
UNWRAP (bd, d, matchExpHandlerChanged);
|
|
(*d->matchExpHandlerChanged) (d);
|
|
WRAP (bd, d, matchExpHandlerChanged, blurMatchExpHandlerChanged);
|
|
|
|
/* match options are up to date after the call to matchExpHandlerChanged */
|
|
for (s = d->screens; s; s = s->next)
|
|
{
|
|
BLUR_SCREEN (s);
|
|
|
|
for (w = s->windows; w; w = w->next)
|
|
blurUpdateWindowMatch (bs, w);
|
|
}
|
|
}
|
|
|
|
static void
|
|
blurMatchPropertyChanged (CompDisplay *d,
|
|
CompWindow *w)
|
|
{
|
|
BLUR_DISPLAY (d);
|
|
BLUR_SCREEN (w->screen);
|
|
|
|
blurUpdateWindowMatch (bs, w);
|
|
|
|
UNWRAP (bd, d, matchPropertyChanged);
|
|
(*d->matchPropertyChanged) (d, w);
|
|
WRAP (bd, d, matchPropertyChanged, blurMatchPropertyChanged);
|
|
}
|
|
|
|
static void
|
|
blurWindowAdd (CompScreen *s,
|
|
CompWindow *w)
|
|
{
|
|
BLUR_SCREEN (s);
|
|
|
|
blurWindowUpdate (w, BLUR_STATE_CLIENT);
|
|
blurWindowUpdate (w, BLUR_STATE_DECOR);
|
|
|
|
blurUpdateWindowMatch (bs, w);
|
|
}
|
|
|
|
static void
|
|
blurObjectAdd (CompObject *parent,
|
|
CompObject *object)
|
|
{
|
|
static ObjectAddProc dispTab[] = {
|
|
(ObjectAddProc) 0, /* CoreAdd */
|
|
(ObjectAddProc) 0, /* DisplayAdd */
|
|
(ObjectAddProc) 0, /* ScreenAdd */
|
|
(ObjectAddProc) blurWindowAdd
|
|
};
|
|
|
|
BLUR_CORE (&core);
|
|
|
|
UNWRAP (bc, &core, objectAdd);
|
|
(*core.objectAdd) (parent, object);
|
|
WRAP (bc, &core, objectAdd, blurObjectAdd);
|
|
|
|
DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), (parent, object));
|
|
}
|
|
|
|
static Bool
|
|
blurInitCore (CompPlugin *p,
|
|
CompCore *c)
|
|
{
|
|
BlurCore *bc;
|
|
|
|
if (!checkPluginABI ("core", CORE_ABIVERSION))
|
|
return FALSE;
|
|
|
|
bc = malloc (sizeof (BlurCore));
|
|
if (!bc)
|
|
return FALSE;
|
|
|
|
displayPrivateIndex = allocateDisplayPrivateIndex ();
|
|
if (displayPrivateIndex < 0)
|
|
{
|
|
free (bc);
|
|
return FALSE;
|
|
}
|
|
|
|
WRAP (bc, c, objectAdd, blurObjectAdd);
|
|
|
|
c->base.privates[corePrivateIndex].ptr = bc;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
blurFiniCore (CompPlugin *p,
|
|
CompCore *c)
|
|
{
|
|
BLUR_CORE (c);
|
|
|
|
freeDisplayPrivateIndex (displayPrivateIndex);
|
|
|
|
UNWRAP (bc, c, objectAdd);
|
|
|
|
free (bc);
|
|
}
|
|
|
|
static const CompMetadataOptionInfo blurDisplayOptionInfo[] = {
|
|
{ "pulse", "bell", 0, blurPulse, 0 }
|
|
};
|
|
|
|
static Bool
|
|
blurInitDisplay (CompPlugin *p,
|
|
CompDisplay *d)
|
|
{
|
|
BlurDisplay *bd;
|
|
|
|
bd = malloc (sizeof (BlurDisplay));
|
|
if (!bd)
|
|
return FALSE;
|
|
|
|
if (!compInitDisplayOptionsFromMetadata (d,
|
|
&blurMetadata,
|
|
blurDisplayOptionInfo,
|
|
bd->opt,
|
|
BLUR_DISPLAY_OPTION_NUM))
|
|
{
|
|
free (bd);
|
|
return FALSE;
|
|
}
|
|
|
|
bd->screenPrivateIndex = allocateScreenPrivateIndex (d);
|
|
if (bd->screenPrivateIndex < 0)
|
|
{
|
|
compFiniDisplayOptions (d, bd->opt, BLUR_DISPLAY_OPTION_NUM);
|
|
free (bd);
|
|
return FALSE;
|
|
}
|
|
|
|
bd->blurAtom[BLUR_STATE_CLIENT] =
|
|
XInternAtom (d->display, "_COMPIZ_WM_WINDOW_BLUR", 0);
|
|
bd->blurAtom[BLUR_STATE_DECOR] =
|
|
XInternAtom (d->display, DECOR_BLUR_ATOM_NAME, 0);
|
|
|
|
WRAP (bd, d, handleEvent, blurHandleEvent);
|
|
WRAP (bd, d, matchExpHandlerChanged, blurMatchExpHandlerChanged);
|
|
WRAP (bd, d, matchPropertyChanged, blurMatchPropertyChanged);
|
|
|
|
d->base.privates[displayPrivateIndex].ptr = bd;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
blurFiniDisplay (CompPlugin *p,
|
|
CompDisplay *d)
|
|
{
|
|
BLUR_DISPLAY (d);
|
|
|
|
freeScreenPrivateIndex (d, bd->screenPrivateIndex);
|
|
|
|
UNWRAP (bd, d, handleEvent);
|
|
UNWRAP (bd, d, matchExpHandlerChanged);
|
|
UNWRAP (bd, d, matchPropertyChanged);
|
|
|
|
compFiniDisplayOptions (d, bd->opt, BLUR_DISPLAY_OPTION_NUM);
|
|
|
|
free (bd);
|
|
}
|
|
|
|
static const CompMetadataOptionInfo blurScreenOptionInfo[] = {
|
|
{ "blur_speed", "float", "<min>0.1</min>", 0, 0 },
|
|
{ "focus_blur_match", "match", 0, 0, 0 },
|
|
{ "focus_blur", "bool", 0, 0, 0 },
|
|
{ "alpha_blur_match", "match", 0, 0, 0 },
|
|
{ "alpha_blur", "bool", 0, 0, 0 },
|
|
{ "filter", "int", RESTOSTRING (0, BLUR_FILTER_LAST), 0, 0 },
|
|
{ "gaussian_radius", "int", "<min>1</min><max>15</max>", 0, 0 },
|
|
{ "gaussian_strength", "float", "<min>0.0</min><max>1.0</max>", 0, 0 },
|
|
{ "mipmap_lod", "float", "<min>0.1</min><max>5.0</max>", 0, 0 },
|
|
{ "saturation", "int", "<min>0</min><max>100</max>", 0, 0 },
|
|
{ "occlusion", "bool", 0, 0, 0 },
|
|
{ "independent_tex", "bool", 0, 0, 0 }
|
|
};
|
|
|
|
static Bool
|
|
blurInitScreen (CompPlugin *p,
|
|
CompScreen *s)
|
|
{
|
|
BlurScreen *bs;
|
|
int i;
|
|
|
|
BLUR_DISPLAY (s->display);
|
|
|
|
bs = malloc (sizeof (BlurScreen));
|
|
if (!bs)
|
|
return FALSE;
|
|
|
|
if (!compInitScreenOptionsFromMetadata (s,
|
|
&blurMetadata,
|
|
blurScreenOptionInfo,
|
|
bs->opt,
|
|
BLUR_SCREEN_OPTION_NUM))
|
|
{
|
|
free (bs);
|
|
return FALSE;
|
|
}
|
|
|
|
bs->region = XCreateRegion ();
|
|
if (!bs->region)
|
|
{
|
|
compFiniScreenOptions (s, bs->opt, BLUR_SCREEN_OPTION_NUM);
|
|
free (bs);
|
|
return FALSE;
|
|
}
|
|
|
|
bs->tmpRegion = XCreateRegion ();
|
|
if (!bs->tmpRegion)
|
|
{
|
|
compFiniScreenOptions (s, bs->opt, BLUR_SCREEN_OPTION_NUM);
|
|
XDestroyRegion (bs->region);
|
|
free (bs);
|
|
return FALSE;
|
|
}
|
|
|
|
bs->tmpRegion2 = XCreateRegion ();
|
|
if (!bs->tmpRegion2)
|
|
{
|
|
compFiniScreenOptions (s, bs->opt, BLUR_SCREEN_OPTION_NUM);
|
|
XDestroyRegion (bs->region);
|
|
XDestroyRegion (bs->tmpRegion);
|
|
free (bs);
|
|
return FALSE;
|
|
}
|
|
|
|
bs->tmpRegion3 = XCreateRegion ();
|
|
if (!bs->tmpRegion3)
|
|
{
|
|
compFiniScreenOptions (s, bs->opt, BLUR_SCREEN_OPTION_NUM);
|
|
XDestroyRegion (bs->region);
|
|
XDestroyRegion (bs->tmpRegion);
|
|
XDestroyRegion (bs->tmpRegion2);
|
|
free (bs);
|
|
return FALSE;
|
|
}
|
|
|
|
bs->occlusion = XCreateRegion ();
|
|
if (!bs->occlusion)
|
|
{
|
|
compFiniScreenOptions (s, bs->opt, BLUR_SCREEN_OPTION_NUM);
|
|
XDestroyRegion (bs->region);
|
|
XDestroyRegion (bs->tmpRegion);
|
|
XDestroyRegion (bs->tmpRegion2);
|
|
XDestroyRegion (bs->tmpRegion3);
|
|
free (bs);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
bs->windowPrivateIndex = allocateWindowPrivateIndex (s);
|
|
if (bs->windowPrivateIndex < 0)
|
|
{
|
|
compFiniScreenOptions (s, bs->opt, BLUR_SCREEN_OPTION_NUM);
|
|
XDestroyRegion (bs->region);
|
|
XDestroyRegion (bs->tmpRegion);
|
|
XDestroyRegion (bs->tmpRegion2);
|
|
XDestroyRegion (bs->tmpRegion3);
|
|
XDestroyRegion (bs->occlusion);
|
|
free (bs);
|
|
return FALSE;
|
|
}
|
|
|
|
bs->output = NULL;
|
|
bs->count = 0;
|
|
|
|
bs->filterRadius = 0;
|
|
|
|
bs->srcBlurFunctions = NULL;
|
|
bs->dstBlurFunctions = NULL;
|
|
bs->blurTime = 1000.0f /
|
|
bs->opt[BLUR_SCREEN_OPTION_BLUR_SPEED].value.f;
|
|
bs->moreBlur = FALSE;
|
|
bs->blurOcclusion =
|
|
bs->opt[BLUR_SCREEN_OPTION_BLUR_OCCLUSION].value.b;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
bs->texture[i] = 0;
|
|
|
|
bs->program = 0;
|
|
bs->maxTemp = 32;
|
|
bs->fbo = 0;
|
|
bs->fboStatus = FALSE;
|
|
|
|
glGetIntegerv (GL_STENCIL_BITS, &bs->stencilBits);
|
|
if (!bs->stencilBits)
|
|
compLogMessage ("blur", CompLogLevelWarn,
|
|
"No stencil buffer. Region based blur disabled");
|
|
|
|
/* We need GL_ARB_fragment_program for blur */
|
|
if (s->fragmentProgram)
|
|
bs->alphaBlur = bs->opt[BLUR_SCREEN_OPTION_ALPHA_BLUR].value.b;
|
|
else
|
|
bs->alphaBlur = FALSE;
|
|
|
|
if (s->fragmentProgram)
|
|
{
|
|
int tmp[4];
|
|
s->getProgramiv (GL_FRAGMENT_PROGRAM_ARB,
|
|
GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB,
|
|
tmp);
|
|
bs->maxTemp = tmp[0];
|
|
}
|
|
|
|
WRAP (bs, s, preparePaintScreen, blurPreparePaintScreen);
|
|
WRAP (bs, s, donePaintScreen, blurDonePaintScreen);
|
|
WRAP (bs, s, paintOutput, blurPaintOutput);
|
|
WRAP (bs, s, paintTransformedOutput, blurPaintTransformedOutput);
|
|
WRAP (bs, s, paintWindow, blurPaintWindow);
|
|
WRAP (bs, s, drawWindow, blurDrawWindow);
|
|
WRAP (bs, s, drawWindowTexture, blurDrawWindowTexture);
|
|
WRAP (bs, s, windowResizeNotify, blurWindowResizeNotify);
|
|
WRAP (bs, s, windowMoveNotify, blurWindowMoveNotify);
|
|
|
|
s->base.privates[bd->screenPrivateIndex].ptr = bs;
|
|
|
|
blurUpdateFilterRadius (s);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
blurFiniScreen (CompPlugin *p,
|
|
CompScreen *s)
|
|
{
|
|
int i;
|
|
|
|
BLUR_SCREEN (s);
|
|
|
|
blurDestroyFragmentFunctions (s, &bs->srcBlurFunctions);
|
|
blurDestroyFragmentFunctions (s, &bs->dstBlurFunctions);
|
|
|
|
damageScreen (s);
|
|
|
|
XDestroyRegion (bs->region);
|
|
XDestroyRegion (bs->tmpRegion);
|
|
XDestroyRegion (bs->tmpRegion2);
|
|
XDestroyRegion (bs->tmpRegion3);
|
|
XDestroyRegion (bs->occlusion);
|
|
|
|
if (bs->fbo)
|
|
(*s->deleteFramebuffers) (1, &bs->fbo);
|
|
|
|
for (i = 0; i < 2; i++)
|
|
if (bs->texture[i])
|
|
glDeleteTextures (1, &bs->texture[i]);
|
|
|
|
freeWindowPrivateIndex (s, bs->windowPrivateIndex);
|
|
|
|
UNWRAP (bs, s, preparePaintScreen);
|
|
UNWRAP (bs, s, donePaintScreen);
|
|
UNWRAP (bs, s, paintOutput);
|
|
UNWRAP (bs, s, paintTransformedOutput);
|
|
UNWRAP (bs, s, paintWindow);
|
|
UNWRAP (bs, s, drawWindow);
|
|
UNWRAP (bs, s, drawWindowTexture);
|
|
UNWRAP (bs, s, windowResizeNotify);
|
|
UNWRAP (bs, s, windowMoveNotify);
|
|
|
|
compFiniScreenOptions (s, bs->opt, BLUR_SCREEN_OPTION_NUM);
|
|
|
|
free (bs);
|
|
}
|
|
|
|
static Bool
|
|
blurInitWindow (CompPlugin *p,
|
|
CompWindow *w)
|
|
{
|
|
BlurWindow *bw;
|
|
int i;
|
|
|
|
BLUR_SCREEN (w->screen);
|
|
|
|
bw = malloc (sizeof (BlurWindow));
|
|
if (!bw)
|
|
return FALSE;
|
|
|
|
bw->blur = 0;
|
|
bw->pulse = FALSE;
|
|
bw->focusBlur = FALSE;
|
|
|
|
for (i = 0; i < BLUR_STATE_NUM; i++)
|
|
{
|
|
bw->state[i].threshold = 0;
|
|
bw->state[i].box = NULL;
|
|
bw->state[i].nBox = 0;
|
|
bw->state[i].clipped = FALSE;
|
|
bw->state[i].active = FALSE;
|
|
|
|
bw->propSet[i] = FALSE;
|
|
}
|
|
|
|
bw->region = NULL;
|
|
|
|
bw->clip = XCreateRegion ();
|
|
if (!bw->clip)
|
|
{
|
|
free (bw);
|
|
return FALSE;
|
|
}
|
|
|
|
w->base.privates[bs->windowPrivateIndex].ptr = bw;
|
|
|
|
if (w->base.parent)
|
|
blurWindowAdd (w->screen, w);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
blurFiniWindow (CompPlugin *p,
|
|
CompWindow *w)
|
|
{
|
|
int i;
|
|
|
|
BLUR_WINDOW (w);
|
|
|
|
for (i = 0; i < BLUR_STATE_NUM; i++)
|
|
if (bw->state[i].box)
|
|
free (bw->state[i].box);
|
|
|
|
if (bw->region)
|
|
XDestroyRegion (bw->region);
|
|
|
|
XDestroyRegion (bw->clip);
|
|
|
|
free (bw);
|
|
}
|
|
|
|
static CompBool
|
|
blurInitObject (CompPlugin *p,
|
|
CompObject *o)
|
|
{
|
|
static InitPluginObjectProc dispTab[] = {
|
|
(InitPluginObjectProc) blurInitCore,
|
|
(InitPluginObjectProc) blurInitDisplay,
|
|
(InitPluginObjectProc) blurInitScreen,
|
|
(InitPluginObjectProc) blurInitWindow
|
|
};
|
|
|
|
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
|
|
}
|
|
|
|
static void
|
|
blurFiniObject (CompPlugin *p,
|
|
CompObject *o)
|
|
{
|
|
static FiniPluginObjectProc dispTab[] = {
|
|
(FiniPluginObjectProc) blurFiniCore,
|
|
(FiniPluginObjectProc) blurFiniDisplay,
|
|
(FiniPluginObjectProc) blurFiniScreen,
|
|
(FiniPluginObjectProc) blurFiniWindow
|
|
};
|
|
|
|
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
|
|
}
|
|
|
|
static CompOption *
|
|
blurGetObjectOptions (CompPlugin *plugin,
|
|
CompObject *object,
|
|
int *count)
|
|
{
|
|
static GetPluginObjectOptionsProc dispTab[] = {
|
|
(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
|
|
(GetPluginObjectOptionsProc) blurGetDisplayOptions,
|
|
(GetPluginObjectOptionsProc) blurGetScreenOptions
|
|
};
|
|
|
|
*count = 0;
|
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
|
|
(void *) count, (plugin, object, count));
|
|
}
|
|
|
|
static CompBool
|
|
blurSetObjectOption (CompPlugin *plugin,
|
|
CompObject *object,
|
|
const char *name,
|
|
CompOptionValue *value)
|
|
{
|
|
static SetPluginObjectOptionProc dispTab[] = {
|
|
(SetPluginObjectOptionProc) 0, /* SetCoreOption */
|
|
(SetPluginObjectOptionProc) blurSetDisplayOption,
|
|
(SetPluginObjectOptionProc) blurSetScreenOption
|
|
};
|
|
|
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
|
|
(plugin, object, name, value));
|
|
}
|
|
|
|
static Bool
|
|
blurInit (CompPlugin *p)
|
|
{
|
|
if (!compInitPluginMetadataFromInfo (&blurMetadata,
|
|
p->vTable->name,
|
|
blurDisplayOptionInfo,
|
|
BLUR_DISPLAY_OPTION_NUM,
|
|
blurScreenOptionInfo,
|
|
BLUR_SCREEN_OPTION_NUM))
|
|
return FALSE;
|
|
|
|
corePrivateIndex = allocateCorePrivateIndex ();
|
|
if (corePrivateIndex < 0)
|
|
{
|
|
compFiniMetadata (&blurMetadata);
|
|
return FALSE;
|
|
}
|
|
|
|
compAddMetadataFromFile (&blurMetadata, p->vTable->name);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
blurFini (CompPlugin *p)
|
|
{
|
|
freeCorePrivateIndex (corePrivateIndex);
|
|
compFiniMetadata (&blurMetadata);
|
|
}
|
|
|
|
static CompMetadata *
|
|
blurGetMetadata (CompPlugin *plugin)
|
|
{
|
|
return &blurMetadata;
|
|
}
|
|
|
|
static CompPluginVTable blurVTable = {
|
|
"blur",
|
|
blurGetMetadata,
|
|
blurInit,
|
|
blurFini,
|
|
blurInitObject,
|
|
blurFiniObject,
|
|
blurGetObjectOptions,
|
|
blurSetObjectOption
|
|
};
|
|
|
|
CompPluginVTable *
|
|
getCompPluginInfo20070830 (void)
|
|
{
|
|
return &blurVTable;
|
|
}
|