~ubuntu-branches/ubuntu/precise/kde-workspace/precise-updates

« back to all changes in this revision

Viewing changes to .pc/enable_kwinactive.diff/kwin/libkwineffects/kwinglutils.cpp

  • Committer: Package Import Robot
  • Author(s): Philip Muškovac, Rodrigo Belem, Philip Muškovac
  • Date: 2012-04-10 19:37:37 UTC
  • Revision ID: package-import@ubuntu.com-20120410193737-rhsuhcb6mfsdom0f
Tags: 4:4.8.2a-0ubuntu2
[ Rodrigo Belem ]
* Move kwin4_effect_builtins.so to kde-window-manager
* Move libkwinnvidiahack4 to its own package
* Add breaks/replaces for kde-window-manager-common on
  libkwinnvidiahack4 and kde-window-manager << 4:4.8.2a-0ubuntu2~
* Enable kwinactive (LP: #956186)
* Build the source twice to create kwinactive binaries
* Add the packages
  - kde-window-manager-active
  - kde-window-manager-active-gles
  - libkwinactiveglutils1
  - libkwinactiveglesutils1
  - libkwinactiveeffects1abi3
  - libkwinactivenvidiahack4
* Fix kwinactive build failure with the patch
  kubuntu_active_fix_kwin_xrender_disable.diff

[ Philip Muškovac ]
* kde-window-manager/-gles depends on libkwinnvidiahack4
  kde-window-manager-active/-gles depends on libkwinactivenvidiahack4
* use ${allLibaries} to generate the library dependencies for
  kde-workspace-dev again

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/********************************************************************
 
2
 KWin - the KDE window manager
 
3
 This file is part of the KDE project.
 
4
 
 
5
Copyright (C) 2006-2007 Rivo Laks <rivolaks@hot.ee>
 
6
Copyright (C) 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
 
7
 
 
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.
 
12
 
 
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.
 
17
 
 
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
*********************************************************************/
 
21
 
 
22
#include "kwinglutils.h"
 
23
 
 
24
// need to call GLTexturePrivate::initStatic()
 
25
#include "kwingltexture_p.h"
 
26
 
 
27
#include "kwinglobals.h"
 
28
#include "kwineffects.h"
 
29
#include "kwinglplatform.h"
 
30
 
 
31
#include "kdebug.h"
 
32
#include <kstandarddirs.h>
 
33
#include <KDE/KConfig>
 
34
#include <KDE/KConfigGroup>
 
35
 
 
36
#include <QPixmap>
 
37
#include <QImage>
 
38
#include <QHash>
 
39
#include <QFile>
 
40
#include <QVector2D>
 
41
#include <QVector3D>
 
42
#include <QVector4D>
 
43
#include <QMatrix4x4>
 
44
 
 
45
#include <math.h>
 
46
 
 
47
#define DEBUG_GLRENDERTARGET 0
 
48
 
 
49
#define MAKE_GL_VERSION(major, minor, release)  ( ((major) << 16) | ((minor) << 8) | (release) )
 
50
 
 
51
namespace KWin
 
52
{
 
53
// Variables
 
54
// GL version, use MAKE_GL_VERSION() macro for comparing with a specific version
 
55
static int glVersion;
 
56
// GLX version, use MAKE_GL_VERSION() macro for comparing with a specific version
 
57
static int glXVersion;
 
58
// EGL version, use MAKE_GL_VERSION() macro for comparing with a specific version
 
59
static int eglVersion;
 
60
// List of all supported GL, EGL and GLX extensions
 
61
static QStringList glExtensions;
 
62
static QStringList glxExtensions;
 
63
static QStringList eglExtension;
 
64
static bool legacyGl;
 
65
 
 
66
int glTextureUnitsCount;
 
67
 
 
68
 
 
69
// Functions
 
70
void initGLX()
 
71
{
 
72
#ifndef KWIN_HAVE_OPENGLES
 
73
    // Get GLX version
 
74
    int major, minor;
 
75
    glXQueryVersion(display(), &major, &minor);
 
76
    glXVersion = MAKE_GL_VERSION(major, minor, 0);
 
77
    // Get list of supported GLX extensions
 
78
    glxExtensions = QString((const char*)glXQueryExtensionsString(
 
79
                                display(), DefaultScreen(display()))).split(' ');
 
80
 
 
81
    glxResolveFunctions();
 
82
#endif
 
83
}
 
84
 
 
85
void initEGL()
 
86
{
 
87
#ifdef KWIN_HAVE_OPENGLES
 
88
    EGLDisplay dpy = eglGetCurrentDisplay();
 
89
    int major, minor;
 
90
    eglInitialize(dpy, &major, &minor);
 
91
    eglVersion = MAKE_GL_VERSION(major, minor, 0);
 
92
    eglExtension = QString((const char*)eglQueryString(dpy, EGL_EXTENSIONS)).split(' ');
 
93
 
 
94
    eglResolveFunctions();
 
95
#endif
 
96
}
 
97
 
 
98
void initGL()
 
99
{
 
100
    // Get OpenGL version
 
101
    QString glversionstring = QString((const char*)glGetString(GL_VERSION));
 
102
    QStringList glversioninfo = glversionstring.left(glversionstring.indexOf(' ')).split('.');
 
103
    while (glversioninfo.count() < 3)
 
104
        glversioninfo << "0";
 
105
#ifdef KWIN_HAVE_OPENGLES
 
106
    legacyGl = false;
 
107
#else
 
108
    KSharedConfig::Ptr kwinconfig = KSharedConfig::openConfig("kwinrc", KConfig::NoGlobals);
 
109
    KConfigGroup config(kwinconfig, "Compositing");
 
110
    legacyGl = config.readEntry<bool>("GLLegacy", false);
 
111
    glVersion = MAKE_GL_VERSION(glversioninfo[0].toInt(), glversioninfo[1].toInt(), glversioninfo[2].toInt());
 
112
#endif
 
113
    // Get list of supported OpenGL extensions
 
114
    glExtensions = QString((const char*)glGetString(GL_EXTENSIONS)).split(' ');
 
115
 
 
116
    // handle OpenGL extensions functions
 
117
    glResolveFunctions();
 
118
 
 
119
    GLTexturePrivate::initStatic();
 
120
    GLRenderTarget::initStatic();
 
121
    GLVertexBuffer::initStatic();
 
122
}
 
123
 
 
124
void cleanupGL()
 
125
{
 
126
    ShaderManager::cleanup();
 
127
}
 
128
 
 
129
bool hasGLVersion(int major, int minor, int release)
 
130
{
 
131
    return glVersion >= MAKE_GL_VERSION(major, minor, release);
 
132
}
 
133
 
 
134
bool hasGLXVersion(int major, int minor, int release)
 
135
{
 
136
    return glXVersion >= MAKE_GL_VERSION(major, minor, release);
 
137
}
 
138
 
 
139
bool hasEGLVersion(int major, int minor, int release)
 
140
{
 
141
    return eglVersion >= MAKE_GL_VERSION(major, minor, release);
 
142
}
 
143
 
 
144
bool hasGLExtension(const QString& extension)
 
145
{
 
146
    return glExtensions.contains(extension) || glxExtensions.contains(extension) || eglExtension.contains(extension);
 
147
}
 
148
 
 
149
static QString formatGLError(GLenum err)
 
150
{
 
151
    switch(err) {
 
152
    case GL_NO_ERROR:          return "GL_NO_ERROR";
 
153
    case GL_INVALID_ENUM:      return "GL_INVALID_ENUM";
 
154
    case GL_INVALID_VALUE:     return "GL_INVALID_VALUE";
 
155
    case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
 
156
#ifndef KWIN_HAVE_OPENGLES
 
157
    case GL_STACK_OVERFLOW:    return "GL_STACK_OVERFLOW";
 
158
    case GL_STACK_UNDERFLOW:   return "GL_STACK_UNDERFLOW";
 
159
#endif
 
160
    case GL_OUT_OF_MEMORY:     return "GL_OUT_OF_MEMORY";
 
161
    default: return QString("0x") + QString::number(err, 16);
 
162
    }
 
163
}
 
164
 
 
165
bool checkGLError(const char* txt)
 
166
{
 
167
    GLenum err = glGetError();
 
168
    if (err != GL_NO_ERROR) {
 
169
        kWarning(1212) << "GL error (" << txt << "): " << formatGLError(err);
 
170
        return true;
 
171
    }
 
172
    return false;
 
173
}
 
174
 
 
175
int nearestPowerOfTwo(int x)
 
176
{
 
177
    // This method had been copied from Qt's nearest_gl_texture_size()
 
178
    int n = 0, last = 0;
 
179
    for (int s = 0; s < 32; ++s) {
 
180
        if (((x >> s) & 1) == 1) {
 
181
            ++n;
 
182
            last = s;
 
183
        }
 
184
    }
 
185
    if (n > 1)
 
186
        return 1 << (last + 1);
 
187
    return 1 << last;
 
188
}
 
189
 
 
190
void pushMatrix()
 
191
{
 
192
#ifndef KWIN_HAVE_OPENGLES
 
193
    glPushMatrix();
 
194
#endif
 
195
}
 
196
 
 
197
void pushMatrix(const QMatrix4x4 &matrix)
 
198
{
 
199
#ifdef KWIN_HAVE_OPENGLES
 
200
    Q_UNUSED(matrix)
 
201
#else
 
202
    glPushMatrix();
 
203
    multiplyMatrix(matrix);
 
204
#endif
 
205
}
 
206
 
 
207
void multiplyMatrix(const QMatrix4x4 &matrix)
 
208
{
 
209
#ifdef KWIN_HAVE_OPENGLES
 
210
    Q_UNUSED(matrix)
 
211
#else
 
212
    GLfloat m[16];
 
213
    const qreal *data = matrix.constData();
 
214
    for (int i = 0; i < 4; ++i) {
 
215
        for (int j = 0; j < 4; ++j) {
 
216
            m[i*4+j] = data[i*4+j];
 
217
        }
 
218
    }
 
219
    glMultMatrixf(m);
 
220
#endif
 
221
}
 
222
 
 
223
void loadMatrix(const QMatrix4x4 &matrix)
 
224
{
 
225
#ifdef KWIN_HAVE_OPENGLES
 
226
    Q_UNUSED(matrix)
 
227
#else
 
228
    GLfloat m[16];
 
229
    const qreal *data = matrix.constData();
 
230
    for (int i = 0; i < 4; ++i) {
 
231
        for (int j = 0; j < 4; ++j) {
 
232
            m[i*4+j] = data[i*4+j];
 
233
        }
 
234
    }
 
235
    glLoadMatrixf(m);
 
236
#endif
 
237
}
 
238
 
 
239
void popMatrix()
 
240
{
 
241
#ifndef KWIN_HAVE_OPENGLES
 
242
    glPopMatrix();
 
243
#endif
 
244
}
 
245
 
 
246
//****************************************
 
247
// GLShader
 
248
//****************************************
 
249
 
 
250
GLShader::GLShader()
 
251
    : mProgram(0)
 
252
    , mValid(false)
 
253
    , mLocationsResolved(false)
 
254
{
 
255
}
 
256
 
 
257
GLShader::GLShader(const QString& vertexfile, const QString& fragmentfile)
 
258
    : mProgram(0)
 
259
    , mValid(false)
 
260
    , mLocationsResolved(false)
 
261
{
 
262
    loadFromFiles(vertexfile, fragmentfile);
 
263
}
 
264
 
 
265
GLShader::~GLShader()
 
266
{
 
267
    if (mProgram) {
 
268
        glDeleteProgram(mProgram);
 
269
    }
 
270
}
 
271
 
 
272
bool GLShader::loadFromFiles(const QString &vertexFile, const QString &fragmentFile)
 
273
{
 
274
    QFile vf(vertexFile);
 
275
    if (!vf.open(QIODevice::ReadOnly)) {
 
276
        kError(1212) << "Couldn't open" << vertexFile << "for reading!" << endl;
 
277
        return false;
 
278
    }
 
279
    const QByteArray vertexSource = vf.readAll();
 
280
 
 
281
    QFile ff(fragmentFile);
 
282
    if (!ff.open(QIODevice::ReadOnly)) {
 
283
        kError(1212) << "Couldn't open" << fragmentFile << "for reading!" << endl;
 
284
        return false;
 
285
    }
 
286
    const QByteArray fragmentSource = ff.readAll();
 
287
 
 
288
    return load(vertexSource, fragmentSource);
 
289
}
 
290
 
 
291
bool GLShader::compile(GLuint program, GLenum shaderType, const QByteArray &source) const
 
292
{
 
293
    GLuint shader = glCreateShader(shaderType);
 
294
 
 
295
    // Prepare the source code
 
296
    QByteArray ba;
 
297
#ifdef KWIN_HAVE_OPENGLES
 
298
    ba.append("#ifdef GL_ES\nprecision highp float;\n#endif\n");
 
299
#endif
 
300
    if (ShaderManager::instance()->isShaderDebug()) {
 
301
        ba.append("#define KWIN_SHADER_DEBUG 1\n");
 
302
    }
 
303
    ba.append(source);
 
304
 
 
305
    const char* src = ba.constData();
 
306
    glShaderSource(shader, 1, &src, NULL);
 
307
 
 
308
    // Compile the shader
 
309
    glCompileShader(shader);
 
310
 
 
311
    // Get the shader info log
 
312
    int maxLength, length;
 
313
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
 
314
 
 
315
    QByteArray log(maxLength, 0);
 
316
    glGetShaderInfoLog(shader, maxLength, &length, log.data());
 
317
 
 
318
    // Check the status
 
319
    int status;
 
320
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
 
321
 
 
322
    if (status == 0) {
 
323
        const char *typeName = (shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment");
 
324
        kError(1212) << "Failed to compile" << typeName << "shader:" << endl << log << endl;
 
325
    } else if (length > 0)
 
326
        kDebug(1212) << "Shader compile log:" << log;
 
327
 
 
328
    if (status != 0)
 
329
        glAttachShader(program, shader);
 
330
 
 
331
    glDeleteShader(shader);
 
332
    return status != 0;
 
333
}
 
334
 
 
335
bool GLShader::load(const QByteArray &vertexSource, const QByteArray &fragmentSource)
 
336
{
 
337
#ifndef KWIN_HAVE_OPENGLES
 
338
    // Make sure shaders are actually supported
 
339
    if (!GLPlatform::instance()->supports(GLSL) || GLPlatform::instance()->supports(LimitedNPOT)) {
 
340
        kError(1212) << "Shaders are not supported";
 
341
        return false;
 
342
    }
 
343
#endif
 
344
 
 
345
    // Create the shader program
 
346
    mProgram = glCreateProgram();
 
347
 
 
348
    // Compile the vertex shader
 
349
    if (!vertexSource.isEmpty()) {
 
350
        bool success = compile(mProgram, GL_VERTEX_SHADER, vertexSource);
 
351
 
 
352
        if (!success) {
 
353
            glDeleteProgram(mProgram);
 
354
            mProgram = 0;
 
355
            return false;
 
356
        }
 
357
    }
 
358
 
 
359
    // Compile the fragment shader
 
360
    if (!fragmentSource.isEmpty()) {
 
361
        bool success = compile(mProgram, GL_FRAGMENT_SHADER, fragmentSource);
 
362
 
 
363
        if (!success) {
 
364
            glDeleteProgram(mProgram);
 
365
            mProgram = 0;
 
366
            return false;
 
367
        }
 
368
    }
 
369
 
 
370
    glLinkProgram(mProgram);
 
371
 
 
372
    // Get the program info log
 
373
    int maxLength, length;
 
374
    glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &maxLength);
 
375
 
 
376
    QByteArray log(maxLength, 0);
 
377
    glGetProgramInfoLog(mProgram, maxLength, &length, log.data());
 
378
 
 
379
    // Make sure the program linked successfully
 
380
    int status;
 
381
    glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
 
382
 
 
383
    if (status == 0) {
 
384
        kError(1212) << "Failed to link shader:" << endl << log << endl;
 
385
        glDeleteProgram(mProgram);
 
386
        mProgram = 0;
 
387
        return false;
 
388
    } else if (length > 0)
 
389
        kDebug(1212) << "Shader link log:" << log;
 
390
 
 
391
    mValid = true;
 
392
    return true;
 
393
}
 
394
 
 
395
void GLShader::bind()
 
396
{
 
397
    glUseProgram(mProgram);
 
398
}
 
399
 
 
400
void GLShader::unbind()
 
401
{
 
402
    glUseProgram(0);
 
403
}
 
404
 
 
405
void GLShader::resolveLocations()
 
406
{
 
407
    if (mLocationsResolved)
 
408
        return;
 
409
 
 
410
    mMatrixLocation[TextureMatrix]        = uniformLocation("textureMatrix");
 
411
    mMatrixLocation[ProjectionMatrix]     = uniformLocation("projection");
 
412
    mMatrixLocation[ModelViewMatrix]      = uniformLocation("modelview");
 
413
    mMatrixLocation[WindowTransformation] = uniformLocation("windowTransformation");
 
414
    mMatrixLocation[ScreenTransformation] = uniformLocation("screenTransformation");
 
415
 
 
416
    mVec2Location[Offset] = uniformLocation("offset");
 
417
 
 
418
    mVec4Location[ModulationConstant] = uniformLocation("modulation");
 
419
 
 
420
    mFloatLocation[Saturation]    = uniformLocation("saturation");
 
421
 
 
422
    mIntLocation[AlphaToOne] = uniformLocation("u_forceAlpha");
 
423
 
 
424
    mLocationsResolved = true;
 
425
}
 
426
 
 
427
int GLShader::uniformLocation(const char *name)
 
428
{
 
429
    const int location = glGetUniformLocation(mProgram, name);
 
430
    return location;
 
431
}
 
432
 
 
433
bool GLShader::setUniform(GLShader::MatrixUniform uniform, const QMatrix4x4 &matrix)
 
434
{
 
435
    resolveLocations();
 
436
    return setUniform(mMatrixLocation[uniform], matrix);
 
437
}
 
438
 
 
439
bool GLShader::setUniform(GLShader::Vec2Uniform uniform, const QVector2D &value)
 
440
{
 
441
    resolveLocations();
 
442
    return setUniform(mVec2Location[uniform], value);
 
443
}
 
444
 
 
445
bool GLShader::setUniform(GLShader::Vec4Uniform uniform, const QVector4D &value)
 
446
{
 
447
    resolveLocations();
 
448
    return setUniform(mVec4Location[uniform], value);
 
449
}
 
450
 
 
451
bool GLShader::setUniform(GLShader::FloatUniform uniform, float value)
 
452
{
 
453
    resolveLocations();
 
454
    return setUniform(mFloatLocation[uniform], value);
 
455
}
 
456
 
 
457
bool GLShader::setUniform(GLShader::IntUniform uniform, int value)
 
458
{
 
459
    resolveLocations();
 
460
    return setUniform(mIntLocation[uniform], value);
 
461
}
 
462
 
 
463
bool GLShader::setUniform(const char *name, float value)
 
464
{
 
465
    const int location = uniformLocation(name);
 
466
    return setUniform(location, value);
 
467
}
 
468
 
 
469
bool GLShader::setUniform(const char *name, int value)
 
470
{
 
471
    const int location = uniformLocation(name);
 
472
    return setUniform(location, value);
 
473
}
 
474
 
 
475
bool GLShader::setUniform(const char *name, const QVector2D& value)
 
476
{
 
477
    const int location = uniformLocation(name);
 
478
    return setUniform(location, value);
 
479
}
 
480
 
 
481
bool GLShader::setUniform(const char *name, const QVector3D& value)
 
482
{
 
483
    const int location = uniformLocation(name);
 
484
    return setUniform(location, value);
 
485
}
 
486
 
 
487
bool GLShader::setUniform(const char *name, const QVector4D& value)
 
488
{
 
489
    const int location = uniformLocation(name);
 
490
    return setUniform(location, value);
 
491
}
 
492
 
 
493
bool GLShader::setUniform(const char *name, const QMatrix4x4& value)
 
494
{
 
495
    const int location = uniformLocation(name);
 
496
    return setUniform(location, value);
 
497
}
 
498
 
 
499
bool GLShader::setUniform(const char *name, const QColor& color)
 
500
{
 
501
    const int location = uniformLocation(name);
 
502
    return setUniform(location, color);
 
503
}
 
504
 
 
505
bool GLShader::setUniform(int location, float value)
 
506
{
 
507
    if (location >= 0) {
 
508
        glUniform1f(location, value);
 
509
    }
 
510
    return (location >= 0);
 
511
}
 
512
 
 
513
bool GLShader::setUniform(int location, int value)
 
514
{
 
515
    if (location >= 0) {
 
516
        glUniform1i(location, value);
 
517
    }
 
518
    return (location >= 0);
 
519
}
 
520
 
 
521
bool GLShader::setUniform(int location, const QVector2D &value)
 
522
{
 
523
    if (location >= 0) {
 
524
        glUniform2fv(location, 1, (const GLfloat*)&value);
 
525
    }
 
526
    return (location >= 0);
 
527
}
 
528
 
 
529
bool GLShader::setUniform(int location, const QVector3D &value)
 
530
{
 
531
    if (location >= 0) {
 
532
        glUniform3fv(location, 1, (const GLfloat*)&value);
 
533
    }
 
534
    return (location >= 0);
 
535
}
 
536
 
 
537
bool GLShader::setUniform(int location, const QVector4D &value)
 
538
{
 
539
    if (location >= 0) {
 
540
        glUniform4fv(location, 1, (const GLfloat*)&value);
 
541
    }
 
542
    return (location >= 0);
 
543
}
 
544
 
 
545
bool GLShader::setUniform(int location, const QMatrix4x4 &value)
 
546
{
 
547
    if (location >= 0) {
 
548
        GLfloat m[16];
 
549
        const qreal *data = value.constData();
 
550
        // i is column, j is row for m
 
551
        for (int i = 0; i < 16; ++i) {
 
552
            m[i] = data[i];
 
553
        }
 
554
        glUniformMatrix4fv(location, 1, GL_FALSE, m);
 
555
    }
 
556
    return (location >= 0);
 
557
}
 
558
 
 
559
bool GLShader::setUniform(int location, const QColor &color)
 
560
{
 
561
    if (location >= 0) {
 
562
        glUniform4f(location, color.redF(), color.greenF(), color.blueF(), color.alphaF());
 
563
    }
 
564
    return (location >= 0);
 
565
}
 
566
 
 
567
int GLShader::attributeLocation(const char* name)
 
568
{
 
569
    int location = glGetAttribLocation(mProgram, name);
 
570
    return location;
 
571
}
 
572
 
 
573
bool GLShader::setAttribute(const char* name, float value)
 
574
{
 
575
    int location = attributeLocation(name);
 
576
    if (location >= 0) {
 
577
        glVertexAttrib1f(location, value);
 
578
    }
 
579
    return (location >= 0);
 
580
}
 
581
 
 
582
QMatrix4x4 GLShader::getUniformMatrix4x4(const char* name)
 
583
{
 
584
    int location = uniformLocation(name);
 
585
    if (location >= 0) {
 
586
        GLfloat m[16];
 
587
        glGetUniformfv(mProgram, location, m);
 
588
        QMatrix4x4 matrix(m[0], m[4], m[8],  m[12],
 
589
                          m[1], m[5], m[9],  m[13],
 
590
                          m[2], m[6], m[10], m[14],
 
591
                          m[3], m[7], m[11], m[15]);
 
592
        matrix.optimize();
 
593
        return matrix;
 
594
    } else {
 
595
        return QMatrix4x4();
 
596
    }
 
597
}
 
598
 
 
599
//****************************************
 
600
// ShaderManager
 
601
//****************************************
 
602
ShaderManager *ShaderManager::s_shaderManager = NULL;
 
603
 
 
604
ShaderManager *ShaderManager::instance()
 
605
{
 
606
    if (!s_shaderManager) {
 
607
        s_shaderManager = new ShaderManager();
 
608
        s_shaderManager->initShaders();
 
609
        s_shaderManager->m_inited = true;
 
610
    }
 
611
    return s_shaderManager;
 
612
}
 
613
 
 
614
void ShaderManager::cleanup()
 
615
{
 
616
    delete s_shaderManager;
 
617
    s_shaderManager = NULL;
 
618
}
 
619
 
 
620
ShaderManager::ShaderManager()
 
621
    : m_orthoShader(NULL)
 
622
    , m_genericShader(NULL)
 
623
    , m_colorShader(NULL)
 
624
    , m_inited(false)
 
625
    , m_valid(false)
 
626
{
 
627
    m_debug = qstrcmp(qgetenv("KWIN_GL_DEBUG"), "1") == 0;
 
628
}
 
629
 
 
630
ShaderManager::~ShaderManager()
 
631
{
 
632
    while (!m_boundShaders.isEmpty()) {
 
633
        popShader();
 
634
    }
 
635
    delete m_orthoShader;
 
636
    delete m_genericShader;
 
637
    delete m_colorShader;
 
638
}
 
639
 
 
640
GLShader *ShaderManager::getBoundShader() const
 
641
{
 
642
    if (m_boundShaders.isEmpty()) {
 
643
        return NULL;
 
644
    } else {
 
645
        return m_boundShaders.top();
 
646
    }
 
647
}
 
648
 
 
649
bool ShaderManager::isShaderBound() const
 
650
{
 
651
    return !m_boundShaders.isEmpty();
 
652
}
 
653
 
 
654
bool ShaderManager::isValid() const
 
655
{
 
656
    return m_valid;
 
657
}
 
658
 
 
659
bool ShaderManager::isShaderDebug() const
 
660
{
 
661
    return m_debug;
 
662
}
 
663
 
 
664
GLShader *ShaderManager::pushShader(ShaderType type, bool reset)
 
665
{
 
666
    if (m_inited && !m_valid) {
 
667
        return NULL;
 
668
    }
 
669
    GLShader *shader;
 
670
    switch(type) {
 
671
    case SimpleShader:
 
672
        shader = m_orthoShader;
 
673
        break;
 
674
    case GenericShader:
 
675
        shader = m_genericShader;
 
676
        break;
 
677
    case ColorShader:
 
678
        shader = m_colorShader;
 
679
        break;
 
680
    default:
 
681
        return NULL;
 
682
    }
 
683
 
 
684
    pushShader(shader);
 
685
    if (reset) {
 
686
        resetShader(type);
 
687
    }
 
688
 
 
689
    return shader;
 
690
}
 
691
 
 
692
void ShaderManager::pushShader(GLShader *shader)
 
693
{
 
694
    // only bind shader if it is not already bound
 
695
    if (shader != getBoundShader()) {
 
696
        shader->bind();
 
697
    }
 
698
    m_boundShaders.push(shader);
 
699
}
 
700
 
 
701
void ShaderManager::popShader()
 
702
{
 
703
    if (m_boundShaders.isEmpty()) {
 
704
        return;
 
705
    }
 
706
    GLShader *shader = m_boundShaders.pop();
 
707
    if (m_boundShaders.isEmpty()) {
 
708
        // no more shader bound - unbind
 
709
        shader->unbind();
 
710
    } else if (shader != m_boundShaders.top()) {
 
711
        // only rebind if a different shader is on top of stack
 
712
        m_boundShaders.top()->bind();
 
713
    }
 
714
}
 
715
 
 
716
GLShader *ShaderManager::loadFragmentShader(ShaderType vertex, const QString &fragmentFile)
 
717
{
 
718
    QString vertexShader;
 
719
    switch(vertex) {
 
720
    case SimpleShader:
 
721
        vertexShader = ":/resources/scene-vertex.glsl";
 
722
        break;
 
723
    case GenericShader:
 
724
        vertexShader = ":/resources/scene-generic-vertex.glsl";
 
725
        break;
 
726
    case ColorShader:
 
727
        vertexShader = ":/resources/scene-color-vertex.glsl";
 
728
        break;
 
729
    }
 
730
    GLShader *shader = new GLShader(vertexShader, fragmentFile);
 
731
    if (shader->isValid()) {
 
732
        pushShader(shader);
 
733
        resetShader(vertex);
 
734
        popShader();
 
735
    }
 
736
    return shader;
 
737
}
 
738
 
 
739
GLShader *ShaderManager::loadVertexShader(ShaderType fragment, const QString &vertexFile)
 
740
{
 
741
    QString fragmentShader;
 
742
    switch(fragment) {
 
743
        // Simple and Generic Shader use same fragment Shader
 
744
    case SimpleShader:
 
745
    case GenericShader:
 
746
        fragmentShader = ":/resources/scene-fragment.glsl";
 
747
        break;
 
748
    case ColorShader:
 
749
        fragmentShader = ":/resources/scene-color-fragment.glsl";
 
750
        break;
 
751
    }
 
752
    GLShader *shader = new GLShader(vertexFile, fragmentShader);
 
753
    if (shader->isValid()) {
 
754
        pushShader(shader);
 
755
        resetShader(fragment);
 
756
        popShader();
 
757
    }
 
758
    return shader;
 
759
}
 
760
 
 
761
GLShader *ShaderManager::loadShaderFromCode(const QByteArray &vertexSource, const QByteArray &fragmentSource)
 
762
{
 
763
    GLShader *shader = new GLShader();
 
764
    shader->load(vertexSource, fragmentSource);
 
765
    return shader;
 
766
}
 
767
 
 
768
void ShaderManager::initShaders()
 
769
{
 
770
    if (legacyGl) {
 
771
        kDebug(1212) << "OpenGL Shaders disabled by config option";
 
772
        return;
 
773
    }
 
774
    m_orthoShader = new GLShader(":/resources/scene-vertex.glsl", ":/resources/scene-fragment.glsl");
 
775
    if (m_orthoShader->isValid()) {
 
776
        pushShader(SimpleShader, true);
 
777
        popShader();
 
778
        kDebug(1212) << "Ortho Shader is valid";
 
779
    } else {
 
780
        delete m_orthoShader;
 
781
        m_orthoShader = NULL;
 
782
        kDebug(1212) << "Orho Shader is not valid";
 
783
        return;
 
784
    }
 
785
    m_genericShader = new GLShader(":/resources/scene-generic-vertex.glsl", ":/resources/scene-fragment.glsl");
 
786
    if (m_genericShader->isValid()) {
 
787
        pushShader(GenericShader, true);
 
788
        popShader();
 
789
        kDebug(1212) << "Generic Shader is valid";
 
790
    } else {
 
791
        delete m_genericShader;
 
792
        m_genericShader = NULL;
 
793
        delete m_orthoShader;
 
794
        m_orthoShader = NULL;
 
795
        kDebug(1212) << "Generic Shader is not valid";
 
796
        return;
 
797
    }
 
798
    m_colorShader = new GLShader(":/resources/scene-color-vertex.glsl", ":/resources/scene-color-fragment.glsl");
 
799
    if (m_colorShader->isValid()) {
 
800
        pushShader(ColorShader, true);
 
801
        popShader();
 
802
        kDebug(1212) << "Color Shader is valid";
 
803
    } else {
 
804
        delete m_genericShader;
 
805
        m_genericShader = NULL;
 
806
        delete m_orthoShader;
 
807
        m_orthoShader = NULL;
 
808
        delete m_colorShader;
 
809
        m_colorShader = NULL;
 
810
        kDebug(1212) << "Color Scene Shader is not valid";
 
811
        return;
 
812
    }
 
813
    m_valid = true;
 
814
}
 
815
 
 
816
void ShaderManager::resetShader(ShaderType type)
 
817
{
 
818
    // resetShader is either called from init or from push, we know that a built-in shader is bound
 
819
    const QMatrix4x4 identity;
 
820
 
 
821
    QMatrix4x4 projection;
 
822
    QMatrix4x4 modelView;
 
823
 
 
824
    GLShader *shader = getBoundShader();
 
825
 
 
826
    switch(type) {
 
827
    case SimpleShader:
 
828
        projection.ortho(0, displayWidth(), displayHeight(), 0, 0, 65535);
 
829
        break;
 
830
 
 
831
    case GenericShader: {
 
832
        // Set up the projection matrix
 
833
        float fovy   = 60.0f;
 
834
        float aspect = 1.0f;
 
835
        float zNear  = 0.1f;
 
836
        float zFar   = 100.0f;
 
837
        float ymax   = zNear * tan(fovy  * M_PI / 360.0f);
 
838
        float ymin   = -ymax;
 
839
        float xmin   =  ymin * aspect;
 
840
        float xmax   = ymax * aspect;
 
841
        projection.frustum(xmin, xmax, ymin, ymax, zNear, zFar);
 
842
 
 
843
        // Set up the model-view matrix
 
844
        float scaleFactor = 1.1 * tan(fovy * M_PI / 360.0f) / ymax;
 
845
        modelView.translate(xmin * scaleFactor, ymax * scaleFactor, -1.1);
 
846
        modelView.scale((xmax - xmin)*scaleFactor / displayWidth(), -(ymax - ymin)*scaleFactor / displayHeight(), 0.001);
 
847
        break;
 
848
    }
 
849
 
 
850
    case ColorShader:
 
851
        projection.ortho(0, displayWidth(), displayHeight(), 0, 0, 65535);
 
852
        shader->setUniform("geometryColor", QVector4D(0, 0, 0, 1));
 
853
        break;
 
854
    }
 
855
 
 
856
    shader->setUniform("sampler", 0);
 
857
 
 
858
    shader->setUniform(GLShader::ProjectionMatrix,     projection);
 
859
    shader->setUniform(GLShader::ModelViewMatrix,      modelView);
 
860
    shader->setUniform(GLShader::ScreenTransformation, identity);
 
861
    shader->setUniform(GLShader::WindowTransformation, identity);
 
862
 
 
863
    shader->setUniform(GLShader::Offset, QVector2D(0, 0));
 
864
    shader->setUniform(GLShader::ModulationConstant, QVector4D(1.0, 1.0, 1.0, 1.0));
 
865
 
 
866
    shader->setUniform(GLShader::Saturation, 1.0f);
 
867
    shader->setUniform(GLShader::AlphaToOne, 0);
 
868
}
 
869
 
 
870
/***  GLRenderTarget  ***/
 
871
bool GLRenderTarget::sSupported = false;
 
872
bool GLRenderTarget::s_blitSupported = false;
 
873
QStack<GLRenderTarget*> GLRenderTarget::s_renderTargets = QStack<GLRenderTarget*>();
 
874
QSize GLRenderTarget::s_oldViewport;
 
875
 
 
876
void GLRenderTarget::initStatic()
 
877
{
 
878
#ifdef KWIN_HAVE_OPENGLES
 
879
    sSupported = true;
 
880
    s_blitSupported = false;
 
881
#else
 
882
    sSupported = hasGLExtension("GL_EXT_framebuffer_object") && glFramebufferTexture2D;
 
883
    s_blitSupported = hasGLExtension("GL_EXT_framebuffer_blit");
 
884
#endif
 
885
}
 
886
 
 
887
bool GLRenderTarget::isRenderTargetBound()
 
888
{
 
889
    return !s_renderTargets.isEmpty();
 
890
}
 
891
 
 
892
bool GLRenderTarget::blitSupported()
 
893
{
 
894
    return s_blitSupported;
 
895
}
 
896
 
 
897
void GLRenderTarget::pushRenderTarget(GLRenderTarget* target)
 
898
{
 
899
    if (s_renderTargets.isEmpty()) {
 
900
        GLint params[4];
 
901
        glGetIntegerv(GL_VIEWPORT, params);
 
902
        s_oldViewport = QSize(params[2], params[3]);
 
903
    }
 
904
 
 
905
    target->enable();
 
906
    s_renderTargets.push(target);
 
907
}
 
908
 
 
909
GLRenderTarget* GLRenderTarget::popRenderTarget()
 
910
{
 
911
    GLRenderTarget* ret = s_renderTargets.pop();
 
912
    ret->disable();
 
913
    if (!s_renderTargets.isEmpty()) {
 
914
        s_renderTargets.top()->enable();
 
915
    } else if (!s_oldViewport.isEmpty()) {
 
916
        glViewport (0, 0, s_oldViewport.width(), s_oldViewport.height());
 
917
    }
 
918
    return ret;
 
919
}
 
920
 
 
921
GLRenderTarget::GLRenderTarget(const GLTexture& color)
 
922
{
 
923
    // Reset variables
 
924
    mValid = false;
 
925
 
 
926
    mTexture = color;
 
927
 
 
928
    // Make sure FBO is supported
 
929
    if (sSupported && !mTexture.isNull()) {
 
930
        initFBO();
 
931
    } else
 
932
        kError(1212) << "Render targets aren't supported!" << endl;
 
933
}
 
934
 
 
935
GLRenderTarget::~GLRenderTarget()
 
936
{
 
937
    if (mValid) {
 
938
        glDeleteFramebuffers(1, &mFramebuffer);
 
939
    }
 
940
}
 
941
 
 
942
bool GLRenderTarget::enable()
 
943
{
 
944
    if (!valid()) {
 
945
        kError(1212) << "Can't enable invalid render target!" << endl;
 
946
        return false;
 
947
    }
 
948
 
 
949
    glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
 
950
    glViewport(0, 0, mTexture.width(), mTexture.height());
 
951
    mTexture.setDirty();
 
952
 
 
953
    return true;
 
954
}
 
955
 
 
956
bool GLRenderTarget::disable()
 
957
{
 
958
    if (!valid()) {
 
959
        kError(1212) << "Can't disable invalid render target!" << endl;
 
960
        return false;
 
961
    }
 
962
 
 
963
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
 
964
    mTexture.setDirty();
 
965
 
 
966
    return true;
 
967
}
 
968
 
 
969
static QString formatFramebufferStatus(GLenum status)
 
970
{
 
971
    switch(status) {
 
972
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
 
973
        // An attachment is the wrong type / is invalid / has 0 width or height
 
974
        return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
 
975
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
 
976
        // There are no images attached to the framebuffer
 
977
        return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
 
978
    case GL_FRAMEBUFFER_UNSUPPORTED:
 
979
        // A format or the combination of formats of the attachments is unsupported
 
980
        return "GL_FRAMEBUFFER_UNSUPPORTED";
 
981
#ifndef KWIN_HAVE_OPENGLES
 
982
    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
 
983
        // Not all attached images have the same width and height
 
984
        return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT";
 
985
    case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
 
986
        // The color attachments don't have the same format
 
987
        return "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT";
 
988
    case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
 
989
        // The attachments don't have the same number of samples
 
990
        return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
 
991
    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
 
992
        // The draw buffer is missing
 
993
        return "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER";
 
994
    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
 
995
        // The read buffer is missing
 
996
        return "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER";
 
997
#endif
 
998
    default:
 
999
        return "Unknown (0x" + QString::number(status, 16) + ')';
 
1000
    }
 
1001
}
 
1002
 
 
1003
void GLRenderTarget::initFBO()
 
1004
{
 
1005
#if DEBUG_GLRENDERTARGET
 
1006
    GLenum err = glGetError();
 
1007
    if (err != GL_NO_ERROR)
 
1008
        kError(1212) << "Error status when entering GLRenderTarget::initFBO: " << formatGLError(err);
 
1009
#endif
 
1010
 
 
1011
    glGenFramebuffers(1, &mFramebuffer);
 
1012
 
 
1013
#if DEBUG_GLRENDERTARGET
 
1014
    if ((err = glGetError()) != GL_NO_ERROR) {
 
1015
        kError(1212) << "glGenFramebuffers failed: " << formatGLError(err);
 
1016
        return;
 
1017
    }
 
1018
#endif
 
1019
 
 
1020
    glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
 
1021
 
 
1022
#if DEBUG_GLRENDERTARGET
 
1023
    if ((err = glGetError()) != GL_NO_ERROR) {
 
1024
        kError(1212) << "glBindFramebuffer failed: " << formatGLError(err);
 
1025
        glDeleteFramebuffers(1, &mFramebuffer);
 
1026
        return;
 
1027
    }
 
1028
#endif
 
1029
 
 
1030
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
 
1031
                           mTexture.target(), mTexture.texture(), 0);
 
1032
 
 
1033
#if DEBUG_GLRENDERTARGET
 
1034
    if ((err = glGetError()) != GL_NO_ERROR) {
 
1035
        kError(1212) << "glFramebufferTexture2D failed: " << formatGLError(err);
 
1036
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
 
1037
        glDeleteFramebuffers(1, &mFramebuffer);
 
1038
        return;
 
1039
    }
 
1040
#endif
 
1041
 
 
1042
    const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 
1043
 
 
1044
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
 
1045
 
 
1046
    if (status != GL_FRAMEBUFFER_COMPLETE) {
 
1047
        // We have an incomplete framebuffer, consider it invalid
 
1048
        if (status == 0)
 
1049
            kError(1212) << "glCheckFramebufferStatus failed: " << formatGLError(glGetError());
 
1050
        else
 
1051
            kError(1212) << "Invalid framebuffer status: " << formatFramebufferStatus(status);
 
1052
        glDeleteFramebuffers(1, &mFramebuffer);
 
1053
        return;
 
1054
    }
 
1055
 
 
1056
    mValid = true;
 
1057
}
 
1058
 
 
1059
void GLRenderTarget::blitFromFramebuffer(const QRect &source, const QRect &destination, GLenum filter)
 
1060
{
 
1061
    if (!GLRenderTarget::blitSupported()) {
 
1062
        return;
 
1063
    }
 
1064
#ifndef KWIN_HAVE_OPENGLES
 
1065
    GLRenderTarget::pushRenderTarget(this);
 
1066
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer);
 
1067
    glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
 
1068
    const QRect s = source.isNull() ? QRect(0, 0, displayWidth(), displayHeight()) : source;
 
1069
    const QRect d = destination.isNull() ? QRect(0, 0, mTexture.width(), mTexture.height()) : destination;
 
1070
 
 
1071
    glBlitFramebuffer(s.x(), displayHeight() - s.y() - s.height(), s.x() + s.width(), displayHeight() - s.y(),
 
1072
                      d.x(), mTexture.height() - d.y() - d.height(), d.x() + d.width(), mTexture.height() - d.y(),
 
1073
                      GL_COLOR_BUFFER_BIT, filter);
 
1074
    GLRenderTarget::popRenderTarget();
 
1075
#endif
 
1076
}
 
