Copy core GL functionality to QtGui with QGL -> QOpenGL naming.

Change-Id: Ibc989afa4a30dd184d41d1a1cd89f97196e48855
Reviewed-on: http://codereview.qt.nokia.com/3710
Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
This commit is contained in:
Samuel Rødal 2011-08-22 10:49:28 +02:00
parent aaa4a26f82
commit 6e28e8441b
205 changed files with 24294 additions and 9028 deletions

View File

@ -1,6 +1,6 @@
#include "hellowindow.h"
#include <QGuiGLContext>
#include <QOpenGLContext>
#include <QTimer>
@ -10,7 +10,7 @@ Renderer::Renderer(const QSurfaceFormat &format, Renderer *share)
: m_initialized(false)
, m_format(format)
{
m_context = new QGuiGLContext;
m_context = new QOpenGLContext;
m_context->setFormat(format);
if (share)
m_context->setShareContext(share->m_context);
@ -91,11 +91,11 @@ void Renderer::render(QSurface *surface, const QColor &color, const QSize &viewS
modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f);
modelview.translate(0.0f, -0.2f, 0.0f);
program.bind();
program.setUniformValue(matrixUniform, modelview);
program.setUniformValue(colorUniform, color);
m_program->bind();
m_program->setUniformValue(matrixUniform, modelview);
m_program->setUniformValue(colorUniform, color);
paintQtLogo();
program.release();
m_program->release();
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
@ -107,20 +107,20 @@ void Renderer::render(QSurface *surface, const QColor &color, const QSize &viewS
void Renderer::paintQtLogo()
{
program.enableAttributeArray(normalAttr);
program.enableAttributeArray(vertexAttr);
program.setAttributeArray(vertexAttr, vertices.constData());
program.setAttributeArray(normalAttr, normals.constData());
m_program->enableAttributeArray(normalAttr);
m_program->enableAttributeArray(vertexAttr);
m_program->setAttributeArray(vertexAttr, vertices.constData());
m_program->setAttributeArray(normalAttr, normals.constData());
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
program.disableAttributeArray(normalAttr);
program.disableAttributeArray(vertexAttr);
m_program->disableAttributeArray(normalAttr);
m_program->disableAttributeArray(vertexAttr);
}
void Renderer::initialize()
{
glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
QGLShader *vshader = new QGLShader(QGLShader::Vertex, this);
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
const char *vsrc =
"attribute highp vec4 vertex;\n"
"attribute mediump vec3 normal;\n"
@ -138,7 +138,7 @@ void Renderer::initialize()
"}\n";
vshader->compileSourceCode(vsrc);
QGLShader *fshader = new QGLShader(QGLShader::Fragment, this);
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
const char *fsrc =
"varying mediump vec4 color;\n"
"void main(void)\n"
@ -147,14 +147,15 @@ void Renderer::initialize()
"}\n";
fshader->compileSourceCode(fsrc);
program.addShader(vshader);
program.addShader(fshader);
program.link();
m_program = new QOpenGLShaderProgram;
m_program->addShader(vshader);
m_program->addShader(fshader);
m_program->link();
vertexAttr = program.attributeLocation("vertex");
normalAttr = program.attributeLocation("normal");
matrixUniform = program.uniformLocation("matrix");
colorUniform = program.uniformLocation("sourceColor");
vertexAttr = m_program->attributeLocation("vertex");
normalAttr = m_program->attributeLocation("normal");
matrixUniform = m_program->uniformLocation("matrix");
colorUniform = m_program->uniformLocation("sourceColor");
m_fAngle = 0;
createGeometry();

View File

@ -1,12 +1,12 @@
#include <QWindow>
#include <QtOpenGL/qgl.h>
#include <QtOpenGL/qglshaderprogram.h>
#include <QtOpenGL/qglframebufferobject.h>
#include <QtGui/qopengl.h>
#include <QtGui/qopenglshaderprogram.h>
#include <QColor>
#include <QTime>
class QGuiGLContext;
class QOpenGLContext;
class Renderer : public QObject
{
@ -31,7 +31,6 @@ private:
void extrude(qreal x1, qreal y1, qreal x2, qreal y2);
QVector<QVector3D> vertices;
QVector<QVector3D> normals;
QGLShaderProgram program;
int vertexAttr;
int normalAttr;
int matrixUniform;
@ -39,7 +38,8 @@ private:
bool m_initialized;
QSurfaceFormat m_format;
QGuiGLContext *m_context;
QOpenGLContext *m_context;
QOpenGLShaderProgram *m_program;
};
class HelloWindow : public QWindow

View File

@ -6,8 +6,6 @@ TEMPLATE = app
DEPENDPATH += .
INCLUDEPATH += .
QT += opengl widgets
# Input
HEADERS += hellowindow.h
SOURCES += hellowindow.cpp main.cpp

View File

@ -24,6 +24,7 @@ contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2){
qpa {
SUBDIRS += hellowindow
SUBDIRS += paintedwindow
}
# install

View File

@ -0,0 +1,27 @@
#include <QGuiApplication>
#include <QRect>
#include <QScreen>
#include "paintedwindow.h"
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
QScreen *screen = QGuiApplication::primaryScreen();
QRect screenGeometry = screen->availableGeometry();
QSurfaceFormat format;
format.setDepthBufferSize(16);
format.setSamples(4);
QPoint center = screenGeometry.center();
QRect windowRect(0, 0, 640, 480);
PaintedWindow window;
window.setGeometry(QRect(center - windowRect.center(), windowRect.size()));
window.show();
app.exec();
}

View File

@ -0,0 +1,124 @@
#include "paintedwindow.h"
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QPainter>
#include <QTimer>
#include <qmath.h>
PaintedWindow::PaintedWindow()
: m_fbo(0)
{
QSurfaceFormat format;
format.setStencilBufferSize(8);
setSurfaceType(QWindow::OpenGLSurface);
setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
setFormat(format);
create();
m_context = new QOpenGLContext(this);
m_context->setFormat(format);
m_context->create();
QTimer *timer = new QTimer(this);
timer->setInterval(16);
connect(timer, SIGNAL(timeout()), this, SLOT(paint()));
timer->start();
m_context->makeCurrent(this);
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
const char *vsrc =
"attribute highp vec2 vertexCoordsInput;\n"
"attribute mediump vec2 texCoordsInput;\n"
"varying mediump vec2 texCoords;\n"
"void main(void)\n"
"{\n"
" texCoords = texCoordsInput;\n"
" gl_Position = vec4(vertexCoordsInput, 0, 1);\n"
"}\n";
vshader->compileSourceCode(vsrc);
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
const char *fsrc =
"uniform sampler2D tex;\n"
"varying mediump vec2 texCoords;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(tex, texCoords);\n"
"}\n";
fshader->compileSourceCode(fsrc);
m_program = new QOpenGLShaderProgram;
m_program->addShader(vshader);
m_program->addShader(fshader);
m_program->link();
m_vertexAttribute = m_program->attributeLocation("vertexCoordsInput");
m_texCoordsAttribute = m_program->attributeLocation("texCoordsInput");
}
void PaintedWindow::resizeEvent(QResizeEvent *)
{
m_context->makeCurrent(this);
delete m_fbo;
m_fbo = new QOpenGLFramebufferObject(size());
}
void PaintedWindow::paint()
{
if (!m_fbo)
return;
m_context->makeCurrent(this);
QPainterPath path;
path.addEllipse(0, 0, m_fbo->width(), m_fbo->height());
QPainter painter;
painter.begin(m_fbo);
painter.fillRect(0, 0, m_fbo->width(), m_fbo->height(), Qt::white);
painter.setRenderHint(QPainter::Antialiasing);
painter.fillPath(path, Qt::blue);
painter.end();
glViewport(0, 0, width(), height());
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLfloat texCoords[] = { 0, 0, 1, 0, 0, 1,
1, 0, 1, 1, 0, 1 };
GLfloat vertexCoords[] = { -1, -1, 1, -1, -1, 1,
1, -1, 1, 1, -1, 1 };
m_program->bind();
m_context->functions()->glEnableVertexAttribArray(m_vertexAttribute);
m_context->functions()->glEnableVertexAttribArray(m_texCoordsAttribute);
m_context->functions()->glVertexAttribPointer(m_vertexAttribute, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
m_context->functions()->glVertexAttribPointer(m_texCoordsAttribute, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindTexture(GL_TEXTURE_2D, 0);
m_context->functions()->glDisableVertexAttribArray(m_vertexAttribute);
m_context->functions()->glDisableVertexAttribArray(m_texCoordsAttribute);
m_program->release();
m_context->swapBuffers(this);
}

View File

@ -0,0 +1,30 @@
#include <QWindow>
#include <QtGui/qopengl.h>
#include <QtGui/qopenglshaderprogram.h>
#include <QtGui/qopenglframebufferobject.h>
#include <QColor>
#include <QTime>
class QOpenGLContext;
class PaintedWindow : public QWindow
{
Q_OBJECT
public:
PaintedWindow();
private slots:
void paint();
private:
void resizeEvent(QResizeEvent *);
QOpenGLContext *m_context;
QOpenGLFramebufferObject *m_fbo;
QOpenGLShaderProgram *m_program;
GLuint m_vertexAttribute;
GLuint m_texCoordsAttribute;
};

View File

@ -0,0 +1,18 @@
######################################################################
# Automatically generated by qmake (2.01a) Wed Apr 27 16:40:46 2011
######################################################################
TEMPLATE = app
DEPENDPATH += .
INCLUDEPATH += .
# Input
HEADERS += paintedwindow.h
SOURCES += paintedwindow.cpp main.cpp
# install
target.path = $$[QT_INSTALL_EXAMPLES]/qtbase/opengl/paintedwindow
sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS paintedwindow.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/qtbase/opengl/paintedwindow
INSTALLS += target sources

View File

@ -47,7 +47,7 @@
// -------------
//
// This file is not part of the Qt API. It exists for the convenience of
// the QtOpenGL and QtOpenVG modules. This header file may change from
// the QtGui and QtOpenVG modules. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.

View File

@ -94,7 +94,7 @@ void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev)
if (!dev)
return;
// Find the QGLScreen for this paint device.
// Find the QOpenGLScreen for this paint device.
QPlatformScreen *screen = screenForDevice(dev);
if (!screen)
return;

View File

@ -47,7 +47,7 @@
// -------------
//
// This file is not part of the Qt API. It exists for the convenience of
// the QtOpenGL and QtOpenVG modules. This header file may change from
// the QtGui and QtOpenVG modules. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.

View File

@ -47,7 +47,7 @@
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QtOpenGL and QtOpenVG modules. This header file may change from
// of the QtGui and QtOpenVG modules. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.

View File

@ -21,6 +21,7 @@ include(text/text.pri)
include(painting/painting.pri)
include(util/util.pri)
include(math3d/math3d.pri)
include(opengl/opengl.pri)
include(egl/egl.pri)

View File

@ -182,7 +182,7 @@ private:
friend class QBitmap;
friend class QPaintDevice;
friend class QPainter;
friend class QGLWidget;
friend class QOpenGLWidget;
friend class QWidgetPrivate;
friend class QRasterBuffer;
#if !defined(QT_NO_DATASTREAM)

View File

@ -73,7 +73,7 @@ QPlatformPixmap::QPlatformPixmap(PixelType pixelType, int objectId)
QPlatformPixmap::~QPlatformPixmap()
{
// Sometimes the pixmap cleanup hooks will be called from derrived classes, which will
// then set is_cached to false. For example, on X11 QtOpenGL needs to delete the GLXPixmap
// then set is_cached to false. For example, on X11 QtGui needs to delete the GLXPixmap
// or EGL Pixmap Surface for a given pixmap _before_ the native X11 pixmap is deleted,
// otherwise some drivers will leak the GL surface. In this case, QX11PlatformPixmap will
// call the cleanup hooks itself before deleting the native pixmap and set is_cached to

View File

@ -136,7 +136,7 @@ protected:
private:
friend class QPixmap;
friend class QImagePixmapCleanupHooks; // Needs to set is_cached
friend class QGLTextureCache; //Needs to check the reference count
friend class QOpenGLTextureCache; //Needs to check the reference count
friend class QExplicitlySharedDataPointer<QPlatformPixmap>;
QAtomicInt ref;

View File

@ -49,9 +49,9 @@ qpa {
kernel/qplatformintegrationfactory_qpa_p.h \
kernel/qplatformintegrationplugin_qpa.h \
kernel/qplatformwindow_qpa.h \
kernel/qplatformglcontext_qpa.h \
kernel/qguiglcontext_qpa.h \
kernel/qguiglcontext_qpa_p.h \
kernel/qplatformopenglcontext_qpa.h \
kernel/qopenglcontext.h \
kernel/qopenglcontext_p.h \
kernel/qplatformcursor_qpa.h \
kernel/qplatformclipboard_qpa.h \
kernel/qplatformnativeinterface_qpa.h \
@ -73,8 +73,8 @@ qpa {
kernel/qplatformintegrationfactory_qpa.cpp \
kernel/qplatformintegrationplugin_qpa.cpp \
kernel/qplatformwindow_qpa.cpp \
kernel/qplatformglcontext_qpa.cpp \
kernel/qguiglcontext_qpa.cpp \
kernel/qplatformopenglcontext_qpa.cpp \
kernel/qopenglcontext.cpp \
kernel/qplatformcursor_qpa.cpp \
kernel/qplatformclipboard_qpa.cpp \
kernel/qplatformnativeinterface_qpa.cpp \

View File

@ -1,181 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenGL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QGUIGLCONTEXT_P_H
#define QGUIGLCONTEXT_P_H
#include "qguiglcontext_qpa.h"
#include <private/qobject_p.h>
#include <qmutex.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QGuiGLContext;
class QGLMultiGroupSharedResource;
class Q_GUI_EXPORT QGLSharedResource
{
public:
QGLSharedResource(QGuiGLContextGroup *group);
virtual ~QGLSharedResource() = 0;
QGuiGLContextGroup *group() const { return m_group; }
// schedule the resource for deletion at an appropriate time
void free();
protected:
// the resource's share group no longer exists, invalidate the resource
virtual void invalidateResource() = 0;
// a valid context in the group is current, free the resource
virtual void freeResource(QGuiGLContext *context) = 0;
private:
QGuiGLContextGroup *m_group;
friend class QGuiGLContextGroup;
friend class QGuiGLContextGroupPrivate;
Q_DISABLE_COPY(QGLSharedResource);
};
class Q_GUI_EXPORT QGuiGLContextGroupPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QGuiGLContextGroup);
public:
QGuiGLContextGroupPrivate()
: m_context(0)
, m_mutex(QMutex::Recursive)
, m_refs(0)
{
}
void addContext(QGuiGLContext *ctx);
void removeContext(QGuiGLContext *ctx);
void deletePendingResources(QGuiGLContext *ctx);
QGuiGLContext *m_context;
QList<QGuiGLContext *> m_shares;
QMutex m_mutex;
QHash<QGLMultiGroupSharedResource *, QGLSharedResource *> m_resources;
QAtomicInt m_refs;
QList<QGLSharedResource *> m_sharedResources;
QList<QGLSharedResource *> m_pendingDeletion;
void cleanupResources(QGuiGLContext *ctx);
};
class Q_GUI_EXPORT QGLMultiGroupSharedResource
{
public:
QGLMultiGroupSharedResource();
~QGLMultiGroupSharedResource();
void insert(QGuiGLContext *context, QGLSharedResource *value);
void cleanup(QGuiGLContext *context);
void cleanup(QGuiGLContext *context, QGLSharedResource *value);
QGLSharedResource *value(QGuiGLContext *context);
template <typename T>
T *value(QGuiGLContext *context) {
QGuiGLContextGroup *group = context->shareGroup();
T *resource = static_cast<T *>(group->d_func()->m_resources.value(this, 0));
if (!resource) {
resource = new T(context);
insert(context, resource);
}
return resource;
}
private:
QAtomicInt active;
QList<QGuiGLContextGroup *> m_groups;
};
class Q_GUI_EXPORT QGuiGLContextPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QGuiGLContext);
public:
QGuiGLContextPrivate()
: qGLContextHandle(0)
, platformGLContext(0)
, shareContext(0)
, shareGroup(0)
, screen(0)
, surface(0)
{
}
virtual ~QGuiGLContextPrivate()
{
//do not delete the QGLContext handle here as it is deleted in
//QWidgetPrivate::deleteTLSysExtra()
}
void *qGLContextHandle;
void (*qGLContextDeleteFunction)(void *handle);
QSurfaceFormat requestedFormat;
QPlatformGLContext *platformGLContext;
QGuiGLContext *shareContext;
QGuiGLContextGroup *shareGroup;
QScreen *screen;
QSurface *surface;
QHash<QGLMultiGroupSharedResource *, void *> m_resources;
static void setCurrentContext(QGuiGLContext *context);
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QGUIGLCONTEXT_P_H

View File

@ -4,7 +4,7 @@
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenGL module of the Qt Toolkit.
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
@ -39,9 +39,9 @@
**
****************************************************************************/
#include "qplatformglcontext_qpa.h"
#include "qguiglcontext_qpa.h"
#include "qguiglcontext_qpa_p.h"
#include "qplatformopenglcontext_qpa.h"
#include "qopenglcontext.h"
#include "qopenglcontext_p.h"
#include "qwindow.h"
#include <QtCore/QThreadStorage>
@ -50,6 +50,8 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/QScreen>
#include <private/qopenglextensions_p.h>
#include <QDebug>
class QGuiGLThreadContext
@ -59,12 +61,12 @@ public:
if (context)
context->doneCurrent();
}
QGuiGLContext *context;
QOpenGLContext *context;
};
static QThreadStorage<QGuiGLThreadContext *> qwindow_context_storage;
void QGuiGLContextPrivate::setCurrentContext(QGuiGLContext *context)
void QOpenGLContextPrivate::setCurrentContext(QOpenGLContext *context)
{
QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
if (!threadContext) {
@ -81,7 +83,7 @@ void QGuiGLContextPrivate::setCurrentContext(QGuiGLContext *context)
/*!
Returns the last context which called makeCurrent. This function is thread aware.
*/
QGuiGLContext* QGuiGLContext::currentContext()
QOpenGLContext* QOpenGLContext::currentContext()
{
QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
if(threadContext) {
@ -90,20 +92,20 @@ QGuiGLContext* QGuiGLContext::currentContext()
return 0;
}
bool QGuiGLContext::areSharing(QGuiGLContext *first, QGuiGLContext *second)
bool QOpenGLContext::areSharing(QOpenGLContext *first, QOpenGLContext *second)
{
return first->shareGroup() == second->shareGroup();
}
QPlatformGLContext *QGuiGLContext::handle() const
QPlatformOpenGLContext *QOpenGLContext::handle() const
{
Q_D(const QGuiGLContext);
Q_D(const QOpenGLContext);
return d->platformGLContext;
}
QPlatformGLContext *QGuiGLContext::shareHandle() const
QPlatformOpenGLContext *QOpenGLContext::shareHandle() const
{
Q_D(const QGuiGLContext);
Q_D(const QOpenGLContext);
if (d->shareContext)
return d->shareContext->handle();
return 0;
@ -112,37 +114,37 @@ QPlatformGLContext *QGuiGLContext::shareHandle() const
/*!
Creates a new GL context instance, you need to call create() before it can be used.
*/
QGuiGLContext::QGuiGLContext()
: QObject(*new QGuiGLContextPrivate())
QOpenGLContext::QOpenGLContext(QObject *parent)
: QObject(*new QOpenGLContextPrivate(), parent)
{
Q_D(QGuiGLContext);
Q_D(QOpenGLContext);
d->screen = QGuiApplication::primaryScreen();
}
/*!
Sets the format the GL context should be compatible with. You need to call create() before it takes effect.
*/
void QGuiGLContext::setFormat(const QSurfaceFormat &format)
void QOpenGLContext::setFormat(const QSurfaceFormat &format)
{
Q_D(QGuiGLContext);
Q_D(QOpenGLContext);
d->requestedFormat = format;
}
/*!
Sets the context to share textures, shaders, and other GL resources with. You need to call create() before it takes effect.
*/
void QGuiGLContext::setShareContext(QGuiGLContext *shareContext)
void QOpenGLContext::setShareContext(QOpenGLContext *shareContext)
{
Q_D(QGuiGLContext);
Q_D(QOpenGLContext);
d->shareContext = shareContext;
}
/*!
Sets the screen the GL context should be valid for. You need to call create() before it takes effect.
*/
void QGuiGLContext::setScreen(QScreen *screen)
void QOpenGLContext::setScreen(QScreen *screen)
{
Q_D(QGuiGLContext);
Q_D(QOpenGLContext);
d->screen = screen;
if (!d->screen)
d->screen = QGuiApplication::primaryScreen();
@ -153,34 +155,36 @@ void QGuiGLContext::setScreen(QScreen *screen)
Returns true if the native context was successfully created and is ready to be used.
*/
bool QGuiGLContext::create()
bool QOpenGLContext::create()
{
destroy();
Q_D(QGuiGLContext);
d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformGLContext(this);
Q_D(QOpenGLContext);
d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformOpenGLContext(this);
d->platformGLContext->setContext(this);
d->shareGroup = d->shareContext ? d->shareContext->shareGroup() : new QGuiGLContextGroup;
d->shareGroup = d->shareContext ? d->shareContext->shareGroup() : new QOpenGLContextGroup;
d->shareGroup->d_func()->addContext(this);
return d->platformGLContext;
}
void QGuiGLContext::destroy()
void QOpenGLContext::destroy()
{
Q_D(QGuiGLContext);
if (QGuiGLContext::currentContext() == this)
Q_D(QOpenGLContext);
if (QOpenGLContext::currentContext() == this)
doneCurrent();
if (d->shareGroup)
d->shareGroup->d_func()->removeContext(this);
d->shareGroup = 0;
delete d->platformGLContext;
d->platformGLContext = 0;
delete d->functions;
d->functions = 0;
}
/*!
If this is the current context for the thread, doneCurrent is called
*/
QGuiGLContext::~QGuiGLContext()
QOpenGLContext::~QOpenGLContext()
{
destroy();
}
@ -188,18 +192,32 @@ QGuiGLContext::~QGuiGLContext()
/*!
Returns if this context is valid, i.e. has been successfully created.
*/
bool QGuiGLContext::isValid() const
bool QOpenGLContext::isValid() const
{
Q_D(const QGuiGLContext);
Q_D(const QOpenGLContext);
return d->platformGLContext != 0;
}
/*!
Get the QOpenGLFunctions instance for this context.
The context or a sharing context must be current.
*/
QOpenGLFunctions *QOpenGLContext::functions() const
{
Q_D(const QOpenGLContext);
if (!d->functions)
const_cast<QOpenGLFunctions *&>(d->functions) = new QOpenGLExtensions(QOpenGLContext::currentContext());
return d->functions;
}
/*!
If surface is 0 this is equivalent to calling doneCurrent().
*/
bool QGuiGLContext::makeCurrent(QSurface *surface)
bool QOpenGLContext::makeCurrent(QSurface *surface)
{
Q_D(QGuiGLContext);
Q_D(QOpenGLContext);
if (!d->platformGLContext)
return false;
@ -212,7 +230,7 @@ bool QGuiGLContext::makeCurrent(QSurface *surface)
return false;
if (d->platformGLContext->makeCurrent(surface->surfaceHandle())) {
QGuiGLContextPrivate::setCurrentContext(this);
QOpenGLContextPrivate::setCurrentContext(this);
d->surface = surface;
d->shareGroup->d_func()->deletePendingResources(this);
@ -226,17 +244,17 @@ bool QGuiGLContext::makeCurrent(QSurface *surface)
/*!
Convenience function for calling makeCurrent with a 0 surface.
*/
void QGuiGLContext::doneCurrent()
void QOpenGLContext::doneCurrent()
{
Q_D(QGuiGLContext);
Q_D(QOpenGLContext);
if (!d->platformGLContext)
return;
if (QGuiGLContext::currentContext() == this)
if (QOpenGLContext::currentContext() == this)
d->shareGroup->d_func()->deletePendingResources(this);
d->platformGLContext->doneCurrent();
QGuiGLContextPrivate::setCurrentContext(0);
QOpenGLContextPrivate::setCurrentContext(0);
d->surface = 0;
}
@ -244,58 +262,58 @@ void QGuiGLContext::doneCurrent()
/*!
Returns the surface the context is current for.
*/
QSurface *QGuiGLContext::surface() const
QSurface *QOpenGLContext::surface() const
{
Q_D(const QGuiGLContext);
Q_D(const QOpenGLContext);
return d->surface;
}
void QGuiGLContext::swapBuffers(QSurface *surface)
void QOpenGLContext::swapBuffers(QSurface *surface)
{
Q_D(QGuiGLContext);
Q_D(QOpenGLContext);
if (!d->platformGLContext)
return;
if (!surface) {
qWarning() << "QGuiGLContext::swapBuffers() called with null argument";
qWarning() << "QOpenGLContext::swapBuffers() called with null argument";
return;
}
d->platformGLContext->swapBuffers(surface->surfaceHandle());
}
void (*QGuiGLContext::getProcAddress(const QByteArray &procName)) ()
void (*QOpenGLContext::getProcAddress(const QByteArray &procName)) ()
{
Q_D(QGuiGLContext);
Q_D(QOpenGLContext);
if (!d->platformGLContext)
return 0;
return d->platformGLContext->getProcAddress(procName);
}
QSurfaceFormat QGuiGLContext::format() const
QSurfaceFormat QOpenGLContext::format() const
{
Q_D(const QGuiGLContext);
Q_D(const QOpenGLContext);
if (!d->platformGLContext)
return d->requestedFormat;
return d->platformGLContext->format();
}
QGuiGLContextGroup *QGuiGLContext::shareGroup() const
QOpenGLContextGroup *QOpenGLContext::shareGroup() const
{
Q_D(const QGuiGLContext);
Q_D(const QOpenGLContext);
return d->shareGroup;
}
QGuiGLContext *QGuiGLContext::shareContext() const
QOpenGLContext *QOpenGLContext::shareContext() const
{
Q_D(const QGuiGLContext);
Q_D(const QOpenGLContext);
return d->shareContext;
}
QScreen *QGuiGLContext::screen() const
QScreen *QOpenGLContext::screen() const
{
Q_D(const QGuiGLContext);
Q_D(const QOpenGLContext);
return d->screen;
}
@ -303,22 +321,22 @@ QScreen *QGuiGLContext::screen() const
internal: Needs to have a pointer to qGLContext. But since this is in QtGui we cant
have any type information.
*/
void *QGuiGLContext::qGLContextHandle() const
void *QOpenGLContext::qGLContextHandle() const
{
Q_D(const QGuiGLContext);
Q_D(const QOpenGLContext);
return d->qGLContextHandle;
}
void QGuiGLContext::setQGLContextHandle(void *handle,void (*qGLContextDeleteFunction)(void *))
void QOpenGLContext::setQGLContextHandle(void *handle,void (*qGLContextDeleteFunction)(void *))
{
Q_D(QGuiGLContext);
Q_D(QOpenGLContext);
d->qGLContextHandle = handle;
d->qGLContextDeleteFunction = qGLContextDeleteFunction;
}
void QGuiGLContext::deleteQGLContext()
void QOpenGLContext::deleteQGLContext()
{
Q_D(QGuiGLContext);
Q_D(QOpenGLContext);
if (d->qGLContextDeleteFunction && d->qGLContextHandle) {
d->qGLContextDeleteFunction(d->qGLContextHandle);
d->qGLContextDeleteFunction = 0;
@ -326,17 +344,17 @@ void QGuiGLContext::deleteQGLContext()
}
}
QGuiGLContextGroup::QGuiGLContextGroup()
: QObject(*new QGuiGLContextGroupPrivate())
QOpenGLContextGroup::QOpenGLContextGroup()
: QObject(*new QOpenGLContextGroupPrivate())
{
}
QGuiGLContextGroup::~QGuiGLContextGroup()
QOpenGLContextGroup::~QOpenGLContextGroup()
{
Q_D(QGuiGLContextGroup);
Q_D(QOpenGLContextGroup);
QList<QGLSharedResource *>::iterator it = d->m_sharedResources.begin();
QList<QGLSharedResource *>::iterator end = d->m_sharedResources.end();
QList<QOpenGLSharedResource *>::iterator it = d->m_sharedResources.begin();
QList<QOpenGLSharedResource *>::iterator end = d->m_sharedResources.end();
while (it != end) {
(*it)->invalidateResource();
@ -347,28 +365,28 @@ QGuiGLContextGroup::~QGuiGLContextGroup()
qDeleteAll(d->m_pendingDeletion.begin(), d->m_pendingDeletion.end());
}
QList<QGuiGLContext *> QGuiGLContextGroup::shares() const
QList<QOpenGLContext *> QOpenGLContextGroup::shares() const
{
Q_D(const QGuiGLContextGroup);
Q_D(const QOpenGLContextGroup);
return d->m_shares;
}
QGuiGLContextGroup *QGuiGLContextGroup::currentContextGroup()
QOpenGLContextGroup *QOpenGLContextGroup::currentContextGroup()
{
QGuiGLContext *current = QGuiGLContext::currentContext();
QOpenGLContext *current = QOpenGLContext::currentContext();
return current ? current->shareGroup() : 0;
}
void QGuiGLContextGroupPrivate::addContext(QGuiGLContext *ctx)
void QOpenGLContextGroupPrivate::addContext(QOpenGLContext *ctx)
{
QMutexLocker locker(&m_mutex);
m_refs.ref();
m_shares << ctx;
}
void QGuiGLContextGroupPrivate::removeContext(QGuiGLContext *ctx)
void QOpenGLContextGroupPrivate::removeContext(QOpenGLContext *ctx)
{
Q_Q(QGuiGLContextGroup);
Q_Q(QOpenGLContextGroup);
QMutexLocker locker(&m_mutex);
m_shares.removeOne(ctx);
@ -380,33 +398,35 @@ void QGuiGLContextGroupPrivate::removeContext(QGuiGLContext *ctx)
q->deleteLater();
}
void QGuiGLContextGroupPrivate::deletePendingResources(QGuiGLContext *ctx)
void QOpenGLContextGroupPrivate::deletePendingResources(QOpenGLContext *ctx)
{
QMutexLocker locker(&m_mutex);
QList<QGLSharedResource *>::iterator it = m_pendingDeletion.begin();
QList<QGLSharedResource *>::iterator end = m_pendingDeletion.end();
QList<QOpenGLSharedResource *> pending = m_pendingDeletion;
m_pendingDeletion.clear();
QList<QOpenGLSharedResource *>::iterator it = pending.begin();
QList<QOpenGLSharedResource *>::iterator end = pending.end();
while (it != end) {
(*it)->freeResource(ctx);
delete *it;
++it;
}
m_pendingDeletion.clear();
}
QGLSharedResource::QGLSharedResource(QGuiGLContextGroup *group)
QOpenGLSharedResource::QOpenGLSharedResource(QOpenGLContextGroup *group)
: m_group(group)
{
QMutexLocker locker(&m_group->d_func()->m_mutex);
m_group->d_func()->m_sharedResources << this;
}
QGLSharedResource::~QGLSharedResource()
QOpenGLSharedResource::~QOpenGLSharedResource()
{
}
// schedule the resource for deletion at an appropriate time
void QGLSharedResource::free()
void QOpenGLSharedResource::free()
{
if (!m_group) {
delete this;
@ -418,13 +438,22 @@ void QGLSharedResource::free()
m_group->d_func()->m_pendingDeletion << this;
// can we delete right away?
QGuiGLContext *current = QGuiGLContext::currentContext();
QOpenGLContext *current = QOpenGLContext::currentContext();
if (current && current->shareGroup() == m_group) {
m_group->d_func()->deletePendingResources(current);
}
}
QGLMultiGroupSharedResource::QGLMultiGroupSharedResource()
void QOpenGLSharedResourceGuard::freeResource(QOpenGLContext *context)
{
if (m_id) {
QOpenGLFunctions functions(context);
m_func(&functions, m_id);
m_id = 0;
}
}
QOpenGLMultiGroupSharedResource::QOpenGLMultiGroupSharedResource()
: active(0)
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
@ -432,61 +461,63 @@ QGLMultiGroupSharedResource::QGLMultiGroupSharedResource()
#endif
}
QGLMultiGroupSharedResource::~QGLMultiGroupSharedResource()
QOpenGLMultiGroupSharedResource::~QOpenGLMultiGroupSharedResource()
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size());
#endif
for (int i = 0; i < m_groups.size(); ++i) {
QGuiGLContext *context = m_groups.at(i)->shares().first();
QGLSharedResource *resource = value(context);
if (resource)
resource->free();
if (!m_groups.at(i)->shares().isEmpty()) {
QOpenGLContext *context = m_groups.at(i)->shares().first();
QOpenGLSharedResource *resource = value(context);
if (resource)
resource->free();
}
m_groups.at(i)->d_func()->m_resources.remove(this);
active.deref();
}
#ifndef QT_NO_DEBUG
if (active != 0) {
qWarning("QtOpenGL: Resources are still available at program shutdown.\n"
" This is possibly caused by a leaked QGLWidget, \n"
" QGLFramebufferObject or QGLPixelBuffer.");
qWarning("QtGui: Resources are still available at program shutdown.\n"
" This is possibly caused by a leaked QOpenGLWidget, \n"
" QOpenGLFramebufferObject or QOpenGLPixelBuffer.");
}
#endif
}
void QGLMultiGroupSharedResource::insert(QGuiGLContext *context, QGLSharedResource *value)
void QOpenGLMultiGroupSharedResource::insert(QOpenGLContext *context, QOpenGLSharedResource *value)
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this);
#endif
QGuiGLContextGroup *group = context->shareGroup();
QOpenGLContextGroup *group = context->shareGroup();
Q_ASSERT(!group->d_func()->m_resources.contains(this));
group->d_func()->m_resources.insert(this, value);
m_groups.append(group);
active.ref();
}
QGLSharedResource *QGLMultiGroupSharedResource::value(QGuiGLContext *context)
QOpenGLSharedResource *QOpenGLMultiGroupSharedResource::value(QOpenGLContext *context)
{
QGuiGLContextGroup *group = context->shareGroup();
QOpenGLContextGroup *group = context->shareGroup();
return group->d_func()->m_resources.value(this, 0);
}
void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx)
void QOpenGLMultiGroupSharedResource::cleanup(QOpenGLContext *ctx)
{
QGLSharedResource *resource = value(ctx);
QOpenGLSharedResource *resource = value(ctx);
if (resource != 0) {
resource->free();
QGuiGLContextGroup *group = ctx->shareGroup();
QOpenGLContextGroup *group = ctx->shareGroup();
group->d_func()->m_resources.remove(this);
m_groups.removeOne(group);
active.deref();
}
}
void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx, QGLSharedResource *value)
void QOpenGLMultiGroupSharedResource::cleanup(QOpenGLContext *ctx, QOpenGLSharedResource *value)
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Cleaning up context group resource %p, for context %p in thread %p.", this, ctx, QThread::currentThread());
@ -494,7 +525,7 @@ void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx, QGLSharedResource
value->free();
active.deref();
QGuiGLContextGroup *group = ctx->shareGroup();
QOpenGLContextGroup *group = ctx->shareGroup();
m_groups.removeOne(group);
}

View File

@ -4,7 +4,7 @@
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenGL module of the Qt Toolkit.
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
@ -39,13 +39,13 @@
**
****************************************************************************/
#ifndef QGUIGLCONTEXT_H
#define QGUIGLCONTEXT_H
#ifndef QOPENGLCONTEXT_H
#define QOPENGLCONTEXT_H
#include <QtCore/qnamespace.h>
#include <QtCore/QScopedPointer>
#include <QSurfaceFormat>
#include <QtGui/QSurfaceFormat>
QT_BEGIN_HEADER
@ -53,49 +53,52 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QGuiGLContextPrivate;
class QGuiGLContextGroupPrivate;
class QPlatformGLContext;
class QOpenGLContextPrivate;
class QOpenGLContextGroupPrivate;
class QOpenGLFunctions;
class QPlatformOpenGLContext;
class QScreen;
class QSurface;
class Q_GUI_EXPORT QGuiGLContextGroup : public QObject
class Q_GUI_EXPORT QOpenGLContextGroup : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QGuiGLContextGroup)
Q_DECLARE_PRIVATE(QOpenGLContextGroup)
public:
~QGuiGLContextGroup();
~QOpenGLContextGroup();
QList<QGuiGLContext *> shares() const;
QList<QOpenGLContext *> shares() const;
static QGuiGLContextGroup *currentContextGroup();
static QOpenGLContextGroup *currentContextGroup();
private:
QGuiGLContextGroup();
QOpenGLContextGroup();
friend class QGuiGLContext;
friend class QGLContextGroupResourceBase;
friend class QGLSharedResource;
friend class QGLMultiGroupSharedResource;
friend class QOpenGLContext;
friend class QOpenGLContextGroupResourceBase;
friend class QOpenGLSharedResource;
friend class QOpenGLMultiGroupSharedResource;
};
class Q_GUI_EXPORT QGuiGLContext : public QObject
class Q_GUI_EXPORT QOpenGLContext : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QGuiGLContext);
Q_DECLARE_PRIVATE(QOpenGLContext);
public:
QGuiGLContext();
~QGuiGLContext();
QOpenGLContext(QObject *parent = 0);
~QOpenGLContext();
void setFormat(const QSurfaceFormat &format);
void setShareContext(QGuiGLContext *shareContext);
void setShareContext(QOpenGLContext *shareContext);
void setScreen(QScreen *screen);
bool create();
bool isValid() const;
QSurfaceFormat format() const;
QGuiGLContext *shareContext() const;
QGuiGLContextGroup *shareGroup() const;
QOpenGLContext *shareContext() const;
QOpenGLContextGroup *shareGroup() const;
QScreen *screen() const;
bool makeCurrent(QSurface *surface);
@ -106,16 +109,26 @@ public:
QSurface *surface() const;
static QGuiGLContext *currentContext();
static bool areSharing(QGuiGLContext *first, QGuiGLContext *second);
static QOpenGLContext *currentContext();
static bool areSharing(QOpenGLContext *first, QOpenGLContext *second);
QPlatformGLContext *handle() const;
QPlatformGLContext *shareHandle() const;
QPlatformOpenGLContext *handle() const;
QPlatformOpenGLContext *shareHandle() const;
QOpenGLFunctions *functions() const;
private:
//hack to make it work with QGLContext::CurrentContext
friend class QGLContext;
friend class QGLContextResourceBase;
friend class QOpenGLContextResourceBase;
friend class QOpenGLPaintDevice;
friend class QOpenGLGlyphTexture;
friend class QOpenGLTextureGlyphCache;
friend class QOpenGLEngineShaderManager;
friend class QOpenGLFramebufferObject;
friend class QOpenGLFramebufferObjectPrivate;
friend class QOpenGL2PaintEngineEx;
friend class QOpenGL2PaintEngineExPrivate;
friend class QSGDistanceFieldGlyphCache;
friend class QWidgetPrivate;
void *qGLContextHandle() const;

