This is required to remove the ; from the macro with Qt 6. Task-number: QTBUG-82978 Change-Id: I3f0b6717956ca8fa486bed9817b89dfa19f5e0e1 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
267 lines
10 KiB
C++
267 lines
10 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** 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 The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU Lesser General Public License version 3 requirements
|
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 2.0 or (at your option) the GNU General
|
|
** Public license version 3 or any later version approved by the KDE Free
|
|
** Qt Foundation. The licenses are as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
|
** https://www.gnu.org/licenses/gpl-3.0.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>
|
|
|
|
#ifndef GL_UNPACK_ROW_LENGTH
|
|
#define GL_UNPACK_ROW_LENGTH 0x0CF2
|
|
#endif
|
|
|
|
#ifndef GL_RGB10_A2
|
|
#define GL_RGB10_A2 0x8059
|
|
#endif
|
|
|
|
#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
|
|
#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
|
|
#endif
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
/*!
|
|
\namespace QPlatformGraphicsBufferHelper
|
|
\inmodule QtGui
|
|
\internal
|
|
*/
|
|
|
|
/*!
|
|
Convenience function to both lock and bind the \a graphicsBuffer to a texture.
|
|
This function will first try to 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, and if \a premultiplied is provided,
|
|
it is set to false.
|
|
|
|
If it fails, it will try to lock with SWReadAccess and then use the
|
|
bindSWToTexture convenience function. If \a premultiplied is provided, it is
|
|
passed to the bindSWToTexture() function.
|
|
|
|
\a swizzle is meant 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 not 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, bool *premultiplied,
|
|
const QRect &rect)
|
|
{
|
|
if (graphicsBuffer->lock(QPlatformGraphicsBuffer::TextureAccess)) {
|
|
if (!graphicsBuffer->bindToTexture(rect)) {
|
|
qWarning("Failed to bind %sgraphicsbuffer to texture", "");
|
|
return false;
|
|
}
|
|
if (swizzle)
|
|
*swizzle = false;
|
|
if (premultiplied)
|
|
*premultiplied = false;
|
|
} else if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) {
|
|
if (!bindSWToTexture(graphicsBuffer, swizzle, premultiplied, rect)) {
|
|
qWarning("Failed to bind %sgraphicsbuffer to texture", "SW ");
|
|
return false;
|
|
}
|
|
} else {
|
|
qWarning("Failed to lock");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
Convenience function that uploads the current raster content to the currently
|
|
bound texture.
|
|
|
|
\a swizzleRandB is meant to be used by the caller to decide 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 region to be bound to the texture. This argument has a
|
|
not less than semantic, meaning more (if not all) of the buffer can be
|
|
bound to the texture. An empty QRect is interpreted as meaning the entire
|
|
buffer should be bound.
|
|
|
|
This function fails if the \a graphicsBuffer is not locked to SWAccess.
|
|
|
|
Returns true on success, otherwise false. If \a premultipliedB is
|
|
provided, it is set according to what happens, if the function returns
|
|
true.
|
|
*/
|
|
bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer,
|
|
bool *swizzleRandB, bool *premultipliedB,
|
|
const QRect &subRect)
|
|
{
|
|
#ifndef QT_NO_OPENGL
|
|
QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
|
if (!ctx)
|
|
return false;
|
|
|
|
if (!(graphicsBuffer->isLocked() & QPlatformGraphicsBuffer::SWReadAccess))
|
|
return false;
|
|
|
|
QSize size = graphicsBuffer->size();
|
|
|
|
Q_ASSERT(subRect.isEmpty() || QRect(QPoint(0,0), size).contains(subRect));
|
|
|
|
GLenum internalFormat = GL_RGBA;
|
|
GLuint pixelType = GL_UNSIGNED_BYTE;
|
|
|
|
bool needsConversion = false;
|
|
bool swizzle = false;
|
|
bool premultiplied = false;
|
|
QImage::Format imageformat = QImage::toImageFormat(graphicsBuffer->format());
|
|
QImage image(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), imageformat);
|
|
switch (imageformat) {
|
|
case QImage::Format_ARGB32_Premultiplied:
|
|
premultiplied = true;
|
|
Q_FALLTHROUGH();
|
|
case QImage::Format_RGB32:
|
|
case QImage::Format_ARGB32:
|
|
swizzle = true;
|
|
break;
|
|
case QImage::Format_RGBA8888_Premultiplied:
|
|
premultiplied = true;
|
|
Q_FALLTHROUGH();
|
|
case QImage::Format_RGBX8888:
|
|
case QImage::Format_RGBA8888:
|
|
break;
|
|
case QImage::Format_BGR30:
|
|
case QImage::Format_A2BGR30_Premultiplied:
|
|
if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
|
|
pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
|
|
internalFormat = GL_RGB10_A2;
|
|
premultiplied = true;
|
|
} else {
|
|
needsConversion = true;
|
|
}
|
|
break;
|
|
case QImage::Format_RGB30:
|
|
case QImage::Format_A2RGB30_Premultiplied:
|
|
if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
|
|
pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
|
|
internalFormat = GL_RGB10_A2;
|
|
premultiplied = true;
|
|
swizzle = true;
|
|
} else {
|
|
needsConversion = true;
|
|
}
|
|
break;
|
|
default:
|
|
needsConversion = true;
|
|
break;
|
|
}
|
|
if (!needsConversion && image.bytesPerLine() != (size.width() * 4) && ctx->isOpenGLES() && ctx->format().majorVersion() < 3)
|
|
needsConversion = true;
|
|
if (needsConversion)
|
|
image.convertTo(QImage::Format_RGBA8888);
|
|
|
|
bool needsRowLength = (image.bytesPerLine() != image.width() * 4);
|
|
QOpenGLFunctions *funcs = ctx->functions();
|
|
|
|
QRect rect = subRect;
|
|
if (rect.isNull() || rect == QRect(QPoint(0,0),size)) {
|
|
if (needsRowLength)
|
|
funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.bytesPerLine() / 4);
|
|
funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, size.width(), size.height(), 0, GL_RGBA, pixelType, image.constBits());
|
|
if (needsRowLength)
|
|
funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
} else {
|
|
if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
|
|
// OpenGL 2.1+ or OpenGL ES/3+
|
|
funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.bytesPerLine() / 4);
|
|
funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
|
|
image.constScanLine(rect.y()) + rect.x() * 4);
|
|
funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
} else
|
|
{
|
|
// 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() == image.bytesPerLine() / 4) {
|
|
funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
|
|
image.constScanLine(rect.y()));
|
|
} else {
|
|
funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
|
|
image.copy(rect).constBits());
|
|
}
|
|
}
|
|
}
|
|
if (swizzleRandB)
|
|
*swizzleRandB = swizzle;
|
|
if (premultipliedB)
|
|
*premultipliedB = premultiplied;
|
|
|
|
return true;
|
|
|
|
#else
|
|
Q_UNUSED(graphicsBuffer);
|
|
Q_UNUSED(swizzleRandB);
|
|
Q_UNUSED(premultipliedB);
|
|
Q_UNUSED(subRect);
|
|
return false;
|
|
#endif // QT_NO_OPENGL
|
|
}
|
|
|
|
QT_END_NAMESPACE
|