1077
 
 
1078
void GLRenderTarget::attachTexture(const GLTexture& target)
 
1079
{
 
1080
    if (!mValid || mTexture.texture() == target.texture()) {
 
1081
        return;
 
1082
    }
 
1083
 
 
1084
    pushRenderTarget(this);
 
1085
 
 
1086
    mTexture = target;
 
1087
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
 
1088
                           mTexture.target(), mTexture.texture(), 0);
 
1089
 
 
1090
    popRenderTarget();
 
1091
}
 
1092
 
 
1093
//*********************************
 
1094
// GLVertexBufferPrivate
 
1095
//*********************************
 
1096
class GLVertexBufferPrivate
 
1097
{
 
1098
public:
 
1099
    GLVertexBufferPrivate(GLVertexBuffer::UsageHint usageHint)
 
1100
        : hint(usageHint)
 
1101
        , numberVertices(0)
 
1102
        , dimension(2)
 
1103
        , useColor(false)
 
1104
        , useTexCoords(true)
 
1105
        , color(0, 0, 0, 255) {
 
1106
        if (GLVertexBufferPrivate::supported) {
 
1107
            glGenBuffers(2, buffers);
 
1108
        }
 
1109
    }
 
1110
    ~GLVertexBufferPrivate() {
 
1111
        if (GLVertexBufferPrivate::supported) {
 
1112
            glDeleteBuffers(2, buffers);
 
1113
        }
 
1114
    }
 
1115
    GLVertexBuffer::UsageHint hint;
 
1116
    GLuint buffers[2];
 
1117
    int numberVertices;
 
1118
    int dimension;
 
1119
    static bool supported;
 
1120
    static GLVertexBuffer *streamingBuffer;
 
1121
    QVector<float> legacyVertices;
 
1122
    QVector<float> legacyTexCoords;
 
1123
    bool useColor;
 
1124
    bool useTexCoords;
 
1125
    QColor color;
 
1126
 
 
1127
    //! VBO is not supported
 
1128
    void legacyPainting(QRegion region, GLenum primitiveMode);
 
1129
    //! VBO and shaders are both supported
 
1130
    void corePainting(const QRegion& region, GLenum primitiveMode);
 
1131
    //! VBO is supported, but shaders are not supported
 
1132
    void fallbackPainting(const QRegion& region, GLenum primitiveMode);
 
1133
};
 