View File

@ -0,0 +1,230 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QGUIGLCONTEXT_P_H
#define QGUIGLCONTEXT_P_H
#include "qopengl.h"
#include "qopenglcontext.h"
#include <private/qobject_p.h>
#include <qmutex.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QOpenGLFunctions;
class QOpenGLContext;
class QOpenGLMultiGroupSharedResource;
class Q_GUI_EXPORT QOpenGLSharedResource
{
public:
QOpenGLSharedResource(QOpenGLContextGroup *group);
virtual ~QOpenGLSharedResource() = 0;
QOpenGLContextGroup *group() const { return m_group; }
// schedule the resource for deletion at an appropriate time
void free();
protected:
// the resource's share group no longer exists, invalidate the resource
virtual void invalidateResource() = 0;
// a valid context in the group is current, free the resource
virtual void freeResource(QOpenGLContext *context) = 0;
private:
QOpenGLContextGroup *m_group;
friend class QOpenGLContextGroup;
friend class QOpenGLContextGroupPrivate;
Q_DISABLE_COPY(QOpenGLSharedResource);
};
class Q_GUI_EXPORT QOpenGLSharedResourceGuard : public QOpenGLSharedResource
{
public:
typedef void (*FreeResourceFunc)(QOpenGLFunctions *functions, GLuint id);
QOpenGLSharedResourceGuard(QOpenGLContext *context, GLuint id, FreeResourceFunc func)
: QOpenGLSharedResource(context->shareGroup())
, m_id(id)
, m_func(func)
{
}
GLuint id() const { return m_id; }
protected:
void invalidateResource()
{
m_id = 0;
}
void freeResource(QOpenGLContext *context);
private:
GLuint m_id;
FreeResourceFunc m_func;
};
class Q_GUI_EXPORT QOpenGLContextGroupPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QOpenGLContextGroup);
public:
QOpenGLContextGroupPrivate()
: m_context(0)
, m_mutex(QMutex::Recursive)
, m_refs(0)
{
}
void addContext(QOpenGLContext *ctx);
void removeContext(QOpenGLContext *ctx);
void deletePendingResources(QOpenGLContext *ctx);
QOpenGLContext *m_context;
QList<QOpenGLContext *> m_shares;
QMutex m_mutex;
QHash<QOpenGLMultiGroupSharedResource *, QOpenGLSharedResource *> m_resources;
QAtomicInt m_refs;
QList<QOpenGLSharedResource *> m_sharedResources;
QList<QOpenGLSharedResource *> m_pendingDeletion;
void cleanupResources(QOpenGLContext *ctx);
};
class Q_GUI_EXPORT QOpenGLMultiGroupSharedResource
{
public:
QOpenGLMultiGroupSharedResource();
~QOpenGLMultiGroupSharedResource();
void insert(QOpenGLContext *context, QOpenGLSharedResource *value);
void cleanup(QOpenGLContext *context);
void cleanup(QOpenGLContext *context, QOpenGLSharedResource *value);
QOpenGLSharedResource *value(QOpenGLContext *context);
template <typename T>
T *value(QOpenGLContext *context) {
QOpenGLContextGroup *group = context->shareGroup();
T *resource = static_cast<T *>(group->d_func()->m_resources.value(this, 0));
if (!resource) {
resource = new T(context);
insert(context, resource);
}
return resource;
}
private:
QAtomicInt active;
QList<QOpenGLContextGroup *> m_groups;
};
class QPaintEngineEx;
class QOpenGLFunctions;
class Q_GUI_EXPORT QOpenGLContextPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QOpenGLContext);
public:
QOpenGLContextPrivate()
: qGLContextHandle(0)
, platformGLContext(0)
, shareContext(0)
, shareGroup(0)
, screen(0)
, surface(0)
, functions(0)
, current_fbo(0)
, default_fbo(0)
, workaround_brokenFBOReadBack(false)
, workaround_brokenTexSubImage(false)
, active_engine(0)
{
}
virtual ~QOpenGLContextPrivate()
{
//do not delete the QOpenGLContext handle here as it is deleted in
//QWidgetPrivate::deleteTLSysExtra()
}
void *qGLContextHandle;
void (*qGLContextDeleteFunction)(void *handle);
QSurfaceFormat requestedFormat;
QPlatformOpenGLContext *platformGLContext;
QOpenGLContext *shareContext;
QOpenGLContextGroup *shareGroup;
QScreen *screen;
QSurface *surface;
QOpenGLFunctions *functions;
GLuint current_fbo;
GLuint default_fbo;
bool workaround_brokenFBOReadBack;
bool workaround_brokenTexSubImage;
QPaintEngineEx *active_engine;
QHash<QOpenGLMultiGroupSharedResource *, void *> m_resources;
static void setCurrentContext(QOpenGLContext *context);
int maxTextureSize() const { return 1024; }
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QGUIGLCONTEXT_P_H

View File

@ -192,10 +192,10 @@ QPlatformPixmap *QPlatformIntegration::createPlatformPixmap(QPlatformPixmap::Pix
return new QRasterPlatformPixmap(type);
}
QPlatformGLContext *QPlatformIntegration::createPlatformGLContext(QGuiGLContext *context) const
QPlatformOpenGLContext *QPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
Q_UNUSED(context);
qWarning("This plugin does not support createPlatformGLContext!");
qWarning("This plugin does not support createPlatformOpenGLContext!");
return 0;
}

View File

@ -59,7 +59,7 @@ class QPlatformFontDatabase;
class QPlatformClipboard;
class QPlatformNativeInterface;
class QPlatformDrag;
class QPlatformGLContext;
class QPlatformOpenGLContext;
class QGuiGLFormat;
class QAbstractEventDispatcher;
class QPlatformInputContext;
@ -80,7 +80,7 @@ public:
virtual QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const;
virtual QPlatformWindow *createPlatformWindow(QWindow *window) const = 0;
virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const = 0;
virtual QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const;
virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
// Event dispatcher:
virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const = 0;

View File

@ -50,7 +50,7 @@ void *QPlatformNativeInterface::nativeResourceForWindow(const QByteArray &resour
return 0;
}
void *QPlatformNativeInterface::nativeResourceForContext(const QByteArray &resource, QGuiGLContext *context)
void *QPlatformNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
{
Q_UNUSED(resource);
Q_UNUSED(context);

View File

@ -50,14 +50,14 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QGuiGLContext;
class QOpenGLContext;
class QWindow;
class QBackingStore;
class Q_GUI_EXPORT QPlatformNativeInterface
{
public:
virtual void *nativeResourceForContext(const QByteArray &resource, QGuiGLContext *context);
virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context);
virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window);
virtual void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *backingStore);
};

View File

@ -4,7 +4,7 @@
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenGL module of the Qt Toolkit.
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
@ -39,73 +39,73 @@
**
****************************************************************************/
#include "qplatformglcontext_qpa.h"
#include "qplatformopenglcontext_qpa.h"
/*!
\class QPlatformGLContext
\class QPlatformOpenGLContext
\since 4.8
\internal
\preliminary
\ingroup qpa
\brief The QPlatformGLContext class provides an abstraction for native GL contexts.
\brief The QPlatformOpenGLContext class provides an abstraction for native GL contexts.
In QPA the way to support OpenGL or OpenVG or other technologies that requires a native GL
context is through the QPlatformGLContext wrapper.
context is through the QPlatformOpenGLContext wrapper.
There is no factory function for QPlatformGLContexts, but rather only one accessor function.
The only place to retrieve a QPlatformGLContext from is through a QPlatformWindow.
There is no factory function for QPlatformOpenGLContexts, but rather only one accessor function.
The only place to retrieve a QPlatformOpenGLContext from is through a QPlatformWindow.
The context which is current for a specific thread can be collected by the currentContext()
function. This is how QPlatformGLContext also makes it possible to use the QtOpenGL module
withhout using QGLWidget. When using QGLContext::currentContext(), it will ask
QPlatformGLContext for the currentContext. Then a corresponding QGLContext will be returned,
which maps to the QPlatformGLContext.
function. This is how QPlatformOpenGLContext also makes it possible to use the QtGui module
withhout using QOpenGLWidget. When using QOpenGLContext::currentContext(), it will ask
QPlatformOpenGLContext for the currentContext. Then a corresponding QOpenGLContext will be returned,
which maps to the QPlatformOpenGLContext.
*/
/*! \fn void QPlatformGLContext::swapBuffers()
/*! \fn void QPlatformOpenGLContext::swapBuffers()
Reimplement in subclass to native swap buffers calls
The implementation must support being called in a thread different than the gui-thread.
*/
/*! \fn void *QPlatformGLContext::getProcAddress(const QString &procName)
/*! \fn void *QPlatformOpenGLContext::getProcAddress(const QString &procName)
Reimplement in subclass to native getProcAddr calls.
Note: its convenient to use qPrintable(const QString &str) to get the const char * pointer
*/
/*! \fn QPlatformWindowFormat QPlatformGLContext::platformWindowFormat() const
/*! \fn QPlatformWindowFormat QPlatformOpenGLContext::platformWindowFormat() const
QWidget has the function qplatformWindowFormat(). That function is for the application
programmer to request the format of the window and the context that he wants.
Reimplement this function in a subclass to indicate what format the glContext actually has.
*/
struct QPlatformGLContextPrivate
struct QPlatformOpenGLContextPrivate
{
QGuiGLContext *context;
QOpenGLContext *context;
};
QPlatformGLContext::QPlatformGLContext()
: d_ptr(new QPlatformGLContextPrivate)
QPlatformOpenGLContext::QPlatformOpenGLContext()
: d_ptr(new QPlatformOpenGLContextPrivate)
{
Q_D(QPlatformGLContext);
Q_D(QPlatformOpenGLContext);
d->context = 0;
}
QPlatformGLContext::~QPlatformGLContext()
QPlatformOpenGLContext::~QPlatformOpenGLContext()
{
}
QGuiGLContext *QPlatformGLContext::context() const
QOpenGLContext *QPlatformOpenGLContext::context() const
{
Q_D(const QPlatformGLContext);
Q_D(const QPlatformOpenGLContext);
return d->context;
}
void QPlatformGLContext::setContext(QGuiGLContext *context)
void QPlatformOpenGLContext::setContext(QOpenGLContext *context)
{
Q_D(QPlatformGLContext);
Q_D(QPlatformOpenGLContext);
d->context = context;
}

View File

@ -4,7 +4,7 @@
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenGL module of the Qt Toolkit.
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
@ -67,14 +67,14 @@ private:
friend class QPlatformWindow;
};
class QPlatformGLContextPrivate;
class QPlatformOpenGLContextPrivate;
class Q_GUI_EXPORT QPlatformGLContext
class Q_GUI_EXPORT QPlatformOpenGLContext
{
Q_DECLARE_PRIVATE(QPlatformGLContext)
Q_DECLARE_PRIVATE(QPlatformOpenGLContext)
public:
QPlatformGLContext();
virtual ~QPlatformGLContext();
QPlatformOpenGLContext();
virtual ~QPlatformOpenGLContext();
virtual QSurfaceFormat format() const = 0;
@ -85,16 +85,16 @@ public:
virtual void (*getProcAddress(const QByteArray &procName)) () = 0;
QGuiGLContext *context() const;
QOpenGLContext *context() const;
private:
friend class QGuiGLContext;
friend class QOpenGLContext;
QScopedPointer<QPlatformGLContextPrivate> d_ptr;
QScopedPointer<QPlatformOpenGLContextPrivate> d_ptr;
void setContext(QGuiGLContext *context);
void setContext(QOpenGLContext *context);
Q_DISABLE_COPY(QPlatformGLContext)
Q_DISABLE_COPY(QPlatformOpenGLContext)
};
QT_END_NAMESPACE

View File

@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QPlatformBackingStore;
class QPlatformGLContext;
class QPlatformOpenGLContext;
class QPlatformScreenPrivate;
class QPlatformWindow;
class QScreen;

View File

@ -260,7 +260,7 @@ bool QPlatformWindow::setMouseGrabEnabled(bool grab)
However, it is not concerned with how Qt renders into the window it represents.
Visible QWindows will always have a QPlatformWindow. However, it is not necessary for
all windows to have a QWindowSurface. This is the case for QGLWidget. And could be the case for
all windows to have a QWindowSurface. This is the case for QOpenGLWidget. And could be the case for
windows where some 3.party renders into it.
The platform specific window handle can be retrieved by the winId function.
@ -268,7 +268,7 @@ bool QPlatformWindow::setMouseGrabEnabled(bool grab)
QPlatformWindow is also the way QPA defines how native child windows should be supported
through the setParent function.
The only way to retrieve a QPlatformGLContext in QPA is by calling the glContext() function
The only way to retrieve a QPlatformOpenGLContext in QPA is by calling the glContext() function
on QPlatformWindow.
\sa QWindowSurface, QWindow

View File

@ -47,7 +47,7 @@
#include <QtCore/qstring.h>
#include <QtGui/qwindowdefs.h>
#include <QtGui/qwindow.h>
#include <QtGui/qplatformglcontext_qpa.h>
#include <QtGui/qplatformopenglcontext_qpa.h>
QT_BEGIN_HEADER

View File

