From eacd58d4e78e7238ba5fcca90ba960aaf3ebd263 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Wed, 18 Dec 2013 14:48:22 +0100 Subject: Enabling QQuickWidget and QOpenGLWidget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable child widgets (without a native window) that render to an FBO and are composed with the raster backingstore by the platform plugin. A preliminary version of QOpenGLWidget is included as private API. Change-Id: I8f984a4d7db285069ce3d6564707942c823d890d Reviewed-by: Jørgen Lind --- src/corelib/global/qnamespace.h | 1 + src/corelib/global/qnamespace.qdoc | 3 + src/gui/kernel/qopenglcontext.cpp | 9 +- src/gui/kernel/qplatformintegration.h | 3 +- src/gui/kernel/qsurface.cpp | 16 ++ src/gui/kernel/qsurface.h | 4 +- src/gui/painting/qplatformbackingstore.cpp | 241 +++++++++++++++++++++++++ src/gui/painting/qplatformbackingstore.h | 32 ++++ src/plugins/platforms/xcb/qglxintegration.cpp | 2 +- src/plugins/platforms/xcb/qxcbbackingstore.cpp | 24 +++ src/plugins/platforms/xcb/qxcbbackingstore.h | 5 + src/plugins/platforms/xcb/qxcbintegration.cpp | 1 + src/plugins/platforms/xcb/qxcbwindow.cpp | 11 +- src/widgets/kernel/kernel.pri | 5 + src/widgets/kernel/qopenglwidget.cpp | 183 +++++++++++++++++++ src/widgets/kernel/qopenglwidget_p.h | 135 ++++++++++++++ src/widgets/kernel/qwidget.cpp | 45 ++++- src/widgets/kernel/qwidget_p.h | 28 +++ src/widgets/kernel/qwidget_qpa.cpp | 5 + src/widgets/kernel/qwidgetbackingstore.cpp | 87 ++++++++- src/widgets/kernel/qwidgetbackingstore_p.h | 6 + src/widgets/kernel/qwidgetwindow.cpp | 6 + 22 files changed, 826 insertions(+), 26 deletions(-) create mode 100644 src/widgets/kernel/qopenglwidget.cpp create mode 100644 src/widgets/kernel/qopenglwidget_p.h (limited to 'src') 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. */ @@ -83,6 +86,19 @@ QT_BEGIN_NAMESPACE Returns the format of the surface. */ +/*! + 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 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 #include +#include +#include +#include +#include +#include +#include +#ifndef QT_NO_OPENGL +#include +#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 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 ®ion, + 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(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 +#include #include #include +#include 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 ®ion, const QPoint &offset) = 0; +#ifndef QT_NO_OPENGL + virtual void composeAndFlush(QWindow *window, const QRegion ®ion, 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 ®ion) } } +QImage QXcbBackingStore::toImage() const +{ + return m_image && m_image->image() ? *m_image->image() : QImage(); +} + void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { if (!m_image || m_image->size().isEmpty()) @@ -319,6 +324,25 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin } } +#ifndef QT_NO_OPENGL +void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, 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(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 ®ion, const QPoint &offset); +#ifndef QT_NO_OPENGL + void composeAndFlush(QWindow *window, const QRegion ®ion, 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 +#include + +#include +#include +#include +#include +#include +#include + +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 +#include + +#include + +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 +#include #include #include @@ -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(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 #include "QtGui/qsurfaceformat.h" +#include #include #include #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 #include +#include + #if defined(Q_OS_WIN) && !defined(QT_NO_PAINT_DEBUG) # include # include @@ -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 ®ion, 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 ®ion, 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(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 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 dirtyWidgets; QVector *dirtyOnScreenWidgets; QList 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); } -- cgit v1.2.3