1134
bool GLVertexBufferPrivate::supported = false;
 
1135
GLVertexBuffer *GLVertexBufferPrivate::streamingBuffer = NULL;
 
1136
 
 
1137
void GLVertexBufferPrivate::legacyPainting(QRegion region, GLenum primitiveMode)
 
1138
{
 
1139
#ifdef KWIN_HAVE_OPENGLES
 
1140
    Q_UNUSED(primitiveMode)
 
1141
#else
 
1142
    Q_UNUSED(region)
 
1143
    // Enable arrays
 
1144
    glEnableClientState(GL_VERTEX_ARRAY);
 
1145
    glVertexPointer(dimension, GL_FLOAT, 0, legacyVertices.constData());
 
1146
    if (!legacyTexCoords.isEmpty()) {
 
1147
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
1148
        glTexCoordPointer(2, GL_FLOAT, 0, legacyTexCoords.constData());
 
1149
    }
 
1150
 
 
1151
    if (useColor) {
 
1152
        glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
 
1153
    }
 
1154
 
 
1155
    glDrawArrays(primitiveMode, 0, numberVertices);
 
1156
 
 
1157
    glDisableClientState(GL_VERTEX_ARRAY);
 
1158
    if (!legacyTexCoords.isEmpty()) {
 
1159
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
1160
    }
 
1161
#endif
 
1162
}
 