@ -44,6 +44,14 @@
#include <QtCore/qatomic.h>
#include <QtCore/QDebug>
#ifdef major
#undef major
#endif
#ifdef minor
#undef minor
#endif
class QSurfaceFormatPrivate
{
public:
@ -59,6 +67,8 @@ public:
, swapBehavior(QSurfaceFormat::DefaultSwapBehavior)
, numSamples(-1)
, profile(QSurfaceFormat::NoProfile)
, major(1)
, minor(1)
{
}
@ -73,7 +83,9 @@ public:
stencilSize(other->stencilSize),
swapBehavior(other->swapBehavior),
numSamples(other->numSamples),
profile(other->profile)
profile(other->profile),
major(other->major),
minor(other->minor)
{
}
@ -88,6 +100,8 @@ public:
QSurfaceFormat::SwapBehavior swapBehavior;
int numSamples;
QSurfaceFormat::OpenGLContextProfile profile;
int major;
int minor;
};
QSurfaceFormat::QSurfaceFormat() : d(new QSurfaceFormatPrivate)
@ -351,6 +365,12 @@ void QSurfaceFormat::setAlphaBufferSize(int size)
}
}
/*!
Sets the desired OpenGL context profile.
This setting is ignored if the requested OpenGL version is
less than 3.2.
*/
void QSurfaceFormat::setProfile(OpenGLContextProfile profile)
{
if (d->profile != profile) {
@ -364,6 +384,38 @@ QSurfaceFormat::OpenGLContextProfile QSurfaceFormat::profile() const
return d->profile;
}
/*!
Sets the desired major OpenGL version.
*/
void QSurfaceFormat::setMajorVersion(int major)
{
d->major = major;
}
/*!
Returns the major OpenGL version.
*/
int QSurfaceFormat::majorVersion() const
{
return d->major;
}
/*!
Sets the desired minor OpenGL version.
*/
void QSurfaceFormat::setMinorVersion(int minor)
{
d->minor = minor;
}
/*!
Returns the minor OpenGL version.
*/
int QSurfaceFormat::minorVersion() const
{
return d->minor;
}
bool operator==(const QSurfaceFormat& a, const QSurfaceFormat& b)
{
return (a.d == b.d) || ((int) a.d->opts == (int) b.d->opts

View File

@ -49,14 +49,16 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QGuiGLContext;
class QOpenGLContext;
class QSurfaceFormatPrivate;
class Q_GUI_EXPORT QSurfaceFormat
{
public:
enum FormatOption {
StereoBuffers = 0x0001
StereoBuffers = 0x0001,
DebugContext = 0x0002,
DeprecatedFunctions = 0x0004
};
Q_DECLARE_FLAGS(FormatOptions, FormatOption)
@ -105,6 +107,12 @@ public:
void setProfile(OpenGLContextProfile profile);
OpenGLContextProfile profile() const;
void setMajorVersion(int majorVersion);
int majorVersion() const;
void setMinorVersion(int minorVersion);
int minorVersion() const;
bool stereo() const;
void setStereo(bool enable);

View File

@ -43,8 +43,8 @@
#include "qplatformwindow_qpa.h"
#include "qsurfaceformat.h"
#include "qplatformglcontext_qpa.h"
#include "qguiglcontext_qpa.h"
#include "qplatformopenglcontext_qpa.h"
#include "qopenglcontext.h"
#include "qscreen.h"
#include "qwindow_p.h"

44
src/gui/opengl/opengl.pri Normal file
View File

@ -0,0 +1,44 @@
# Qt gui library, opengl module
contains(QT_CONFIG, opengl):CONFIG += opengl
contains(QT_CONFIG, opengles2):CONFIG += opengles2
contains(QT_CONFIG, egl):CONFIG += egl
HEADERS += opengl/qopengl.h \
opengl/qopengl_p.h \
opengl/qopenglfunctions.h \
opengl/qopenglframebufferobject.h \
opengl/qopenglframebufferobject_p.h \
opengl/qopenglpaintdevice_p.h \
opengl/qopenglbuffer.h \
opengl/qopenglshaderprogram.h \
opengl/qopenglextensions_p.h \
opengl/qopenglgradientcache_p.h \
opengl/qopenglengineshadermanager_p.h \
opengl/qopengl2pexvertexarray_p.h \
opengl/qpaintengineex_opengl2_p.h \
opengl/qopenglengineshadersource_p.h \
opengl/qopenglcustomshaderstage_p.h \
opengl/qtriangulatingstroker_p.h \
opengl/qtriangulator_p.h \
opengl/qrbtree_p.h \
opengl/qtextureglyphcache_gl_p.h \
opengl/qopenglshadercache_p.h \
opengl/qopenglshadercache_meego_p.h
SOURCES += opengl/qopengl.cpp \
opengl/qopenglfunctions.cpp \
opengl/qopenglframebufferobject.cpp \
opengl/qopenglpaintdevice.cpp \
opengl/qopenglbuffer.cpp \
opengl/qopenglshaderprogram.cpp \
opengl/qopenglgradientcache.cpp \
opengl/qopenglengineshadermanager.cpp \
opengl/qopengl2pexvertexarray.cpp \
opengl/qpaintengineex_opengl2.cpp \
opengl/qopenglcustomshaderstage.cpp \
opengl/qtriangulatingstroker.cpp \
opengl/qtriangulator.cpp \
opengl/qtextureglyphcache_gl.cpp
#INCLUDEPATH += ../3rdparty/harfbuzz/src

109
src/gui/opengl/qopengl.cpp Normal file
View File

@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qopengl_p.h"
#include "qopenglcontext.h"
QT_BEGIN_NAMESPACE
QOpenGLExtensionMatcher::QOpenGLExtensionMatcher(const char *str)
{
init(str);
}
typedef GLubyte * (*qt_glGetStringi)(GLenum, GLuint);
#ifndef GL_NUM_EXTENSIONS
#define GL_NUM_EXTENSIONS 0x821D
#endif
QOpenGLExtensionMatcher::QOpenGLExtensionMatcher()
{
const char *extensionStr = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
if (extensionStr) {
init(extensionStr);
} else {
// clear error state
while (glGetError()) {}
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx) {
qt_glGetStringi glGetStringi = (qt_glGetStringi)ctx->getProcAddress("glGetStringi");
if (!glGetStringi)
return;
GLint numExtensions;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
for (int i = 0; i < numExtensions; ++i) {
const char *str = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
m_offsets << m_extensions.size();
while (*str != 0)
m_extensions.append(*str++);
m_extensions.append(' ');
}
}
}
}
void QOpenGLExtensionMatcher::init(const char *str)
{
m_extensions = str;
// make sure extension string ends with a space
if (!m_extensions.endsWith(' '))
m_extensions.append(' ');
int index = 0;
int next = 0;
while ((next = m_extensions.indexOf(' ', index)) >= 0) {
m_offsets << index;
index = next + 1;
}
}
QT_END_NAMESPACE

73
src/gui/opengl/qopengl.h Normal file
View File

@ -0,0 +1,73 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QOPENGL_H
#define QOPENGL_H
#include <qglobal.h>
QT_BEGIN_HEADER
#if 1
#if defined(QT_OPENGL_ES_2)
# if defined(Q_OS_MAC)
# include <OpenGLES/ES2/gl.h>
# else
# include <GLES2/gl2.h>
# endif
# ifndef GL_DOUBLE
# define GL_DOUBLE GL_FLOAT
# endif
# ifndef GLdouble
typedef GLfloat GLdouble;
# endif
#else
# if defined(Q_OS_MAC)
# include <OpenGL/gl.h>
# else
# include <GL/gl.h>
# endif
#endif
#endif
QT_END_HEADER
#endif // QOPENGL_H

View File

@ -0,0 +1,175 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qopengl2pexvertexarray_p.h"
#include <private/qbezier_p.h>
QT_BEGIN_NAMESPACE
void QOpenGL2PEXVertexArray::clear()
{
vertexArray.reset();
vertexArrayStops.reset();
boundingRectDirty = true;
}
QOpenGLRect QOpenGL2PEXVertexArray::boundingRect() const
{
if (boundingRectDirty)
return QOpenGLRect(0.0, 0.0, 0.0, 0.0);
else
return QOpenGLRect(minX, minY, maxX, maxY);
}
void QOpenGL2PEXVertexArray::addClosingLine(int index)
{
QPointF point(vertexArray.at(index));
if (point != QPointF(vertexArray.last()))
vertexArray.add(point);
}
void QOpenGL2PEXVertexArray::addCentroid(const QVectorPath &path, int subPathIndex)
{
const QPointF *const points = reinterpret_cast<const QPointF *>(path.points());
const QPainterPath::ElementType *const elements = path.elements();
QPointF sum = points[subPathIndex];
int count = 1;
for (int i = subPathIndex + 1; i < path.elementCount() && (!elements || elements[i] != QPainterPath::MoveToElement); ++i) {
sum += points[i];
++count;
}
const QPointF centroid = sum / qreal(count);
vertexArray.add(centroid);
}
void QOpenGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline)
{
const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
const QPainterPath::ElementType* const elements = path.elements();
if (boundingRectDirty) {
minX = maxX = points[0].x();
minY = maxY = points[0].y();
boundingRectDirty = false;
}
if (!outline && !path.isConvex())
addCentroid(path, 0);
int lastMoveTo = vertexArray.size();
vertexArray.add(points[0]); // The first element is always a moveTo
do {
if (!elements) {
// qDebug("QVectorPath has no elements");
// If the path has a null elements pointer, the elements implicitly
// start with a moveTo (already added) and continue with lineTos:
for (int i=1; i<path.elementCount(); ++i)
lineToArray(points[i].x(), points[i].y());
break;
}
// qDebug("QVectorPath has element types");
for (int i=1; i<path.elementCount(); ++i) {
switch (elements[i]) {
case QPainterPath::MoveToElement:
if (!outline)
addClosingLine(lastMoveTo);
// qDebug("element[%d] is a MoveToElement", i);
vertexArrayStops.add(vertexArray.size());
if (!outline) {
if (!path.isConvex()) addCentroid(path, i);
lastMoveTo = vertexArray.size();
}
lineToArray(points[i].x(), points[i].y()); // Add the moveTo as a new vertex
break;
case QPainterPath::LineToElement:
// qDebug("element[%d] is a LineToElement", i);
lineToArray(points[i].x(), points[i].y());
break;
case QPainterPath::CurveToElement: {
QBezier b = QBezier::fromPoints(*(((const QPointF *) points) + i - 1),
points[i],
points[i+1],
points[i+2]);
QRectF bounds = b.bounds();
// threshold based on same algorithm as in qtriangulatingstroker.cpp
int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * 3.14f / (curveInverseScale * 6));
if (threshold < 3) threshold = 3;
qreal one_over_threshold_minus_1 = qreal(1) / (threshold - 1);
for (int t=0; t<threshold; ++t) {
QPointF pt = b.pointAt(t * one_over_threshold_minus_1);
lineToArray(pt.x(), pt.y());
}
i += 2;
break; }
default:
break;
}
}
} while (0);
if (!outline)
addClosingLine(lastMoveTo);
vertexArrayStops.add(vertexArray.size());
}
void QOpenGL2PEXVertexArray::lineToArray(const GLfloat x, const GLfloat y)
{
vertexArray.add(QOpenGLPoint(x, y));
if (x > maxX)
maxX = x;
else if (x < minX)
minX = x;
if (y > maxY)
maxY = y;
else if (y < minY)
minY = y;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,169 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#ifndef QOPENGL2PEXVERTEXARRAY_P_H
#define QOPENGL2PEXVERTEXARRAY_P_H
#include <QRectF>
#include <private/qdatabuffer_p.h>
#include <private/qvectorpath_p.h>
#include <private/qopenglcontext_p.h>
QT_BEGIN_NAMESPACE
class QOpenGLPoint
{
public:
QOpenGLPoint(GLfloat new_x, GLfloat new_y) :
x(new_x), y(new_y) {};
QOpenGLPoint(const QPointF &p) :
x(p.x()), y(p.y()) {};
QOpenGLPoint(const QPointF* p) :
x(p->x()), y(p->y()) {};
GLfloat x;
GLfloat y;
operator QPointF() {return QPointF(x,y);}
operator QPointF() const {return QPointF(x,y);}
};
struct QOpenGLRect
{
QOpenGLRect(const QRectF &r)
: left(r.left()), top(r.top()), right(r.right()), bottom(r.bottom()) {}
QOpenGLRect(GLfloat l, GLfloat t, GLfloat r, GLfloat b)
: left(l), top(t), right(r), bottom(b) {}
GLfloat left;
GLfloat top;
GLfloat right;
GLfloat bottom;
operator QRectF() const {return QRectF(left, top, right-left, bottom-top);}
};
class QOpenGL2PEXVertexArray
{
public:
QOpenGL2PEXVertexArray() :
vertexArray(0), vertexArrayStops(0),
maxX(-2e10), maxY(-2e10), minX(2e10), minY(2e10),
boundingRectDirty(true)
{ }
inline void addRect(const QRectF &rect)
{
qreal top = rect.top();
qreal left = rect.left();
qreal bottom = rect.bottom();
qreal right = rect.right();
vertexArray << QOpenGLPoint(left, top)
<< QOpenGLPoint(right, top)
<< QOpenGLPoint(right, bottom)
<< QOpenGLPoint(right, bottom)
<< QOpenGLPoint(left, bottom)
<< QOpenGLPoint(left, top);
}
inline void addQuad(const QRectF &rect)
{
qreal top = rect.top();
qreal left = rect.left();
qreal bottom = rect.bottom();
qreal right = rect.right();
vertexArray << QOpenGLPoint(left, top)
<< QOpenGLPoint(right, top)
<< QOpenGLPoint(left, bottom)
<< QOpenGLPoint(right, bottom);
}
inline void addVertex(const GLfloat x, const GLfloat y)
{
vertexArray.add(QOpenGLPoint(x, y));
}
void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true);
void clear();
QOpenGLPoint* data() {return vertexArray.data();}
int *stops() const { return vertexArrayStops.data(); }
int stopCount() const { return vertexArrayStops.size(); }
QOpenGLRect boundingRect() const;
int vertexCount() const { return vertexArray.size(); }
void lineToArray(const GLfloat x, const GLfloat y);
private:
QDataBuffer<QOpenGLPoint> vertexArray;
QDataBuffer<int> vertexArrayStops;
GLfloat maxX;
GLfloat maxY;
GLfloat minX;
GLfloat minY;
bool boundingRectDirty;
void addClosingLine(int index);
void addCentroid(const QVectorPath &path, int subPathIndex);
};
QT_END_NAMESPACE
#endif

200
src/gui/opengl/qopengl_p.h Normal file
View File

@ -0,0 +1,200 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QOPENGL_P_H
#define QOPENGL_P_H
#include <qopengl.h>
#include <private/qopenglcontext_p.h>
#include <qthreadstorage.h>
#include <qcache.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QOpenGLExtensionMatcher
{
public:
QOpenGLExtensionMatcher(const char *str);
QOpenGLExtensionMatcher();
bool match(const char *str) const {
int str_length = qstrlen(str);
Q_ASSERT(str);
Q_ASSERT(str_length > 0);
Q_ASSERT(str[str_length-1] != ' ');
for (int i = 0; i < m_offsets.size(); ++i) {
const char *extension = m_extensions.constData() + m_offsets.at(i);
if (qstrncmp(extension, str, str_length) == 0 && extension[str_length] == ' ')
return true;
}
return false;
}
private:
void init(const char *str);
QByteArray m_extensions;
QVector<int> m_offsets;
};
// this is a class that wraps a QThreadStorage object for storing
// thread local instances of the GL 1 and GL 2 paint engines
class QPaintEngine;
template <class T>
class QOpenGLEngineThreadStorage
{
public:
QPaintEngine *engine() {
QPaintEngine *&localEngine = storage.localData();
if (!localEngine)
localEngine = new T;
return localEngine;
}
private:
QThreadStorage<QPaintEngine *> storage;
};
class QOpenGLTexture : public QOpenGLSharedResource {
public:
QOpenGLTexture(QOpenGLContext *ctx, GLuint id, bool inverted)
: QOpenGLSharedResource(ctx->shareGroup())
, m_id(id)
, m_inverted(inverted)
{
}
GLuint id() const { return m_id; }
bool invertedY() const { return m_inverted; }
protected:
void invalidateResource()
{
m_id = 0;
}
void freeResource(QOpenGLContext *)
{
glDeleteTextures(1, &m_id);
}
private:
GLuint m_id;
bool m_inverted;
};
struct QOpenGLTextureCacheKey {
qint64 key;
QOpenGLContextGroup *group;
};
inline bool operator==(const QOpenGLTextureCacheKey &a, const QOpenGLTextureCacheKey &b)
{
return a.key == b.key && a.group == b.group;
}
inline uint qHash(const QOpenGLTextureCacheKey &key)
{
return qHash(key.key) ^ qHash(key.group);
}
class QPlatformPixmap;
class QOpenGLTextureCache {
public:
QOpenGLTextureCache();
~QOpenGLTextureCache();
void insert(QOpenGLContext *ctx, qint64 key, QOpenGLTexture *texture, int cost);
void remove(qint64 key);
inline int size();
inline void setMaxCost(int newMax);
inline int maxCost();
inline QOpenGLTexture* getTexture(QOpenGLContext *ctx, qint64 key);
bool remove(QOpenGLContext *ctx, GLuint textureId);
void removeContextTextures(QOpenGLContext *ctx);
static QOpenGLTextureCache *instance();
static void cleanupTexturesForCacheKey(qint64 cacheKey);
static void cleanupTexturesForPixampData(QPlatformPixmap* pixmap);
static void cleanupBeforePixmapDestruction(QPlatformPixmap* pixmap);
private:
QCache<QOpenGLTextureCacheKey, QOpenGLTexture> m_cache;
QReadWriteLock m_lock;
};
int QOpenGLTextureCache::size() {
QReadLocker locker(&m_lock);
return m_cache.size();
}
void QOpenGLTextureCache::setMaxCost(int newMax)
{
QWriteLocker locker(&m_lock);
m_cache.setMaxCost(newMax);
}
int QOpenGLTextureCache::maxCost()
{
QReadLocker locker(&m_lock);
return m_cache.maxCost();
}
QOpenGLTexture* QOpenGLTextureCache::getTexture(QOpenGLContext *ctx, qint64 key)
{
QReadLocker locker(&m_lock);
const QOpenGLTextureCacheKey cacheKey = { key, ctx->shareGroup() };
return m_cache.object(cacheKey);
}
QT_END_NAMESPACE
QT_END_HEADER
#endif // QOPENGL_H

View File

@ -0,0 +1,582 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtGui/qopengl.h>
#include <QtGui/private/qopenglcontext_p.h>
#include <QtCore/qatomic.h>
#include "qopenglbuffer.h"
#include <private/qopenglextensions_p.h>
QT_BEGIN_NAMESPACE
/*!
\class QOpenGLBuffer
\brief The QOpenGLBuffer class provides functions for creating and managing GL buffer objects.
\since 4.7
\ingroup painting-3D
Buffer objects are created in the GL server so that the
client application can avoid uploading vertices, indices,
texture image data, etc every time they are needed.
QOpenGLBuffer objects can be copied around as a reference to the
underlying GL buffer object:
\code
QOpenGLBuffer buffer1(QOpenGLBuffer::IndexBuffer);
buffer1.create();
QOpenGLBuffer buffer2 = buffer1;
\endcode
QOpenGLBuffer performs a shallow copy when objects are copied in this
manner, but does not implement copy-on-write semantics. The original
object will be affected whenever the copy is modified.
*/
/*!
\enum QOpenGLBuffer::Type
This enum defines the type of GL buffer object to create with QOpenGLBuffer.
\value VertexBuffer Vertex buffer object for use when specifying
vertex arrays.
\value IndexBuffer Index buffer object for use with \c{glDrawElements()}.
\value PixelPackBuffer Pixel pack buffer object for reading pixel
data from the GL server (for example, with \c{glReadPixels()}).
Not supported under OpenGL/ES.
\value PixelUnpackBuffer Pixel unpack buffer object for writing pixel
data to the GL server (for example, with \c{glTexImage2D()}).
Not supported under OpenGL/ES.
*/
/*!
\enum QOpenGLBuffer::UsagePattern
This enum defines the usage pattern of a QOpenGLBuffer object.
\value StreamDraw The data will be set once and used a few times
for drawing operations. Under OpenGL/ES 1.1 this is identical
to StaticDraw.
\value StreamRead The data will be set once and used a few times
for reading data back from the GL server. Not supported
under OpenGL/ES.
\value StreamCopy The data will be set once and used a few times
for reading data back from the GL server for use in further
drawing operations. Not supported under OpenGL/ES.
\value StaticDraw The data will be set once and used many times
for drawing operations.
\value StaticRead The data will be set once and used many times
for reading data back from the GL server. Not supported
under OpenGL/ES.
\value StaticCopy The data will be set once and used many times
for reading data back from the GL server for use in further
drawing operations. Not supported under OpenGL/ES.
\value DynamicDraw The data will be modified repeatedly and used
many times for drawing operations.
\value DynamicRead The data will be modified repeatedly and used
many times for reading data back from the GL server.
Not supported under OpenGL/ES.
\value DynamicCopy The data will be modified repeatedly and used
many times for reading data back from the GL server for
use in further drawing operations. Not supported under OpenGL/ES.
*/
/*!
\enum QOpenGLBuffer::Access
This enum defines the access mode for QOpenGLBuffer::map().
\value ReadOnly The buffer will be mapped for reading only.
\value WriteOnly The buffer will be mapped for writing only.
\value ReadWrite The buffer will be mapped for reading and writing.
*/
class QOpenGLBufferPrivate
{
public:
QOpenGLBufferPrivate(QOpenGLBuffer::Type t)
: ref(1),
type(t),
guard(0),
usagePattern(QOpenGLBuffer::StaticDraw),
actualUsagePattern(QOpenGLBuffer::StaticDraw),
funcs(0)
{
}
QAtomicInt ref;
QOpenGLBuffer::Type type;
QOpenGLSharedResourceGuard *guard;
QOpenGLBuffer::UsagePattern usagePattern;
QOpenGLBuffer::UsagePattern actualUsagePattern;
QOpenGLExtensions *funcs;
};
/*!
Constructs a new buffer object of type QOpenGLBuffer::VertexBuffer.
Note: this constructor just creates the QOpenGLBuffer instance. The actual
buffer object in the GL server is not created until create() is called.
\sa create()
*/
QOpenGLBuffer::QOpenGLBuffer()
: d_ptr(new QOpenGLBufferPrivate(QOpenGLBuffer::VertexBuffer))
{
}
/*!
Constructs a new buffer object of \a type.
Note: this constructor just creates the QOpenGLBuffer instance. The actual
buffer object in the GL server is not created until create() is called.
\sa create()
*/
QOpenGLBuffer::QOpenGLBuffer(QOpenGLBuffer::Type type)
: d_ptr(new QOpenGLBufferPrivate(type))
{
}
/*!
Constructs a shallow copy of \a other.
Note: QOpenGLBuffer does not implement copy-on-write semantics,
so \a other will be affected whenever the copy is modified.
*/
QOpenGLBuffer::QOpenGLBuffer(const QOpenGLBuffer &other)
: d_ptr(other.d_ptr)
{
d_ptr->ref.ref();
}
#define ctx QOpenGLContext::currentContext();
/*!
Destroys this buffer object, including the storage being
used in the GL server.
*/
QOpenGLBuffer::~QOpenGLBuffer()
{
if (!d_ptr->ref.deref()) {
destroy();
delete d_ptr;
}
}
/*!
Assigns a shallow copy of \a other to this object.
Note: QOpenGLBuffer does not implement copy-on-write semantics,
so \a other will be affected whenever the copy is modified.
*/
QOpenGLBuffer &QOpenGLBuffer::operator=(const QOpenGLBuffer &other)
{
if (d_ptr != other.d_ptr) {
other.d_ptr->ref.ref();
if (!d_ptr->ref.deref())
destroy();
d_ptr = other.d_ptr;
}
return *this;
}
/*!
Returns the type of buffer represented by this object.
*/
QOpenGLBuffer::Type QOpenGLBuffer::type() const
{
Q_D(const QOpenGLBuffer);
return d->type;
}
/*!
Returns the usage pattern for this buffer object.
The default value is StaticDraw.
\sa setUsagePattern()
*/
QOpenGLBuffer::UsagePattern QOpenGLBuffer::usagePattern() const
{
Q_D(const QOpenGLBuffer);
return d->usagePattern;
}
/*!
Sets the usage pattern for this buffer object to \a value.
This function must be called before allocate() or write().
\sa usagePattern(), allocate(), write()
*/
void QOpenGLBuffer::setUsagePattern(QOpenGLBuffer::UsagePattern value)
{
Q_D(QOpenGLBuffer);
d->usagePattern = d->actualUsagePattern = value;
}
#undef ctx
namespace {
void freeBufferFunc(QOpenGLFunctions *funcs, GLuint id)
{
funcs->glDeleteBuffers(1, &id);
}
}
/*!
Creates the buffer object in the GL server. Returns true if
the object was created; false otherwise.
This function must be called with a current QOpenGLContext.
The buffer will be bound to and can only be used in
that context (or any other context that is shared with it).
This function will return false if the GL implementation
does not support buffers, or there is no current QOpenGLContext.
\sa isCreated(), allocate(), write(), destroy()
*/
bool QOpenGLBuffer::create()
{
Q_D(QOpenGLBuffer);
if (d->guard && d->guard->id())
return true;
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx) {
delete d->funcs;
d->funcs = new QOpenGLExtensions(ctx);
GLuint bufferId = 0;
d->funcs->glGenBuffers(1, &bufferId);
if (bufferId) {
if (d->guard)
d->guard->free();
d->guard = new QOpenGLSharedResourceGuard(ctx, bufferId, freeBufferFunc);
return true;
}
}
return false;
}
#define ctx QOpenGLContext::currentContext()
/*!
Returns true if this buffer has been created; false otherwise.
\sa create(), destroy()
*/
bool QOpenGLBuffer::isCreated() const
{
Q_D(const QOpenGLBuffer);
return d->guard && d->guard->id();
}
/*!
Destroys this buffer object, including the storage being
used in the GL server. All references to the buffer will
become invalid.
*/
void QOpenGLBuffer::destroy()
{
Q_D(QOpenGLBuffer);
if (d->guard) {
d->guard->free();
d->guard = 0;
}
}
/*!
Reads the \a count bytes in this buffer starting at \a offset
into \a data. Returns true on success; false if reading from
the buffer is not supported. Buffer reading is not supported
under OpenGL/ES.
It is assumed that this buffer has been bound to the current context.
\sa write(), bind()
*/
bool QOpenGLBuffer::read(int offset, void *data, int count)
{
#if !defined(QT_OPENGL_ES)
Q_D(QOpenGLBuffer);
if (!d->funcs->hasOpenGLFeature(QOpenGLFunctions::Buffers) || !d->guard->id())
return false;
while (glGetError() != GL_NO_ERROR) ; // Clear error state.
d->funcs->glGetBufferSubData(d->type, offset, count, data);
return glGetError() == GL_NO_ERROR;
#else
Q_UNUSED(offset);
Q_UNUSED(data);
Q_UNUSED(count);
return false;
#endif
}
/*!
Replaces the \a count bytes of this buffer starting at \a offset
with the contents of \a data. Any other bytes in the buffer
will be left unmodified.
It is assumed that create() has been called on this buffer and that
it has been bound to the current context.
\sa create(), read(), allocate()
*/
void QOpenGLBuffer::write(int offset, const void *data, int count)
{
#ifndef QT_NO_DEBUG
if (!isCreated())
qWarning("QOpenGLBuffer::allocate(): buffer not created");
#endif
Q_D(QOpenGLBuffer);
if (d->guard && d->guard->id())
d->funcs->glBufferSubData(d->type, offset, count, data);
}
/*!
Allocates \a count bytes of space to the buffer, initialized to
the contents of \a data. Any previous contents will be removed.
It is assumed that create() has been called on this buffer and that
it has been bound to the current context.
\sa create(), read(), write()
*/
void QOpenGLBuffer::allocate(const void *data, int count)
{
#ifndef QT_NO_DEBUG
if (!isCreated())
qWarning("QOpenGLBuffer::allocate(): buffer not created");
#endif
Q_D(QOpenGLBuffer);
if (d->guard && d->guard->id())
d->funcs->glBufferData(d->type, count, data, d->actualUsagePattern);
}
/*!
\fn void QOpenGLBuffer::allocate(int count)
\overload
Allocates \a count bytes of space to the buffer. Any previous
contents will be removed.
It is assumed that create() has been called on this buffer and that
it has been bound to the current context.
\sa create(), write()
*/
/*!
Binds the buffer associated with this object to the current
GL context. Returns false if binding was not possible, usually because
type() is not supported on this GL implementation.
The buffer must be bound to the same QOpenGLContext current when create()
was called, or to another QOpenGLContext that is sharing with it.
Otherwise, false will be returned from this function.
\sa release(), create()
*/
bool QOpenGLBuffer::bind()
{
#ifndef QT_NO_DEBUG
if (!isCreated())
qWarning("QOpenGLBuffer::bind(): buffer not created");
#endif
Q_D(const QOpenGLBuffer);
GLuint bufferId = d->guard ? d->guard->id() : 0;
if (bufferId) {
if (d->guard->group() != QOpenGLContextGroup::currentContextGroup()) {
#ifndef QT_NO_DEBUG
qWarning("QOpenGLBuffer::bind: buffer is not valid in the current context");
#endif
return false;
}
d->funcs->glBindBuffer(d->type, bufferId);
return true;
} else {
return false;
}
}
/*!
Releases the buffer associated with this object from the
current GL context.
This function must be called with the same QOpenGLContext current
as when bind() was called on the buffer.
\sa bind()
*/
void QOpenGLBuffer::release()
{
#ifndef QT_NO_DEBUG
if (!isCreated())
qWarning("QOpenGLBuffer::release(): buffer not created");
#endif
Q_D(const QOpenGLBuffer);
if (d->guard && d->guard->id())
d->funcs->glBindBuffer(d->type, 0);
}
#undef ctx
/*!
Releases the buffer associated with \a type in the current
QOpenGLContext.
This function is a direct call to \c{glBindBuffer(type, 0)}
for use when the caller does not know which QOpenGLBuffer has
been bound to the context but wants to make sure that it
is released.
\code
QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer);
\endcode
*/
void QOpenGLBuffer::release(QOpenGLBuffer::Type type)
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx) {
QOpenGLFunctions(ctx).glBindBuffer(GLenum(type), 0);
}
}
#define ctx QOpenGLContext::currentContext()
/*!
Returns the GL identifier associated with this buffer; zero if
the buffer has not been created.
\sa isCreated()
*/
GLuint QOpenGLBuffer::bufferId() const
{
Q_D(const QOpenGLBuffer);
return d->guard ? d->guard->id() : 0;
}
#ifndef GL_BUFFER_SIZE
#define GL_BUFFER_SIZE 0x8764
#endif
/*!
Returns the size of the data in this buffer, for reading operations.
Returns -1 if fetching the buffer size is not supported, or the
buffer has not been created.
It is assumed that this buffer has been bound to the current context.
\sa isCreated(), bind()
*/
int QOpenGLBuffer::size() const
{
Q_D(const QOpenGLBuffer);
if (!d->guard || !d->guard->id())
return -1;
GLint value = -1;
d->funcs->glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value);
return value;
}
/*!
Maps the contents of this buffer into the application's memory
space and returns a pointer to it. Returns null if memory
mapping is not possible. The \a access parameter indicates the
type of access to be performed.
It is assumed that create() has been called on this buffer and that
it has been bound to the current context.
This function is only supported under OpenGL/ES if the
\c{GL_OES_mapbuffer} extension is present.
\sa unmap(), create(), bind()
*/
void *QOpenGLBuffer::map(QOpenGLBuffer::Access access)
{
Q_D(QOpenGLBuffer);
#ifndef QT_NO_DEBUG
if (!isCreated())
qWarning("QOpenGLBuffer::map(): buffer not created");
#endif
if (!d->guard || !d->guard->id())
return 0;
#if 0
if (!glMapBufferARB)
return 0;
return glMapBufferARB(d->type, access);
#endif
Q_UNUSED(access);
qWarning("QOpenGLBuffer::map(): pending implementation");
return 0;
}
/*!
Unmaps the buffer after it was mapped into the application's
memory space with a previous call to map(). Returns true if
the unmap succeeded; false otherwise.
It is assumed that this buffer has been bound to the current context,
and that it was previously mapped with map().
This function is only supported under OpenGL/ES if the
\c{GL_OES_mapbuffer} extension is present.
\sa map()
*/
bool QOpenGLBuffer::unmap()
{
Q_D(QOpenGLBuffer);
#ifndef QT_NO_DEBUG
if (!isCreated())
qWarning("QOpenGLBuffer::unmap(): buffer not created");
#endif
if (!d->guard || !d->guard->id())
return false;
#if 0
if (!glUnmapBufferARB)
return false;
return glUnmapBufferARB(d->type) == GL_TRUE;
#endif
qWarning("QOpenGLBuffer::map(): pending implementation");
return 0;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,132 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QOPENGLBUFFER_H
#define QOPENGLBUFFER_H
#include <QtCore/qscopedpointer.h>
#include <QtGui/qopengl.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QOpenGLBufferPrivate;
class Q_GUI_EXPORT QOpenGLBuffer
{
public:
enum Type
{
VertexBuffer = 0x8892, // GL_ARRAY_BUFFER
IndexBuffer = 0x8893, // GL_ELEMENT_ARRAY_BUFFER
PixelPackBuffer = 0x88EB, // GL_PIXEL_PACK_BUFFER
PixelUnpackBuffer = 0x88EC // GL_PIXEL_UNPACK_BUFFER
};
QOpenGLBuffer();
explicit QOpenGLBuffer(QOpenGLBuffer::Type type);
QOpenGLBuffer(const QOpenGLBuffer &other);
~QOpenGLBuffer();
QOpenGLBuffer &operator=(const QOpenGLBuffer &other);
enum UsagePattern
{
StreamDraw = 0x88E0, // GL_STREAM_DRAW
StreamRead = 0x88E1, // GL_STREAM_READ
StreamCopy = 0x88E2, // GL_STREAM_COPY
StaticDraw = 0x88E4, // GL_STATIC_DRAW
StaticRead = 0x88E5, // GL_STATIC_READ
StaticCopy = 0x88E6, // GL_STATIC_COPY
DynamicDraw = 0x88E8, // GL_DYNAMIC_DRAW
DynamicRead = 0x88E9, // GL_DYNAMIC_READ
DynamicCopy = 0x88EA // GL_DYNAMIC_COPY
};
enum Access
{
ReadOnly = 0x88B8, // GL_READ_ONLY
WriteOnly = 0x88B9, // GL_WRITE_ONLY
ReadWrite = 0x88BA // GL_READ_WRITE
};
QOpenGLBuffer::Type type() const;
QOpenGLBuffer::UsagePattern usagePattern() const;
void setUsagePattern(QOpenGLBuffer::UsagePattern value);
bool create();
bool isCreated() const;
void destroy();
bool bind();
void release();
static void release(QOpenGLBuffer::Type type);
GLuint bufferId() const;
int size() const;
bool read(int offset, void *data, int count);
void write(int offset, const void *data, int count);
void allocate(const void *data, int count);
inline void allocate(int count) { allocate(0, count); }
void *map(QOpenGLBuffer::Access access);
bool unmap();
private:
QOpenGLBufferPrivate *d_ptr;
Q_DECLARE_PRIVATE(QOpenGLBuffer)
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@ -0,0 +1,297 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\class QOpenGLColormap
\brief The QOpenGLColormap class is used for installing custom colormaps into
a QOpenGLWidget.
\module OpenGL
\ingroup painting-3D
\ingroup shared
QOpenGLColormap provides a platform independent way of specifying and
installing indexed colormaps for a QOpenGLWidget. QOpenGLColormap is
especially useful when using the OpenGL color-index mode.
Under X11 you must use an X server that supports either a \c
PseudoColor or \c DirectColor visual class. If your X server
currently only provides a \c GrayScale, \c TrueColor, \c
StaticColor or \c StaticGray visual, you will not be able to
allocate colorcells for writing. If this is the case, try setting
your X server to 8 bit mode. It should then provide you with at
least a \c PseudoColor visual. Note that you may experience
colormap flashing if your X server is running in 8 bit mode.
The size() of the colormap is always set to 256
colors. Note that under Windows you can also install colormaps
in child widgets.
This class uses \l{implicit sharing} as a memory and speed
optimization.
Example of use:
\snippet doc/src/snippets/code/src_opengl_qopenglcolormap.cpp 0
\sa QOpenGLWidget::setColormap(), QOpenGLWidget::colormap()
*/
/*!
\fn Qt::HANDLE QOpenGLColormap::handle()
\internal
Returns the handle for this color map.
*/
/*!
\fn void QOpenGLColormap::setHandle(Qt::HANDLE handle)
\internal
Sets the handle for this color map to \a handle.
*/
#include "qopenglcolormap.h"
QT_BEGIN_NAMESPACE
QOpenGLColormap::QOpenGLColormapData QOpenGLColormap::shared_null = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0 };
/*!
Construct a QOpenGLColormap.
*/
QOpenGLColormap::QOpenGLColormap()
: d(&shared_null)
{
d->ref.ref();
}
/*!
Construct a shallow copy of \a map.
*/
QOpenGLColormap::QOpenGLColormap(const QOpenGLColormap &map)
: d(map.d)
{
d->ref.ref();
}
/*!
Dereferences the QOpenGLColormap and deletes it if this was the last
reference to it.
*/
QOpenGLColormap::~QOpenGLColormap()
{
if (!d->ref.deref())
cleanup(d);
}
void QOpenGLColormap::cleanup(QOpenGLColormap::QOpenGLColormapData *x)
{
delete x->cells;
x->cells = 0;
delete x;
}
/*!
Assign a shallow copy of \a map to this QOpenGLColormap.
*/
QOpenGLColormap & QOpenGLColormap::operator=(const QOpenGLColormap &map)
{
map.d->ref.ref();
if (!d->ref.deref())
cleanup(d);
d = map.d;
return *this;
}
/*!
\fn void QOpenGLColormap::detach()
\internal
Detaches this QOpenGLColormap from the shared block.
*/
void QOpenGLColormap::detach_helper()
{
QOpenGLColormapData *x = new QOpenGLColormapData;
x->ref = 1;
x->cmapHandle = 0;
x->cells = 0;
if (d->cells) {
x->cells = new QVector<QRgb>(256);
*x->cells = *d->cells;
}
if (!d->ref.deref())
cleanup(d);
d = x;
}
/*!
Set cell at index \a idx in the colormap to color \a color.
*/
void QOpenGLColormap::setEntry(int idx, QRgb color)
{
detach();
if (!d->cells)
d->cells = new QVector<QRgb>(256);
d->cells->replace(idx, color);
}
/*!
Set an array of cells in this colormap. \a count is the number of
colors that should be set, \a colors is the array of colors, and
\a base is the starting index. The first element in \a colors
is set at \a base in the colormap.
*/
void QOpenGLColormap::setEntries(int count, const QRgb *colors, int base)
{
detach();
if (!d->cells)
d->cells = new QVector<QRgb>(256);
Q_ASSERT_X(colors && base >= 0 && (base + count) <= d->cells->size(), "QOpenGLColormap::setEntries",
"preconditions not met");
for (int i = 0; i < count; ++i)
setEntry(base + i, colors[i]);
}
/*!
Returns the QRgb value in the colorcell with index \a idx.
*/
QRgb QOpenGLColormap::entryRgb(int idx) const
{
if (d == &shared_null || !d->cells)
return 0;
else
return d->cells->at(idx);
}
/*!
\overload
Set the cell with index \a idx in the colormap to color \a color.
*/
void QOpenGLColormap::setEntry(int idx, const QColor &color)
{
setEntry(idx, color.rgb());
}
/*!
Returns the QRgb value in the colorcell with index \a idx.
*/
QColor QOpenGLColormap::entryColor(int idx) const
{
if (d == &shared_null || !d->cells)
return QColor();
else
return QColor(d->cells->at(idx));
}
/*!
Returns true if the colormap is empty or it is not in use
by a QOpenGLWidget; otherwise returns false.
A colormap with no color values set is considered to be empty.
For historical reasons, a colormap that has color values set
but which is not in use by a QOpenGLWidget is also considered empty.
Compare size() with zero to determine if the colormap is empty
regardless of whether it is in use by a QOpenGLWidget or not.
\sa size()
*/
bool QOpenGLColormap::isEmpty() const
{
return d == &shared_null || d->cells == 0 || d->cells->size() == 0 || d->cmapHandle == 0;
}
/*!
Returns the number of colorcells in the colormap.
*/
int QOpenGLColormap::size() const
{
return d->cells ? d->cells->size() : 0;
}
/*!
Returns the index of the color \a color. If \a color is not in the
map, -1 is returned.
*/
int QOpenGLColormap::find(QRgb color) const
{
if (d->cells)
return d->cells->indexOf(color);
return -1;
}
/*!
Returns the index of the color that is the closest match to color
\a color.
*/
int QOpenGLColormap::findNearest(QRgb color) const
{
int idx = find(color);
if (idx >= 0)
return idx;
int mapSize = size();
int mindist = 200000;
int r = qRed(color);
int g = qGreen(color);
int b = qBlue(color);
int rx, gx, bx, dist;
for (int i = 0; i < mapSize; ++i) {
QRgb ci = d->cells->at(i);
rx = r - qRed(ci);
gx = g - qGreen(ci);
bx = b - qBlue(ci);
dist = rx * rx + gx * gx + bx * bx; // calculate distance
if (dist < mindist) { // minimal?
mindist = dist;
idx = i;
}
}
return idx;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,105 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QOPENGLCOLORMAP_H
#define QOPENGLCOLORMAP_H
#include <QtGui/qcolor.h>
#include <QtCore/qvector.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class Q_GUI_EXPORT QOpenGLColormap
{
public:
QOpenGLColormap();
QOpenGLColormap(const QOpenGLColormap &);
~QOpenGLColormap();
QOpenGLColormap &operator=(const QOpenGLColormap &);
bool isEmpty() const;
int size() const;
void detach();
void setEntries(int count, const QRgb * colors, int base = 0);
void setEntry(int idx, QRgb color);
void setEntry(int idx, const QColor & color);
QRgb entryRgb(int idx) const;
QColor entryColor(int idx) const;
int find(QRgb color) const;
int findNearest(QRgb color) const;
protected:
Qt::HANDLE handle() { return d ? d->cmapHandle : 0; }
void setHandle(Qt::HANDLE ahandle) { d->cmapHandle = ahandle; }
private:
struct QOpenGLColormapData {
QBasicAtomicInt ref;
QVector<QRgb> *cells;
Qt::HANDLE cmapHandle;
};
QOpenGLColormapData *d;
static struct QOpenGLColormapData shared_null;
static void cleanup(QOpenGLColormapData *x);
void detach_helper();
friend class QOpenGLWidget;
friend class QOpenGLWidgetPrivate;
};
inline void QOpenGLColormap::detach()
{
if (d->ref != 1)
detach_helper();
}
QT_END_NAMESPACE
QT_END_HEADER
#endif // QOPENGLCOLORMAP_H

View File

@ -0,0 +1,138 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qopenglcustomshaderstage_p.h"
#include "qopenglengineshadermanager_p.h"
#include "qpaintengineex_opengl2_p.h"
#include <private/qpainter_p.h>
QT_BEGIN_NAMESPACE
class QOpenGLCustomShaderStagePrivate
{
public:
QOpenGLCustomShaderStagePrivate() :
m_manager(0) {}
QPointer<QOpenGLEngineShaderManager> m_manager;
QByteArray m_source;
};
QOpenGLCustomShaderStage::QOpenGLCustomShaderStage()
: d_ptr(new QOpenGLCustomShaderStagePrivate)
{
}
QOpenGLCustomShaderStage::~QOpenGLCustomShaderStage()
{
Q_D(QOpenGLCustomShaderStage);
if (d->m_manager) {
d->m_manager->removeCustomStage();
d->m_manager->sharedShaders->cleanupCustomStage(this);
}
}
void QOpenGLCustomShaderStage::setUniformsDirty()
{
Q_D(QOpenGLCustomShaderStage);
if (d->m_manager)
d->m_manager->setDirty(); // ### Probably a bit overkill!
}
bool QOpenGLCustomShaderStage::setOnPainter(QPainter* p)
{
Q_D(QOpenGLCustomShaderStage);
if (p->paintEngine()->type() != QPaintEngine::OpenGL2) {
qWarning("QOpenGLCustomShaderStage::setOnPainter() - paint engine not OpenGL2");
return false;
}
if (d->m_manager)
qWarning("Custom shader is already set on a painter");
QOpenGL2PaintEngineEx *engine = static_cast<QOpenGL2PaintEngineEx*>(p->paintEngine());
d->m_manager = QOpenGL2PaintEngineExPrivate::shaderManagerForEngine(engine);
Q_ASSERT(d->m_manager);
d->m_manager->setCustomStage(this);
return true;
}
void QOpenGLCustomShaderStage::removeFromPainter(QPainter* p)
{
Q_D(QOpenGLCustomShaderStage);
if (p->paintEngine()->type() != QPaintEngine::OpenGL2)
return;
QOpenGL2PaintEngineEx *engine = static_cast<QOpenGL2PaintEngineEx*>(p->paintEngine());
d->m_manager = QOpenGL2PaintEngineExPrivate::shaderManagerForEngine(engine);
Q_ASSERT(d->m_manager);
// Just set the stage to null, don't call removeCustomStage().
// This should leave the program in a compiled/linked state
// if the next custom shader stage is this one again.
d->m_manager->setCustomStage(0);
d->m_manager = 0;
}
QByteArray QOpenGLCustomShaderStage::source() const
{
Q_D(const QOpenGLCustomShaderStage);
return d->m_source;
}
// Called by the shader manager if another custom shader is attached or
// the manager is deleted
void QOpenGLCustomShaderStage::setInactive()
{
Q_D(QOpenGLCustomShaderStage);
d->m_manager = 0;
}
void QOpenGLCustomShaderStage::setSource(const QByteArray& s)
{
Q_D(QOpenGLCustomShaderStage);
d->m_source = s;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,93 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QOPENGL_CUSTOM_SHADER_STAGE_H
#define QOPENGL_CUSTOM_SHADER_STAGE_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QOpenGLShaderProgram>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QOpenGLCustomShaderStagePrivate;
class Q_GUI_EXPORT QOpenGLCustomShaderStage
{
Q_DECLARE_PRIVATE(QOpenGLCustomShaderStage)
public:
QOpenGLCustomShaderStage();
virtual ~QOpenGLCustomShaderStage();
virtual void setUniforms(QOpenGLShaderProgram*) {}
void setUniformsDirty();
bool setOnPainter(QPainter*);
void removeFromPainter(QPainter*);
QByteArray source() const;
void setInactive();
protected:
void setSource(const QByteArray&);
private:
QOpenGLCustomShaderStagePrivate* d_ptr;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@ -0,0 +1,881 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qopenglengineshadermanager_p.h"
#include "qopenglengineshadersource_p.h"
#include "qpaintengineex_opengl2_p.h"
#include "qopenglshadercache_p.h"
#include <QtGui/private/qopenglcontext_p.h>
#include <QtCore/qthreadstorage.h>
#if defined(QT_DEBUG)
#include <QMetaEnum>
#endif
// #define QT_GL_SHARED_SHADER_DEBUG
QT_BEGIN_NAMESPACE
class QOpenGLEngineSharedShadersResource : public QOpenGLSharedResource
{
public:
QOpenGLEngineSharedShadersResource(QOpenGLContext *ctx)
: QOpenGLSharedResource(ctx->shareGroup())
, m_shaders(new QOpenGLEngineSharedShaders(ctx))
{
}
~QOpenGLEngineSharedShadersResource()
{
delete m_shaders;
}
void invalidateResource()
{
delete m_shaders;
m_shaders = 0;
}
void freeResource(QOpenGLContext *)
{
}
QOpenGLEngineSharedShaders *shaders() const { return m_shaders; }
private:
QOpenGLEngineSharedShaders *m_shaders;
};
class QOpenGLShaderStorage
{
public:
QOpenGLEngineSharedShaders *shadersForThread(QOpenGLContext *context) {
QOpenGLMultiGroupSharedResource *&shaders = m_storage.localData();
if (!shaders)
shaders = new QOpenGLMultiGroupSharedResource;
QOpenGLEngineSharedShadersResource *resource =
shaders->value<QOpenGLEngineSharedShadersResource>(context);
return resource ? resource->shaders() : 0;
}
private:
QThreadStorage<QOpenGLMultiGroupSharedResource *> m_storage;
};
Q_GLOBAL_STATIC(QOpenGLShaderStorage, qt_shader_storage);
QOpenGLEngineSharedShaders *QOpenGLEngineSharedShaders::shadersForContext(QOpenGLContext *context)
{
return qt_shader_storage()->shadersForThread(context);
}
const char* QOpenGLEngineSharedShaders::qShaderSnippets[] = {
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0
};
QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
: blitShaderProg(0)
, simpleShaderProg(0)
{
/*
Rather than having the shader source array statically initialised, it is initialised
here instead. This is to allow new shader names to be inserted or existing names moved
around without having to change the order of the glsl strings. It is hoped this will
make future hard-to-find runtime bugs more obvious and generally give more solid code.
*/
static bool snippetsPopulated = false;
if (!snippetsPopulated) {
const char** code = qShaderSnippets; // shortcut
code[MainVertexShader] = qopenglslMainVertexShader;
code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader;
code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader;
code[UntransformedPositionVertexShader] = qopenglslUntransformedPositionVertexShader;
code[PositionOnlyVertexShader] = qopenglslPositionOnlyVertexShader;
code[ComplexGeometryPositionOnlyVertexShader] = qopenglslComplexGeometryPositionOnlyVertexShader;
code[PositionWithPatternBrushVertexShader] = qopenglslPositionWithPatternBrushVertexShader;
code[PositionWithLinearGradientBrushVertexShader] = qopenglslPositionWithLinearGradientBrushVertexShader;
code[PositionWithConicalGradientBrushVertexShader] = qopenglslPositionWithConicalGradientBrushVertexShader;
code[PositionWithRadialGradientBrushVertexShader] = qopenglslPositionWithRadialGradientBrushVertexShader;
code[PositionWithTextureBrushVertexShader] = qopenglslPositionWithTextureBrushVertexShader;
code[AffinePositionWithPatternBrushVertexShader] = qopenglslAffinePositionWithPatternBrushVertexShader;
code[AffinePositionWithLinearGradientBrushVertexShader] = qopenglslAffinePositionWithLinearGradientBrushVertexShader;
code[AffinePositionWithConicalGradientBrushVertexShader] = qopenglslAffinePositionWithConicalGradientBrushVertexShader;
code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader;
code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader;
code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO;
code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM;
code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO;
code[MainFragmentShader_M] = qopenglslMainFragmentShader_M;
code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO;
code[MainFragmentShader_C] = qopenglslMainFragmentShader_C;
code[MainFragmentShader_O] = qopenglslMainFragmentShader_O;
code[MainFragmentShader] = qopenglslMainFragmentShader;
code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays;
code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader;
code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader;
code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader;
code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader;
code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader;
code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader;
code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader;
code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader;
code[RadialGradientBrushSrcFragmentShader] = qopenglslRadialGradientBrushSrcFragmentShader;
code[ConicalGradientBrushSrcFragmentShader] = qopenglslConicalGradientBrushSrcFragmentShader;
code[ShockingPinkSrcFragmentShader] = qopenglslShockingPinkSrcFragmentShader;
code[NoMaskFragmentShader] = "";
code[MaskFragmentShader] = qopenglslMaskFragmentShader;
code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1;
code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2;
code[RgbMaskWithGammaFragmentShader] = ""; //###
code[NoCompositionModeFragmentShader] = "";
code[MultiplyCompositionModeFragmentShader] = ""; //###
code[ScreenCompositionModeFragmentShader] = ""; //###
code[OverlayCompositionModeFragmentShader] = ""; //###
code[DarkenCompositionModeFragmentShader] = ""; //###
code[LightenCompositionModeFragmentShader] = ""; //###
code[ColorDodgeCompositionModeFragmentShader] = ""; //###
code[ColorBurnCompositionModeFragmentShader] = ""; //###
code[HardLightCompositionModeFragmentShader] = ""; //###
code[SoftLightCompositionModeFragmentShader] = ""; //###
code[DifferenceCompositionModeFragmentShader] = ""; //###
code[ExclusionCompositionModeFragmentShader] = ""; //###
#if defined(QT_DEBUG)
// Check that all the elements have been filled:
for (int i = 0; i < TotalSnippetCount; ++i) {
if (qShaderSnippets[i] == 0) {
qFatal("Shader snippet for %s (#%d) is missing!",
snippetNameStr(SnippetName(i)).constData(), i);
}
}
#endif
snippetsPopulated = true;
}
QOpenGLShader* fragShader;
QOpenGLShader* vertexShader;
QByteArray vertexSource;
QByteArray fragSource;
// Compile up the simple shader:
vertexSource.append(qShaderSnippets[MainVertexShader]);
vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]);
fragSource.append(qShaderSnippets[MainFragmentShader]);
fragSource.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
simpleShaderProg = new QOpenGLShaderProgram;
CachedShader simpleShaderCache(fragSource, vertexSource);
bool inCache = simpleShaderCache.load(simpleShaderProg, context);
if (!inCache) {
vertexShader = new QOpenGLShader(QOpenGLShader::Vertex);
shaders.append(vertexShader);
if (!vertexShader->compileSourceCode(vertexSource))
qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile");
fragShader = new QOpenGLShader(QOpenGLShader::Fragment);
shaders.append(fragShader);
if (!fragShader->compileSourceCode(fragSource))
qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile");
simpleShaderProg->addShader(vertexShader);
simpleShaderProg->addShader(fragShader);
simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
simpleShaderProg->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
}
simpleShaderProg->link();
if (simpleShaderProg->isLinked()) {
if (!inCache)
simpleShaderCache.store(simpleShaderProg, context);
} else {
qCritical() << "Errors linking simple shader:"
<< simpleShaderProg->log();
}
// Compile the blit shader:
vertexSource.clear();
vertexSource.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
vertexSource.append(qShaderSnippets[UntransformedPositionVertexShader]);
fragSource.clear();
fragSource.append(qShaderSnippets[MainFragmentShader]);
fragSource.append(qShaderSnippets[ImageSrcFragmentShader]);
blitShaderProg = new QOpenGLShaderProgram;
CachedShader blitShaderCache(fragSource, vertexSource);
inCache = blitShaderCache.load(blitShaderProg, context);
if (!inCache) {
vertexShader = new QOpenGLShader(QOpenGLShader::Vertex);
shaders.append(vertexShader);
if (!vertexShader->compileSourceCode(vertexSource))
qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile");
fragShader = new QOpenGLShader(QOpenGLShader::Fragment);
shaders.append(fragShader);
if (!fragShader->compileSourceCode(fragSource))
qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile");
blitShaderProg->addShader(vertexShader);
blitShaderProg->addShader(fragShader);
blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
}
blitShaderProg->link();
if (blitShaderProg->isLinked()) {
if (!inCache)
blitShaderCache.store(blitShaderProg, context);
} else {
qCritical() << "Errors linking blit shader:"
<< blitShaderProg->log();
}
#ifdef QT_GL_SHARED_SHADER_DEBUG
qDebug(" -> QOpenGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread());
#endif
}
QOpenGLEngineSharedShaders::~QOpenGLEngineSharedShaders()
{
#ifdef QT_GL_SHARED_SHADER_DEBUG
qDebug(" -> ~QOpenGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread());
#endif
qDeleteAll(shaders);
shaders.clear();
qDeleteAll(cachedPrograms);
cachedPrograms.clear();
if (blitShaderProg) {
delete blitShaderProg;
blitShaderProg = 0;
}
if (simpleShaderProg) {
delete simpleShaderProg;
simpleShaderProg = 0;
}
}
#if defined (QT_DEBUG)
QByteArray QOpenGLEngineSharedShaders::snippetNameStr(SnippetName name)
{
QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("SnippetName"));
return QByteArray(m.valueToKey(name));
}
#endif
// The address returned here will only be valid until next time this function is called.
// The program is return bound.
QOpenGLEngineShaderProg *QOpenGLEngineSharedShaders::findProgramInCache(const QOpenGLEngineShaderProg &prog)
{
for (int i = 0; i < cachedPrograms.size(); ++i) {
QOpenGLEngineShaderProg *cachedProg = cachedPrograms[i];
if (*cachedProg == prog) {
// Move the program to the top of the list as a poor-man's cache algo
cachedPrograms.move(i, 0);
cachedProg->program->bind();
return cachedProg;
}
}
QScopedPointer<QOpenGLEngineShaderProg> newProg;
do {
QByteArray fragSource;
// Insert the custom stage before the srcPixel shader to work around an ATI driver bug
// where you cannot forward declare a function that takes a sampler as argument.
if (prog.srcPixelFragShader == CustomImageSrcFragmentShader)
fragSource.append(prog.customStageSource);
fragSource.append(qShaderSnippets[prog.mainFragShader]);
fragSource.append(qShaderSnippets[prog.srcPixelFragShader]);
if (prog.compositionFragShader)
fragSource.append(qShaderSnippets[prog.compositionFragShader]);
if (prog.maskFragShader)
fragSource.append(qShaderSnippets[prog.maskFragShader]);
QByteArray vertexSource;
vertexSource.append(qShaderSnippets[prog.mainVertexShader]);
vertexSource.append(qShaderSnippets[prog.positionVertexShader]);
QScopedPointer<QOpenGLShaderProgram> shaderProgram(new QOpenGLShaderProgram);
CachedShader shaderCache(fragSource, vertexSource);
bool inCache = shaderCache.load(shaderProgram.data(), QOpenGLContext::currentContext());
if (!inCache) {
QScopedPointer<QOpenGLShader> fragShader(new QOpenGLShader(QOpenGLShader::Fragment));
QByteArray description;
#if defined(QT_DEBUG)
// Name the shader for easier debugging
description.append("Fragment shader: main=");
description.append(snippetNameStr(prog.mainFragShader));
description.append(", srcPixel=");
description.append(snippetNameStr(prog.srcPixelFragShader));
if (prog.compositionFragShader) {
description.append(", composition=");
description.append(snippetNameStr(prog.compositionFragShader));
}
if (prog.maskFragShader) {
description.append(", mask=");
description.append(snippetNameStr(prog.maskFragShader));
}
fragShader->setObjectName(QString::fromLatin1(description));
#endif
if (!fragShader->compileSourceCode(fragSource)) {
qWarning() << "Warning:" << description << "failed to compile!";
break;
}
QScopedPointer<QOpenGLShader> vertexShader(new QOpenGLShader(QOpenGLShader::Vertex));
#if defined(QT_DEBUG)
// Name the shader for easier debugging
description.clear();
description.append("Vertex shader: main=");
description.append(snippetNameStr(prog.mainVertexShader));
description.append(", position=");
description.append(snippetNameStr(prog.positionVertexShader));
vertexShader->setObjectName(QString::fromLatin1(description));
#endif
if (!vertexShader->compileSourceCode(vertexSource)) {
qWarning() << "Warning:" << description << "failed to compile!";
break;
}
shaders.append(vertexShader.data());
shaders.append(fragShader.data());
shaderProgram->addShader(vertexShader.take());
shaderProgram->addShader(fragShader.take());
// We have to bind the vertex attribute names before the program is linked:
shaderProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
if (prog.useTextureCoords)
shaderProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
if (prog.useOpacityAttribute)
shaderProgram->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
if (prog.usePmvMatrixAttribute) {
shaderProgram->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
shaderProgram->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
shaderProgram->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
}
}
newProg.reset(new QOpenGLEngineShaderProg(prog));
newProg->program = shaderProgram.take();
newProg->program->link();
if (newProg->program->isLinked()) {
if (!inCache)
shaderCache.store(newProg->program, QOpenGLContext::currentContext());
} else {
QLatin1String none("none");
QLatin1String br("\n");
QString error;
error = QLatin1String("Shader program failed to link,");
#if defined(QT_DEBUG)
error += QLatin1String("\n Shaders Used:\n");
for (int i = 0; i < newProg->program->shaders().count(); ++i) {
QOpenGLShader *shader = newProg->program->shaders().at(i);
error += QLatin1String(" ") + shader->objectName() + QLatin1String(": \n")
+ QLatin1String(shader->sourceCode()) + br;
}
#endif
error += QLatin1String(" Error Log:\n")
+ QLatin1String(" ") + newProg->program->log();
qWarning() << error;
break;
}
newProg->program->bind();
if (newProg->maskFragShader != QOpenGLEngineSharedShaders::NoMaskFragmentShader) {
GLuint location = newProg->program->uniformLocation("maskTexture");
newProg->program->setUniformValue(location, QT_MASK_TEXTURE_UNIT);
}
if (cachedPrograms.count() > 30) {
// The cache is full, so delete the last 5 programs in the list.
// These programs will be least used, as a program us bumped to
// the top of the list when it's used.
for (int i = 0; i < 5; ++i) {
delete cachedPrograms.last();
cachedPrograms.removeLast();
}
}
cachedPrograms.insert(0, newProg.data());
} while (false);
return newProg.take();
}
void QOpenGLEngineSharedShaders::cleanupCustomStage(QOpenGLCustomShaderStage* stage)
{
// Remove any shader programs which has this as the custom shader src:
for (int i = 0; i < cachedPrograms.size(); ++i) {
QOpenGLEngineShaderProg *cachedProg = cachedPrograms[i];
if (cachedProg->customStageSource == stage->source()) {
delete cachedProg;
cachedPrograms.removeAt(i);
i--;
}
}
}
QOpenGLEngineShaderManager::QOpenGLEngineShaderManager(QOpenGLContext* context)
: ctx(context),
shaderProgNeedsChanging(true),
complexGeometry(false),
srcPixelType(Qt::NoBrush),
opacityMode(NoOpacity),
maskType(NoMask),
compositionMode(QPainter::CompositionMode_SourceOver),
customSrcStage(0),
currentShaderProg(0)
{
sharedShaders = QOpenGLEngineSharedShaders::shadersForContext(context);
}
QOpenGLEngineShaderManager::~QOpenGLEngineShaderManager()
{
//###
removeCustomStage();
}
GLuint QOpenGLEngineShaderManager::getUniformLocation(Uniform id)
{
if (!currentShaderProg)
return 0;
QVector<uint> &uniformLocations = currentShaderProg->uniformLocations;
if (uniformLocations.isEmpty())
uniformLocations.fill(GLuint(-1), NumUniforms);
static const char *uniformNames[] = {
"imageTexture",
"patternColor",
"globalOpacity",
"depth",
"maskTexture",
"fragmentColor",
"linearData",
"angle",
"halfViewportSize",
"fmp",
"fmp2_m_radius2",
"inverse_2_fmp2_m_radius2",
"sqrfr",
"bradius",
"invertedTextureSize",
"brushTransform",
"brushTexture",
"matrix"
};
if (uniformLocations.at(id) == GLuint(-1))
uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformNames[id]);
return uniformLocations.at(id);
}
void QOpenGLEngineShaderManager::optimiseForBrushTransform(QTransform::TransformationType transformType)
{
Q_UNUSED(transformType); // Currently ignored
}
void QOpenGLEngineShaderManager::setDirty()
{
shaderProgNeedsChanging = true;
}
void QOpenGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style)
{
Q_ASSERT(style != Qt::NoBrush);
if (srcPixelType == PixelSrcType(style))
return;
srcPixelType = style;
shaderProgNeedsChanging = true; //###
}
void QOpenGLEngineShaderManager::setSrcPixelType(PixelSrcType type)
{
if (srcPixelType == type)
return;
srcPixelType = type;
shaderProgNeedsChanging = true; //###
}
void QOpenGLEngineShaderManager::setOpacityMode(OpacityMode mode)
{
if (opacityMode == mode)
return;
opacityMode = mode;
shaderProgNeedsChanging = true; //###
}
void QOpenGLEngineShaderManager::setMaskType(MaskType type)
{
if (maskType == type)
return;
maskType = type;
shaderProgNeedsChanging = true; //###
}
void QOpenGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode)
{
if (compositionMode == mode)
return;
compositionMode = mode;
shaderProgNeedsChanging = true; //###
}
void QOpenGLEngineShaderManager::setCustomStage(QOpenGLCustomShaderStage* stage)
{
if (customSrcStage)
removeCustomStage();
customSrcStage = stage;
shaderProgNeedsChanging = true;
}
void QOpenGLEngineShaderManager::removeCustomStage()
{
if (customSrcStage)
customSrcStage->setInactive();
customSrcStage = 0;
shaderProgNeedsChanging = true;
}
QOpenGLShaderProgram* QOpenGLEngineShaderManager::currentProgram()
{
if (currentShaderProg)
return currentShaderProg->program;
else
return sharedShaders->simpleProgram();
}
void QOpenGLEngineShaderManager::useSimpleProgram()
{
sharedShaders->simpleProgram()->bind();
QOpenGLContextPrivate* ctx_d = ctx->d_func();
Q_UNUSED(ctx_d);
QOpenGL2PaintEngineEx *active_engine = static_cast<QOpenGL2PaintEngineEx *>(ctx_d->active_engine);
active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false);
active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
shaderProgNeedsChanging = true;
}
void QOpenGLEngineShaderManager::useBlitProgram()
{
sharedShaders->blitProgram()->bind();
QOpenGLContextPrivate* ctx_d = ctx->d_func();
QOpenGL2PaintEngineEx *active_engine = static_cast<QOpenGL2PaintEngineEx *>(ctx_d->active_engine);
active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true);
active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
shaderProgNeedsChanging = true;
}
QOpenGLShaderProgram* QOpenGLEngineShaderManager::simpleProgram()
{
return sharedShaders->simpleProgram();
}
QOpenGLShaderProgram* QOpenGLEngineShaderManager::blitProgram()
{
return sharedShaders->blitProgram();
}
// Select & use the correct shader program using the current state.
// Returns true if program needed changing.
bool QOpenGLEngineShaderManager::useCorrectShaderProg()
{
if (!shaderProgNeedsChanging)
return false;
bool useCustomSrc = customSrcStage != 0;
if (useCustomSrc && srcPixelType != QOpenGLEngineShaderManager::ImageSrc && srcPixelType != Qt::TexturePattern) {
useCustomSrc = false;
qWarning("QOpenGLEngineShaderManager - Ignoring custom shader stage for non image src");
}
QOpenGLEngineShaderProg requiredProgram;
bool texCoords = false;
// Choose vertex shader shader position function (which typically also sets
// varyings) and the source pixel (srcPixel) fragment shader function:
requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::InvalidSnippetName;
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::InvalidSnippetName;
bool isAffine = brushTransform.isAffine();
if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) {
if (isAffine)
requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader;
else
requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionWithPatternBrushVertexShader;
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::PatternBrushSrcFragmentShader;
}
else switch (srcPixelType) {
default:
case Qt::NoBrush:
qFatal("QOpenGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set");
break;
case QOpenGLEngineShaderManager::ImageSrc:
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ImageSrcFragmentShader;
requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader;
texCoords = true;
break;
case QOpenGLEngineShaderManager::NonPremultipliedImageSrc:
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader;
requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader;
texCoords = true;
break;
case QOpenGLEngineShaderManager::PatternSrc:
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ImageSrcWithPatternFragmentShader;
requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader;
texCoords = true;
break;
case QOpenGLEngineShaderManager::TextureSrcWithPattern:
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader;
requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
: QOpenGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
break;
case Qt::SolidPattern:
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::SolidBrushSrcFragmentShader;
requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader;
break;
case Qt::LinearGradientPattern:
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader;
requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader
: QOpenGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader;
break;
case Qt::ConicalGradientPattern:
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader;
requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader
: QOpenGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader;
break;
case Qt::RadialGradientPattern:
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader;
requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader
: QOpenGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader;
break;
case Qt::TexturePattern:
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::TextureBrushSrcFragmentShader;
requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
: QOpenGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
break;
};
if (useCustomSrc) {
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::CustomImageSrcFragmentShader;
requiredProgram.customStageSource = customSrcStage->source();
}
const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus;
const bool hasMask = maskType != QOpenGLEngineShaderManager::NoMask;
// Choose fragment shader main function:
if (opacityMode == AttributeOpacity) {
Q_ASSERT(!hasCompose && !hasMask);
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_ImageArrays;
} else {
bool useGlobalOpacity = (opacityMode == UniformOpacity);
if (hasCompose && hasMask && useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CMO;
if (hasCompose && hasMask && !useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CM;
if (!hasCompose && hasMask && useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_MO;
if (!hasCompose && hasMask && !useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_M;
if (hasCompose && !hasMask && useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CO;
if (hasCompose && !hasMask && !useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_C;
if (!hasCompose && !hasMask && useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_O;
if (!hasCompose && !hasMask && !useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader;
}
if (hasMask) {
if (maskType == PixelMask) {
requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::MaskFragmentShader;
texCoords = true;
} else if (maskType == SubPixelMaskPass1) {
requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::RgbMaskFragmentShaderPass1;
texCoords = true;
} else if (maskType == SubPixelMaskPass2) {
requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::RgbMaskFragmentShaderPass2;
texCoords = true;
} else if (maskType == SubPixelWithGammaMask) {
requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::RgbMaskWithGammaFragmentShader;
texCoords = true;
} else {
qCritical("QOpenGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type");
}
} else {
requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::NoMaskFragmentShader;
}
if (hasCompose) {
switch (compositionMode) {
case QPainter::CompositionMode_Multiply:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::MultiplyCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Screen:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ScreenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Overlay:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::OverlayCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Darken:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::DarkenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Lighten:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::LightenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_ColorDodge:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_ColorBurn:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_HardLight:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::HardLightCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_SoftLight:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::SoftLightCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Difference:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::DifferenceCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Exclusion:
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ExclusionCompositionModeFragmentShader;
break;
default:
qWarning("QOpenGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode");
}
} else {
requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::NoCompositionModeFragmentShader;
}
// Choose vertex shader main function
if (opacityMode == AttributeOpacity) {
Q_ASSERT(texCoords);
requiredProgram.mainVertexShader = QOpenGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader;
} else if (texCoords) {
requiredProgram.mainVertexShader = QOpenGLEngineSharedShaders::MainWithTexCoordsVertexShader;
} else {
requiredProgram.mainVertexShader = QOpenGLEngineSharedShaders::MainVertexShader;
}
requiredProgram.useTextureCoords = texCoords;
requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);
if (complexGeometry && srcPixelType == Qt::SolidPattern) {
requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::ComplexGeometryPositionOnlyVertexShader;
requiredProgram.usePmvMatrixAttribute = false;
} else {
requiredProgram.usePmvMatrixAttribute = true;
// Force complexGeometry off, since we currently don't support that mode for
// non-solid brushes
complexGeometry = false;
}
// At this point, requiredProgram is fully populated so try to find the program in the cache
currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
if (currentShaderProg && useCustomSrc) {
customSrcStage->setUniforms(currentShaderProg->program);
}
// Make sure all the vertex attribute arrays the program uses are enabled (and the ones it
// doesn't use are disabled)
QOpenGLContextPrivate* ctx_d = ctx->d_func();
QOpenGL2PaintEngineEx *active_engine = static_cast<QOpenGL2PaintEngineEx *>(ctx_d->active_engine);
active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, currentShaderProg && currentShaderProg->useTextureCoords);
active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, currentShaderProg && currentShaderProg->useOpacityAttribute);
shaderProgNeedsChanging = false;
return true;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,514 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
/*
VERTEX SHADERS
==============
Vertex shaders are specified as multiple (partial) shaders. On desktop,
this works fine. On ES, QOpenGLShader & QOpenGLShaderProgram will make partial
shaders work by concatenating the source in each QOpenGLShader and compiling
it as a single shader. This is abstracted nicely by QOpenGLShaderProgram and
the GL2 engine doesn't need to worry about it.
Generally, there's two vertex shader objects. The position shaders are
the ones which set gl_Position. There's also two "main" vertex shaders,
one which just calls the position shader and another which also passes
through some texture coordinates from a vertex attribute array to a
varying. These texture coordinates are used for mask position in text
rendering and for the source coordinates in drawImage/drawPixmap. There's
also a "Simple" vertex shader for rendering a solid colour (used to render
into the stencil buffer where the actual colour value is discarded).
The position shaders for brushes look scary. This is because many of the
calculations which logically belong in the fragment shader have been moved
into the vertex shader to improve performance. This is why the position
calculation is in a separate shader. Not only does it calculate the
position, but it also calculates some data to be passed to the fragment
shader as a varying. It is optimal to move as much of the calculation as
possible into the vertex shader as this is executed less often.
The varyings passed to the fragment shaders are interpolated (which is
cheap). Unfortunately, GL will apply perspective correction to the
interpolation calusing errors. To get around this, the vertex shader must
apply perspective correction itself and set the w-value of gl_Position to
zero. That way, GL will be tricked into thinking it doesn't need to apply a
perspective correction and use linear interpolation instead (which is what
we want). Of course, if the brush transform is affeine, no perspective
correction is needed and a simpler vertex shader can be used instead.
So there are the following "main" vertex shaders:
qopenglslMainVertexShader
qopenglslMainWithTexCoordsVertexShader
And the the following position vertex shaders:
qopenglslPositionOnlyVertexShader
qopenglslPositionWithTextureBrushVertexShader
qopenglslPositionWithPatternBrushVertexShader
qopenglslPositionWithLinearGradientBrushVertexShader
qopenglslPositionWithRadialGradientBrushVertexShader
qopenglslPositionWithConicalGradientBrushVertexShader
qopenglslAffinePositionWithTextureBrushVertexShader
qopenglslAffinePositionWithPatternBrushVertexShader
qopenglslAffinePositionWithLinearGradientBrushVertexShader
qopenglslAffinePositionWithRadialGradientBrushVertexShader
qopenglslAffinePositionWithConicalGradientBrushVertexShader
Leading to 23 possible vertex shaders
FRAGMENT SHADERS
================
Fragment shaders are also specified as multiple (partial) shaders. The
different fragment shaders represent the different stages in Qt's fragment
pipeline. There are 1-3 stages in this pipeline: First stage is to get the
fragment's colour value. The next stage is to get the fragment's mask value
(coverage value for anti-aliasing) and the final stage is to blend the
incoming fragment with the background (for composition modes not supported
by GL).
Of these, the first stage will always be present. If Qt doesn't need to
apply anti-aliasing (because it's off or handled by multisampling) then
the coverage value doesn't need to be applied. (Note: There are two types
of mask, one for regular anti-aliasing and one for sub-pixel anti-
aliasing.) If the composition mode is one which GL supports natively then
the blending stage doesn't need to be applied.
As eash stage can have multiple implementations, they are abstracted as
GLSL function calls with the following signatures:
Brushes & image drawing are implementations of "qcolorp vec4 srcPixel()":
qopenglslImageSrcFragShader
qopenglslImageSrcWithPatternFragShader
qopenglslNonPremultipliedImageSrcFragShader
qopenglslSolidBrushSrcFragShader
qopenglslTextureBrushSrcFragShader
qopenglslTextureBrushWithPatternFragShader
qopenglslPatternBrushSrcFragShader
qopenglslLinearGradientBrushSrcFragShader
qopenglslRadialGradientBrushSrcFragShader
qopenglslConicalGradientBrushSrcFragShader
NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied
Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)":
qopenglslMaskFragmentShader
qopenglslRgbMaskFragmentShaderPass1
qopenglslRgbMaskFragmentShaderPass2
qopenglslRgbMaskWithGammaFragmentShader
Composition modes are "qcolorp vec4 compose(qcolorp vec4 src)":
qopenglslColorBurnCompositionModeFragmentShader
qopenglslColorDodgeCompositionModeFragmentShader
qopenglslDarkenCompositionModeFragmentShader
qopenglslDifferenceCompositionModeFragmentShader
qopenglslExclusionCompositionModeFragmentShader
qopenglslHardLightCompositionModeFragmentShader
qopenglslLightenCompositionModeFragmentShader
qopenglslMultiplyCompositionModeFragmentShader
qopenglslOverlayCompositionModeFragmentShader
qopenglslScreenCompositionModeFragmentShader
qopenglslSoftLightCompositionModeFragmentShader
Note: In the future, some GLSL compilers will support an extension allowing
a new 'color' precision specifier. To support this, qcolorp is used for
all color components so it can be defined to colorp or lowp depending upon
the implementation.
So there are differnt frament shader main functions, depending on the
number & type of pipelines the fragment needs to go through.
The choice of which main() fragment shader string to use depends on:
- Use of global opacity
- Brush style (some brushes apply opacity themselves)
- Use & type of mask (TODO: Need to support high quality anti-aliasing & text)
- Use of non-GL Composition mode
Leading to the following fragment shader main functions:
gl_FragColor = compose(applyMask(srcPixel()*globalOpacity));
gl_FragColor = compose(applyMask(srcPixel()));
gl_FragColor = applyMask(srcPixel()*globalOpacity);
gl_FragColor = applyMask(srcPixel());
gl_FragColor = compose(srcPixel()*globalOpacity);
gl_FragColor = compose(srcPixel());
gl_FragColor = srcPixel()*globalOpacity;
gl_FragColor = srcPixel();
Called:
qopenglslMainFragmentShader_CMO
qopenglslMainFragmentShader_CM
qopenglslMainFragmentShader_MO
qopenglslMainFragmentShader_M
qopenglslMainFragmentShader_CO
qopenglslMainFragmentShader_C
qopenglslMainFragmentShader_O
qopenglslMainFragmentShader
Where:
M = Mask
C = Composition
O = Global Opacity
CUSTOM SHADER CODE
==================
The use of custom shader code is supported by the engine for drawImage and
drawPixmap calls. This is implemented via hooks in the fragment pipeline.
The custom shader is passed to the engine as a partial fragment shader
(QOpenGLCustomShaderStage). The shader will implement a pre-defined method name
which Qt's fragment pipeline will call:
lowp vec4 customShader(lowp sampler2d imageTexture, highp vec2 textureCoords)
The provided src and srcCoords parameters can be used to sample from the
source image.
Transformations, clipping, opacity, and composition modes set using QPainter
will be respected when using the custom shader hook.
*/
#ifndef QOPENGLENGINE_SHADER_MANAGER_H
#define QOPENGLENGINE_SHADER_MANAGER_H
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include <QPainter>
#include <private/qopenglcontext_p.h>
#include <private/qopenglcustomshaderstage_p.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
/*
struct QOpenGLEngineCachedShaderProg
{
QOpenGLEngineCachedShaderProg(QOpenGLEngineShaderManager::ShaderName vertexMain,
QOpenGLEngineShaderManager::ShaderName vertexPosition,
QOpenGLEngineShaderManager::ShaderName fragMain,
QOpenGLEngineShaderManager::ShaderName pixelSrc,
QOpenGLEngineShaderManager::ShaderName mask,
QOpenGLEngineShaderManager::ShaderName composition);
int cacheKey;
QOpenGLShaderProgram* program;
}
*/
static const GLuint QT_VERTEX_COORDS_ATTR = 0;
static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
static const GLuint QT_OPACITY_ATTR = 2;
static const GLuint QT_PMV_MATRIX_1_ATTR = 3;
static const GLuint QT_PMV_MATRIX_2_ATTR = 4;
static const GLuint QT_PMV_MATRIX_3_ATTR = 5;
class QOpenGLEngineShaderProg;
class Q_GUI_EXPORT QOpenGLEngineSharedShaders
{
Q_GADGET
public:
enum SnippetName {
MainVertexShader,
MainWithTexCoordsVertexShader,
MainWithTexCoordsAndOpacityVertexShader,
// UntransformedPositionVertexShader must be first in the list:
UntransformedPositionVertexShader,
PositionOnlyVertexShader,
ComplexGeometryPositionOnlyVertexShader,
PositionWithPatternBrushVertexShader,
PositionWithLinearGradientBrushVertexShader,
PositionWithConicalGradientBrushVertexShader,
PositionWithRadialGradientBrushVertexShader,
PositionWithTextureBrushVertexShader,
AffinePositionWithPatternBrushVertexShader,
AffinePositionWithLinearGradientBrushVertexShader,
AffinePositionWithConicalGradientBrushVertexShader,
AffinePositionWithRadialGradientBrushVertexShader,
AffinePositionWithTextureBrushVertexShader,
// MainFragmentShader_CMO must be first in the list:
MainFragmentShader_CMO,
MainFragmentShader_CM,
MainFragmentShader_MO,
MainFragmentShader_M,
MainFragmentShader_CO,
MainFragmentShader_C,
MainFragmentShader_O,
MainFragmentShader,
MainFragmentShader_ImageArrays,
// ImageSrcFragmentShader must be first in the list::
ImageSrcFragmentShader,
ImageSrcWithPatternFragmentShader,
NonPremultipliedImageSrcFragmentShader,
CustomImageSrcFragmentShader,
SolidBrushSrcFragmentShader,
TextureBrushSrcFragmentShader,
TextureBrushSrcWithPatternFragmentShader,
PatternBrushSrcFragmentShader,
LinearGradientBrushSrcFragmentShader,
RadialGradientBrushSrcFragmentShader,
ConicalGradientBrushSrcFragmentShader,
ShockingPinkSrcFragmentShader,
// NoMaskFragmentShader must be first in the list:
NoMaskFragmentShader,
MaskFragmentShader,
RgbMaskFragmentShaderPass1,
RgbMaskFragmentShaderPass2,
RgbMaskWithGammaFragmentShader,
// NoCompositionModeFragmentShader must be first in the list:
NoCompositionModeFragmentShader,
MultiplyCompositionModeFragmentShader,
ScreenCompositionModeFragmentShader,
OverlayCompositionModeFragmentShader,
DarkenCompositionModeFragmentShader,
LightenCompositionModeFragmentShader,
ColorDodgeCompositionModeFragmentShader,
ColorBurnCompositionModeFragmentShader,
HardLightCompositionModeFragmentShader,
SoftLightCompositionModeFragmentShader,
DifferenceCompositionModeFragmentShader,
ExclusionCompositionModeFragmentShader,
TotalSnippetCount, InvalidSnippetName
};
#if defined (QT_DEBUG)
Q_ENUMS(SnippetName)
static QByteArray snippetNameStr(SnippetName snippetName);
#endif
/*
// These allow the ShaderName enum to be used as a cache key
const int mainVertexOffset = 0;
const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader;
const int mainFragOffset = (1<<6) - MainFragmentShader_CMO;
const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader;
const int maskOffset = (1<<14) - NoMaskShader;
const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader;
*/
QOpenGLEngineSharedShaders(QOpenGLContext *context);
~QOpenGLEngineSharedShaders();
QOpenGLShaderProgram *simpleProgram() { return simpleShaderProg; }
QOpenGLShaderProgram *blitProgram() { return blitShaderProg; }
// Compile the program if it's not already in the cache, return the item in the cache.
QOpenGLEngineShaderProg *findProgramInCache(const QOpenGLEngineShaderProg &prog);
// Compile the custom shader if it's not already in the cache, return the item in the cache.
static QOpenGLEngineSharedShaders *shadersForContext(QOpenGLContext *context);
// Ideally, this would be static and cleanup all programs in all contexts which
// contain the custom code. Currently it is just a hint and we rely on deleted
// custom shaders being cleaned up by being kicked out of the cache when it's
// full.
void cleanupCustomStage(QOpenGLCustomShaderStage* stage);
private:
QOpenGLShaderProgram *blitShaderProg;
QOpenGLShaderProgram *simpleShaderProg;
QList<QOpenGLEngineShaderProg*> cachedPrograms;
QList<QOpenGLShader *> shaders;
static const char* qShaderSnippets[TotalSnippetCount];
};
class QOpenGLEngineShaderProg
{
public:
QOpenGLEngineShaderProg() : program(0) {}
~QOpenGLEngineShaderProg() {
if (program)
delete program;
}
QOpenGLEngineSharedShaders::SnippetName mainVertexShader;
QOpenGLEngineSharedShaders::SnippetName positionVertexShader;
QOpenGLEngineSharedShaders::SnippetName mainFragShader;
QOpenGLEngineSharedShaders::SnippetName srcPixelFragShader;
QOpenGLEngineSharedShaders::SnippetName maskFragShader;
QOpenGLEngineSharedShaders::SnippetName compositionFragShader;
QByteArray customStageSource; //TODO: Decent cache key for custom stages
QOpenGLShaderProgram* program;
QVector<uint> uniformLocations;
bool useTextureCoords;
bool useOpacityAttribute;
bool usePmvMatrixAttribute;
bool operator==(const QOpenGLEngineShaderProg& other) {
// We don't care about the program
return ( mainVertexShader == other.mainVertexShader &&
positionVertexShader == other.positionVertexShader &&
mainFragShader == other.mainFragShader &&
srcPixelFragShader == other.srcPixelFragShader &&
maskFragShader == other.maskFragShader &&
compositionFragShader == other.compositionFragShader &&
customStageSource == other.customStageSource
);
}
};
class Q_GUI_EXPORT QOpenGLEngineShaderManager : public QObject
{
Q_OBJECT
public:
QOpenGLEngineShaderManager(QOpenGLContext* context);
~QOpenGLEngineShaderManager();
enum MaskType {NoMask, PixelMask, SubPixelMaskPass1, SubPixelMaskPass2, SubPixelWithGammaMask};
enum PixelSrcType {
ImageSrc = Qt::TexturePattern+1,
NonPremultipliedImageSrc = Qt::TexturePattern+2,
PatternSrc = Qt::TexturePattern+3,
TextureSrcWithPattern = Qt::TexturePattern+4
};
enum Uniform {
ImageTexture,
PatternColor,
GlobalOpacity,
Depth,
MaskTexture,
FragmentColor,
LinearData,
Angle,
HalfViewportSize,
Fmp,
Fmp2MRadius2,
Inverse2Fmp2MRadius2,
SqrFr,
BRadius,
InvertedTextureSize,
BrushTransform,
BrushTexture,
Matrix,
NumUniforms
};
enum OpacityMode {
NoOpacity,
UniformOpacity,
AttributeOpacity
};
// There are optimizations we can do, depending on the brush transform:
// 1) May not have to apply perspective-correction
// 2) Can use lower precision for matrix
void optimiseForBrushTransform(QTransform::TransformationType transformType);
void setSrcPixelType(Qt::BrushStyle);
void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images
void setOpacityMode(OpacityMode);
void setMaskType(MaskType);
void setCompositionMode(QPainter::CompositionMode);
void setCustomStage(QOpenGLCustomShaderStage* stage);
void removeCustomStage();
GLuint getUniformLocation(Uniform id);
void setDirty(); // someone has manually changed the current shader program
bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
void useSimpleProgram();
void useBlitProgram();
void setHasComplexGeometry(bool hasComplexGeometry)
{
complexGeometry = hasComplexGeometry;
shaderProgNeedsChanging = true;
}
bool hasComplexGeometry() const
{
return complexGeometry;
}
QOpenGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
QOpenGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
QOpenGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
QOpenGLEngineSharedShaders* sharedShaders;
private:
QOpenGLContext* ctx;
bool shaderProgNeedsChanging;
bool complexGeometry;
// Current state variables which influence the choice of shader:
QTransform brushTransform;
int srcPixelType;
OpacityMode opacityMode;
MaskType maskType;
QPainter::CompositionMode compositionMode;
QOpenGLCustomShaderStage* customSrcStage;
QOpenGLEngineShaderProg* currentShaderProg;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif //QOPENGLENGINE_SHADER_MANAGER_H

View File

@ -0,0 +1,529 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#ifndef QOPENGL_ENGINE_SHADER_SOURCE_H
#define QOPENGL_ENGINE_SHADER_SOURCE_H
#include "qopenglengineshadermanager_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
static const char* const qopenglslMainVertexShader = "\n\
void setPosition(); \n\
void main(void) \n\
{ \n\
setPosition(); \n\
}\n";
static const char* const qopenglslMainWithTexCoordsVertexShader = "\n\
attribute highp vec2 textureCoordArray; \n\
varying highp vec2 textureCoords; \n\
void setPosition(); \n\
void main(void) \n\
{ \n\
setPosition(); \n\
textureCoords = textureCoordArray; \n\
}\n";
static const char* const qopenglslMainWithTexCoordsAndOpacityVertexShader = "\n\
attribute highp vec2 textureCoordArray; \n\
attribute lowp float opacityArray; \n\
varying highp vec2 textureCoords; \n\
varying lowp float opacity; \n\
void setPosition(); \n\
void main(void) \n\
{ \n\
setPosition(); \n\
textureCoords = textureCoordArray; \n\
opacity = opacityArray; \n\
}\n";
// NOTE: We let GL do the perspective correction so texture lookups in the fragment
// shader are also perspective corrected.
static const char* const qopenglslPositionOnlyVertexShader = "\n\
attribute highp vec2 vertexCoordsArray; \n\
attribute highp vec3 pmvMatrix1; \n\
attribute highp vec3 pmvMatrix2; \n\
attribute highp vec3 pmvMatrix3; \n\
void setPosition(void) \n\
{ \n\
highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
gl_Position = vec4(transformedPos.xy, 0.0, transformedPos.z); \n\
}\n";
static const char* const qopenglslComplexGeometryPositionOnlyVertexShader = "\n\
uniform highp mat3 matrix; \n\
attribute highp vec2 vertexCoordsArray; \n\
void setPosition(void) \n\
{ \n\
gl_Position = vec4(matrix * vec3(vertexCoordsArray, 1), 1);\n\
} \n";
static const char* const qopenglslUntransformedPositionVertexShader = "\n\
attribute highp vec4 vertexCoordsArray; \n\
void setPosition(void) \n\
{ \n\
gl_Position = vertexCoordsArray; \n\
}\n";
// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125
static const char* const qopenglslPositionWithPatternBrushVertexShader = "\n\
attribute highp vec2 vertexCoordsArray; \n\
attribute highp vec3 pmvMatrix1; \n\
attribute highp vec3 pmvMatrix2; \n\
attribute highp vec3 pmvMatrix3; \n\
uniform mediump vec2 halfViewportSize; \n\
uniform highp vec2 invertedTextureSize; \n\
uniform highp mat3 brushTransform; \n\
varying highp vec2 patternTexCoords; \n\
void setPosition(void) \n\
{ \n\
highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1.0); \n\
mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \n\
}\n";
static const char* const qopenglslAffinePositionWithPatternBrushVertexShader
= qopenglslPositionWithPatternBrushVertexShader;
static const char* const qopenglslPatternBrushSrcFragmentShader = "\n\
uniform sampler2D brushTexture; \n\
uniform lowp vec4 patternColor; \n\
varying highp vec2 patternTexCoords;\n\
lowp vec4 srcPixel() \n\
{ \n\
return patternColor * (1.0 - texture2D(brushTexture, patternTexCoords).r); \n\
}\n";
// Linear Gradient Brush
static const char* const qopenglslPositionWithLinearGradientBrushVertexShader = "\n\
attribute highp vec2 vertexCoordsArray; \n\
attribute highp vec3 pmvMatrix1; \n\
attribute highp vec3 pmvMatrix2; \n\
attribute highp vec3 pmvMatrix3; \n\
uniform mediump vec2 halfViewportSize; \n\
uniform highp vec3 linearData; \n\
uniform highp mat3 brushTransform; \n\
varying mediump float index; \n\
void setPosition() \n\
{ \n\
highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \n\
}\n";
static const char* const qopenglslAffinePositionWithLinearGradientBrushVertexShader
= qopenglslPositionWithLinearGradientBrushVertexShader;
static const char* const qopenglslLinearGradientBrushSrcFragmentShader = "\n\
uniform sampler2D brushTexture; \n\
varying mediump float index; \n\
lowp vec4 srcPixel() \n\
{ \n\
mediump vec2 val = vec2(index, 0.5); \n\
return texture2D(brushTexture, val); \n\
}\n";
// Conical Gradient Brush
static const char* const qopenglslPositionWithConicalGradientBrushVertexShader = "\n\
attribute highp vec2 vertexCoordsArray; \n\
attribute highp vec3 pmvMatrix1; \n\
attribute highp vec3 pmvMatrix2; \n\
attribute highp vec3 pmvMatrix3; \n\
uniform mediump vec2 halfViewportSize; \n\
uniform highp mat3 brushTransform; \n\
varying highp vec2 A; \n\
void setPosition(void) \n\
{ \n\
highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
A = hTexCoords.xy * invertedHTexCoordsZ; \n\
}\n";
static const char* const qopenglslAffinePositionWithConicalGradientBrushVertexShader
= qopenglslPositionWithConicalGradientBrushVertexShader;
static const char* const qopenglslConicalGradientBrushSrcFragmentShader = "\n\
#define INVERSE_2PI 0.1591549430918953358 \n\
uniform sampler2D brushTexture; \n\
uniform mediump float angle; \n\
varying highp vec2 A; \n\
lowp vec4 srcPixel() \n\
{ \n\
highp float t; \n\
if (abs(A.y) == abs(A.x)) \n\
t = (atan(-A.y + 0.002, A.x) + angle) * INVERSE_2PI; \n\
else \n\
t = (atan(-A.y, A.x) + angle) * INVERSE_2PI; \n\
return texture2D(brushTexture, vec2(t - floor(t), 0.5)); \n\
}\n";
// Radial Gradient Brush
static const char* const qopenglslPositionWithRadialGradientBrushVertexShader = "\n\
attribute highp vec2 vertexCoordsArray;\n\
attribute highp vec3 pmvMatrix1; \n\
attribute highp vec3 pmvMatrix2; \n\
attribute highp vec3 pmvMatrix3; \n\
uniform mediump vec2 halfViewportSize; \n\
uniform highp mat3 brushTransform; \n\
uniform highp vec2 fmp; \n\
uniform highp vec3 bradius; \n\
varying highp float b; \n\
varying highp vec2 A; \n\
void setPosition(void) \n\
{\n\
highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
A = hTexCoords.xy * invertedHTexCoordsZ; \n\
b = bradius.x + 2.0 * dot(A, fmp); \n\
}\n";
static const char* const qopenglslAffinePositionWithRadialGradientBrushVertexShader
= qopenglslPositionWithRadialGradientBrushVertexShader;
static const char* const qopenglslRadialGradientBrushSrcFragmentShader = "\n\
uniform sampler2D brushTexture; \n\
uniform highp float fmp2_m_radius2; \n\
uniform highp float inverse_2_fmp2_m_radius2; \n\
uniform highp float sqrfr; \n\
varying highp float b; \n\
varying highp vec2 A; \n\
uniform highp vec3 bradius; \n\
lowp vec4 srcPixel() \n\
{ \n\
highp float c = sqrfr-dot(A, A); \n\
highp float det = b*b - 4.0*fmp2_m_radius2*c; \n\
lowp vec4 result = vec4(0.0); \n\
if (det >= 0.0) { \n\
highp float detSqrt = sqrt(det); \n\
highp float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); \n\
if (bradius.y + w * bradius.z >= 0.0) \n\
result = texture2D(brushTexture, vec2(w, 0.5)); \n\
} \n\
return result; \n\
}\n";
// Texture Brush
static const char* const qopenglslPositionWithTextureBrushVertexShader = "\n\
attribute highp vec2 vertexCoordsArray; \n\
attribute highp vec3 pmvMatrix1; \n\
attribute highp vec3 pmvMatrix2; \n\
attribute highp vec3 pmvMatrix3; \n\
uniform mediump vec2 halfViewportSize; \n\
uniform highp vec2 invertedTextureSize; \n\
uniform highp mat3 brushTransform; \n\
varying highp vec2 brushTextureCoords; \n\
void setPosition(void) \n\
{ \n\
highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \n\
}\n";
static const char* const qopenglslAffinePositionWithTextureBrushVertexShader
= qopenglslPositionWithTextureBrushVertexShader;
#if defined(QT_OPENGL_ES_2)
// OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead,
// we emulate GL_REPEAT by only taking the fractional part of the texture coords.
// TODO: Special case POT textures which don't need this emulation
static const char* const qopenglslTextureBrushSrcFragmentShader = "\n\
varying highp vec2 brushTextureCoords; \n\
uniform sampler2D brushTexture; \n\
lowp vec4 srcPixel() { \n\
return texture2D(brushTexture, fract(brushTextureCoords)); \n\
}\n";
#else
static const char* const qopenglslTextureBrushSrcFragmentShader = "\n\
varying highp vec2 brushTextureCoords; \n\
uniform sampler2D brushTexture; \n\
lowp vec4 srcPixel() \n\
{ \n\
return texture2D(brushTexture, brushTextureCoords); \n\
}\n";
#endif
static const char* const qopenglslTextureBrushSrcWithPatternFragmentShader = "\n\
varying highp vec2 brushTextureCoords; \n\
uniform lowp vec4 patternColor; \n\
uniform sampler2D brushTexture; \n\
lowp vec4 srcPixel() \n\
{ \n\
return patternColor * (1.0 - texture2D(brushTexture, brushTextureCoords).r); \n\
}\n";
// Solid Fill Brush
static const char* const qopenglslSolidBrushSrcFragmentShader = "\n\
uniform lowp vec4 fragmentColor; \n\
lowp vec4 srcPixel() \n\
{ \n\
return fragmentColor; \n\
}\n";
static const char* const qopenglslImageSrcFragmentShader = "\n\
varying highp vec2 textureCoords; \n\
uniform sampler2D imageTexture; \n\
lowp vec4 srcPixel() \n\
{ \n"
"return texture2D(imageTexture, textureCoords); \n"
"}\n";
static const char* const qopenglslCustomSrcFragmentShader = "\n\
varying highp vec2 textureCoords; \n\
uniform sampler2D imageTexture; \n\
lowp vec4 srcPixel() \n\
{ \n\
return customShader(imageTexture, textureCoords); \n\
}\n";
static const char* const qopenglslImageSrcWithPatternFragmentShader = "\n\
varying highp vec2 textureCoords; \n\
uniform lowp vec4 patternColor; \n\
uniform sampler2D imageTexture; \n\
lowp vec4 srcPixel() \n\
{ \n\
return patternColor * (1.0 - texture2D(imageTexture, textureCoords).r); \n\
}\n";
static const char* const qopenglslNonPremultipliedImageSrcFragmentShader = "\n\
varying highp vec2 textureCoords; \n\
uniform sampler2D imageTexture; \n\
lowp vec4 srcPixel() \n\
{ \n\
lowp vec4 sample = texture2D(imageTexture, textureCoords); \n\
sample.rgb = sample.rgb * sample.a; \n\
return sample; \n\
}\n";
static const char* const qopenglslShockingPinkSrcFragmentShader = "\n\
lowp vec4 srcPixel() \n\
{ \n\
return vec4(0.98, 0.06, 0.75, 1.0); \n\
}\n";
static const char* const qopenglslMainFragmentShader_ImageArrays = "\n\
varying lowp float opacity; \n\
lowp vec4 srcPixel(); \n\
void main() \n\
{ \n\
gl_FragColor = srcPixel() * opacity; \n\
}\n";
static const char* const qopenglslMainFragmentShader_CMO = "\n\
uniform lowp float globalOpacity; \n\
lowp vec4 srcPixel(); \n\
lowp vec4 applyMask(lowp vec4); \n\
lowp vec4 compose(lowp vec4); \n\
void main() \n\
{ \n\
gl_FragColor = applyMask(compose(srcPixel()*globalOpacity))); \n\
}\n";
static const char* const qopenglslMainFragmentShader_CM = "\n\
lowp vec4 srcPixel(); \n\
lowp vec4 applyMask(lowp vec4); \n\
lowp vec4 compose(lowp vec4); \n\
void main() \n\
{ \n\
gl_FragColor = applyMask(compose(srcPixel())); \n\
}\n";
static const char* const qopenglslMainFragmentShader_MO = "\n\
uniform lowp float globalOpacity; \n\
lowp vec4 srcPixel(); \n\
lowp vec4 applyMask(lowp vec4); \n\
void main() \n\
{ \n\
gl_FragColor = applyMask(srcPixel()*globalOpacity); \n\
}\n";
static const char* const qopenglslMainFragmentShader_M = "\n\
lowp vec4 srcPixel(); \n\
lowp vec4 applyMask(lowp vec4); \n\
void main() \n\
{ \n\
gl_FragColor = applyMask(srcPixel()); \n\
}\n";
static const char* const qopenglslMainFragmentShader_CO = "\n\
uniform lowp float globalOpacity; \n\
lowp vec4 srcPixel(); \n\
lowp vec4 compose(lowp vec4); \n\
void main() \n\
{ \n\
gl_FragColor = compose(srcPixel()*globalOpacity); \n\
}\n";
static const char* const qopenglslMainFragmentShader_C = "\n\
lowp vec4 srcPixel(); \n\
lowp vec4 compose(lowp vec4); \n\
void main() \n\
{ \n\
gl_FragColor = compose(srcPixel()); \n\
}\n";
static const char* const qopenglslMainFragmentShader_O = "\n\
uniform lowp float globalOpacity; \n\
lowp vec4 srcPixel(); \n\
void main() \n\
{ \n\
gl_FragColor = srcPixel()*globalOpacity; \n\
}\n";
static const char* const qopenglslMainFragmentShader = "\n\
lowp vec4 srcPixel(); \n\
void main() \n\
{ \n\
gl_FragColor = srcPixel(); \n\
}\n";
static const char* const qopenglslMaskFragmentShader = "\n\
varying highp vec2 textureCoords;\n\
uniform sampler2D maskTexture;\n\
lowp vec4 applyMask(lowp vec4 src) \n\
{\n\
lowp vec4 mask = texture2D(maskTexture, textureCoords); \n\
return src * mask.a; \n\
}\n";
// For source over with subpixel antialiasing, the final color is calculated per component as follows
// (.a is alpha component, .c is red, green or blue component):
// alpha = src.a * mask.c * opacity
// dest.c = dest.c * (1 - alpha) + src.c * alpha
//
// In the first pass, calculate: dest.c = dest.c * (1 - alpha) with blend funcs: zero, 1 - source color
// In the second pass, calculate: dest.c = dest.c + src.c * alpha with blend funcs: one, one
//
// If source is a solid color (src is constant), only the first pass is needed, with blend funcs: constant, 1 - source color
// For source composition with subpixel antialiasing, the final color is calculated per component as follows:
// alpha = src.a * mask.c * opacity
// dest.c = dest.c * (1 - mask.c) + src.c * alpha
//
static const char* const qopenglslRgbMaskFragmentShaderPass1 = "\n\
varying highp vec2 textureCoords;\n\
uniform sampler2D maskTexture;\n\
lowp vec4 applyMask(lowp vec4 src) \n\
{ \n\
lowp vec4 mask = texture2D(maskTexture, textureCoords); \n\
return src.a * mask; \n\
}\n";
static const char* const qopenglslRgbMaskFragmentShaderPass2 = "\n\
varying highp vec2 textureCoords;\n\
uniform sampler2D maskTexture;\n\
lowp vec4 applyMask(lowp vec4 src) \n\
{ \n\
lowp vec4 mask = texture2D(maskTexture, textureCoords); \n\
return src * mask; \n\
}\n";
/*
Left to implement:
RgbMaskFragmentShader,
RgbMaskWithGammaFragmentShader,
MultiplyCompositionModeFragmentShader,
ScreenCompositionModeFragmentShader,
OverlayCompositionModeFragmentShader,
DarkenCompositionModeFragmentShader,
LightenCompositionModeFragmentShader,
ColorDodgeCompositionModeFragmentShader,
ColorBurnCompositionModeFragmentShader,
HardLightCompositionModeFragmentShader,
SoftLightCompositionModeFragmentShader,
DifferenceCompositionModeFragmentShader,
ExclusionCompositionModeFragmentShader,
*/
QT_END_NAMESPACE
QT_END_HEADER
#endif // GLGC_SHADER_SOURCE_H

View File

@ -0,0 +1,676 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QOPENGL_EXTENSIONS_P_H
#define QOPENGL_EXTENSIONS_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the Qt OpenGL classes. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include "qopenglfunctions.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
#if 0
#ifndef GL_ARB_vertex_buffer_object
typedef ptrdiff_t GLintptrARB;
typedef ptrdiff_t GLsizeiptrARB;
#endif
#endif
#ifndef GL_VERSION_2_0
typedef char GLchar;
#endif
struct QOpenGLExtensionsPrivate;
class Q_GUI_EXPORT QOpenGLExtensions : public QOpenGLFunctions
{
Q_DECLARE_PRIVATE(QOpenGLExtensions)
public:
QOpenGLExtensions();
QOpenGLExtensions(QOpenGLContext *context);
~QOpenGLExtensions() {}
enum OpenGLExtension {
TextureRectangle = 0x00000001,
GenerateMipmap = 0x00000002,
TextureCompression = 0x00000004,
MirroredRepeat = 0x00000008,
FramebufferMultisample = 0x00000010,
StencilTwoSide = 0x00000020,
StencilWrap = 0x00000040,
PackedDepthStencil = 0x00000080,
NVFloatBuffer = 0x00000100,
PixelBufferObject = 0x00000200,
FramebufferBlit = 0x00000400,
BGRATextureFormat = 0x00000800,
DDSTextureCompression = 0x00001000,
ETC1TextureCompression = 0x00002000,
PVRTCTextureCompression = 0x00004000,
ElementIndexUint = 0x00008000,
Depth24 = 0x00010000,
SRGBFrameBuffer = 0x00020000,
MapBuffer = 0x00040000,
GeometryShaders = 0x00080000
};
Q_DECLARE_FLAGS(OpenGLExtensions, OpenGLExtension)
OpenGLExtensions openGLExtensions();
bool hasOpenGLExtension(QOpenGLExtensions::OpenGLExtension extension) const;
void initializeGLExtensions();
GLvoid *glMapBuffer(GLenum target, GLenum access);
GLboolean glUnmapBuffer(GLenum target);
void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void glRenderbufferStorageMultisample(GLenum target, GLsizei samples,
GLenum internalFormat,
GLsizei width, GLsizei height);
void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data);
private:
static bool isInitialized(const QOpenGLFunctionsPrivate *d) { return d != 0; }
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLExtensions::OpenGLExtensions)
struct QOpenGLExtensionsPrivate : public QOpenGLFunctionsPrivate
{
QOpenGLExtensionsPrivate(QOpenGLContext *ctx);
GLvoid* (QOPENGLF_APIENTRYP MapBuffer)(GLenum target, GLenum access);
GLboolean (QOPENGLF_APIENTRYP UnmapBuffer)(GLenum target);
void (QOPENGLF_APIENTRYP BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void (QOPENGLF_APIENTRYP RenderbufferStorageMultisample)(GLenum target, GLsizei samples,
GLenum internalFormat,
GLsizei width, GLsizei height);
void (QOPENGLF_APIENTRYP GetBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data);
};
inline GLvoid *QOpenGLExtensions::glMapBuffer(GLenum target, GLenum access)
{
Q_D(QOpenGLExtensions);
Q_ASSERT(QOpenGLExtensions::isInitialized(d));
GLvoid *result = d->MapBuffer(target, access);
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline GLboolean QOpenGLExtensions::glUnmapBuffer(GLenum target)
{
Q_D(QOpenGLExtensions);
Q_ASSERT(QOpenGLExtensions::isInitialized(d));
GLboolean result = d->UnmapBuffer(target);
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline void QOpenGLExtensions::glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter)
{
Q_D(QOpenGLExtensions);
Q_ASSERT(QOpenGLExtensions::isInitialized(d));
d->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLExtensions::glRenderbufferStorageMultisample(GLenum target, GLsizei samples,
GLenum internalFormat,
GLsizei width, GLsizei height)
{
Q_D(QOpenGLExtensions);
Q_ASSERT(QOpenGLExtensions::isInitialized(d));
d->RenderbufferStorageMultisample(target, samples, internalFormat, width, height);
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLExtensions::glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data)
{
Q_D(QOpenGLExtensions);
Q_ASSERT(QOpenGLExtensions::isInitialized(d));
d->GetBufferSubData(target, offset, size, data);
Q_OPENGL_FUNCTIONS_DEBUG
}
#ifndef GL_FRAMEBUFFER_SRGB_CAPABLE
#define GL_FRAMEBUFFER_SRGB_CAPABLE 0x8DBA
#endif
#ifndef GL_FRAMEBUFFER_SRGB
#define GL_FRAMEBUFFER_SRGB 0x8DB9
#endif
#ifndef GL_ARRAY_BUFFER
#define GL_ARRAY_BUFFER 0x8892
#endif
#ifndef GL_STATIC_DRAW
#define GL_STATIC_DRAW 0x88E4
#endif
#ifndef GL_TEXTURE_RECTANGLE
#define GL_TEXTURE_RECTANGLE 0x84F5
#endif
#ifndef GL_TEXTURE_BINDING_RECTANGLE
#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6
#endif
#ifndef GL_PROXY_TEXTURE_RECTANGLE
#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7
#endif
#ifndef GL_MAX_RECTANGLE_TEXTURE_SIZE
#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8
#endif
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
#ifndef GL_RGB16
#define GL_RGB16 0x8054
#endif
#ifndef GL_UNSIGNED_SHORT_5_6_5
#define GL_UNSIGNED_SHORT_5_6_5 0x8363
#endif
#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
#endif
#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE 0x809D
#endif
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif
#ifndef GL_MIRRORED_REPEAT
#define GL_MIRRORED_REPEAT 0x8370
#endif
#ifndef GL_GENERATE_MIPMAP
#define GL_GENERATE_MIPMAP 0x8191
#endif
#ifndef GL_GENERATE_MIPMAP_HINT
#define GL_GENERATE_MIPMAP_HINT 0x8192
#endif
#ifndef GL_FRAGMENT_PROGRAM
#define GL_FRAGMENT_PROGRAM 0x8804
#endif
#ifndef GL_PROGRAM_FORMAT_ASCII
#define GL_PROGRAM_FORMAT_ASCII 0x8875
#endif
#ifndef GL_PIXEL_UNPACK_BUFFER
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
#endif
#ifndef GL_WRITE_ONLY
#define GL_WRITE_ONLY 0x88B9
#endif
#ifndef GL_STREAM_DRAW
#define GL_STREAM_DRAW 0x88E0
#endif
#ifndef GL_STENCIL_TEST_TWO_SIDE
#define GL_STENCIL_TEST_TWO_SIDE 0x8910
#endif
#ifndef GL_INCR_WRAP
#define GL_INCR_WRAP 0x8507
#endif
#ifndef GL_DECR_WRAP
#define GL_DECR_WRAP 0x8508
#endif
#ifndef GL_TEXTURE0
#define GL_TEXTURE0 0x84C0
#endif
#ifndef GL_TEXTURE1
#define GL_TEXTURE1 0x84C1
#endif
#ifndef GL_DEPTH_COMPONENT16
#define GL_DEPTH_COMPONENT16 0x81A5
#endif
#ifndef GL_DEPTH_COMPONENT24
#define GL_DEPTH_COMPONENT24 0x81A6
#endif
#ifndef GL_INVALID_FRAMEBUFFER_OPERATION
#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
#endif
#ifndef GL_MAX_RENDERBUFFER_SIZE
#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
#endif
#ifndef GL_FRAMEBUFFER_BINDING
#define GL_FRAMEBUFFER_BINDING 0x8CA6
#endif
#ifndef GL_RENDERBUFFER_BINDING
#define GL_RENDERBUFFER_BINDING 0x8CA7
#endif
#ifndef GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
#endif
#ifndef GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
#endif
#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
#endif
#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
#endif
#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET 0x8CD4
#endif
#ifndef GL_FRAMEBUFFER_COMPLETE
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT
#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT 0x8CD8
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_FORMATS
#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS 0x8CDA
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
#endif
#ifndef GL_FRAMEBUFFER_UNSUPPORTED
#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
#endif
#ifndef GL_MAX_COLOR_ATTACHMENTS
#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
#endif
#ifndef GL_COLOR_ATTACHMENT0
#define GL_COLOR_ATTACHMENT0 0x8CE0
#endif
#ifndef GL_COLOR_ATTACHMENT1
#define GL_COLOR_ATTACHMENT1 0x8CE1
#endif
#ifndef GL_COLOR_ATTACHMENT2
#define GL_COLOR_ATTACHMENT2 0x8CE2
#endif
#ifndef GL_COLOR_ATTACHMENT3
#define GL_COLOR_ATTACHMENT3 0x8CE3
#endif
#ifndef GL_COLOR_ATTACHMENT4
#define GL_COLOR_ATTACHMENT4 0x8CE4
#endif
#ifndef GL_COLOR_ATTACHMENT5
#define GL_COLOR_ATTACHMENT5 0x8CE5
#endif
#ifndef GL_COLOR_ATTACHMENT6
#define GL_COLOR_ATTACHMENT6 0x8CE6
#endif
#ifndef GL_COLOR_ATTACHMENT7
#define GL_COLOR_ATTACHMENT7 0x8CE7
#endif
#ifndef GL_COLOR_ATTACHMENT8
#define GL_COLOR_ATTACHMENT8 0x8CE8
#endif
#ifndef GL_COLOR_ATTACHMENT9
#define GL_COLOR_ATTACHMENT9 0x8CE9
#endif
#ifndef GL_COLOR_ATTACHMENT10
#define GL_COLOR_ATTACHMENT10 0x8CEA
#endif
#ifndef GL_COLOR_ATTACHMENT11
#define GL_COLOR_ATTACHMENT11 0x8CEB
#endif
#ifndef GL_COLOR_ATTACHMENT12
#define GL_COLOR_ATTACHMENT12 0x8CEC
#endif
#ifndef GL_COLOR_ATTACHMENT13
#define GL_COLOR_ATTACHMENT13 0x8CED
#endif
#ifndef GL_COLOR_ATTACHMENT14
#define GL_COLOR_ATTACHMENT14 0x8CEE
#endif
#ifndef GL_COLOR_ATTACHMENT15
#define GL_COLOR_ATTACHMENT15 0x8CEF
#endif
#ifndef GL_DEPTH_ATTACHMENT
#define GL_DEPTH_ATTACHMENT 0x8D00
#endif
#ifndef GL_STENCIL_ATTACHMENT
#define GL_STENCIL_ATTACHMENT 0x8D20
#endif
#ifndef GL_FRAMEBUFFER
#define GL_FRAMEBUFFER 0x8D40
#endif
#ifndef GL_RENDERBUFFER
#define GL_RENDERBUFFER 0x8D41
#endif
#ifndef GL_RENDERBUFFER_WIDTH
#define GL_RENDERBUFFER_WIDTH 0x8D42
#endif
#ifndef GL_RENDERBUFFER_HEIGHT
#define GL_RENDERBUFFER_HEIGHT 0x8D43
#endif
#ifndef GL_RENDERBUFFER_INTERNAL_FORMAT
#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
#endif
#ifndef GL_STENCIL_INDEX
#define GL_STENCIL_INDEX 0x8D45
#endif
#ifndef GL_STENCIL_INDEX1
#define GL_STENCIL_INDEX1 0x8D46
#endif
#ifndef GL_STENCIL_INDEX4
#define GL_STENCIL_INDEX4 0x8D47
#endif
#ifndef GL_STENCIL_INDEX8
#define GL_STENCIL_INDEX8 0x8D48
#endif
#ifndef GL_STENCIL_INDEX16
#define GL_STENCIL_INDEX16 0x8D49
#endif
#ifndef GL_RENDERBUFFER_RED_SIZE
#define GL_RENDERBUFFER_RED_SIZE 0x8D50
#endif
#ifndef GL_RENDERBUFFER_GREEN_SIZE
#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
#endif
#ifndef GL_RENDERBUFFER_BLUE_SIZE
#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
#endif
#ifndef GL_RENDERBUFFER_ALPHA_SIZE
#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
#endif
#ifndef GL_RENDERBUFFER_DEPTH_SIZE
#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
#endif
#ifndef GL_RENDERBUFFER_STENCIL_SIZE
#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
#endif
#ifndef GL_READ_FRAMEBUFFER
#define GL_READ_FRAMEBUFFER 0x8CA8
#endif
#ifndef GL_RENDERBUFFER_SAMPLES
#define GL_RENDERBUFFER_SAMPLES 0x8CAB
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
#endif
#ifndef GL_MAX_SAMPLES
#define GL_MAX_SAMPLES 0x8D57
#endif
#ifndef GL_DRAW_FRAMEBUFFER
#define GL_DRAW_FRAMEBUFFER 0x8CA9
#endif
#ifndef GL_DEPTH_STENCIL
#define GL_DEPTH_STENCIL 0x84F9
#endif
#ifndef GL_UNSIGNED_INT_24_8
#define GL_UNSIGNED_INT_24_8 0x84FA
#endif
#ifndef GL_DEPTH24_STENCIL8
#define GL_DEPTH24_STENCIL8 0x88F0
#endif
#ifndef GL_TEXTURE_STENCIL_SIZE
#define GL_TEXTURE_STENCIL_SIZE 0x88F1
#endif
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif
#ifndef GL_PACK_SKIP_IMAGES
#define GL_PACK_SKIP_IMAGES 0x806B
#endif
#ifndef GL_PACK_IMAGE_HEIGHT
#define GL_PACK_IMAGE_HEIGHT 0x806C
#endif
#ifndef GL_UNPACK_SKIP_IMAGES
#define GL_UNPACK_SKIP_IMAGES 0x806D
#endif
#ifndef GL_UNPACK_IMAGE_HEIGHT
#define GL_UNPACK_IMAGE_HEIGHT 0x806E
#endif
#ifndef GL_CONSTANT_COLOR
#define GL_CONSTANT_COLOR 0x8001
#endif
#ifndef GL_ONE_MINUS_CONSTANT_COLOR
#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
#endif
#ifndef GL_CONSTANT_ALPHA
#define GL_CONSTANT_ALPHA 0x8003
#endif
#ifndef GL_ONE_MINUS_CONSTANT_ALPHA
#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
#endif
#ifndef GL_INCR_WRAP
#define GL_INCR_WRAP 0x8507
#endif
#ifndef GL_DECR_WRAP
#define GL_DECR_WRAP 0x8508
#endif
#ifndef GL_ARRAY_BUFFER
#define GL_ARRAY_BUFFER 0x8892
#endif
#ifndef GL_ELEMENT_ARRAY_BUFFER
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
#endif
#ifndef GL_STREAM_DRAW
#define GL_STREAM_DRAW 0x88E0
#endif
#ifndef GL_STREAM_READ
#define GL_STREAM_READ 0x88E1
#endif
#ifndef GL_STREAM_COPY
#define GL_STREAM_COPY 0x88E2
#endif
#ifndef GL_STATIC_DRAW
#define GL_STATIC_DRAW 0x88E4
#endif
#ifndef GL_STATIC_READ
#define GL_STATIC_READ 0x88E5
#endif
#ifndef GL_STATIC_COPY
#define GL_STATIC_COPY 0x88E6
#endif
#ifndef GL_DYNAMIC_DRAW
#define GL_DYNAMIC_DRAW 0x88E8
#endif
#ifndef GL_DYNAMIC_READ
#define GL_DYNAMIC_READ 0x88E9
#endif
#ifndef GL_DYNAMIC_COPY
#define GL_DYNAMIC_COPY 0x88EA
#endif
#ifndef GL_FRAGMENT_SHADER
#define GL_FRAGMENT_SHADER 0x8B30
#endif
#ifndef GL_VERTEX_SHADER
#define GL_VERTEX_SHADER 0x8B31
#endif
#ifndef GL_FLOAT_VEC2
#define GL_FLOAT_VEC2 0x8B50
#endif
#ifndef GL_FLOAT_VEC3
#define GL_FLOAT_VEC3 0x8B51
#endif
#ifndef GL_FLOAT_VEC4
#define GL_FLOAT_VEC4 0x8B52
#endif
#ifndef GL_INT_VEC2
#define GL_INT_VEC2 0x8B53
#endif
#ifndef GL_INT_VEC3
#define GL_INT_VEC3 0x8B54
#endif
#ifndef GL_INT_VEC4
#define GL_INT_VEC4 0x8B55
#endif
#ifndef GL_BOOL
#define GL_BOOL 0x8B56
#endif
#ifndef GL_BOOL_VEC2
#define GL_BOOL_VEC2 0x8B57
#endif
#ifndef GL_BOOL_VEC3
#define GL_BOOL_VEC3 0x8B58
#endif
#ifndef GL_BOOL_VEC4
#define GL_BOOL_VEC4 0x8B59
#endif
#ifndef GL_FLOAT_MAT2
#define GL_FLOAT_MAT2 0x8B5A
#endif
#ifndef GL_FLOAT_MAT3
#define GL_FLOAT_MAT3 0x8B5B
#endif
#ifndef GL_FLOAT_MAT4
#define GL_FLOAT_MAT4 0x8B5C
#endif
#ifndef GL_SAMPLER_1D
#define GL_SAMPLER_1D 0x8B5D
#endif
#ifndef GL_SAMPLER_2D
#define GL_SAMPLER_2D 0x8B5E
#endif
#ifndef GL_SAMPLER_3D
#define GL_SAMPLER_3D 0x8B5F
#endif
#ifndef GL_SAMPLER_CUBE
#define GL_SAMPLER_CUBE 0x8B60
#endif
#ifndef GL_COMPILE_STATUS
#define GL_COMPILE_STATUS 0x8B81
#endif
#ifndef GL_LINK_STATUS
#define GL_LINK_STATUS 0x8B82
#endif
#ifndef GL_INFO_LOG_LENGTH
#define GL_INFO_LOG_LENGTH 0x8B84
#endif
#ifndef GL_ACTIVE_UNIFORMS
#define GL_ACTIVE_UNIFORMS 0x8B86
#endif
#ifndef GL_ACTIVE_UNIFORM_MAX_LENGTH
#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
#endif
#ifndef GL_ACTIVE_ATTRIBUTES
#define GL_ACTIVE_ATTRIBUTES 0x8B89
#endif
#ifndef GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
#endif
#ifndef GL_GEOMETRY_SHADER
#define GL_GEOMETRY_SHADER 0x8DD9
#endif
#ifndef GL_GEOMETRY_VERTICES_OUT
#define GL_GEOMETRY_VERTICES_OUT 0x8DDA
#endif
#ifndef GL_GEOMETRY_INPUT_TYPE
#define GL_GEOMETRY_INPUT_TYPE 0x8DDB
#endif
#ifndef GL_GEOMETRY_OUTPUT_TYPE
#define GL_GEOMETRY_OUTPUT_TYPE 0x8DDC
#endif
#ifndef GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS
#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
#endif
#ifndef GL_MAX_GEOMETRY_VARYING_COMPONENTS
#define GL_MAX_GEOMETRY_VARYING_COMPONENTS 0x8DDD
#endif
#ifndef GL_MAX_VERTEX_VARYING_COMPONENTS
#define GL_MAX_VERTEX_VARYING_COMPONENTS 0x8DDE
#endif
#ifndef GL_MAX_VARYING_COMPONENTS
#define GL_MAX_VARYING_COMPONENTS 0x8B4B
#endif
#ifndef GL_MAX_GEOMETRY_UNIFORM_COMPONENTS
#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF
#endif
#ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES
#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
#endif
#ifndef GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS
#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
#endif
#ifndef GL_LINES_ADJACENCY
#define GL_LINES_ADJACENCY 0xA
#endif
#ifndef GL_LINE_STRIP_ADJACENCY
#define GL_LINE_STRIP_ADJACENCY 0xB
#endif
#ifndef GL_TRIANGLES_ADJACENCY
#define GL_TRIANGLES_ADJACENCY 0xC
#endif
#ifndef GL_TRIANGLE_STRIP_ADJACENCY
#define GL_TRIANGLE_STRIP_ADJACENCY 0xD
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS
#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8
#endif
#ifndef GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT
#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT 0x8DA9
#endif
#ifndef GL_FRAMEBUFFER_ATTACHMENT_LAYERED
#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7
#endif
#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
#endif
#ifndef GL_PROGRAM_POINT_SIZE
#define GL_PROGRAM_POINT_SIZE 0x8642
#endif
QT_END_NAMESPACE
QT_END_HEADER
#endif // QOPENGL_EXTENSIONS_P_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,158 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QOPENGLFRAMEBUFFEROBJECT_H
#define QOPENGLFRAMEBUFFEROBJECT_H
#include <QtGui/qopengl.h>
#include <QtGui/qpaintdevice.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QOpenGLFramebufferObjectPrivate;
class QOpenGLFramebufferObjectFormat;
class Q_GUI_EXPORT QOpenGLFramebufferObject : public QPaintDevice
{
Q_DECLARE_PRIVATE(QOpenGLFramebufferObject)
public:
enum Attachment {
NoAttachment,
CombinedDepthStencil,
Depth
};
QOpenGLFramebufferObject(const QSize &size, GLenum target = GL_TEXTURE_2D);
QOpenGLFramebufferObject(int width, int height, GLenum target = GL_TEXTURE_2D);
#if !defined(QT_OPENGL_ES) || defined(Q_QDOC)
QOpenGLFramebufferObject(const QSize &size, Attachment attachment,
GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA8);
QOpenGLFramebufferObject(int width, int height, Attachment attachment,
GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA8);
#else
QOpenGLFramebufferObject(const QSize &size, Attachment attachment,
GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA);
QOpenGLFramebufferObject(int width, int height, Attachment attachment,
GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA);
#endif
QOpenGLFramebufferObject(const QSize &size, const QOpenGLFramebufferObjectFormat &format);
QOpenGLFramebufferObject(int width, int height, const QOpenGLFramebufferObjectFormat &format);
virtual ~QOpenGLFramebufferObject();
QOpenGLFramebufferObjectFormat format() const;
bool isValid() const;
bool isBound() const;
bool bind();
bool release();
GLuint texture() const;
QSize size() const;
QImage toImage() const;
Attachment attachment() const;
QPaintEngine *paintEngine() const;
GLuint handle() const;
static bool bindDefault();
static bool hasOpenGLFramebufferObjects();
static bool hasOpenGLFramebufferBlit();
static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,
QOpenGLFramebufferObject *source, const QRect &sourceRect,
GLbitfield buffers = GL_COLOR_BUFFER_BIT,
GLenum filter = GL_NEAREST);
protected:
int metric(PaintDeviceMetric metric) const;
int devType() const { return QInternal::FramebufferObject; }
private:
Q_DISABLE_COPY(QOpenGLFramebufferObject)
QScopedPointer<QOpenGLFramebufferObjectPrivate> d_ptr;
friend class QOpenGLPaintDevice;
friend class QOpenGLFBOGLPaintDevice;
};
class QOpenGLFramebufferObjectFormatPrivate;
class Q_GUI_EXPORT QOpenGLFramebufferObjectFormat
{
public:
QOpenGLFramebufferObjectFormat();
QOpenGLFramebufferObjectFormat(const QOpenGLFramebufferObjectFormat &other);
QOpenGLFramebufferObjectFormat &operator=(const QOpenGLFramebufferObjectFormat &other);
~QOpenGLFramebufferObjectFormat();
void setSamples(int samples);
int samples() const;
void setMipmap(bool enabled);
bool mipmap() const;
void setAttachment(QOpenGLFramebufferObject::Attachment attachment);
QOpenGLFramebufferObject::Attachment attachment() const;
void setTextureTarget(GLenum target);
GLenum textureTarget() const;
void setInternalTextureFormat(GLenum internalTextureFormat);
GLenum internalTextureFormat() const;
bool operator==(const QOpenGLFramebufferObjectFormat& other) const;
bool operator!=(const QOpenGLFramebufferObjectFormat& other) const;
private:
QOpenGLFramebufferObjectFormatPrivate *d;
void detach();
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QOPENGLFRAMEBUFFEROBJECT_H

View File

@ -0,0 +1,164 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QOPENGLFRAMEBUFFEROBJECT_P_H
#define QOPENGLFRAMEBUFFEROBJECT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
QT_BEGIN_NAMESPACE
QT_BEGIN_INCLUDE_NAMESPACE
#include <qopenglframebufferobject.h>
#include <private/qopenglpaintdevice_p.h>
#include <private/qopenglcontext_p.h>
#include <private/qopenglextensions_p.h>
QT_END_INCLUDE_NAMESPACE
#ifndef QT_OPENGL_ES
#define DEFAULT_FORMAT GL_RGBA8
#else
#define DEFAULT_FORMAT GL_RGBA
#endif
class QOpenGLFramebufferObjectFormatPrivate
{
public:
QOpenGLFramebufferObjectFormatPrivate()
: ref(1),
samples(0),
attachment(QOpenGLFramebufferObject::NoAttachment),
target(GL_TEXTURE_2D),
internal_format(DEFAULT_FORMAT),
mipmap(false)
{
}
QOpenGLFramebufferObjectFormatPrivate
(const QOpenGLFramebufferObjectFormatPrivate *other)
: ref(1),
samples(other->samples),
attachment(other->attachment),
target(other->target),
internal_format(other->internal_format),
mipmap(other->mipmap)
{
}
bool equals(const QOpenGLFramebufferObjectFormatPrivate *other)
{
return samples == other->samples &&
attachment == other->attachment &&
target == other->target &&
internal_format == other->internal_format &&
mipmap == other->mipmap;
}
QAtomicInt ref;
int samples;
QOpenGLFramebufferObject::Attachment attachment;
GLenum target;
GLenum internal_format;
uint mipmap : 1;
};
class QOpenGLFBOGLPaintDevice : public QOpenGLPaintDevice
{
public:
virtual QPaintEngine* paintEngine() const {return fbo->paintEngine();}
virtual QSize size() const {return fbo->size();}
virtual QSurfaceFormat format() const {return fboFormat;}
virtual QOpenGLContextGroup *group() const;
virtual bool alphaRequested() const { return reqAlpha; }
void setFBO(QOpenGLFramebufferObject* f,
QOpenGLFramebufferObject::Attachment attachment);
private:
QOpenGLFramebufferObject* fbo;
QSurfaceFormat fboFormat;
bool wasBound;
bool reqAlpha;
};
class QOpenGLFramebufferObjectPrivate
{
public:
QOpenGLFramebufferObjectPrivate() : fbo_guard(0), texture_guard(0), depth_buffer_guard(0)
, stencil_buffer_guard(0), color_buffer_guard(0)
, valid(false), engine(0) {}
~QOpenGLFramebufferObjectPrivate() {}
void init(QOpenGLFramebufferObject *q, const QSize& sz,
QOpenGLFramebufferObject::Attachment attachment,
GLenum internal_format, GLenum texture_target,
GLint samples = 0, bool mipmap = false);
bool checkFramebufferStatus() const;
QOpenGLSharedResourceGuard *fbo_guard;
QOpenGLSharedResourceGuard *texture_guard;
QOpenGLSharedResourceGuard *depth_buffer_guard;
QOpenGLSharedResourceGuard *stencil_buffer_guard;
QOpenGLSharedResourceGuard *color_buffer_guard;
GLenum target;
QSize size;
QOpenGLFramebufferObjectFormat format;
uint valid : 1;
QOpenGLFramebufferObject::Attachment fbo_attachment;
mutable QPaintEngine *engine;
QOpenGLFBOGLPaintDevice glDevice;
QOpenGLExtensions funcs;
inline GLuint fbo() const { return fbo_guard ? fbo_guard->id() : 0; }
};
QT_END_NAMESPACE
#endif // QOPENGLFRAMEBUFFEROBJECT_P_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,227 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qopenglgradientcache_p.h"
#include <private/qdrawhelper_p.h>
#include <private/qopenglcontext_p.h>
#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
class QOpenGL2GradientCacheWrapper
{
public:
QOpenGL2GradientCache *cacheForContext(QOpenGLContext *context) {
QMutexLocker lock(&m_mutex);
return m_resource.value<QOpenGL2GradientCache>(context);
}
private:
QOpenGLMultiGroupSharedResource m_resource;
QMutex m_mutex;
};
Q_GLOBAL_STATIC(QOpenGL2GradientCacheWrapper, qt_gradient_caches)
QOpenGL2GradientCache::QOpenGL2GradientCache(QOpenGLContext *ctx)
: QOpenGLSharedResource(ctx->shareGroup())
{
}
QOpenGL2GradientCache::~QOpenGL2GradientCache()
{
cache.clear();
}
QOpenGL2GradientCache *QOpenGL2GradientCache::cacheForContext(QOpenGLContext *context)
{
return qt_gradient_caches()->cacheForContext(context);
}
void QOpenGL2GradientCache::invalidateResource()
{
QMutexLocker lock(&m_mutex);
cache.clear();
}
void QOpenGL2GradientCache::freeResource(QOpenGLContext *)
{
cleanCache();
}
void QOpenGL2GradientCache::cleanCache()
{
QMutexLocker lock(&m_mutex);
QOpenGLGradientColorTableHash::const_iterator it = cache.constBegin();
for (; it != cache.constEnd(); ++it) {
const CacheInfo &cache_info = it.value();
glDeleteTextures(1, &cache_info.texId);
}
cache.clear();
}
GLuint QOpenGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity)
{
QMutexLocker lock(&m_mutex);
quint64 hash_val = 0;
QGradientStops stops = gradient.stops();
for (int i = 0; i < stops.size() && i <= 2; i++)
hash_val += stops[i].second.rgba();
QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
if (it == cache.constEnd())
return addCacheElement(hash_val, gradient, opacity);
else {
do {
const CacheInfo &cache_info = it.value();
if (cache_info.stops == stops && cache_info.opacity == opacity
&& cache_info.interpolationMode == gradient.interpolationMode())
{
return cache_info.texId;
}
++it;
} while (it != cache.constEnd() && it.key() == hash_val);
// an exact match for these stops and opacity was not found, create new cache
return addCacheElement(hash_val, gradient, opacity);
}
}
GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)
{
if (cache.size() == maxCacheSize()) {
int elem_to_remove = qrand() % maxCacheSize();
quint64 key = cache.keys()[elem_to_remove];
// need to call glDeleteTextures on each removed cache entry:
QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key);
do {
glDeleteTextures(1, &it.value().texId);
} while (++it != cache.constEnd() && it.key() == key);
cache.remove(key); // may remove more than 1, but OK
}
CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
uint buffer[1024];
generateGradientColorTable(gradient, buffer, paletteSize(), opacity);
glGenTextures(1, &cache_entry.texId);
glBindTexture(GL_TEXTURE_2D, cache_entry.texId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, paletteSize(), 1,
0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
return cache.insert(hash_val, cache_entry).value().texId;
}
// GL's expects pixels in RGBA (when using GL_RGBA), bin-endian (ABGR on x86).
// Qt always stores in ARGB reguardless of the byte-order the mancine uses.
static inline uint qtToGlColor(uint c)
{
uint o;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
o = (c & 0xff00ff00) // alpha & green already in the right place
| ((c >> 16) & 0x000000ff) // red
| ((c << 16) & 0x00ff0000); // blue
#else //Q_BIG_ENDIAN
o = (c << 8)
| ((c >> 24) & 0x000000ff);
#endif // Q_BYTE_ORDER
return o;
}
//TODO: Let GL generate the texture using an FBO
void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const
{
int pos = 0;
QGradientStops s = gradient.stops();
QVector<uint> colors(s.size());
for (int i = 0; i < s.size(); ++i)
colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB (on little-endian AND on big-endian)
bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
uint alpha = qRound(opacity * 256);
uint current_color = ARGB_COMBINE_ALPHA(colors[0], alpha);
qreal incr = 1.0 / qreal(size);
qreal fpos = 1.5 * incr;
colorTable[pos++] = qtToGlColor(PREMUL(current_color));
while (fpos <= s.first().first) {
colorTable[pos] = colorTable[pos - 1];
pos++;
fpos += incr;
}
if (colorInterpolation)
current_color = PREMUL(current_color);
for (int i = 0; i < s.size() - 1; ++i) {
qreal delta = 1/(s[i+1].first - s[i].first);
uint next_color = ARGB_COMBINE_ALPHA(colors[i+1], alpha);
if (colorInterpolation)
next_color = PREMUL(next_color);
while (fpos < s[i+1].first && pos < size) {
int dist = int(256 * ((fpos - s[i].first) * delta));
int idist = 256 - dist;
if (colorInterpolation)
colorTable[pos] = qtToGlColor(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
else
colorTable[pos] = qtToGlColor(PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
++pos;
fpos += incr;
}
current_color = next_color;
}
Q_ASSERT(s.size() > 0);
uint last_color = qtToGlColor(PREMUL(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha)));
for (;pos < size; ++pos)
colorTable[pos] = last_color;
// Make sure the last color stop is represented at the end of the table
colorTable[size-1] = last_color;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,101 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QMultiHash>
#include <QObject>
#include <QtGui/QtGui>
#include <private/qopenglcontext_p.h>
#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
class QOpenGL2GradientCache : public QOpenGLSharedResource
{
struct CacheInfo
{
inline CacheInfo(QGradientStops s, qreal op, QGradient::InterpolationMode mode) :
stops(s), opacity(op), interpolationMode(mode) {}
GLuint texId;
QGradientStops stops;
qreal opacity;
QGradient::InterpolationMode interpolationMode;
};
typedef QMultiHash<quint64, CacheInfo> QOpenGLGradientColorTableHash;
public:
static QOpenGL2GradientCache *cacheForContext(QOpenGLContext *context);
QOpenGL2GradientCache(QOpenGLContext *);
~QOpenGL2GradientCache();
GLuint getBuffer(const QGradient &gradient, qreal opacity);
inline int paletteSize() const { return 1024; }
void invalidateResource();
void freeResource(QOpenGLContext *ctx);
private:
inline int maxCacheSize() const { return 60; }
inline void generateGradientColorTable(const QGradient& gradient,
uint *colorTable,
int size, qreal opacity) const;
GLuint addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity);
void cleanCache();
QOpenGLGradientColorTableHash cache;
QMutex m_mutex;
};
QT_END_NAMESPACE

View File

@ -0,0 +1,153 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <private/qopenglpaintdevice_p.h>
#include <private/qopenglcontext_p.h>
#include <private/qopenglframebufferobject_p.h>
#include <qopenglfunctions.h>
QT_BEGIN_NAMESPACE
QOpenGLPaintDevice::QOpenGLPaintDevice()
: m_thisFBO(0)
{
}
QOpenGLPaintDevice::~QOpenGLPaintDevice()
{
}
int QOpenGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const
{
switch(metric) {
case PdmWidth:
return size().width();
case PdmHeight:
return size().height();
case PdmDepth: {
const QSurfaceFormat f = format();
return f.redBufferSize() + f.greenBufferSize() + f.blueBufferSize() + f.alphaBufferSize();
}
default:
qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric);
return 0;
}
}
void QOpenGLPaintDevice::beginPaint()
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
// Record the currently bound FBO so we can restore it again
// in endPaint() and bind this device's FBO
//
// Note: m_thisFBO could be zero if the paint device is not
// backed by an FBO (e.g. window back buffer). But there could
// be a previous FBO bound to the context which we need to
// explicitly unbind. Otherwise the painting will go into
// the previous FBO instead of to the window.
m_previousFBO = ctx->d_func()->current_fbo;
if (m_previousFBO != m_thisFBO) {
ctx->d_func()->current_fbo = m_thisFBO;
QOpenGLFunctions(ctx).glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO);
}
// Set the default fbo for the context to m_thisFBO so that
// if some raw GL code between beginNativePainting() and
// endNativePainting() calls QOpenGLFramebufferObject::release(),
// painting will revert to the window surface's fbo.
ctx->d_func()->default_fbo = m_thisFBO;
}
void QOpenGLPaintDevice::ensureActiveTarget()
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx->d_func()->current_fbo != m_thisFBO) {
ctx->d_func()->current_fbo = m_thisFBO;
QOpenGLFunctions(ctx).glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO);
}
ctx->d_func()->default_fbo = m_thisFBO;
}
void QOpenGLPaintDevice::endPaint()
{
// Make sure the FBO bound at beginPaint is re-bound again here:
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (m_previousFBO != ctx->d_func()->current_fbo) {
ctx->d_func()->current_fbo = m_previousFBO;
QOpenGLFunctions(ctx).glBindFramebuffer(GL_FRAMEBUFFER, m_previousFBO);
}
ctx->d_func()->default_fbo = 0;
}
bool QOpenGLPaintDevice::isFlipped() const
{
return false;
}
// returns the QOpenGLPaintDevice for the given QPaintDevice
QOpenGLPaintDevice* QOpenGLPaintDevice::getDevice(QPaintDevice* pd)
{
QOpenGLPaintDevice* glpd = 0;
switch(pd->devType()) {
case QInternal::FramebufferObject:
glpd = &(static_cast<QOpenGLFramebufferObject*>(pd)->d_func()->glDevice);
break;
case QInternal::Pixmap: {
qWarning("Pixmap type not supported for GL rendering");
break;
}
default:
qWarning("QOpenGLPaintDevice::getDevice() - Unknown device type %d", pd->devType());
break;
}
return glpd;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,119 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QOPENGLPAINTDEVICE_P_H
#define QOPENGLPAINTDEVICE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QtGui module. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <qpaintdevice.h>
#include <QtGui/qopengl.h>
#include <QtGui/qopenglcontext.h>
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QOpenGLPaintDevice : public QPaintDevice
{
public:
QOpenGLPaintDevice();
virtual ~QOpenGLPaintDevice();
int devType() const {return QInternal::OpenGL;}
virtual void beginPaint();
virtual void ensureActiveTarget();
virtual void endPaint();
virtual QOpenGLContextGroup *group() const = 0;
virtual QSurfaceFormat format() const = 0;
virtual QSize size() const = 0;
virtual bool alphaRequested() const = 0;
virtual bool isFlipped() const;
// returns the QOpenGLPaintDevice for the given QPaintDevice
static QOpenGLPaintDevice* getDevice(QPaintDevice*);
protected:
int metric(QPaintDevice::PaintDeviceMetric metric) const;
GLuint m_previousFBO;
GLuint m_thisFBO;
};
#if 0
// Wraps a QOpenGLWidget
class QOpenGLWidget;
class Q_GUI_EXPORT QOpenGLWidgetGLPaintDevice : public QOpenGLPaintDevice
{
public:
QOpenGLWidgetGLPaintDevice();
virtual QPaintEngine* paintEngine() const;
// QOpenGLWidgets need to do swapBufers in endPaint:
virtual void beginPaint();
virtual void endPaint();
virtual QSize size() const;
virtual QOpenGLContext* context() const;
void setWidget(QOpenGLWidget*);
private:
friend class QOpenGLWidget;
QOpenGLWidget *glWidget;
};
#endif
QT_END_NAMESPACE
#endif // QOPENGLPAINTDEVICE_P_H

View File

@ -0,0 +1,457 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#ifndef QOPENGLSHADERCACHE_MEEGO_P_H
#define QOPENGLSHADERCACHE_MEEGO_P_H
#include <QtCore/qopenglobal.h>
#if defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE) && defined(QT_OPENGL_ES_2)
#include <QtCore/qcryptographichash.h>
#include <QtCore/qsharedmemory.h>
#include <QtCore/qsystemsemaphore.h>
#ifndef QT_BOOTSTRAPPED
# include <GLES2/gl2ext.h>
#endif
#if defined(QT_DEBUG) || defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE_TRACE)
# include <syslog.h>
#endif
QT_BEGIN_HEADER
/*
This cache stores internal Qt shader programs in shared memory.
This header file is ugly on purpose and can only be included once. It is only to be used
for the internal shader cache, not as a generic cache for anyone's shaders.
The cache stores either ShaderCacheMaxEntries shader programs or ShaderCacheDataSize kilobytes
of shader programs, whatever limit is reached first.
The layout of the cache is as outlined in the CachedShaders struct. After some
integers, an array of headers is reserved, then comes the space for the actual binaries.
Shader Programs are identified by the md5sum of their frag and vertex shader source code.
Shader Programs are never removed. The cache never shrinks or re-shuffles. This is done
on purpose to ensure minimum amount of locking, no alignment problems and very few write
operations.
Note: Locking the shader cache could be expensive, because the entire system might hang.
That's why the cache is immutable to minimize the time we need to keep it locked.
Why is it Meego specific?
First, the size is chosen so that it fits to generic meego usage. Second, on Meego, there's
always at least one Qt application active (the launcher), so the cache will never be destroyed.
Only when the last Qt app exits, the cache dies, which should only be when someone kills the
X11 server. And last but not least it was only tested with Meego's SGX driver.
There's a small tool in src/opengl/util/meego that dumps the contents of the cache.
*/
// anonymous namespace, prevent exporting of the private symbols
namespace
{
struct CachedShaderHeader
{
/* the index in the data[] member of CachedShaders */
int index;
/* the size of the binary shader */
GLsizei size;
/* the format of the binary shader */
GLenum format;
/* the md5sum of the frag+vertex shaders */
char md5Sum[16];
};
enum
{
/* The maximum amount of shader programs the cache can hold */
ShaderCacheMaxEntries = 20
};
typedef CachedShaderHeader CachedShaderHeaders[ShaderCacheMaxEntries];
enum
{
// ShaderCacheDataSize is 20k minus the other data members of CachedShaders
ShaderCacheDataSize = 1024 * ShaderCacheMaxEntries - sizeof(CachedShaderHeaders) - 2 * sizeof(int)
};
struct CachedShaders
{
/* How much space is still available in the cache */
inline int availableSize() const { return ShaderCacheDataSize - dataSize; }
/* The current amount of cached shaders */
int shaderCount;
/* The current amount (in bytes) of cached data */
int dataSize;
/* The headers describing the shaders */
CachedShaderHeaders headers;
/* The actual binary data of the shader programs */
char data[ShaderCacheDataSize];
};
//#define QT_DEBUG_SHADER_CACHE
#ifdef QT_DEBUG_SHADER_CACHE
static QDebug shaderCacheDebug()
{
return QDebug(QtDebugMsg);
}
#else
static inline QNoDebug shaderCacheDebug() { return QNoDebug(); }
#endif
class ShaderCacheSharedMemory
{
public:
ShaderCacheSharedMemory()
: shm(QLatin1String("qt_gles2_shadercache_" QT_VERSION_STR))
{
// we need a system semaphore here, since cache creation and initialization must be atomic
QSystemSemaphore attachSemaphore(QLatin1String("qt_gles2_shadercache_mutex_" QT_VERSION_STR), 1);
if (!attachSemaphore.acquire()) {
shaderCacheDebug() << "Unable to require shader cache semaphore:" << attachSemaphore.errorString();
return;
}
if (shm.attach()) {
// success!
shaderCacheDebug() << "Attached to shader cache";
} else {
// no cache exists - create and initialize it
if (shm.create(sizeof(CachedShaders))) {
shaderCacheDebug() << "Created new shader cache";
initializeCache();
} else {
shaderCacheDebug() << "Unable to create shader cache:" << shm.errorString();
}
}
attachSemaphore.release();
}
inline bool isAttached() const { return shm.isAttached(); }
inline bool lock() { return shm.lock(); }
inline bool unlock() { return shm.unlock(); }
inline void *data() { return shm.data(); }
inline QString errorString() { return shm.errorString(); }
~ShaderCacheSharedMemory()
{
if (!shm.detach())
shaderCacheDebug() << "Unable to detach shader cache" << shm.errorString();
}
private:
void initializeCache()
{
// no need to lock the shared memory since we're already protected by the
// attach system semaphore.
void *data = shm.data();
Q_ASSERT(data);
memset(data, 0, sizeof(CachedShaders));
}
QSharedMemory shm;
};
class ShaderCacheLocker
{
public:
inline ShaderCacheLocker(ShaderCacheSharedMemory *cache)
: shm(cache->lock() ? cache : (ShaderCacheSharedMemory *)0)
{
if (!shm)
shaderCacheDebug() << "Unable to lock shader cache" << cache->errorString();
}
inline bool isLocked() const { return shm; }
inline ~ShaderCacheLocker()
{
if (!shm)
return;
if (!shm->unlock())
shaderCacheDebug() << "Unable to unlock shader cache" << shm->errorString();
}
private:
ShaderCacheSharedMemory *shm;
};
#ifdef QT_BOOTSTRAPPED
} // end namespace
#else
static void traceCacheOverflow(const char *message)
{
#if defined(QT_DEBUG) || defined (QT_MEEGO_EXPERIMENTAL_SHADERCACHE_TRACE)
openlog(qPrintable(QCoreApplication::applicationName()), LOG_PID | LOG_ODELAY, LOG_USER);
syslog(LOG_DEBUG, message);
closelog();
#endif
shaderCacheDebug() << message;
}
Q_GLOBAL_STATIC(ShaderCacheSharedMemory, shaderCacheSharedMemory)
/*
Finds the index of the shader program identified by md5Sum in the cache.
Note: Does NOT lock the cache for reading, the cache must already be locked!
Returns -1 when no shader was found.
*/
static int qt_cache_index_unlocked(const QByteArray &md5Sum, CachedShaders *cache)
{
for (int i = 0; i < cache->shaderCount; ++i) {
if (qstrncmp(md5Sum.constData(), cache->headers[i].md5Sum, 16) == 0) {
return i;
}
}
return -1;
}
/* Returns the index of the shader identified by md5Sum */
static int qt_cache_index(const QByteArray &md5Sum)
{
ShaderCacheSharedMemory *shm = shaderCacheSharedMemory();
if (!shm || !shm->isAttached())
return false;
Q_ASSERT(md5Sum.length() == 16);
ShaderCacheLocker locker(shm);
if (!locker.isLocked())
return false;
void *data = shm->data();
Q_ASSERT(data);
CachedShaders *cache = reinterpret_cast<CachedShaders *>(data);
return qt_cache_index_unlocked(md5Sum, cache);
}
/* Loads the cached shader at index \a shaderIndex into \a program
* Note: Since the cache is immutable, this operation doesn't lock the shared memory.
*/
static bool qt_cached_shader(QOpenGLShaderProgram *program, QOpenGLContext *ctx, int shaderIndex)
{
Q_ASSERT(shaderIndex >= 0 && shaderIndex <= ShaderCacheMaxEntries);
Q_ASSERT(program);
ShaderCacheSharedMemory *shm = shaderCacheSharedMemory();
if (!shm || !shm->isAttached())
return false;
void *data = shm->data();
Q_ASSERT(data);
CachedShaders *cache = reinterpret_cast<CachedShaders *>(data);
shaderCacheDebug() << "fetching cached shader at index" << shaderIndex
<< "dataIndex" << cache->headers[shaderIndex].index
<< "size" << cache->headers[shaderIndex].size
<< "format" << cache->headers[shaderIndex].format;
// call program->programId first, since that resolves the glProgramBinaryOES symbol
GLuint programId = program->programId();
glProgramBinaryOES(programId, cache->headers[shaderIndex].format,
cache->data + cache->headers[shaderIndex].index,
cache->headers[shaderIndex].size);
return true;
}
/* Stores the shader program in the cache. Returns false if there's an error with the cache, or
if the cache is too small to hold the shader. */
static bool qt_cache_shader(const QOpenGLShaderProgram *shader, QOpenGLContext *ctx, const QByteArray &md5Sum)
{
ShaderCacheSharedMemory *shm = shaderCacheSharedMemory();
if (!shm || !shm->isAttached())
return false;
void *data = shm->data();
Q_ASSERT(data);
CachedShaders *cache = reinterpret_cast<CachedShaders *>(data);
ShaderCacheLocker locker(shm);
if (!locker.isLocked())
return false;
int cacheIdx = cache->shaderCount;
if (cacheIdx >= ShaderCacheMaxEntries) {
traceCacheOverflow("Qt OpenGL shader cache index overflow!");
return false;
}
// now that we have the lock on the shared memory, make sure no one
// inserted the shader already while we were unlocked
if (qt_cache_index_unlocked(md5Sum, cache) != -1)
return true; // already cached
shaderCacheDebug() << "Caching shader at index" << cacheIdx;
GLint binaryLength = 0;
glGetProgramiv(shader->programId(), GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength);
if (!binaryLength) {
shaderCacheDebug() << "Unable to determine binary shader size!";
return false;
}
if (binaryLength > cache->availableSize()) {
traceCacheOverflow("Qt OpenGL shader cache data overflow!");
return false;
}
GLsizei size = 0;
GLenum format = 0;
glGetProgramBinaryOES(shader->programId(), binaryLength, &size, &format,
cache->data + cache->dataSize);
if (!size) {
shaderCacheDebug() << "Unable to get binary shader!";
return false;
}
cache->headers[cacheIdx].index = cache->dataSize;
cache->dataSize += binaryLength;
++cache->shaderCount;
cache->headers[cacheIdx].size = binaryLength;
cache->headers[cacheIdx].format = format;
memcpy(cache->headers[cacheIdx].md5Sum, md5Sum.constData(), 16);
shaderCacheDebug() << "cached shader size" << size
<< "format" << format
<< "binarySize" << binaryLength
<< "cache index" << cacheIdx
<< "data index" << cache->headers[cacheIdx].index;
return true;
}
} // namespace
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class CachedShader
{
public:
CachedShader(const QByteArray &fragSource, const QByteArray &vertexSource)
: cacheIdx(-1)
{
QCryptographicHash md5Hash(QCryptographicHash::Md5);
md5Hash.addData(fragSource);
md5Hash.addData(vertexSource);
md5Sum = md5Hash.result();
}
bool isCached()
{
return cacheIndex() != -1;
}
int cacheIndex()
{
if (cacheIdx != -1)
return cacheIdx;
cacheIdx = qt_cache_index(md5Sum);
return cacheIdx;
}
bool load(QOpenGLShaderProgram *program, QOpenGLContext *ctx)
{
if (cacheIndex() == -1)
return false;
return qt_cached_shader(program, ctx, cacheIdx);
}
bool store(QOpenGLShaderProgram *program, QOpenGLContext *ctx)
{
return qt_cache_shader(program, ctx, md5Sum);
}
private:
QByteArray md5Sum;
int cacheIdx;
};
QT_END_NAMESPACE
#endif
QT_END_HEADER
#endif
#endif

