summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorPaul Olav Tvete <paul.tvete@digia.com>2013-12-18 14:48:22 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-12 20:12:17 +0100
commiteacd58d4e78e7238ba5fcca90ba960aaf3ebd263 (patch)
tree779bf1735aecb7985bc3136264b9147eb23d5374 /src/gui
parent5ae5bebb93ec38e17c0dcb9bec47e0ebfbce4937 (diff)
Enabling QQuickWidget and QOpenGLWidget
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 <jorgen.lind@digia.com>
Diffstat (limited to 'src/gui')
-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
6 files changed, 298 insertions, 7 deletions
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;