1163
 
 
1164
void GLVertexBufferPrivate::corePainting(const QRegion& region, GLenum primitiveMode)
 
1165
{
 
1166
    Q_UNUSED(region)
 
1167
    GLShader *shader = ShaderManager::instance()->getBoundShader();
 
1168
    GLint vertexAttrib = shader->attributeLocation("vertex");
 
1169
    GLint texAttrib = shader->attributeLocation("texCoord");
 
1170
 
 
1171
    glEnableVertexAttribArray(vertexAttrib);
 
1172
    if (useTexCoords) {
 
1173
        glEnableVertexAttribArray(texAttrib);
 
1174
    }
 
1175
 
 
1176
    if (useColor) {
 
1177
        shader->setUniform("geometryColor", color);
 
1178
    }
 
1179
 
 
1180
    glBindBuffer(GL_ARRAY_BUFFER, buffers[ 0 ]);
 
1181
    glVertexAttribPointer(vertexAttrib, dimension, GL_FLOAT, GL_FALSE, 0, 0);
 
1182
 
 
1183
    if (texAttrib != -1 && useTexCoords) {
 
1184
        glBindBuffer(GL_ARRAY_BUFFER, buffers[ 1 ]);
 
1185
        glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
 
1186
    }
 
1187
 
 
1188
    glDrawArrays(primitiveMode, 0, numberVertices);
 
1189
 
 
1190
    glBindBuffer(GL_ARRAY_BUFFER, 0);
 
1191
 
 
1192
    if (useTexCoords) {
 
1193
        glDisableVertexAttribArray(texAttrib);
 
1194
    }
 
1195
    glDisableVertexAttribArray(vertexAttrib);
 
1196
}
 