View File

@ -4,7 +4,7 @@
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenGL module of the Qt Toolkit.
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
@ -39,51 +39,60 @@
**
****************************************************************************/
#include <QtCore/qdebug.h>
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#define QT_DEBUG_SHADER_CACHE
#define QT_MEEGO_EXPERIMENTAL_SHADERCACHE
#define QT_OPENGL_ES_2
#define QT_BOOTSTRAPPED
#ifndef QOPENGLSHADERCACHE_P_H
#define QOPENGLSHADERCACHE_P_H
typedef int GLsizei;
typedef unsigned int GLenum;
#include <QtCore/qglobal.h>
#include "../../gl2paintengineex/qglshadercache_meego_p.h"
#if defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE) && defined(QT_OPENGL_ES_2)
# include "qopenglshadercache_meego_p.h"
#else
#include <stdlib.h>
#include <stdio.h>
QT_BEGIN_HEADER
int main()
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QOpenGLShaderProgram;
class QOpenGLContext;
class CachedShader
{
ShaderCacheSharedMemory shm;
public:
inline CachedShader(const QByteArray &, const QByteArray &)
{}
if (!shm.isAttached()) {
fprintf(stderr, "Unable to attach to shared memory\n");
return EXIT_FAILURE;
inline bool isCached()
{
return false;
}
ShaderCacheLocker locker(&shm);
if (!locker.isLocked()) {
fprintf(stderr, "Unable to lock shared memory\n");
return EXIT_FAILURE;
inline bool load(QOpenGLShaderProgram *, QOpenGLContext *)
{
return false;
}
void *data = shm.data();
Q_ASSERT(data);
CachedShaders *cache = reinterpret_cast<CachedShaders *>(data);
for (int i = 0; i < cache->shaderCount; ++i) {
printf("Shader %d: %d bytes\n", i, cache->headers[i].size);
inline bool store(QOpenGLShaderProgram *, QOpenGLContext *)
{
return false;
}
};
printf("\nSummary:\n\n"
" Amount of cached shaders: %d\n"
" Bytes used: %d\n"
" Bytes available: %d\n",
cache->shaderCount, cache->dataSize, cache->availableSize());
QT_END_NAMESPACE
return EXIT_SUCCESS;
}
QT_END_HEADER
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,317 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QOPENGLSHADERPROGRAM_H
#define QOPENGLSHADERPROGRAM_H
#include <QtGui/qopengl.h>
#include <QtGui/qvector2d.h>
#include <QtGui/qvector3d.h>
#include <QtGui/qvector4d.h>
#include <QtGui/qmatrix4x4.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QOpenGLContext;
class QOpenGLShaderProgram;
class QOpenGLShaderPrivate;
class Q_GUI_EXPORT QOpenGLShader : public QObject
{
Q_OBJECT
public:
enum ShaderTypeBit
{
Vertex = 0x0001,
Fragment = 0x0002,
Geometry = 0x0004
};
Q_DECLARE_FLAGS(ShaderType, ShaderTypeBit)
explicit QOpenGLShader(QOpenGLShader::ShaderType type, QObject *parent = 0);
virtual ~QOpenGLShader();
QOpenGLShader::ShaderType shaderType() const;
bool compileSourceCode(const char *source);
bool compileSourceCode(const QByteArray& source);
bool compileSourceCode(const QString& source);
bool compileSourceFile(const QString& fileName);
QByteArray sourceCode() const;
bool isCompiled() const;
QString log() const;
GLuint shaderId() const;
static bool hasOpenGLShaders(ShaderType type, QOpenGLContext *context = 0);
private:
friend class QOpenGLShaderProgram;
Q_DISABLE_COPY(QOpenGLShader)
Q_DECLARE_PRIVATE(QOpenGLShader)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLShader::ShaderType)
class QOpenGLShaderProgramPrivate;
#ifndef GL_EXT_geometry_shader4
# define GL_LINES_ADJACENCY_EXT 0xA
# define GL_LINE_STRIP_ADJACENCY_EXT 0xB
# define GL_TRIANGLES_ADJACENCY_EXT 0xC
# define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0xD
#endif
class Q_GUI_EXPORT QOpenGLShaderProgram : public QObject
{
Q_OBJECT
public:
explicit QOpenGLShaderProgram(QObject *parent = 0);
virtual ~QOpenGLShaderProgram();
bool addShader(QOpenGLShader *shader);
void removeShader(QOpenGLShader *shader);
QList<QOpenGLShader *> shaders() const;
bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source);
bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray& source);
bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString& source);
bool addShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString& fileName);
void removeAllShaders();
virtual bool link();
bool isLinked() const;
QString log() const;
bool bind();
void release();
GLuint programId() const;
int maxGeometryOutputVertices() const;
void setGeometryOutputVertexCount(int count);
int geometryOutputVertexCount() const;
void setGeometryInputType(GLenum inputType);
GLenum geometryInputType() const;
void setGeometryOutputType(GLenum outputType);
GLenum geometryOutputType() const;
void bindAttributeLocation(const char *name, int location);
void bindAttributeLocation(const QByteArray& name, int location);
void bindAttributeLocation(const QString& name, int location);
int attributeLocation(const char *name) const;
int attributeLocation(const QByteArray& name) const;
int attributeLocation(const QString& name) const;
void setAttributeValue(int location, GLfloat value);
void setAttributeValue(int location, GLfloat x, GLfloat y);
void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z);
void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void setAttributeValue(int location, const QVector2D& value);
void setAttributeValue(int location, const QVector3D& value);
void setAttributeValue(int location, const QVector4D& value);
void setAttributeValue(int location, const QColor& value);
void setAttributeValue(int location, const GLfloat *values, int columns, int rows);
void setAttributeValue(const char *name, GLfloat value);
void setAttributeValue(const char *name, GLfloat x, GLfloat y);
void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z);
void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void setAttributeValue(const char *name, const QVector2D& value);
void setAttributeValue(const char *name, const QVector3D& value);
void setAttributeValue(const char *name, const QVector4D& value);
void setAttributeValue(const char *name, const QColor& value);
void setAttributeValue(const char *name, const GLfloat *values, int columns, int rows);
void setAttributeArray
(int location, const GLfloat *values, int tupleSize, int stride = 0);
void setAttributeArray
(int location, const QVector2D *values, int stride = 0);
void setAttributeArray
(int location, const QVector3D *values, int stride = 0);
void setAttributeArray
(int location, const QVector4D *values, int stride = 0);
void setAttributeArray
(int location, GLenum type, const void *values, int tupleSize, int stride = 0);
void setAttributeArray
(const char *name, const GLfloat *values, int tupleSize, int stride = 0);
void setAttributeArray
(const char *name, const QVector2D *values, int stride = 0);
void setAttributeArray
(const char *name, const QVector3D *values, int stride = 0);
void setAttributeArray
(const char *name, const QVector4D *values, int stride = 0);
void setAttributeArray
(const char *name, GLenum type, const void *values, int tupleSize, int stride = 0);
void setAttributeBuffer
(int location, GLenum type, int offset, int tupleSize, int stride = 0);
void setAttributeBuffer
(const char *name, GLenum type, int offset, int tupleSize, int stride = 0);
void enableAttributeArray(int location);
void enableAttributeArray(const char *name);
void disableAttributeArray(int location);
void disableAttributeArray(const char *name);
int uniformLocation(const char *name) const;
int uniformLocation(const QByteArray& name) const;
int uniformLocation(const QString& name) const;
void setUniformValue(int location, GLfloat value);
void setUniformValue(int location, GLint value);
void setUniformValue(int location, GLuint value);
void setUniformValue(int location, GLfloat x, GLfloat y);
void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z);
void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void setUniformValue(int location, const QVector2D& value);
void setUniformValue(int location, const QVector3D& value);
void setUniformValue(int location, const QVector4D& value);
void setUniformValue(int location, const QColor& color);
void setUniformValue(int location, const QPoint& point);
void setUniformValue(int location, const QPointF& point);
void setUniformValue(int location, const QSize& size);
void setUniformValue(int location, const QSizeF& size);
void setUniformValue(int location, const QMatrix2x2& value);
void setUniformValue(int location, const QMatrix2x3& value);
void setUniformValue(int location, const QMatrix2x4& value);
void setUniformValue(int location, const QMatrix3x2& value);
void setUniformValue(int location, const QMatrix3x3& value);
void setUniformValue(int location, const QMatrix3x4& value);
void setUniformValue(int location, const QMatrix4x2& value);
void setUniformValue(int location, const QMatrix4x3& value);
void setUniformValue(int location, const QMatrix4x4& value);
void setUniformValue(int location, const GLfloat value[2][2]);
void setUniformValue(int location, const GLfloat value[3][3]);
void setUniformValue(int location, const GLfloat value[4][4]);
void setUniformValue(int location, const QTransform& value);
void setUniformValue(const char *name, GLfloat value);
void setUniformValue(const char *name, GLint value);
void setUniformValue(const char *name, GLuint value);
void setUniformValue(const char *name, GLfloat x, GLfloat y);
void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z);
void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void setUniformValue(const char *name, const QVector2D& value);
void setUniformValue(const char *name, const QVector3D& value);
void setUniformValue(const char *name, const QVector4D& value);
void setUniformValue(const char *name, const QColor& color);
void setUniformValue(const char *name, const QPoint& point);
void setUniformValue(const char *name, const QPointF& point);
void setUniformValue(const char *name, const QSize& size);
void setUniformValue(const char *name, const QSizeF& size);
void setUniformValue(const char *name, const QMatrix2x2& value);
void setUniformValue(const char *name, const QMatrix2x3& value);
void setUniformValue(const char *name, const QMatrix2x4& value);
void setUniformValue(const char *name, const QMatrix3x2& value);
void setUniformValue(const char *name, const QMatrix3x3& value);
void setUniformValue(const char *name, const QMatrix3x4& value);
void setUniformValue(const char *name, const QMatrix4x2& value);
void setUniformValue(const char *name, const QMatrix4x3& value);
void setUniformValue(const char *name, const QMatrix4x4& value);
void setUniformValue(const char *name, const GLfloat value[2][2]);
void setUniformValue(const char *name, const GLfloat value[3][3]);
void setUniformValue(const char *name, const GLfloat value[4][4]);
void setUniformValue(const char *name, const QTransform& value);
void setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize);
void setUniformValueArray(int location, const GLint *values, int count);
void setUniformValueArray(int location, const GLuint *values, int count);
void setUniformValueArray(int location, const QVector2D *values, int count);
void setUniformValueArray(int location, const QVector3D *values, int count);
void setUniformValueArray(int location, const QVector4D *values, int count);
void setUniformValueArray(int location, const QMatrix2x2 *values, int count);
void setUniformValueArray(int location, const QMatrix2x3 *values, int count);
void setUniformValueArray(int location, const QMatrix2x4 *values, int count);
void setUniformValueArray(int location, const QMatrix3x2 *values, int count);
void setUniformValueArray(int location, const QMatrix3x3 *values, int count);
void setUniformValueArray(int location, const QMatrix3x4 *values, int count);
void setUniformValueArray(int location, const QMatrix4x2 *values, int count);
void setUniformValueArray(int location, const QMatrix4x3 *values, int count);
void setUniformValueArray(int location, const QMatrix4x4 *values, int count);
void setUniformValueArray(const char *name, const GLfloat *values, int count, int tupleSize);
void setUniformValueArray(const char *name, const GLint *values, int count);
void setUniformValueArray(const char *name, const GLuint *values, int count);
void setUniformValueArray(const char *name, const QVector2D *values, int count);
void setUniformValueArray(const char *name, const QVector3D *values, int count);
void setUniformValueArray(const char *name, const QVector4D *values, int count);
void setUniformValueArray(const char *name, const QMatrix2x2 *values, int count);
void setUniformValueArray(const char *name, const QMatrix2x3 *values, int count);
void setUniformValueArray(const char *name, const QMatrix2x4 *values, int count);
void setUniformValueArray(const char *name, const QMatrix3x2 *values, int count);
void setUniformValueArray(const char *name, const QMatrix3x3 *values, int count);
void setUniformValueArray(const char *name, const QMatrix3x4 *values, int count);
void setUniformValueArray(const char *name, const QMatrix4x2 *values, int count);
void setUniformValueArray(const char *name, const QMatrix4x3 *values, int count);
void setUniformValueArray(const char *name, const QMatrix4x4 *values, int count);
static bool hasOpenGLShaderPrograms(QOpenGLContext *context = 0);
private Q_SLOTS:
void shaderDestroyed();
private:
Q_DISABLE_COPY(QOpenGLShaderProgram)
Q_DECLARE_PRIVATE(QOpenGLShaderProgram)
bool init();
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,338 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QGRAPHICSCONTEXT_OPENGL2_P_H
#define QGRAPHICSCONTEXT_OPENGL2_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QDebug>
#include <private/qpaintengineex_p.h>
#include <private/qopenglengineshadermanager_p.h>
#include <private/qopengl2pexvertexarray_p.h>
#include <private/qopenglpaintdevice_p.h>
#include <private/qfontengine_p.h>
#include <private/qdatabuffer_p.h>
#include <private/qtriangulatingstroker_p.h>
#include <private/qopenglextensions_p.h>
enum EngineMode {
ImageDrawingMode,
TextDrawingMode,
BrushDrawingMode,
ImageArrayDrawingMode
};
QT_BEGIN_NAMESPACE
#define GL_STENCIL_HIGH_BIT GLuint(0x80)
#define QT_BRUSH_TEXTURE_UNIT GLuint(0)
#define QT_IMAGE_TEXTURE_UNIT GLuint(0) //Can be the same as brush texture unit
#define QT_MASK_TEXTURE_UNIT GLuint(1)
#define QT_BACKGROUND_TEXTURE_UNIT GLuint(2)
class QOpenGL2PaintEngineExPrivate;
class QOpenGL2PaintEngineState : public QPainterState
{
public:
QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other);
QOpenGL2PaintEngineState();
~QOpenGL2PaintEngineState();
uint isNew : 1;
uint needsClipBufferClear : 1;
uint clipTestEnabled : 1;
uint canRestoreClip : 1;
uint matrixChanged : 1;
uint compositionModeChanged : 1;
uint opacityChanged : 1;
uint renderHintsChanged : 1;
uint clipChanged : 1;
uint currentClip : 8;
QRect rectangleClip;
};
class Q_GUI_EXPORT QOpenGL2PaintEngineEx : public QPaintEngineEx
{
Q_DECLARE_PRIVATE(QOpenGL2PaintEngineEx)
public:
QOpenGL2PaintEngineEx();
~QOpenGL2PaintEngineEx();
bool begin(QPaintDevice *device);
void ensureActive();
bool end();
virtual void clipEnabledChanged();
virtual void penChanged();
virtual void brushChanged();
virtual void brushOriginChanged();
virtual void opacityChanged();
virtual void compositionModeChanged();
virtual void renderHintsChanged();
virtual void transformChanged();
virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
virtual void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap,
QPainter::PixmapFragmentHints hints);
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
Qt::ImageConversionFlags flags = Qt::AutoColor);
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
virtual void fill(const QVectorPath &path, const QBrush &brush);
virtual void stroke(const QVectorPath &path, const QPen &pen);
virtual void clip(const QVectorPath &path, Qt::ClipOperation op);
virtual void drawStaticTextItem(QStaticTextItem *textItem);
bool drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr);
Type type() const { return OpenGL2; }
virtual void setState(QPainterState *s);
virtual QPainterState *createState(QPainterState *orig) const;
inline QOpenGL2PaintEngineState *state() {
return static_cast<QOpenGL2PaintEngineState *>(QPaintEngineEx::state());
}
inline const QOpenGL2PaintEngineState *state() const {
return static_cast<const QOpenGL2PaintEngineState *>(QPaintEngineEx::state());
}
void beginNativePainting();
void endNativePainting();
void invalidateState();
void setRenderTextActive(bool);
bool isNativePaintingActive() const;
bool supportsTransformations(qreal, const QTransform &) const { return true; }
private:
Q_DISABLE_COPY(QOpenGL2PaintEngineEx)
friend class QOpenGLEngineShaderManager;
};
// This probably needs to grow to GL_MAX_VERTEX_ATTRIBS, but 3 is ok for now as that's
// all the GL2 engine uses:
#define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3
class QOpenGL2PaintEngineExPrivate : public QPaintEngineExPrivate
{
Q_DECLARE_PUBLIC(QOpenGL2PaintEngineEx)
public:
enum StencilFillMode {
OddEvenFillMode,
WindingFillMode,
TriStripStrokeFillMode
};
QOpenGL2PaintEngineExPrivate(QOpenGL2PaintEngineEx *q_ptr) :
q(q_ptr),
shaderManager(0),
width(0), height(0),
ctx(0),
useSystemClip(true),
elementIndicesVBOId(0),
opacityArray(0),
snapToPixelGrid(false),
nativePaintingActive(false),
inverseScale(1),
lastMaskTextureUsed(0)
{ }
~QOpenGL2PaintEngineExPrivate();
void updateBrushTexture();
void updateBrushUniforms();
void updateMatrix();
void updateCompositionMode();
void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id = -1);
void resetGLState();
// fill, stroke, drawTexture, drawPixmaps & drawCachedGlyphs are the main rendering entry-points,
// however writeClip can also be thought of as en entry point as it does similar things.
void fill(const QVectorPath &path);
void stroke(const QVectorPath &path, const QPen &pen);
void drawTexture(const QOpenGLRect& dest, const QOpenGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false);
void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap,
QPainter::PixmapFragmentHints hints);
void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem);
// Calls glVertexAttributePointer if the pointer has changed
inline void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer);
// draws whatever is in the vertex array:
void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive);
void drawVertexArrays(QOpenGL2PEXVertexArray &vertexArray, GLenum primitive) {
drawVertexArrays((const float *) vertexArray.data(), vertexArray.stops(), vertexArray.stopCount(), primitive);
}
// Composites the bounding rect onto dest buffer:
void composite(const QOpenGLRect& boundingRect);
// Calls drawVertexArrays to render into stencil buffer:
void fillStencilWithVertexArray(const float *data, int count, int *stops, int stopCount, const QOpenGLRect &bounds, StencilFillMode mode);
void fillStencilWithVertexArray(QOpenGL2PEXVertexArray& vertexArray, bool useWindingFill) {
fillStencilWithVertexArray((const float *) vertexArray.data(), 0, vertexArray.stops(), vertexArray.stopCount(),
vertexArray.boundingRect(),
useWindingFill ? WindingFillMode : OddEvenFillMode);
}
void setBrush(const QBrush& brush);
void transferMode(EngineMode newMode);
bool prepareForDraw(bool srcPixelsAreOpaque); // returns true if the program has changed
inline void useSimpleShader();
inline GLuint location(const QOpenGLEngineShaderManager::Uniform uniform) {
return shaderManager->getUniformLocation(uniform);
}
void clearClip(uint value);
void writeClip(const QVectorPath &path, uint value);
void resetClipIfNeeded();
void updateClipScissorTest();
void setScissor(const QRect &rect);
void regenerateClip();
void systemStateChanged();
void setVertexAttribArrayEnabled(int arrayIndex, bool enabled = true);
void syncGlState();
static QOpenGLEngineShaderManager* shaderManagerForEngine(QOpenGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; }
static QOpenGL2PaintEngineExPrivate *getData(QOpenGL2PaintEngineEx *engine) { return engine->d_func(); }
static void cleanupVectorPath(QPaintEngineEx *engine, void *data);
QOpenGLExtensions funcs;
QOpenGL2PaintEngineEx* q;
QOpenGLEngineShaderManager* shaderManager;
QOpenGLPaintDevice* device;
int width, height;
QOpenGLContext *ctx;
EngineMode mode;
QFontEngineGlyphCache::Type glyphCacheType;
bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT];
// Dirty flags
bool matrixDirty; // Implies matrix uniforms are also dirty
bool compositionModeDirty;
bool brushTextureDirty;
bool brushUniformsDirty;
bool opacityUniformDirty;
bool matrixUniformDirty;
bool stencilClean; // Has the stencil not been used for clipping so far?
bool useSystemClip;
QRegion dirtyStencilRegion;
QRect currentScissorBounds;
uint maxClip;
QBrush currentBrush; // May not be the state's brush!
const QBrush noBrush;
QPixmap currentBrushPixmap;
QOpenGL2PEXVertexArray vertexCoordinateArray;
QOpenGL2PEXVertexArray textureCoordinateArray;
QVector<GLushort> elementIndices;
GLuint elementIndicesVBOId;
QDataBuffer<GLfloat> opacityArray;
GLfloat staticVertexCoordinateArray[8];
GLfloat staticTextureCoordinateArray[8];
bool snapToPixelGrid;
bool nativePaintingActive;
GLfloat pmvMatrix[3][3];
GLfloat inverseScale;
GLuint lastTextureUsed;
GLuint lastMaskTextureUsed;
bool needsSync;
bool multisamplingAlwaysEnabled;
GLfloat depthRange[2];
float textureInvertedY;
QTriangulatingStroker stroker;
QDashedStrokeProcessor dasher;
QSet<QVectorPath::CacheEntry *> pathCaches;
QVector<GLuint> unusedVBOSToClean;
QVector<GLuint> unusedIBOSToClean;
const GLfloat *vertexAttribPointers[3];
};
void QOpenGL2PaintEngineExPrivate::setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer)
{
Q_ASSERT(arrayIndex < 3);
if (pointer == vertexAttribPointers[arrayIndex])
return;
vertexAttribPointers[arrayIndex] = pointer;
if (arrayIndex == QT_OPACITY_ATTR)
funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, pointer);
else
funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, pointer);
}
QT_END_NAMESPACE
#endif

