1
/********************************************************************
2
KWin - the KDE window manager
3
This file is part of the KDE project.
5
Copyright (C) 2006-2007 Rivo Laks <rivolaks@hot.ee>
6
Copyright (C) 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
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 "kwinglutils.h"
24
// need to call GLTexturePrivate::initStatic()
25
#include "kwingltexture_p.h"
27
#include "kwinglobals.h"
28
#include "kwineffects.h"
29
#include "kwinglplatform.h"
32
#include <kstandarddirs.h>
33
#include <KDE/KConfig>
34
#include <KDE/KConfigGroup>
47
#define DEBUG_GLRENDERTARGET 0
49
#define MAKE_GL_VERSION(major, minor, release) ( ((major) << 16) | ((minor) << 8) | (release) )
54
// GL version, use MAKE_GL_VERSION() macro for comparing with a specific version
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;
66
int glTextureUnitsCount;
72
#ifndef KWIN_HAVE_OPENGLES
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(' ');
81
glxResolveFunctions();
87
#ifdef KWIN_HAVE_OPENGLES
88
EGLDisplay dpy = eglGetCurrentDisplay();
90
eglInitialize(dpy, &major, &minor);
91
eglVersion = MAKE_GL_VERSION(major, minor, 0);
92
eglExtension = QString((const char*)eglQueryString(dpy, EGL_EXTENSIONS)).split(' ');
94
eglResolveFunctions();
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
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());
113
// Get list of supported OpenGL extensions
114
glExtensions = QString((const char*)glGetString(GL_EXTENSIONS)).split(' ');
116
// handle OpenGL extensions functions
117
glResolveFunctions();
119
GLTexturePrivate::initStatic();
120
GLRenderTarget::initStatic();
121
GLVertexBuffer::initStatic();
126
ShaderManager::cleanup();
129
bool hasGLVersion(int major, int minor, int release)
131
return glVersion >= MAKE_GL_VERSION(major, minor, release);
134
bool hasGLXVersion(int major, int minor, int release)
136
return glXVersion >= MAKE_GL_VERSION(major, minor, release);
139
bool hasEGLVersion(int major, int minor, int release)
141
return eglVersion >= MAKE_GL_VERSION(major, minor, release);
144
bool hasGLExtension(const QString& extension)
146
return glExtensions.contains(extension) || glxExtensions.contains(extension) || eglExtension.contains(extension);
149
static QString formatGLError(GLenum 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";
160
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
161
default: return QString("0x") + QString::number(err, 16);
165
bool checkGLError(const char* txt)
167
GLenum err = glGetError();
168
if (err != GL_NO_ERROR) {
169
kWarning(1212) << "GL error (" << txt << "): " << formatGLError(err);
175
int nearestPowerOfTwo(int x)
177
// This method had been copied from Qt's nearest_gl_texture_size()
179
for (int s = 0; s < 32; ++s) {
180
if (((x >> s) & 1) == 1) {
186
return 1 << (last + 1);
192
#ifndef KWIN_HAVE_OPENGLES
197
void pushMatrix(const QMatrix4x4 &matrix)
199
#ifdef KWIN_HAVE_OPENGLES
203
multiplyMatrix(matrix);
207
void multiplyMatrix(const QMatrix4x4 &matrix)
209
#ifdef KWIN_HAVE_OPENGLES
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];
223
void loadMatrix(const QMatrix4x4 &matrix)
225
#ifdef KWIN_HAVE_OPENGLES
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];
241
#ifndef KWIN_HAVE_OPENGLES
246
//****************************************
248
//****************************************
253
, mLocationsResolved(false)
257
GLShader::GLShader(const QString& vertexfile, const QString& fragmentfile)
260
, mLocationsResolved(false)
262
loadFromFiles(vertexfile, fragmentfile);
265
GLShader::~GLShader()
268
glDeleteProgram(mProgram);
272
bool GLShader::loadFromFiles(const QString &vertexFile, const QString &fragmentFile)
274
QFile vf(vertexFile);
275
if (!vf.open(QIODevice::ReadOnly)) {
276
kError(1212) << "Couldn't open" << vertexFile << "for reading!" << endl;
279
const QByteArray vertexSource = vf.readAll();
281
QFile ff(fragmentFile);
282
if (!ff.open(QIODevice::ReadOnly)) {
283
kError(1212) << "Couldn't open" << fragmentFile << "for reading!" << endl;
286
const QByteArray fragmentSource = ff.readAll();
288
return load(vertexSource, fragmentSource);
291
bool GLShader::compile(GLuint program, GLenum shaderType, const QByteArray &source) const
293
GLuint shader = glCreateShader(shaderType);
295
// Prepare the source code
297
#ifdef KWIN_HAVE_OPENGLES
298
ba.append("#ifdef GL_ES\nprecision highp float;\n#endif\n");
300
if (ShaderManager::instance()->isShaderDebug()) {
301
ba.append("#define KWIN_SHADER_DEBUG 1\n");
305
const char* src = ba.constData();
306
glShaderSource(shader, 1, &src, NULL);
308
// Compile the shader
309
glCompileShader(shader);
311
// Get the shader info log
312
int maxLength, length;
313
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
315
QByteArray log(maxLength, 0);
316
glGetShaderInfoLog(shader, maxLength, &length, log.data());
320
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
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;
329
glAttachShader(program, shader);
331
glDeleteShader(shader);
335
bool GLShader::load(const QByteArray &vertexSource, const QByteArray &fragmentSource)
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";
345
// Create the shader program
346
mProgram = glCreateProgram();
348
// Compile the vertex shader
349
if (!vertexSource.isEmpty()) {
350
bool success = compile(mProgram, GL_VERTEX_SHADER, vertexSource);
353
glDeleteProgram(mProgram);
359
// Compile the fragment shader
360
if (!fragmentSource.isEmpty()) {
361
bool success = compile(mProgram, GL_FRAGMENT_SHADER, fragmentSource);
364
glDeleteProgram(mProgram);
370
glLinkProgram(mProgram);
372
// Get the program info log
373
int maxLength, length;
374
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &maxLength);
376
QByteArray log(maxLength, 0);
377
glGetProgramInfoLog(mProgram, maxLength, &length, log.data());
379
// Make sure the program linked successfully
381
glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
384
kError(1212) << "Failed to link shader:" << endl << log << endl;
385
glDeleteProgram(mProgram);
388
} else if (length > 0)
389
kDebug(1212) << "Shader link log:" << log;
395
void GLShader::bind()
397
glUseProgram(mProgram);
400
void GLShader::unbind()
405
void GLShader::resolveLocations()
407
if (mLocationsResolved)
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");
416
mVec2Location[Offset] = uniformLocation("offset");
418
mVec4Location[ModulationConstant] = uniformLocation("modulation");
420
mFloatLocation[Saturation] = uniformLocation("saturation");
422
mIntLocation[AlphaToOne] = uniformLocation("u_forceAlpha");
424
mLocationsResolved = true;
427
int GLShader::uniformLocation(const char *name)
429
const int location = glGetUniformLocation(mProgram, name);
433
bool GLShader::setUniform(GLShader::MatrixUniform uniform, const QMatrix4x4 &matrix)
436
return setUniform(mMatrixLocation[uniform], matrix);
439
bool GLShader::setUniform(GLShader::Vec2Uniform uniform, const QVector2D &value)
442
return setUniform(mVec2Location[uniform], value);
445
bool GLShader::setUniform(GLShader::Vec4Uniform uniform, const QVector4D &value)
448
return setUniform(mVec4Location[uniform], value);
451
bool GLShader::setUniform(GLShader::FloatUniform uniform, float value)
454
return setUniform(mFloatLocation[uniform], value);
457
bool GLShader::setUniform(GLShader::IntUniform uniform, int value)
460
return setUniform(mIntLocation[uniform], value);
463
bool GLShader::setUniform(const char *name, float value)
465
const int location = uniformLocation(name);
466
return setUniform(location, value);
469
bool GLShader::setUniform(const char *name, int value)
471
const int location = uniformLocation(name);
472
return setUniform(location, value);
475
bool GLShader::setUniform(const char *name, const QVector2D& value)
477
const int location = uniformLocation(name);
478
return setUniform(location, value);
481
bool GLShader::setUniform(const char *name, const QVector3D& value)
483
const int location = uniformLocation(name);
484
return setUniform(location, value);
487
bool GLShader::setUniform(const char *name, const QVector4D& value)
489
const int location = uniformLocation(name);
490
return setUniform(location, value);
493
bool GLShader::setUniform(const char *name, const QMatrix4x4& value)
495
const int location = uniformLocation(name);
496
return setUniform(location, value);
499
bool GLShader::setUniform(const char *name, const QColor& color)
501
const int location = uniformLocation(name);
502
return setUniform(location, color);
505
bool GLShader::setUniform(int location, float value)
508
glUniform1f(location, value);
510
return (location >= 0);
513
bool GLShader::setUniform(int location, int value)
516
glUniform1i(location, value);
518
return (location >= 0);
521
bool GLShader::setUniform(int location, const QVector2D &value)
524
glUniform2fv(location, 1, (const GLfloat*)&value);
526
return (location >= 0);
529
bool GLShader::setUniform(int location, const QVector3D &value)
532
glUniform3fv(location, 1, (const GLfloat*)&value);
534
return (location >= 0);
537
bool GLShader::setUniform(int location, const QVector4D &value)
540
glUniform4fv(location, 1, (const GLfloat*)&value);
542
return (location >= 0);
545
bool GLShader::setUniform(int location, const QMatrix4x4 &value)
549
const qreal *data = value.constData();
550
// i is column, j is row for m
551
for (int i = 0; i < 16; ++i) {
554
glUniformMatrix4fv(location, 1, GL_FALSE, m);
556
return (location >= 0);
559
bool GLShader::setUniform(int location, const QColor &color)
562
glUniform4f(location, color.redF(), color.greenF(), color.blueF(), color.alphaF());
564
return (location >= 0);
567
int GLShader::attributeLocation(const char* name)
569
int location = glGetAttribLocation(mProgram, name);
573
bool GLShader::setAttribute(const char* name, float value)
575
int location = attributeLocation(name);
577
glVertexAttrib1f(location, value);
579
return (location >= 0);
582
QMatrix4x4 GLShader::getUniformMatrix4x4(const char* name)
584
int location = uniformLocation(name);
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]);
599
//****************************************
601
//****************************************
602
ShaderManager *ShaderManager::s_shaderManager = NULL;
604
ShaderManager *ShaderManager::instance()
606
if (!s_shaderManager) {
607
s_shaderManager = new ShaderManager();
608
s_shaderManager->initShaders();
609
s_shaderManager->m_inited = true;
611
return s_shaderManager;
614
void ShaderManager::cleanup()
616
delete s_shaderManager;
617
s_shaderManager = NULL;
620
ShaderManager::ShaderManager()
621
: m_orthoShader(NULL)
622
, m_genericShader(NULL)
623
, m_colorShader(NULL)
627
m_debug = qstrcmp(qgetenv("KWIN_GL_DEBUG"), "1") == 0;
630
ShaderManager::~ShaderManager()
632
while (!m_boundShaders.isEmpty()) {
635
delete m_orthoShader;
636
delete m_genericShader;
637
delete m_colorShader;
640
GLShader *ShaderManager::getBoundShader() const
642
if (m_boundShaders.isEmpty()) {
645
return m_boundShaders.top();
649
bool ShaderManager::isShaderBound() const
651
return !m_boundShaders.isEmpty();
654
bool ShaderManager::isValid() const
659
bool ShaderManager::isShaderDebug() const
664
GLShader *ShaderManager::pushShader(ShaderType type, bool reset)
666
if (m_inited && !m_valid) {
672
shader = m_orthoShader;
675
shader = m_genericShader;
678
shader = m_colorShader;
692
void ShaderManager::pushShader(GLShader *shader)
694
// only bind shader if it is not already bound
695
if (shader != getBoundShader()) {
698
m_boundShaders.push(shader);
701
void ShaderManager::popShader()
703
if (m_boundShaders.isEmpty()) {
706
GLShader *shader = m_boundShaders.pop();
707
if (m_boundShaders.isEmpty()) {
708
// no more shader bound - 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();
716
GLShader *ShaderManager::loadFragmentShader(ShaderType vertex, const QString &fragmentFile)
718
QString vertexShader;
721
vertexShader = ":/resources/scene-vertex.glsl";
724
vertexShader = ":/resources/scene-generic-vertex.glsl";
727
vertexShader = ":/resources/scene-color-vertex.glsl";
730
GLShader *shader = new GLShader(vertexShader, fragmentFile);
731
if (shader->isValid()) {
739
GLShader *ShaderManager::loadVertexShader(ShaderType fragment, const QString &vertexFile)
741
QString fragmentShader;
743
// Simple and Generic Shader use same fragment Shader
746
fragmentShader = ":/resources/scene-fragment.glsl";
749
fragmentShader = ":/resources/scene-color-fragment.glsl";
752
GLShader *shader = new GLShader(vertexFile, fragmentShader);
753
if (shader->isValid()) {
755
resetShader(fragment);
761
GLShader *ShaderManager::loadShaderFromCode(const QByteArray &vertexSource, const QByteArray &fragmentSource)
763
GLShader *shader = new GLShader();
764
shader->load(vertexSource, fragmentSource);
768
void ShaderManager::initShaders()
771
kDebug(1212) << "OpenGL Shaders disabled by config option";
774
m_orthoShader = new GLShader(":/resources/scene-vertex.glsl", ":/resources/scene-fragment.glsl");
775
if (m_orthoShader->isValid()) {
776
pushShader(SimpleShader, true);
778
kDebug(1212) << "Ortho Shader is valid";
780
delete m_orthoShader;
781
m_orthoShader = NULL;
782
kDebug(1212) << "Orho Shader is not valid";
785
m_genericShader = new GLShader(":/resources/scene-generic-vertex.glsl", ":/resources/scene-fragment.glsl");
786
if (m_genericShader->isValid()) {
787
pushShader(GenericShader, true);
789
kDebug(1212) << "Generic Shader is valid";
791
delete m_genericShader;
792
m_genericShader = NULL;
793
delete m_orthoShader;
794
m_orthoShader = NULL;
795
kDebug(1212) << "Generic Shader is not valid";
798
m_colorShader = new GLShader(":/resources/scene-color-vertex.glsl", ":/resources/scene-color-fragment.glsl");
799
if (m_colorShader->isValid()) {
800
pushShader(ColorShader, true);
802
kDebug(1212) << "Color Shader is valid";
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";
816
void ShaderManager::resetShader(ShaderType type)
818
// resetShader is either called from init or from push, we know that a built-in shader is bound
819
const QMatrix4x4 identity;
821
QMatrix4x4 projection;
822
QMatrix4x4 modelView;
824
GLShader *shader = getBoundShader();
828
projection.ortho(0, displayWidth(), displayHeight(), 0, 0, 65535);
831
case GenericShader: {
832
// Set up the projection matrix
837
float ymax = zNear * tan(fovy * M_PI / 360.0f);
839
float xmin = ymin * aspect;
840
float xmax = ymax * aspect;
841
projection.frustum(xmin, xmax, ymin, ymax, zNear, zFar);
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);
851
projection.ortho(0, displayWidth(), displayHeight(), 0, 0, 65535);
852
shader->setUniform("geometryColor", QVector4D(0, 0, 0, 1));
856
shader->setUniform("sampler", 0);
858
shader->setUniform(GLShader::ProjectionMatrix, projection);
859
shader->setUniform(GLShader::ModelViewMatrix, modelView);
860
shader->setUniform(GLShader::ScreenTransformation, identity);
861
shader->setUniform(GLShader::WindowTransformation, identity);
863
shader->setUniform(GLShader::Offset, QVector2D(0, 0));
864
shader->setUniform(GLShader::ModulationConstant, QVector4D(1.0, 1.0, 1.0, 1.0));
866
shader->setUniform(GLShader::Saturation, 1.0f);
867
shader->setUniform(GLShader::AlphaToOne, 0);
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;
876
void GLRenderTarget::initStatic()
878
#ifdef KWIN_HAVE_OPENGLES
880
s_blitSupported = false;
882
sSupported = hasGLExtension("GL_EXT_framebuffer_object") && glFramebufferTexture2D;
883
s_blitSupported = hasGLExtension("GL_EXT_framebuffer_blit");
887
bool GLRenderTarget::isRenderTargetBound()
889
return !s_renderTargets.isEmpty();
892
bool GLRenderTarget::blitSupported()
894
return s_blitSupported;
897
void GLRenderTarget::pushRenderTarget(GLRenderTarget* target)
899
if (s_renderTargets.isEmpty()) {
901
glGetIntegerv(GL_VIEWPORT, params);
902
s_oldViewport = QSize(params[2], params[3]);
906
s_renderTargets.push(target);
909
GLRenderTarget* GLRenderTarget::popRenderTarget()
911
GLRenderTarget* ret = s_renderTargets.pop();
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());
921
GLRenderTarget::GLRenderTarget(const GLTexture& color)
928
// Make sure FBO is supported
929
if (sSupported && !mTexture.isNull()) {
932
kError(1212) << "Render targets aren't supported!" << endl;
935
GLRenderTarget::~GLRenderTarget()
938
glDeleteFramebuffers(1, &mFramebuffer);
942
bool GLRenderTarget::enable()
945
kError(1212) << "Can't enable invalid render target!" << endl;
949
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
950
glViewport(0, 0, mTexture.width(), mTexture.height());
956
bool GLRenderTarget::disable()
959
kError(1212) << "Can't disable invalid render target!" << endl;
963
glBindFramebuffer(GL_FRAMEBUFFER, 0);
969
static QString formatFramebufferStatus(GLenum 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";
999
return "Unknown (0x" + QString::number(status, 16) + ')';
1003
void GLRenderTarget::initFBO()
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);
1011
glGenFramebuffers(1, &mFramebuffer);
1013
#if DEBUG_GLRENDERTARGET
1014
if ((err = glGetError()) != GL_NO_ERROR) {
1015
kError(1212) << "glGenFramebuffers failed: " << formatGLError(err);
1020
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
1022
#if DEBUG_GLRENDERTARGET
1023
if ((err = glGetError()) != GL_NO_ERROR) {
1024
kError(1212) << "glBindFramebuffer failed: " << formatGLError(err);
1025
glDeleteFramebuffers(1, &mFramebuffer);
1030
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1031
mTexture.target(), mTexture.texture(), 0);
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);
1042
const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1044
glBindFramebuffer(GL_FRAMEBUFFER, 0);
1046
if (status != GL_FRAMEBUFFER_COMPLETE) {
1047
// We have an incomplete framebuffer, consider it invalid
1049
kError(1212) << "glCheckFramebufferStatus failed: " << formatGLError(glGetError());
1051
kError(1212) << "Invalid framebuffer status: " << formatFramebufferStatus(status);
1052
glDeleteFramebuffers(1, &mFramebuffer);
1059
void GLRenderTarget::blitFromFramebuffer(const QRect &source, const QRect &destination, GLenum filter)
1061
if (!GLRenderTarget::blitSupported()) {
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;
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();
1078
void GLRenderTarget::attachTexture(const GLTexture& target)
1080
if (!mValid || mTexture.texture() == target.texture()) {
1084
pushRenderTarget(this);
1087
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1088
mTexture.target(), mTexture.texture(), 0);
1093
//*********************************
1094
// GLVertexBufferPrivate
1095
//*********************************
1096
class GLVertexBufferPrivate
1099
GLVertexBufferPrivate(GLVertexBuffer::UsageHint usageHint)
1104
, useTexCoords(true)
1105
, color(0, 0, 0, 255) {
1106
if (GLVertexBufferPrivate::supported) {
1107
glGenBuffers(2, buffers);
1110
~GLVertexBufferPrivate() {
1111
if (GLVertexBufferPrivate::supported) {
1112
glDeleteBuffers(2, buffers);
1115
GLVertexBuffer::UsageHint hint;
1119
static bool supported;
1120
static GLVertexBuffer *streamingBuffer;
1121
QVector<float> legacyVertices;
1122
QVector<float> legacyTexCoords;
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);
1134
bool GLVertexBufferPrivate::supported = false;
1135
GLVertexBuffer *GLVertexBufferPrivate::streamingBuffer = NULL;
1137
void GLVertexBufferPrivate::legacyPainting(QRegion region, GLenum primitiveMode)
1139
#ifdef KWIN_HAVE_OPENGLES
1140
Q_UNUSED(primitiveMode)
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());
1152
glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
1155
glDrawArrays(primitiveMode, 0, numberVertices);
1157
glDisableClientState(GL_VERTEX_ARRAY);
1158
if (!legacyTexCoords.isEmpty()) {
1159
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1164
void GLVertexBufferPrivate::corePainting(const QRegion& region, GLenum primitiveMode)
1167
GLShader *shader = ShaderManager::instance()->getBoundShader();
1168
GLint vertexAttrib = shader->attributeLocation("vertex");
1169
GLint texAttrib = shader->attributeLocation("texCoord");
1171
glEnableVertexAttribArray(vertexAttrib);
1173
glEnableVertexAttribArray(texAttrib);
1177
shader->setUniform("geometryColor", color);
1180
glBindBuffer(GL_ARRAY_BUFFER, buffers[ 0 ]);
1181
glVertexAttribPointer(vertexAttrib, dimension, GL_FLOAT, GL_FALSE, 0, 0);
1183
if (texAttrib != -1 && useTexCoords) {
1184
glBindBuffer(GL_ARRAY_BUFFER, buffers[ 1 ]);
1185
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
1188
glDrawArrays(primitiveMode, 0, numberVertices);
1190
glBindBuffer(GL_ARRAY_BUFFER, 0);
1193
glDisableVertexAttribArray(texAttrib);
1195
glDisableVertexAttribArray(vertexAttrib);
1198
void GLVertexBufferPrivate::fallbackPainting(const QRegion& region, GLenum primitiveMode)
1200
#ifdef KWIN_HAVE_OPENGLES
1201
Q_UNUSED(primitiveMode)
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);
1209
glBindBuffer(GL_ARRAY_BUFFER, buffers[ 1 ]);
1210
glTexCoordPointer(2, GL_FLOAT, 0, 0);
1213
glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
1216
// Clip using scissoring
1217
glDrawArrays(primitiveMode, 0, numberVertices);
1219
glBindBuffer(GL_ARRAY_BUFFER, 0);
1221
glDisableClientState(GL_VERTEX_ARRAY);
1222
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1226
//*********************************
1228
//*********************************
1229
GLVertexBuffer::GLVertexBuffer(UsageHint hint)
1230
: d(new GLVertexBufferPrivate(hint))
1234
GLVertexBuffer::~GLVertexBuffer()
1239
void GLVertexBuffer::setData(int numberVertices, int dim, const float* vertices, const float* texcoords)
1241
d->numberVertices = numberVertices;
1243
d->useTexCoords = (texcoords != NULL);
1244
if (!GLVertexBufferPrivate::supported) {
1246
d->legacyVertices.clear();
1247
d->legacyVertices.reserve(numberVertices * dim);
1248
for (int i = 0; i < numberVertices * dim; ++i) {
1249
d->legacyVertices << vertices[i];
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];
1263
hint = GL_DYNAMIC_DRAW;
1266
hint = GL_STATIC_DRAW;
1269
hint = GL_STREAM_DRAW;
1272
// just to make the compiler happy
1273
hint = GL_STREAM_DRAW;
1276
glBindBuffer(GL_ARRAY_BUFFER, d->buffers[ 0 ]);
1277
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*numberVertices * d->dimension, vertices, hint);
1279
if (d->useTexCoords) {
1280
glBindBuffer(GL_ARRAY_BUFFER, d->buffers[ 1 ]);
1281
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*numberVertices * 2, texcoords, hint);
1284
glBindBuffer(GL_ARRAY_BUFFER, 0);
1287
void GLVertexBuffer::render(GLenum primitiveMode)
1289
render(infiniteRegion(), primitiveMode);
1292
void GLVertexBuffer::render(const QRegion& region, GLenum primitiveMode)
1294
if (!GLVertexBufferPrivate::supported) {
1295
d->legacyPainting(region, primitiveMode);
1296
} else if (ShaderManager::instance()->isShaderBound()) {
1297
d->corePainting(region, primitiveMode);
1299
d->fallbackPainting(region, primitiveMode);
1303
bool GLVertexBuffer::isSupported()
1305
return GLVertexBufferPrivate::supported;
1308
bool GLVertexBuffer::isUseColor() const
1313
void GLVertexBuffer::setUseColor(bool enable)
1315
d->useColor = enable;
1318
void GLVertexBuffer::setColor(const QColor& color, bool enable)
1320
d->useColor = enable;
1324
void GLVertexBuffer::reset()
1326
d->useColor = false;
1327
d->color = QColor(0, 0, 0, 255);
1328
d->numberVertices = 0;
1330
d->useTexCoords = true;
1333
void GLVertexBuffer::initStatic()
1335
#ifdef KWIN_HAVE_OPENGLES
1336
GLVertexBufferPrivate::supported = true;
1338
GLVertexBufferPrivate::supported = hasGLExtension("GL_ARB_vertex_buffer_object");
1340
GLVertexBufferPrivate::streamingBuffer = new GLVertexBuffer(GLVertexBuffer::Stream);
1343
GLVertexBuffer *GLVertexBuffer::streamingBuffer()
1345
return GLVertexBufferPrivate::streamingBuffer;