1197
 
 
1198
void GLVertexBufferPrivate::fallbackPainting(const QRegion& region, GLenum primitiveMode)
 
1199
{
 
1200
#ifdef KWIN_HAVE_OPENGLES
 
1201
    Q_UNUSED(primitiveMode)
 
1202
#else
 
1203
    Q_UNUSED(region)
 
1204
    glEnableClientState(GL_VERTEX_ARRAY);
 
1205
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
1206
    glBindBuffer(GL_ARRAY_BUFFER, buffers[ 0 ]);
 
1207
    glVertexPointer(dimension, GL_FLOAT, 0, 0);
 
1208
 
 
1209
    glBindBuffer(GL_ARRAY_BUFFER, buffers[ 1 ]);
 
1210
    glTexCoordPointer(2, GL_FLOAT, 0, 0);
 
1211
 
 
1212
    if (useColor) {
 
1213
        glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
 
1214
    }
 
1215
 
 
1216
    // Clip using scissoring
 
1217
    glDrawArrays(primitiveMode, 0, numberVertices);
 
1218
 
 
1219
    glBindBuffer(GL_ARRAY_BUFFER, 0);
 
1220
 
 
1221
    glDisableClientState(GL_VERTEX_ARRAY);
 
1222
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
1223
#endif
 
1224
}
 