573
src/gui/opengl/qrbtree_p.h Normal file
View File

@ -0,0 +1,573 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QRBTREE_P_H
#define QRBTREE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
template <class T>
struct QRBTree
{
struct Node
{
inline Node() : parent(0), left(0), right(0), red(true) { }
inline ~Node() {if (left) delete left; if (right) delete right;}
T data;
Node *parent;
Node *left;
Node *right;
bool red;
};
inline QRBTree() : root(0), freeList(0) { }
inline ~QRBTree();
inline void clear();
void attachBefore(Node *parent, Node *child);
void attachAfter(Node *parent, Node *child);
inline Node *front(Node *node) const;
inline Node *back(Node *node) const;
Node *next(Node *node) const;
Node *previous(Node *node) const;
inline void deleteNode(Node *&node);
inline Node *newNode();
// Return 1 if 'left' comes after 'right', 0 if equal, and -1 otherwise.
// 'left' and 'right' cannot be null.
int order(Node *left, Node *right);
inline bool validate() const;
private:
void rotateLeft(Node *node);
void rotateRight(Node *node);
void update(Node *node);
inline void attachLeft(Node *parent, Node *child);
inline void attachRight(Node *parent, Node *child);
int blackDepth(Node *top) const;
bool checkRedBlackProperty(Node *top) const;
void swapNodes(Node *n1, Node *n2);
void detach(Node *node);
// 'node' must be black. rebalance will reduce the depth of black nodes by one in the sibling tree.
void rebalance(Node *node);
public:
Node *root;
private:
Node *freeList;
};
template <class T>
inline QRBTree<T>::~QRBTree()
{
clear();
while (freeList) {
// Avoid recursively calling the destructor, as this list may become large.
Node *next = freeList->right;
freeList->right = 0;
delete freeList;
freeList = next;
}
}
template <class T>
inline void QRBTree<T>::clear()
{
if (root)
delete root;
root = 0;
}
template <class T>
void QRBTree<T>::rotateLeft(Node *node)
{
// | | //
// N B //
// / \ / \ //
// A B ---> N D //
// / \ / \ //
// C D A C //
Node *&ref = (node->parent ? (node == node->parent->left ? node->parent->left : node->parent->right) : root);
ref = node->right;
node->right->parent = node->parent;
// : //
// N //
// / :| //
// A B //
// / \ //
// C D //
node->right = ref->left;
if (ref->left)
ref->left->parent = node;
// : | //
// N B //
// / \ : \ //
// A C D //
ref->left = node;
node->parent = ref;
// | //
// B //
// / \ //
// N D //
// / \ //
// A C //
}
template <class T>
void QRBTree<T>::rotateRight(Node *node)
{
// | | //
// N A //
// / \ / \ //
// A B ---> C N //
// / \ / \ //
// C D D B //
Node *&ref = (node->parent ? (node == node->parent->left ? node->parent->left : node->parent->right) : root);
ref = node->left;
node->left->parent = node->parent;
node->left = ref->right;
if (ref->right)
ref->right->parent = node;
ref->right = node;
node->parent = ref;
}
template <class T>
void QRBTree<T>::update(Node *node) // call this after inserting a node
{
for (;;) {
Node *parent = node->parent;
// if the node is the root, color it black
if (!parent) {
node->red = false;
return;
}
// if the parent is black, the node can be left red
if (!parent->red)
return;
// at this point, the parent is red and cannot be the root
Node *grandpa = parent->parent;
Q_ASSERT(grandpa);
Node *uncle = (parent == grandpa->left ? grandpa->right : grandpa->left);
if (uncle && uncle->red) {
// grandpa's black, parent and uncle are red.
// let parent and uncle be black, grandpa red and recursively update grandpa.
Q_ASSERT(!grandpa->red);
parent->red = false;
uncle->red = false;
grandpa->red = true;
node = grandpa;
continue;
}
// at this point, uncle is black
if (node == parent->right && parent == grandpa->left)
rotateLeft(node = parent);
else if (node == parent->left && parent == grandpa->right)
rotateRight(node = parent);
parent = node->parent;
if (parent == grandpa->left) {
rotateRight(grandpa);
parent->red = false;
grandpa->red = true;
} else {
rotateLeft(grandpa);
parent->red = false;
grandpa->red = true;
}
return;
}
}
template <class T>
inline void QRBTree<T>::attachLeft(Node *parent, Node *child)
{
Q_ASSERT(!parent->left);
parent->left = child;
child->parent = parent;
update(child);
}
template <class T>
inline void QRBTree<T>::attachRight(Node *parent, Node *child)
{
Q_ASSERT(!parent->right);
parent->right = child;
child->parent = parent;
update(child);
}
template <class T>
void QRBTree<T>::attachBefore(Node *parent, Node *child)
{
if (!root)
update(root = child);
else if (!parent)
attachRight(back(root), child);
else if (parent->left)
attachRight(back(parent->left), child);
else
attachLeft(parent, child);
}
template <class T>
void QRBTree<T>::attachAfter(Node *parent, Node *child)
{
if (!root)
update(root = child);
else if (!parent)
attachLeft(front(root), child);
else if (parent->right)
attachLeft(front(parent->right), child);
else
attachRight(parent, child);
}
template <class T>
void QRBTree<T>::swapNodes(Node *n1, Node *n2)
{
// Since iterators must not be invalidated, it is not sufficient to only swap the data.
if (n1->parent == n2) {
n1->parent = n2->parent;
n2->parent = n1;
} else if (n2->parent == n1) {
n2->parent = n1->parent;
n1->parent = n2;
} else {
qSwap(n1->parent, n2->parent);
}
qSwap(n1->left, n2->left);
qSwap(n1->right, n2->right);
qSwap(n1->red, n2->red);
if (n1->parent) {
if (n1->parent->left == n2)
n1->parent->left = n1;
else
n1->parent->right = n1;
} else {
root = n1;
}
if (n2->parent) {
if (n2->parent->left == n1)
n2->parent->left = n2;
else
n2->parent->right = n2;
} else {
root = n2;
}
if (n1->left)
n1->left->parent = n1;
if (n1->right)
n1->right->parent = n1;
if (n2->left)
n2->left->parent = n2;
if (n2->right)
n2->right->parent = n2;
}
template <class T>
void QRBTree<T>::detach(Node *node) // call this before removing a node.
{
if (node->right)
swapNodes(node, front(node->right));
Node *child = (node->left ? node->left : node->right);
if (!node->red) {
if (child && child->red)
child->red = false;
else
rebalance(node);
}
Node *&ref = (node->parent ? (node == node->parent->left ? node->parent->left : node->parent->right) : root);
ref = child;
if (child)
child->parent = node->parent;
node->left = node->right = node->parent = 0;
}
// 'node' must be black. rebalance will reduce the depth of black nodes by one in the sibling tree.
template <class T>
void QRBTree<T>::rebalance(Node *node)
{
Q_ASSERT(!node->red);
for (;;) {
if (!node->parent)
return;
// at this point, node is not a parent, it is black, thus it must have a sibling.
Node *sibling = (node == node->parent->left ? node->parent->right : node->parent->left);
Q_ASSERT(sibling);
if (sibling->red) {
sibling->red = false;
node->parent->red = true;
if (node == node->parent->left)
rotateLeft(node->parent);
else
rotateRight(node->parent);
sibling = (node == node->parent->left ? node->parent->right : node->parent->left);
Q_ASSERT(sibling);
}
// at this point, the sibling is black.
Q_ASSERT(!sibling->red);
if ((!sibling->left || !sibling->left->red) && (!sibling->right || !sibling->right->red)) {
bool parentWasRed = node->parent->red;
sibling->red = true;
node->parent->red = false;
if (parentWasRed)
return;
node = node->parent;
continue;
}
// at this point, at least one of the sibling's children is red.
if (node == node->parent->left) {
if (!sibling->right || !sibling->right->red) {
Q_ASSERT(sibling->left);
sibling->red = true;
sibling->left->red = false;
rotateRight(sibling);
sibling = sibling->parent;
Q_ASSERT(sibling);
}
sibling->red = node->parent->red;
node->parent->red = false;
Q_ASSERT(sibling->right->red);
sibling->right->red = false;
rotateLeft(node->parent);
} else {
if (!sibling->left || !sibling->left->red) {
Q_ASSERT(sibling->right);
sibling->red = true;
sibling->right->red = false;
rotateLeft(sibling);
sibling = sibling->parent;
Q_ASSERT(sibling);
}
sibling->red = node->parent->red;
node->parent->red = false;
Q_ASSERT(sibling->left->red);
sibling->left->red = false;
rotateRight(node->parent);
}
return;
}
}
template <class T>
inline typename QRBTree<T>::Node *QRBTree<T>::front(Node *node) const
{
while (node->left)
node = node->left;
return node;
}
template <class T>
inline typename QRBTree<T>::Node *QRBTree<T>::back(Node *node) const
{
while (node->right)
node = node->right;
return node;
}
template <class T>
typename QRBTree<T>::Node *QRBTree<T>::next(Node *node) const
{
if (node->right)
return front(node->right);
while (node->parent && node == node->parent->right)
node = node->parent;
return node->parent;
}
template <class T>
typename QRBTree<T>::Node *QRBTree<T>::previous(Node *node) const
{
if (node->left)
return back(node->left);
while (node->parent && node == node->parent->left)
node = node->parent;
return node->parent;
}
template <class T>
int QRBTree<T>::blackDepth(Node *top) const
{
if (!top)
return 0;
int leftDepth = blackDepth(top->left);
int rightDepth = blackDepth(top->right);
if (leftDepth != rightDepth)
return -1;
if (!top->red)
++leftDepth;
return leftDepth;
}
template <class T>
bool QRBTree<T>::checkRedBlackProperty(Node *top) const
{
if (!top)
return true;
if (top->left && !checkRedBlackProperty(top->left))
return false;
if (top->right && !checkRedBlackProperty(top->right))
return false;
return !(top->red && ((top->left && top->left->red) || (top->right && top->right->red)));
}
template <class T>
inline bool QRBTree<T>::validate() const
{
return checkRedBlackProperty(root) && blackDepth(root) != -1;
}
template <class T>
inline void QRBTree<T>::deleteNode(Node *&node)
{
Q_ASSERT(node);
detach(node);
node->right = freeList;
freeList = node;
node = 0;
}
template <class T>
inline typename QRBTree<T>::Node *QRBTree<T>::newNode()
{
if (freeList) {
Node *node = freeList;
freeList = freeList->right;
node->parent = node->left = node->right = 0;
node->red = true;
return node;
}
return new Node;
}
// Return 1 if 'left' comes after 'right', 0 if equal, and -1 otherwise.
// 'left' and 'right' cannot be null.
template <class T>
int QRBTree<T>::order(Node *left, Node *right)
{
Q_ASSERT(left && right);
if (left == right)
return 0;
QVector<Node *> leftAncestors;
QVector<Node *> rightAncestors;
while (left) {
leftAncestors.push_back(left);
left = left->parent;
}
while (right) {
rightAncestors.push_back(right);
right = right->parent;
}
Q_ASSERT(leftAncestors.back() == root && rightAncestors.back() == root);
while (!leftAncestors.empty() && !rightAncestors.empty() && leftAncestors.back() == rightAncestors.back()) {
leftAncestors.pop_back();
rightAncestors.pop_back();
}
if (!leftAncestors.empty())
return (leftAncestors.back() == leftAncestors.back()->parent->left ? -1 : 1);
if (!rightAncestors.empty())
return (rightAncestors.back() == rightAncestors.back()->parent->right ? -1 : 1);
// The code should never reach this point.
Q_ASSERT(!leftAncestors.empty() || !rightAncestors.empty());
return 0;
}
QT_END_NAMESPACE
#endif

View File

@ -0,0 +1,396 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtextureglyphcache_gl_p.h"
#include "qpaintengineex_opengl2_p.h"
#include "private/qopenglengineshadersource_p.h"
QT_BEGIN_NAMESPACE
#ifdef Q_WS_WIN
extern Q_GUI_EXPORT bool qt_cleartype_enabled;
#endif
QBasicAtomicInt qopengltextureglyphcache_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
QOpenGLTextureGlyphCache::QOpenGLTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix)
: QImageTextureGlyphCache(type, matrix)
, pex(0)
, m_blitProgram(0)
, m_filterMode(Nearest)
, m_serialNumber(qopengltextureglyphcache_serial_number.fetchAndAddRelaxed(1))
{
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
qDebug(" -> QOpenGLTextureGlyphCache() %p for context %p.", this, QOpenGLContext::currentContext());
#endif
m_vertexCoordinateArray[0] = -1.0f;
m_vertexCoordinateArray[1] = -1.0f;
m_vertexCoordinateArray[2] = 1.0f;
m_vertexCoordinateArray[3] = -1.0f;
m_vertexCoordinateArray[4] = 1.0f;
m_vertexCoordinateArray[5] = 1.0f;
m_vertexCoordinateArray[6] = -1.0f;
m_vertexCoordinateArray[7] = 1.0f;
m_textureCoordinateArray[0] = 0.0f;
m_textureCoordinateArray[1] = 0.0f;
m_textureCoordinateArray[2] = 1.0f;
m_textureCoordinateArray[3] = 0.0f;
m_textureCoordinateArray[4] = 1.0f;
m_textureCoordinateArray[5] = 1.0f;
m_textureCoordinateArray[6] = 0.0f;
m_textureCoordinateArray[7] = 1.0f;
}
QOpenGLTextureGlyphCache::~QOpenGLTextureGlyphCache()
{
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
qDebug(" -> ~QOpenGLTextureGlyphCache() %p.", this);
#endif
delete m_blitProgram;
}
void QOpenGLTextureGlyphCache::createTextureData(int width, int height)
{
QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
if (ctx == 0) {
qWarning("QOpenGLTextureGlyphCache::createTextureData: Called with no context");
return;
}
// create in QImageTextureGlyphCache baseclass is meant to be called
// only to create the initial image and does not preserve the content,
// so we don't call when this function is called from resize.
if (ctx->d_func()->workaround_brokenFBOReadBack && image().isNull())
QImageTextureGlyphCache::createTextureData(width, height);
// Make the lower glyph texture size 16 x 16.
if (width < 16)
width = 16;
if (height < 16)
height = 16;
if (m_textureResource && !m_textureResource->m_texture)
delete m_textureResource;
if (!m_textureResource)
m_textureResource = new QOpenGLGlyphTexture(ctx);
glGenTextures(1, &m_textureResource->m_texture);
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
m_textureResource->m_width = width;
m_textureResource->m_height = height;
if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
QVarLengthArray<uchar> data(width * height * 4);
for (int i = 0; i < data.size(); ++i)
data[i] = 0;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
} else {
QVarLengthArray<uchar> data(width * height);
for (int i = 0; i < data.size(); ++i)
data[i] = 0;
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
}
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_filterMode = Nearest;
}
void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height)
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx == 0) {
qWarning("QOpenGLTextureGlyphCache::resizeTextureData: Called with no context");
return;
}
int oldWidth = m_textureResource->m_width;
int oldHeight = m_textureResource->m_height;
// Make the lower glyph texture size 16 x 16.
if (width < 16)
width = 16;
if (height < 16)
height = 16;
GLuint oldTexture = m_textureResource->m_texture;
createTextureData(width, height);
if (ctx->d_func()->workaround_brokenFBOReadBack) {
QImageTextureGlyphCache::resizeTextureData(width, height);
Q_ASSERT(image().depth() == 8);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, image().constBits());
glDeleteTextures(1, &oldTexture);
return;
}
// ### the QTextureGlyphCache API needs to be reworked to allow
// ### resizeTextureData to fail
QOpenGLFunctions funcs(ctx);
funcs.glBindFramebuffer(GL_FRAMEBUFFER, m_textureResource->m_fbo);
GLuint tmp_texture;
glGenTextures(1, &tmp_texture);
glBindTexture(GL_TEXTURE_2D, tmp_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_filterMode = Nearest;
glBindTexture(GL_TEXTURE_2D, 0);
funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tmp_texture, 0);
funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, oldTexture);
if (pex != 0)
pex->transferMode(BrushDrawingMode);
glDisable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glViewport(0, 0, oldWidth, oldHeight);
QOpenGLShaderProgram *blitProgram = 0;
if (pex == 0) {
if (m_blitProgram == 0) {
m_blitProgram = new QOpenGLShaderProgram(ctx);
{
QString source;
source.append(QLatin1String(qopenglslMainWithTexCoordsVertexShader));
source.append(QLatin1String(qopenglslUntransformedPositionVertexShader));
QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram);
vertexShader->compileSourceCode(source);
m_blitProgram->addShader(vertexShader);
}
{
QString source;
source.append(QLatin1String(qopenglslMainFragmentShader));
source.append(QLatin1String(qopenglslImageSrcFragmentShader));
QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram);
fragmentShader->compileSourceCode(source);
m_blitProgram->addShader(fragmentShader);
}
m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
m_blitProgram->link();
}
funcs.glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_vertexCoordinateArray);
funcs.glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_textureCoordinateArray);
m_blitProgram->bind();
m_blitProgram->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
m_blitProgram->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
m_blitProgram->disableAttributeArray(int(QT_OPACITY_ATTR));
blitProgram = m_blitProgram;
} else {
pex->setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, m_vertexCoordinateArray);
pex->setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, m_textureCoordinateArray);
pex->shaderManager->useBlitProgram();
blitProgram = pex->shaderManager->blitProgram();
}
blitProgram->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, 0);
glDeleteTextures(1, &tmp_texture);
glDeleteTextures(1, &oldTexture);
funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo);
if (pex != 0) {
glViewport(0, 0, pex->width, pex->height);
pex->updateClipScissorTest();
}
}
void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition)
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx == 0) {
qWarning("QOpenGLTextureGlyphCache::fillTexture: Called with no context");
return;
}
if (ctx->d_func()->workaround_brokenFBOReadBack) {
QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition);
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
const QImage &texture = image();
const uchar *bits = texture.constBits();
bits += c.y * texture.bytesPerLine() + c.x;
for (int i=0; i<c.h; ++i) {
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, c.w, 1, GL_ALPHA, GL_UNSIGNED_BYTE, bits);
bits += texture.bytesPerLine();
}
return;
}
QImage mask = textureMapForGlyph(glyph, subPixelPosition);
const int maskWidth = mask.width();
const int maskHeight = mask.height();
if (mask.format() == QImage::Format_Mono) {
mask = mask.convertToFormat(QImage::Format_Indexed8);
for (int y = 0; y < maskHeight; ++y) {
uchar *src = (uchar *) mask.scanLine(y);
for (int x = 0; x < maskWidth; ++x)
src[x] = -src[x]; // convert 0 and 1 into 0 and 255
}
} else if (mask.format() == QImage::Format_RGB32) {
// Make the alpha component equal to the average of the RGB values.
// This is needed when drawing sub-pixel antialiased text on translucent targets.
for (int y = 0; y < maskHeight; ++y) {
quint32 *src = (quint32 *) mask.scanLine(y);
for (int x = 0; x < maskWidth; ++x) {
uchar r = src[x] >> 16;
uchar g = src[x] >> 8;
uchar b = src[x];
quint32 avg = (quint32(r) + quint32(g) + quint32(b) + 1) / 3; // "+1" for rounding.
src[x] = (src[x] & 0x00ffffff) | (avg << 24);
}
}
}
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
if (mask.format() == QImage::Format_RGB32) {
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
} else {
// glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is
// not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista
// and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a
// multiple of four bytes per line, and most of the glyph shows up correctly in the
// texture, which makes me think that this is a driver bug.
// One workaround is to make sure the mask width is a multiple of four bytes, for instance
// by converting it to a format with four bytes per pixel. Another is to copy one line at a
// time.
#if 0
if (!ctx->d_func()->workaround_brokenAlphaTexSubImage_init) {
// don't know which driver versions exhibit this bug, so be conservative for now
const QByteArray versionString(reinterpret_cast<const char*>(glGetString(GL_VERSION)));
glctx->d_func()->workaround_brokenAlphaTexSubImage = versionString.indexOf("NVIDIA") >= 0;
glctx->d_func()->workaround_brokenAlphaTexSubImage_init = true;
}
#endif
#if 0
if (ctx->d_func()->workaround_brokenAlphaTexSubImage) {
for (int i = 0; i < maskHeight; ++i)
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i));
} else {
#endif
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
// }
}
}
int QOpenGLTextureGlyphCache::glyphPadding() const
{
return 1;
}
int QOpenGLTextureGlyphCache::maxTextureWidth() const
{
QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
if (ctx == 0)
return QImageTextureGlyphCache::maxTextureWidth();
else
return ctx->d_func()->maxTextureSize();
}
int QOpenGLTextureGlyphCache::maxTextureHeight() const
{
QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
if (ctx == 0)
return QImageTextureGlyphCache::maxTextureHeight();
if (ctx->d_func()->workaround_brokenTexSubImage)
return qMin(1024, ctx->d_func()->maxTextureSize());
else
return ctx->d_func()->maxTextureSize();
}
void QOpenGLTextureGlyphCache::clear()
{
m_textureResource->free();
m_textureResource = 0;
m_w = 0;
m_h = 0;
m_cx = 0;
m_cy = 0;
m_currentRowHeight = 0;
coords.clear();
}
QT_END_NAMESPACE

View File

@ -0,0 +1,169 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTEXTUREGLYPHCACHE_GL_P_H
#define QTEXTUREGLYPHCACHE_GL_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <private/qtextureglyphcache_p.h>
#include <private/qopenglcontext_p.h>
#include <qopenglshaderprogram.h>
#include <qopenglfunctions.h>
// #define QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
QT_BEGIN_NAMESPACE
class QOpenGL2PaintEngineExPrivate;
struct QOpenGLGlyphTexture : public QOpenGLSharedResource
{
QOpenGLGlyphTexture(QOpenGLContext *ctx)
: QOpenGLSharedResource(ctx->shareGroup())
, m_width(0)
, m_height(0)
{
if (ctx && !ctx->d_func()->workaround_brokenFBOReadBack)
QOpenGLFunctions(ctx).glGenFramebuffers(1, &m_fbo);
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
qDebug(" -> QOpenGLGlyphTexture() %p for context %p.", this, ctx);
#endif
}
void freeResource(QOpenGLContext *context)
{
QOpenGLContext *ctx = context;
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
qDebug("~QOpenGLGlyphTexture() %p for context %p.", this, ctx);
#endif
if (!ctx->d_func()->workaround_brokenFBOReadBack)
QOpenGLFunctions(ctx).glDeleteFramebuffers(1, &m_fbo);
if (m_width || m_height)
glDeleteTextures(1, &m_texture);
}
void invalidateResource()
{
m_texture = 0;
m_fbo = 0;
m_width = 0;
m_height = 0;
}
GLuint m_texture;
GLuint m_fbo;
int m_width;
int m_height;
};
class Q_GUI_EXPORT QOpenGLTextureGlyphCache : public QImageTextureGlyphCache
{
public:
QOpenGLTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix);
~QOpenGLTextureGlyphCache();
virtual void createTextureData(int width, int height);
virtual void resizeTextureData(int width, int height);
virtual void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition);
virtual int glyphPadding() const;
virtual int maxTextureWidth() const;
virtual int maxTextureHeight() const;
inline GLuint texture() const {
QOpenGLTextureGlyphCache *that = const_cast<QOpenGLTextureGlyphCache *>(this);
QOpenGLGlyphTexture *glyphTexture = that->m_textureResource;
return glyphTexture ? glyphTexture->m_texture : 0;
}
inline int width() const {
QOpenGLTextureGlyphCache *that = const_cast<QOpenGLTextureGlyphCache *>(this);
QOpenGLGlyphTexture *glyphTexture = that->m_textureResource;
return glyphTexture ? glyphTexture->m_width : 0;
}
inline int height() const {
QOpenGLTextureGlyphCache *that = const_cast<QOpenGLTextureGlyphCache *>(this);
QOpenGLGlyphTexture *glyphTexture = that->m_textureResource;
return glyphTexture ? glyphTexture->m_height : 0;
}
inline void setPaintEnginePrivate(QOpenGL2PaintEngineExPrivate *p) { pex = p; }
inline const QOpenGLContextGroup *contextGroup() const { return m_textureResource ? m_textureResource->group() : 0; }
inline int serialNumber() const { return m_serialNumber; }
enum FilterMode {
Nearest,
Linear
};
FilterMode filterMode() const { return m_filterMode; }
void setFilterMode(FilterMode m) { m_filterMode = m; }
void clear();
private:
QOpenGLGlyphTexture *m_textureResource;
QOpenGL2PaintEngineExPrivate *pex;
QOpenGLShaderProgram *m_blitProgram;
FilterMode m_filterMode;
GLfloat m_vertexCoordinateArray[8];
GLfloat m_textureCoordinateArray[8];
int m_serialNumber;
};
QT_END_NAMESPACE
#endif

View File

@ -0,0 +1,588 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtriangulatingstroker_p.h"
#include <qmath.h>
QT_BEGIN_NAMESPACE
#define CURVE_FLATNESS Q_PI / 8
void QTriangulatingStroker::endCapOrJoinClosed(const qreal *start, const qreal *cur,
bool implicitClose, bool endsAtStart)
{
if (endsAtStart) {
join(start + 2);
} else if (implicitClose) {
join(start);
lineTo(start);
join(start+2);
} else {
endCap(cur);
}
int count = m_vertices.size();
// Copy the (x, y) values because QDataBuffer::add(const float& t)
// may resize the buffer, which will leave t pointing at the
// previous buffer's memory region if we don't copy first.
float x = m_vertices.at(count-2);
float y = m_vertices.at(count-1);
m_vertices.add(x);
m_vertices.add(y);
}
void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, const QRectF &)
{
const qreal *pts = path.points();
const QPainterPath::ElementType *types = path.elements();
int count = path.elementCount();
if (count < 2)
return;
float realWidth = qpen_widthf(pen);
if (realWidth == 0)
realWidth = 1;
m_width = realWidth / 2;
bool cosmetic = pen.isCosmetic();
if (cosmetic) {
m_width = m_width * m_inv_scale;
}
m_join_style = qpen_joinStyle(pen);
m_cap_style = qpen_capStyle(pen);
m_vertices.reset();
m_miter_limit = pen.miterLimit() * qpen_widthf(pen);
// The curvyness is based on the notion that I originally wanted
// roughly one line segment pr 4 pixels. This may seem little, but
// because we sample at constantly incrementing B(t) E [0<t<1], we
// will get longer segments where the curvature is small and smaller
// segments when the curvature is high.
//
// To get a rough idea of the length of each curve, I pretend that
// the curve is a 90 degree arc, whose radius is
// qMax(curveBounds.width, curveBounds.height). Based on this
// logic we can estimate the length of the outline edges based on
// the radius + a pen width and adjusting for scale factors
// depending on if the pen is cosmetic or not.
//
// The curvyness value of PI/14 was based on,
// arcLength = 2*PI*r/4 = PI*r/2 and splitting length into somewhere
// between 3 and 8 where 5 seemed to be give pretty good results
// hence: Q_PI/14. Lower divisors will give more detail at the
// direct cost of performance.
// simplfy pens that are thin in device size (2px wide or less)
if (realWidth < 2.5 && (cosmetic || m_inv_scale == 1)) {
if (m_cap_style == Qt::RoundCap)
m_cap_style = Qt::SquareCap;
if (m_join_style == Qt::RoundJoin)
m_join_style = Qt::MiterJoin;
m_curvyness_add = 0.5;
m_curvyness_mul = CURVE_FLATNESS / m_inv_scale;
m_roundness = 1;
} else if (cosmetic) {
m_curvyness_add = realWidth / 2;
m_curvyness_mul = CURVE_FLATNESS;
m_roundness = qMax<int>(4, realWidth * CURVE_FLATNESS);
} else {
m_curvyness_add = m_width;
m_curvyness_mul = CURVE_FLATNESS / m_inv_scale;
m_roundness = qMax<int>(4, realWidth * m_curvyness_mul);
}
// Over this level of segmentation, there doesn't seem to be any
// benefit, even for huge penWidth
if (m_roundness > 24)
m_roundness = 24;
m_sin_theta = qFastSin(Q_PI / m_roundness);
m_cos_theta = qFastCos(Q_PI / m_roundness);
const qreal *endPts = pts + (count<<1);
const qreal *startPts = 0;
Qt::PenCapStyle cap = m_cap_style;
if (!types) {
// skip duplicate points
while((pts + 2) < endPts && pts[0] == pts[2] && pts[1] == pts[3])
pts += 2;
if ((pts + 2) == endPts)
return;
startPts = pts;
bool endsAtStart = startPts[0] == *(endPts-2) && startPts[1] == *(endPts-1);
if (endsAtStart || path.hasImplicitClose())
m_cap_style = Qt::FlatCap;
moveTo(pts);
m_cap_style = cap;
pts += 2;
lineTo(pts);
pts += 2;
while (pts < endPts) {
if (m_cx != pts[0] || m_cy != pts[1]) {
join(pts);
lineTo(pts);
}
pts += 2;
}
endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);
} else {
bool endsAtStart = false;
while (pts < endPts) {
switch (*types) {
case QPainterPath::MoveToElement: {
if (pts != path.points())
endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);
startPts = pts;
int end = (endPts - pts) / 2;
int i = 2; // Start looking to ahead since we never have two moveto's in a row
while (i<end && types[i] != QPainterPath::MoveToElement) {
++i;
}
endsAtStart = startPts[0] == pts[i*2 - 2] && startPts[1] == pts[i*2 - 1];
if (endsAtStart || path.hasImplicitClose())
m_cap_style = Qt::FlatCap;
moveTo(pts);
m_cap_style = cap;
pts+=2;
++types;
break; }
case QPainterPath::LineToElement:
if (*(types - 1) != QPainterPath::MoveToElement)
join(pts);
lineTo(pts);
pts+=2;
++types;
break;
case QPainterPath::CurveToElement:
if (*(types - 1) != QPainterPath::MoveToElement)
join(pts);
cubicTo(pts);
pts+=6;
types+=3;
break;
default:
Q_ASSERT(false);
break;
}
}
endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);
}
}
void QTriangulatingStroker::moveTo(const qreal *pts)
{
m_cx = pts[0];
m_cy = pts[1];
float x2 = pts[2];
float y2 = pts[3];
normalVector(m_cx, m_cy, x2, y2, &m_nvx, &m_nvy);
// To acheive jumps we insert zero-area tringles. This is done by
// adding two identical points in both the end of previous strip
// and beginning of next strip
bool invisibleJump = m_vertices.size();
switch (m_cap_style) {
case Qt::FlatCap:
if (invisibleJump) {
m_vertices.add(m_cx + m_nvx);
m_vertices.add(m_cy + m_nvy);
}
break;
case Qt::SquareCap: {
float sx = m_cx - m_nvy;
float sy = m_cy + m_nvx;
if (invisibleJump) {
m_vertices.add(sx + m_nvx);
m_vertices.add(sy + m_nvy);
}
emitLineSegment(sx, sy, m_nvx, m_nvy);
break; }
case Qt::RoundCap: {
QVarLengthArray<float> points;
arcPoints(m_cx, m_cy, m_cx + m_nvx, m_cy + m_nvy, m_cx - m_nvx, m_cy - m_nvy, points);
m_vertices.resize(m_vertices.size() + points.size() + 2 * int(invisibleJump));
int count = m_vertices.size();
int front = 0;
int end = points.size() / 2;
while (front != end) {
m_vertices.at(--count) = points[2 * end - 1];
m_vertices.at(--count) = points[2 * end - 2];
--end;
if (front == end)
break;
m_vertices.at(--count) = points[2 * front + 1];
m_vertices.at(--count) = points[2 * front + 0];
++front;
}
if (invisibleJump) {
m_vertices.at(count - 1) = m_vertices.at(count + 1);
m_vertices.at(count - 2) = m_vertices.at(count + 0);
}
break; }
default: break; // ssssh gcc...
}
emitLineSegment(m_cx, m_cy, m_nvx, m_nvy);
}
void QTriangulatingStroker::cubicTo(const qreal *pts)
{
const QPointF *p = (const QPointF *) pts;
QBezier bezier = QBezier::fromPoints(*(p - 1), p[0], p[1], p[2]);
QRectF bounds = bezier.bounds();
float rad = qMax(bounds.width(), bounds.height());
int threshold = qMin<float>(64, (rad + m_curvyness_add) * m_curvyness_mul);
if (threshold < 4)
threshold = 4;
qreal threshold_minus_1 = threshold - 1;
float vx, vy;
float cx = m_cx, cy = m_cy;
float x, y;
for (int i=1; i<threshold; ++i) {
qreal t = qreal(i) / threshold_minus_1;
QPointF p = bezier.pointAt(t);
x = p.x();
y = p.y();
normalVector(cx, cy, x, y, &vx, &vy);
emitLineSegment(x, y, vx, vy);
cx = x;
cy = y;
}
m_cx = cx;
m_cy = cy;
m_nvx = vx;
m_nvy = vy;
}
void QTriangulatingStroker::join(const qreal *pts)
{
// Creates a join to the next segment (m_cx, m_cy) -> (pts[0], pts[1])
normalVector(m_cx, m_cy, pts[0], pts[1], &m_nvx, &m_nvy);
switch (m_join_style) {
case Qt::BevelJoin:
break;
case Qt::SvgMiterJoin:
case Qt::MiterJoin: {
// Find out on which side the join should be.
int count = m_vertices.size();
float prevNvx = m_vertices.at(count - 2) - m_cx;
float prevNvy = m_vertices.at(count - 1) - m_cy;
float xprod = prevNvx * m_nvy - prevNvy * m_nvx;
float px, py, qx, qy;
// If the segments are parallel, use bevel join.
if (qFuzzyIsNull(xprod))
break;
// Find the corners of the previous and next segment to join.
if (xprod < 0) {
px = m_vertices.at(count - 2);
py = m_vertices.at(count - 1);
qx = m_cx - m_nvx;
qy = m_cy - m_nvy;
} else {
px = m_vertices.at(count - 4);
py = m_vertices.at(count - 3);
qx = m_cx + m_nvx;
qy = m_cy + m_nvy;
}
// Find intersection point.
float pu = px * prevNvx + py * prevNvy;
float qv = qx * m_nvx + qy * m_nvy;
float ix = (m_nvy * pu - prevNvy * qv) / xprod;
float iy = (prevNvx * qv - m_nvx * pu) / xprod;
// Check that the distance to the intersection point is less than the miter limit.
if ((ix - px) * (ix - px) + (iy - py) * (iy - py) <= m_miter_limit * m_miter_limit) {
m_vertices.add(ix);
m_vertices.add(iy);
m_vertices.add(ix);
m_vertices.add(iy);
}
// else
// Do a plain bevel join if the miter limit is exceeded or if
// the lines are parallel. This is not what the raster
// engine's stroker does, but it is both faster and similar to
// what some other graphics API's do.
break; }
case Qt::RoundJoin: {
QVarLengthArray<float> points;
int count = m_vertices.size();
float prevNvx = m_vertices.at(count - 2) - m_cx;
float prevNvy = m_vertices.at(count - 1) - m_cy;
if (m_nvx * prevNvy - m_nvy * prevNvx < 0) {
arcPoints(0, 0, m_nvx, m_nvy, -prevNvx, -prevNvy, points);
for (int i = points.size() / 2; i > 0; --i)
emitLineSegment(m_cx, m_cy, points[2 * i - 2], points[2 * i - 1]);
} else {
arcPoints(0, 0, -prevNvx, -prevNvy, m_nvx, m_nvy, points);
for (int i = 0; i < points.size() / 2; ++i)
emitLineSegment(m_cx, m_cy, points[2 * i + 0], points[2 * i + 1]);
}
break; }
default: break; // gcc warn--
}
emitLineSegment(m_cx, m_cy, m_nvx, m_nvy);
}
void QTriangulatingStroker::endCap(const qreal *)
{
switch (m_cap_style) {
case Qt::FlatCap:
break;
case Qt::SquareCap:
emitLineSegment(m_cx + m_nvy, m_cy - m_nvx, m_nvx, m_nvy);
break;
case Qt::RoundCap: {
QVarLengthArray<float> points;
int count = m_vertices.size();
arcPoints(m_cx, m_cy, m_vertices.at(count - 2), m_vertices.at(count - 1), m_vertices.at(count - 4), m_vertices.at(count - 3), points);
int front = 0;
int end = points.size() / 2;
while (front != end) {
m_vertices.add(points[2 * end - 2]);
m_vertices.add(points[2 * end - 1]);
--end;
if (front == end)
break;
m_vertices.add(points[2 * front + 0]);
m_vertices.add(points[2 * front + 1]);
++front;
}
break; }
default: break; // to shut gcc up...
}
}
void QTriangulatingStroker::arcPoints(float cx, float cy, float fromX, float fromY, float toX, float toY, QVarLengthArray<float> &points)
{
float dx1 = fromX - cx;
float dy1 = fromY - cy;
float dx2 = toX - cx;
float dy2 = toY - cy;
// while more than 180 degrees left:
while (dx1 * dy2 - dx2 * dy1 < 0) {
float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta;
float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta;
dx1 = tmpx;
dy1 = tmpy;
points.append(cx + dx1);
points.append(cy + dy1);
}
// while more than 90 degrees left:
while (dx1 * dx2 + dy1 * dy2 < 0) {
float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta;
float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta;
dx1 = tmpx;
dy1 = tmpy;
points.append(cx + dx1);
points.append(cy + dy1);
}
// while more than 0 degrees left:
while (dx1 * dy2 - dx2 * dy1 > 0) {
float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta;
float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta;
dx1 = tmpx;
dy1 = tmpy;
points.append(cx + dx1);
points.append(cy + dy1);
}
// remove last point which was rotated beyond [toX, toY].
if (!points.isEmpty())
points.resize(points.size() - 2);
}
static void qdashprocessor_moveTo(qreal x, qreal y, void *data)
{
((QDashedStrokeProcessor *) data)->addElement(QPainterPath::MoveToElement, x, y);
}
static void qdashprocessor_lineTo(qreal x, qreal y, void *data)
{
((QDashedStrokeProcessor *) data)->addElement(QPainterPath::LineToElement, x, y);
}
static void qdashprocessor_cubicTo(qreal, qreal, qreal, qreal, qreal, qreal, void *)
{
Q_ASSERT(0); // The dasher should not produce curves...
}
QDashedStrokeProcessor::QDashedStrokeProcessor()
: m_points(0), m_types(0),
m_dash_stroker(0), m_inv_scale(1)
{
m_dash_stroker.setMoveToHook(qdashprocessor_moveTo);
m_dash_stroker.setLineToHook(qdashprocessor_lineTo);
m_dash_stroker.setCubicToHook(qdashprocessor_cubicTo);
}
void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen, const QRectF &clip)
{
const qreal *pts = path.points();
const QPainterPath::ElementType *types = path.elements();
int count = path.elementCount();
bool cosmetic = pen.isCosmetic();
m_points.reset();
m_types.reset();
m_points.reserve(path.elementCount());
m_types.reserve(path.elementCount());
qreal width = qpen_widthf(pen);
if (width == 0)
width = 1;
m_dash_stroker.setDashPattern(pen.dashPattern());
m_dash_stroker.setStrokeWidth(cosmetic ? width * m_inv_scale : width);
m_dash_stroker.setDashOffset(pen.dashOffset());
m_dash_stroker.setMiterLimit(pen.miterLimit());
m_dash_stroker.setClipRect(clip);
float curvynessAdd, curvynessMul, roundness = 0;
// simplfy pens that are thin in device size (2px wide or less)
if (width < 2.5 && (cosmetic || m_inv_scale == 1)) {
curvynessAdd = 0.5;
curvynessMul = CURVE_FLATNESS / m_inv_scale;
roundness = 1;
} else if (cosmetic) {
curvynessAdd= width / 2;
curvynessMul= CURVE_FLATNESS;
roundness = qMax<int>(4, width * CURVE_FLATNESS);
} else {
curvynessAdd = width * m_inv_scale;
curvynessMul = CURVE_FLATNESS / m_inv_scale;
roundness = qMax<int>(4, width * curvynessMul);
}
if (count < 2)
return;
const qreal *endPts = pts + (count<<1);
m_dash_stroker.begin(this);
if (!types) {
m_dash_stroker.moveTo(pts[0], pts[1]);
pts += 2;
while (pts < endPts) {
m_dash_stroker.lineTo(pts[0], pts[1]);
pts += 2;
}
} else {
while (pts < endPts) {
switch (*types) {
case QPainterPath::MoveToElement:
m_dash_stroker.moveTo(pts[0], pts[1]);
pts += 2;
++types;
break;
case QPainterPath::LineToElement:
m_dash_stroker.lineTo(pts[0], pts[1]);
pts += 2;
++types;
break;
case QPainterPath::CurveToElement: {
QBezier b = QBezier::fromPoints(*(((const QPointF *) pts) - 1),
*(((const QPointF *) pts)),
*(((const QPointF *) pts) + 1),
*(((const QPointF *) pts) + 2));
QRectF bounds = b.bounds();
float rad = qMax(bounds.width(), bounds.height());
int threshold = qMin<float>(64, (rad + curvynessAdd) * curvynessMul);
if (threshold < 4)
threshold = 4;
qreal threshold_minus_1 = threshold - 1;
for (int i=0; i<threshold; ++i) {
QPointF pt = b.pointAt(i / threshold_minus_1);
m_dash_stroker.lineTo(pt.x(), pt.y());
}
pts += 6;
types += 3;
break; }
default: break;
}
}
}
m_dash_stroker.end();
}
QT_END_NAMESPACE

