diff options
author | Jørgen Lind <jorgen.lind@digia.com> | 2014-08-14 15:47:55 +0200 |
---|---|---|
committer | Gunnar Sletta <gunnar@sletta.org> | 2015-01-17 08:03:34 +0100 |
commit | 37956e6605dd5d5a714607a7e04217d293d9c25f (patch) | |
tree | 90651bfa41d2885f3d876cca382522d3dfbe46ff | |
parent | 517fb9026896f7ac20376f253babae5a7c57721d (diff) |
Introducing QPlatformGraphicsBuffer
Change-Id: Idcf8f75bd151a877c7097b79df998c1ffd56871c
Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
-rw-r--r-- | src/gui/kernel/kernel.pri | 8 | ||||
-rw-r--r-- | src/gui/kernel/qplatformgraphicsbuffer.cpp | 277 | ||||
-rw-r--r-- | src/gui/kernel/qplatformgraphicsbuffer.h | 117 | ||||
-rw-r--r-- | src/gui/kernel/qplatformgraphicsbufferhelper.cpp | 185 | ||||
-rw-r--r-- | src/gui/kernel/qplatformgraphicsbufferhelper.h | 56 | ||||
-rw-r--r-- | src/gui/painting/qplatformbackingstore.cpp | 54 | ||||
-rw-r--r-- | src/gui/painting/qplatformbackingstore.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbbackingstore.cpp | 43 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbbackingstore.h | 3 |
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 ®i // 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 ®ion, 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; |