summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp81
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h3
-rw-r--r--src/opengl/opengl.pro7
-rw-r--r--src/opengl/qgl.cpp315
-rw-r--r--src/opengl/qgl.h8
-rw-r--r--src/opengl/qgl_p.h67
-rw-r--r--src/opengl/qgl_x11.cpp1
-rw-r--r--src/opengl/qglframebufferobject.cpp136
-rw-r--r--src/opengl/qglframebufferobject.h6
-rw-r--r--src/opengl/qglframebufferobject_p.h152
-rw-r--r--src/opengl/qglpaintdevice.cpp187
-rw-r--r--src/opengl/qglpaintdevice_p.h112
-rw-r--r--src/opengl/qglpixelbuffer.cpp17
-rw-r--r--src/opengl/qglpixelbuffer.h2
-rw-r--r--src/opengl/qglpixelbuffer_p.h15
-rw-r--r--src/opengl/qpaintengine_opengl.cpp121
-rw-r--r--src/opengl/qpixmapdata_gl.cpp123
-rw-r--r--src/opengl/qpixmapdata_gl_p.h52
-rw-r--r--src/opengl/qwindowsurface_gl.cpp65
-rw-r--r--src/opengl/qwindowsurface_gl_p.h19
20 files changed, 905 insertions, 584 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index e24539b..e028e63 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -710,7 +710,7 @@ void QGL2PaintEngineEx::beginNativePainting()
{ mtx.dx(), mtx.dy(), 0, mtx.m33() }
};
- const QSize sz = d->drawable.size();
+ const QSize sz = d->device->size();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@@ -1308,21 +1308,20 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
Q_D(QGL2PaintEngineEx);
// qDebug("QGL2PaintEngineEx::begin()");
- d->drawable.setDevice(pdev);
- d->ctx = d->drawable.context();
-
- if (d->ctx->d_ptr->active_engine) {
- QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(d->ctx->d_ptr->active_engine);
- QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr.data());
- p->transferMode(BrushDrawingMode);
- p->drawable.doneCurrent();
- }
+ if (pdev->devType() == QInternal::OpenGL)
+ d->device = static_cast<QGLPaintDevice*>(pdev);
+ else
+ d->device = QGLPaintDevice::getDevice(pdev);
+
+ if (!d->device)
+ return false;
+
+ d->ctx = d->device->context();
d->ctx->d_ptr->active_engine = this;
d->last_created_state = 0;
- d->drawable.makeCurrent();
- QSize sz = d->drawable.size();
+ QSize sz = d->device->size();
d->width = sz.width();
d->height = sz.height();
d->mode = BrushDrawingMode;
@@ -1333,8 +1332,6 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
d->shaderManager = new QGLEngineShaderManager(d->ctx);
- glViewport(0, 0, d->width, d->height);
-
d->brushTextureDirty = true;
d->brushUniformsDirty = true;
d->matrixDirty = true;
@@ -1343,10 +1340,12 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
d->simpleShaderDepthUniformDirty = true;
d->depthUniformDirty = true;
d->opacityUniformDirty = true;
- d->needsSync = false;
-
+ d->needsSync = true;
d->use_system_clip = !systemClip().isEmpty();
+
+ d->device->beginPaint();
+
if (!d->inRenderText) {
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
@@ -1358,30 +1357,6 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
glDisable(GL_MULTISAMPLE);
#endif
- QGLPixmapData *source = d->drawable.copyOnBegin();
- if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) {
- if (d->drawable.hasTransparentBackground())
- glClearColor(0.0, 0.0, 0.0, 0.0);
- else {
- const QColor &c = d->drawable.backgroundColor();
- float alpha = c.alphaF();
- glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
- }
- glClear(GL_COLOR_BUFFER_BIT);
- } else if (source) {
- QGLContext *ctx = d->ctx;
-
- d->transferMode(ImageDrawingMode);
-
- glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
- source->bind(false);
-
- QRect rect(0, 0, source->width(), source->height());
- d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
- d->drawTexture(QRectF(rect), QRectF(rect), rect.size(), true);
- }
-
- d->systemStateChanged();
return true;
}
@@ -1389,19 +1364,11 @@ bool QGL2PaintEngineEx::end()
{
Q_D(QGL2PaintEngineEx);
QGLContext *ctx = d->ctx;
- if (ctx->d_ptr->active_engine != this) {
- QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine);
- if (engine && engine->isActive()) {
- QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr.data());
- p->transferMode(BrushDrawingMode);
- p->drawable.doneCurrent();
- }
- d->drawable.makeCurrent();
- }
glUseProgram(0);
d->transferMode(BrushDrawingMode);
- d->drawable.swapBuffers();
+ d->device->endPaint();
+
#if defined(Q_WS_X11)
// On some (probably all) drivers, deleting an X pixmap which has been bound to a texture
// before calling glFinish/swapBuffers renders garbage. Presumably this is because X deletes
@@ -1410,7 +1377,6 @@ bool QGL2PaintEngineEx::end()
// them here, after swapBuffers, where they can be safely deleted.
ctx->d_func()->boundPixmaps.clear();
#endif
- d->drawable.doneCurrent();
d->ctx->d_ptr->active_engine = 0;
d->resetGLState();
@@ -1427,21 +1393,12 @@ void QGL2PaintEngineEx::ensureActive()
QGLContext *ctx = d->ctx;
if (isActive() && ctx->d_ptr->active_engine != this) {
- QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine);
- if (engine && engine->isActive()) {
- QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr.data());
- p->transferMode(BrushDrawingMode);
- p->drawable.doneCurrent();
- }
- d->drawable.context()->makeCurrent();
- d->drawable.makeCurrent();
-
ctx->d_ptr->active_engine = this;
d->needsSync = true;
- } else {
- d->drawable.context()->makeCurrent();
}
+ d->device->ensureActiveTarget();
+
if (d->needsSync) {
glViewport(0, 0, d->width, d->height);
glDepthMask(false);
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index cb23b11..2fbee1b 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -58,6 +58,7 @@
#include <private/qpaintengineex_p.h>
#include <private/qglengineshadermanager_p.h>
#include <private/qgl2pexvertexarray_p.h>
+#include <private/qglpaintdevice_p.h>
enum EngineMode {
ImageDrawingMode,
@@ -199,7 +200,7 @@ public:
static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; }
QGL2PaintEngineEx* q;
- QGLDrawable drawable;
+ QGLPaintDevice* device;
int width, height;
QGLContext *ctx;
EngineMode mode;
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index 560d31f..d479c2e 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -22,13 +22,18 @@ HEADERS += qgl.h \
qglpixelbuffer.h \
qglpixelbuffer_p.h \
qglframebufferobject.h \
- qglextensions_p.h
+ qglframebufferobject_p.h \
+ qglextensions_p.h \
+ qglpaintdevice_p.h \
+
SOURCES += qgl.cpp \
qglcolormap.cpp \
qglpixelbuffer.cpp \
qglframebufferobject.cpp \
qglextensions.cpp \
+ qglpaintdevice.cpp \
+
!contains(QT_CONFIG, opengles2) {
HEADERS += qpaintengine_opengl_p.h
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 087902b..a0b2d3a 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -141,6 +141,48 @@ QGLSignalProxy *QGLSignalProxy::instance()
return theSignalProxy();
}
+
+class QGLEngineSelector
+{
+public:
+ QGLEngineSelector() : engineType(QPaintEngine::MaxUser) { }
+
+ void setPreferredPaintEngine(QPaintEngine::Type type) {
+ if (type == QPaintEngine::OpenGL || type == QPaintEngine::OpenGL2)
+ engineType = type;
+ }
+
+ QPaintEngine::Type preferredPaintEngine() {
+ if (engineType == QPaintEngine::MaxUser) {
+ // No user-set engine - use the defaults
+#if defined(QT_OPENGL_ES_2)
+ engineType = QPaintEngine::OpenGL2;
+#else
+ // We can't do this in the constructor for this object because it
+ // needs to be called *before* the QApplication constructor
+ if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)
+ && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty())
+ engineType = QPaintEngine::OpenGL2;
+ else
+ engineType = QPaintEngine::OpenGL;
+#endif
+ }
+ return engineType;
+ }
+
+private:
+ QPaintEngine::Type engineType;
+};
+
+Q_GLOBAL_STATIC(QGLEngineSelector, qgl_engine_selector)
+
+
+bool qt_gl_preferGL2Engine()
+{
+ return qgl_engine_selector()->preferredPaintEngine() == QPaintEngine::OpenGL2;
+}
+
+
/*!
\namespace QGL
\inmodule QtOpenGL
@@ -181,6 +223,32 @@ QGLSignalProxy *QGLSignalProxy::instance()
\sa {Sample Buffers Example}
*/
+/*!
+ \fn void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType)
+
+ \since 4.6
+
+ Sets the preferred OpenGL paint engine that is used to draw onto
+ QGLWidgets, QGLPixelBuffers and QGLFrameBufferObjects with QPainter
+ in Qt.
+
+ The \a engineType parameter specifies which of the GL engines to
+ use. Only \c QPaintEngine::OpenGL and \c QPaintEngine::OpenGL2 are
+ valid parameters to this function. All other values are ignored.
+
+ By default, the \c QPaintEngine::OpenGL2 engine is used if GL/GLES
+ version 2.0 is available, otherwise \c QPaintEngine::OpenGL is
+ used.
+
+ \warning This function must be called before the QApplication
+ constructor is called.
+*/
+void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType)
+{
+ qgl_engine_selector()->setPreferredPaintEngine(engineType);
+}
+
+
/*****************************************************************************
QGLFormat implementation
*****************************************************************************/
@@ -1331,7 +1399,6 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
crWin = false;
initDone = false;
sharing = false;
- clear_on_painter_begin = true;
max_texture_size = -1;
version_flags_cached = false;
version_flags = QGLFormat::OpenGL_Version_None;
@@ -4186,7 +4253,7 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
} else {
setAutoBufferSwap(false);
// disable glClear() as a result of QPainter::begin()
- d->glcx->d_func()->clear_on_painter_begin = false;
+ d->disable_clear_on_painter_begin = true;
if (engine->type() == QPaintEngine::OpenGL2) {
qt_save_gl_state();
#ifndef QT_OPENGL_ES_2
@@ -4216,7 +4283,7 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
p->end();
delete p;
setAutoBufferSwap(auto_swap);
- d->glcx->d_func()->clear_on_painter_begin = true;
+ d->disable_clear_on_painter_begin = false;
if (engine->type() == QPaintEngine::OpenGL2)
qt_restore_gl_state();
}
@@ -4359,7 +4426,7 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
} else {
setAutoBufferSwap(false);
// disable glClear() as a result of QPainter::begin()
- d->glcx->d_func()->clear_on_painter_begin = false;
+ d->disable_clear_on_painter_begin = true;
if (engine->type() == QPaintEngine::OpenGL2)
qt_save_gl_state();
p = new QPainter(this);
@@ -4399,7 +4466,7 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
if (engine->type() == QPaintEngine::OpenGL2)
qt_restore_gl_state();
setAutoBufferSwap(auto_swap);
- d->glcx->d_func()->clear_on_painter_begin = true;
+ d->disable_clear_on_painter_begin = false;
}
#ifndef QT_OPENGL_ES
if (engine->type() == QPaintEngine::OpenGL2)
@@ -4747,6 +4814,8 @@ void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWi
{
Q_Q(QGLWidget);
+ glDevice.setWidget(q);
+
QGLExtensions::init();
glcx = 0;
autoSwap = true;
@@ -4782,242 +4851,6 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name()
}
#endif
-void QGLDrawable::setDevice(QPaintDevice *pdev)
-{
- wasBound = false;
- widget = 0;
- buffer = 0;
- fbo = 0;
-#ifdef Q_WS_QWS
- wsurf = 0;
-#endif
-
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- if (pdev->devType() == QInternal::Pixmap) {
- QPixmapData *data = static_cast<QPixmap *>(pdev)->pixmapData();
- Q_ASSERT(data->classId() == QPixmapData::OpenGLClass);
- pixmapData = static_cast<QGLPixmapData *>(data);
-
- fbo = pixmapData->fbo();
- }
-#else
- Q_ASSERT(pdev->devType() != QInternal::Pixmap);
-#endif
-
- if (pdev->devType() == QInternal::Widget)
- widget = static_cast<QGLWidget *>(pdev);
- else if (pdev->devType() == QInternal::Pbuffer)
- buffer = static_cast<QGLPixelBuffer *>(pdev);
- else if (pdev->devType() == QInternal::FramebufferObject)
- fbo = static_cast<QGLFramebufferObject *>(pdev);
-#ifdef Q_WS_QWS
- else if (pdev->devType() == QInternal::UnknownDevice)
- wsurf = static_cast<QWSGLPaintDevice*>(pdev)->windowSurface();
-#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- else if (pdev->devType() == QInternal::UnknownDevice)
- wsurf = static_cast<QGLWindowSurface *>(pdev);
-#endif
-}
-
-void QGLDrawable::swapBuffers()
-{
- if (widget) {
- if (widget->autoBufferSwap())
- widget->swapBuffers();
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- } else if (pixmapData) {
- pixmapData->swapBuffers();
-#endif
- } else {
- glFlush();
- }
-}
-
-void QGLDrawable::makeCurrent()
-{
- previous_fbo = 0;
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- if (!pixmapData && !fbo) {
-#else
- if (!fbo) {
-#endif
- QGLContext *ctx = context();
- previous_fbo = ctx->d_ptr->current_fbo;
- ctx->d_ptr->current_fbo = 0;
- if (previous_fbo)
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
- }
-
- if (widget)
- widget->makeCurrent();
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- else if (pixmapData)
- pixmapData->makeCurrent();
-#endif
- else if (buffer)
- buffer->makeCurrent();
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- else if (wsurf)
- wsurf->context()->makeCurrent();
-#endif
- else if (fbo) {
- wasBound = fbo->isBound();
- if (!wasBound)
- fbo->bind();
- }
-}
-
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
-QGLPixmapData *QGLDrawable::copyOnBegin() const
-{
- if (!pixmapData || pixmapData->isUninitialized())
- return 0;
- return pixmapData;
-}
-#endif
-
-void QGLDrawable::doneCurrent()
-{
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- if (pixmapData) {
- pixmapData->doneCurrent();
- return;
- }
-#endif
-
- if (previous_fbo) {
- QGLContext *ctx = context();
- ctx->d_ptr->current_fbo = previous_fbo;
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, previous_fbo);
- }
-
- if (fbo && !wasBound)
- fbo->release();
-}
-
-QSize QGLDrawable::size() const
-{
- if (widget) {
- return QSize(widget->d_func()->glcx->device()->width(),
- widget->d_func()->glcx->device()->height());
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- } else if (pixmapData) {
- return pixmapData->size();
-#endif
- } else if (buffer) {
- return buffer->size();
- } else if (fbo) {
- return fbo->size();
- }
-#ifdef Q_WS_QWS
- else if (wsurf)
- return wsurf->window()->frameSize();
-#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- else if (wsurf)
- return QSize(wsurf->width(), wsurf->height());
-#endif
- return QSize();
-}
-
-QGLFormat QGLDrawable::format() const
-{
- if (widget)
- return widget->format();
- else if (buffer)
- return buffer->format();
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- else if (wsurf)
- return wsurf->context()->format();
-#endif
- else if (fbo && QGLContext::currentContext()) {
- QGLFormat fmt = QGLContext::currentContext()->format();
- fmt.setStencil(fbo->attachment() == QGLFramebufferObject::CombinedDepthStencil);
- fmt.setDepth(fbo->attachment() != QGLFramebufferObject::NoAttachment);
- return fmt;
- }
-
- return QGLFormat();
-}
-
-GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format,
- QGLContext::BindOptions options)
-{
- QGLTexture *texture = 0;
- options |= QGLContext::MemoryManagedBindOption;
- if (widget)
- texture = widget->d_func()->glcx->d_func()->bindTexture(image, target, format, options);
- else if (buffer)
- texture = buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, options);
- else if (fbo && QGLContext::currentContext())
- texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, options);
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- else if (wsurf)
- texture = wsurf->context()->d_func()->bindTexture(image, target, format, options);
-#endif
- return texture->id;
-}
-
-GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
- QGLContext::BindOptions options)
-{
- QGLTexture *texture = 0;
- if (widget)
- texture = widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, options);
- else if (buffer)
- texture = buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, options);
- else if (fbo && QGLContext::currentContext())
- texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, options);
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- else if (wsurf)
- texture = wsurf->context()->d_func()->bindTexture(pixmap, target, format, options);
-#endif
- return texture->id;
-}
-
-QColor QGLDrawable::backgroundColor() const
-{
- if (widget)
- return widget->palette().brush(widget->backgroundRole()).color();
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- else if (pixmapData)
- return pixmapData->fillColor();
-#endif
- return QApplication::palette().brush(QPalette::Background).color();
-}
-
-bool QGLDrawable::hasTransparentBackground() const
-{
- return widget && widget->testAttribute(Qt::WA_TranslucentBackground);
-}
-
-QGLContext *QGLDrawable::context() const
-{
- if (widget)
- return widget->d_func()->glcx;
- else if (buffer)
- return buffer->d_func()->qctx;
- else if (fbo)
- return const_cast<QGLContext *>(QGLContext::currentContext());
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- else if (wsurf)
- return wsurf->context();
-#endif
- return 0;
-}
-
-bool QGLDrawable::autoFillBackground() const
-{
- if (widget)
- return widget->autoFillBackground();
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- else if (pixmapData)
- return pixmapData->needsFill();
-#endif
- else
- return false;
-}
-
-
bool QGLShareRegister::checkSharing(const QGLContext *context1, const QGLContext *context2) {
bool sharing = (context1 && context2 && context1->d_ptr->group == context2->d_ptr->group);
return sharing;
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index daac760..151c7c4 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -43,6 +43,7 @@
#define QGL_H
#include <QtGui/qwidget.h>
+#include <QtGui/qpaintengine.h>
#include <QtOpenGL/qglcolormap.h>
#include <QtCore/qmap.h>
#include <QtCore/qscopedpointer.h>
@@ -130,6 +131,8 @@ class QGLContextPrivate;
// Namespace class:
namespace QGL
{
+ Q_OPENGL_EXPORT void setPreferredPaintEngine(QPaintEngine::Type engineType);
+
enum FormatOption {
DoubleBuffer = 0x0001,
DepthBuffer = 0x0002,
@@ -382,7 +385,6 @@ private:
friend class QGLPixelBuffer;
friend class QGLPixelBufferPrivate;
friend class QGLWidget;
- friend class QGLDrawable;
friend class QGLWidgetPrivate;
friend class QGLGlyphCache;
friend class QOpenGLPaintEngine;
@@ -404,6 +406,8 @@ private:
#endif
friend class QGLFramebufferObject;
friend class QGLFramebufferObjectPrivate;
+ friend class QGLFBOGLPaintDevice;
+ friend class QGLPaintDevice;
private:
Q_DISABLE_COPY(QGLContext)
};
@@ -539,6 +543,8 @@ private:
friend class QGLContext;
friend class QGLOverlayWidget;
friend class QOpenGLPaintEngine;
+ friend class QGLPaintDevice;
+ friend class QGLWidgetGLPaintDevice;
};
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index d4b7597..b10d5da 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -62,6 +62,7 @@
#include "QtCore/qatomic.h"
#include "private/qwidget_p.h"
#include "qcache.h"
+#include "qglpaintdevice_p.h"
#ifndef QT_OPENGL_ES_1_CL
#define q_vertexType float
@@ -174,6 +175,7 @@ class QGLWidgetPrivate : public QWidgetPrivate
Q_DECLARE_PUBLIC(QGLWidget)
public:
QGLWidgetPrivate() : QWidgetPrivate()
+ , disable_clear_on_painter_begin(false)
#ifdef Q_WS_QWS
, wsurf(0)
#endif
@@ -190,11 +192,14 @@ public:
void cleanupColormaps();
QGLContext *glcx;
+ QGLWidgetGLPaintDevice glDevice;
bool autoSwap;
QGLColormap cmap;
QMap<QString, int> displayListCache;
+ bool disable_clear_on_painter_begin;
+
#if defined(Q_WS_WIN)
void updateColormap();
QGLContext *olcx;
@@ -293,7 +298,6 @@ public:
uint sharing : 1;
uint initDone : 1;
uint crWin : 1;
- uint clear_on_painter_begin : 1;
uint internal_context : 1;
uint version_flags_cached : 1;
QPaintDevice *paintDevice;
@@ -337,57 +341,6 @@ Q_SIGNALS:
void aboutToDestroyContext(const QGLContext *context);
};
-class QGLPixelBuffer;
-class QGLFramebufferObject;
-class QWSGLWindowSurface;
-class QGLWindowSurface;
-class QGLPixmapData;
-class QGLDrawable {
-public:
- QGLDrawable() : widget(0), buffer(0), fbo(0)
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- , wsurf(0)
-#endif
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- , pixmapData(0)
-#endif
- {}
- void setDevice(QPaintDevice *pdev);
- void swapBuffers();
- void makeCurrent();
- void doneCurrent();
- QSize size() const;
- QGLFormat format() const;
- GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA,
- QGLContext::BindOptions = QGLContext::InternalBindOption);
- GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA,
- QGLContext::BindOptions = QGLContext::InternalBindOption);
- QColor backgroundColor() const;
- QGLContext *context() const;
- bool autoFillBackground() const;
- bool hasTransparentBackground() const;
-
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- QGLPixmapData *copyOnBegin() const;
-#endif
-
-private:
- bool wasBound;
- QGLWidget *widget;
- QGLPixelBuffer *buffer;
- QGLFramebufferObject *fbo;
-#ifdef Q_WS_QWS
- QWSGLWindowSurface *wsurf;
-#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- QGLWindowSurface *wsurf;
-#endif
-
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- QGLPixmapData *pixmapData;
-#endif
- int previous_fbo;
-};
-
// GL extension definitions
class QGLExtensions {
public:
@@ -519,15 +472,7 @@ extern QPaintEngine* qt_qgl_paint_engine();
extern EGLDisplay qt_qgl_egl_display();
#endif
-inline bool qt_gl_preferGL2Engine()
-{
-#if defined(QT_OPENGL_ES_2)
- return true;
-#else
- return (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)
- && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty();
-#endif
-}
+bool qt_gl_preferGL2Engine();
inline GLenum qt_gl_preferredTextureFormat()
{
diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp
index 81985cd..a7376b2 100644
--- a/src/opengl/qgl_x11.cpp
+++ b/src/opengl/qgl_x11.cpp
@@ -1308,7 +1308,6 @@ void QGLWidget::setContext(QGLContext *context,
QGLContext* oldcx = d->glcx;
d->glcx = context;
-
if (parentWidget()) {
// force creation of delay-created widgets
parentWidget()->winId();
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index 452f155..9dbf5c8 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qglframebufferobject.h"
+#include "qglframebufferobject_p.h"
#include <qdebug.h>
#include <private/qgl_p.h>
@@ -74,40 +75,6 @@ extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
} \
}
-#ifndef QT_OPENGL_ES
-#define DEFAULT_FORMAT GL_RGBA8
-#else
-#define DEFAULT_FORMAT GL_RGBA
-#endif
-
-class QGLFramebufferObjectFormatPrivate
-{
-public:
- QGLFramebufferObjectFormatPrivate()
- : ref(1),
- samples(0),
- attachment(QGLFramebufferObject::NoAttachment),
- target(GL_TEXTURE_2D),
- internal_format(DEFAULT_FORMAT)
- {
- }
- QGLFramebufferObjectFormatPrivate
- (const QGLFramebufferObjectFormatPrivate *other)
- : ref(1),
- samples(other->samples),
- attachment(other->attachment),
- target(other->target),
- internal_format(other->internal_format)
- {
- }
-
- QAtomicInt ref;
- int samples;
- QGLFramebufferObject::Attachment attachment;
- GLenum target;
- GLenum internal_format;
-};
-
/*!
\class QGLFramebufferObjectFormat
\brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL
@@ -311,28 +278,59 @@ void QGLFramebufferObjectFormat::setInternalTextureFormat(QMacCompatGLenum inter
}
#endif
-class QGLFramebufferObjectPrivate
+/*!
+ Returns true if all the options of this framebuffer object format
+ are the same as \a other; otherwise returns false.
+*/
+bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& other) const
+{
+ if (d == other.d)
+ return true;
+ else
+ return d->equals(other.d);
+}
+
+/*!
+ Returns false if all the options of this framebuffer object format
+ are the same as \a other; otherwise returns true.
+*/
+bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const
+{
+ return !(*this == other);
+}
+
+void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f)
+{
+ fbo = f;
+ m_thisFBO = fbo->d_func()->fbo; // This shouldn't be needed
+}
+
+void QGLFBOGLPaintDevice::ensureActiveTarget()
{
-public:
- QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), ctx(0), previous_fbo(0), engine(0) {}
- ~QGLFramebufferObjectPrivate() {}
-
- void init(const QSize& sz, QGLFramebufferObject::Attachment attachment,
- GLenum internal_format, GLenum texture_target, GLint samples = 0);
- bool checkFramebufferStatus() const;
- GLuint texture;
- GLuint fbo;
- GLuint depth_stencil_buffer;
- GLuint color_buffer;
- GLenum target;
- QSize size;
- QGLFramebufferObjectFormat format;
- uint valid : 1;
- QGLFramebufferObject::Attachment fbo_attachment;
- QGLContextGroup *ctx; // for Windows extension ptrs
- GLuint previous_fbo;
- mutable QPaintEngine *engine;
-};
+ QGLContext* ctx = const_cast<QGLContext*>(QGLContext::currentContext());
+ Q_ASSERT(ctx);
+ const GLuint fboId = fbo->d_func()->fbo;
+ if (ctx->d_func()->current_fbo != fboId) {
+ ctx->d_func()->current_fbo = fboId;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
+ }
+}
+
+void QGLFBOGLPaintDevice::beginPaint()
+{
+ // We let QFBO track the previously bound FBO rather than doing it
+ // ourselves here. This has the advantage that begin/release & bind/end
+ // work as expected.
+ wasBound = fbo->isBound();
+ if (!wasBound)
+ fbo->bind();
+}
+
+void QGLFBOGLPaintDevice::endPaint()
+{
+ if (!wasBound)
+ fbo->release();
+}
bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
{
@@ -378,11 +376,14 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
return false;
}
-void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::Attachment attachment,
+void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
+ QGLFramebufferObject::Attachment attachment,
GLenum texture_target, GLenum internal_format, GLint samples)
{
QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
ctx = QGLContextPrivate::contextGroup(currentContext);
+ glDevice.setFBO(q);
+
bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(currentContext)))
return;
@@ -395,6 +396,8 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
+ glDevice.setFBO(q);
+
QT_CHECK_GLERROR();
// init texture
if (samples == 0) {
@@ -641,7 +644,8 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, NoAttachment, target, DEFAULT_FORMAT);
+ d->glDevice.setFBO(this);
+ d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -665,7 +669,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
+ d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
}
/*! \overload
@@ -678,7 +682,8 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebuff
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, format.attachment(), format.textureTarget(), format.internalTextureFormat(), format.samples());
+ d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
+ format.samples());
}
/*! \overload
@@ -691,7 +696,8 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFrame
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), format.attachment(), format.textureTarget(), format.internalTextureFormat(), format.samples());
+ d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
+ format.internalTextureFormat(), format.samples());
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -700,7 +706,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLen
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
+ d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
}
#endif
@@ -721,7 +727,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), attachment, target, internal_format);
+ d->init(this, QSize(width, height), attachment, target, internal_format);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -731,7 +737,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), attachment, target, internal_format);
+ d->init(this, QSize(width, height), attachment, target, internal_format);
}
#endif
@@ -752,7 +758,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, attachment, target, internal_format);
+ d->init(this, size, attachment, target, internal_format);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -762,7 +768,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, attachment, target, internal_format);
+ d->init(this, size, attachment, target, internal_format);
}
#endif
diff --git a/src/opengl/qglframebufferobject.h b/src/opengl/qglframebufferobject.h
index 6c1c0be..6efbb73 100644
--- a/src/opengl/qglframebufferobject.h
+++ b/src/opengl/qglframebufferobject.h
@@ -130,7 +130,8 @@ protected:
private:
Q_DISABLE_COPY(QGLFramebufferObject)
QScopedPointer<QGLFramebufferObjectPrivate> d_ptr;
- friend class QGLDrawable;
+ friend class QGLPaintDevice;
+ friend class QGLFBOGLPaintDevice;
};
class QGLFramebufferObjectFormatPrivate;
@@ -159,6 +160,9 @@ public:
void setInternalTextureFormat(QMacCompatGLenum internalTextureFormat);
#endif
+ bool operator==(const QGLFramebufferObjectFormat& other) const;
+ bool operator!=(const QGLFramebufferObjectFormat& other) const;
+
private:
QGLFramebufferObjectFormatPrivate *d;
diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h
new file mode 100644
index 0000000..58e6505
--- /dev/null
+++ b/src/opengl/qglframebufferobject_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLFRAMEBUFFEROBJECT_P_H
+#define QGLFRAMEBUFFEROBJECT_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 <qglframebufferobject.h>
+#include <private/qglpaintdevice_p.h>
+#include <private/qgl_p.h>
+
+QT_END_INCLUDE_NAMESPACE
+
+#ifndef QT_OPENGL_ES
+#define DEFAULT_FORMAT GL_RGBA8
+#else
+#define DEFAULT_FORMAT GL_RGBA
+#endif
+
+class QGLFramebufferObjectFormatPrivate
+{
+public:
+ QGLFramebufferObjectFormatPrivate()
+ : ref(1),
+ samples(0),
+ attachment(QGLFramebufferObject::NoAttachment),
+ target(GL_TEXTURE_2D),
+ internal_format(DEFAULT_FORMAT)
+ {
+ }
+ QGLFramebufferObjectFormatPrivate
+ (const QGLFramebufferObjectFormatPrivate *other)
+ : ref(1),
+ samples(other->samples),
+ attachment(other->attachment),
+ target(other->target),
+ internal_format(other->internal_format)
+ {
+ }
+ bool equals(const QGLFramebufferObjectFormatPrivate *other)
+ {
+ return samples == other->samples &&
+ attachment == other->attachment &&
+ target == other->target &&
+ internal_format == other->internal_format;
+ }
+
+ QAtomicInt ref;
+ int samples;
+ QGLFramebufferObject::Attachment attachment;
+ GLenum target;
+ GLenum internal_format;
+};
+
+class QGLFBOGLPaintDevice : public QGLPaintDevice
+{
+public:
+ virtual QPaintEngine* paintEngine() const {return fbo->paintEngine();}
+ virtual QSize size() const {return fbo->size();}
+ virtual QGLContext* context() const {return const_cast<QGLContext *>(QGLContext::currentContext());}
+ virtual void ensureActiveTarget();
+ virtual void beginPaint();
+ virtual void endPaint();
+
+ void setFBO(QGLFramebufferObject* f);
+
+private:
+ bool wasBound;
+ QGLFramebufferObject* fbo;
+};
+
+class QGLFramebufferObjectPrivate
+{
+public:
+ QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), ctx(0), previous_fbo(0), engine(0) {}
+ ~QGLFramebufferObjectPrivate() {}
+
+ void init(QGLFramebufferObject *q, const QSize& sz,
+ QGLFramebufferObject::Attachment attachment,
+ GLenum internal_format, GLenum texture_target, GLint samples = 0);
+ bool checkFramebufferStatus() const;
+ GLuint texture;
+ GLuint fbo;
+ GLuint depth_stencil_buffer;
+ GLuint color_buffer;
+ GLenum target;
+ QSize size;
+ QGLFramebufferObjectFormat format;
+ uint valid : 1;
+ QGLFramebufferObject::Attachment fbo_attachment;
+ QGLContextGroup *ctx; // for Windows extension ptrs
+ GLuint previous_fbo;
+ mutable QPaintEngine *engine;
+ QGLFBOGLPaintDevice glDevice;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QGLFRAMEBUFFEROBJECT_P_H
diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp
new file mode 100644
index 0000000..a89b884
--- /dev/null
+++ b/src/opengl/qglpaintdevice.cpp
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qglpaintdevice_p.h>
+#include <private/qgl_p.h>
+#include <private/qglpixelbuffer_p.h>
+#include <private/qglframebufferobject_p.h>
+#include <private/qwindowsurface_gl_p.h>
+#include <private/qpixmapdata_gl_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QGLPaintDevice::QGLPaintDevice()
+ : m_thisFBO(0)
+{
+}
+
+QGLPaintDevice::~QGLPaintDevice()
+{
+}
+
+
+void QGLPaintDevice::beginPaint()
+{
+ // Make sure our context is the current one:
+ QGLContext *ctx = context();
+ if (ctx != QGLContext::currentContext())
+ ctx->makeCurrent();
+
+ // Record the currently bound FBO so we can restore it again
+ // in endPaint() and bind this device's FBO
+ m_previousFBO = ctx->d_func()->current_fbo;
+ if (m_previousFBO != m_thisFBO) {
+ ctx->d_ptr->current_fbo = m_thisFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO);
+ }
+}
+
+void QGLPaintDevice::ensureActiveTarget()
+{
+ QGLContext* ctx = context();
+ if (ctx != QGLContext::currentContext())
+ ctx->makeCurrent();
+
+ if (ctx->d_ptr->current_fbo != m_thisFBO) {
+ ctx->d_ptr->current_fbo = m_thisFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO);
+ }
+}
+
+void QGLPaintDevice::endPaint()
+{
+ // Make sure the FBO bound at beginPaint is re-bound again here:
+ QGLContext *ctx = context();
+ if (m_previousFBO != ctx->d_func()->current_fbo) {
+ ctx->d_ptr->current_fbo = m_previousFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_previousFBO);
+ }
+}
+
+QGLFormat QGLPaintDevice::format() const
+{
+ return context()->format();
+}
+
+
+
+
+////////////////// QGLWidgetGLPaintDevice //////////////////
+
+QGLWidgetGLPaintDevice::QGLWidgetGLPaintDevice()
+{
+}
+
+QPaintEngine* QGLWidgetGLPaintDevice::paintEngine() const
+{
+ return glWidget->paintEngine();
+}
+
+void QGLWidgetGLPaintDevice::setWidget(QGLWidget* w)
+{
+ glWidget = w;
+}
+
+void QGLWidgetGLPaintDevice::beginPaint()
+{
+ QGLPaintDevice::beginPaint();
+ if (!glWidget->d_func()->disable_clear_on_painter_begin && glWidget->autoFillBackground()) {
+ if (glWidget->testAttribute(Qt::WA_TranslucentBackground))
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ else {
+ const QColor &c = glWidget->palette().brush(glWidget->backgroundRole()).color();
+ float alpha = c.alphaF();
+ glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
+ }
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+}
+
+void QGLWidgetGLPaintDevice::endPaint()
+{
+ if (glWidget->autoBufferSwap())
+ glWidget->swapBuffers();
+ QGLPaintDevice::endPaint();
+}
+
+
+QSize QGLWidgetGLPaintDevice::size() const
+{
+ return glWidget->size();
+}
+
+QGLContext* QGLWidgetGLPaintDevice::context() const
+{
+ return const_cast<QGLContext*>(glWidget->context());
+}
+
+// returns the QGLPaintDevice for the given QPaintDevice
+QGLPaintDevice* QGLPaintDevice::getDevice(QPaintDevice* pd)
+{
+ QGLPaintDevice* glpd = 0;
+
+ switch(pd->devType()) {
+ case QInternal::Widget:
+ // Should not be called on a non-gl widget:
+ Q_ASSERT(qobject_cast<QGLWidget*>(static_cast<QWidget*>(pd)));
+ glpd = &(static_cast<QGLWidget*>(pd)->d_func()->glDevice);
+ break;
+ case QInternal::Pbuffer:
+ glpd = &(static_cast<QGLPixelBuffer*>(pd)->d_func()->glDevice);
+ break;
+ case QInternal::FramebufferObject:
+ glpd = &(static_cast<QGLFramebufferObject*>(pd)->d_func()->glDevice);
+ break;
+ case QInternal::Pixmap: {
+ QPixmapData* pmd = static_cast<QPixmap*>(pd)->pixmapData();
+ Q_ASSERT(pmd->classId() == QPixmapData::OpenGLClass);
+ glpd = static_cast<QGLPixmapData*>(pmd)->glDevice();
+ break;
+ }
+ default:
+ qWarning("QGLPaintDevice::getDevice() - Unknown device type %d", pd->devType());
+ break;
+ }
+
+ return glpd;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qglpaintdevice_p.h b/src/opengl/qglpaintdevice_p.h
new file mode 100644
index 0000000..32a1275
--- /dev/null
+++ b/src/opengl/qglpaintdevice_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLPAINTDEVICE_P_H
+#define QGLPAINTDEVICE_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 QtOpenGL module. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <qpaintdevice.h>
+#include <qgl.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class QGLPaintDevice : public QPaintDevice
+{
+public:
+ QGLPaintDevice();
+ virtual ~QGLPaintDevice();
+
+ int devType() const {return QInternal::OpenGL;}
+
+ virtual void beginPaint();
+ virtual void ensureActiveTarget();
+ virtual void endPaint();
+
+ virtual QGLContext* context() const = 0;
+ QGLFormat format() const;
+ virtual QSize size() const = 0;
+
+ // returns the QGLPaintDevice for the given QPaintDevice
+ static QGLPaintDevice* getDevice(QPaintDevice*);
+
+protected:
+ GLuint m_previousFBO;
+ GLuint m_thisFBO;
+};
+
+
+// Wraps a QGLWidget
+class QGLWidget;
+class QGLWidgetGLPaintDevice : public QGLPaintDevice
+{
+public:
+ QGLWidgetGLPaintDevice();
+
+ virtual QPaintEngine* paintEngine() const;
+
+ // QGLWidgets need to do swapBufers in endPaint:
+ virtual void beginPaint();
+ virtual void endPaint();
+ virtual QSize size() const;
+ virtual QGLContext* context() const;
+
+ void setWidget(QGLWidget*);
+
+private:
+ friend class QGLWidget;
+ QGLWidget *glWidget;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGLPAINTDEVICE_P_H
diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp
index f082ff0..b6a919c 100644
--- a/src/opengl/qglpixelbuffer.cpp
+++ b/src/opengl/qglpixelbuffer.cpp
@@ -100,6 +100,22 @@ void qgl_cleanup_glyph_cache(QGLContext *) {}
extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
+
+QGLContext* QGLPBufferGLPaintDevice::context() const
+{
+ return pbuf->d_func()->qctx;
+}
+
+void QGLPBufferGLPaintDevice::endPaint() {
+ glFlush();
+ QGLPaintDevice::endPaint();
+}
+
+void QGLPBufferGLPaintDevice::setPBuffer(QGLPixelBuffer* pb)
+{
+ pbuf = pb;
+}
+
void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
{
Q_Q(QGLPixelBuffer);
@@ -115,6 +131,7 @@ void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &form
shareWidget->d_func()->glcx->d_func()->sharing = true;
}
+ glDevice.setPBuffer(q);
qctx->d_func()->paintDevice = q;
qctx->d_func()->valid = true;
#if defined(Q_WS_WIN) && !defined(QT_OPENGL_ES)
diff --git a/src/opengl/qglpixelbuffer.h b/src/opengl/qglpixelbuffer.h
index 5e81ea3..fe313a6 100644
--- a/src/opengl/qglpixelbuffer.h
+++ b/src/opengl/qglpixelbuffer.h
@@ -110,6 +110,8 @@ private:
QScopedPointer<QGLPixelBufferPrivate> d_ptr;
friend class QGLDrawable;
friend class QGLWindowSurface;
+ friend class QGLPaintDevice;
+ friend class QGLPBufferGLPaintDevice;
};
QT_END_NAMESPACE
diff --git a/src/opengl/qglpixelbuffer_p.h b/src/opengl/qglpixelbuffer_p.h
index 74cb330..96d41d7 100644
--- a/src/opengl/qglpixelbuffer_p.h
+++ b/src/opengl/qglpixelbuffer_p.h
@@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE
QT_BEGIN_INCLUDE_NAMESPACE
#include "QtOpenGL/qglpixelbuffer.h"
#include <private/qgl_p.h>
+#include <private/qglpaintdevice_p.h>
#if defined(Q_WS_X11) && !defined(QT_OPENGL_ES)
#include <GL/glx.h>
@@ -135,6 +136,19 @@ QT_END_INCLUDE_NAMESPACE
class QEglContext;
+
+class QGLPBufferGLPaintDevice : public QGLPaintDevice
+{
+public:
+ virtual QPaintEngine* paintEngine() const {return pbuf->paintEngine();}
+ virtual QSize size() const {return pbuf->size();}
+ virtual QGLContext* context() const;
+ virtual void endPaint();
+ void setPBuffer(QGLPixelBuffer* pb);
+private:
+ QGLPixelBuffer* pbuf;
+};
+
class QGLPixelBufferPrivate {
Q_DECLARE_PUBLIC(QGLPixelBuffer)
public:
@@ -154,6 +168,7 @@ public:
QGLPixelBuffer *q_ptr;
bool invalid;
QGLContext *qctx;
+ QGLPBufferGLPaintDevice glDevice;
QGLFormat format;
QGLFormat req_format;
diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp
index bf4d4b9..34fff10 100644
--- a/src/opengl/qpaintengine_opengl.cpp
+++ b/src/opengl/qpaintengine_opengl.cpp
@@ -49,6 +49,7 @@
#include "qbrush.h"
#include "qgl.h"
#include <private/qgl_p.h>
+#include <private/qglpaintdevice_p.h>
#include <private/qpainter_p.h>
#include "qmap.h"
#include <private/qpaintengine_opengl_p.h>
@@ -75,7 +76,7 @@
#include "qgl_cl_p.h"
#endif
-#define QGL_FUNC_CONTEXT QGLContext *ctx = const_cast<QGLContext *>(drawable.context());
+#define QGL_FUNC_CONTEXT QGLContext *ctx = const_cast<QGLContext *>(device->context());
#include <stdlib.h>
#include "qpaintengine_opengl_p.h"
@@ -286,7 +287,7 @@ public Q_SLOTS:
}
private:
- QGLDrawable drawable;
+ QGLPaintDevice* device;
QGLFramebufferObject *offscreen;
QGLContext *ctx;
@@ -305,7 +306,13 @@ private:
inline void QGLOffscreen::setDevice(QPaintDevice *pdev)
{
- drawable.setDevice(pdev);
+ if (pdev->devType() == QInternal::OpenGL)
+ device = static_cast<QGLPaintDevice*>(pdev);
+ else
+ device = QGLPaintDevice::getDevice(pdev);
+
+ if (!device)
+ return;
drawable_fbo = (pdev->devType() == QInternal::FramebufferObject);
}
@@ -329,12 +336,12 @@ void QGLOffscreen::initialize()
activated = true;
initialized = true;
- int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(drawable.size().width(), drawable.size().height()))));
+ int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(device->size().width(), device->size().height()))));
- bool shared_context = qgl_share_reg()->checkSharing(drawable.context(), ctx);
+ bool shared_context = qgl_share_reg()->checkSharing(device->context(), ctx);
bool would_fail = last_failed_size.isValid() &&
- (drawable.size().width() >= last_failed_size.width() ||
- drawable.size().height() >= last_failed_size.height());
+ (device->size().width() >= last_failed_size.width() ||
+ device->size().height() >= last_failed_size.height());
bool needs_refresh = dim > mask_dim || !shared_context;
if (needs_refresh && !would_fail) {
@@ -348,13 +355,13 @@ void QGLOffscreen::initialize()
delete offscreen;
offscreen = 0;
mask_dim = 0;
- last_failed_size = drawable.size();
+ last_failed_size = device->size();
}
}
qt_mask_texture_cache()->setOffscreenSize(offscreenSize());
- qt_mask_texture_cache()->setDrawableSize(drawable.size());
- ctx = drawable.context();
+ qt_mask_texture_cache()->setDrawableSize(device->size());
+ ctx = device->context();
#endif
}
@@ -428,11 +435,11 @@ inline void QGLOffscreen::release()
DEBUG_ONCE_STR("QGLOffscreen: releasing offscreen");
if (drawable_fbo)
- drawable.makeCurrent();
+ device->ensureActiveTarget(); //###
else
offscreen->release();
- QSize sz(drawable.size());
+ QSize sz(device->size());
glViewport(0, 0, sz.width(), sz.height());
glMatrixMode(GL_PROJECTION);
@@ -455,7 +462,7 @@ inline bool QGLOffscreen::isBound() const
inline QSize QGLOffscreen::drawableSize() const
{
- return drawable.size();
+ return device->size();
}
inline QSize QGLOffscreen::offscreenSize() const
@@ -757,7 +764,7 @@ public:
GLubyte pen_color[4];
GLubyte brush_color[4];
QTransform::TransformationType txop;
- QGLDrawable drawable;
+ QGLPaintDevice* device;
QGLOffscreen offscreen;
qreal inverseScale;
@@ -1167,7 +1174,7 @@ void QOpenGLPaintEnginePrivate::createGradientPaletteTexture(const QGradient& g)
#ifdef QT_OPENGL_ES //###
Q_UNUSED(g);
#else
- GLuint texId = qt_opengl_gradient_cache()->getBuffer(g, opacity, drawable.context());
+ GLuint texId = qt_opengl_gradient_cache()->getBuffer(g, opacity, device->context());
glBindTexture(GL_TEXTURE_1D, texId);
grad_palette = texId;
if (g.spread() == QGradient::RepeatSpread || g.type() == QGradient::ConicalGradient)
@@ -1236,12 +1243,19 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
{
Q_D(QOpenGLPaintEngine);
- d->drawable.setDevice(pdev);
+ if (pdev->devType() == QInternal::OpenGL)
+ d->device = static_cast<QGLPaintDevice*>(pdev);
+ else
+ d->device = QGLPaintDevice::getDevice(pdev);
+
+ if (!d->device)
+ return false;
+
d->offscreen.setDevice(pdev);
d->has_fast_pen = false;
d->inverseScale = 1;
d->opacity = 1;
- d->drawable.makeCurrent();
+ d->device->beginPaint();
d->matrix = QTransform();
d->has_antialiasing = false;
d->high_quality_antialiasing = false;
@@ -1256,7 +1270,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
bool has_frag_program = (QGLExtensions::glExtensions & QGLExtensions::FragmentProgram)
&& (pdev->devType() != QInternal::Pixmap);
- QGLContext *ctx = const_cast<QGLContext *>(d->drawable.context());
+ QGLContext *ctx = const_cast<QGLContext *>(d->device->context());
if (!ctx) {
qWarning() << "QOpenGLPaintEngine: paint device doesn't have a valid GL context.";
return false;
@@ -1265,9 +1279,9 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
if (has_frag_program)
has_frag_program = qt_resolve_frag_program_extensions(ctx) && qt_resolve_version_1_3_functions(ctx);
- d->use_stencil_method = d->drawable.format().stencil()
+ d->use_stencil_method = d->device->format().stencil()
&& (QGLExtensions::glExtensions & QGLExtensions::StencilWrap);
- if (d->drawable.format().directRendering()
+ if (d->device->format().directRendering()
&& (d->use_stencil_method && QGLExtensions::glExtensions & QGLExtensions::StencilTwoSide))
d->has_stencil_face_ext = qt_resolve_stencil_face_extension(ctx);
@@ -1333,23 +1347,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
d->offscreen.begin();
- if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) {
-
- if (d->drawable.hasTransparentBackground())
- glClearColor(0.0, 0.0, 0.0, 0.0);
- else {
- const QColor &c = d->drawable.backgroundColor();
- glClearColor(c.redF(), c.greenF(), c.blueF(), 1.0);
- }
-
- GLbitfield clearBits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
-#ifndef QT_OPENGL_ES
- clearBits |= GL_ACCUM_BUFFER_BIT;
-#endif
- glClear(clearBits);
- }
-
- QSize sz(d->drawable.size());
+ QSize sz(d->device->size());
glViewport(0, 0, sz.width(), sz.height()); // XXX (Embedded): We need a solution for GLWidgets that draw in a part or a bigger surface...
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@@ -1366,7 +1364,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
#ifdef QT_OPENGL_ES
d->max_texture_size = ctx->d_func()->maxTextureSize();
#else
- bool shared_ctx = qgl_share_reg()->checkSharing(d->drawable.context(), d->shader_ctx);
+ bool shared_ctx = qgl_share_reg()->checkSharing(d->device->context(), d->shader_ctx);
if (shared_ctx) {
d->max_texture_size = d->shader_ctx->d_func()->maxTextureSize();
@@ -1382,7 +1380,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
glDeleteTextures(1, &d->drawable_texture);
ctx->makeCurrent();
}
- d->shader_ctx = d->drawable.context();
+ d->shader_ctx = d->device->context();
glGenTextures(1, &d->grad_palette);
qt_mask_texture_cache()->clearCache();
@@ -1417,7 +1415,7 @@ bool QOpenGLPaintEngine::end()
Q_D(QOpenGLPaintEngine);
d->flushDrawQueue();
d->offscreen.end();
- QGLContext *ctx = const_cast<QGLContext *>(d->drawable.context());
+ QGLContext *ctx = const_cast<QGLContext *>(d->device->context());
if (!ctx->d_ptr->internal_context) {
glMatrixMode(GL_TEXTURE);
glPopMatrix();
@@ -1434,8 +1432,7 @@ bool QOpenGLPaintEngine::end()
glPopClientAttrib();
}
#endif
- d->drawable.swapBuffers();
- d->drawable.doneCurrent();
+ d->device->endPaint();
qt_mask_texture_cache()->maintainCache();
return true;
@@ -1961,7 +1958,7 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule)
const int left = rect.left();
const int width = rect.width();
- const int bottom = drawable.size().height() - (rect.bottom() + 1);
+ const int bottom = device->size().height() - (rect.bottom() + 1);
const int height = rect.height();
glScissor(left, bottom, width, height);
@@ -2242,7 +2239,7 @@ void QOpenGLPaintEnginePrivate::updateDepthClip()
const int left = fastClip.left();
const int width = fastClip.width();
- const int bottom = drawable.size().height() - (fastClip.bottom() + 1);
+ const int bottom = device->size().height() - (fastClip.bottom() + 1);
const int height = fastClip.height();
glScissor(left, bottom, width, height);
@@ -2325,7 +2322,7 @@ void QOpenGLPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOpe
// clipping is only supported when a stencil or depth buffer is
// available
- if (!d->drawable.format().depth())
+ if (!d->device->format().depth())
return;
d->use_system_clip = false;
@@ -2362,7 +2359,7 @@ void QOpenGLPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOpe
path.addRect(untransformedRects[0]);
path = d->matrix.map(path);
- if (path.contains(QRectF(QPointF(), d->drawable.size())))
+ if (path.contains(QRectF(QPointF(), d->device->size())))
isScreenClip = true;
}
}
@@ -3369,7 +3366,7 @@ void QOpenGLPaintEnginePrivate::drawOffscreenPath(const QPainterPath &path)
disableClipping();
- GLuint program = qt_gl_program_cache()->getProgram(drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(device->context(),
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true);
QGLPathMaskGenerator maskGenerator(path, matrix, offscreen, program);
addItem(qt_mask_texture_cache()->getMask(maskGenerator, this));
@@ -3506,7 +3503,7 @@ void QOpenGLPaintEngine::drawRects(const QRectF *rects, int rectCount)
if (d->has_brush) {
d->disableClipping();
- GLuint program = qt_gl_program_cache()->getProgram(d->drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(d->device->context(),
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true);
if (d->matrix.type() >= QTransform::TxProject) {
@@ -3916,7 +3913,7 @@ void QOpenGLPaintEnginePrivate::strokeLines(const QPainterPath &path)
qreal penWidth = cpen.widthF();
- GLuint program = qt_gl_program_cache()->getProgram(drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(device->context(),
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true);
QGLLineMaskGenerator maskGenerator(path, matrix, penWidth == 0 ? 1.0 : penWidth,
offscreen, program);
@@ -4302,7 +4299,7 @@ void QOpenGLPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QR
else {
GLenum target = qt_gl_preferredTextureTarget();
d->flushDrawQueue();
- d->drawable.bindTexture(pm, target);
+ d->device->context()->bindTexture(pm, target);
drawTextureRect(pm.width(), pm.height(), r, sr, target);
}
}
@@ -4336,9 +4333,9 @@ void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con
d->flushDrawQueue();
if (scaled.isNull())
- d->drawable.bindTexture(pm);
+ d->device->context()->bindTexture(pm);
else
- d->drawable.bindTexture(scaled);
+ d->device->context()->bindTexture(scaled);
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, d->use_smooth_pixmap_transform);
#ifndef QT_OPENGL_ES
@@ -4404,7 +4401,7 @@ void QOpenGLPaintEngine::drawImage(const QRectF &r, const QImage &image, const Q
else {
GLenum target = qt_gl_preferredTextureTarget();
d->flushDrawQueue();
- d->drawable.bindTexture(image, target);
+ d->device->context()->bindTexture(image, target);
drawTextureRect(image.width(), image.height(), r, sr, target);
}
}
@@ -4871,7 +4868,7 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
// make sure the glyphs we want to draw are in the cache
- qt_glyph_cache()->cacheGlyphs(d->drawable.context(), ti, glyphs);
+ qt_glyph_cache()->cacheGlyphs(d->device->context(), ti, glyphs);
d->setGradientOps(Qt::SolidPattern, QRectF()); // turns off gradient ops
qt_glColor4ubv(d->pen_color);
@@ -4949,7 +4946,7 @@ void QOpenGLPaintEngine::drawEllipse(const QRectF &rect)
glPushMatrix();
glLoadIdentity();
- GLuint program = qt_gl_program_cache()->getProgram(d->drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(d->device->context(),
FRAGMENT_PROGRAM_MASK_ELLIPSE_AA, 0, true);
QGLEllipseMaskGenerator maskGenerator(rect,
d->matrix,
@@ -5084,10 +5081,10 @@ void QOpenGLPaintEnginePrivate::copyDrawable(const QRectF &rect)
QRectF screen_rect = rect.adjusted(-1, -1, 1, 1);
int left = qMax(0, static_cast<int>(screen_rect.left()));
- int width = qMin(drawable.size().width() - left, static_cast<int>(screen_rect.width()) + 1);
+ int width = qMin(device->size().width() - left, static_cast<int>(screen_rect.width()) + 1);
- int bottom = qMax(0, static_cast<int>(drawable.size().height() - screen_rect.bottom()));
- int height = qMin(drawable.size().height() - bottom, static_cast<int>(screen_rect.height()) + 1);
+ int bottom = qMax(0, static_cast<int>(device->size().height() - screen_rect.bottom()));
+ int height = qMin(device->size().height() - bottom, static_cast<int>(screen_rect.height()) + 1);
glBindTexture(GL_TEXTURE_2D, drawable_texture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, left, bottom, width, height);
@@ -5181,9 +5178,9 @@ void QOpenGLPaintEnginePrivate::composite(GLuint primitive, const q_vertexType *
glActiveTexture(GL_TEXTURE0 + brush_texture_location);
if (current_style == Qt::TexturePattern)
- drawable.bindTexture(cbrush.textureImage());
+ device->context()->bindTexture(cbrush.textureImage());
else
- drawable.bindTexture(qt_imageForBrush(current_style, true));
+ device->context()->bindTexture(qt_imageForBrush(current_style, true));
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, use_smooth_pixmap_transform);
}
@@ -5191,7 +5188,7 @@ void QOpenGLPaintEnginePrivate::composite(GLuint primitive, const q_vertexType *
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
glEnable(GL_FRAGMENT_PROGRAM_ARB);
- GLuint program = qt_gl_program_cache()->getProgram(drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(device->context(),
fragment_brush,
fragment_composition_mode, false);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program);
@@ -5263,7 +5260,7 @@ void QOpenGLPaintEnginePrivate::drawItem(const QDrawQueueItem &item)
setGradientOps(item.brush, item.location.screen_rect);
composite(item.location.screen_rect, item.location.rect.topLeft() - item.location.screen_rect.topLeft()
- - QPoint(0, offscreen.offscreenSize().height() - drawable.size().height()));
+ - QPoint(0, offscreen.offscreenSize().height() - device->size().height()));
}
void QOpenGLPaintEnginePrivate::flushDrawQueue()
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index d63d2ad..ae616a8 100644
--- a/src/opengl/qpixmapdata_gl.cpp
+++ b/src/opengl/qpixmapdata_gl.cpp
@@ -80,12 +80,7 @@ QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize
for (int i = 0; !chosen && i < m_fbos.size(); ++i) {
QGLFramebufferObject *fbo = m_fbos.at(i);
- QGLFramebufferObjectFormat format = fbo->format();
- if (format.samples() == requestFormat.samples()
- && format.attachment() == requestFormat.attachment()
- && format.textureTarget() == requestFormat.textureTarget()
- && format.internalTextureFormat() == requestFormat.internalTextureFormat())
- {
+ if (fbo->format() == requestFormat) {
// choose the fbo with a matching format and the closest size
if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo))
candidate = fbo;
@@ -132,6 +127,76 @@ void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo)
m_fbos << fbo;
}
+
+QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const
+{
+ return data->paintEngine();
+}
+
+void QGLPixmapGLPaintDevice::beginPaint()
+{
+ if (!data->isValid())
+ return;
+
+ // QGLPaintDevice::beginPaint will store the current binding and replace
+ // it with m_thisFBO:
+ m_thisFBO = data->m_renderFbo->handle();
+ QGLPaintDevice::beginPaint();
+
+ Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2);
+
+ // QPixmap::fill() is deferred until now, where we actually need to do the fill:
+ if (data->needsFill()) {
+ const QColor &c = data->fillColor();
+ float alpha = c.alphaF();
+ glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ else if (!data->isUninitialized()) {
+ // If the pixmap (GL Texture) has valid content (it has been
+ // uploaded from an image or rendered into before), we need to
+ // copy it from the texture to the render FBO.
+
+ // Pass false to tell bind to _not_ copy the FBO into the texture!
+ GLuint texId = data->bind(false);
+
+ QGL2PaintEngineEx* pe = static_cast<QGL2PaintEngineEx*>(data->paintEngine());
+ QRect rect(0, 0, data->width(), data->height());
+ pe->drawTexture(QRectF(rect), texId, rect.size(), QRectF(rect));
+ }
+}
+
+void QGLPixmapGLPaintDevice::endPaint()
+{
+ if (!data->isValid())
+ return;
+
+ data->copyBackFromRenderFbo(false);
+
+ data->m_renderFbo->release();
+ qgl_fbo_pool()->release(data->m_renderFbo);
+ data->m_renderFbo = 0;
+
+ // Base's endPaint will restore the previous FBO binding
+ QGLPaintDevice::endPaint();
+}
+
+QGLContext* QGLPixmapGLPaintDevice::context() const
+{
+ data->ensureCreated();
+ return data->m_ctx;
+}
+
+QSize QGLPixmapGLPaintDevice::size() const
+{
+ return data->size();
+}
+
+void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d)
+{
+ data = d;
+}
+
static int qt_gl_pixmap_serial = 0;
QGLPixmapData::QGLPixmapData(PixelType type)
@@ -144,6 +209,7 @@ QGLPixmapData::QGLPixmapData(PixelType type)
, m_hasAlpha(false)
{
setSerialNumber(++qt_gl_pixmap_serial);
+ m_glDevice.setPixmapData(this);
}
QGLPixmapData::~QGLPixmapData()
@@ -237,11 +303,6 @@ void QGLPixmapData::ensureCreated() const
m_texture.options &= ~QGLContext::MemoryManagedBindOption;
}
-QGLFramebufferObject *QGLPixmapData::fbo() const
-{
- return m_renderFbo;
-}
-
void QGLPixmapData::fromImage(const QImage &image,
Qt::ImageConversionFlags)
{
@@ -417,31 +478,6 @@ void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
}
-void QGLPixmapData::swapBuffers()
-{
- if (!isValid())
- return;
-
- copyBackFromRenderFbo(false);
- m_renderFbo->release();
-
- qgl_fbo_pool()->release(m_renderFbo);
-
- m_renderFbo = 0;
-}
-
-void QGLPixmapData::makeCurrent()
-{
- if (isValid() && m_renderFbo)
- m_renderFbo->bind();
-}
-
-void QGLPixmapData::doneCurrent()
-{
- if (isValid() && m_renderFbo)
- m_renderFbo->release();
-}
-
bool QGLPixmapData::useFramebufferObjects()
{
return QGLFramebufferObject::hasOpenGLFramebufferObjects()
@@ -490,6 +526,10 @@ QPaintEngine* QGLPixmapData::paintEngine() const
return m_source.paintEngine();
}
+
+// If copyBack is true, bind will copy the contents of the render
+// FBO to the texture (which is not bound to the texture, as it's
+// a multisample FBO).
GLuint QGLPixmapData::bind(bool copyBack) const
{
if (m_renderFbo && copyBack) {
@@ -509,12 +549,6 @@ GLuint QGLPixmapData::bind(bool copyBack) const
return id;
}
-GLuint QGLPixmapData::textureId() const
-{
- ensureCreated();
- return m_texture.id;
-}
-
QGLTexture* QGLPixmapData::texture() const
{
return &m_texture;
@@ -553,4 +587,9 @@ int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
}
}
+QGLPaintDevice *QGLPixmapData::glDevice() const
+{
+ return &m_glDevice;
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index ab1ff47..31ae7c7 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -57,12 +57,14 @@
#include "qgl.h"
#include "private/qpixmapdata_p.h"
+#include "private/qglpaintdevice_p.h"
QT_BEGIN_NAMESPACE
class QPaintEngine;
class QGLFramebufferObject;
class QGLFramebufferObjectFormat;
+class QGLPixmapData;
class QGLFramebufferObjectPool
{
@@ -76,31 +78,50 @@ private:
QGLFramebufferObjectPool* qgl_fbo_pool();
+
+class QGLPixmapGLPaintDevice : public QGLPaintDevice
+{
+public:
+ QPaintEngine* paintEngine() const;
+
+ void beginPaint();
+ void endPaint();
+ QGLContext* context() const;
+ QSize size() const;
+
+ void setPixmapData(QGLPixmapData*);
+private:
+ QGLPixmapData *data;
+};
+
+
class QGLPixmapData : public QPixmapData
{
public:
QGLPixmapData(PixelType type);
~QGLPixmapData();
- bool isValid() const;
-
+ // Re-implemented from QPixmapData:
void resize(int width, int height);
- void fromImage(const QImage &image,
- Qt::ImageConversionFlags flags);
+ void fromImage(const QImage &image, Qt::ImageConversionFlags flags);
void copy(const QPixmapData *data, const QRect &rect);
-
bool scroll(int dx, int dy, const QRect &rect);
-
void fill(const QColor &color);
bool hasAlphaChannel() const;
QImage toImage() const;
QPaintEngine *paintEngine() const;
+ int metric(QPaintDevice::PaintDeviceMetric metric) const;
+ // For accessing as a target:
+ QGLPaintDevice *glDevice() const;
+
+ // For accessing as a source:
+ bool isValidContext(const QGLContext *ctx) const;
GLuint bind(bool copyBack = true) const;
- GLuint textureId() const;
QGLTexture *texture() const;
- bool isValidContext(const QGLContext *ctx) const;
+private:
+ bool isValid() const;
void ensureCreated() const;
@@ -109,22 +130,13 @@ public:
bool needsFill() const { return m_hasFillColor; }
QColor fillColor() const { return m_fillColor; }
- QSize size() const { return QSize(w, h); }
-
- QGLFramebufferObject *fbo() const;
- void makeCurrent();
- void doneCurrent();
- void swapBuffers();
-protected:
- int metric(QPaintDevice::PaintDeviceMetric metric) const;
-
-private:
QGLPixmapData(const QGLPixmapData &other);
QGLPixmapData &operator=(const QGLPixmapData &other);
void copyBackFromRenderFbo(bool keepCurrentFboBound) const;
+ QSize size() const { return QSize(w, h); }
static bool useFramebufferObjects();
@@ -145,6 +157,10 @@ private:
mutable bool m_hasFillColor;
mutable bool m_hasAlpha;
+
+ mutable QGLPixmapGLPaintDevice m_glDevice;
+
+ friend class QGLPixmapGLPaintDevice;
};
QT_END_NAMESPACE
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp
index a85b9ae..3a6ed06 100644
--- a/src/opengl/qwindowsurface_gl.cpp
+++ b/src/opengl/qwindowsurface_gl.cpp
@@ -229,6 +229,7 @@ QGLWidget* qt_gl_share_widget()
return _qt_gl_share_widget()->shareWidget();
}
+
struct QGLWindowSurfacePrivate
{
QGLFramebufferObject *fbo;
@@ -248,10 +249,49 @@ struct QGLWindowSurfacePrivate
QSize size;
QList<QImage> buffers;
+ QGLWindowSurfaceGLPaintDevice glDevice;
+ QGLWindowSurface* q_ptr;
};
QGLFormat QGLWindowSurface::surfaceFormat;
+void QGLWindowSurfaceGLPaintDevice::endPaint()
+{
+ glFlush();
+ QGLPaintDevice::endPaint();
+}
+
+QSize QGLWindowSurfaceGLPaintDevice::size() const
+{
+ return d->size;
+}
+
+QGLContext* QGLWindowSurfaceGLPaintDevice::context() const
+{
+ return d->ctx;
+}
+
+
+int QGLWindowSurfaceGLPaintDevice::metric(PaintDeviceMetric m) const
+{
+ return d->q_ptr->window()->metric(m);
+}
+
+Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_window_surface_2_engine)
+
+#if !defined (QT_OPENGL_ES_2)
+Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_window_surface_engine)
+#endif
+
+QPaintEngine *QGLWindowSurfaceGLPaintDevice::paintEngine() const
+{
+#if !defined(QT_OPENGL_ES_2)
+ if (!qt_gl_preferGL2Engine())
+ return qt_gl_window_surface_engine();
+#endif
+ return qt_gl_window_surface_2_engine();
+}
+
QGLWindowSurface::QGLWindowSurface(QWidget *window)
: QWindowSurface(window), d_ptr(new QGLWindowSurfacePrivate)
{
@@ -263,6 +303,8 @@ QGLWindowSurface::QGLWindowSurface(QWidget *window)
d_ptr->tried_fbo = false;
d_ptr->tried_pb = false;
d_ptr->destructive_swap_buffers = qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull();
+ d_ptr->glDevice.d = d_ptr;
+ d_ptr->q_ptr = this;
}
QGLWindowSurface::~QGLWindowSurface()
@@ -320,27 +362,6 @@ void QGLWindowSurface::hijackWindow(QWidget *widget)
qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size();
}
-Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_window_surface_2_engine)
-
-#if !defined (QT_OPENGL_ES_2)
-Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_window_surface_engine)
-#endif
-
-/*! \reimp */
-QPaintEngine *QGLWindowSurface::paintEngine() const
-{
-#if !defined(QT_OPENGL_ES_2)
- if (!qt_gl_preferGL2Engine())
- return qt_gl_window_surface_engine();
-#endif
- return qt_gl_window_surface_2_engine();
-}
-
-int QGLWindowSurface::metric(PaintDeviceMetric m) const
-{
- return window()->metric(m);
-}
-
QGLContext *QGLWindowSurface::context() const
{
return d_ptr->ctx;
@@ -354,7 +375,7 @@ QPaintDevice *QGLWindowSurface::paintDevice()
return d_ptr->pb;
if (d_ptr->ctx)
- return this;
+ return &d_ptr->glDevice;
QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
ctx->makeCurrent();
diff --git a/src/opengl/qwindowsurface_gl_p.h b/src/opengl/qwindowsurface_gl_p.h
index ad583b2..7b18f2e 100644
--- a/src/opengl/qwindowsurface_gl_p.h
+++ b/src/opengl/qwindowsurface_gl_p.h
@@ -56,6 +56,7 @@
#include <qglobal.h>
#include <qgl.h>
#include <private/qwindowsurface_p.h>
+#include <private/qglpaintdevice_p.h>
QT_BEGIN_NAMESPACE
@@ -65,7 +66,18 @@ class QRegion;
class QWidget;
struct QGLWindowSurfacePrivate;
-class QGLWindowSurface : public QObject, public QWindowSurface, public QPaintDevice
+class QGLWindowSurfaceGLPaintDevice : public QGLPaintDevice
+{
+public:
+ QPaintEngine* paintEngine() const;
+ void endPaint();
+ QSize size() const;
+ int metric(PaintDeviceMetric m) const;
+ QGLContext* context() const;
+ QGLWindowSurfacePrivate* d;
+};
+
+class QGLWindowSurface : public QObject, public QWindowSurface // , public QPaintDevice
{
Q_OBJECT
public:
@@ -87,11 +99,6 @@ public:
static QGLFormat surfaceFormat;
- QPaintEngine *paintEngine() const;
-
-protected:
- int metric(PaintDeviceMetric metric) const;
-
private slots:
void deleted(QObject *object);