1
/********************************************************************
2
KWin - the KDE window manager
3
This file is part of the KDE project.
5
Copyright (C) 2010 by Fredrik Höglund <fredrik@kde.org>
6
Copyright (C) 2010 Martin Gräßlin <kde@martin-graesslin.com>
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 2 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program. If not, see <http://www.gnu.org/licenses/>.
20
*********************************************************************/
22
#include "lanczosfilter.h"
25
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
26
#include <kwinglutils.h>
27
#include <kwinglplatform.h>
30
#include <kwineffects.h>
31
#include <KDE/KGlobalSettings>
39
LanczosFilter::LanczosFilter(QObject* parent)
41
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
43
, m_offscreenTarget(0)
50
LanczosFilter::~LanczosFilter()
52
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
53
delete m_offscreenTarget;
54
delete m_offscreenTex;
58
void LanczosFilter::init()
63
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
65
KSharedConfigPtr config = KSharedConfig::openConfig("kwinrc");
67
if (config->group("Compositing").readEntry("GLTextureFilter", 2) != 2)
68
return; // disabled by config
70
// The lanczos filter is reported to be broken with the Intel driver and Mesa 7.10
71
GLPlatform *gl = GLPlatform::instance();
72
if (gl->driver() == Driver_Intel && gl->mesaVersion() >= kVersionNumber(7, 10))
75
m_shader = new LanczosShader(this);
76
if (!m_shader->init()) {
84
void LanczosFilter::updateOffscreenSurfaces()
86
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
87
int w = displayWidth();
88
int h = displayHeight();
89
if (!GLTexture::NPOTTextureSupported()) {
90
w = nearestPowerOfTwo(w);
91
h = nearestPowerOfTwo(h);
93
if (!m_offscreenTex || m_offscreenTex->width() != w || m_offscreenTex->height() != h) {
95
delete m_offscreenTex;
96
delete m_offscreenTarget;
98
m_offscreenTex = new GLTexture(w, h);
99
m_offscreenTex->setFilter(GL_LINEAR);
100
m_offscreenTex->setWrapMode(GL_CLAMP_TO_EDGE);
101
m_offscreenTarget = new GLRenderTarget(m_offscreenTex);
106
static float sinc(float x)
108
return std::sin(x * M_PI) / (x * M_PI);
111
static float lanczos(float x, float a)
113
if (qFuzzyCompare(x + 1.0, 1.0))
119
return sinc(x) * sinc(x / a);
122
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
123
void LanczosShader::createKernel(float delta, int *size)
127
// The two outermost samples always fall at points where the lanczos
128
// function returns 0, so we'll skip them.
129
const int sampleCount = qBound(3, qCeil(delta * a) * 2 + 1 - 2, 29);
130
const int center = sampleCount / 2;
131
const int kernelSize = center + 1;
132
const float factor = 1.0 / delta;
134
QVector<float> values(kernelSize);
137
for (int i = 0; i < kernelSize; i++) {
138
const float val = lanczos(i * factor, a);
139
sum += i > 0 ? val * 2 : val;
143
memset(m_kernel, 0, 16 * sizeof(QVector4D));
145
// Normalize the kernel
146
for (int i = 0; i < kernelSize; i++) {
147
const float val = values[i] / sum;
148
m_kernel[i] = QVector4D(val, val, val, val);
154
void LanczosShader::createOffsets(int count, float width, Qt::Orientation direction)
156
memset(m_offsets, 0, 16 * sizeof(QVector2D));
157
for (int i = 0; i < count; i++) {
158
m_offsets[i] = (direction == Qt::Horizontal) ?
159
QVector2D(i / width, 0) : QVector2D(0, i / width);
164
void LanczosFilter::performPaint(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data)
166
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
167
if (effects->compositingType() == KWin::OpenGLCompositing && (data.xScale < 0.9 || data.yScale < 0.9) &&
168
KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) {
171
const QRect screenRect = Workspace::self()->clientArea(ScreenArea, w->screen(), w->desktop());
172
// window geometry may not be bigger than screen geometry to fit into the FBO
173
if (m_shader && w->width() <= screenRect.width() && w->height() <= screenRect.height()) {
176
double right = w->width();
177
double bottom = w->height();
178
foreach (const WindowQuad & quad, data.quads) {
179
// we need this loop to include the decoration padding
180
left = qMin(left, quad.left());
181
top = qMin(top, quad.top());
182
right = qMax(right, quad.right());
183
bottom = qMax(bottom, quad.bottom());
185
double width = right - left;
186
double height = bottom - top;
187
if (width > screenRect.width() || height > screenRect.height()) {
188
// window with padding does not fit into the framebuffer
189
// so cut of the shadow
193
height = w->height();
195
int tx = data.xTranslate + w->x() + left * data.xScale;
196
int ty = data.yTranslate + w->y() + top * data.yScale;
197
int tw = width * data.xScale;
198
int th = height * data.yScale;
199
const QRect textureRect(tx, ty, tw, th);
204
GLTexture *cachedTexture = static_cast< GLTexture*>(w->data(LanczosCacheRole).value<void*>());
206
if (cachedTexture->width() == tw && cachedTexture->height() == th) {
207
cachedTexture->bind();
208
if (ShaderManager::instance()->isValid()) {
210
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
212
const float rgb = data.brightness * data.opacity;
213
const float a = data.opacity;
215
GLShader *shader = ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
216
shader->setUniform(GLShader::Offset, QVector2D(0, 0));
217
shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a));
218
shader->setUniform(GLShader::Saturation, data.saturation);
219
shader->setUniform(GLShader::AlphaToOne, 0);
221
cachedTexture->render(textureRect, textureRect);
223
ShaderManager::instance()->popShader();
226
prepareRenderStates(cachedTexture, data.opacity, data.brightness, data.saturation);
227
cachedTexture->render(textureRect, textureRect);
228
restoreRenderStates(cachedTexture, data.opacity, data.brightness, data.saturation);
230
cachedTexture->unbind();
231
m_timer.start(5000, this);
234
// offscreen texture not matching - delete
235
delete cachedTexture;
237
w->setData(LanczosCacheRole, QVariant());
241
WindowPaintData thumbData = data;
242
thumbData.xScale = 1.0;
243
thumbData.yScale = 1.0;
244
thumbData.xTranslate = -w->x() - left;
245
thumbData.yTranslate = -w->y() - top;
246
thumbData.brightness = 1.0;
247
thumbData.opacity = 1.0;
248
thumbData.saturation = 1.0;
250
// Bind the offscreen FBO and draw the window on it unscaled
251
updateOffscreenSurfaces();
252
GLRenderTarget::pushRenderTarget(m_offscreenTarget);
254
glClearColor(0.0, 0.0, 0.0, 0.0);
255
glClear(GL_COLOR_BUFFER_BIT);
256
w->sceneWindow()->performPaint(mask, infiniteRegion(), thumbData);
258
// Create a scratch texture and copy the rendered window into it
259
GLTexture tex(sw, sh);
260
tex.setFilter(GL_LINEAR);
261
tex.setWrapMode(GL_CLAMP_TO_EDGE);
264
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, m_offscreenTex->height() - sh, sw, sh);
266
// Set up the shader for horizontal scaling
267
float dx = sw / float(tw);
269
m_shader->createKernel(dx, &kernelSize);
270
m_shader->createOffsets(kernelSize, sw, Qt::Horizontal);
273
m_shader->setUniforms();
275
// Draw the window back into the FBO, this time scaled horizontally
276
glClear(GL_COLOR_BUFFER_BIT);
277
QVector<float> verts;
278
QVector<float> texCoords;
280
texCoords.reserve(12);
282
texCoords << 1.0 << 0.0; verts << tw << 0.0; // Top right
283
texCoords << 0.0 << 0.0; verts << 0.0 << 0.0; // Top left
284
texCoords << 0.0 << 1.0; verts << 0.0 << sh; // Bottom left
285
texCoords << 0.0 << 1.0; verts << 0.0 << sh; // Bottom left
286
texCoords << 1.0 << 1.0; verts << tw << sh; // Bottom right
287
texCoords << 1.0 << 0.0; verts << tw << 0.0; // Top right
288
GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
290
vbo->setData(6, 2, verts.constData(), texCoords.constData());
291
vbo->render(GL_TRIANGLES);
293
// At this point we don't need the scratch texture anymore
297
// create scratch texture for second rendering pass
298
GLTexture tex2(tw, sh);
299
tex2.setFilter(GL_LINEAR);
300
tex2.setWrapMode(GL_CLAMP_TO_EDGE);
303
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, m_offscreenTex->height() - sh, tw, sh);
305
// Set up the shader for vertical scaling
306
float dy = sh / float(th);
307
m_shader->createKernel(dy, &kernelSize);
308
m_shader->createOffsets(kernelSize, m_offscreenTex->height(), Qt::Vertical);
309
m_shader->setUniforms();
311
// Now draw the horizontally scaled window in the FBO at the right
312
// coordinates on the screen, while scaling it vertically and blending it.
313
glClear(GL_COLOR_BUFFER_BIT);
317
verts << tw << 0.0; // Top right
318
verts << 0.0 << 0.0; // Top left
319
verts << 0.0 << th; // Bottom left
320
verts << 0.0 << th; // Bottom left
321
verts << tw << th; // Bottom right
322
verts << tw << 0.0; // Top right
323
vbo->setData(6, 2, verts.constData(), texCoords.constData());
324
vbo->render(GL_TRIANGLES);
330
// create cache texture
331
GLTexture *cache = new GLTexture(tw, th);
333
cache->setFilter(GL_LINEAR);
334
cache->setWrapMode(GL_CLAMP_TO_EDGE);
336
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, m_offscreenTex->height() - th, tw, th);
337
GLRenderTarget::popRenderTarget();
339
if (ShaderManager::instance()->isValid()) {
341
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
343
const float rgb = data.brightness * data.opacity;
344
const float a = data.opacity;
346
GLShader *shader = ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
347
shader->setUniform(GLShader::Offset, QVector2D(0, 0));
348
shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a));
349
shader->setUniform(GLShader::Saturation, data.saturation);
350
shader->setUniform(GLShader::AlphaToOne, 0);
352
cache->render(textureRect, textureRect);
354
ShaderManager::instance()->popShader();
357
prepareRenderStates(cache, data.opacity, data.brightness, data.saturation);
358
cache->render(textureRect, textureRect);
359
restoreRenderStates(cache, data.opacity, data.brightness, data.saturation);
363
w->setData(LanczosCacheRole, QVariant::fromValue(static_cast<void*>(cache)));
365
// Delete the offscreen surface after 5 seconds
366
m_timer.start(5000, this);
369
} // if ( effects->compositingType() == KWin::OpenGLCompositing )
371
w->sceneWindow()->performPaint(mask, region, data);
374
void LanczosFilter::timerEvent(QTimerEvent *event)
376
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
377
if (event->timerId() == m_timer.timerId()) {
380
delete m_offscreenTarget;
381
delete m_offscreenTex;
382
m_offscreenTarget = 0;
384
foreach (EffectWindow * w, effects->stackingOrder()) {
385
QVariant cachedTextureVariant = w->data(LanczosCacheRole);
386
if (cachedTextureVariant.isValid()) {
387
GLTexture *cachedTexture = static_cast< GLTexture*>(cachedTextureVariant.value<void*>());
388
delete cachedTexture;
390
w->setData(LanczosCacheRole, QVariant());
397
void LanczosFilter::prepareRenderStates(GLTexture* tex, double opacity, double brightness, double saturation)
399
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
400
#ifndef KWIN_HAVE_OPENGLES
401
const bool alpha = true;
402
// setup blending of transparent windows
403
glPushAttrib(GL_ENABLE_BIT);
405
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
406
if (saturation != 1.0 && tex->saturationSupported()) {
407
// First we need to get the color from [0; 1] range to [0.5; 1] range
408
glActiveTexture(GL_TEXTURE0);
409
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
410
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
411
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
412
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
413
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
414
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
415
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT);
416
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
417
const float scale_constant[] = { 1.0, 1.0, 1.0, 0.5};
418
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, scale_constant);
421
// Then we take dot product of the result of previous pass and
422
// saturation_constant. This gives us completely unsaturated
424
// Note that both operands have to be in range [0.5; 1] since opengl
425
// automatically substracts 0.5 from them
426
glActiveTexture(GL_TEXTURE1);
427
float saturation_constant[] = { 0.5 + 0.5 * 0.30, 0.5 + 0.5 * 0.59, 0.5 + 0.5 * 0.11, saturation };
428
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
429
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
430
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
431
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
432
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
433
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
434
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, saturation_constant);
437
// Finally we need to interpolate between the original image and the
438
// greyscale image to get wanted level of saturation
439
glActiveTexture(GL_TEXTURE2);
440
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
441
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
442
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
443
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
444
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
445
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
446
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT);
447
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
448
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, saturation_constant);
449
// Also replace alpha by primary color's alpha here
450
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
451
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
452
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
453
// And make primary color contain the wanted opacity
454
glColor4f(opacity, opacity, opacity, opacity);
457
if (alpha || brightness != 1.0f) {
458
glActiveTexture(GL_TEXTURE3);
459
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
460
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
461
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
462
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
463
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
464
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
465
// The color has to be multiplied by both opacity and brightness
466
float opacityByBrightness = opacity * brightness;
467
glColor4f(opacityByBrightness, opacityByBrightness, opacityByBrightness, opacity);
469
// Multiply original texture's alpha by our opacity
470
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
471
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
472
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
473
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
474
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
476
// Alpha will be taken from previous stage
477
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
478
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
479
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
484
glActiveTexture(GL_TEXTURE0);
485
} else if (opacity != 1.0 || brightness != 1.0) {
486
// the window is additionally configured to have its opacity adjusted,
488
float opacityByBrightness = opacity * brightness;
490
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
491
glColor4f(opacityByBrightness, opacityByBrightness, opacityByBrightness,
494
// Multiply color by brightness and replace alpha by opacity
495
float constant[] = { opacityByBrightness, opacityByBrightness, opacityByBrightness, opacity };
496
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
497
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
498
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
499
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
500
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
501
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
502
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
503
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);
504
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
511
void LanczosFilter::restoreRenderStates(GLTexture* tex, double opacity, double brightness, double saturation)
513
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
514
#ifndef KWIN_HAVE_OPENGLES
515
if (opacity != 1.0 || saturation != 1.0 || brightness != 1.0f) {
516
if (saturation != 1.0 && tex->saturationSupported()) {
517
glActiveTexture(GL_TEXTURE3);
518
glDisable(tex->target());
519
glActiveTexture(GL_TEXTURE2);
520
glDisable(tex->target());
521
glActiveTexture(GL_TEXTURE1);
522
glDisable(tex->target());
523
glActiveTexture(GL_TEXTURE0);
526
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
527
glColor4f(0, 0, 0, 0);
529
glPopAttrib(); // ENABLE_BIT
534
/************************************************
536
************************************************/
537
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
538
LanczosShader::LanczosShader(QObject* parent)
545
LanczosShader::~LanczosShader()
548
#ifndef KWIN_HAVE_OPENGLES
550
glDeleteProgramsARB(1, &m_arbProgram);
556
void LanczosShader::bind()
559
ShaderManager::instance()->pushShader(m_shader);
560
#ifndef KWIN_HAVE_OPENGLES
562
glEnable(GL_FRAGMENT_PROGRAM_ARB);
563
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_arbProgram);
568
void LanczosShader::unbind()
571
ShaderManager::instance()->popShader();
572
#ifndef KWIN_HAVE_OPENGLES
575
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &boundObject);
576
if (boundObject == m_arbProgram) {
577
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
578
glDisable(GL_FRAGMENT_PROGRAM_ARB);
584
void LanczosShader::setUniforms()
587
glUniform1i(m_uTexUnit, 0);
588
glUniform2fv(m_uOffsets, 16, (const GLfloat*)m_offsets);
589
glUniform4fv(m_uKernel, 16, (const GLfloat*)m_kernel);
591
#ifndef KWIN_HAVE_OPENGLES
593
for (int i = 0; i < 16; ++i) {
594
glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, i, m_offsets[i].x(), m_offsets[i].y(), 0, 0);
596
for (int i = 0; i < 16; ++i) {
597
glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, i + 16, m_kernel[i].x(), m_kernel[i].y(), m_kernel[i].z(), m_kernel[i].w());
603
bool LanczosShader::init()
605
GLPlatform *gl = GLPlatform::instance();
606
if (gl->supports(GLSL) &&
607
ShaderManager::instance()->isValid() &&
608
GLRenderTarget::supported() &&
609
!(gl->isRadeon() && gl->chipClass() < R600)) {
610
m_shader = ShaderManager::instance()->loadFragmentShader(ShaderManager::SimpleShader, ":/resources/lanczos-fragment.glsl");
611
if (m_shader->isValid()) {
612
ShaderManager::instance()->pushShader(m_shader);
613
m_uTexUnit = m_shader->uniformLocation("texUnit");
614
m_uKernel = m_shader->uniformLocation("kernel");
615
m_uOffsets = m_shader->uniformLocation("offsets");
616
ShaderManager::instance()->popShader();
619
kDebug(1212) << "Shader is not valid";
625
#ifdef KWIN_HAVE_OPENGLES
626
// no ARB shader in GLES
629
// try to create an ARB Shader
630
if (!hasGLExtension("GL_ARB_fragment_program"))
634
QTextStream stream(&text);
636
// Note: This program uses 31 temporaries, 61 ALU instructions, 31 texture
637
// fetches, 3 texture indirections and 93 instructions.
638
// The R300 limitations are 32, 64, 32, 4 and 96 respectively.
639
stream << "!!ARBfp1.0\n";
640
stream << "TEMP sum;\n";
642
// Declare 30 temporaries for holding texcoords and TEX results
643
for (int i = 0; i < 30; i++)
644
stream << "TEMP temp" << i << ";\n";
646
// Compute the texture coordinates
647
for (int i = 0, j = 0; i < 30 / 2; i++) {
648
stream << "ADD temp" << j++ << ", fragment.texcoord, program.local[" << i + 1 << "];\n";
649
stream << "SUB temp" << j++ << ", fragment.texcoord, program.local[" << i + 1 << "];\n";
652
// Sample the texture coordinates
653
stream << "TEX sum, fragment.texcoord, texture[0], 2D;\n";
654
for (int i = 0; i < 30; i++)
655
stream << "TEX temp" << i << ", temp" << i << ", texture[0], 2D;\n";
657
// Process the results
658
stream << "MUL sum, sum, program.local[16];\n"; // sum = sum * kernel[0]
659
for (int i = 0, j = 0; i < 30 / 2; i++) {
660
stream << "MAD sum, temp" << j++ << ", program.local[" << (17 + i) << "], sum;\n";
661
stream << "MAD sum, temp" << j++ << ", program.local[" << (17 + i) << "], sum;\n";
664
stream << "MOV result.color, sum;\n";
668
glEnable(GL_FRAGMENT_PROGRAM_ARB);
669
glGenProgramsARB(1, &m_arbProgram);
670
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_arbProgram);
671
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, text.length(), text.constData());
674
const char *error = (const char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
675
kError() << "Failed to compile fragment program:" << error;
676
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
677
glDeleteProgramsARB(1, &m_arbProgram);
678
glDisable(GL_FRAGMENT_PROGRAM_ARB);
683
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
684
glDisable(GL_FRAGMENT_PROGRAM_ARB);
685
kDebug(1212) << "ARB Shader compiled, id: " << m_arbProgram;