1225
 
 
1226
//*********************************
 
1227
// GLVertexBuffer
 
1228
//*********************************
 
1229
GLVertexBuffer::GLVertexBuffer(UsageHint hint)
 
1230
    : d(new GLVertexBufferPrivate(hint))
 
1231
{
 
1232
}
 
1233
 
 
1234
GLVertexBuffer::~GLVertexBuffer()
 
1235
{
 
1236
    delete d;
 
1237
}
 
1238
 
 
1239
void GLVertexBuffer::setData(int numberVertices, int dim, const float* vertices, const float* texcoords)
 
1240
{
 
1241
    d->numberVertices = numberVertices;
 
1242
    d->dimension = dim;
 
1243
    d->useTexCoords = (texcoords != NULL);
 
1244
    if (!GLVertexBufferPrivate::supported) {
 
1245
        // legacy data
 
1246
        d->legacyVertices.clear();
 
1247
        d->legacyVertices.reserve(numberVertices * dim);
 
1248
        for (int i = 0; i < numberVertices * dim; ++i) {
 
1249
            d->legacyVertices << vertices[i];
 
1250
        }
 
1251
        d->legacyTexCoords.clear();
 
1252
        if (d->useTexCoords) {
 
1253
            d->legacyTexCoords.reserve(numberVertices * 2);
 
1254
            for (int i = 0; i < numberVertices * 2; ++i) {
 
1255
                d->legacyTexCoords << texcoords[i];
 
1256
            }
 
1257
        }
 
1258
        return;
 
1259
    }
 
1260
    GLenum hint;
 
1261
    switch(d->hint) {
 
1262
    case Dynamic:
 
1263
        hint = GL_DYNAMIC_DRAW;
 
1264
        break;
 
1265
    case Static:
 
1266
        hint = GL_STATIC_DRAW;
 
1267
        break;
 
1268
    case Stream:
 
1269
        hint = GL_STREAM_DRAW;
 
1270
        break;
 
1271
    default:
 
1272
        // just to make the compiler happy
 
1273
        hint = GL_STREAM_DRAW;
 
1274
        break;
 
1275
    }
 
1276
    glBindBuffer(GL_ARRAY_BUFFER, d->buffers[ 0 ]);
 
1277
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*numberVertices * d->dimension, vertices, hint);
 