View File

@ -0,0 +1,157 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTRIANGULATINGSTROKER_P_H
#define QTRIANGULATINGSTROKER_P_H
#include <private/qdatabuffer_p.h>
#include <qvarlengtharray.h>
#include <private/qvectorpath_p.h>
#include <private/qbezier_p.h>
#include <private/qnumeric_p.h>
#include <private/qmath_p.h>
QT_BEGIN_NAMESPACE
class QTriangulatingStroker
{
public:
QTriangulatingStroker() : m_vertices(0) {}
void process(const QVectorPath &path, const QPen &pen, const QRectF &clip);
inline int vertexCount() const { return m_vertices.size(); }
inline const float *vertices() const { return m_vertices.data(); }
inline void setInvScale(qreal invScale) { m_inv_scale = invScale; }
private:
inline void emitLineSegment(float x, float y, float nx, float ny);
void moveTo(const qreal *pts);
inline void lineTo(const qreal *pts);
void cubicTo(const qreal *pts);
void join(const qreal *pts);
inline void normalVector(float x1, float y1, float x2, float y2, float *nx, float *ny);
void endCap(const qreal *pts);
void arcPoints(float cx, float cy, float fromX, float fromY, float toX, float toY, QVarLengthArray<float> &points);
void endCapOrJoinClosed(const qreal *start, const qreal *cur, bool implicitClose, bool endsAtStart);
QDataBuffer<float> m_vertices;
float m_cx, m_cy; // current points
float m_nvx, m_nvy; // normal vector...
float m_width;
qreal m_miter_limit;
int m_roundness; // Number of line segments in a round join
qreal m_sin_theta; // sin(m_roundness / 360);
qreal m_cos_theta; // cos(m_roundness / 360);
qreal m_inv_scale;
float m_curvyness_mul;
float m_curvyness_add;
Qt::PenJoinStyle m_join_style;
Qt::PenCapStyle m_cap_style;
};
class QDashedStrokeProcessor
{
public:
QDashedStrokeProcessor();
void process(const QVectorPath &path, const QPen &pen, const QRectF &clip);
inline void addElement(QPainterPath::ElementType type, qreal x, qreal y) {
m_points.add(x);
m_points.add(y);
m_types.add(type);
}
inline int elementCount() const { return m_types.size(); }
inline qreal *points() const { return m_points.data(); }
inline QPainterPath::ElementType *elementTypes() const { return m_types.data(); }
inline void setInvScale(qreal invScale) { m_inv_scale = invScale; }
private:
QDataBuffer<qreal> m_points;
QDataBuffer<QPainterPath::ElementType> m_types;
QDashStroker m_dash_stroker;
qreal m_inv_scale;
};
inline void QTriangulatingStroker::normalVector(float x1, float y1, float x2, float y2,
float *nx, float *ny)
{
float dx = x2 - x1;
float dy = y2 - y1;
float pw;
if (dx == 0)
pw = m_width / qAbs(dy);
else if (dy == 0)
pw = m_width / qAbs(dx);
else
pw = m_width / sqrt(dx*dx + dy*dy);
*nx = -dy * pw;
*ny = dx * pw;
}
inline void QTriangulatingStroker::emitLineSegment(float x, float y, float vx, float vy)
{
m_vertices.add(x + vx);
m_vertices.add(y + vy);
m_vertices.add(x - vx);
m_vertices.add(y - vy);
}
void QTriangulatingStroker::lineTo(const qreal *pts)
{
emitLineSegment(pts[0], pts[1], m_nvx, m_nvy);
m_cx = pts[0];
m_cy = pts[1];
}
QT_END_NAMESPACE
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,148 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTRIANGULATOR_P_H
#define QTRIANGULATOR_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qvector.h>
#include <QtGui/private/qvectorpath_p.h>
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QVertexIndexVector
{
public:
enum Type {
UnsignedInt,
UnsignedShort
};
inline Type type() const { return t; }
inline void setDataUint(const QVector<quint32> &data)
{
t = UnsignedInt;
indices32 = data;
}
inline void setDataUshort(const QVector<quint16> &data)
{
t = UnsignedShort;
indices16 = data;
}
inline const void* data() const
{
if (t == UnsignedInt)
return indices32.data();
return indices16.data();
}
inline int size() const
{
if (t == UnsignedInt)
return indices32.size();
return indices16.size();
}
inline QVertexIndexVector &operator = (const QVertexIndexVector &other)
{
if (t == UnsignedInt)
indices32 = other.indices32;
else
indices16 = other.indices16;
return *this;
}
private:
Type t;
QVector<quint32> indices32;
QVector<quint16> indices16;
};
struct Q_GUI_EXPORT QTriangleSet
{
inline QTriangleSet() { }
inline QTriangleSet(const QTriangleSet &other) : vertices(other.vertices), indices(other.indices) { }
QTriangleSet &operator = (const QTriangleSet &other) {vertices = other.vertices; indices = other.indices; return *this;}
// The vertices of a triangle are given by: (x[i[n]], y[i[n]]), (x[j[n]], y[j[n]]), (x[k[n]], y[k[n]]), n = 0, 1, ...
QVector<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
QVertexIndexVector indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...]
};
struct Q_GUI_EXPORT QPolylineSet
{
inline QPolylineSet() { }
inline QPolylineSet(const QPolylineSet &other) : vertices(other.vertices), indices(other.indices) { }
QPolylineSet &operator = (const QPolylineSet &other) {vertices = other.vertices; indices = other.indices; return *this;}
QVector<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
QVertexIndexVector indices; // End of polyline is marked with -1.
};
// The vertex coordinates of the returned triangle set will be rounded to a grid with a mesh size
// of 1/32. The polygon is first transformed, then scaled by 32, the coordinates are rounded to
// integers, the polygon is triangulated, and then scaled back by 1/32.
// 'hint' should be a combination of QVectorPath::Hints.
// 'lod' is the level of detail. Default is 1. Curves are split into more lines when 'lod' is higher.
QTriangleSet qTriangulate(const qreal *polygon, int count, uint hint = QVectorPath::PolygonHint | QVectorPath::OddEvenFill, const QTransform &matrix = QTransform());
QTriangleSet qTriangulate(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
QTriangleSet Q_GUI_EXPORT qTriangulate(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
QPolylineSet qPolyline(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
QPolylineSet Q_GUI_EXPORT qPolyline(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
QT_END_NAMESPACE
#endif

View File

@ -154,7 +154,7 @@ QFont QTextItem::font() const
different painter backends we support. We provide one paint engine for each
window system and painting framework we support. This includes X11 on
Unix/Linux and CoreGraphics on Mac OS X. In addition we provide QPaintEngine
implementations for OpenGL (accessible through QGLWidget) and PostScript
implementations for OpenGL (accessible through QOpenGLWidget) and PostScript
(accessible through QPSPrinter on X11). Additionally there is a raster-based
paint engine that is a fallback for when an engine does not support a certain
capability.

View File

@ -212,7 +212,7 @@ public:
virtual void beginNativePainting() {}
virtual void endNativePainting() {}
// ### Qt5: remove, once QtOpenGL is merged into QtGui and QtWidgets
// ### Qt5: remove, once QtGui is merged into QtGui and QtWidgets
// Return a pixmap filter of "type" that can render the parameters
// in "prototype". The returned filter is owned by the engine and
// will be destroyed when the engine is destroyed. The "prototype"

View File

@ -1351,7 +1351,7 @@ void QPainterPrivate::updateState(QPainterState *newState)
and embedded devices supporting the OpenGL 2.0 or OpenGL/ES 2.0
specification. This includes most graphics chips produced in the
last couple of years. The engine can be enabled by using QPainter
onto a QGLWidget or by passing \c {-graphicssystem opengl} on the
onto a QOpenGLWidget or by passing \c {-graphicssystem opengl} on the
command line when the underlying system supports it.
\o OpenVG - This backend implements the Khronos standard for 2D

View File

@ -316,7 +316,7 @@ private:
friend class QStackTextEngine;
friend class QTextLine;
friend struct QScriptLine;
friend class QGLContext;
friend class QOpenGLContext;
friend class QWin32PaintEngine;
friend class QAlphaPaintEngine;
friend class QPainterPath;

View File

@ -39,8 +39,8 @@
**
****************************************************************************/
#ifndef QGLYPHRUN_H
#define QGLYPHRUN_H
#ifndef QOpenGLYPHRUN_H
#define QOpenGLYPHRUN_H
#include <QtCore/qsharedpointer.h>
#include <QtCore/qvector.h>
@ -113,4 +113,4 @@ QT_END_HEADER
#endif // QT_NO_RAWFONT
#endif // QGLYPHS_H
#endif // QOpenGLYPHS_H

View File

@ -39,8 +39,8 @@
**
****************************************************************************/
#ifndef QGLYPHRUN_P_H
#define QGLYPHRUN_P_H
#ifndef QOpenGLYPHRUN_P_H
#define QOpenGLYPHRUN_P_H
//
// W A R N I N G
@ -119,6 +119,6 @@ QT_END_NAMESPACE
QT_END_HEADER
#endif // QGLYPHS_P_H
#endif // QOpenGLYPHS_P_H
#endif // QT_NO_RAWFONT

View File

@ -139,7 +139,7 @@ QT_BEGIN_NAMESPACE
can be used to indicate that the QStaticText should use additional caches, if possible,
to improve performance at the expense of memory. In particular, setting the performance hint
AggressiveCaching on the QStaticText will improve performance when using the OpenGL graphics
system or when drawing to a QGLWidget.
system or when drawing to a QOpenGLWidget.
\value ModerateCaching Do basic caching for high performance at a low memory cost.
\value AggressiveCaching Use additional caching when available. This may improve performance

View File

@ -11,4 +11,5 @@ QT.gui.libs = $$QT_MODULE_LIB_BASE
QT.gui.plugins = $$QT_MODULE_PLUGIN_BASE
QT.gui.imports = $$QT_MODULE_IMPORT_BASE
QT.gui.depends = core
QT.gui.CONFIG = opengl
QT.gui.DEFINES = QT_GUI_LIB

View File

@ -44,7 +44,7 @@
#include "qpaintengineex_opengl2_p.h"
#include "qglshadercache_p.h"
#include <QtGui/private/qguiglcontext_qpa_p.h>
#include <QtGui/private/qopenglcontext_p.h>
#if defined(QT_DEBUG)
#include <QMetaEnum>
@ -54,12 +54,12 @@
QT_BEGIN_NAMESPACE
class QGLEngineSharedShadersResource : public QGLSharedResource
class QGLEngineSharedShadersResource : public QOpenGLSharedResource
{
public:
QGLEngineSharedShadersResource(QGuiGLContext *ctx)
: QGLSharedResource(ctx->shareGroup())
, m_shaders(new QGLEngineSharedShaders(QGLContext::fromGuiGLContext(ctx)))
QGLEngineSharedShadersResource(QOpenGLContext *ctx)
: QOpenGLSharedResource(ctx->shareGroup())
, m_shaders(new QGLEngineSharedShaders(QGLContext::fromOpenGLContext(ctx)))
{
}
@ -74,7 +74,7 @@ public:
m_shaders = 0;
}
void freeResource(QGuiGLContext *)
void freeResource(QOpenGLContext *)
{
}
@ -88,16 +88,16 @@ class QGLShaderStorage
{
public:
QGLEngineSharedShaders *shadersForThread(const QGLContext *context) {
QGLMultiGroupSharedResource *&shaders = m_storage.localData();
QOpenGLMultiGroupSharedResource *&shaders = m_storage.localData();
if (!shaders)
shaders = new QGLMultiGroupSharedResource;
shaders = new QOpenGLMultiGroupSharedResource;
QGLEngineSharedShadersResource *resource =
shaders->value<QGLEngineSharedShadersResource>(context->contextHandle());
return resource ? resource->shaders() : 0;
}
private:
QThreadStorage<QGLMultiGroupSharedResource *> m_storage;
QThreadStorage<QOpenGLMultiGroupSharedResource *> m_storage;
};
Q_GLOBAL_STATIC(QGLShaderStorage, qt_shader_storage);

View File

@ -55,14 +55,14 @@ public:
}
private:
QGLMultiGroupSharedResource m_resource;
QOpenGLMultiGroupSharedResource m_resource;
QMutex m_mutex;
};
Q_GLOBAL_STATIC(QGL2GradientCacheWrapper, qt_gradient_caches)
QGL2GradientCache::QGL2GradientCache(QGuiGLContext *ctx)
: QGLSharedResource(ctx->shareGroup())
QGL2GradientCache::QGL2GradientCache(QOpenGLContext *ctx)
: QOpenGLSharedResource(ctx->shareGroup())
{
}
@ -82,7 +82,7 @@ void QGL2GradientCache::invalidateResource()
cache.clear();
}
void QGL2GradientCache::freeResource(QGuiGLContext *)
void QGL2GradientCache::freeResource(QOpenGLContext *)
{
cleanCache();
}

View File

@ -58,7 +58,7 @@
QT_BEGIN_NAMESPACE
class QGL2GradientCache : public QGLSharedResource
class QGL2GradientCache : public QOpenGLSharedResource
{
struct CacheInfo
{
@ -76,14 +76,14 @@ class QGL2GradientCache : public QGLSharedResource
public:
static QGL2GradientCache *cacheForContext(const QGLContext *context);
QGL2GradientCache(QGuiGLContext *);
QGL2GradientCache(QOpenGLContext *);
~QGL2GradientCache();
GLuint getBuffer(const QGradient &gradient, qreal opacity);
inline int paletteSize() const { return 1024; }
void invalidateResource();
void freeResource(QGuiGLContext *ctx);
void freeResource(QOpenGLContext *ctx);
private:
inline int maxCacheSize() const { return 60; }

View File

@ -59,7 +59,7 @@ QGLTextureGlyphCache::QGLTextureGlyphCache(QFontEngineGlyphCache::Type type, con
, m_serialNumber(qgltextureglyphcache_serial_number.fetchAndAddRelaxed(1))
{
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, QGuiGLContext::currentContext());
qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, QOpenGLContext::currentContext());
#endif
m_vertexCoordinateArray[0] = -1.0f;
m_vertexCoordinateArray[1] = -1.0f;

View File

@ -63,10 +63,10 @@ QT_BEGIN_NAMESPACE
class QGL2PaintEngineExPrivate;
struct QGLGlyphTexture : public QGLSharedResource
struct QGLGlyphTexture : public QOpenGLSharedResource
{
QGLGlyphTexture(const QGLContext *ctx)
: QGLSharedResource(ctx->contextHandle()->shareGroup())
: QOpenGLSharedResource(ctx->contextHandle()->shareGroup())
, m_width(0)
, m_height(0)
{
@ -78,9 +78,9 @@ struct QGLGlyphTexture : public QGLSharedResource
#endif
}
void freeResource(QGuiGLContext *context)
void freeResource(QOpenGLContext *context)
{
const QGLContext *ctx = QGLContext::fromGuiGLContext(context);
const QGLContext *ctx = QGLContext::fromOpenGLContext(context);
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
qDebug("~QGLGlyphTexture() %p for context %p.", this, ctx);
#endif
@ -136,7 +136,7 @@ public:
inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
inline const QGuiGLContextGroup *contextGroup() const { return m_textureResource ? m_textureResource->group() : 0; }
inline const QOpenGLContextGroup *contextGroup() const { return m_textureResource ? m_textureResource->group() : 0; }
inline int serialNumber() const { return m_serialNumber; }

View File

@ -58,7 +58,7 @@
QT_BEGIN_NAMESPACE
class Q_OPENGL_EXPORT QVertexIndexVector
class QVertexIndexVector
{
public:
enum Type {
@ -111,7 +111,7 @@ private:
QVector<quint16> indices16;
};
struct Q_OPENGL_EXPORT QTriangleSet
struct QTriangleSet
{
inline QTriangleSet() { }
inline QTriangleSet(const QTriangleSet &other) : vertices(other.vertices), indices(other.indices) { }
@ -122,7 +122,7 @@ struct Q_OPENGL_EXPORT QTriangleSet
QVertexIndexVector indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...]
};
struct Q_OPENGL_EXPORT QPolylineSet
struct QPolylineSet
{
inline QPolylineSet() { }
inline QPolylineSet(const QPolylineSet &other) : vertices(other.vertices), indices(other.indices) { }
@ -139,9 +139,9 @@ struct Q_OPENGL_EXPORT QPolylineSet
// 'lod' is the level of detail. Default is 1. Curves are split into more lines when 'lod' is higher.
QTriangleSet qTriangulate(const qreal *polygon, int count, uint hint = QVectorPath::PolygonHint | QVectorPath::OddEvenFill, const QTransform &matrix = QTransform());
QTriangleSet qTriangulate(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
QTriangleSet Q_OPENGL_EXPORT qTriangulate(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
QTriangleSet qTriangulate(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
QPolylineSet qPolyline(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
QPolylineSet Q_OPENGL_EXPORT qPolyline(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
QPolylineSet qPolyline(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
QT_END_NAMESPACE

View File

@ -55,7 +55,7 @@
#include "gl2paintengineex/qpaintengineex_opengl2_p.h"
#include <QtGui/QPlatformGLContext>
#include <QtGui/QPlatformOpenGLContext>
#include <qglpixelbuffer.h>
#include <qglframebufferobject.h>
@ -1501,11 +1501,15 @@ const QGLContext *qt_gl_transfer_context(const QGLContext *ctx)
QGLContextPrivate::QGLContextPrivate(QGLContext *context)
: internal_context(false)
, q_ptr(context)
, texture_destroyer(0)
, functions(0)
{
group = new QGLContextGroup(context);
texture_destroyer = new QGLTextureDestroyer;
texture_destroyer->moveToThread(qApp->thread());
if (qApp) {
texture_destroyer = new QGLTextureDestroyer;
texture_destroyer->moveToThread(qApp->thread());
}
}
QGLContextPrivate::~QGLContextPrivate()
@ -1605,7 +1609,7 @@ static void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, boo
img = img.mirrored();
}
Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)
QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)
{
QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32_Premultiplied
: QImage::Format_RGB32);
@ -3076,8 +3080,8 @@ void QGLContext::setInitialized(bool on)
const QGLContext* QGLContext::currentContext()
{
if (const QGuiGLContext *threadContext = QGuiGLContext::currentContext()) {
return QGLContext::fromGuiGLContext(const_cast<QGuiGLContext *>(threadContext));
if (const QOpenGLContext *threadContext = QOpenGLContext::currentContext()) {
return QGLContext::fromOpenGLContext(const_cast<QOpenGLContext *>(threadContext));
}
return 0;
}
@ -4664,7 +4668,7 @@ void QGLWidget::drawTexture(const QPointF &point, GLuint textureId, GLenum textu
Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_gl_2_engine)
Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine()
QPaintEngine* qt_qgl_paint_engine()
{
return qt_gl_2_engine()->engine();
}
@ -4934,12 +4938,12 @@ void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWi
Q_GLOBAL_STATIC(QString, qt_gl_lib_name)
Q_OPENGL_EXPORT void qt_set_gl_library_name(const QString& name)
void qt_set_gl_library_name(const QString& name)
{
qt_gl_lib_name()->operator=(name);
}
Q_OPENGL_EXPORT const QString qt_gl_library_name()
const QString qt_gl_library_name()
{
if (qt_gl_lib_name()->isNull()) {
# if defined(QT_OPENGL_ES_2)

View File

@ -338,8 +338,8 @@ public:
static const QGLContext* currentContext();
static QGLContext *fromGuiGLContext(QGuiGLContext *platformContext);
QGuiGLContext *contextHandle() const;
static QGLContext *fromOpenGLContext(QOpenGLContext *platformContext);
QOpenGLContext *contextHandle() const;
protected:
virtual bool chooseContext(const QGLContext* shareContext = 0);
@ -359,7 +359,7 @@ protected:
static QGLContext* currentCtx;
private:
QGLContext(QGuiGLContext *windowContext);
QGLContext(QOpenGLContext *windowContext);
QScopedPointer<QGLContextPrivate> d_ptr;

View File

@ -61,11 +61,11 @@
#include "QtCore/qhash.h"
#include "QtCore/qatomic.h"
#include "QtWidgets/private/qwidget_p.h"
#include "QtGui/private/qguiglcontext_qpa_p.h"
#include "QtGui/private/qopenglcontext_p.h"
#include "qcache.h"
#include "qglpaintdevice_p.h"
#include <QtGui/QGuiGLContext>
#include <QtGui/QOpenGLContext>
QT_BEGIN_NAMESPACE
@ -209,7 +209,7 @@ private:
// Get the context that resources for "ctx" will transfer to once
// "ctx" is destroyed. Returns null if nothing is sharing with ctx.
Q_OPENGL_EXPORT const QGLContext *qt_gl_transfer_context(const QGLContext *);
const QGLContext *qt_gl_transfer_context(const QGLContext *);
// GL extension definitions
class QGLExtensions {
@ -298,7 +298,7 @@ public:
void syncGlState(); // Makes sure the GL context's state is what we think it is
void swapRegion(const QRegion &region);
QGuiGLContext *guiGlContext;
QOpenGLContext *guiGlContext;
void setupSharing();
QGLFormat glFormat;
@ -528,18 +528,18 @@ QGLTexture* QGLTextureCache::getTexture(QGLContext *ctx, qint64 key)
return m_cache.object(cacheKey);
}
extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine();
extern QPaintEngine* qt_qgl_paint_engine();
// Put a guard around a GL object identifier and its context.
// When the context goes away, a shared context will be used
// in its place. If there are no more shared contexts, then
// the identifier is returned as zero - it is assumed that the
// context destruction cleaned up the identifier in this case.
class Q_OPENGL_EXPORT QGLSharedResourceGuardBase : public QGLSharedResource
class QGLSharedResourceGuardBase : public QOpenGLSharedResource
{
public:
QGLSharedResourceGuardBase(QGLContext *context, GLuint id)
: QGLSharedResource(context->contextHandle()->shareGroup())
: QOpenGLSharedResource(context->contextHandle()->shareGroup())
, m_id(id)
{
}
@ -555,10 +555,10 @@ protected:
m_id = 0;
}
void freeResource(QGuiGLContext *context)
void freeResource(QOpenGLContext *context)
{
if (m_id) {
freeResource(QGLContext::fromGuiGLContext(context), m_id);
freeResource(QGLContext::fromOpenGLContext(context), m_id);
}
}

View File

@ -45,7 +45,7 @@
#include <QDebug>
#include <private/qapplication_p.h>
#include <QtGui/QPlatformGLContext>
#include <QtGui/QPlatformOpenGLContext>
#include <QtGui/QPlatformWindow>
#include <QtGui/QSurfaceFormat>
@ -110,9 +110,9 @@ QSurfaceFormat QGLFormat::toSurfaceFormat(const QGLFormat &format)
void QGLContextPrivate::setupSharing() {
Q_Q(QGLContext);
QGuiGLContext *sharedContext = guiGlContext->shareContext();
QOpenGLContext *sharedContext = guiGlContext->shareContext();
if (sharedContext) {
QGLContext *actualSharedContext = QGLContext::fromGuiGLContext(sharedContext);
QGLContext *actualSharedContext = QGLContext::fromOpenGLContext(sharedContext);
sharing = true;
QGLContextGroup::addShare(q, actualSharedContext);
}
@ -149,8 +149,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
}
delete d->guiGlContext;
QGuiGLContext *shareGlContext = shareContext ? shareContext->d_func()->guiGlContext : 0;
d->guiGlContext = new QGuiGLContext;
QOpenGLContext *shareGlContext = shareContext ? shareContext->d_func()->guiGlContext : 0;
d->guiGlContext = new QOpenGLContext;
d->guiGlContext->setFormat(winFormat);
d->guiGlContext->setShareContext(shareGlContext);
d->valid = d->guiGlContext->create();
@ -286,7 +286,7 @@ class QGLTemporaryContextPrivate
{
public:
QWindow *window;
QGuiGLContext *context;
QOpenGLContext *context;
QGLContext *oldContext;
};
@ -301,7 +301,7 @@ QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
d->window->setGeometry(QRect(0, 0, 3, 3));
d->window->create();
d->context = new QGuiGLContext;
d->context = new QOpenGLContext;
d->context->create();
d->context->makeCurrent(d->window);
}
@ -378,7 +378,7 @@ void QGLWidget::setColormap(const QGLColormap & c)
Q_UNUSED(c);
}
QGLContext::QGLContext(QGuiGLContext *context)
QGLContext::QGLContext(QOpenGLContext *context)
: d_ptr(new QGLContextPrivate(this))
{
Q_D(QGLContext);
@ -389,7 +389,7 @@ QGLContext::QGLContext(QGuiGLContext *context)
d->setupSharing();
}
QGuiGLContext *QGLContext::contextHandle() const
QOpenGLContext *QGLContext::contextHandle() const
{
Q_D(const QGLContext);
return d->guiGlContext;
@ -398,7 +398,7 @@ QGuiGLContext *QGLContext::contextHandle() const
/*!
Returns a OpenGL context for the window context specified by \a windowContext
*/
QGLContext *QGLContext::fromGuiGLContext(QGuiGLContext *context)
QGLContext *QGLContext::fromOpenGLContext(QOpenGLContext *context)
{
if (!context)
return 0;

View File

@ -334,7 +334,7 @@ bool QGLBuffer::read(int offset, void *data, int count)
{
#if !defined(QT_OPENGL_ES)
Q_D(QGLBuffer);
if (!glGetBufferSubData || !d->guard.id())
if (!glGetBufferSubData || !d->guard->id())
return false;
while (glGetError() != GL_NO_ERROR) ; // Clear error state.
glGetBufferSubData(d->type, offset, count, data);
@ -421,7 +421,7 @@ bool QGLBuffer::bind()
Q_D(const QGLBuffer);
GLuint bufferId = d->guard ? d->guard->id() : 0;
if (bufferId) {
if (d->guard->group() != QGuiGLContextGroup::currentContextGroup()) {
if (d->guard->group() != QOpenGLContextGroup::currentContextGroup()) {
#ifndef QT_NO_DEBUG
qWarning("QGLBuffer::bind: buffer is not valid in the current context");
#endif

View File

@ -855,10 +855,10 @@ struct QGLExtensionFuncs
#endif
extern bool qt_resolve_framebufferobject_extensions(QGLContext *ctx);
bool Q_OPENGL_EXPORT qt_resolve_buffer_extensions(QGLContext *ctx);
bool qt_resolve_buffer_extensions(QGLContext *ctx);
bool qt_resolve_version_1_3_functions(QGLContext *ctx);
bool Q_OPENGL_EXPORT qt_resolve_version_2_0_functions(QGLContext *ctx);
bool qt_resolve_version_2_0_functions(QGLContext *ctx);
bool qt_resolve_stencil_face_extension(QGLContext *ctx);
bool qt_resolve_frag_program_extensions(QGLContext *ctx);

View File

@ -45,7 +45,7 @@
#include <qdebug.h>
#include <private/qgl_p.h>
#include <private/qfont_p.h>
#include <private/qpaintengineex_opengl2_p.h>
#include <gl2paintengineex/qpaintengineex_opengl2_p.h>
#include <qglframebufferobject.h>
#include <qlibrary.h>
@ -53,7 +53,7 @@
QT_BEGIN_NAMESPACE
extern Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
#define QGL_FUNC_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
#define QGL_FUNCP_CONTEXT const QGLContext *ctx = QGLContext::currentContext();

View File

@ -41,7 +41,7 @@
#include "qglfunctions.h"
#include "qgl_p.h"
#include "QtGui/private/qguiglcontext_qpa_p.h"
#include "QtGui/private/qopenglcontext_p.h"
QT_BEGIN_NAMESPACE
@ -140,11 +140,11 @@ QT_BEGIN_NAMESPACE
*/
// Hidden private fields for additional extension data.
struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QGLSharedResource
struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QOpenGLSharedResource
{
QGLFunctionsPrivateEx(QGuiGLContext *context)
: QGLFunctionsPrivate(QGLContext::fromGuiGLContext(context))
, QGLSharedResource(context->shareGroup())
QGLFunctionsPrivateEx(QOpenGLContext *context)
: QGLFunctionsPrivate(QGLContext::fromOpenGLContext(context))
, QOpenGLSharedResource(context->shareGroup())
, m_features(-1) {}
void invalidateResource()
@ -152,7 +152,7 @@ struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QGLSharedResou
m_features = -1;
}
void freeResource(QGuiGLContext *)
void freeResource(QOpenGLContext *)
{
// no gl resources to free
}
@ -160,7 +160,7 @@ struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QGLSharedResou
int m_features;
};
Q_GLOBAL_STATIC(QGLMultiGroupSharedResource, qt_gl_functions_resource)
Q_GLOBAL_STATIC(QOpenGLMultiGroupSharedResource, qt_gl_functions_resource)
static QGLFunctionsPrivateEx *qt_gl_functions(const QGLContext *context = 0)
{

View File

@ -91,7 +91,7 @@
#include <QtCore/qglobal.h>
#include <private/qpaintengineex_opengl2_p.h>
#include <gl2paintengineex/qpaintengineex_opengl2_p.h>
#include <qglpixelbuffer.h>
#include <private/qglpixelbuffer_p.h>
@ -100,7 +100,7 @@
QT_BEGIN_NAMESPACE
extern Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
QGLContext* QGLPBufferGLPaintDevice::context() const

View File

@ -958,7 +958,7 @@ bool QGLShaderProgram::bind()
if (!d->linked && !link())
return false;
#ifndef QT_NO_DEBUG
if (d->programGuard->group() != QGuiGLContextGroup::currentContextGroup()) {
if (d->programGuard->group() != QOpenGLContextGroup::currentContextGroup()) {
qWarning("QGLShaderProgram::bind: program is not valid in the current context.");
return false;
}
@ -980,7 +980,7 @@ void QGLShaderProgram::release()
{
#ifndef QT_NO_DEBUG
Q_D(QGLShaderProgram);
if (d->programGuard->group() != QGuiGLContextGroup::currentContextGroup())
if (d->programGuard->group() != QOpenGLContextGroup::currentContextGroup())
qWarning("QGLShaderProgram::release: program is not valid in the current context.");
#endif
#if defined(QT_OPENGL_ES_2)
@ -991,9 +991,6 @@ void QGLShaderProgram::release()
#endif
}
#undef ctx
#define ctx d->programGuard.context()
/*!
Returns the OpenGL identifier associated with this shader program.

View File

@ -1,18 +0,0 @@
Use of GLSL for vertex and fragment programs in Qt
---------------------------------------------------
We don't compile the *.glsl files because we don't want the build process of
Qt to require cgc from nVidia to build the fragment programs.
The script src/opengl/util/glsl_to_include.sh will compile a GLSL program to a file
that can be included in a C(++) program. The file is the output from cgc
quoted as a string.
This can be done manually by:
./glsl_to_include.sh radial.glsl
./glsl_to_include.sh conical.glsl
This will produce the files radial.frag and radial.glsl_quoted.
(and also conical.frag and conical.glsl_quoted)
These files are included by qpaintengine_opengl.cpp

View File

@ -1,7 +0,0 @@
// fast brush painter for composition modes which can be implemented with blendfuncs
// no mask, used for fast filling of aliased primitives (or multisampled)
void main()
{
gl_FragColor = brush();
}

View File

@ -1,6 +0,0 @@
FRAGMENT_PROGRAM_BRUSH_SOLID solid_brush.glsl
FRAGMENT_PROGRAM_BRUSH_RADIAL radial_brush.glsl
FRAGMENT_PROGRAM_BRUSH_CONICAL conical_brush.glsl
FRAGMENT_PROGRAM_BRUSH_LINEAR linear_brush.glsl
FRAGMENT_PROGRAM_BRUSH_TEXTURE texture_brush.glsl
FRAGMENT_PROGRAM_BRUSH_PATTERN pattern_brush.glsl

View File

@ -1,13 +0,0 @@
// Dca' = Sca.Da + Dca.Sa <= Sa.Da ?
// Sca.(1 - Da) + Dca.(1 - Sa)
// Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
// Da' = Sa + Da - Sa.Da
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
result.rgb = mix(src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a),
src.a * (src.rgb * dst.a + dst.rgb * src.a - src.a * dst.a) / max(src.rgb, 0.00001) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a),
step(src.a * dst.a, src.rgb * dst.a + dst.rgb * src.a));
result.a = src.a + dst.a - src.a * dst.a;
return result;
}

View File

@ -1,15 +0,0 @@
// Dca' = Sca.Da + Dca.Sa <= Sa.Da ?
// Dca.Sa/(1 - Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa) :
// Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
// Da' = Sa + Da - Sa.Da
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
vec3 temp = src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
result.rgb = mix(dst.rgb * src.a / max(1.0 - src.rgb / max(src.a, 0.000001), 0.000001) + temp,
src.a * dst.a + temp,
step(src.a * dst.a, src.rgb * dst.a + dst.rgb * src.a));
result.a = src.a + dst.a - src.a * dst.a;
return result;
}

Some files were not shown because too many files have changed in this diff Show More