From 37956e6605dd5d5a714607a7e04217d293d9c25f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Thu, 14 Aug 2014 15:47:55 +0200 Subject: Introducing QPlatformGraphicsBuffer Change-Id: Idcf8f75bd151a877c7097b79df998c1ffd56871c Reviewed-by: Gunnar Sletta --- src/gui/kernel/qplatformgraphicsbufferhelper.cpp | 185 +++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/gui/kernel/qplatformgraphicsbufferhelper.cpp (limited to 'src/gui/kernel/qplatformgraphicsbufferhelper.cpp') 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 + +#include "qplatformgraphicsbufferhelper.h" +#include +#include +#include +#include +#include + +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 -- cgit v1.2.3