1278
 
 
1279
    if (d->useTexCoords) {
 
1280
        glBindBuffer(GL_ARRAY_BUFFER, d->buffers[ 1 ]);
 
1281
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*numberVertices * 2, texcoords, hint);
 
1282
    }
 
1283
 
 
1284
    glBindBuffer(GL_ARRAY_BUFFER, 0);
 
1285
}
 
1286
 
 
1287
void GLVertexBuffer::render(GLenum primitiveMode)
 
1288
{
 
1289
    render(infiniteRegion(), primitiveMode);
 
1290
}
 
1291
 
 
1292
void GLVertexBuffer::render(const QRegion& region, GLenum primitiveMode)
 
1293
{
 
1294
    if (!GLVertexBufferPrivate::supported) {
 
1295
        d->legacyPainting(region, primitiveMode);
 
1296
    } else if (ShaderManager::instance()->isShaderBound()) {
 
1297
        d->corePainting(region, primitiveMode);
 
1298
    } else {
 
1299
        d->fallbackPainting(region, primitiveMode);
 
1300
    }
 
1301
}
 
1302
 
 
1303
bool GLVertexBuffer::isSupported()
 
1304
{
 
1305
    return GLVertexBufferPrivate::supported;
 
1306
}
 
1307
 
 
1308
bool GLVertexBuffer::isUseColor() const
 
1309
{
 
1310
    return d->useColor;
 
1311
}
 
1312
 
 
1313
void GLVertexBuffer::setUseColor(bool enable)
 
1314
{
 
1315
    d->useColor = enable;
 
1316
}
 
1317
 
 
1318
void GLVertexBuffer::setColor(const QColor& color, bool enable)
 
1319
{
 
1320
    d->useColor = enable;
 
1321
    d->color = color;
 
1322
}
 
1323
 
 
1324
void GLVertexBuffer::reset()
 
1325
{
 
1326
    d->useColor       = false;
 
1327
    d->color          = QColor(0, 0, 0, 255);
 
1328
    d->numberVertices = 0;
 
1329
    d->dimension      = 2;
 
1330
    d->useTexCoords   = true;
 
1331
}
 
1332
 
 
1333
void GLVertexBuffer::initStatic()
 
1334
{
 
1335
#ifdef KWIN_HAVE_OPENGLES
 
1336
    GLVertexBufferPrivate::supported = true;
 
1337
#else
 
1338
    GLVertexBufferPrivate::supported = hasGLExtension("GL_ARB_vertex_buffer_object");
 
1339
#endif
 
1340
    GLVertexBufferPrivate::streamingBuffer = new GLVertexBuffer(GLVertexBuffer::Stream);
 
1341
}
 
1342
 
 
1343
GLVertexBuffer *GLVertexBuffer::streamingBuffer()
 
1344
{
 
1345
    return GLVertexBufferPrivate::streamingBuffer;
 
1346
}
 
1347
 
 
1348
} // namespace