summaryrefslogtreecommitdiff
path: root/plugins/blur
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/blur')
-rw-r--r--plugins/blur/CMakeLists.txt16
-rw-r--r--plugins/blur/blur.xml.in112
-rw-r--r--plugins/blur/src/blur.cpp2335
-rw-r--r--plugins/blur/src/blur.h241
4 files changed, 2704 insertions, 0 deletions
diff --git a/plugins/blur/CMakeLists.txt b/plugins/blur/CMakeLists.txt
new file mode 100644
index 0000000..d625cdf
--- /dev/null
+++ b/plugins/blur/CMakeLists.txt
@@ -0,0 +1,16 @@
+find_package (Compiz REQUIRED)
+
+include (CompizPlugin)
+
+find_package (OpenGL)
+
+if (OPENGL_GLU_FOUND)
+ compiz_plugin(blur PLUGINDEPS composite opengl LIBRARIES decoration ${OPENGL_glu_LIBRARY} INCDIRS ${OPENGL_INCLUDE_DIR})
+
+ if (COMPIZ_BUILD_WITH_RPATH)
+ set_target_properties (
+ blur PROPERTIES
+ INSTALL_RPATH "${COMPIZ_LIBDIR}"
+ )
+ endif (COMPIZ_BUILD_WITH_RPATH)
+endif ()
diff --git a/plugins/blur/blur.xml.in b/plugins/blur/blur.xml.in
new file mode 100644
index 0000000..b8af0b0
--- /dev/null
+++ b/plugins/blur/blur.xml.in
@@ -0,0 +1,112 @@
+<compiz>
+ <plugin name="blur" useBcop="true">
+ <_short>Blur Windows</_short>
+ <_long>Blur windows</_long>
+ <category>Effects</category>
+ <feature>blur</feature>
+ <deps>
+ <relation type="before">
+ <plugin>video</plugin>
+ </relation>
+ <relation type="after">
+ <plugin>decor</plugin>
+ </relation>
+ <requirement>
+ <plugin>opengl</plugin>
+ </requirement>
+ </deps>
+ <options>
+ <option name="pulse" type="bell">
+ <_short>Pulse</_short>
+ <_long>Pulse effect</_long>
+ </option>
+ <option name="blur_speed" type="float">
+ <_short>Blur Speed</_short>
+ <_long>Window blur speed</_long>
+ <default>3.5</default>
+ <min>0.1</min>
+ <max>10.0</max>
+ <precision>0.1</precision>
+ </option>
+ <option name="focus_blur_match" type="match">
+ <_short>Focus blur windows</_short>
+ <_long>Windows that should be affected by focus blur</_long>
+ <default>toolbar | menu | utility | normal | dialog | modaldialog</default>
+ </option>
+ <option name="focus_blur" type="bool">
+ <_short>Focus Blur</_short>
+ <_long>Blur windows that doesn't have focus</_long>
+ <default>false</default>
+ </option>
+ <option name="alpha_blur_match" type="match">
+ <_short>Alpha blur windows</_short>
+ <_long>Windows that should be use alpha blur by default</_long>
+ <default></default>
+ </option>
+ <option name="alpha_blur" type="bool">
+ <_short>Alpha Blur</_short>
+ <_long>Blur behind translucent parts of windows</_long>
+ <default>true</default>
+ </option>
+ <option name="filter" type="int">
+ <_short>Blur Filter</_short>
+ <_long>Filter method used for blurring</_long>
+ <default>0</default>
+ <min>0</min>
+ <max>2</max>
+ <desc>
+ <value>0</value>
+ <_name>4xBilinear</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Gaussian</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Mipmap</_name>
+ </desc>
+ </option>
+ <option name="gaussian_radius" type="int">
+ <_short>Gaussian Radius</_short>
+ <_long>Gaussian radius</_long>
+ <default>3</default>
+ <min>1</min>
+ <max>15</max>
+ </option>
+ <option name="gaussian_strength" type="float">
+ <_short>Gaussian Strength</_short>
+ <_long>Gaussian strength</_long>
+ <default>1.0</default>
+ <min>0.0</min>
+ <max>1.0</max>
+ <precision>0.1</precision>
+ </option>
+ <option name="mipmap_lod" type="float">
+ <_short>Mipmap LOD</_short>
+ <_long>Mipmap level-of-detail</_long>
+ <default>2.5</default>
+ <min>0.1</min>
+ <max>5.0</max>
+ <precision>0.1</precision>
+ </option>
+ <option name="saturation" type="int">
+ <_short>Blur Saturation</_short>
+ <_long>Blur saturation</_long>
+ <default>100</default>
+ <min>0</min>
+ <max>100</max>
+ </option>
+ <option name="occlusion" type="bool">
+ <_short>Blur Occlusion</_short>
+ <_long>Disable blurring of screen regions obscured by other windows.</_long>
+ <default>true</default>
+ </option>
+ <option name="independent_tex" type="bool">
+ <_short>Independent texture fetch</_short>
+ <_long>Use the available texture units to do as many as possible independent texture fetches.</_long>
+ <default>false</default>
+ </option>
+ </options>
+ </plugin>
+</compiz>
diff --git a/plugins/blur/src/blur.cpp b/plugins/blur/src/blur.cpp
new file mode 100644
index 0000000..555b7d0
--- /dev/null
+++ b/plugins/blur/src/blur.cpp
@@ -0,0 +1,2335 @@
+/*
+ * 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_20090315 (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 (optionGetFilter ()) {
+ case BlurOptions::Filter4xbilinear:
+ filterRadius = 2;
+ break;
+ case BlurOptions::FilterGaussian: {
+ int radius = optionGetGaussianRadius ();
+ float strength = optionGetGaussianStrength ();
+
+ blurCreateGaussianLinearKernel (radius, strength, amp, pos,
+ &numTexop);
+
+ filterRadius = radius;
+ } break;
+ case BlurOptions::FilterMipmap: {
+ float lod = optionGetMipmapLod ();
+
+ 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->optionGetAlphaBlurMatch ();
+ 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->optionGetFocusBlurMatch ();
+
+ 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)
+ {
+ unsigned 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 = optionGetFocusBlur ();
+ 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" };
+ unsigned 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 (optionGetFilter ()) {
+ case BlurOptions::Filter4xbilinear:
+ 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 = optionGetSaturation ();
+ int numIndirect;
+ int numIndirectOp;
+ int base, end, ITCbase;
+
+ for (i = 0; (unsigned int) i < sizeof (temp) / sizeof (temp[0]); i++)
+ data.addTempHeaderOp (temp[i]);
+
+ if (saturation < 100)
+ data.addTempHeaderOp ("sat");
+
+ switch (optionGetFilter ()) {
+ case BlurOptions::Filter4xbilinear: {
+ static const char *filterTemp[] = {
+ "t0", "t1", "t2", "t3",
+ "s0", "s1", "s2", "s3"
+ };
+
+ for (i = 0;
+ (unsigned int) 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 BlurOptions::FilterGaussian: {
+
+ /* 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 BlurOptions::FilterMipmap:
+ 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);
+
+ int currStatus = (*GL::checkFramebufferStatus) (GL_FRAMEBUFFER_EXT);
+ if (currStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ compLogMessage ("blur", CompLogLevelError,
+ "Framebuffer incomplete");
+
+ (*GL::bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
+ (*GL::deleteFramebuffers) (1, &fbo);
+
+ fbo = 0;
+
+ return false;
+ }
+ else
+ fboStatus = true;
+ }
+
+ 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 && optionGetIndependentTex ())
+ 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->optionGetFilter ();
+
+ bScreen->tmpRegion3 = CompRegion ();
+
+ if (filter == BlurOptions::FilterGaussian)
+ {
+
+ 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 == BlurOptions::FilterGaussian)
+ {
+ 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 == BlurOptions::FilterMipmap)
+ {
+ 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 BlurOptions::FilterGaussian:
+ return bScreen->fboUpdate (bScreen->tmpRegion.handle ()->rects,
+ bScreen->tmpRegion.numRects ());
+ case BlurOptions::FilterMipmap:
+ if (GL::generateMipmap)
+ (*GL::generateMipmap) (bScreen->target);
+ break;
+ case BlurOptions::Filter4xbilinear:
+ 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;
+
+ 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->optionGetFilter ()) {
+ case BlurOptions::Filter4xbilinear:
+ 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 BlurOptions::FilterGaussian:
+ if (bScreen->optionGetIndependentTex ())
+ {
+ /* 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 BlurOptions::FilterMipmap:
+ param = dstFa.allocParameters (2);
+ unit = dstFa.allocTextureUnits (1);
+
+ function =
+ bScreen->getDstBlurFragmentFunction (texture, param,
+ unit, 0, 0);
+ if (function)
+ {
+ float lod =
+ bScreen->optionGetMipmapLod ();
+
+ 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 (optionGetFocusBlur ())
+ {
+ CompositeWindow::get (w)->addDamage ();
+ moreBlur = true;
+ }
+ }
+
+ w = screen->findWindow (screen->activeWindow ());
+ if (w)
+ {
+ if (optionGetFocusBlur ())
+ {
+ 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);
+}
+
+bool
+BlurScreen::setOption (const CompString &name, CompOption::Value &value)
+{
+ unsigned int index;
+
+ bool rv = BlurOptions::setOption (name, value);
+
+ if (!rv || !CompOption::findOption (getOptions (), name, &index))
+ return false;
+
+ switch (index) {
+ case BlurOptions::BlurSpeed:
+ blurTime = 1000.0f / optionGetBlurSpeed ();
+ break;
+ case BlurOptions::FocusBlurMatch:
+ case BlurOptions::AlphaBlurMatch:
+ foreach (CompWindow *w, screen->windows ())
+ BlurWindow::get (w)->updateMatch ();
+
+ moreBlur = true;
+ cScreen->damageScreen ();
+ break;
+ case BlurOptions::FocusBlur:
+ moreBlur = true;
+ cScreen->damageScreen ();
+ break;
+ case BlurOptions::AlphaBlur:
+ if (GL::fragmentProgram && optionGetAlphaBlur ())
+ alphaBlur = true;
+ else
+ alphaBlur = false;
+
+ cScreen->damageScreen ();
+ break;
+ case BlurOptions::Filter:
+ blurReset ();
+ cScreen->damageScreen ();
+ break;
+ case BlurOptions::GaussianRadius:
+ case BlurOptions::GaussianStrength:
+ case BlurOptions::IndependentTex:
+ if (optionGetFilter () == BlurOptions::FilterGaussian)
+ {
+ blurReset ();
+ cScreen->damageScreen ();
+ }
+ break;
+ case BlurOptions::MipmapLod:
+ if (optionGetFilter () == BlurOptions::FilterMipmap)
+ {
+ blurReset ();
+ cScreen->damageScreen ();
+ }
+ break;
+ case BlurOptions::Saturation:
+ blurReset ();
+ cScreen->damageScreen ();
+ break;
+ case BlurOptions::Occlusion:
+ blurOcclusion = optionGetOcclusion ();
+ blurReset ();
+ cScreen->damageScreen ();
+ break;
+ default:
+ break;
+ }
+
+ return rv;
+}
+
+BlurScreen::BlurScreen (CompScreen *screen) :
+ PluginClassHandler<BlurScreen,CompScreen> (screen),
+ gScreen (GLScreen::get (screen)),
+ cScreen (CompositeScreen::get (screen)),
+ moreBlur (false),
+ filterRadius (0),
+ srcBlurFunctions (0),
+ dstBlurFunctions (0),
+ output (NULL),
+ count (0),
+ program (0),
+ maxTemp (32),
+ fbo (0),
+ fboStatus (0)
+{
+
+ 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 / optionGetBlurSpeed ();
+ blurOcclusion = optionGetOcclusion ();
+
+ 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 = optionGetAlphaBlur ();
+ 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 ();
+
+ optionSetPulseInitiate (blurPulse);
+
+ 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) :
+ PluginClassHandler<BlurWindow,CompWindow> (w),
+ window (w),
+ cWindow (CompositeWindow::get (w)),
+ gWindow (GLWindow::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;
+
+ return true;
+}
+
diff --git a/plugins/blur/src/blur.h b/plugins/blur/src/blur.h
new file mode 100644
index 0000000..a03c5dd
--- /dev/null
+++ b/plugins/blur/src/blur.h
@@ -0,0 +1,241 @@
+/*
+ * 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 <core/core.h>
+#include <composite/composite.h>
+#include <opengl/opengl.h>
+#include <decoration.h>
+
+#include <X11/Xatom.h>
+#include <GL/glu.h>
+
+#include "blur_options.h"
+
+#define BLUR_GAUSSIAN_RADIUS_MAX 15
+
+struct BlurFunction {
+
+ GLFragment::FunctionId id;
+
+ int target;
+ int param;
+ int unit;
+ int startTC;
+ int numITC;
+};
+
+struct BlurBox {
+ decor_point_t p1;
+ decor_point_t p2;
+};
+
+#define BLUR_STATE_CLIENT 0
+#define BLUR_STATE_DECOR 1
+#define BLUR_STATE_NUM 2
+
+struct BlurState {
+ int threshold;
+ std::vector<BlurBox> box;
+ bool active;
+ bool clipped;
+};
+
+class BlurScreen :
+ public ScreenInterface,
+ public CompositeScreenInterface,
+ public GLScreenInterface,
+ public PluginClassHandler<BlurScreen,CompScreen>,
+ public BlurOptions
+{
+ public:
+ BlurScreen (CompScreen *screen);
+ ~BlurScreen ();
+
+ bool setOption (const CompString &name, CompOption::Value &value);
+
+ void handleEvent (XEvent *);
+
+ virtual void matchExpHandlerChanged ();
+ virtual void matchPropertyChanged (CompWindow *window);
+
+ void preparePaint (int);
+ void donePaint ();
+
+ bool glPaintOutput (const GLScreenPaintAttrib &,
+ const GLMatrix &, const CompRegion &,
+ CompOutput *, unsigned int);
+ void glPaintTransformedOutput (const GLScreenPaintAttrib &,
+ const GLMatrix &,
+ const CompRegion &,
+ CompOutput *, unsigned int);
+
+ void updateFilterRadius ();
+ void blurReset ();
+
+ GLFragment::FunctionId getSrcBlurFragmentFunction (GLTexture *, int);
+ GLFragment::FunctionId getDstBlurFragmentFunction (GLTexture *texture,
+ int param,
+ int unit,
+ int numITC,
+ int startTC);
+
+ bool projectVertices (CompOutput *output,
+ const GLMatrix &transform,
+ const float *object,
+ float *scr,
+ int n);
+
+ bool loadFragmentProgram (GLuint *program,
+ const char *string);
+
+ bool loadFilterProgram (int numITC);
+
+ bool fboPrologue ();
+ void fboEpilogue ();
+ bool fboUpdate (BoxPtr pBox, int nBox);
+
+
+ public:
+ GLScreen *gScreen;
+ CompositeScreen *cScreen;
+
+ Atom blurAtom[BLUR_STATE_NUM];
+
+ bool alphaBlur;
+
+ int blurTime;
+ bool moreBlur;
+
+ bool blurOcclusion;
+
+ int filterRadius;
+
+ std::vector<BlurFunction> srcBlurFunctions;
+ std::vector<BlurFunction> dstBlurFunctions;
+
+ CompRegion region;
+ CompRegion tmpRegion;
+ CompRegion tmpRegion2;
+ CompRegion tmpRegion3;
+ CompRegion occlusion;
+
+ CompRect 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;
+
+ GLMatrix mvp;
+};
+
+class BlurWindow :
+ public WindowInterface,
+ public GLWindowInterface,
+ public PluginClassHandler<BlurWindow,CompWindow>
+{
+
+ public:
+
+ BlurWindow (CompWindow *window);
+ ~BlurWindow ();
+
+ void resizeNotify (int dx, int dy, int dwidth, int dheight);
+ void moveNotify (int dx, int dy, bool immediate);
+
+ bool glPaint (const GLWindowPaintAttrib &, const GLMatrix &,
+ const CompRegion &, unsigned int);
+ bool glDraw (const GLMatrix &, GLFragment::Attrib &,
+ const CompRegion &, unsigned int);
+ void glDrawTexture (GLTexture *texture, GLFragment::Attrib &,
+ unsigned int);
+
+ void updateRegion ();
+
+ void setBlur (int state,
+ int threshold,
+ std::vector<BlurBox> box);
+
+ void updateAlphaMatch ();
+ void updateMatch ();
+ void update (int state);
+
+ void projectRegion (CompOutput *output,
+ const GLMatrix &transform);
+
+ bool updateDstTexture (const GLMatrix &transform,
+ CompRect *pExtents,
+ int clientThreshold);
+
+ public:
+ CompWindow *window;
+ CompositeWindow *cWindow;
+ GLWindow *gWindow;
+ BlurScreen *bScreen;
+
+ int blur;
+ bool pulse;
+ bool focusBlur;
+
+ BlurState state[BLUR_STATE_NUM];
+ bool propSet[BLUR_STATE_NUM];
+
+ CompRegion region;
+ CompRegion clip;
+};
+
+#define BLUR_SCREEN(s) \
+ BlurScreen *bs = BlurScreen::get (s)
+
+#define BLUR_WINDOW(w) \
+ BlurWindow *bw = BlurWindow::get (w)
+
+class BlurPluginVTable :
+ public CompPlugin::VTableForScreenAndWindow<BlurScreen,BlurWindow>
+{
+ public:
+
+ bool init ();
+};