summaryrefslogtreecommitdiff
path: root/plugins/blur/src/blur.cpp
diff options
context:
space:
mode:
authorDennis Kasprzyk <onestone@compiz-fusion.org>2009-03-15 06:09:18 +0100
committerDennis kasprzyk <onestone@compiz-fusion.org>2009-03-15 06:09:18 +0100
commit163f6b6f3c3b7764987cbdf8e03cc355edeaa499 (patch)
tree4278afde195343dcb8277b0bb0b6efc926ce8907 /plugins/blur/src/blur.cpp
parent28e45c55c11e20206d3bc9056aea8fc7f1b7a0e7 (diff)
downloadzcomp-163f6b6f3c3b7764987cbdf8e03cc355edeaa499.tar.gz
zcomp-163f6b6f3c3b7764987cbdf8e03cc355edeaa499.tar.bz2
New generalized build system.
Diffstat (limited to 'plugins/blur/src/blur.cpp')
-rw-r--r--plugins/blur/src/blur.cpp2403
1 files changed, 2403 insertions, 0 deletions
diff --git a/plugins/blur/src/blur.cpp b/plugins/blur/src/blur.cpp
new file mode 100644
index 0000000..766f98c
--- /dev/null
+++ b/plugins/blur/src/blur.cpp
@@ -0,0 +1,2403 @@
+/*
+ * 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 <blur.h>
+
+COMPIZ_PLUGIN_20081216 (blur, BlurPluginVTable)
+
+/* 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;
+}
+
+void
+BlurScreen::updateFilterRadius ()
+{
+
+ switch (opt[BLUR_OPTION_FILTER].value ().i ()) {
+ case BLUR_FILTER_4X_BILINEAR:
+ filterRadius = 2;
+ break;
+ case BLUR_FILTER_GAUSSIAN: {
+ int radius = opt[BLUR_OPTION_GAUSSIAN_RADIUS].value ().i ();
+ float strength = opt[BLUR_OPTION_GAUSSIAN_STRENGTH].value ().f ();
+
+ blurCreateGaussianLinearKernel (radius, strength, amp, pos,
+ &numTexop);
+
+ filterRadius = radius;
+ } break;
+ case BLUR_FILTER_MIPMAP: {
+ float lod = opt[BLUR_OPTION_MIPMAP_LOD].value ().f ();
+
+ filterRadius = powf (2.0f, ceilf (lod));
+ } break;
+ }
+}
+
+
+void
+BlurScreen::blurReset ()
+{
+ updateFilterRadius ();
+
+ foreach (BlurFunction &bf, srcBlurFunctions)
+ GLFragment::destroyFragmentFunction (bf.id);
+ srcBlurFunctions.clear ();
+ foreach (BlurFunction &bf, dstBlurFunctions)
+ GLFragment::destroyFragmentFunction (bf.id);
+ dstBlurFunctions.clear ();
+
+ width = height = 0;
+
+ if (program)
+ {
+ GL::deletePrograms (1, &program);
+ program = 0;
+ }
+}
+
+static CompRegion
+regionFromBoxes (std::vector<BlurBox> boxes,
+ int width,
+ int height)
+{
+ CompRegion region;
+ int x1, x2, y1, y2;
+
+ foreach (BlurBox &box, boxes)
+ {
+ decor_apply_gravity (box.p1.gravity, box.p1.x, box.p1.y,
+ width, height,
+ &x1, &y1);
+
+
+ decor_apply_gravity (box.p2.gravity, box.p2.x, box.p2.y,
+ width, height,
+ &x2, &y2);
+
+ if (x2 > x1 && y2 > y1)
+ region += CompRect (x1, y1, x2 - x1, y2 - y1);
+ }
+
+ return region;
+}
+
+void
+BlurWindow::updateRegion ()
+{
+ CompRegion region;
+
+ if (state[BLUR_STATE_DECOR].threshold)
+ {
+ region += CompRect (-window->output ().left,
+ -window->output ().top,
+ window->width () + window->output ().right,
+ window->height () + window->output ().bottom);
+
+ region -= CompRect (0, 0, window->width (), window->height ());
+
+ state[BLUR_STATE_DECOR].clipped = false;
+
+ if (!state[BLUR_STATE_DECOR].box.empty ())
+ {
+ CompRegion q = regionFromBoxes (state[BLUR_STATE_DECOR].box,
+ window->width (),
+ window->height ());
+ if (!q.isEmpty ())
+ {
+ q &= region;
+ if (q != region)
+ {
+ region = q;
+ state[BLUR_STATE_DECOR].clipped = true;
+ }
+ }
+ }
+ }
+
+ if (state[BLUR_STATE_CLIENT].threshold)
+ {
+ CompRegion r (0, 0, window->width (), window->height ());
+
+ state[BLUR_STATE_CLIENT].clipped = false;
+
+ if (!state[BLUR_STATE_CLIENT].box.empty ())
+ {
+ CompRegion q = regionFromBoxes (state[BLUR_STATE_CLIENT].box,
+ window->width (),
+ window->height ());
+ if (!q.isEmpty ())
+ {
+ q &= r;
+
+ if (q != r)
+ state[BLUR_STATE_CLIENT].clipped = true;
+
+ region += q;
+ }
+ }
+ else
+ {
+ region += r;
+ }
+ }
+
+ this->region = region;
+ if (!region.isEmpty ())
+ this->region.translate (window->x (), window->y ());
+}
+
+void
+BlurWindow::setBlur (int state,
+ int threshold,
+ std::vector<BlurBox> box)
+{
+
+ this->state[state].threshold = threshold;
+ this->state[state].box = box;
+
+ updateRegion ();
+
+ cWindow->addDamage ();
+}
+
+void
+BlurWindow::updateAlphaMatch ()
+{
+ if (!propSet[BLUR_STATE_CLIENT])
+ {
+ CompMatch *match;
+
+ match = &bScreen->opt[BLUR_OPTION_ALPHA_BLUR_MATCH].value ().match ();
+ if (match->evaluate (window))
+ {
+ if (!state[BLUR_STATE_CLIENT].threshold)
+ setBlur (BLUR_STATE_CLIENT, 4, std::vector<BlurBox> ());
+ }
+ else
+ {
+ if (state[BLUR_STATE_CLIENT].threshold)
+ setBlur (BLUR_STATE_CLIENT, 0, std::vector<BlurBox> ());
+ }
+ }
+}
+
+void
+BlurWindow::updateMatch ()
+{
+ CompMatch *match;
+ bool focus;
+
+ updateAlphaMatch ();
+
+ match = &bScreen->opt[BLUR_OPTION_FOCUS_BLUR_MATCH].value ().match ();
+
+ focus = GL::fragmentProgram && match->evaluate (window);
+ if (focus != focusBlur)
+ {
+ focusBlur = focus;
+ cWindow->addDamage ();
+ }
+}
+
+
+
+void
+BlurWindow::update (int state)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *propData;
+ int threshold = 0;
+ std::vector<BlurBox> boxes;
+
+ result = XGetWindowProperty (screen->dpy (), window->id (),
+ bScreen->blurAtom[state], 0L, 8192L, FALSE,
+ XA_INTEGER, &actual, &format,
+ &n, &left, &propData);
+
+ if (result == Success && n && propData)
+ {
+ propSet[state] = true;
+
+ if (n >= 2)
+ {
+ long *data = (long *) propData;
+ BlurBox box;
+
+ threshold = data[0];
+
+ if ((n - 2) / 6)
+ {
+ int i;
+
+ data += 2;
+
+ for (i = 0; i < (n - 2) / 6; i++)
+ {
+ box.p1.gravity = *data++;
+ box.p1.x = *data++;
+ box.p1.y = *data++;
+ box.p2.gravity = *data++;
+ box.p2.x = *data++;
+ box.p2.y = *data++;
+
+ boxes.push_back (box);
+ }
+
+ }
+ }
+
+ XFree (propData);
+ }
+ else
+ {
+ propSet[state] = false;
+ }
+
+ setBlur (state, threshold, boxes);
+
+ updateAlphaMatch ();
+}
+
+void
+BlurScreen::preparePaint (int msSinceLastPaint)
+{
+ if (moreBlur)
+ {
+ int steps;
+ bool focus = opt[BLUR_OPTION_FOCUS_BLUR].value ().b ();
+ bool focusBlur;
+
+ steps = (msSinceLastPaint * 0xffff) / blurTime;
+ if (steps < 12)
+ steps = 12;
+
+ moreBlur = false;
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ BLUR_WINDOW (w);
+
+ focusBlur = bw->focusBlur && focus;
+
+ if (!bw->pulse &&
+ (!focusBlur || w->id () == screen->activeWindow ()))
+ {
+ if (bw->blur)
+ {
+ bw->blur -= steps;
+ if (bw->blur > 0)
+ 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;
+ }
+
+ moreBlur = true;
+ }
+ else
+ {
+ bw->blur += steps;
+ if (bw->blur < 0xffff)
+ moreBlur = true;
+ else
+ bw->blur = 0xffff;
+ }
+ }
+ }
+ }
+ }
+
+ cScreen->preparePaint (msSinceLastPaint);
+
+ if (cScreen->damageMask () & COMPOSITE_SCREEN_DAMAGE_REGION_MASK)
+ {
+ /* walk from bottom to top and expand damage */
+ if (alphaBlur)
+ {
+ int x1, y1, x2, y2;
+ int count = 0;
+ CompRegion damage (cScreen->currentDamage ());
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ BLUR_WINDOW (w);
+
+ if (!w->isViewable () || !CompositeWindow::get (w)->damaged ())
+ continue;
+
+ if (!bw->region.isEmpty ())
+ {
+ CompRect r = bw->region.boundingRect ();
+ CompRect d = damage.boundingRect ();
+ x1 = r.x1 () - filterRadius;
+ y1 = r.y1 () - filterRadius;
+ x2 = r.x2 () + filterRadius;
+ y2 = r.y2 () + filterRadius;
+
+ if (x1 < d.x2 () &&
+ y1 < d.y2 () &&
+ x2 > d.x1 () &&
+ y2 > d.y1 ())
+ {
+ damage.shrink (-filterRadius, -filterRadius);
+ count++;
+ }
+ }
+ }
+
+ if (count)
+ cScreen->damageRegion (damage);
+
+ this->count = count;
+ }
+ }
+}
+
+bool
+BlurScreen::glPaintOutput (const GLScreenPaintAttrib &sAttrib,
+ const GLMatrix &transform, const CompRegion &region,
+ CompOutput *output, unsigned int mask)
+{
+ bool status;
+
+ if (alphaBlur)
+ {
+ stencilBox = region.boundingRect ();
+ this->region = region;
+
+ if (mask & PAINT_SCREEN_REGION_MASK)
+ {
+ /* we need to redraw more than the screen region being updated */
+ if (count)
+ {
+ this->region.shrink (-filterRadius * 2, -filterRadius * 2);
+
+ this->region &= screen->region ();
+ }
+ }
+ }
+
+ if (!blurOcclusion)
+ {
+ occlusion = CompRegion ();
+
+ foreach (CompWindow *w, screen->windows ())
+ BlurWindow::get (w)->clip = CompRegion ();
+ }
+
+ this->output = output;
+
+ if (alphaBlur)
+ status = gScreen->glPaintOutput (sAttrib, transform, this->region, output, mask);
+ else
+ status = gScreen->glPaintOutput (sAttrib, transform, region, output, mask);
+
+ return status;
+}
+
+void
+BlurScreen::glPaintTransformedOutput (const GLScreenPaintAttrib &sAttrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output, unsigned int mask)
+{
+ if (!blurOcclusion)
+ {
+ occlusion = CompRegion ();
+
+ foreach (CompWindow *w, screen->windows ())
+ BlurWindow::get (w)->clip = CompRegion ();
+ }
+
+ gScreen->glPaintTransformedOutput (sAttrib, transform, region, output, mask);
+}
+
+void
+BlurScreen::donePaint ()
+{
+ if (moreBlur)
+ {
+ foreach (CompWindow *w, screen->windows ())
+ {
+ BLUR_WINDOW (w);
+
+ if (bw->blur > 0 && bw->blur < 0xffff)
+ bw->cWindow->addDamage ();
+ }
+ }
+
+ cScreen->donePaint ();
+}
+
+bool
+BlurWindow::glPaint (const GLWindowPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region, unsigned int mask)
+{
+
+ bool status = gWindow->glPaint (attrib, transform, region, mask);
+
+ if (!bScreen->blurOcclusion &&
+ (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK))
+ {
+ clip = bScreen->occlusion;
+
+ if (!(gWindow->lastMask () & PAINT_WINDOW_NO_CORE_INSTANCE_MASK) &&
+ !(gWindow->lastMask () & PAINT_WINDOW_TRANSFORMED_MASK) &&
+ !this->region.isEmpty ())
+ bScreen->occlusion += this->region;
+ }
+
+ return status;
+}
+
+GLFragment::FunctionId
+BlurScreen::getSrcBlurFragmentFunction (GLTexture *texture,
+ int param)
+{
+ GLFragment::FunctionData data;
+ BlurFunction function;
+ int target;
+
+ if (texture->target () == GL_TEXTURE_2D)
+ target = COMP_FETCH_TARGET_2D;
+ else
+ target = COMP_FETCH_TARGET_RECT;
+
+ foreach (BlurFunction &bf, srcBlurFunctions)
+ if (bf.param == param && bf.target == target)
+ return bf.id;
+
+ if (data.status ())
+ {
+ static const char *temp[] = { "offset0", "offset1", "sum" };
+ int i;
+
+ for (i = 0; i < sizeof (temp) / sizeof (temp[0]); i++)
+ data.addTempHeaderOp (temp[i]);
+
+ data.addDataOp (
+ "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);
+
+
+ switch (opt[BLUR_OPTION_FILTER].value ().i ()) {
+ case BLUR_FILTER_4X_BILINEAR:
+ default:
+ data.addFetchOp ("output", "offset0", target);
+ data.addDataOp ("MUL sum, output, 0.25;");
+ data.addFetchOp ("output", "-offset0", target);
+ data.addDataOp ("MAD sum, output, 0.25, sum;");
+ data.addFetchOp ("output", "offset1", target);
+ data.addDataOp ("MAD sum, output, 0.25, sum;");
+ data.addFetchOp ("output", "-offset1", target);
+ data.addDataOp ("MAD output, output, 0.25, sum;");
+ break;
+ }
+
+ if (!data.status ())
+ return 0;
+
+ function.id = data.createFragmentFunction ("blur");
+ function.target = target;
+ function.param = param;
+ function.unit = 0;
+
+ srcBlurFunctions.push_back (function);
+
+ return function.id;
+ }
+
+ return 0;
+}
+
+GLFragment::FunctionId
+BlurScreen::getDstBlurFragmentFunction (GLTexture *texture,
+ int param,
+ int unit,
+ int numITC,
+ int startTC)
+{
+ BlurFunction function;
+ GLFragment::FunctionData data;
+ int target;
+ char *targetString;
+
+ if (texture->target () == GL_TEXTURE_2D)
+ {
+ target = COMP_FETCH_TARGET_2D;
+ targetString = (char *) "2D";
+ }
+ else
+ {
+ target = COMP_FETCH_TARGET_RECT;
+ targetString = (char *) "RECT";
+ }
+
+ foreach (BlurFunction &function, dstBlurFunctions)
+ if (function.param == param &&
+ function.target == target &&
+ function.unit == unit &&
+ function.numITC == numITC &&
+ function.startTC == startTC)
+ return function.id;
+
+ if (data.status ())
+ {
+ static const char *temp[] = { "fCoord", "mask", "sum", "dst" };
+ int i, j;
+ char str[1024];
+ int saturation = opt[BLUR_OPTION_SATURATION].value ().i ();
+ int numIndirect;
+ int numIndirectOp;
+ int base, end, ITCbase;
+
+ for (i = 0; i < sizeof (temp) / sizeof (temp[0]); i++)
+ data.addTempHeaderOp (temp[i]);
+
+ if (saturation < 100)
+ data.addTempHeaderOp ("sat");
+
+ switch (opt[BLUR_OPTION_FILTER].value ().i ()) {
+ case BLUR_FILTER_4X_BILINEAR: {
+ static const char *filterTemp[] = {
+ "t0", "t1", "t2", "t3",
+ "s0", "s1", "s2", "s3"
+ };
+
+ for (i = 0; i < sizeof (filterTemp) / sizeof (filterTemp[0]); i++)
+ data.addTempHeaderOp (filterTemp[i]);
+
+ data.addFetchOp ("output", NULL, target);
+ data.addColorOp ("output", "output");
+
+ data.addDataOp (
+ "MUL fCoord, fragment.position, program.env[%d];",
+ param);
+
+
+ data.addDataOp (
+ "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);
+
+ } break;
+ case BLUR_FILTER_GAUSSIAN: {
+
+ /* try to use only half of the available temporaries to keep
+ other plugins working */
+ if ((maxTemp / 2) - 4 >
+ (numTexop + (numTexop - numITC)) * 2)
+ {
+ numIndirect = 1;
+ numIndirectOp = numTexop;
+ }
+ else
+ {
+ i = MAX(((maxTemp / 2) - 4) / 4, 1);
+ numIndirect = ceil ((float)numTexop / (float)i);
+ numIndirectOp = ceil ((float)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);
+ data.addTempHeaderOp (str);
+ }
+
+ for (i = j * 2; i < numIndirectOp * 2; i++)
+ {
+ snprintf (str, 1024, "coord_%d", i);
+ data.addTempHeaderOp (str);
+ }
+
+
+ data.addFetchOp ("output", NULL, target);
+ data.addColorOp ("output", "output");
+
+ data.addDataOp (
+ "MUL fCoord, fragment.position, program.env[%d];",
+ param);
+
+
+ data.addDataOp ("TEX sum, fCoord, texture[%d], %s;",
+ unit + 1, targetString);
+
+
+ data.addDataOp ("MUL_SAT mask, output.a, program.env[%d];"
+ "MUL sum, sum, %f;",
+ param + 1, amp[numTexop]);
+
+ for (j = 0; j < numIndirect; j++)
+ {
+ base = j * numIndirectOp;
+ end = MIN ((j + 1) * numIndirectOp, numTexop) - base;
+
+ ITCbase = MAX (numITC - base, 0);
+
+ for (i = ITCbase; i < end; i++)
+ {
+ data.addDataOp (
+ "ADD coord_%d, fCoord, {0.0, %g, 0.0, 0.0};"
+ "SUB coord_%d, fCoord, {0.0, %g, 0.0, 0.0};",
+ i * 2, pos[base + i] * ty,
+ (i * 2) + 1, pos[base + i] * ty);
+ }
+
+ for (i = 0; i < ITCbase; i++)
+ {
+ data.addDataOp (
+ "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);
+ }
+
+ for (i = ITCbase; i < end; i++)
+ {
+ data.addDataOp (
+ "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);
+ }
+
+ for (i = 0; i < end * 2; i++)
+ {
+ data.addDataOp (
+ "MAD sum, pix_%d, %f, sum;",
+ i, amp[base + (i / 2)]);
+ }
+ }
+
+ } break;
+ case BLUR_FILTER_MIPMAP:
+ data.addFetchOp ("output", NULL, target);
+ data.addColorOp ("output", "output");
+
+ data.addDataOp (
+ "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);
+
+ break;
+ }
+
+ if (saturation < 100)
+ {
+ data.addDataOp (
+ "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);
+ }
+
+ data.addDataOp (
+ "MAD dst, mask, -output.a, mask;"
+ "MAD output.rgb, sum, dst.a, output;"
+ "ADD output.a, output.a, dst.a;");
+
+ if (!data.status ())
+ {
+ return 0;
+ }
+
+
+
+ function.id = data.createFragmentFunction ("blur");
+ function.target = target;
+ function.param = param;
+ function.unit = unit;
+ function.numITC = numITC;
+ function.startTC = startTC;
+
+ dstBlurFunctions.push_back (function);
+
+ return function.id;
+ }
+
+ return 0;
+}
+
+bool
+BlurScreen::projectVertices (CompOutput *output,
+ const GLMatrix &transform,
+ const float *object,
+ float *scr,
+ int n)
+{
+ GLdouble dProjection[16];
+ GLdouble dModel[16];
+ GLint viewport[4];
+ double x, y, z;
+ int i;
+
+ viewport[0] = output->x1 ();
+ viewport[1] = screen->height () - output->y2 ();
+ viewport[2] = output->width ();
+ viewport[3] = output->height ();
+
+ for (i = 0; i < 16; i++)
+ {
+ dModel[i] = transform.getMatrix ()[i];
+ dProjection[i] = gScreen->projectionMatrix ()[i];
+ }
+
+ while (n--)
+ {
+ if (!gluProject (object[0], object[1], object[2],
+ dModel, dProjection, viewport,
+ &x, &y, &z))
+ return false;
+
+ scr[0] = x;
+ scr[1] = y;
+
+ object += 3;
+ scr += 2;
+ }
+
+ return true;
+}
+
+bool
+BlurScreen::loadFragmentProgram (GLuint *program,
+ const char *string)
+{
+ GLint errorPos;
+
+ /* clear errors */
+ glGetError ();
+
+ if (!*program)
+ (*GL::genPrograms) (1, program);
+
+ (*GL::bindProgram) (GL_FRAGMENT_PROGRAM_ARB, *program);
+ (*GL::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);
+
+ (*GL::deletePrograms) (1, program);
+ *program = 0;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool
+BlurScreen::loadFilterProgram (int numITC)
+{
+ char buffer[4096];
+ char *targetString;
+ char *str = buffer;
+ int i, j;
+ int numIndirect;
+ int numIndirectOp;
+ int base, end, ITCbase;
+
+ if (target == GL_TEXTURE_2D)
+ targetString = (char *) "2D";
+ else
+ targetString = (char *) "RECT";
+
+ str += sprintf (str,
+ "!!ARBfp1.0"
+ "ATTRIB texcoord = fragment.texcoord[0];"
+ "TEMP sum;");
+
+ if (maxTemp - 1 > (numTexop + (numTexop - numITC)) * 2)
+ {
+ numIndirect = 1;
+ numIndirectOp = numTexop;
+ }
+ else
+ {
+ i = (maxTemp - 1) / 4;
+ numIndirect = ceil ((float)numTexop / (float)i);
+ numIndirectOp = ceil ((float)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;",
+ amp[numTexop]);
+
+ for (j = 0; j < numIndirect; j++)
+ {
+ base = j * numIndirectOp;
+ end = MIN ((j + 1) * numIndirectOp, 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, pos[base + i] * tx,
+ (i * 2) + 1, pos[base + i] * 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, amp[base + (i / 2)]);
+ }
+
+ str += sprintf (str,
+ "MOV result.color, sum;"
+ "END");
+
+ return loadFragmentProgram (&program, buffer);
+}
+
+bool
+BlurScreen::fboPrologue ()
+{
+ if (!fbo)
+ return false;
+
+ (*GL::bindFramebuffer) (GL_FRAMEBUFFER_EXT, fbo);
+
+ /* bind texture and check status the first time */
+ if (!fboStatus)
+ {
+ (*GL::framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ target, texture[1],
+ 0);
+
+ fboStatus = (*GL::checkFramebufferStatus) (GL_FRAMEBUFFER_EXT);
+ if (fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ compLogMessage ("blur", CompLogLevelError,
+ "Framebuffer incomplete");
+
+ (*GL::bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
+ (*GL::deleteFramebuffers) (1, &fbo);
+
+ fbo = 0;
+
+ return false;
+ }
+ }
+
+ 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, width, height);
+ glMatrixMode (GL_PROJECTION);
+ glPushMatrix ();
+ glLoadIdentity ();
+ glOrtho (0.0, width, 0.0, height, -1.0, 1.0);
+ glMatrixMode (GL_MODELVIEW);
+ glPushMatrix ();
+ glLoadIdentity ();
+
+ return true;
+}
+
+void
+BlurScreen::fboEpilogue ()
+{
+ (*GL::bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ glMatrixMode (GL_MODELVIEW);
+ glLoadIdentity ();
+ glDepthRange (0, 1);
+ glViewport (-1, -1, 2, 2);
+ glRasterPos2f (0, 0);
+
+ gScreen->resetRasterPos ();
+
+ glMatrixMode (GL_PROJECTION);
+ glPopMatrix ();
+ glMatrixMode (GL_MODELVIEW);
+ glPopMatrix ();
+
+ glDrawBuffer (GL_BACK);
+ glReadBuffer (GL_BACK);
+
+ glPopAttrib ();
+}
+
+bool
+BlurScreen::fboUpdate (BoxPtr pBox,
+ int nBox)
+{
+ int i, y, iTC = 0;
+ Bool wasCulled = glIsEnabled (GL_CULL_FACE);
+
+ if (GL::maxTextureUnits &&
+ opt[BLUR_OPTION_INDEPENDENT_TEX].value ().b ())
+ iTC = MIN ((GL::maxTextureUnits - 1) / 2, numTexop);
+
+ if (!program)
+ if (!loadFilterProgram (iTC))
+ return false;
+
+ if (!fboPrologue ())
+ return false;
+
+ glDisable (GL_CULL_FACE);
+
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ glBindTexture (target, texture[0]);
+
+ glEnable (GL_FRAGMENT_PROGRAM_ARB);
+ (*GL::bindProgram) (GL_FRAGMENT_PROGRAM_ARB, program);
+
+ glBegin (GL_QUADS);
+
+ while (nBox--)
+ {
+ y = screen->height () - pBox->y2;
+
+ for (i = 0; i < iTC; i++)
+ {
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
+ tx * (pBox->x1 + pos[i]),
+ ty * y);
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
+ tx * (pBox->x1 - pos[i]),
+ ty * y);
+ }
+
+ glTexCoord2f (tx * pBox->x1, ty * y);
+ glVertex2i (pBox->x1, y);
+
+ for (i = 0; i < iTC; i++)
+ {
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
+ tx * (pBox->x2 + pos[i]),
+ ty * y);
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
+ tx * (pBox->x2 - pos[i]),
+ ty * y);
+ }
+
+ glTexCoord2f (tx * pBox->x2, ty * y);
+ glVertex2i (pBox->x2, y);
+
+ y = screen->height () - pBox->y1;
+
+ for (i = 0; i < iTC; i++)
+ {
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
+ tx * (pBox->x2 + pos[i]),
+ ty * y);
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
+ tx * (pBox->x2 - pos[i]),
+ ty * y);
+ }
+
+ glTexCoord2f (tx * pBox->x2, ty * y);
+ glVertex2i (pBox->x2, y);
+
+ for (i = 0; i < iTC; i++)
+ {
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
+ tx * (pBox->x1 + pos[i]),
+ ty * y);
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
+ tx * (pBox->x1 - pos[i]),
+ ty * y);
+ }
+
+ glTexCoord2f (tx * pBox->x1, 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 ();
+
+ return true;
+}
+
+#define MAX_VERTEX_PROJECT_COUNT 20
+
+void
+BlurWindow::projectRegion (CompOutput *output,
+ const GLMatrix &transform)
+{
+ float scrv[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;
+
+ GLTexture::MatrixList ml;
+ GLWindow::Geometry *gm;
+
+ gWindow->geometry ().reset ();
+ gWindow->glAddGeometry (ml, bScreen->tmpRegion2, infiniteRegion);
+
+ if (!gWindow->geometry ().vCount)
+ return;
+
+ gm = &gWindow->geometry ();
+
+ nVertices = (gm->indexCount) ? gm->indexCount: gm->vCount;
+ nQuadCombine = 1;
+
+ stride = gm->vertexStride;
+ vert = gm->vertices + (stride - 3);
+
+ /* we need to find the best value here */
+ if (nVertices <= MAX_VERTEX_PROJECT_COUNT)
+ {
+ for (i = 0; i < nVertices; i++)
+ {
+ if (gm->indexCount)
+ {
+ v = vert + (stride * gm->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 = screen->width ();
+ maxX = 0;
+ minY = screen->height ();
+ maxY = 0;
+ minZ = 1000000;
+ maxZ = -1000000;
+
+ for (i = 0; i < gm->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 (!bScreen->projectVertices (output, transform, vertices, scrv,
+ nVertices * nQuadCombine))
+ return;
+
+ for (i = 0; i < nVertices / 4; i++)
+ {
+ scr = scrv + (i * 4 * 2);
+
+ minX = screen->width ();
+ maxX = 0;
+ minY = screen->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];
+ }
+
+ int x1, y1, x2, y2;
+
+ x1 = minX - bScreen->filterRadius;
+ y1 = screen->height () - maxY - bScreen->filterRadius;
+ x2 = maxX + bScreen->filterRadius + 0.5f;
+ y2 = screen->height () - minY + bScreen->filterRadius + 0.5f;
+
+
+ bScreen->tmpRegion3 += CompRect (x1, y1, x2 - x1, y2 - y1);
+
+ }
+}
+
+bool
+BlurWindow::updateDstTexture (const GLMatrix &transform,
+ CompRect *pExtents,
+ int clientThreshold)
+{
+ int y;
+ int filter;
+
+ filter = bScreen->opt[BLUR_OPTION_FILTER].value ().i ();
+
+ bScreen->tmpRegion3 = CompRegion ();
+
+ if (filter == BLUR_FILTER_GAUSSIAN)
+ {
+
+ if (state[BLUR_STATE_DECOR].threshold)
+ {
+ int xx, yy, ww, hh;
+ // top
+ xx = window->x () - window->output ().left;
+ yy = window->y () - window->output ().top;
+ ww = window->width () + window->output ().left + window->output ().right;
+ hh = window->output ().top;
+
+ bScreen->tmpRegion2 = bScreen->tmpRegion.intersected (
+ CompRect (xx, yy, ww, hh));
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+
+ // bottom
+ xx = window->x () - window->output ().left;
+ yy = window->y () + window->height ();
+ ww = window->width () + window->output ().left + window->output ().right;
+ hh = window->output ().bottom;
+
+ bScreen->tmpRegion2 = bScreen->tmpRegion.intersected (
+ CompRect (xx, yy, ww, hh));
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+
+ // left
+ xx = window->x () - window->output ().left;
+ yy = window->y ();
+ ww = window->output ().left;
+ hh = window->height ();
+
+ bScreen->tmpRegion2 = bScreen->tmpRegion.intersected (
+ CompRect (xx, yy, ww, hh));
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+
+ // right
+ xx = window->x () + window->width ();
+ yy = window->y ();
+ ww = window->output ().right;
+ hh = window->height ();
+
+ bScreen->tmpRegion2 = bScreen->tmpRegion.intersected (
+ CompRect (xx, yy, ww, hh));
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+ }
+
+ if (clientThreshold)
+ {
+ // center
+ bScreen->tmpRegion2 = bScreen->tmpRegion.intersected (
+ CompRect (window->x (),
+ window->y (),
+ window->width (),
+ window->height ()));
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+ }
+ }
+ else
+ {
+ // center
+ bScreen->tmpRegion2 = bScreen->tmpRegion;
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+ }
+
+ bScreen->tmpRegion = bScreen->region.intersected (bScreen->tmpRegion3);
+
+ if (bScreen->tmpRegion.isEmpty ())
+ return false;
+
+ *pExtents = bScreen->tmpRegion.boundingRect ();
+
+ if (!bScreen->texture[0] || bScreen->width != screen->width () ||
+ bScreen->height != screen->height ())
+ {
+ int i, textures = 1;
+
+ bScreen->width = screen->width ();
+ bScreen->height = screen->height ();
+
+ if (GL::textureNonPowerOfTwo ||
+ (POWER_OF_TWO (bScreen->width) && POWER_OF_TWO (bScreen->height)))
+ {
+ bScreen->target = GL_TEXTURE_2D;
+ bScreen->tx = 1.0f / bScreen->width;
+ bScreen->ty = 1.0f / bScreen->height;
+ }
+ else
+ {
+ bScreen->target = GL_TEXTURE_RECTANGLE_NV;
+ bScreen->tx = 1;
+ bScreen->ty = 1;
+ }
+
+ if (filter == BLUR_FILTER_GAUSSIAN)
+ {
+ if (GL::fbo && !bScreen->fbo)
+ (*GL::genFramebuffers) (1, &bScreen->fbo);
+
+ if (!bScreen->fbo)
+ compLogMessage ("blur", CompLogLevelError,
+ "Failed to create framebuffer object");
+
+ textures = 2;
+ }
+
+ bScreen->fboStatus = FALSE;
+
+ for (i = 0; i < textures; i++)
+ {
+ if (!bScreen->texture[i])
+ glGenTextures (1, &bScreen->texture[i]);
+
+ glBindTexture (bScreen->target, bScreen->texture[i]);
+
+ glTexImage2D (bScreen->target, 0, GL_RGB,
+ bScreen->width,
+ bScreen->height,
+ 0, GL_BGRA,
+
+#if IMAGE_BYTE_ORDER == MSBFirst
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+#else
+ GL_UNSIGNED_BYTE,
+#endif
+
+ NULL);
+
+ glTexParameteri (bScreen->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (bScreen->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ if (filter == BLUR_FILTER_MIPMAP)
+ {
+ if (!GL::fbo)
+ {
+ compLogMessage ("blur", CompLogLevelWarn,
+ "GL_EXT_framebuffer_object extension "
+ "is required for mipmap filter");
+ }
+ else if (bScreen->target != GL_TEXTURE_2D)
+ {
+ compLogMessage ("blur", CompLogLevelWarn,
+ "GL_ARB_texture_non_power_of_two "
+ "extension is required for mipmap filter");
+ }
+ else
+ {
+ glTexParameteri (bScreen->target, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri (bScreen->target, GL_TEXTURE_MAG_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ }
+ }
+
+ glTexParameteri (bScreen->target, GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ glTexParameteri (bScreen->target, GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
+
+ glCopyTexSubImage2D (bScreen->target, 0, 0, 0, 0, 0,
+ bScreen->width, bScreen->height);
+ }
+ }
+ else
+ {
+ glBindTexture (bScreen->target, bScreen->texture[0]);
+
+ CompRect br = bScreen->tmpRegion.boundingRect ();
+
+ y = screen->height () - br.y2 ();
+
+ glCopyTexSubImage2D (bScreen->target, 0,
+ br.x1 (), y,
+ br.x1 (), y,
+ br.width (),
+ br.height ());
+ }
+
+ switch (filter) {
+ case BLUR_FILTER_GAUSSIAN:
+ return bScreen->fboUpdate (bScreen->tmpRegion.handle()->rects,
+ bScreen->tmpRegion.numRects ());
+ case BLUR_FILTER_MIPMAP:
+ (*GL::generateMipmap) (bScreen->target);
+ break;
+ case BLUR_FILTER_4X_BILINEAR:
+ break;
+ }
+
+ glBindTexture (bScreen->target, 0);
+
+ return true;
+}
+
+bool
+BlurWindow::glDraw (const GLMatrix &transform,
+ GLFragment::Attrib &attrib,
+ const CompRegion &region,
+ unsigned int mask)
+{
+ bool status;
+
+ if (bScreen->alphaBlur && !region.isEmpty ())
+ {
+ int clientThreshold;
+
+ /* only care about client window blurring when it's translucent */
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ clientThreshold = state[BLUR_STATE_CLIENT].threshold;
+ else
+ clientThreshold = 0;
+
+ if (state[BLUR_STATE_DECOR].threshold || clientThreshold)
+ {
+ bool clipped = FALSE;
+ CompRect box (0, 0, 0, 0);
+ CompRegion reg;
+ int i;
+
+ bScreen->mvp = GLMatrix (bScreen->gScreen->projectionMatrix ());
+ bScreen->mvp *= transform;
+
+ if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
+ reg = infiniteRegion;
+ else
+ reg = region;
+
+ bScreen->tmpRegion = this->region.intersected (reg);
+ if (!bScreen->blurOcclusion &&
+ !(mask & PAINT_WINDOW_TRANSFORMED_MASK))
+ bScreen->tmpRegion -= clip;
+
+ if (updateDstTexture (transform, &box, clientThreshold))
+ {
+ if (clientThreshold)
+ {
+ if (state[BLUR_STATE_CLIENT].clipped)
+ {
+ if (bScreen->stencilBits)
+ {
+ state[BLUR_STATE_CLIENT].active = true;
+ clipped = true;
+ }
+ }
+ else
+ {
+ state[BLUR_STATE_CLIENT].active = true;
+ }
+ }
+
+ if (state[BLUR_STATE_DECOR].threshold)
+ {
+ if (state[BLUR_STATE_DECOR].clipped)
+ {
+ if (bScreen->stencilBits)
+ {
+ state[BLUR_STATE_DECOR].active = true;
+ clipped = true;
+ }
+ }
+ else
+ {
+ state[BLUR_STATE_DECOR].active = true;
+ }
+ }
+
+ if (!bScreen->blurOcclusion && !clip.isEmpty ())
+ clipped = true;
+ }
+
+ if (!bScreen->blurOcclusion)
+ bScreen->tmpRegion = this->region - clip;
+ else
+ bScreen->tmpRegion = this->region;
+
+ if (!clientThreshold)
+ {
+ bScreen->tmpRegion -= CompRect (window->x (),
+ window->x () + window->width (),
+ window->y (),
+ window->y () + window->height ());
+ }
+
+ if (clipped)
+ {
+ GLTexture::MatrixList ml;
+
+ gWindow->geometry ().reset ();
+
+ gWindow->glAddGeometry (ml, bScreen->tmpRegion, reg);
+ if (gWindow->geometry ().vCount)
+ {
+ CompRect clearBox = bScreen->stencilBox;
+
+ bScreen->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 (),
+ screen->height () - clearBox.y2 (),
+ clearBox.width (),
+ clearBox.height ());
+ glClear (GL_STENCIL_BUFFER_BIT);
+ glPopAttrib ();
+ }
+
+ glStencilFunc (GL_ALWAYS, 0x1, ~0);
+ glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
+
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+ gWindow->glDrawGeometry ();
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDisable (GL_STENCIL_TEST);
+ }
+ }
+ }
+ }
+
+ status = gWindow->glDraw (transform, attrib, region, mask);
+
+ state[BLUR_STATE_CLIENT].active = false;
+ state[BLUR_STATE_DECOR].active = false;
+
+ return status;
+}
+
+void
+BlurWindow::glDrawTexture (GLTexture *texture,
+ GLFragment::Attrib &attrib,
+ unsigned int mask)
+{
+ int state = BLUR_STATE_DECOR;
+
+ foreach (GLTexture *tex, gWindow->textures ())
+ if (texture == tex)
+ state = BLUR_STATE_CLIENT;
+
+ if (blur || this->state[state].active)
+ {
+ GLFragment::Attrib fa (attrib);
+ int param, function;
+ int unit = 0;
+ GLfloat dx, dy;
+ int iTC = 0;
+
+ if (blur)
+ {
+ param = fa.allocParameters (1);
+
+ function = bScreen->getSrcBlurFragmentFunction (texture, param);
+ if (function)
+ {
+ fa.addFunction (function);
+
+ dx = ((texture->matrix ().xx / 2.1f) * blur) / 65535.0f;
+ dy = ((texture->matrix ().yy / 2.1f) * blur) / 65535.0f;
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param, dx, dy, dx, -dy);
+
+ /* bi-linear filtering is required */
+ mask |= PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
+ }
+ }
+
+ if (this->state[state].active)
+ {
+ GLFragment::Attrib dstFa (fa);
+ float threshold = (float) this->state[state].threshold;
+
+ switch (bScreen->opt[BLUR_OPTION_FILTER].value ().i ()) {
+ case BLUR_FILTER_4X_BILINEAR:
+ dx = bScreen->tx / 2.1f;
+ dy = bScreen->ty / 2.1f;
+
+ param = dstFa.allocParameters (3);
+ unit = dstFa.allocTextureUnits (1);
+
+ function = bScreen->getDstBlurFragmentFunction (
+ texture, param, unit, 0, 0);
+ if (function)
+ {
+ dstFa.addFunction (function);
+
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit);
+ glBindTexture (bScreen->target, bScreen->texture[0]);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param,
+ bScreen->tx, bScreen->ty,
+ 0.0f, 0.0f);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param + 1,
+ threshold, threshold,
+ threshold, threshold);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param + 2,
+ dx, dy, 0.0f, 0.0f);
+ }
+ break;
+ case BLUR_FILTER_GAUSSIAN:
+ if (bScreen->opt[BLUR_OPTION_INDEPENDENT_TEX].value ().b ())
+ {
+ /* leave one free texture unit for fragment position */
+ iTC = MAX (0, GL::maxTextureUnits -
+ (gWindow->geometry ().texUnits + 1));
+ if (iTC)
+ iTC = MIN (iTC / 2, bScreen->numTexop);
+ }
+
+ param = dstFa.allocParameters (2);
+ unit = dstFa.allocTextureUnits (2);
+
+ function = bScreen->getDstBlurFragmentFunction (
+ texture, param, unit, iTC, gWindow->geometry().texUnits);
+ if (function)
+ {
+ int i;
+
+ dstFa.addFunction (function);
+
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit);
+ glBindTexture (bScreen->target, bScreen->texture[0]);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit + 1);
+ glBindTexture (bScreen->target, bScreen->texture[1]);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param, bScreen->tx,
+ bScreen->ty, 0.0f, 0.0f);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param + 1,
+ threshold, threshold,
+ threshold, threshold);
+
+ if (iTC)
+ {
+ GLMatrix tm, rm;
+ float s_gen[4], t_gen[4], q_gen[4];
+
+ for (i = 0; i < 16; i++)
+ tm[i] = 0;
+ tm[0] = (bScreen->output->width () / 2.0) *
+ bScreen->tx;
+ tm[5] = (bScreen->output->height () / 2.0) *
+ bScreen->ty;
+ tm[10] = 1;
+
+ tm[12] = (bScreen->output->width () / 2.0 +
+ bScreen->output->x1 ()) * bScreen->tx;
+ tm[13] = (bScreen->output->height () / 2.0 +
+ screen->height () -
+ bScreen->output->y2 ()) * bScreen->ty;
+ tm[14] = 1;
+ tm[15] = 1;
+
+ tm *= bScreen->mvp;
+
+ for (i = 0; i < iTC; i++)
+ {
+ (*GL::activeTexture) (GL_TEXTURE0_ARB +
+ gWindow->geometry ().texUnits + (i * 2));
+
+ rm.reset ();
+ rm[13] = bScreen->ty * bScreen->pos[i];
+ rm *= tm;
+
+ s_gen[0] = rm[0];
+ s_gen[1] = rm[4];
+ s_gen[2] = rm[8];
+ s_gen[3] = rm[12];
+ t_gen[0] = rm[1];
+ t_gen[1] = rm[5];
+ t_gen[2] = rm[9];
+ t_gen[3] = rm[13];
+ q_gen[0] = rm[3];
+ q_gen[1] = rm[7];
+ q_gen[2] = rm[11];
+ q_gen[3] = rm[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);
+
+ (*GL::activeTexture) (GL_TEXTURE0_ARB +
+ gWindow->geometry ().texUnits +
+ 1 + (i * 2));
+
+ rm.reset ();
+
+ rm[13] = -bScreen->ty * bScreen->pos[i];
+ rm *= tm;
+
+ s_gen[0] = rm[0];
+ s_gen[1] = rm[4];
+ s_gen[2] = rm[8];
+ s_gen[3] = rm[12];
+ t_gen[0] = rm[1];
+ t_gen[1] = rm[5];
+ t_gen[2] = rm[9];
+ t_gen[3] = rm[13];
+ q_gen[0] = rm[3];
+ q_gen[1] = rm[7];
+ q_gen[2] = rm[11];
+ q_gen[3] = rm[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);
+ }
+
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+ }
+
+ }
+ break;
+ case BLUR_FILTER_MIPMAP:
+ param = dstFa.allocParameters (2);
+ unit = dstFa.allocTextureUnits (1);
+
+ function =
+ bScreen->getDstBlurFragmentFunction (texture, param,
+ unit, 0, 0);
+ if (function)
+ {
+ float lod =
+ bScreen->opt[BLUR_OPTION_MIPMAP_LOD].value ().f ();
+
+ dstFa.addFunction (function);
+
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit);
+ glBindTexture (bScreen->target, bScreen->texture[0]);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param,
+ bScreen->tx, bScreen->ty,
+ 0.0f, lod);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param + 1,
+ threshold, threshold,
+ threshold, threshold);
+ }
+ break;
+ }
+
+ if (this->state[state].clipped ||
+ (!bScreen->blurOcclusion && !clip.isEmpty ()))
+ {
+ glEnable (GL_STENCIL_TEST);
+
+ glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
+ glStencilFunc (GL_EQUAL, 0x1, ~0);
+
+ /* draw region with destination blur */
+ gWindow->glDrawTexture (texture, dstFa, mask);
+
+ glStencilFunc (GL_EQUAL, 0, ~0);
+
+ /* draw region without destination blur */
+ gWindow->glDrawTexture (texture, fa, mask);
+
+ glDisable (GL_STENCIL_TEST);
+ }
+ else
+ {
+ /* draw with destination blur */
+ gWindow->glDrawTexture (texture, dstFa, mask);
+ }
+ }
+ else
+ {
+ gWindow->glDrawTexture (texture, fa, mask);
+ }
+
+ if (unit)
+ {
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit);
+ glBindTexture (bScreen->target, 0);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit + 1);
+ glBindTexture (bScreen->target, 0);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+ }
+
+ if (iTC)
+ {
+ int i;
+ for (i = gWindow->geometry().texUnits;
+ i < gWindow->geometry().texUnits + (2 * iTC); i++)
+ {
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + i);
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_TEXTURE_GEN_Q);
+ }
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+ }
+ }
+ else
+ {
+ gWindow->glDrawTexture (texture, attrib, mask);
+ }
+}
+
+void
+BlurScreen::handleEvent (XEvent *event)
+{
+ Window activeWindow = screen->activeWindow ();
+
+ screen->handleEvent (event);
+
+ if (screen->activeWindow () != activeWindow)
+ {
+ CompWindow *w;
+
+ w = screen->findWindow (activeWindow);
+ if (w)
+ {
+ if (opt[BLUR_OPTION_FOCUS_BLUR].value ().b ())
+ {
+ CompositeWindow::get (w)->addDamage ();
+ moreBlur = true;
+ }
+ }
+
+ w = screen->findWindow (screen->activeWindow ());
+ if (w)
+ {
+ if (opt[BLUR_OPTION_FOCUS_BLUR].value ().b ())
+ {
+ CompositeWindow::get (w)->addDamage ();
+ moreBlur = true;
+ }
+ }
+ }
+
+ if (event->type == PropertyNotify)
+ {
+ int i;
+
+ for (i = 0; i < BLUR_STATE_NUM; i++)
+ {
+ if (event->xproperty.atom == blurAtom[i])
+ {
+ CompWindow *w;
+
+ w = screen->findWindow (event->xproperty.window);
+ if (w)
+ BlurWindow::get (w)->update (i);
+ }
+ }
+ }
+}
+
+void
+BlurWindow::resizeNotify (int dx,
+ int dy,
+ int dwidth,
+ int dheight)
+{
+ if (bScreen->alphaBlur)
+ {
+ if (state[BLUR_STATE_CLIENT].threshold ||
+ state[BLUR_STATE_DECOR].threshold)
+ updateRegion ();
+ }
+
+ window->resizeNotify (dx, dy, dwidth, dheight);
+
+}
+
+void
+BlurWindow::moveNotify (int dx,
+ int dy,
+ bool immediate)
+{
+ if (!region.isEmpty ())
+ region.translate (dx, dy);
+
+ window->moveNotify (dx, dy, immediate);
+}
+
+static bool
+blurPulse (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ int xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window",
+ screen->activeWindow ());
+
+ w = screen->findWindow (xid);
+ if (w && GL::fragmentProgram)
+ {
+ BLUR_SCREEN (screen);
+ BLUR_WINDOW (w);
+
+ bw->pulse = TRUE;
+ bs->moreBlur = TRUE;
+
+ bw->cWindow->addDamage ();
+ }
+
+ return false;
+}
+
+void
+BlurScreen::matchExpHandlerChanged ()
+{
+ screen->matchExpHandlerChanged ();
+
+ /* match options are up to date after the call to matchExpHandlerChanged */
+ foreach (CompWindow *w, screen->windows ())
+ BlurWindow::get (w)->updateMatch ();
+
+}
+
+void
+BlurScreen::matchPropertyChanged (CompWindow *w)
+{
+ BlurWindow::get (w)->updateMatch ();
+
+ screen->matchPropertyChanged (w);
+}
+
+static CompMetadata *blurMetadata;
+
+static const CompMetadata::OptionInfo blurOptionInfo[] = {
+ { "pulse", "bell", 0, blurPulse, 0 },
+ { "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 }
+};
+
+CompOption::Vector &
+BlurScreen::getOptions ()
+{
+ return opt;
+}
+
+bool
+BlurScreen::setOption (const char *name,
+ CompOption::Value &value)
+{
+ CompOption *o;
+ unsigned int index;
+
+ o = CompOption::findOption (opt, name, &index);
+ if (!o)
+ return false;
+
+ switch (index) {
+ case BLUR_OPTION_BLUR_SPEED:
+ if (o->set (value))
+ {
+ blurTime = 1000.0f / o->value ().f ();
+ return true;
+ }
+ break;
+ case BLUR_OPTION_FOCUS_BLUR_MATCH:
+ case BLUR_OPTION_ALPHA_BLUR_MATCH:
+ if (o->set (value))
+ {
+ foreach (CompWindow *w, screen->windows ())
+ BlurWindow::get (w)->updateMatch ();
+
+ moreBlur = true;
+ cScreen->damageScreen ();
+
+ return true;
+ }
+ break;
+ case BLUR_OPTION_FOCUS_BLUR:
+ if (o->set (value))
+ {
+ moreBlur = true;
+ cScreen->damageScreen ();
+
+ return true;
+ }
+ break;
+ case BLUR_OPTION_ALPHA_BLUR:
+ if (o->set (value))
+ {
+ if (GL::fragmentProgram && o->value ().b ())
+ alphaBlur = true;
+ else
+ alphaBlur = false;
+
+ cScreen->damageScreen ();
+
+ return true;
+ }
+ break;
+ case BLUR_OPTION_FILTER:
+ if (o->set (value))
+ {
+ blurReset ();
+ cScreen->damageScreen ();
+ return true;
+ }
+ break;
+ case BLUR_OPTION_GAUSSIAN_RADIUS:
+ case BLUR_OPTION_GAUSSIAN_STRENGTH:
+ case BLUR_OPTION_INDEPENDENT_TEX:
+ if (o->set (value))
+ {
+ if (opt[BLUR_OPTION_FILTER].value ().i () == BLUR_FILTER_GAUSSIAN)
+ {
+ blurReset ();
+ cScreen->damageScreen ();
+ }
+ return true;
+ }
+ break;
+ case BLUR_OPTION_MIPMAP_LOD:
+ if (o->set (value))
+ {
+ if (opt[BLUR_OPTION_FILTER].value ().i () == BLUR_FILTER_MIPMAP)
+ {
+ blurReset ();
+ cScreen->damageScreen ();
+ }
+ return true;
+ }
+ break;
+ case BLUR_OPTION_SATURATION:
+ if (o->set (value))
+ {
+ blurReset ();
+ cScreen->damageScreen ();
+ return true;
+ }
+ break;
+ case BLUR_OPTION_BLUR_OCCLUSION:
+ if (o->set (value))
+ {
+ blurOcclusion = o->value ().b ();
+ blurReset ();
+ cScreen->damageScreen ();
+ return true;
+ }
+ break;
+ default:
+ return CompOption::setOption (*o, value);
+ break;
+ }
+
+ return false;
+}
+
+BlurScreen::BlurScreen (CompScreen *screen) :
+ PrivateHandler<BlurScreen,CompScreen> (screen),
+ cScreen (CompositeScreen::get (screen)),
+ gScreen (GLScreen::get (screen)),
+ opt(BLUR_OPTION_NUM),
+ moreBlur (false),
+ filterRadius (0),
+ srcBlurFunctions (0),
+ dstBlurFunctions (0),
+ output (NULL),
+ count (0),
+ program (0),
+ maxTemp (32),
+ fbo (0),
+ fboStatus (0)
+{
+ if (!blurVTable->getMetadata ()->initOptions (blurOptionInfo,
+ BLUR_OPTION_NUM, opt))
+ {
+ setFailed ();
+ return;
+ }
+
+ blurAtom[BLUR_STATE_CLIENT] =
+ XInternAtom (screen->dpy (), "_COMPIZ_WM_WINDOW_BLUR", 0);
+ blurAtom[BLUR_STATE_DECOR] =
+ XInternAtom (screen->dpy (), DECOR_BLUR_ATOM_NAME, 0);
+
+ blurTime = 1000.0f / opt[BLUR_OPTION_BLUR_SPEED].value ().f ();
+ blurOcclusion = opt[BLUR_OPTION_BLUR_OCCLUSION].value ().b ();
+
+ for (int i = 0; i < 2; i++)
+ texture[i] = 0;
+
+ glGetIntegerv (GL_STENCIL_BITS, &stencilBits);
+ if (!stencilBits)
+ compLogMessage ("blur", CompLogLevelWarn,
+ "No stencil buffer. Region based blur disabled");
+
+ /* We need GL_ARB_fragment_program for blur */
+ if (GL::fragmentProgram)
+ alphaBlur = opt[BLUR_OPTION_ALPHA_BLUR].value ().b ();
+ else
+ alphaBlur = false;
+
+ if (GL::fragmentProgram)
+ {
+ int tmp[4];
+ GL::getProgramiv (GL_FRAGMENT_PROGRAM_ARB,
+ GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB,
+ tmp);
+ maxTemp = tmp[0];
+ }
+
+ updateFilterRadius ();
+
+ ScreenInterface::setHandler (screen, true);
+ CompositeScreenInterface::setHandler (cScreen, true);
+ GLScreenInterface::setHandler (gScreen, true);
+}
+
+
+BlurScreen::~BlurScreen ()
+{
+ foreach (BlurFunction &bf, srcBlurFunctions)
+ GLFragment::destroyFragmentFunction (bf.id);
+ foreach (BlurFunction &bf, dstBlurFunctions)
+ GLFragment::destroyFragmentFunction (bf.id);
+
+ cScreen->damageScreen ();
+
+ if (fbo)
+ (*GL::deleteFramebuffers) (1, &fbo);
+
+ for (int i = 0; i < 2; i++)
+ if (texture[i])
+ glDeleteTextures (1, &texture[i]);
+
+}
+
+BlurWindow::BlurWindow (CompWindow *w) :
+ PrivateHandler<BlurWindow,CompWindow> (w),
+ window (w),
+ gWindow (GLWindow::get (w)),
+ cWindow (CompositeWindow::get (w)),
+ bScreen (BlurScreen::get (screen)),
+ blur (0),
+ pulse (false),
+ focusBlur (false)
+{
+ for (int i = 0; i < BLUR_STATE_NUM; i++)
+ {
+ state[i].threshold = 0;
+ state[i].clipped = false;
+ state[i].active = false;
+
+ propSet[i] = false;
+ }
+
+ update (BLUR_STATE_CLIENT);
+ update (BLUR_STATE_DECOR);
+
+ updateMatch ();
+
+
+ WindowInterface::setHandler (window, true);
+ GLWindowInterface::setHandler (gWindow, true);
+}
+
+BlurWindow::~BlurWindow ()
+{
+}
+
+bool
+BlurPluginVTable::init ()
+{
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) |
+ !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) |
+ !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
+ return false;
+
+ getMetadata ()->addFromOptionInfo (blurOptionInfo, BLUR_OPTION_NUM);
+ getMetadata ()->addFromFile (name ());
+
+ return true;
+}
+