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:
parent
aaa4a26f82
commit
6e28e8441b
@ -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();
|
||||
|
@ -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
|
||||
|
@ -6,8 +6,6 @@ TEMPLATE = app
|
||||
DEPENDPATH += .
|
||||
INCLUDEPATH += .
|
||||
|
||||
QT += opengl widgets
|
||||
|
||||
# Input
|
||||
HEADERS += hellowindow.h
|
||||
SOURCES += hellowindow.cpp main.cpp
|
||||
|
@ -24,6 +24,7 @@ contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2){
|
||||
|
||||
qpa {
|
||||
SUBDIRS += hellowindow
|
||||
SUBDIRS += paintedwindow
|
||||
}
|
||||
|
||||
# install
|
||||
|
27
examples/opengl/paintedwindow/main.cpp
Normal file
27
examples/opengl/paintedwindow/main.cpp
Normal 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();
|
||||
}
|
124
examples/opengl/paintedwindow/paintedwindow.cpp
Normal file
124
examples/opengl/paintedwindow/paintedwindow.cpp
Normal 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);
|
||||
}
|
30
examples/opengl/paintedwindow/paintedwindow.h
Normal file
30
examples/opengl/paintedwindow/paintedwindow.h
Normal 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;
|
||||
};
|
18
examples/opengl/paintedwindow/paintedwindow.pro
Normal file
18
examples/opengl/paintedwindow/paintedwindow.pro
Normal 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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
@ -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
|
@ -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 (!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);
|
||||
}
|
||||
|
@ -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;
|
230
src/gui/kernel/qopenglcontext_p.h
Normal file
230
src/gui/kernel/qopenglcontext_p.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
|
||||
QT_MODULE(Gui)
|
||||
|
||||
class QPlatformBackingStore;
|
||||
class QPlatformGLContext;
|
||||
class QPlatformOpenGLContext;
|
||||
class QPlatformScreenPrivate;
|
||||
class QPlatformWindow;
|
||||
class QScreen;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
44
src/gui/opengl/opengl.pri
Normal 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
109
src/gui/opengl/qopengl.cpp
Normal 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
73
src/gui/opengl/qopengl.h
Normal 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
|
175
src/gui/opengl/qopengl2pexvertexarray.cpp
Normal file
175
src/gui/opengl/qopengl2pexvertexarray.cpp
Normal 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
|
169
src/gui/opengl/qopengl2pexvertexarray_p.h
Normal file
169
src/gui/opengl/qopengl2pexvertexarray_p.h
Normal 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
200
src/gui/opengl/qopengl_p.h
Normal 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
|
582
src/gui/opengl/qopenglbuffer.cpp
Normal file
582
src/gui/opengl/qopenglbuffer.cpp
Normal 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
|
132
src/gui/opengl/qopenglbuffer.h
Normal file
132
src/gui/opengl/qopenglbuffer.h
Normal 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
|
297
src/gui/opengl/qopenglcolormap.cpp
Normal file
297
src/gui/opengl/qopenglcolormap.cpp
Normal 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
|
105
src/gui/opengl/qopenglcolormap.h
Normal file
105
src/gui/opengl/qopenglcolormap.h
Normal 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
|
138
src/gui/opengl/qopenglcustomshaderstage.cpp
Normal file
138
src/gui/opengl/qopenglcustomshaderstage.cpp
Normal 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
|
93
src/gui/opengl/qopenglcustomshaderstage_p.h
Normal file
93
src/gui/opengl/qopenglcustomshaderstage_p.h
Normal 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
|
881
src/gui/opengl/qopenglengineshadermanager.cpp
Normal file
881
src/gui/opengl/qopenglengineshadermanager.cpp
Normal 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
|
514
src/gui/opengl/qopenglengineshadermanager_p.h
Normal file
514
src/gui/opengl/qopenglengineshadermanager_p.h
Normal 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
|
529
src/gui/opengl/qopenglengineshadersource_p.h
Normal file
529
src/gui/opengl/qopenglengineshadersource_p.h
Normal 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
|
676
src/gui/opengl/qopenglextensions_p.h
Normal file
676
src/gui/opengl/qopenglextensions_p.h
Normal 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
|
1354
src/gui/opengl/qopenglframebufferobject.cpp
Normal file
1354
src/gui/opengl/qopenglframebufferobject.cpp
Normal file
File diff suppressed because it is too large
Load Diff
158
src/gui/opengl/qopenglframebufferobject.h
Normal file
158
src/gui/opengl/qopenglframebufferobject.h
Normal 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
|
164
src/gui/opengl/qopenglframebufferobject_p.h
Normal file
164
src/gui/opengl/qopenglframebufferobject_p.h
Normal 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
|
2452
src/gui/opengl/qopenglfunctions.cpp
Normal file
2452
src/gui/opengl/qopenglfunctions.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2427
src/gui/opengl/qopenglfunctions.h
Normal file
2427
src/gui/opengl/qopenglfunctions.h
Normal file
File diff suppressed because it is too large
Load Diff
227
src/gui/opengl/qopenglgradientcache.cpp
Normal file
227
src/gui/opengl/qopenglgradientcache.cpp
Normal 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
|
101
src/gui/opengl/qopenglgradientcache_p.h
Normal file
101
src/gui/opengl/qopenglgradientcache_p.h
Normal 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
|
||||
|
153
src/gui/opengl/qopenglpaintdevice.cpp
Normal file
153
src/gui/opengl/qopenglpaintdevice.cpp
Normal 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
|
119
src/gui/opengl/qopenglpaintdevice_p.h
Normal file
119
src/gui/opengl/qopenglpaintdevice_p.h
Normal 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
|
457
src/gui/opengl/qopenglshadercache_meego_p.h
Normal file
457
src/gui/opengl/qopenglshadercache_meego_p.h
Normal 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
|
@ -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
|
3171
src/gui/opengl/qopenglshaderprogram.cpp
Normal file
3171
src/gui/opengl/qopenglshaderprogram.cpp
Normal file
File diff suppressed because it is too large
Load Diff
317
src/gui/opengl/qopenglshaderprogram.h
Normal file
317
src/gui/opengl/qopenglshaderprogram.h
Normal 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
|
2454
src/gui/opengl/qpaintengineex_opengl2.cpp
Normal file
2454
src/gui/opengl/qpaintengineex_opengl2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
338
src/gui/opengl/qpaintengineex_opengl2_p.h
Normal file
338
src/gui/opengl/qpaintengineex_opengl2_p.h
Normal 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
573
src/gui/opengl/qrbtree_p.h
Normal 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
|
396
src/gui/opengl/qtextureglyphcache_gl.cpp
Normal file
396
src/gui/opengl/qtextureglyphcache_gl.cpp
Normal 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
|
169
src/gui/opengl/qtextureglyphcache_gl_p.h
Normal file
169
src/gui/opengl/qtextureglyphcache_gl_p.h
Normal 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
|
||||
|
588
src/gui/opengl/qtriangulatingstroker.cpp
Normal file
588
src/gui/opengl/qtriangulatingstroker.cpp
Normal 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
|
||||
|
157
src/gui/opengl/qtriangulatingstroker_p.h
Normal file
157
src/gui/opengl/qtriangulatingstroker_p.h
Normal 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
|
2622
src/gui/opengl/qtriangulator.cpp
Normal file
2622
src/gui/opengl/qtriangulator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
148
src/gui/opengl/qtriangulator_p.h
Normal file
148
src/gui/opengl/qtriangulator_p.h
Normal 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
|
@ -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.
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 ®ion);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
@ -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();
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
Loading…
Reference in New Issue
Block a user