summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJørgen Lind <jorgen.lind@digia.com>2014-08-14 15:47:55 +0200
committerGunnar Sletta <gunnar@sletta.org>2015-01-17 08:03:34 +0100
commit37956e6605dd5d5a714607a7e04217d293d9c25f (patch)
tree90651bfa41d2885f3d876cca382522d3dfbe46ff
parent517fb9026896f7ac20376f253babae5a7c57721d (diff)
Introducing QPlatformGraphicsBuffer
Change-Id: Idcf8f75bd151a877c7097b79df998c1ffd56871c Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
-rw-r--r--src/gui/kernel/kernel.pri8
-rw-r--r--src/gui/kernel/qplatformgraphicsbuffer.cpp277
-rw-r--r--src/gui/kernel/qplatformgraphicsbuffer.h117
-rw-r--r--src/gui/kernel/qplatformgraphicsbufferhelper.cpp185
-rw-r--r--src/gui/kernel/qplatformgraphicsbufferhelper.h56
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp54
-rw-r--r--src/gui/painting/qplatformbackingstore.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp43
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.h3
9 files changed, 740 insertions, 6 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 1169985ea8..e0d4464d47 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -71,7 +71,9 @@ HEADERS += \
kernel/qpixelformat.h \
kernel/qpaintdevicewindow.h \
kernel/qpaintdevicewindow_p.h \
- kernel/qrasterwindow.h
+ kernel/qrasterwindow.h \
+ kernel/qplatformgraphicsbuffer.h \
+ kernel/qplatformgraphicsbufferhelper.h
SOURCES += \
kernel/qgenericpluginfactory.cpp \
@@ -124,7 +126,9 @@ SOURCES += \
kernel/qplatformmenu.cpp \
kernel/qpixelformat.cpp \
kernel/qpaintdevicewindow.cpp \
- kernel/qrasterwindow.cpp
+ kernel/qrasterwindow.cpp \
+ kernel/qplatformgraphicsbuffer.cpp \
+ kernel/qplatformgraphicsbufferhelper.cpp
contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) {
HEADERS += \
diff --git a/src/gui/kernel/qplatformgraphicsbuffer.cpp b/src/gui/kernel/qplatformgraphicsbuffer.cpp
new file mode 100644
index 0000000000..f032601b29
--- /dev/null
+++ b/src/gui/kernel/qplatformgraphicsbuffer.cpp
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtGui 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 "qplatformgraphicsbuffer.h"
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/qopengl.h>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+/*!
+ \class QPlatformGraphicsBuffer
+ \inmodule QtGui
+ \since 5.5
+ \brief The QPlatformGraphicsBuffer is a windowsystem abstraction for native graphics buffers
+
+ Different platforms have different ways of representing graphics buffers. On
+ some platforms, it is possible to create one graphics buffer that you can bind
+ to a texture and also get main memory access to the image bits. On the
+ other hand, on some platforms all graphics buffer abstraction is completely
+ hidden.
+
+ QPlatformGraphicsBuffer is an abstraction of a single Graphics Buffer.
+
+ There is no public constructor nor any public factory function.
+
+ QPlatformGraphicsBuffer is intended to be created by using platform specific
+ APIs available from QtPlatformHeaders, or there might be accessor functions
+ similar to the accessor function that QPlatformBackingstore has.
+*/
+
+/*!
+ \enum QPlatformGraphicsBuffer::AccessType
+
+ This enum describes the access that is desired or granted for the graphics
+ buffer.
+
+ \value None
+ \value SWReadAccess
+ \value SWWriteAccess
+ \value TextureAccess
+ \value HWCompositor
+*/
+
+/*!
+ \enum QPlatformGraphicsBuffer::Origin
+
+ This enum describes the origin of the content of the buffer.
+
+ \value OriginTopLeft
+ \value OriginBottomLeft
+*/
+
+/*!
+ Protected constructor to initialize the private members.
+
+ \a size is the size of the buffer.
+ \a format is the format of the buffer.
+
+ \sa size() format()
+*/
+QPlatformGraphicsBuffer::QPlatformGraphicsBuffer(const QSize &size, const QPixelFormat &format)
+ : m_size(size)
+ , m_format(format)
+{
+}
+
+
+/*!
+ Virtual destructor.
+*/
+QPlatformGraphicsBuffer::~QPlatformGraphicsBuffer()
+{
+}
+
+/*!
+ Binds the content of this graphics buffer into the currently bound texture.
+
+ This function should fail for buffers not capable of locking to TextureAccess.
+
+ \a rect is the subrect which is desired to be bounded to the texture. This
+ argument has a no less than semantic, meaning more (if not all) of the buffer
+ can be bounded to the texture. An empty QRect is interpreted as entire buffer
+ should be bound.
+
+ This function only supports binding buffers to the GL_TEXTURE_2D texture
+ target.
+
+ Returns true on success, otherwise false.
+*/
+bool QPlatformGraphicsBuffer::bindToTexture(const QRect &rect) const
+{
+ Q_UNUSED(rect);
+ return false;
+}
+
+/*!
+ \fn QPlatformGraphicsBuffer::AccessTypes QPlatformGraphicsBuffer::isLocked() const
+ Function to check if the buffer is locked.
+
+ \sa lock()
+*/
+
+/*!
+ Before the data can be retrieved or before a buffer can be bound to a
+ texture it needs to be locked. This is a separate function call since this
+ operation might be time consuming, and it would not be satisfactory to do
+ it per function call.
+
+ \a access is the access type wanted.
+
+ \a rect is the subrect which is desired to be locked. This
+ argument has a no less than semantic, meaning more (if not all) of the buffer
+ can be locked. An empty QRect is interpreted as entire buffer should be locked.
+
+ Return true on successfully locking all AccessTypes specified \a access
+ otherwise returns false and no locks have been granted.
+*/
+bool QPlatformGraphicsBuffer::lock(AccessTypes access, const QRect &rect)
+{
+ bool locked = doLock(access, rect);
+ if (locked)
+ m_lock_access |= access;
+
+ return locked;
+}
+
+/*!
+ Unlocks the current buffer lock.
+
+ This function calls doUnlock, and then emits the unlocked signal with the
+ AccessTypes from before doUnlock was called.
+*/
+void QPlatformGraphicsBuffer::unlock()
+{
+ if (m_lock_access == None)
+ return;
+ AccessTypes previous = m_lock_access;
+ doUnlock();
+ m_lock_access = None;
+ emit unlocked(previous);
+}
+
+
+/*!
+ \fn QPlatformGraphicsBuffer::doLock(AccessTypes access, const QRect &rect = QRect())
+
+ This function should be reimplemented by subclasses. If one of the \a
+ access types specified can not be locked, then all should fail and this
+ function should return false.
+
+ \a rect is the subrect which is desired to be locked. This
+ argument has a no less than semantic, meaning more (if not all) of the
+ buffer can be locked. An empty QRect should be interpreted as the entire buffer
+ should be locked.
+
+ It is safe to call isLocked() to verify the current lock state.
+*/
+
+/*!
+ \fn QPlatformGraphicsBuffer::doUnlock()
+
+ This function should remove all locks set on the buffer.
+
+ It is safe to call isLocked() to verify the current lock state.
+*/
+
+/*!
+ \fn QPlatformGraphicsBuffer::unlocked(AccessTypes previousAccessTypes)
+
+ Signal that is emitted after unlocked has been called.
+
+ \a previousAccessTypes is the access types locked before unlock was called.
+*/
+
+/*!
+ Accessor for the bytes of the buffer. This function needs to be called on a
+ buffer with SWReadAccess access lock. Behavior is undefined for modifying
+ the memory returned when not having a SWWriteAccess.
+*/
+const uchar *QPlatformGraphicsBuffer::data() const
+{ return Q_NULLPTR; }
+
+/*!
+ Accessor for the bytes of the buffer. This function needs to be called on a
+ buffer with SWReadAccess access lock. Behavior is undefined for modifying
+ the memory returned when not having a SWWriteAccess.
+*/
+uchar *QPlatformGraphicsBuffer::data()
+{
+ return Q_NULLPTR;
+}
+
+/*!
+ Accessor for the length of the data buffer. This function is a convenience
+ function multiplying height of buffer with bytesPerLine().
+
+ \sa data() bytesPerLine() size()
+*/
+int QPlatformGraphicsBuffer::byteCount() const
+{
+ Q_ASSERT(isLocked() & SWReadAccess);
+ return size().height() * bytesPerLine();
+}
+
+/*!
+ Accessor for bytes per line in the graphics buffer.
+*/
+int QPlatformGraphicsBuffer::bytesPerLine() const
+{
+ return 0;
+}
+
+
+/*!
+ In origin of the content of the graphics buffer.
+
+ Default implementation is OriginTopLeft, as this is the coordinate
+ system default for Qt. However, for most regular OpenGL textures
+ this will be OriginBottomLeft.
+*/
+QPlatformGraphicsBuffer::Origin QPlatformGraphicsBuffer::origin() const
+{
+ return OriginTopLeft;
+}
+
+/*!
+ \fn QPlatformGraphicsBuffer::size() const
+
+ Accessor for content size.
+*/
+
+/*!
+ \fn QPlatformGraphicsBuffer::format() const
+
+ Accessor for the pixel format of the buffer.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformgraphicsbuffer.h b/src/gui/kernel/qplatformgraphicsbuffer.h
new file mode 100644
index 0000000000..62e06bceeb
--- /dev/null
+++ b/src/gui/kernel/qplatformgraphicsbuffer.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtGui 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$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMGRAPHICSBUFFER_H
+#define QPLATFORMGRAPHICSBUFFER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is part of the QPA API and is not meant to be used
+// in applications. Usage of this API may make your code
+// source and binary incompatible with future versions of Qt.
+//
+
+
+#include <QtCore/QSize>
+#include <QtCore/QRect>
+#include <QtGui/QPixelFormat>
+#include <QtCore/qflags.h>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QPlatformGraphicsBuffer : public QObject
+{
+Q_OBJECT
+public:
+ enum AccessType
+ {
+ None = 0x00,
+ SWReadAccess = 0x01,
+ SWWriteAccess = 0x02,
+ TextureAccess = 0x04,
+ HWCompositor = 0x08
+ };
+ Q_DECLARE_FLAGS(AccessTypes, AccessType);
+
+ enum Origin {
+ OriginBottomLeft,
+ OriginTopLeft
+ };
+
+ virtual ~QPlatformGraphicsBuffer();
+
+ AccessTypes isLocked() const { return m_lock_access; }
+ bool lock(AccessTypes access, const QRect &rect = QRect());
+ void unlock();
+
+ virtual bool bindToTexture(const QRect &rect = QRect()) const;
+
+ virtual const uchar *data() const;
+ virtual uchar *data();
+ virtual int bytesPerLine() const;
+ int byteCount() const;
+
+ virtual Origin origin() const;
+
+ QSize size() const { return m_size; }
+ QPixelFormat format() const { return m_format; }
+
+Q_SIGNALS:
+ void unlocked(AccessTypes previousAccessTypes);
+
+protected:
+ QPlatformGraphicsBuffer(const QSize &size, const QPixelFormat &format);
+
+ virtual bool doLock(AccessTypes access, const QRect &rect = QRect()) = 0;
+ virtual void doUnlock() = 0;
+
+private:
+ QSize m_size;
+ QPixelFormat m_format;
+ AccessTypes m_lock_access;
+};
+
+QT_END_NAMESPACE
+
+#endif //QPLATFORMGRAPHICSBUFFER_H
diff --git a/src/gui/kernel/qplatformgraphicsbufferhelper.cpp b/src/gui/kernel/qplatformgraphicsbufferhelper.cpp
new file mode 100644
index 0000000000..f3ea521356
--- /dev/null
+++ b/src/gui/kernel/qplatformgraphicsbufferhelper.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtPlatformSupport 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 <QtGui/qpa/qplatformgraphicsbuffer.h>
+
+#include "qplatformgraphicsbufferhelper.h"
+#include <QtCore/QDebug>
+#include <QtGui/qopengl.h>
+#include <QtGui/QImage>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Convenience function to both lock and bind the buffer to a texture. This
+ function will first try and lock with texture read and texture write
+ access. If this succeeds it will use the bindToTexture function to bind the
+ content to the currently bound texture. If this fail it will try and lock
+ with SWReadAccess and then use the bindSWToTexture convenience function.
+
+ \a swizzle is suppose to be used by the caller to figure out if the Red and
+ Blue color channels need to be swizzled when rendering.
+
+ \a rect is the subrect which is desired to be bounded to the texture. This
+ argument has a no less than semantic, meaning more (if not all) of the buffer
+ can be bounded to the texture. An empty QRect is interpreted as entire buffer
+ should be bound.
+
+ The user should use the AccessTypes returned by isLocked to figure out what
+ lock has been obtained.
+
+ returns true if the buffer has successfully been bound to the currently
+ bound texture, otherwise returns false.
+*/
+bool QPlatformGraphicsBufferHelper::lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer,
+ bool *swizzle,
+ const QRect &rect)
+{
+ if (graphicsBuffer->lock(QPlatformGraphicsBuffer::TextureAccess)) {
+ if (!graphicsBuffer->bindToTexture(rect)) {
+ qWarning() << Q_FUNC_INFO << "Failed to bind graphicsbuffer to texture";
+ return false;
+ }
+ if (swizzle)
+ *swizzle = false;
+ } else if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) {
+ if (!bindSWToTexture(graphicsBuffer, swizzle, rect)) {
+ qWarning() << Q_FUNC_INFO << "Failed to bind SW graphcisbuffer to texture";
+ return false;
+ }
+ } else {
+ qWarning() << Q_FUNC_INFO << "Failed to lock";
+ return false;
+ }
+ return true;
+}
+
+/*!
+ Convenience function that uploads the current raster content to the currently bound texture.
+
+ \a swizzleRandB is suppose to be used by the caller to figure out if the Red and
+ Blue color channels need to be swizzled when rendering. This is an
+ optimization. Qt often renders to software buffers interpreting pixels as
+ unsigned ints. When these buffers are uploaded to textures and each color
+ channel per pixel is interpreted as a byte (read sequentially), then the
+ Red and Blue channels are swapped. Conveniently the Alpha buffer will be
+ correct since Qt historically has had the alpha channel as the first
+ channel, while OpenGL typically expects the alpha channel to be the last
+ channel.
+
+ \a subRect is the subrect which is desired to be bounded to the texture. This
+ argument has a no less than semantic, meaning more (if not all) of the buffer
+ can be bounded to the texture. An empty QRect is interpreted as entire buffer
+ should be bound.
+
+ This function fails for buffers not capable of locking to SWAccess.
+
+ Returns true on success, otherwise false.
+*/
+bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer,
+ bool *swizzleRandB,
+ const QRect &subRect)
+{
+ if (!QOpenGLContext::currentContext())
+ return false;
+
+ if (!(graphicsBuffer->isLocked() & QPlatformGraphicsBuffer::SWReadAccess))
+ return false;
+
+ QSize size = graphicsBuffer->size();
+
+ Q_ASSERT(subRect.isEmpty() || QRect(QPoint(0,0), size).contains(subRect));
+
+ bool swizzle = false;
+ QImage::Format imageformat = QImage::toImageFormat(graphicsBuffer->format());
+ QImage image(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), imageformat);
+ if (graphicsBuffer->bytesPerLine() != (size.width() * 4)) {
+ image = image.convertToFormat(QImage::Format_RGBA8888);
+ } else if (imageformat == QImage::Format_RGB32) {
+ swizzle = true;
+ } else if (imageformat != QImage::Format_RGBA8888) {
+ image = image.convertToFormat(QImage::Format_RGBA8888);
+ }
+
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+
+ QRect rect = subRect;
+ if (rect.isNull() || rect == QRect(QPoint(0,0),size)) {
+ funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
+ } else {
+#ifndef QT_OPENGL_ES_2
+ if (!QOpenGLContext::currentContext()->isOpenGLES()) {
+ funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.width());
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+ image.constScanLine(rect.y()) + rect.x() * 4);
+ funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ } else
+#endif
+ {
+ // if the rect is wide enough it's cheaper to just
+ // extend it instead of doing an image copy
+ if (rect.width() >= size.width() / 2) {
+ rect.setX(0);
+ rect.setWidth(size.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() == size.width()) {
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+ image.constScanLine(rect.y()));
+ } else {
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+ image.copy(rect).constBits());
+ }
+ }
+ }
+ if (swizzleRandB)
+ *swizzleRandB = swizzle;
+
+ return true;
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformgraphicsbufferhelper.h b/src/gui/kernel/qplatformgraphicsbufferhelper.h
new file mode 100644
index 0000000000..089bbba755
--- /dev/null
+++ b/src/gui/kernel/qplatformgraphicsbufferhelper.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtPlatformSupport 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$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMGRAPHICSBUFFERHELPER_H
+#define QPLATFORMGRAPHICSBUFFERHELPER_H
+
+#include <QtGui/qpa/qplatformgraphicsbuffer.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QPlatformGraphicsBufferHelper {
+ bool lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB, const QRect &rect = QRect());
+ bool bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB = Q_NULLPTR, const QRect &rect = QRect());
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index 76269f6e65..0d550887d9 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -45,6 +45,8 @@
#ifndef QT_NO_OPENGL
#include <QtGui/private/qopengltextureblitter_p.h>
#endif
+#include <qpa/qplatformgraphicsbuffer.h>
+#include <qpa/qplatformgraphicsbufferhelper.h>
QT_BEGIN_NAMESPACE
@@ -69,7 +71,6 @@ public:
#endif
}
QWindow *window;
- QSize size;
#ifndef QT_NO_OPENGL
mutable GLuint textureId;
mutable QSize textureSize;
@@ -267,13 +268,50 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
// semi-transparency even when it is not wanted.
funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
- // Backingstore texture with the normal widgets.
- GLuint textureId = toTexture(deviceRegion(region, window), &d_ptr->textureSize, &d_ptr->needsSwizzle);
+ GLuint textureId = 0;
+ QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft;
+ if (QPlatformGraphicsBuffer *graphicsBuffer = this->graphicsBuffer()) {
+ if (graphicsBuffer->size() != d_ptr->textureSize) {
+ if (d_ptr->textureId)
+ funcs->glDeleteTextures(1, &d_ptr->textureId);
+ funcs->glGenTextures(1, &d_ptr->textureId);
+ funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
+#ifndef QT_OPENGL_ES_2
+ if (!QOpenGLContext::currentContext()->isOpenGLES()) {
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ }
+#endif
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ if (QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle)) {
+ d_ptr->textureSize = graphicsBuffer->size();
+ } else {
+ d_ptr->textureSize = QSize(0,0);
+ }
+
+ graphicsBuffer->unlock();
+ } else if (!region.isEmpty()){
+ funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
+ QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle);
+ }
+
+ if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
+ origin = QOpenGLTextureBlitter::OriginBottomLeft;
+ textureId = d_ptr->textureId;
+ } else {
+ // Backingstore texture with the normal widgets.
+ textureId = toTexture(deviceRegion(region, window), &d_ptr->textureSize, &d_ptr->needsSwizzle);
+ }
+
if (textureId) {
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(QRect(QPoint(), d_ptr->textureSize), windowRect);
if (d_ptr->needsSwizzle)
d_ptr->blitter->setSwizzleRB(true);
- d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
+ d_ptr->blitter->blit(textureId, target, origin);
if (d_ptr->needsSwizzle)
d_ptr->blitter->setSwizzleRB(false);
}
@@ -463,6 +501,14 @@ void QPlatformBackingStore::endPaint()
}
/*!
+ Accessor for a backingstores graphics buffer abstraction
+*/
+QPlatformGraphicsBuffer *QPlatformBackingStore::graphicsBuffer() const
+{
+ return Q_NULLPTR;
+}
+
+/*!
Scrolls the given \a area \a dx pixels to the right and \a dy
downward; both \a dx and \a dy may be negative.
diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h
index c69612ca44..e967e757e3 100644
--- a/src/gui/painting/qplatformbackingstore.h
+++ b/src/gui/painting/qplatformbackingstore.h
@@ -62,6 +62,7 @@ class QPlatformWindow;
class QPlatformTextureList;
class QPlatformTextureListPrivate;
class QOpenGLContext;
+class QPlatformGraphicsBuffer;
#ifndef QT_NO_OPENGL
class Q_GUI_EXPORT QPlatformTextureList : public QObject
@@ -116,6 +117,8 @@ public:
virtual GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, bool *needsSwizzle) const;
#endif
+ virtual QPlatformGraphicsBuffer *graphicsBuffer() const;
+
virtual void resize(const QSize &size, const QRegion &staticContents) = 0;
virtual bool scroll(const QRegion &area, int dx, int dy);
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 5c200b4058..74d73d7cdf 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -49,6 +49,7 @@
#include <qdebug.h>
#include <qpainter.h>
#include <qscreen.h>
+#include <qpa/qplatformgraphicsbuffer.h>
#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -60,6 +61,8 @@ public:
~QXcbShmImage() { destroy(); }
QImage *image() { return &m_qimage; }
+ QPlatformGraphicsBuffer *graphicsBuffer() { return m_graphics_buffer; }
+
QSize size() const { return m_qimage.size(); }
void put(xcb_window_t window, const QPoint &dst, const QRect &source);
@@ -73,6 +76,7 @@ private:
xcb_image_t *m_xcb_image;
QImage m_qimage;
+ QPlatformGraphicsBuffer *m_graphics_buffer;
xcb_gcontext_t m_gc;
xcb_window_t m_gc_window;
@@ -80,8 +84,39 @@ private:
QRegion m_dirty;
};
+class QXcbShmGraphicsBuffer : public QPlatformGraphicsBuffer
+{
+public:
+ QXcbShmGraphicsBuffer(QImage *image)
+ : QPlatformGraphicsBuffer(image->size(), QImage::toPixelFormat(image->format()))
+ , m_access_lock(QPlatformGraphicsBuffer::None)
+ , m_image(image)
+ { }
+
+ bool doLock(AccessTypes access, const QRect &rect) Q_DECL_OVERRIDE
+ {
+ Q_UNUSED(rect);
+ if (access & ~(QPlatformGraphicsBuffer::SWReadAccess | QPlatformGraphicsBuffer::SWWriteAccess))
+ return false;
+
+ m_access_lock |= access;
+ return true;
+ }
+ void doUnlock() Q_DECL_OVERRIDE { m_access_lock = None; }
+
+ const uchar *data() const Q_DECL_OVERRIDE { return m_image->bits(); }
+ uchar *data() Q_DECL_OVERRIDE { return m_image->bits(); }
+ int bytesPerLine() const Q_DECL_OVERRIDE { return m_image->bytesPerLine(); }
+
+ Origin origin() const Q_DECL_OVERRIDE { return QPlatformGraphicsBuffer::OriginTopLeft; }
+private:
+ AccessTypes m_access_lock;
+ QImage *m_image;
+};
+
QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format)
: QXcbObject(screen->connection())
+ , m_graphics_buffer(Q_NULLPTR)
, m_gc(0)
, m_gc_window(0)
{
@@ -137,6 +172,7 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI
}
m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format);
+ m_graphics_buffer = new QXcbShmGraphicsBuffer(&m_qimage);
}
void QXcbShmImage::destroy()
@@ -158,6 +194,8 @@ void QXcbShmImage::destroy()
if (m_gc)
Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc));
+ delete m_graphics_buffer;
+ m_graphics_buffer = Q_NULLPTR;
}
void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &source)
@@ -294,6 +332,11 @@ QImage QXcbBackingStore::toImage() const
}
#endif
+QPlatformGraphicsBuffer *QXcbBackingStore::graphicsBuffer() const
+{
+ return m_image ? m_image->graphicsBuffer() : Q_NULLPTR;
+}
+
void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
if (!m_image || m_image->size().isEmpty())
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h
index 3a7e124b3f..aa2c953983 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.h
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.h
@@ -58,6 +58,9 @@ public:
bool translucentBackground) Q_DECL_OVERRIDE;
QImage toImage() const Q_DECL_OVERRIDE;
#endif
+
+ QPlatformGraphicsBuffer *graphicsBuffer() const Q_DECL_OVERRIDE;
+
void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE;
bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE;