summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qnamespace.h1
-rw-r--r--src/corelib/global/qnamespace.qdoc3
-rw-r--r--src/gui/kernel/qopenglcontext.cpp9
-rw-r--r--src/gui/kernel/qplatformintegration.h3
-rw-r--r--src/gui/kernel/qsurface.cpp16
-rw-r--r--src/gui/kernel/qsurface.h4
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp241
-rw-r--r--src/gui/painting/qplatformbackingstore.h32
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp24
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp1
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp11
-rw-r--r--src/widgets/kernel/kernel.pri5
-rw-r--r--src/widgets/kernel/qopenglwidget.cpp183
-rw-r--r--src/widgets/kernel/qopenglwidget_p.h135
-rw-r--r--src/widgets/kernel/qwidget.cpp45
-rw-r--r--src/widgets/kernel/qwidget_p.h28
-rw-r--r--src/widgets/kernel/qwidget_qpa.cpp5
-rw-r--r--src/widgets/kernel/qwidgetbackingstore.cpp87
-rw-r--r--src/widgets/kernel/qwidgetbackingstore_p.h6
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp6
-rw-r--r--tests/manual/qopenglwidget/openglwidget/main.cpp73
-rw-r--r--tests/manual/qopenglwidget/openglwidget/openglwidget.cpp193
-rw-r--r--tests/manual/qopenglwidget/openglwidget/openglwidget.h63
-rw-r--r--tests/manual/qopenglwidget/openglwidget/openglwidget.pro9
26 files changed, 1164 insertions, 26 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 366cfb5ed9..28d0c19b8d 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -516,6 +516,7 @@ public:
AA_SynthesizeTouchForUnhandledMouseEvents = 11,
AA_SynthesizeMouseForUnhandledTouchEvents = 12,
AA_UseHighDpiPixmaps = 13,
+ AA_ForceRasterWidgets = 14,
// Add new attributes before this line
AA_AttributeCount
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 4396cec51c..a96f37fd32 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -165,6 +165,9 @@
sizes in layout geometry calculations should typically divide by
QPixmap::devicePixelRatio() to get device-independent layout geometry.
+ \value AA_ForceRasterWidgets Make top-level widgets use pure raster surfaces,
+ and do not support non-native GL-based child widgets.
+
The following values are obsolete:
\value AA_ImmediateWidgetCreation This attribute is no longer fully
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 39dd2a2dfa..7fb51ddd52 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -761,8 +761,7 @@ bool QOpenGLContext::makeCurrent(QSurface *surface)
if (!surface->surfaceHandle())
return false;
-
- if (surface->surfaceType() != QSurface::OpenGLSurface) {
+ if (!surface->supportsOpenGL()) {
qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface" << surface;
return false;
}
@@ -837,9 +836,9 @@ void QOpenGLContext::swapBuffers(QSurface *surface)
return;
}
- if (surface->surfaceType() != QSurface::OpenGLSurface) {
- qWarning() << "QOpenGLContext::swapBuffers() called with non-opengl surface";
- return;
+ if (!surface->supportsOpenGL()) {
+ qWarning() << "QOpenGLContext::swapBuffers() called with non-opengl surface";
+ return;
}
if (surface->surfaceClass() == QSurface::Window
diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h
index e3676b1be8..35ef88949f 100644
--- a/src/gui/kernel/qplatformintegration.h
+++ b/src/gui/kernel/qplatformintegration.h
@@ -95,7 +95,8 @@ public:
NonFullScreenWindows,
NativeWidgets,
WindowManagement,
- SyncState
+ SyncState,
+ RasterGLSurface
};
virtual ~QPlatformIntegration() { }
diff --git a/src/gui/kernel/qsurface.cpp b/src/gui/kernel/qsurface.cpp
index a943639d5f..a27bdaccde 100644
--- a/src/gui/kernel/qsurface.cpp
+++ b/src/gui/kernel/qsurface.cpp
@@ -74,6 +74,9 @@ QT_BEGIN_NAMESPACE
a software rasterizer like Qt's raster paint engine.
\value OpenGLSurface The surface is an OpenGL compatible surface and can be used
in conjunction with QOpenGLContext.
+ \value RasterGLSurface The surface can be rendered to using a software rasterizer,
+ and also supports OpenGL. This surface type is intended for internal Qt use, and
+ requires the use of private API.
*/
@@ -84,6 +87,19 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ Returns true if the surface is OpenGL compatible and can be used in
+ conjunction with QOpenGLContext; otherwise returns false.
+
+ \since 5.3
+*/
+
+bool QSurface::supportsOpenGL() const
+{
+ SurfaceType type = surfaceType();
+ return type == OpenGLSurface || type == RasterGLSurface;
+}
+
+/*!
\fn QPlatformSurface *QSurface::surfaceHandle() const
Returns a handle to the platform-specific implementation of the surface.
diff --git a/src/gui/kernel/qsurface.h b/src/gui/kernel/qsurface.h
index 8dbc230c10..c4a3276372 100644
--- a/src/gui/kernel/qsurface.h
+++ b/src/gui/kernel/qsurface.h
@@ -64,7 +64,8 @@ public:
enum SurfaceType {
RasterSurface,
- OpenGLSurface
+ OpenGLSurface,
+ RasterGLSurface
};
virtual ~QSurface();
@@ -75,6 +76,7 @@ public:
virtual QPlatformSurface *surfaceHandle() const = 0;
virtual SurfaceType surfaceType() const = 0;
+ bool supportsOpenGL() const;
virtual QSize size() const = 0;
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index feec0c7f3d..d2b1f056d7 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -44,6 +44,16 @@
#include <qpixmap.h>
#include <private/qwindow_p.h>
+#include <qopengl.h>
+#include <qopenglcontext.h>
+#include <QtGui/QMatrix4x4>
+#include <QtGui/QOpenGLShaderProgram>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+#ifndef QT_NO_OPENGL
+#include <QtGui/private/qopengltextureblitter_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
class QPlatformBackingStorePrivate
@@ -51,13 +61,103 @@ class QPlatformBackingStorePrivate
public:
QPlatformBackingStorePrivate(QWindow *w)
: window(w)
+#ifndef QT_NO_OPENGL
+ , blitter(0)
+#endif
{
}
+ ~QPlatformBackingStorePrivate()
+ {
+#ifndef QT_NO_OPENGL
+ if (blitter)
+ blitter->destroy();
+ delete blitter;
+#endif
+ }
QWindow *window;
QSize size;
+#ifndef QT_NO_OPENGL
+ mutable GLuint textureId;
+ mutable QSize textureSize;
+ QOpenGLTextureBlitter *blitter;
+#endif
};
+#ifndef QT_NO_OPENGL
+
+struct QBackingstoreTextureInfo
+{
+ GLuint textureId;
+ QRect rect;
+};
+
+Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_MOVABLE_TYPE);
+
+class QPlatformTextureListPrivate : public QObjectPrivate
+{
+public:
+ QPlatformTextureListPrivate()
+ : locked(false)
+ {
+ }
+
+ QList<QBackingstoreTextureInfo> textures;
+ bool locked;
+};
+
+QPlatformTextureList::QPlatformTextureList(QObject *parent)
+: QObject(*new QPlatformTextureListPrivate, parent)
+{
+}
+
+QPlatformTextureList::~QPlatformTextureList()
+{
+}
+
+int QPlatformTextureList::count() const
+{
+ Q_D(const QPlatformTextureList);
+ return d->textures.count();
+}
+
+GLuint QPlatformTextureList::textureId(int index) const
+{
+ Q_D(const QPlatformTextureList);
+ return d->textures.at(index).textureId;
+}
+
+QRect QPlatformTextureList::geometry(int index) const
+{
+ Q_D(const QPlatformTextureList);
+ return d->textures.at(index).rect;
+}
+
+void QPlatformTextureList::lock(bool on)
+{
+ Q_D(QPlatformTextureList);
+ if (on != d->locked) {
+ d->locked = on;
+ emit locked(on);
+ }
+}
+
+bool QPlatformTextureList::isLocked() const
+{
+ Q_D(const QPlatformTextureList);
+ return d->locked;
+}
+
+void QPlatformTextureList::appendTexture(GLuint textureId, const QRect &geometry)
+{
+ Q_D(QPlatformTextureList);
+ QBackingstoreTextureInfo bi;
+ bi.textureId = textureId;
+ bi.rect = geometry;
+ d->textures.append(bi);
+}
+#endif // QT_NO_OPENGL
+
/*!
\class QPlatformBackingStore
\since 5.0
@@ -79,6 +179,147 @@ public:
Note that the \a offset parameter is currently unused.
*/
+#ifndef QT_NO_OPENGL
+/*!
+ Flushes the given \a region from the specified \a window onto the
+ screen, and composes it with the specified \a textures.
+
+ The default implementation retrieves the contents using toTexture()
+ and composes using OpenGL. May be reimplemented in subclasses if there
+ is a more efficient native way to do it.
+
+ Note that the \a offset parameter is currently unused.
+ */
+
+void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &region,
+ const QPoint &offset,
+ QPlatformTextureList *textures, QOpenGLContext *context)
+{
+ Q_UNUSED(offset);
+
+ context->makeCurrent(window);
+ glViewport(0, 0, window->width(), window->height());
+
+ if (!d_ptr->blitter) {
+ d_ptr->blitter = new QOpenGLTextureBlitter;
+ d_ptr->blitter->create();
+ }
+
+ d_ptr->blitter->bind();
+
+ QRect windowRect(QPoint(), window->size());
+ for (int i = 0; i < textures->count(); ++i) {
+ GLuint textureId = textures->textureId(i);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), windowRect,
+ QOpenGLTextureBlitter::OriginTopLeft);
+ d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft);
+ }
+
+ GLuint textureId = toTexture(region);
+ if (!textureId)
+ return;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(windowRect, windowRect,
+ QOpenGLTextureBlitter::OriginTopLeft);
+ d_ptr->blitter->setSwizzleRB(true);
+ d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
+ d_ptr->blitter->setSwizzleRB(false);
+
+ glDisable(GL_BLEND);
+ d_ptr->blitter->release();
+ context->swapBuffers(window);
+}
+
+/*!
+ Implemented in subclasses to return the content of the backingstore as a QImage.
+
+ If QPlatformIntegration::RasterGLSurface is supported, either this function or
+ toTexture() must be implemented.
+
+ \sa toTexture()
+ */
+QImage QPlatformBackingStore::toImage() const
+{
+ return QImage();
+}
+
+/*!
+ May be reimplemented in subclasses to return the content of the
+ backingstore as an OpenGL texture. \a dirtyRegion is the part of the
+ backingstore which may have changed since the last call to this function. The
+ caller of this function must ensure that there is a current context.
+
+ The ownership of the texture is not transferred. The caller must not store
+ the return value between calls, but instead call this function before each use.
+
+ The default implementation returns a cached texture if \a dirtyRegion is
+ empty and the window has not been resized, otherwise it retrieves the
+ content using toImage() and performs a texture upload.
+ */
+
+GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion) const
+{
+ QImage image = toImage();
+ QSize imageSize = image.size();
+ if (imageSize.isEmpty())
+ return 0;
+
+ bool resized = d_ptr->textureSize != imageSize;
+ if (dirtyRegion.isEmpty() && !resized)
+ return d_ptr->textureId;
+
+ if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_RGBA8888)
+ image = image.convertToFormat(QImage::Format_RGBA8888);
+
+ if (resized) {
+ if (d_ptr->textureId)
+ glDeleteTextures(1, &d_ptr->textureId);
+ glGenTextures(1, &d_ptr->textureId);
+ glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
+#ifndef QT_OPENGL_ES_2
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+#endif
+ 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_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageSize.width(), imageSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ const_cast<uchar*>(image.constBits()));
+ d_ptr->textureSize = imageSize;
+ } else {
+ glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
+ QRect imageRect = image.rect();
+ QRect rect = dirtyRegion.boundingRect() & imageRect;
+ // if the rect is wide enough it's cheaper to just
+ // extend it instead of doing an image copy
+ if (rect.width() >= imageRect.width() / 2) {
+ rect.setX(0);
+ rect.setWidth(imageRect.width());
+ }
+
+ // if the sub-rect is full-width we can pass the image data directly to
+ // OpenGL instead of copying, since there's no gap between scanlines
+
+ if (rect.width() == imageRect.width()) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+ image.constScanLine(rect.y()));
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+ image.copy(rect).constBits());
+ }
+ }
+
+ return d_ptr->textureId;
+}
+#endif // QT_NO_OPENGL
+
/*!
\fn QPaintDevice* QPlatformBackingStore::paintDevice()
diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h
index 1b19b2c379..a662a2290b 100644
--- a/src/gui/painting/qplatformbackingstore.h
+++ b/src/gui/painting/qplatformbackingstore.h
@@ -52,9 +52,11 @@
//
#include <QtCore/qrect.h>
+#include <QtCore/qobject.h>
#include <QtGui/qwindow.h>
#include <QtGui/qregion.h>
+#include <QtGui/qopengl.h>
QT_BEGIN_NAMESPACE
@@ -65,6 +67,31 @@ class QPoint;
class QImage;
class QPlatformBackingStorePrivate;
class QPlatformWindow;
+class QPlatformTextureList;
+class QPlatformTextureListPrivate;
+class QOpenGLContext;
+
+#ifndef QT_NO_OPENGL
+class Q_GUI_EXPORT QPlatformTextureList : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPlatformTextureList)
+public:
+ explicit QPlatformTextureList(QObject *parent = 0);
+ ~QPlatformTextureList();
+
+ int count() const;
+ GLuint textureId(int index) const;
+ QRect geometry(int index) const;
+ void lock(bool on);
+ bool isLocked() const;
+
+ void appendTexture(GLuint textureId, const QRect &geometry);
+
+ Q_SIGNALS:
+ void locked(bool);
+};
+#endif
class Q_GUI_EXPORT QPlatformBackingStore
{
@@ -79,6 +106,11 @@ public:
// 'window' can be a child window, in which case 'region' is in child window coordinates and
// offset is the (child) window's offset in relation to the window surface.
virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset) = 0;
+#ifndef QT_NO_OPENGL
+ virtual void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset, QPlatformTextureList *textures, QOpenGLContext *context);
+ virtual QImage toImage() const;
+ virtual GLuint toTexture(const QRegion &dirtyRegion) const;
+#endif
virtual void resize(const QSize &size, const QRegion &staticContents) = 0;
diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp
index 3f1c53b122..f7abb4662b 100644
--- a/src/plugins/platforms/xcb/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/qglxintegration.cpp
@@ -328,7 +328,7 @@ QGLXContext::~QGLXContext()
bool QGLXContext::makeCurrent(QPlatformSurface *surface)
{
bool success = false;
- Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
+ Q_ASSERT(surface->surface()->supportsOpenGL());
Display *dpy = DISPLAY_FROM_XCB(m_screen);
GLXDrawable glxDrawable = 0;
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 366e043e98..1579797f85 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -280,6 +280,11 @@ void QXcbBackingStore::beginPaint(const QRegion &region)
}
}
+QImage QXcbBackingStore::toImage() const
+{
+ return m_image && m_image->image() ? *m_image->image() : QImage();
+}
+
void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
if (!m_image || m_image->size().isEmpty())
@@ -319,6 +324,25 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
}
}
+#ifndef QT_NO_OPENGL
+void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
+ QPlatformTextureList *textures, QOpenGLContext *context)
+{
+ QPlatformBackingStore::composeAndFlush(window, region, offset, textures, context);
+
+ Q_XCB_NOOP(connection());
+
+ if (m_syncingResize) {
+ QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
+ connection()->sync();
+ m_syncingResize = false;
+ platformWindow->updateSyncRequestCounter();
+ } else {
+ xcb_flush(xcb_connection());
+ }
+}
+#endif // QT_NO_OPENGL
+
void QXcbBackingStore::resize(const QSize &size, const QRegion &)
{
if (m_image && size == m_image->size())
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h
index d2548242db..19a5ac62d0 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.h
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.h
@@ -60,6 +60,11 @@ public:
QPaintDevice *paintDevice();
void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+#ifndef QT_NO_OPENGL
+ void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
+ QPlatformTextureList *textures, QOpenGLContext *context);
+#endif
+ QImage toImage() const;
void resize(const QSize &size, const QRegion &staticContents);
bool scroll(const QRegion &area, int dx, int dy);
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 1803282071..768a591ab5 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -284,6 +284,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
case MultipleWindows: return true;
case ForeignWindows: return true;
case SyncState: return true;
+ case RasterGLSurface: return true;
default: return QPlatformIntegration::hasCapability(cap);
}
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 58abc7abfe..d0106984a2 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -292,8 +292,6 @@ void QXcbWindow::create()
if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) {
#if defined(XCB_USE_GLX)
XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), &m_format);
- if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
- qFatal("Could not initialize GLX");
#elif defined(XCB_USE_EGL)
EGLDisplay eglDisplay = connection()->egl_display();
EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, m_format, true);
@@ -308,9 +306,14 @@ void QXcbWindow::create()
XVisualInfo *visualInfo;
int matchingCount = 0;
visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount);
- if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
- qFatal("Could not initialize EGL");
#endif //XCB_USE_GLX
+ if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
+ qFatal("Could not initialize OpenGL");
+
+ if (!visualInfo && window()->surfaceType() == QSurface::RasterGLSurface) {
+ qWarning("Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface.");
+ window()->setSurfaceType(QSurface::RasterSurface);
+ }
if (visualInfo) {
m_depth = visualInfo->depth;
m_imageFormat = imageFormatForDepth(m_depth);
diff --git a/src/widgets/kernel/kernel.pri b/src/widgets/kernel/kernel.pri
index 444b9b687f..857fe4ac91 100644
--- a/src/widgets/kernel/kernel.pri
+++ b/src/widgets/kernel/kernel.pri
@@ -79,3 +79,8 @@ wince*: {
SOURCES += \
kernel/qwidgetsfunctions_wince.cpp
}
+
+contains(QT_CONFIG, opengl) {
+ HEADERS += kernel/qopenglwidget_p.h
+ SOURCES += kernel/qopenglwidget.cpp
+}
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp
new file mode 100644
index 0000000000..a5f81a9df8
--- /dev/null
+++ b/src/widgets/kernel/qopenglwidget.cpp
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopenglwidget_p.h"
+#include <QOpenGLContext>
+#include <QtWidgets/private/qwidget_p.h>
+
+#include <QOpenGLFramebufferObject>
+#include <QWindow>
+#include <qpa/qplatformwindow.h>
+#include <QDebug>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLWidgetPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QOpenGLWidget)
+public:
+ QOpenGLWidgetPrivate()
+ : fbo(0), uninitialized(true)
+ {
+ setRenderToTexture();
+ }
+ GLuint textureId() const { return fbo ? fbo->texture() : 0; }
+
+ const QSurface *surface() const { return q_func()->window()->windowHandle(); }
+ QSurface *surface() { return q_func()->window()->windowHandle(); }
+ void initialize();
+
+ QOpenGLContext context;
+ QOpenGLFramebufferObject *fbo;
+ bool uninitialized;
+
+ int w,h;
+};
+
+void QOpenGLWidgetPrivate::initialize()
+{
+ Q_Q(QOpenGLWidget);
+ if (!uninitialized)
+ return;
+ context.setShareContext(get(q->window())->shareContext());
+ context.setFormat(surface()->format());
+ context.create();
+ context.makeCurrent(surface());
+ q->initializeGL();
+ uninitialized = false;
+}
+
+QOpenGLWidget::QOpenGLWidget(QWidget *parent, Qt::WindowFlags f)
+ : QWidget(*(new QOpenGLWidgetPrivate), parent, f)
+{
+}
+
+QOpenGLWidget::~QOpenGLWidget()
+{
+}
+
+bool QOpenGLWidget::isValid() const
+{
+ Q_D(const QOpenGLWidget);
+ return d->context.isValid();
+}
+
+void QOpenGLWidget::makeCurrent()
+{
+ Q_D(QOpenGLWidget);
+ d->context.makeCurrent(d->surface());
+ d->fbo->bind();
+}
+
+void QOpenGLWidget::doneCurrent()
+{
+ Q_D(QOpenGLWidget);
+ d->context.doneCurrent();
+}
+
+QSurfaceFormat QOpenGLWidget::format() const
+{
+ Q_D(const QOpenGLWidget);
+ return d->surface()->format();
+}
+
+GLuint QOpenGLWidget::defaultFramebufferObject() const
+{
+ Q_D(const QOpenGLWidget);
+ return d->fbo ? d->fbo->handle() : 0;
+}
+
+void QOpenGLWidget::initializeGL()
+{
+
+}
+
+void QOpenGLWidget::resizeGL(int w, int h)
+{
+ Q_UNUSED(w);
+ Q_UNUSED(h);
+}
+
+void QOpenGLWidget::paintGL()
+{
+}
+
+void QOpenGLWidget::updateGL()
+{
+ makeCurrent();
+ paintGL();
+ glFlush();
+ doneCurrent();
+ update();
+}
+
+
+void QOpenGLWidget::resizeEvent(QResizeEvent *)
+{
+ Q_D(QOpenGLWidget);
+ d->w = width();
+ d->h = height();
+ d->initialize();
+
+ d->context.makeCurrent(d->surface());
+ delete d->fbo; // recreate when resized
+ d->fbo = new QOpenGLFramebufferObject(size());
+ d->fbo->bind();
+ glBindTexture(GL_TEXTURE_2D, d->fbo->texture());
+ 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_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ resizeGL(width(), height());
+ paintGL();
+ glFlush();
+}
+
+void QOpenGLWidget::paintEvent(QPaintEvent *)
+{
+ qWarning("QOpenGLWidget does not support paintEvent() yet.");
+ return;
+}
+
+QT_END_NAMESPACE
diff --git a/src/widgets/kernel/qopenglwidget_p.h b/src/widgets/kernel/qopenglwidget_p.h
new file mode 100644
index 0000000000..1c7f0bfeec
--- /dev/null
+++ b/src/widgets/kernel/qopenglwidget_p.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It may change from version to version
+// without notice, or even be removed.
+//
+// We mean it.
+//
+#ifndef QOPENGLWIDGET_H
+#define QOPENGLWIDGET_H
+
+#include <QWidget>
+#include <QSurfaceFormat>
+
+#include <QtGui/qopengl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLWidgetPrivate;
+
+class Q_WIDGETS_EXPORT QOpenGLWidget : public QWidget
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QOpenGLWidget)
+
+public:
+ explicit QOpenGLWidget(QWidget* parent=0,
+ Qt::WindowFlags f=0);
+
+// This API is not finalized yet. The commented-out functions below are
+// QGLWidget functions that have not been implemented for QOpenGLWidget.
+// Some of them may not end up in the final version (which is planned for a
+// future release of Qt).
+
+// explicit QOpenGLWidget(const QSurfaceFormat& format, QWidget* parent=0,
+// Qt::WindowFlags f=0);
+ ~QOpenGLWidget();
+
+// void qglClearColor(const QColor& c) const;
+
+ bool isValid() const;
+// bool isSharing() const;
+
+ void makeCurrent();
+ void doneCurrent();
+
+// void swapBuffers();
+
+ QSurfaceFormat format() const;
+ GLuint defaultFramebufferObject() const;
+
+// QPixmap renderPixmap(int w = 0, int h = 0, bool useContext = false);
+ QImage grabFrameBuffer(bool withAlpha = false);
+
+// static QImage convertToGLFormat(const QImage& img);
+
+// QPaintEngine *paintEngine() const;
+
+// void drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget = GL_TEXTURE_2D);
+// void drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget = GL_TEXTURE_2D);
+
+public Q_SLOTS:
+ void updateGL();
+
+protected:
+// bool event(QEvent *);
+ virtual void initializeGL();
+ virtual void resizeGL(int w, int h);
+ virtual void paintGL();
+
+// void setAutoBufferSwap(bool on);
+// bool autoBufferSwap() const;
+
+ void paintEvent(QPaintEvent*);
+ void resizeEvent(QResizeEvent*);
+
+// virtual void glInit();
+// virtual void glDraw();
+
+// QOpenGLWidget(QOpenGLWidgetPrivate &dd,
+// const QGLFormat &format = QGLFormat(),
+// QWidget *parent = 0,
+// const QOpenGLWidget* shareWidget = 0,
+// Qt::WindowFlags f = 0);
+private:
+ Q_DISABLE_COPY(QOpenGLWidget)
+
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPENGLWIDGET_H
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 034e2c9e97..46aa93fe48 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -78,6 +78,7 @@
#include "private/qstyle_p.h"
#include "qfileinfo.h"
#include <QtGui/qinputmethod.h>
+#include <QtGui/qopenglcontext.h>
#include <private/qgraphicseffect_p.h>
#include <qbackingstore.h>
@@ -270,6 +271,8 @@ QWidgetPrivate::QWidgetPrivate(int version)
, isMoved(0)
, usesDoubleBufferedGLContext(0)
, mustHaveWindowHandle(0)
+ , renderToTexture(0)
+ , textureChildSeen(0)
#ifndef QT_NO_IM
, inheritsInputMethodHints(0)
#endif
@@ -1558,6 +1561,7 @@ void QWidgetPrivate::createTLExtra()
x->inRepaint = false;
x->embedded = 0;
x->window = 0;
+ x->shareContext = 0;
x->screenIndex = 0;
#ifdef Q_WS_MAC
x->wasMaximized = false;
@@ -5133,9 +5137,17 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
<< "geometry ==" << QRect(q->mapTo(q->window(), QPoint(0, 0)), q->size());
#endif
- //actually send the paint event
- QPaintEvent e(toBePainted);
- QCoreApplication::sendSpontaneousEvent(q, &e);
+ if (renderToTexture) {
+ // This widget renders into a texture which is composed later. We just need to
+ // punch a hole in the backingstore, so the texture will be visible.
+ QPainter p(q);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.fillRect(q->rect(), Qt::transparent);
+ } else {
+ //actually send the paint event
+ QPaintEvent e(toBePainted);
+ QCoreApplication::sendSpontaneousEvent(q, &e);
+ }
// Native widgets need to be marked dirty on screen so painting will be done in correct context
if (backingStore && !onScreen && !asRoot && (q->internalWinId() || !q->nativeParentWidget()->isWindow()))
@@ -9637,6 +9649,13 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
if (desktopWidget)
parent = 0;
+#ifndef QT_NO_OPENGL
+ if (d->textureChildSeen && parent) {
+ // set the textureChildSeen flag up the whole parent chain
+ QWidgetPrivate::get(parent)->setTextureChildSeen();
+ }
+#endif
+
if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) {
if (newParent)
oldBs->removeDirtyWidget(this);
@@ -11108,7 +11127,25 @@ void QWidgetPrivate::adjustQuitOnCloseAttribute()
}
}
-
+QOpenGLContext *QWidgetPrivate::shareContext() const
+{
+#ifdef QT_NO_OPENGL
+ return 0;
+#else
+ if (!extra || !extra->topextra || !extra->topextra->window) {
+ qWarning() << "Asking for share context for widget that does not have a window handle";
+ return 0;
+ }
+ QWidgetPrivate *that = const_cast<QWidgetPrivate *>(this);
+ if (!extra->topextra->shareContext) {
+ QOpenGLContext *ctx = new QOpenGLContext();
+ ctx->setFormat(extra->topextra->window->format());
+ ctx->create();
+ that->extra->topextra->shareContext = ctx;
+ }
+ return that->extra->topextra->shareContext;
+#endif // QT_NO_OPENGL
+}
Q_WIDGETS_EXPORT QWidgetData *qt_qwidget_data(QWidget *widget)
{
diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h
index 45606685cb..bdfc57f7c3 100644
--- a/src/widgets/kernel/qwidget_p.h
+++ b/src/widgets/kernel/qwidget_p.h
@@ -60,6 +60,7 @@
#include "QtCore/qset.h"
#include "QtGui/qregion.h"
#include "QtGui/qinputmethod.h"
+#include "QtGui/qopengl.h"
#include "QtWidgets/qsizepolicy.h"
#include "QtWidgets/qstyle.h"
#include "QtWidgets/qapplication.h"
@@ -80,6 +81,7 @@ class QPixmap;
class QWidgetBackingStore;
class QGraphicsProxyWidget;
class QWidgetItemV2;
+class QOpenGLContext;
class QStyle;
@@ -216,6 +218,7 @@ struct QTLWExtra {
bool wasMaximized;
#endif
QWidgetWindow *window;
+ QOpenGLContext *shareContext;
quint32 screenIndex; // index in qplatformscreenlist
};
@@ -324,6 +327,8 @@ public:
explicit QWidgetPrivate(int version = QObjectPrivateVersion);
~QWidgetPrivate();
+ static QWidgetPrivate *get(QWidget *w) { return w->d_func(); }
+
QWExtra *extraData() const;
QTLWExtra *topData() const;
QTLWExtra *maybeTopData() const;
@@ -618,6 +623,27 @@ public:
inline QRect mapFromWS(const QRect &r) const
{ QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; }
+ QOpenGLContext *shareContext() const;
+
+#ifndef QT_NO_OPENGL
+ virtual GLuint textureId() const { return 0; }
+
+ void setRenderToTexture() { renderToTexture = true; textureChildSeen = true; }
+ void setTextureChildSeen()
+ {
+ Q_Q(QWidget);
+ if (textureChildSeen)
+ return;
+ textureChildSeen = 1;
+
+ if (!q->isWindow()) {
+ QWidget *parent = q->parentWidget();
+ if (parent)
+ get(parent)->setTextureChildSeen();
+ }
+ }
+#endif
+
// Variables.
// Regular pointers (keep them together to avoid gaps on 64 bit architectures).
QWExtra *extra;
@@ -698,6 +724,8 @@ public:
uint isMoved : 1;
uint usesDoubleBufferedGLContext : 1;
uint mustHaveWindowHandle : 1;
+ uint renderToTexture : 1;
+ uint textureChildSeen : 1;
#ifndef QT_NO_IM
uint inheritsInputMethodHints : 1;
#endif
diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp
index 0a4bc990e6..c2260b6e7d 100644
--- a/src/widgets/kernel/qwidget_qpa.cpp
+++ b/src/widgets/kernel/qwidget_qpa.cpp
@@ -49,6 +49,7 @@
#include "QtWidgets/qdesktopwidget.h"
#include <qpa/qplatformwindow.h>
#include "QtGui/qsurfaceformat.h"
+#include <QtGui/qopenglcontext.h>
#include <qpa/qplatformopenglcontext.h>
#include <qpa/qplatformintegration.h>
#include "QtGui/private/qwindow_p.h"
@@ -953,6 +954,10 @@ void QWidgetPrivate::deleteTLSysExtra()
delete extra->topextra->backingStore;
extra->topextra->backingStore = 0;
+#ifndef QT_NO_OPENGL
+ delete extra->topextra->shareContext;
+ extra->topextra->shareContext = 0;
+#endif
}
}
diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp
index d373400623..c8d5440999 100644
--- a/src/widgets/kernel/qwidgetbackingstore.cpp
+++ b/src/widgets/kernel/qwidgetbackingstore.cpp
@@ -57,6 +57,8 @@
#include <private/qpaintengine_raster_p.h>
#include <private/qgraphicseffect_p.h>
+#include <qpa/qplatformbackingstore.h>
+
#if defined(Q_OS_WIN) && !defined(QT_NO_PAINT_DEBUG)
# include <QtCore/qt_windows.h>
# include <qpa/qplatformnativeinterface.h>
@@ -72,10 +74,15 @@ extern QRegion qt_dirtyRegion(QWidget *);
* \a region is the region to be updated in \a widget coordinates.
*/
static inline void qt_flush(QWidget *widget, const QRegion &region, QBackingStore *backingStore,
- QWidget *tlw, const QPoint &tlwOffset)
+ QWidget *tlw, const QPoint &tlwOffset, QPlatformTextureList *widgetTextures = 0,
+ QOpenGLContext *context = 0)
{
+#ifdef QT_NO_OPENGL
+ Q_UNUSED(widgetTextures);
+ Q_UNUSED(context);
+#endif
Q_ASSERT(widget);
- Q_ASSERT(!region.isEmpty());
+ Q_ASSERT(!region.isEmpty() || (context && widgetTextures && widgetTextures->count()));
Q_ASSERT(backingStore);
Q_ASSERT(tlw);
@@ -104,10 +111,16 @@ static inline void qt_flush(QWidget *widget, const QRegion &region, QBackingStor
if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen))
return;
+ QPoint offset = tlwOffset;
if (widget != tlw)
- backingStore->flush(region, widget->windowHandle(), tlwOffset + widget->mapTo(tlw, QPoint()));
+ offset += widget->mapTo(tlw, QPoint());
+
+#ifndef QT_NO_OPENGL
+ if (widgetTextures)
+ backingStore->handle()->composeAndFlush(widget->windowHandle(), region, offset, widgetTextures, context);
else
- backingStore->flush(region, widget->windowHandle(), tlwOffset);
+#endif
+ backingStore->flush(region, widget->windowHandle(), offset);
}
#ifndef QT_NO_PAINT_DEBUG
@@ -430,7 +443,7 @@ QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &within
return region;
}
-static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
+void QWidgetBackingStore::sendUpdateRequest(QWidget *widget, bool updateImmediately)
{
if (!widget)
return;
@@ -439,6 +452,7 @@ static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
QEvent event(QEvent::UpdateRequest);
QApplication::sendEvent(widget, &event);
} else {
+ updateRequestSent = true;
QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
}
}
@@ -488,6 +502,7 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
return;
}
+ //### FIXME fullUpdatePending seems to be always false????
if (fullUpdatePending) {
if (updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
@@ -495,6 +510,13 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
}
const QPoint offset = widget->mapTo(tlw, QPoint());
+
+ if (QWidgetPrivate::get(widget)->renderToTexture) {
+ if (!updateRequestSent || updateImmediately)
+ sendUpdateRequest(tlw, updateImmediately);
+ return;
+ }
+
const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect());
if (qt_region_strictContains(dirty, widgetRect.translated(offset))) {
if (updateImmediately)
@@ -503,7 +525,7 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
}
if (invalidateBuffer) {
- const bool eventAlreadyPosted = !dirty.isEmpty();
+ const bool eventAlreadyPosted = !dirty.isEmpty() || updateRequestSent;
#ifndef QT_NO_GRAPHICSEFFECT
if (widget->d_func()->graphicsEffect)
dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset);
@@ -583,6 +605,13 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd
return;
}
+ if (QWidgetPrivate::get(widget)->renderToTexture) {
+ if (!updateRequestSent || updateImmediately)
+ sendUpdateRequest(tlw, updateImmediately);
+ return;
+ }
+
+
const QRect widgetRect = widget->d_func()->effectiveRectFor(rect);
const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
if (qt_region_strictContains(dirty, translatedRect)) {
@@ -703,7 +732,11 @@ void QWidgetBackingStore::updateLists(QWidget *cur)
}
QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel)
- : tlw(topLevel), dirtyOnScreenWidgets(0), fullUpdatePending(0)
+ : tlw(topLevel),
+ dirtyOnScreenWidgets(0),
+ widgetTextures(0),
+ fullUpdatePending(0),
+ updateRequestSent(0)
{
store = tlw->backingStore();
Q_ASSERT(store);
@@ -902,7 +935,7 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg
// Nothing to repaint.
if (!isDirty()) {
- qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset);
+ qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext());
return;
}
@@ -914,11 +947,27 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg
doSync();
}
+#ifndef QT_NO_OPENGL
+static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatformTextureList *widgetTextures)
+{
+ QWidgetPrivate *wd = QWidgetPrivate::get(widget);
+ if (wd->renderToTexture)
+ widgetTextures->appendTexture(wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size()));
+
+ for (int i = 0; i < wd->children.size(); ++i) {
+ QWidget *w = qobject_cast<QWidget *>(wd->children.at(i));
+ if (w && !w->isWindow() && !w->isHidden() && QWidgetPrivate::get(w)->textureChildSeen)
+ findTextureWidgetsRecursively(tlw, w, widgetTextures);
+ }
+}
+#endif
+
/*!
Synchronizes the backing store, i.e. dirty areas are repainted and flushed.
*/
void QWidgetBackingStore::sync()
{
+ updateRequestSent = false;
QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
if (discardSyncRequest(tlw, tlwExtra)) {
// If the top-level is minimized, it's not visible on the screen so we can delay the
@@ -1024,7 +1073,15 @@ void QWidgetBackingStore::doSync()
}
dirtyWidgets.clear();
+#ifndef QT_NO_OPENGL
+ delete widgetTextures;
+ widgetTextures = 0;
+ if (tlw->d_func()->textureChildSeen) {
+ widgetTextures = new QPlatformTextureList; // TODO: implement support for locking
+ findTextureWidgetsRecursively(tlw, tlw, widgetTextures);
+ }
fullUpdatePending = false;
+#endif
if (toClean.isEmpty()) {
// Nothing to repaint. However, we might have newly exposed areas on the
@@ -1038,6 +1095,7 @@ void QWidgetBackingStore::doSync()
if (tlw->d_func()->extra->proxyWidget) {
updateStaticContentsSize();
dirty = QRegion();
+ updateRequestSent = false;
const QVector<QRect> rects(toClean.rects());
for (int i = 0; i < rects.size(); ++i)
tlw->d_func()->extra->proxyWidget->update(rects.at(i));
@@ -1051,6 +1109,7 @@ void QWidgetBackingStore::doSync()
for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i)
resetWidget(opaqueNonOverlappedWidgets[i]);
dirty = QRegion();
+ updateRequestSent = false;
return;
}
@@ -1059,6 +1118,7 @@ void QWidgetBackingStore::doSync()
updateStaticContentsSize();
const QRegion dirtyCopy(dirty);
dirty = QRegion();
+ updateRequestSent = false;
// Paint opaque non overlapped widgets.
for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) {
@@ -1099,12 +1159,19 @@ void QWidgetBackingStore::flush(QWidget *widget)
{
if (!dirtyOnScreen.isEmpty()) {
QWidget *target = widget ? widget : tlw;
- qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset);
+ qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext());
dirtyOnScreen = QRegion();
}
- if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty())
+ if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) {
+#ifndef QT_NO_OPENGL
+ if (widgetTextures && widgetTextures->count()) {
+ QWidget *target = widget ? widget : tlw;
+ qt_flush(target, QRegion(), store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext());
+ }
+#endif
return;
+ }
for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
QWidget *w = dirtyOnScreenWidgets->at(i);
diff --git a/src/widgets/kernel/qwidgetbackingstore_p.h b/src/widgets/kernel/qwidgetbackingstore_p.h
index 3d12524c98..c6f6541e1f 100644
--- a/src/widgets/kernel/qwidgetbackingstore_p.h
+++ b/src/widgets/kernel/qwidgetbackingstore_p.h
@@ -60,6 +60,8 @@
QT_BEGIN_NAMESPACE
+class QPlatformTextureList;
+
struct BeginPaintInfo {
inline BeginPaintInfo() : wasFlushed(0), nothingToPaint(0), backingStoreRecreated(0) {}
uint wasFlushed : 1;
@@ -102,11 +104,15 @@ private:
QVector<QWidget *> dirtyWidgets;
QVector<QWidget *> *dirtyOnScreenWidgets;
QList<QWidget *> staticWidgets;
+ QPlatformTextureList *widgetTextures;
QBackingStore *store;
uint fullUpdatePending : 1;
+ uint updateRequestSent : 1;
QPoint tlwOffset;
+ void sendUpdateRequest(QWidget *widget, bool updateImmediately);
+
static bool flushPaint(QWidget *widget, const QRegion &rgn);
static void unflushPaint(QWidget *widget, const QRegion &rgn);
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index 672c4156cd..0e40dd866f 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -92,6 +92,12 @@ QWidgetWindow::QWidgetWindow(QWidget *widget)
, m_widget(widget)
{
updateObjectName();
+ // Enable QOpenGLWidget/QQuickWidget children if the platform plugin supports it,
+ // and the application developer has not explicitly disabled it.
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)
+ && !QApplication::testAttribute(Qt::AA_ForceRasterWidgets)) {
+ setSurfaceType(QSurface::RasterGLSurface);
+ }
connect(m_widget, &QObject::objectNameChanged, this, &QWidgetWindow::updateObjectName);
}
diff --git a/tests/manual/qopenglwidget/openglwidget/main.cpp b/tests/manual/qopenglwidget/openglwidget/main.cpp
new file mode 100644
index 0000000000..68f9be7199
--- /dev/null
+++ b/tests/manual/qopenglwidget/openglwidget/main.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "openglwidget.h"
+#include <QApplication>
+#include <QPushButton>
+#include <QMdiArea>
+#include <QLCDNumber>
+#include <QTimer>
+
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ QMdiArea w;
+ w.resize(400,400);
+
+ OpenGLWidget *glw = new OpenGLWidget;
+ w.addSubWindow(glw);
+ glw->setMinimumSize(100,100);
+
+ OpenGLWidget *glw2 = new OpenGLWidget;
+ glw2->setMinimumSize(100,100);
+ w.addSubWindow(glw2);
+
+ QLCDNumber *lcd = new QLCDNumber;
+ lcd->display(1337);
+ lcd->setMinimumSize(300,100);
+ w.addSubWindow(lcd);
+
+ w.show();
+
+ return a.exec();
+}
diff --git a/tests/manual/qopenglwidget/openglwidget/openglwidget.cpp b/tests/manual/qopenglwidget/openglwidget/openglwidget.cpp
new file mode 100644
index 0000000000..09e0dd5419
--- /dev/null
+++ b/tests/manual/qopenglwidget/openglwidget/openglwidget.cpp
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define GL_GLEXT_PROTOTYPES
+
+#include "openglwidget.h"
+#include <QtWidgets/private/qwidget_p.h>
+#include <QOpenGLFramebufferObject>
+#include <QWindow>
+#include <qpa/qplatformwindow.h>
+#include <QDebug>
+#include <QTimer>
+
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QMatrix4x4>
+#include <QtGui/QOpenGLShaderProgram>
+#include <QtGui/QScreen>
+
+#include <QtCore/qmath.h>
+#include <qopengl.h>
+
+#include <GL/glext.h>
+
+class OpenGLWidgetPrivate
+{
+public:
+ OpenGLWidgetPrivate()
+ : m_program(0), m_frame(0)
+ {
+
+ }
+
+ void initialize();
+ void render();
+
+
+ int width() {return w;}
+ int height() {return h;}
+
+ GLuint m_posAttr;
+ GLuint m_colAttr;
+ GLuint m_matrixUniform;
+
+ QOpenGLShaderProgram *m_program;
+ int m_frame;
+
+ int w,h;
+};
+
+
+OpenGLWidget::OpenGLWidget(QWidget *parent)
+ : QOpenGLWidget(parent)
+{
+ d = new OpenGLWidgetPrivate;
+ QTimer *timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
+ timer->start(30);
+}
+
+OpenGLWidget::~OpenGLWidget()
+{
+
+}
+
+void OpenGLWidget::initializeGL()
+{
+// qDebug("*initializeGL*");
+ d->initialize();
+}
+
+void OpenGLWidget::resizeGL(int w, int h)
+{
+// qDebug("*resizeGL*");
+ d->w = w;
+ d->h = h;
+}
+void OpenGLWidget::paintGL()
+{
+// qDebug("*paintGL* %d", d->m_frame);
+ d->render();
+}
+
+
+static const char *vertexShaderSource =
+ "attribute highp vec4 posAttr;\n"
+ "attribute lowp vec4 colAttr;\n"
+ "varying lowp vec4 col;\n"
+ "uniform highp mat4 matrix;\n"
+ "void main() {\n"
+ " col = colAttr;\n"
+ " gl_Position = matrix * posAttr;\n"
+ "}\n";
+
+static const char *fragmentShaderSource =
+ "varying lowp vec4 col;\n"
+ "void main() {\n"
+ " gl_FragColor = col;\n"
+ "}\n";
+
+void OpenGLWidgetPrivate::initialize()
+{
+ m_program = new QOpenGLShaderProgram;
+ m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
+ m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
+ m_program->link();
+ m_posAttr = m_program->attributeLocation("posAttr");
+ m_colAttr = m_program->attributeLocation("colAttr");
+ m_matrixUniform = m_program->uniformLocation("matrix");
+}
+
+void OpenGLWidgetPrivate::render()
+{
+ const qreal retinaScale = 1.0;//devicePixelRatio();
+ glViewport(0, 0, width() * retinaScale, height() * retinaScale);
+
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ m_program->bind();
+
+ QMatrix4x4 matrix;
+ matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
+ matrix.translate(0, 0, -2);
+ matrix.rotate(100.0f * m_frame / 30/*screen()->refreshRate()*/, 0, 1, 0);
+
+ m_program->setUniformValue(m_matrixUniform, matrix);
+
+ GLfloat vertices[] = {
+ 0.0f, 0.707f,
+ -0.5f, -0.5f,
+ 0.5f, -0.5f
+ };
+
+ GLfloat colors[] = {
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f
+ };
+
+ glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, 0, vertices);
+ glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors);
+
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+
+ glDisableVertexAttribArray(1);
+ glDisableVertexAttribArray(0);
+
+ m_program->release();
+
+ ++m_frame;
+}
diff --git a/tests/manual/qopenglwidget/openglwidget/openglwidget.h b/tests/manual/qopenglwidget/openglwidget/openglwidget.h
new file mode 100644
index 0000000000..eaba27df26
--- /dev/null
+++ b/tests/manual/qopenglwidget/openglwidget/openglwidget.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OPENGLWIDGET_H
+#define OPENGLWIDGET_H
+
+#include <QtWidgets/private/qopenglwidget_p.h>
+
+class OpenGLWidgetPrivate;
+class OpenGLWidget : public QOpenGLWidget
+{
+ Q_OBJECT
+public:
+ OpenGLWidget(QWidget *parent = 0);
+ ~OpenGLWidget();
+
+ void initializeGL();
+ void resizeGL(int w, int h);
+ void paintGL();
+
+private:
+ OpenGLWidgetPrivate *d;
+};
+
+#endif // OPENGLWIDGET_H
diff --git a/tests/manual/qopenglwidget/openglwidget/openglwidget.pro b/tests/manual/qopenglwidget/openglwidget/openglwidget.pro
new file mode 100644
index 0000000000..63d877e7b0
--- /dev/null
+++ b/tests/manual/qopenglwidget/openglwidget/openglwidget.pro
@@ -0,0 +1,9 @@
+QT += widgets widgets-private gui-private core-private
+
+TARGET = openglwidget
+TEMPLATE = app
+
+SOURCES += main.cpp \
+ openglwidget.cpp
+
+HEADERS += openglwidget.h