aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/util')
-rw-r--r--src/quick/scenegraph/util/qsgdefaultpainternode.cpp24
-rw-r--r--src/quick/scenegraph/util/qsgdefaultpainternode_p.h11
-rw-r--r--src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgengine.cpp25
-rw-r--r--src/quick/scenegraph/util/qsgengine.h2
-rw-r--r--src/quick/scenegraph/util/qsgflatcolormaterial.cpp55
-rw-r--r--src/quick/scenegraph/util/qsgopenglatlastexture.cpp (renamed from src/quick/scenegraph/util/qsgatlastexture.cpp)33
-rw-r--r--src/quick/scenegraph/util/qsgopenglatlastexture_p.h (renamed from src/quick/scenegraph/util/qsgatlastexture_p.h)10
-rw-r--r--src/quick/scenegraph/util/qsgplaintexture.cpp457
-rw-r--r--src/quick/scenegraph/util/qsgplaintexture_p.h (renamed from src/quick/scenegraph/util/qsgtexture_p.h)60
-rw-r--r--src/quick/scenegraph/util/qsgrhiatlastexture.cpp491
-rw-r--r--src/quick/scenegraph/util/qsgrhiatlastexture_p.h217
-rw-r--r--src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp104
-rw-r--r--src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h70
-rw-r--r--src/quick/scenegraph/util/qsgsimplematerial.cpp5
-rw-r--r--src/quick/scenegraph/util/qsgsimplerectnode.cpp8
-rw-r--r--src/quick/scenegraph/util/qsgsimpletexturenode.cpp8
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp851
-rw-r--r--src/quick/scenegraph/util/qsgtexture.h138
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp120
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial_p.h23
-rw-r--r--src/quick/scenegraph/util/qsgvertexcolormaterial.cpp54
22 files changed, 1675 insertions, 1095 deletions
diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
index 981ea089be..f15ea67b46 100644
--- a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
+++ b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
@@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE
#define QT_MINIMUM_DYNAMIC_FBO_SIZE 64U
QSGPainterTexture::QSGPainterTexture()
- : QSGPlainTexture()
+ : QSGPlainTexture(*(new QSGPainterTexturePrivate))
{
m_retain_image = true;
}
@@ -73,6 +73,16 @@ void QSGPainterTexture::bind()
m_dirty_rect = QRect();
}
+void QSGPainterTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates)
+{
+ Q_Q(QSGPainterTexture);
+ if (!q->m_dirty_rect.isNull()) {
+ q->setImage(q->m_image);
+ q->m_dirty_rect = QRect();
+ }
+ QSGPlainTexturePrivate::updateRhiTexture(rhi, resourceUpdates);
+}
+
QSGDefaultPainterNode::QSGDefaultPainterNode(QQuickPaintedItem *item)
: QSGPainterNode()
, m_preferredRenderTarget(QQuickPaintedItem::Image)
@@ -126,6 +136,7 @@ void QSGDefaultPainterNode::paint()
return;
painter.begin(&m_image);
} else {
+ Q_ASSERT(!m_context->rhi());
if (!m_gl_device) {
m_gl_device = new QOpenGLPaintDevice(m_fboSize);
m_gl_device->setPaintFlipped(true);
@@ -237,7 +248,7 @@ void QSGDefaultPainterNode::updateGeometry()
void QSGDefaultPainterNode::updateRenderTarget()
{
- if (!m_extensionsChecked) {
+ if (!m_extensionsChecked && !m_context->rhi()) {
QOpenGLExtensions *e = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());
m_multisamplingSupported = e->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
&& e->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
@@ -250,7 +261,10 @@ void QSGDefaultPainterNode::updateRenderTarget()
if (m_preferredRenderTarget == QQuickPaintedItem::Image) {
m_actualRenderTarget = QQuickPaintedItem::Image;
} else {
- if (!m_multisamplingSupported && m_smoothPainting)
+ // Image is the only option when there is no multisample framebuffer
+ // support and smooth painting is wanted, and when using the RHI. The
+ // latter may change in the future.
+ if ((!m_multisamplingSupported && m_smoothPainting) || m_context->rhi())
m_actualRenderTarget = QQuickPaintedItem::Image;
else
m_actualRenderTarget = m_preferredRenderTarget;
@@ -265,7 +279,9 @@ void QSGDefaultPainterNode::updateRenderTarget()
}
if (m_actualRenderTarget == QQuickPaintedItem::FramebufferObject ||
- m_actualRenderTarget == QQuickPaintedItem::InvertedYFramebufferObject) {
+ m_actualRenderTarget == QQuickPaintedItem::InvertedYFramebufferObject)
+ {
+ Q_ASSERT(!m_context->rhi());
const QOpenGLContext *ctx = m_context->openglContext();
if (m_fbo && !m_dirtyGeometry && (!ctx->format().samples() || !m_multisamplingSupported))
return;
diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode_p.h b/src/quick/scenegraph/util/qsgdefaultpainternode_p.h
index 084fc1e004..a86f7397be 100644
--- a/src/quick/scenegraph/util/qsgdefaultpainternode_p.h
+++ b/src/quick/scenegraph/util/qsgdefaultpainternode_p.h
@@ -53,7 +53,7 @@
#include <private/qsgadaptationlayer_p.h>
#include "qsgtexturematerial.h"
-#include "qsgtexture_p.h"
+#include "qsgplaintexture_p.h"
#include <QtQuick/qquickpainteditem.h>
@@ -64,9 +64,11 @@ QT_BEGIN_NAMESPACE
class QOpenGLFramebufferObject;
class QOpenGLPaintDevice;
class QSGDefaultRenderContext;
+class QSGPainterTexturePrivate;
class Q_QUICK_PRIVATE_EXPORT QSGPainterTexture : public QSGPlainTexture
{
+ Q_DECLARE_PRIVATE(QSGPainterTexture)
public:
QSGPainterTexture();
@@ -78,6 +80,13 @@ private:
QRect m_dirty_rect;
};
+class QSGPainterTexturePrivate : public QSGPlainTexturePrivate
+{
+ Q_DECLARE_PUBLIC(QSGPainterTexture)
+public:
+ void updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates) override;
+};
+
class Q_QUICK_PRIVATE_EXPORT QSGDefaultPainterNode : public QSGPainterNode
{
public:
diff --git a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
index 94912778f8..1154c06d7c 100644
--- a/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
+++ b/src/quick/scenegraph/util/qsgdepthstencilbuffer.cpp
@@ -183,7 +183,9 @@ void QSGDefaultDepthStencilBuffer::free()
QSGDepthStencilBufferManager::~QSGDepthStencilBufferManager()
{
for (Hash::const_iterator it = m_buffers.constBegin(), cend = m_buffers.constEnd(); it != cend; ++it) {
- QSGDepthStencilBuffer *buffer = it.value().data();
+ QSharedPointer<QSGDepthStencilBuffer> buffer = it.value().toStrongRef();
+ Q_ASSERT_X(buffer, "~QSGDepthStencilBufferManager",
+ "~QSGDepthStencilBuffer is supposed to unregister from the manager");
buffer->free();
buffer->m_manager = nullptr;
}
diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp
index 91fa46033c..4880d98871 100644
--- a/src/quick/scenegraph/util/qsgengine.cpp
+++ b/src/quick/scenegraph/util/qsgengine.cpp
@@ -42,7 +42,7 @@
#include <QtQuick/qsgtexture.h>
#include <private/qsgcontext_p.h>
#include <private/qsgrenderer_p.h>
-#include <private/qsgtexture_p.h>
+#include <private/qsgplaintexture_p.h>
#if QT_CONFIG(opengl)
# include <QtGui/QOpenGLContext>
@@ -69,6 +69,10 @@ QT_BEGIN_NAMESPACE
Most of the time you will instead want to subclass QQuickItem and insert
your QSGNode in a normal QtQuick scene by overriding QQuickItem::updatePaintNode().
+ \warning This class is only suitable when working directly with OpenGL. It
+ is not compatible with the \l{Scene Graph Adaptations}{RHI-based rendering
+ path}.
+
\sa QSGAbstractRenderer
*/
@@ -126,12 +130,29 @@ void QSGEngine::initialize(QOpenGLContext *context)
#endif
if (d->sgRenderContext && !d->sgRenderContext->isValid()) {
d->sgRenderContext->setAttachToGraphicsContext(false);
- d->sgRenderContext->initialize(context);
+#if QT_CONFIG(opengl)
+ QSGDefaultRenderContext *rc = qobject_cast<QSGDefaultRenderContext *>(d->sgRenderContext.data());
+ if (rc) {
+ QSGDefaultRenderContext::InitParams params;
+ params.sampleCount = qMax(1, context->format().samples());
+ params.openGLContext = context;
+ // leave the size hint and surface unset, we do not know, that's fine
+ rc->initialize(&params);
+ } else {
+ d->sgRenderContext->initialize(nullptr);
+ }
+#else
+ d->sgRenderContext->initialize(nullptr);
+#endif
#if QT_CONFIG(opengl)
if (context)
connect(context, &QOpenGLContext::aboutToBeDestroyed, this, &QSGEngine::invalidate);
#endif
}
+
+#if !QT_CONFIG(opengl)
+ Q_UNUSED(context);
+#endif
}
/*!
diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h
index e48b7784ae..c5a59b47e7 100644
--- a/src/quick/scenegraph/util/qsgengine.h
+++ b/src/quick/scenegraph/util/qsgengine.h
@@ -54,6 +54,8 @@ class QSGRectangleNode;
class QSGImageNode;
class QSGNinePatchNode;
+// ### Qt 6: Remove or redesign.
+
class Q_QUICK_EXPORT QSGEngine : public QObject
{
Q_OBJECT
diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
index 28f6113a60..87941bf31a 100644
--- a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
@@ -116,6 +116,51 @@ void FlatColorMaterialShader::initialize()
}
+class FlatColorMaterialRhiShader : public QSGMaterialRhiShader
+{
+public:
+ FlatColorMaterialRhiShader();
+
+ bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
+};
+
+FlatColorMaterialRhiShader::FlatColorMaterialRhiShader()
+{
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/flatcolor.vert.qsb"));
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/flatcolor.frag.qsb"));
+}
+
+bool FlatColorMaterialRhiShader::updateUniformData(RenderState &state,
+ QSGMaterial *newMaterial,
+ QSGMaterial *oldMaterial)
+{
+ Q_ASSERT(!oldMaterial || newMaterial->type() == oldMaterial->type());
+ QSGFlatColorMaterial *oldMat = static_cast<QSGFlatColorMaterial *>(oldMaterial);
+ QSGFlatColorMaterial *mat = static_cast<QSGFlatColorMaterial *>(newMaterial);
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+
+ if (state.isMatrixDirty()) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ changed = true;
+ }
+
+ const QColor &c = mat->color();
+ if (!oldMat || c != oldMat->color() || state.isOpacityDirty()) {
+ const float opacity = state.opacity() * c.alphaF();
+ QVector4D v(c.redF() * opacity,
+ c.greenF() * opacity,
+ c.blueF() * opacity,
+ opacity);
+ Q_ASSERT(sizeof(v) == 16);
+ memcpy(buf->data() + 64, &v, 16);
+ changed = true;
+ }
+
+ return changed;
+}
+
/*!
\class QSGFlatColorMaterial
@@ -126,7 +171,7 @@ void FlatColorMaterialShader::initialize()
\inmodule QtQuick
\ingroup qtquick-scenegraph-materials
- \warning This utility class is only functional when running with the OpenGL
+ \warning This utility class is only functional when running with the default
backend of the Qt Quick scenegraph.
The flat color material will fill every pixel in a geometry using
@@ -150,10 +195,9 @@ void FlatColorMaterialShader::initialize()
QSGFlatColorMaterial::QSGFlatColorMaterial() : m_color(QColor(255, 255, 255))
{
+ setFlag(SupportsRhiShader, true);
}
-
-
/*!
\fn const QColor &QSGFlatColorMaterial::color() const
@@ -193,7 +237,10 @@ QSGMaterialType *QSGFlatColorMaterial::type() const
QSGMaterialShader *QSGFlatColorMaterial::createShader() const
{
- return new FlatColorMaterialShader;
+ if (flags().testFlag(RhiShaderWanted))
+ return new FlatColorMaterialRhiShader;
+ else
+ return new FlatColorMaterialShader;
}
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgopenglatlastexture.cpp
index 921ed0c1fc..75a874424a 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgopenglatlastexture.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "qsgatlastexture_p.h"
+#include "qsgopenglatlastexture_p.h"
#include <QtCore/QVarLengthArray>
#include <QtCore/QElapsedTimer>
@@ -71,24 +71,22 @@ static QElapsedTimer qsg_renderer_timer;
DEFINE_BOOL_CONFIG_OPTION(qsgEnableCompressedAtlas, QSG_ENABLE_COMPRESSED_ATLAS)
-namespace QSGAtlasTexture
+namespace QSGOpenGLAtlasTexture
{
-Manager::Manager()
+Manager::Manager(const QSize &surfacePixelSize)
: m_atlas(nullptr)
{
QOpenGLContext *gl = QOpenGLContext::currentContext();
Q_ASSERT(gl);
- QSurface *surface = gl->surface();
- QSize surfaceSize = surface->size();
int max;
gl->functions()->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
- int w = qMin(max, qt_sg_envInt("QSG_ATLAS_WIDTH", qMax(512U, qNextPowerOfTwo(surfaceSize.width() - 1))));
- int h = qMin(max, qt_sg_envInt("QSG_ATLAS_HEIGHT", qMax(512U, qNextPowerOfTwo(surfaceSize.height() - 1))));
+ int w = qMin(max, qt_sg_envInt("QSG_ATLAS_WIDTH", qMax(512U, qNextPowerOfTwo(surfacePixelSize.width() - 1))));
+ int h = qMin(max, qt_sg_envInt("QSG_ATLAS_HEIGHT", qMax(512U, qNextPowerOfTwo(surfacePixelSize.height() - 1))));
- if (surface->surfaceClass() == QSurface::Window) {
- QWindow *window = static_cast<QWindow *>(surface);
+ if (gl->surface()->surfaceClass() == QSurface::Window) {
+ QWindow *window = static_cast<QWindow *>(gl->surface());
// Coverwindows, optimize for memory rather than speed
if ((window->type() & Qt::CoverWindow) == Qt::CoverWindow) {
w /= 2;
@@ -99,10 +97,9 @@ Manager::Manager()
m_atlas_size_limit = qt_sg_envInt("QSG_ATLAS_SIZE_LIMIT", qMax(w, h) / 2);
m_atlas_size = QSize(w, h);
- qCDebug(QSG_LOG_INFO, "texture atlas dimensions: %dx%d", w, h);
+ qCDebug(QSG_LOG_INFO, "opengl texture atlas dimensions: %dx%d", w, h);
}
-
Manager::~Manager()
{
Q_ASSERT(m_atlas == nullptr);
@@ -153,6 +150,10 @@ QSGTexture *Manager::create(const QSGCompressedTextureFactory *factory)
case QOpenGLTexture::RGB8_ETC2:
case QOpenGLTexture::RGBA8_ETC2_EAC:
case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2:
+ case QOpenGLTexture::RGB_DXT1:
+ case QOpenGLTexture::RGBA_DXT1:
+ case QOpenGLTexture::RGBA_DXT3:
+ case QOpenGLTexture::RGBA_DXT5:
break;
default:
return t;
@@ -161,8 +162,12 @@ QSGTexture *Manager::create(const QSGCompressedTextureFactory *factory)
QSize size = factory->m_textureData.size();
if (size.width() < m_atlas_size_limit && size.height() < m_atlas_size_limit) {
QHash<unsigned int, QSGCompressedAtlasTexture::Atlas*>::iterator i = m_atlases.find(format);
- if (i == m_atlases.end())
- i = m_atlases.insert(format, new QSGCompressedAtlasTexture::Atlas(m_atlas_size, format));
+ if (i == m_atlases.end()) {
+ // must be multiple of 4
+ QSize paddedSize(((m_atlas_size.width() + 3) / 4) * 4, ((m_atlas_size.height() + 3) / 4) * 4);
+ i = m_atlases.insert(format, new QSGCompressedAtlasTexture::Atlas(paddedSize, format));
+ }
+
// must be multiple of 4
QSize paddedSize(((size.width() + 3) / 4) * 4, ((size.height() + 3) / 4) * 4);
QByteArray data = factory->m_textureData.data();
@@ -593,4 +598,4 @@ QSGTexture *Texture::removedFromAtlas() const
QT_END_NAMESPACE
-#include "moc_qsgatlastexture_p.cpp"
+#include "moc_qsgopenglatlastexture_p.cpp"
diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgopenglatlastexture_p.h
index 14dc8f7958..f8dd7cdf02 100644
--- a/src/quick/scenegraph/util/qsgatlastexture_p.h
+++ b/src/quick/scenegraph/util/qsgopenglatlastexture_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QSGATLASTEXTURE_P_H
-#define QSGATLASTEXTURE_P_H
+#ifndef QSGOPENGLATLASTEXTURE_P_H
+#define QSGOPENGLATLASTEXTURE_P_H
//
// W A R N I N G
@@ -56,7 +56,7 @@
#include <QtGui/qopengl.h>
#include <QtQuick/QSGTexture>
-#include <QtQuick/private/qsgtexture_p.h>
+#include <QtQuick/private/qsgplaintexture_p.h>
#include <QtQuick/private/qsgareaallocator_p.h>
QT_BEGIN_NAMESPACE
@@ -66,7 +66,7 @@ namespace QSGCompressedAtlasTexture {
}
class QSGCompressedTextureFactory;
-namespace QSGAtlasTexture
+namespace QSGOpenGLAtlasTexture
{
class Texture;
@@ -78,7 +78,7 @@ class Manager : public QObject
Q_OBJECT
public:
- Manager();
+ Manager(const QSize &surfacePixelSize);
~Manager();
QSGTexture *create(const QImage &image, bool hasAlphaChannel);
diff --git a/src/quick/scenegraph/util/qsgplaintexture.cpp b/src/quick/scenegraph/util/qsgplaintexture.cpp
new file mode 100644
index 0000000000..fdebe03494
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgplaintexture.cpp
@@ -0,0 +1,457 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick 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 "qsgplaintexture_p.h"
+#include "qsgrhinativetextureimporter_p.h"
+#include <QtQuick/private/qsgcontext_p.h>
+#include <qmath.h>
+#include <private/qquickprofiler_p.h>
+#include <private/qqmlglobal_p.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#if QT_CONFIG(opengl)
+# include <QtGui/qopenglcontext.h>
+# include <QtGui/qopenglfunctions.h>
+# include <QtGui/private/qopengltextureuploader_p.h>
+# include <private/qsgdefaultrendercontext_p.h>
+#endif
+#include <QtGui/private/qrhi_p.h>
+
+#if QT_CONFIG(opengl)
+static QElapsedTimer qsg_renderer_timer;
+#endif
+
+#ifndef GL_BGRA
+#define GL_BGRA 0x80E1
+#endif
+
+#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QSGPlainTexture::QSGPlainTexture()
+ : QSGTexture(*(new QSGPlainTexturePrivate))
+ , m_texture_id(0)
+ , m_texture(nullptr)
+ , m_has_alpha(false)
+ , m_dirty_texture(false)
+ , m_dirty_bind_options(false)
+ , m_owns_texture(true)
+ , m_mipmaps_generated(false)
+ , m_retain_image(false)
+ , m_mipmap_warned(false)
+{
+}
+
+QSGPlainTexture::QSGPlainTexture(QSGPlainTexturePrivate &dd)
+ : QSGTexture(dd)
+ , m_texture_id(0)
+ , m_texture(nullptr)
+ , m_has_alpha(false)
+ , m_dirty_texture(false)
+ , m_dirty_bind_options(false)
+ , m_owns_texture(true)
+ , m_mipmaps_generated(false)
+ , m_retain_image(false)
+ , m_mipmap_warned(false)
+{
+}
+
+QSGPlainTexture::~QSGPlainTexture()
+{
+#if QT_CONFIG(opengl)
+ if (m_texture_id && m_owns_texture && QOpenGLContext::currentContext())
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
+#endif
+ if (m_texture && m_owns_texture)
+ delete m_texture;
+}
+
+void QSGPlainTexture::setImage(const QImage &image)
+{
+ m_image = image;
+ m_texture_size = image.size();
+ m_has_alpha = image.hasAlphaChannel();
+ m_dirty_texture = true;
+ m_dirty_bind_options = true;
+ m_mipmaps_generated = false;
+ }
+
+int QSGPlainTexture::textureId() const // legacy (GL-only)
+{
+ if (m_dirty_texture) {
+ if (m_image.isNull()) {
+ // The actual texture and id will be updated/deleted in a later bind()
+ // or ~QSGPlainTexture so just keep it minimal here.
+ return 0;
+ } else if (m_texture_id == 0){
+#if QT_CONFIG(opengl)
+ // Generate a texture id for use later and return it.
+ QOpenGLContext::currentContext()->functions()->glGenTextures(1, &const_cast<QSGPlainTexture *>(this)->m_texture_id);
+#endif
+ return m_texture_id;
+ }
+ }
+ return m_texture_id;
+}
+
+void QSGPlainTexture::setTextureId(int id) // legacy (GL-only)
+{
+#if QT_CONFIG(opengl)
+ if (m_texture_id && m_owns_texture)
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
+#endif
+
+ m_texture_id = id;
+ m_dirty_texture = false;
+ m_dirty_bind_options = true;
+ m_image = QImage();
+ m_mipmaps_generated = false;
+}
+
+void QSGPlainTexture::bind() // legacy (GL-only)
+{
+#if QT_CONFIG(opengl)
+ QOpenGLContext *context = QOpenGLContext::currentContext();
+ QOpenGLFunctions *funcs = context->functions();
+ if (!m_dirty_texture) {
+ funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
+ if (mipmapFiltering() != QSGTexture::None && !m_mipmaps_generated) {
+ funcs->glGenerateMipmap(GL_TEXTURE_2D);
+ m_mipmaps_generated = true;
+ }
+ updateBindOptions(m_dirty_bind_options);
+ m_dirty_bind_options = false;
+ return;
+ }
+
+ m_dirty_texture = false;
+
+ bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled();
+ if (profileFrames)
+ qsg_renderer_timer.start();
+ Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(QQuickProfiler::SceneGraphTexturePrepare,
+ QQuickProfiler::SceneGraphTextureDeletion);
+
+
+ if (m_image.isNull()) {
+ if (m_texture_id && m_owns_texture) {
+ funcs->glDeleteTextures(1, &m_texture_id);
+ qCDebug(QSG_LOG_TIME_TEXTURE, "plain texture deleted in %dms - %dx%d",
+ (int) qsg_renderer_timer.elapsed(),
+ m_texture_size.width(),
+ m_texture_size.height());
+ Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphTextureDeletion,
+ QQuickProfiler::SceneGraphTextureDeletionDelete);
+ }
+ m_texture_id = 0;
+ m_texture_size = QSize();
+ m_has_alpha = false;
+
+ return;
+ }
+
+ if (m_texture_id == 0)
+ funcs->glGenTextures(1, &m_texture_id);
+ funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
+
+ qint64 bindTime = 0;
+ if (profileFrames)
+ bindTime = qsg_renderer_timer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare,
+ QQuickProfiler::SceneGraphTexturePrepareBind);
+
+ // ### TODO: check for out-of-memory situations...
+
+ QOpenGLTextureUploader::BindOptions options = QOpenGLTextureUploader::PremultipliedAlphaBindOption;
+
+ // Downscale the texture to fit inside the max texture limit if it is too big.
+ // It would be better if the image was already downscaled to the right size,
+ // but this information is not always available at that time, so as a last
+ // resort we can do it here. Texture coordinates are normalized, so it
+ // won't cause any problems and actual texture sizes will be written
+ // based on QSGTexture::textureSize which is updated after this, so that
+ // should be ok.
+ int max;
+ if (auto rc = QSGDefaultRenderContext::from(context))
+ max = rc->maxTextureSize();
+ else
+ funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
+
+ m_texture_size = m_texture_size.boundedTo(QSize(max, max));
+
+ // Scale to a power of two size if mipmapping is requested and the
+ // texture is npot and npot textures are not properly supported.
+ if (mipmapFiltering() != QSGTexture::None
+ && !funcs->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures)) {
+ options |= QOpenGLTextureUploader::PowerOfTwoBindOption;
+ }
+
+ updateBindOptions(m_dirty_bind_options);
+
+ QOpenGLTextureUploader::textureImage(GL_TEXTURE_2D, m_image, options, QSize(max, max));
+
+ qint64 uploadTime = 0;
+ if (profileFrames)
+ uploadTime = qsg_renderer_timer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare,
+ QQuickProfiler::SceneGraphTexturePrepareUpload);
+
+ if (mipmapFiltering() != QSGTexture::None) {
+ funcs->glGenerateMipmap(GL_TEXTURE_2D);
+ m_mipmaps_generated = true;
+ }
+
+ qint64 mipmapTime = 0;
+ if (profileFrames) {
+ mipmapTime = qsg_renderer_timer.nsecsElapsed();
+ qCDebug(QSG_LOG_TIME_TEXTURE,
+ "plain texture uploaded in: %dms (%dx%d), bind=%d, upload=%d, mipmap=%d%s",
+ int(mipmapTime / 1000000),
+ m_texture_size.width(), m_texture_size.height(),
+ int(bindTime / 1000000),
+ int((uploadTime - bindTime)/1000000),
+ int((mipmapTime - uploadTime)/1000000),
+ m_texture_size != m_image.size() ? " (scaled to GL_MAX_TEXTURE_SIZE)" : "");
+ }
+ Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphTexturePrepare,
+ QQuickProfiler::SceneGraphTexturePrepareMipmap);
+
+ m_texture_rect = QRectF(0, 0, 1, 1);
+
+ m_dirty_bind_options = false;
+ if (!m_retain_image)
+ m_image = QImage();
+#endif
+}
+
+void QSGPlainTexture::setTexture(QRhiTexture *texture) // RHI only
+{
+ if (m_texture && m_owns_texture && m_texture != texture)
+ delete m_texture;
+
+ m_texture = texture;
+ m_dirty_texture = false;
+ m_dirty_bind_options = true;
+ m_image = QImage();
+ m_mipmaps_generated = false;
+}
+
+void QSGPlainTexture::setTextureFromNativeObject(QRhi *rhi, QQuickWindow::NativeObjectType type,
+ const void *nativeObjectPtr, int nativeLayout,
+ const QSize &size, bool mipmap)
+{
+ Q_UNUSED(type);
+
+ QRhiTexture::Flags flags = 0;
+ if (mipmap)
+ flags |= QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips;
+
+ QRhiTexture *t = rhi->newTexture(QRhiTexture::RGBA8, size, 1, flags);
+
+ // ownership of the native object is never taken
+ QSGRhiNativeTextureImporter::buildWrapper(rhi, t, nativeObjectPtr, nativeLayout);
+
+ setTexture(t);
+}
+
+int QSGPlainTexturePrivate::comparisonKey() const
+{
+ Q_Q(const QSGPlainTexture);
+
+ // not textureId() as that would create an id when not yet done - that's not wanted here
+ if (q->m_texture_id)
+ return q->m_texture_id;
+
+ if (q->m_texture)
+ return int(qintptr(q->m_texture));
+
+ // two textures (and so materials) with not-yet-created texture underneath are never equal
+ return int(qintptr(q));
+}
+
+QRhiTexture *QSGPlainTexturePrivate::rhiTexture() const
+{
+ Q_Q(const QSGPlainTexture);
+ return q->m_texture;
+}
+
+void QSGPlainTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates)
+{
+ Q_Q(QSGPlainTexture);
+
+ const bool hasMipMaps = q->mipmapFiltering() != QSGTexture::None;
+ const bool mipmappingChanged = q->m_texture && ((hasMipMaps && !q->m_texture->flags().testFlag(QRhiTexture::MipMapped)) // did not have it before
+ || (!hasMipMaps && q->m_texture->flags().testFlag(QRhiTexture::MipMapped))); // does not have it anymore
+
+ if (!q->m_dirty_texture) {
+ if (!q->m_texture)
+ return;
+ if (q->m_texture && !mipmappingChanged) {
+ if (hasMipMaps && !q->m_mipmaps_generated) {
+ resourceUpdates->generateMips(q->m_texture);
+ q->m_mipmaps_generated = true;
+ }
+ return;
+ }
+ }
+
+ if (q->m_image.isNull()) {
+ if (!q->m_dirty_texture && mipmappingChanged) {
+ // Full Mipmap Panic!
+ if (!q->m_mipmap_warned) {
+ qWarning("QSGPlainTexture: Mipmap settings changed without having image data available. "
+ "Call setImage() again or enable m_retain_image. "
+ "Falling back to previous mipmap filtering mode.");
+ q->m_mipmap_warned = true;
+ }
+ // leave the texture valid and rather ignore the mipmap mode change attempt
+ q->setMipmapFiltering(m_last_mipmap_filter);
+ return;
+ }
+
+ if (q->m_texture && q->m_owns_texture)
+ delete q->m_texture;
+
+ q->m_texture = nullptr;
+ q->m_texture_size = QSize();
+ q->m_has_alpha = false;
+
+ q->m_dirty_texture = false;
+ return;
+ }
+
+ q->m_dirty_texture = false;
+
+ QImage tmp;
+ bool bgra = false;
+ bool needsConvert = false;
+ if (q->m_image.format() == QImage::Format_RGB32 || q->m_image.format() == QImage::Format_ARGB32_Premultiplied) {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ if (rhi->isTextureFormatSupported(QRhiTexture::BGRA8)) {
+ tmp = q->m_image;
+ bgra = true;
+ } else {
+ needsConvert = true;
+ }
+#else
+ needsConvert = true;
+#endif
+ } else if (q->m_image.format() == QImage::Format_RGBX8888 || q->m_image.format() == QImage::Format_RGBA8888_Premultiplied) {
+ tmp = q->m_image;
+ } else {
+ needsConvert = true;
+ }
+
+ if (needsConvert)
+ tmp = q->m_image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
+
+ // Downscale the texture to fit inside the max texture limit if it is too big.
+ // It would be better if the image was already downscaled to the right size,
+ // but this information is not always available at that time, so as a last
+ // resort we can do it here. Texture coordinates are normalized, so it
+ // won't cause any problems and actual texture sizes will be written
+ // based on QSGTexture::textureSize which is updated after this, so that
+ // should be ok.
+ const int max = rhi->resourceLimit(QRhi::TextureSizeMax);
+ if (tmp.width() > max || tmp.height() > max) {
+ tmp = tmp.scaled(qMin(max, tmp.width()), qMin(max, tmp.height()), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ q->m_texture_size = tmp.size();
+ }
+
+ if ((q->mipmapFiltering() != QSGTexture::None
+ || q->horizontalWrapMode() != QSGTexture::ClampToEdge
+ || q->verticalWrapMode() != QSGTexture::ClampToEdge)
+ && !rhi->isFeatureSupported(QRhi::NPOTTextureRepeat))
+ {
+ const int w = qNextPowerOfTwo(tmp.width() - 1);
+ const int h = qNextPowerOfTwo(tmp.height() - 1);
+ if (tmp.width() != w || tmp.height() != h) {
+ tmp = tmp.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ q->m_texture_size = tmp.size();
+ }
+ }
+
+ bool needsRebuild = q->m_texture && q->m_texture->pixelSize() != q->m_texture_size;
+
+ if (mipmappingChanged) {
+ QRhiTexture::Flags f = q->m_texture->flags();
+ f.setFlag(QRhiTexture::MipMapped, hasMipMaps);
+ f.setFlag(QRhiTexture::UsedWithGenerateMips, hasMipMaps);
+ q->m_texture->setFlags(f);
+ needsRebuild = true;
+ }
+
+ if (!q->m_texture) {
+ QRhiTexture::Flags f = 0;
+ if (hasMipMaps)
+ f |= QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips;
+
+ q->m_texture = rhi->newTexture(bgra ? QRhiTexture::BGRA8 : QRhiTexture::RGBA8, q->m_texture_size, 1, f);
+ needsRebuild = true;
+ }
+
+ if (needsRebuild) {
+ if (!q->m_texture->build()) {
+ qWarning("Failed to build texture for QSGPlainTexture (size %dx%d)",
+ q->m_texture_size.width(), q->m_texture_size.height());
+ return;
+ }
+ }
+
+ if (tmp.width() * 4 != tmp.bytesPerLine())
+ tmp = tmp.copy();
+
+ resourceUpdates->uploadTexture(q->m_texture, tmp);
+
+ if (hasMipMaps) {
+ resourceUpdates->generateMips(q->m_texture);
+ q->m_mipmaps_generated = true;
+ }
+
+ m_last_mipmap_filter = q->mipmapFiltering();
+ q->m_texture_rect = QRectF(0, 0, 1, 1);
+
+ if (!q->m_retain_image)
+ q->m_image = QImage();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgplaintexture_p.h
index 18dd5eff68..1eb0b59d2e 100644
--- a/src/quick/scenegraph/util/qsgtexture_p.h
+++ b/src/quick/scenegraph/util/qsgplaintexture_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QSGTEXTURE_P_H
-#define QSGTEXTURE_P_H
+#ifndef QSGPLAINTEXTURE_P_H
+#define QSGPLAINTEXTURE_P_H
//
// W A R N I N G
@@ -51,36 +51,18 @@
// We mean it.
//
-#include <QtQuick/qtquickglobal.h>
-#include <private/qobject_p.h>
-#if QT_CONFIG(opengl)
-# include <QtGui/qopengl.h>
-#endif
-#include "qsgtexture.h"
-#include <QtQuick/private/qsgcontext_p.h>
+#include <QtQuick/private/qtquickglobal_p.h>
+#include <QtQuick/private/qsgtexture_p.h>
+#include <QtQuick/qquickwindow.h>
QT_BEGIN_NAMESPACE
-class QSGTexturePrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QSGTexture)
-public:
- QSGTexturePrivate();
-
- uint wrapChanged : 1;
- uint filteringChanged : 1;
- uint anisotropyChanged : 1;
-
- uint horizontalWrap : 2;
- uint verticalWrap : 2;
- uint mipmapMode : 2;
- uint filterMode : 2;
- uint anisotropyLevel: 3;
-};
+class QSGPlainTexturePrivate;
class Q_QUICK_PRIVATE_EXPORT QSGPlainTexture : public QSGTexture
{
Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGPlainTexture)
public:
QSGPlainTexture();
~QSGPlainTexture() override;
@@ -103,6 +85,11 @@ public:
void bind() override;
+ void setTexture(QRhiTexture *texture);
+ void setTextureFromNativeObject(QRhi *rhi, QQuickWindow::NativeObjectType type,
+ const void *nativeObjectPtr, int nativeLayout,
+ const QSize &size, bool mipmap);
+
static QSGPlainTexture *fromImage(const QImage &image) {
QSGPlainTexture *t = new QSGPlainTexture();
t->setImage(image);
@@ -110,22 +97,35 @@ public:
}
protected:
+ QSGPlainTexture(QSGPlainTexturePrivate &dd);
+
QImage m_image;
uint m_texture_id;
QSize m_texture_size;
QRectF m_texture_rect;
+ QRhiTexture *m_texture;
uint m_has_alpha : 1;
uint m_dirty_texture : 1;
- uint m_dirty_bind_options : 1;
+ uint m_dirty_bind_options : 1; // legacy (GL-only)
uint m_owns_texture : 1;
uint m_mipmaps_generated : 1;
- uint m_retain_image: 1;
+ uint m_retain_image : 1;
+ uint m_mipmap_warned : 1; // RHI only
};
-Q_QUICK_PRIVATE_EXPORT bool qsg_safeguard_texture(QSGTexture *);
+class QSGPlainTexturePrivate : public QSGTexturePrivate
+{
+ Q_DECLARE_PUBLIC(QSGPlainTexture)
+public:
+ int comparisonKey() const override;
+ QRhiTexture *rhiTexture() const override;
+ void updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ QSGTexture::Filtering m_last_mipmap_filter = QSGTexture::None;
+};
QT_END_NAMESPACE
-#endif // QSGTEXTURE_P_H
+#endif // QSGPLAINTEXTURE_P_H
diff --git a/src/quick/scenegraph/util/qsgrhiatlastexture.cpp b/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
new file mode 100644
index 0000000000..3dc1f5f526
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
@@ -0,0 +1,491 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick 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 "qsgrhiatlastexture_p.h"
+
+#include <QtCore/QVarLengthArray>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QtMath>
+
+#include <QtGui/QWindow>
+
+#include <private/qqmlglobal_p.h>
+#include <private/qquickprofiler_p.h>
+#include <private/qsgdefaultrendercontext_p.h>
+#include <private/qsgtexture_p.h>
+#if 0
+#include <private/qsgcompressedtexture_p.h>
+#include <private/qsgcompressedatlastexture_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+int qt_sg_envInt(const char *name, int defaultValue);
+
+static QElapsedTimer qsg_renderer_timer;
+
+//DEFINE_BOOL_CONFIG_OPTION(qsgEnableCompressedAtlas, QSG_ENABLE_COMPRESSED_ATLAS)
+
+namespace QSGRhiAtlasTexture
+{
+
+Manager::Manager(QSGDefaultRenderContext *rc, const QSize &surfacePixelSize, QSurface *maybeSurface)
+ : m_rc(rc)
+ , m_rhi(rc->rhi())
+{
+ const int maxSize = m_rhi->resourceLimit(QRhi::TextureSizeMax);
+ int w = qMin(maxSize, qt_sg_envInt("QSG_ATLAS_WIDTH", qMax(512U, qNextPowerOfTwo(surfacePixelSize.width() - 1))));
+ int h = qMin(maxSize, qt_sg_envInt("QSG_ATLAS_HEIGHT", qMax(512U, qNextPowerOfTwo(surfacePixelSize.height() - 1))));
+
+ if (maybeSurface && maybeSurface->surfaceClass() == QSurface::Window) {
+ QWindow *window = static_cast<QWindow *>(maybeSurface);
+ // Coverwindows, optimize for memory rather than speed
+ if ((window->type() & Qt::CoverWindow) == Qt::CoverWindow) {
+ w /= 2;
+ h /= 2;
+ }
+ }
+
+ m_atlas_size_limit = qt_sg_envInt("QSG_ATLAS_SIZE_LIMIT", qMax(w, h) / 2);
+ m_atlas_size = QSize(w, h);
+
+ qCDebug(QSG_LOG_INFO, "rhi texture atlas dimensions: %dx%d", w, h);
+}
+
+Manager::~Manager()
+{
+ Q_ASSERT(m_atlas == nullptr);
+ Q_ASSERT(m_atlases.isEmpty());
+}
+
+void Manager::invalidate()
+{
+ if (m_atlas) {
+ m_atlas->invalidate();
+ m_atlas->deleteLater();
+ m_atlas = nullptr;
+ }
+
+ #if 0
+ QHash<unsigned int, QSGCompressedAtlasTexture::Atlas*>::iterator i = m_atlases.begin();
+ while (i != m_atlases.end()) {
+ i.value()->invalidate();
+ i.value()->deleteLater();
+ ++i;
+ }
+ m_atlases.clear();
+#endif
+}
+
+QSGTexture *Manager::create(const QImage &image, bool hasAlphaChannel)
+{
+ Texture *t = nullptr;
+ if (image.width() < m_atlas_size_limit && image.height() < m_atlas_size_limit) {
+ if (!m_atlas)
+ m_atlas = new Atlas(m_rc, m_atlas_size);
+ t = m_atlas->create(image);
+ if (t && !hasAlphaChannel && t->hasAlphaChannel())
+ t->setHasAlphaChannel(false);
+ }
+ return t;
+}
+
+QSGTexture *Manager::create(const QSGCompressedTextureFactory *factory)
+{
+ Q_UNUSED(factory);
+ return nullptr;
+ // ###
+
+#if 0
+ QSGTexture *t = nullptr;
+ if (!qsgEnableCompressedAtlas() || !factory->m_textureData.isValid())
+ return t;
+
+ // TODO: further abstract the atlas and remove this restriction
+ unsigned int format = factory->m_textureData.glInternalFormat();
+ switch (format) {
+ case QOpenGLTexture::RGB8_ETC1:
+ case QOpenGLTexture::RGB8_ETC2:
+ case QOpenGLTexture::RGBA8_ETC2_EAC:
+ case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2:
+ break;
+ default:
+ return t;
+ }
+
+ QSize size = factory->m_textureData.size();
+ if (size.width() < m_atlas_size_limit && size.height() < m_atlas_size_limit) {
+ QHash<unsigned int, QSGCompressedAtlasTexture::Atlas*>::iterator i = m_atlases.find(format);
+ if (i == m_atlases.end())
+ i = m_atlases.insert(format, new QSGCompressedAtlasTexture::Atlas(m_atlas_size, format));
+ // must be multiple of 4
+ QSize paddedSize(((size.width() + 3) / 4) * 4, ((size.height() + 3) / 4) * 4);
+ QByteArray data = factory->m_textureData.data();
+ t = i.value()->create(data, factory->m_textureData.dataLength(), factory->m_textureData.dataOffset(), size, paddedSize);
+ }
+#endif
+}
+
+AtlasBase::AtlasBase(QSGDefaultRenderContext *rc, const QSize &size)
+ : m_rc(rc)
+ , m_rhi(rc->rhi())
+ , m_allocator(size)
+ , m_size(size)
+{
+}
+
+AtlasBase::~AtlasBase()
+{
+ Q_ASSERT(!m_texture);
+}
+
+void AtlasBase::invalidate()
+{
+ delete m_texture;
+ m_texture = nullptr;
+}
+
+void AtlasBase::updateRhiTexture(QRhiResourceUpdateBatch *resourceUpdates)
+{
+ if (!m_allocated) {
+ m_allocated = true;
+ if (!generateTexture()) {
+ qWarning("QSGTextureAtlas: Failed to create texture");
+ return;
+ }
+ }
+
+ for (TextureBase *t : m_pending_uploads) {
+ // ### this profiling is all wrong, the real work is done elsewhere
+ bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled();
+ if (profileFrames)
+ qsg_renderer_timer.start();
+
+ Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphTexturePrepare);
+
+ // Skip bind, convert, swizzle; they're irrelevant
+ Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphTexturePrepare,
+ QQuickProfiler::SceneGraphTexturePrepareStart, 3);
+
+ enqueueTextureUpload(t, resourceUpdates);
+
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare,
+ QQuickProfiler::SceneGraphTexturePrepareUpload);
+
+ // Skip mipmap; unused
+ Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphTexturePrepare,
+ QQuickProfiler::SceneGraphTexturePrepareUpload, 1);
+ Q_QUICK_SG_PROFILE_REPORT(QQuickProfiler::SceneGraphTexturePrepare,
+ QQuickProfiler::SceneGraphTexturePrepareMipmap);
+ }
+
+ m_pending_uploads.clear();
+}
+
+void AtlasBase::remove(TextureBase *t)
+{
+ QRect atlasRect = t->atlasSubRect();
+ m_allocator.deallocate(atlasRect);
+ m_pending_uploads.removeOne(t);
+}
+
+Atlas::Atlas(QSGDefaultRenderContext *rc, const QSize &size)
+ : AtlasBase(rc, size)
+{
+ // use RGBA texture internally as that is the only one guaranteed to be always supported
+ m_format = QRhiTexture::RGBA8;
+
+ m_debug_overlay = qt_sg_envInt("QSG_ATLAS_OVERLAY", 0);
+
+ // images smaller than this will retain their QImage.
+ // by default no images are retained (favoring memory)
+ // set to a very large value to retain all images (allowing quick removal from the atlas)
+ m_atlas_transient_image_threshold = qt_sg_envInt("QSG_ATLAS_TRANSIENT_IMAGE_THRESHOLD", 0);
+}
+
+Atlas::~Atlas()
+{
+}
+
+Texture *Atlas::create(const QImage &image)
+{
+ // No need to lock, as manager already locked it.
+ QRect rect = m_allocator.allocate(QSize(image.width() + 2, image.height() + 2));
+ if (rect.width() > 0 && rect.height() > 0) {
+ Texture *t = new Texture(this, rect, image);
+ m_pending_uploads << t;
+ return t;
+ }
+ return nullptr;
+}
+
+bool Atlas::generateTexture()
+{
+ m_texture = m_rhi->newTexture(m_format, m_size, 1, QRhiTexture::UsedAsTransferSource);
+ if (!m_texture)
+ return false;
+
+ if (!m_texture->build()) {
+ delete m_texture;
+ m_texture = nullptr;
+ return false;
+ }
+
+ return true;
+}
+
+void Atlas::enqueueTextureUpload(TextureBase *t, QRhiResourceUpdateBatch *resourceUpdates)
+{
+ Texture *tex = static_cast<Texture *>(t);
+ const QRect &r = tex->atlasSubRect();
+ QImage image = tex->image();
+
+ if (image.isNull())
+ return;
+
+ if (image.format() != QImage::Format_RGBA8888_Premultiplied)
+ image = std::move(image).convertToFormat(QImage::Format_RGBA8888_Premultiplied);
+
+ if (m_debug_overlay) {
+ QPainter p(&image);
+ p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
+ p.fillRect(0, 0, image.width(), image.height(), QBrush(QColor::fromRgbF(0, 1, 1, 0.5)));
+ }
+
+ const int iw = image.width();
+ const int ih = image.height();
+ const int bpl = image.bytesPerLine() / 4;
+ QVarLengthArray<quint32, 1024> tmpBits(qMax(iw + 2, ih + 2));
+ const int tmpBitsSize = tmpBits.size() * 4;
+ const quint32 *src = reinterpret_cast<const quint32 *>(image.constBits());
+ quint32 *dst = tmpBits.data();
+ QVarLengthArray<QRhiTextureUploadEntry, 5> entries;
+
+ // top row, padding corners
+ dst[0] = src[0];
+ memcpy(dst + 1, src, iw * sizeof(quint32));
+ dst[1 + iw] = src[iw - 1];
+ {
+ QRhiTextureSubresourceUploadDescription subresDesc(dst, tmpBitsSize);
+ subresDesc.setDestinationTopLeft(QPoint(r.x(), r.y()));
+ subresDesc.setSourceSize(QSize(iw + 2, 1));
+ entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
+ }
+
+ // bottom row, padded corners
+ const quint32 *lastRow = src + bpl * (ih - 1);
+ dst[0] = lastRow[0];
+ memcpy(dst + 1, lastRow, iw * sizeof(quint32));
+ dst[1 + iw] = lastRow[iw - 1];
+ {
+ QRhiTextureSubresourceUploadDescription subresDesc(dst, tmpBitsSize);
+ subresDesc.setDestinationTopLeft(QPoint(r.x(), r.y() + ih + 1));
+ subresDesc.setSourceSize(QSize(iw + 2, 1));
+ entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
+ }
+
+ // left column
+ for (int i = 0; i < ih; ++i)
+ dst[i] = src[i * bpl];
+ {
+ QRhiTextureSubresourceUploadDescription subresDesc(dst, tmpBitsSize);
+ subresDesc.setDestinationTopLeft(QPoint(r.x(), r.y() + 1));
+ subresDesc.setSourceSize(QSize(1, ih));
+ entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
+ }
+
+
+ // right column
+ for (int i = 0; i < ih; ++i)
+ dst[i] = src[i * bpl + iw - 1];
+ {
+ QRhiTextureSubresourceUploadDescription subresDesc(dst, tmpBitsSize);
+ subresDesc.setDestinationTopLeft(QPoint(r.x() + iw + 1, r.y() + 1));
+ subresDesc.setSourceSize(QSize(1, ih));
+ entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
+ }
+
+ // Inner part of the image....
+ if (bpl != iw) {
+ int sy = r.y() + 1;
+ int ey = sy + r.height() - 2;
+ entries.reserve(4 + (ey - sy));
+ for (int y = sy; y < ey; ++y) {
+ QRhiTextureSubresourceUploadDescription subresDesc(src, image.bytesPerLine());
+ subresDesc.setDestinationTopLeft(QPoint(r.x() + 1, y));
+ subresDesc.setSourceSize(QSize(r.width() - 2, 1));
+ entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
+ src += bpl;
+ }
+ } else {
+ QRhiTextureSubresourceUploadDescription subresDesc(src, image.sizeInBytes());
+ subresDesc.setDestinationTopLeft(QPoint(r.x() + 1, r.y() + 1));
+ subresDesc.setSourceSize(QSize(r.width() - 2, r.height() - 2));
+ entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
+ }
+
+ QRhiTextureUploadDescription desc;
+ desc.setEntries(entries.cbegin(), entries.cend());
+ resourceUpdates->uploadTexture(m_texture, desc);
+
+ const QSize textureSize = t->textureSize();
+ if (textureSize.width() > m_atlas_transient_image_threshold || textureSize.height() > m_atlas_transient_image_threshold)
+ tex->releaseImage();
+
+ qCDebug(QSG_LOG_TIME_TEXTURE, "atlastexture upload enqueued in: %lldms (%dx%d)",
+ qsg_renderer_timer.elapsed(),
+ t->textureSize().width(),
+ t->textureSize().height());
+}
+
+TextureBase::TextureBase(AtlasBase *atlas, const QRect &textureRect)
+ : QSGTexture(*(new TextureBasePrivate))
+ , m_allocated_rect(textureRect)
+ , m_atlas(atlas)
+{
+}
+
+TextureBase::~TextureBase()
+{
+ m_atlas->remove(this);
+}
+
+QRhiResourceUpdateBatch *TextureBase::workResourceUpdateBatch() const
+{
+ Q_D(const TextureBase);
+ return d->workResourceUpdateBatch;
+}
+
+int TextureBasePrivate::comparisonKey() const
+{
+ Q_Q(const TextureBase);
+
+ // We need special care here: a typical comparisonKey() implementation
+ // returns a unique result when there is no underlying texture yet. This is
+ // not quite ideal for atlasing however since textures with the same atlas
+ // should be considered equal regardless of the state of the underlying
+ // graphics resources.
+
+ // base the comparison on the atlas ptr; this way textures for the same
+ // atlas are considered equal
+ return int(qintptr(q->m_atlas));
+}
+
+QRhiTexture *TextureBasePrivate::rhiTexture() const
+{
+ Q_Q(const TextureBase);
+ return q->m_atlas->m_texture;
+}
+
+void TextureBasePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates)
+{
+ Q_Q(TextureBase);
+#ifdef QT_NO_DEBUG
+ Q_UNUSED(rhi);
+#endif
+ Q_ASSERT(rhi == q->m_atlas->m_rhi);
+ q->m_atlas->updateRhiTexture(resourceUpdates);
+}
+
+Texture::Texture(Atlas *atlas, const QRect &textureRect, const QImage &image)
+ : TextureBase(atlas, textureRect)
+ , m_image(image)
+ , m_has_alpha(image.hasAlphaChannel())
+{
+ float w = atlas->size().width();
+ float h = atlas->size().height();
+ QRect nopad = atlasSubRectWithoutPadding();
+ m_texture_coords_rect = QRectF(nopad.x() / w,
+ nopad.y() / h,
+ nopad.width() / w,
+ nopad.height() / h);
+}
+
+Texture::~Texture()
+{
+ if (m_nonatlas_texture)
+ delete m_nonatlas_texture;
+}
+
+QSGTexture *Texture::removedFromAtlas() const
+{
+ if (!m_nonatlas_texture) {
+ m_nonatlas_texture = new QSGPlainTexture;
+ if (!m_image.isNull()) {
+ m_nonatlas_texture->setImage(m_image);
+ m_nonatlas_texture->setFiltering(filtering());
+ } else {
+ QSGDefaultRenderContext *rc = m_atlas->renderContext();
+ QRhi *rhi = m_atlas->rhi();
+ Q_ASSERT(rhi->isRecordingFrame());
+ const QRect r = atlasSubRectWithoutPadding();
+
+ QRhiTexture *extractTex = rhi->newTexture(m_atlas->texture()->format(), r.size());
+ if (extractTex->build()) {
+ bool ownResUpd = false;
+ QRhiResourceUpdateBatch *resUpd = workResourceUpdateBatch(); // ### Qt 6: should be an arg to this function
+ if (!resUpd) {
+ ownResUpd = true;
+ resUpd = rhi->nextResourceUpdateBatch();
+ }
+ QRhiTextureCopyDescription desc;
+ desc.setSourceTopLeft(r.topLeft());
+ desc.setPixelSize(r.size());
+ resUpd->copyTexture(extractTex, m_atlas->texture(), desc);
+ if (ownResUpd)
+ rc->currentFrameCommandBuffer()->resourceUpdate(resUpd);
+ }
+
+ m_nonatlas_texture->setTexture(extractTex);
+ m_nonatlas_texture->setOwnsTexture(true);
+ m_nonatlas_texture->setHasAlphaChannel(m_has_alpha);
+ m_nonatlas_texture->setTextureSize(r.size());
+ }
+ }
+
+ m_nonatlas_texture->setMipmapFiltering(mipmapFiltering());
+ m_nonatlas_texture->setFiltering(filtering());
+ return m_nonatlas_texture;
+}
+
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qsgrhiatlastexture_p.cpp"
diff --git a/src/quick/scenegraph/util/qsgrhiatlastexture_p.h b/src/quick/scenegraph/util/qsgrhiatlastexture_p.h
new file mode 100644
index 0000000000..50d7b2a53f
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgrhiatlastexture_p.h
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick 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$
+**
+****************************************************************************/
+
+#ifndef QSGRHIATLASTEXTURE_P_H
+#define QSGRHIATLASTEXTURE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QSize>
+#include <QtQuick/private/qsgplaintexture_p.h>
+#include <QtQuick/private/qsgareaallocator_p.h>
+#include <QtGui/QSurface>
+#include <QtGui/private/qrhi_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGDefaultRenderContext;
+
+namespace QSGCompressedAtlasTexture {
+ class Atlas;
+}
+class QSGCompressedTextureFactory;
+
+namespace QSGRhiAtlasTexture
+{
+
+class Texture;
+class TextureBase;
+class TextureBasePrivate;
+class Atlas;
+
+class Manager : public QObject
+{
+ Q_OBJECT
+
+public:
+ Manager(QSGDefaultRenderContext *rc, const QSize &surfacePixelSize, QSurface *maybeSurface);
+ ~Manager();
+
+ QSGTexture *create(const QImage &image, bool hasAlphaChannel);
+ QSGTexture *create(const QSGCompressedTextureFactory *factory);
+ void invalidate();
+
+private:
+ QSGDefaultRenderContext *m_rc;
+ QRhi *m_rhi;
+ Atlas *m_atlas = nullptr;
+ // set of atlases for different compressed formats
+ QHash<unsigned int, QSGCompressedAtlasTexture::Atlas*> m_atlases;
+
+ QSize m_atlas_size;
+ int m_atlas_size_limit;
+};
+
+class AtlasBase : public QObject
+{
+ Q_OBJECT
+public:
+ AtlasBase(QSGDefaultRenderContext *rc, const QSize &size);
+ ~AtlasBase();
+
+ void invalidate();
+ void updateRhiTexture(QRhiResourceUpdateBatch *resourceUpdates);
+ void remove(TextureBase *t);
+
+ QSGDefaultRenderContext *renderContext() const { return m_rc; }
+ QRhi *rhi() const { return m_rhi; }
+ QRhiTexture *texture() const { return m_texture; }
+ QSize size() const { return m_size; }
+
+protected:
+ virtual bool generateTexture() = 0;
+ virtual void enqueueTextureUpload(TextureBase *t, QRhiResourceUpdateBatch *resourceUpdates) = 0;
+
+protected:
+ QSGDefaultRenderContext *m_rc;
+ QRhi *m_rhi;
+ QSGAreaAllocator m_allocator;
+ QRhiTexture *m_texture = nullptr;
+ QSize m_size;
+ QVector<TextureBase *> m_pending_uploads;
+ friend class TextureBase;
+ friend class TextureBasePrivate;
+
+private:
+ bool m_allocated = false;
+};
+
+class Atlas : public AtlasBase
+{
+public:
+ Atlas(QSGDefaultRenderContext *rc, const QSize &size);
+ ~Atlas();
+
+ bool generateTexture() override;
+ void enqueueTextureUpload(TextureBase *t, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ Texture *create(const QImage &image);
+
+ QRhiTexture::Format format() const { return m_format; }
+
+private:
+ QRhiTexture::Format m_format;
+ int m_atlas_transient_image_threshold = 0;
+
+ uint m_debug_overlay : 1;
+};
+
+class TextureBase : public QSGTexture
+{
+ Q_DECLARE_PRIVATE(TextureBase)
+ Q_OBJECT
+public:
+ TextureBase(AtlasBase *atlas, const QRect &textureRect);
+ ~TextureBase();
+
+ int textureId() const override { return 0; } // not used
+ void bind() override { } // not used
+
+ bool isAtlasTexture() const override { return true; }
+ QRect atlasSubRect() const { return m_allocated_rect; }
+
+ QRhiResourceUpdateBatch *workResourceUpdateBatch() const;
+
+protected:
+ QRect m_allocated_rect;
+ AtlasBase *m_atlas;
+};
+
+class TextureBasePrivate : public QSGTexturePrivate
+{
+ Q_DECLARE_PUBLIC(TextureBase)
+public:
+ int comparisonKey() const override;
+ QRhiTexture *rhiTexture() const override;
+ void updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates) override;
+};
+
+class Texture : public TextureBase
+{
+ Q_OBJECT
+public:
+ Texture(Atlas *atlas, const QRect &textureRect, const QImage &image);
+ ~Texture();
+
+ QSize textureSize() const override { return atlasSubRectWithoutPadding().size(); }
+ void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; }
+ bool hasAlphaChannel() const override { return m_has_alpha; }
+ bool hasMipmaps() const override { return false; }
+
+ QRectF normalizedTextureSubRect() const override { return m_texture_coords_rect; }
+
+ QRect atlasSubRect() const { return m_allocated_rect; }
+ QRect atlasSubRectWithoutPadding() const { return m_allocated_rect.adjusted(1, 1, -1, -1); }
+
+ QSGTexture *removedFromAtlas() const override;
+
+ void releaseImage() { m_image = QImage(); }
+ const QImage &image() const { return m_image; }
+
+private:
+ QRectF m_texture_coords_rect;
+ QImage m_image;
+ mutable QSGPlainTexture *m_nonatlas_texture = nullptr;
+ bool m_has_alpha;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp b/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp
new file mode 100644
index 0000000000..7a7c19f587
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick 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 "qsgrhinativetextureimporter_p.h"
+#include <private/qsgrhisupport_p.h> // to get all the relevant qrhi headers
+
+QT_BEGIN_NAMESPACE
+
+void QSGRhiNativeTextureImporter::buildWrapper(QRhi *rhi, QRhiTexture *t,
+ const void *nativeObjectPtr, int nativeLayout)
+{
+#if !QT_CONFIG(vulkan)
+ Q_UNUSED(nativeLayout);
+#endif
+#if !QT_CONFIG(opengl) && !QT_CONFIG(vulkan) && !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN)
+ Q_UNUSED(nativeObjectPtr);
+#endif
+
+ switch (rhi->backend()) {
+ case QRhi::OpenGLES2:
+ {
+#if QT_CONFIG(opengl)
+ QRhiGles2TextureNativeHandles h;
+ h.texture = *reinterpret_cast<const uint *>(nativeObjectPtr);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::Vulkan:
+ {
+#if QT_CONFIG(vulkan)
+ QRhiVulkanTextureNativeHandles h;
+ h.image = *reinterpret_cast<const VkImage *>(nativeObjectPtr);
+ h.layout = VkImageLayout(nativeLayout);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::D3D11:
+ {
+#ifdef Q_OS_WIN
+ QRhiD3D11TextureNativeHandles h;
+ h.texture = *reinterpret_cast<void * const *>(nativeObjectPtr);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::Metal:
+ {
+#ifdef Q_OS_DARWIN
+ QRhiMetalTextureNativeHandles h;
+ h.texture = *reinterpret_cast<void * const *>(nativeObjectPtr);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::Null:
+ t->build();
+ break;
+ default:
+ qWarning("QSGRhiNativeTextureImporter: encountered an unsupported QRhi backend (%d)",
+ int(rhi->backend()));
+ t->build();
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h b/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h
new file mode 100644
index 0000000000..e811109a94
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick 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$
+**
+****************************************************************************/
+
+#ifndef QSGRHINATIVETEXTUREIMPORTER_P_H
+#define QSGRHINATIVETEXTUREIMPORTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qtquickglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRhi;
+class QRhiTexture;
+
+class QSGRhiNativeTextureImporter
+{
+public:
+ static void buildWrapper(QRhi *rhi, QRhiTexture *t,
+ const void *nativeObjectPtr, int nativeLayout);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGRHINATIVETEXTUREIMPORTER_P_H
diff --git a/src/quick/scenegraph/util/qsgsimplematerial.cpp b/src/quick/scenegraph/util/qsgsimplematerial.cpp
index 376f7dce5c..1064caccc7 100644
--- a/src/quick/scenegraph/util/qsgsimplematerial.cpp
+++ b/src/quick/scenegraph/util/qsgsimplematerial.cpp
@@ -46,8 +46,9 @@
\inmodule QtQuick
\ingroup qtquick-scenegraph-materials
- \warning This utility class is only functional when running with the OpenGL
- backend of the Qt Quick scenegraph.
+ \warning This utility class is only functional when running with the legacy
+ OpenGL renderer of the Qt Quick scenegraph. Its usage is not recommended in
+ new application code.
Where the QSGMaterial and QSGMaterialShader API requires a bit of
boilerplate code to create a functioning material, the
diff --git a/src/quick/scenegraph/util/qsgsimplerectnode.cpp b/src/quick/scenegraph/util/qsgsimplerectnode.cpp
index 28b177be84..7b96a3fdde 100644
--- a/src/quick/scenegraph/util/qsgsimplerectnode.cpp
+++ b/src/quick/scenegraph/util/qsgsimplerectnode.cpp
@@ -49,10 +49,10 @@ QT_BEGIN_NAMESPACE
solid filled rectangles using scenegraph.
\inmodule QtQuick
- \warning This utility class is only functional when running with the OpenGL
- or software backends of the Qt Quick scenegraph. For a proper cross-platform
- alternative prefer using QSGRectangleNode via
- QQuickWindow::createRectangleNode() or QSGEngine::createRectangleNode().
+ \warning This utility class is only functional when running with the default
+ or software backends of the Qt Quick scenegraph. As an alternative, prefer
+ using QSGRectangleNode via QQuickWindow::createRectangleNode() or
+ QSGEngine::createRectangleNode().
\deprecated
*/
diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
index 0c49ca9aa5..1d0a423aa9 100644
--- a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
+++ b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
@@ -97,10 +97,10 @@ static void qsgsimpletexturenode_update(QSGGeometry *g,
\warning The simple texture node class must have a texture before being
added to the scene graph to be rendered.
- \warning This utility class is only functional when running with the OpenGL
- or software backends of the Qt Quick scenegraph. For a proper cross-platform
- alternative prefer using QSGImageNode via
- QQuickWindow::createImageNode() or QSGEngine::createImageNode().
+ \warning This utility class is only functional when running with the default
+ or software backends of the Qt Quick scenegraph. As an alternative, prefer
+ using QSGImageNode via QQuickWindow::createImageNode() or
+ QSGEngine::createImageNode().
\deprecated
*/
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
deleted file mode 100644
index 042eee19f5..0000000000
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ /dev/null
@@ -1,851 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick 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 "qsgtexture_p.h"
-#include <QtQuick/private/qsgcontext_p.h>
-#include <qthread.h>
-#include <qmath.h>
-#include <private/qquickprofiler_p.h>
-#include <private/qqmlglobal_p.h>
-#include <QtGui/qguiapplication.h>
-#include <QtGui/qpa/qplatformnativeinterface.h>
-#if QT_CONFIG(opengl)
-# include <qopenglfunctions.h>
-# include <QtGui/qopenglcontext.h>
-# include <QtGui/qopenglfunctions.h>
-# include <QtGui/private/qopengltextureuploader_p.h>
-# include <private/qsgdefaultrendercontext_p.h>
-#endif
-#include <private/qsgmaterialshader_p.h>
-
-#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && defined(__GLIBC__)
-#define CAN_BACKTRACE_EXECINFO
-#endif
-
-#if defined(Q_OS_MAC)
-#define CAN_BACKTRACE_EXECINFO
-#endif
-
-#if defined(QT_NO_DEBUG)
-#undef CAN_BACKTRACE_EXECINFO
-#endif
-
-#if defined(CAN_BACKTRACE_EXECINFO)
-#include <execinfo.h>
-#include <QHash>
-#endif
-
-#if QT_CONFIG(opengl)
-static QElapsedTimer qsg_renderer_timer;
-#endif
-
-#ifndef QT_NO_DEBUG
-static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK");
-#endif
-
-
-#ifndef GL_BGRA
-#define GL_BGRA 0x80E1
-#endif
-
-#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
-#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
-#endif
-
-QT_BEGIN_NAMESPACE
-
-#if QT_CONFIG(opengl) && !defined(QT_NO_DEBUG)
-inline static bool isPowerOfTwo(int x)
-{
- // Assumption: x >= 1
- return x == (x & -x);
-}
-#endif
-
-QSGTexturePrivate::QSGTexturePrivate()
- : wrapChanged(false)
- , filteringChanged(false)
- , anisotropyChanged(false)
- , horizontalWrap(QSGTexture::ClampToEdge)
- , verticalWrap(QSGTexture::ClampToEdge)
- , mipmapMode(QSGTexture::None)
- , filterMode(QSGTexture::Nearest)
- , anisotropyLevel(QSGTexture::AnisotropyNone)
-{
-}
-
-#ifndef QT_NO_DEBUG
-
-static int qt_debug_texture_count = 0;
-
-#if (defined(Q_OS_LINUX) || defined (Q_OS_MAC)) && !defined(Q_OS_ANDROID)
-DEFINE_BOOL_CONFIG_OPTION(qmlDebugLeakBacktrace, QML_DEBUG_LEAK_BACKTRACE)
-
-#define BACKTRACE_SIZE 20
-class SGTextureTraceItem
-{
-public:
- void *backTrace[BACKTRACE_SIZE];
- size_t backTraceSize;
-};
-
-static QHash<QSGTexture*, SGTextureTraceItem*> qt_debug_allocated_textures;
-#endif
-
-inline static void qt_debug_print_texture_count()
-{
- qDebug("Number of leaked textures: %i", qt_debug_texture_count);
- qt_debug_texture_count = -1;
-
-#if defined(CAN_BACKTRACE_EXECINFO)
- if (qmlDebugLeakBacktrace()) {
- while (!qt_debug_allocated_textures.isEmpty()) {
- QHash<QSGTexture*, SGTextureTraceItem*>::Iterator it = qt_debug_allocated_textures.begin();
- QSGTexture* texture = it.key();
- SGTextureTraceItem* item = it.value();
-
- qt_debug_allocated_textures.erase(it);
-
- qDebug() << "------";
- qDebug() << "Leaked" << texture << "backtrace:";
-
- char** symbols = backtrace_symbols(item->backTrace, item->backTraceSize);
-
- if (symbols) {
- for (int i=0; i<(int) item->backTraceSize; i++)
- qDebug("Backtrace <%02d>: %s", i, symbols[i]);
- free(symbols);
- }
-
- qDebug() << "------";
-
- delete item;
- }
- }
-#endif
-}
-
-inline static void qt_debug_add_texture(QSGTexture* texture)
-{
-#if defined(CAN_BACKTRACE_EXECINFO)
- if (qmlDebugLeakBacktrace()) {
- SGTextureTraceItem* item = new SGTextureTraceItem;
- item->backTraceSize = backtrace(item->backTrace, BACKTRACE_SIZE);
- qt_debug_allocated_textures.insert(texture, item);
- }
-#else
- Q_UNUSED(texture);
-#endif // Q_OS_LINUX
-
- ++qt_debug_texture_count;
-
- static bool atexit_registered = false;
- if (!atexit_registered) {
- atexit(qt_debug_print_texture_count);
- atexit_registered = true;
- }
-}
-
-static void qt_debug_remove_texture(QSGTexture* texture)
-{
-#if defined(CAN_BACKTRACE_EXECINFO)
- if (qmlDebugLeakBacktrace()) {
- SGTextureTraceItem* item = qt_debug_allocated_textures.value(texture, 0);
- if (item) {
- qt_debug_allocated_textures.remove(texture);
- delete item;
- }
- }
-#else
- Q_UNUSED(texture)
-#endif
-
- --qt_debug_texture_count;
-
- if (qt_debug_texture_count < 0)
- qDebug("Texture destroyed after qt_debug_print_texture_count() was called.");
-}
-
-#endif // QT_NO_DEBUG
-
-/*!
- \class QSGTexture
-
- \inmodule QtQuick
-
- \brief The QSGTexture class is a baseclass for textures used in
- the scene graph.
-
-
- Users can freely implement their own texture classes to support
- arbitrary input textures, such as YUV video frames or 8 bit alpha
- masks. The scene graph backend provides a default implementation
- of normal color textures. As the implementation of these may be
- hardware specific, they are constructed via the factory
- function QQuickWindow::createTextureFromImage().
-
- The texture is a wrapper around an OpenGL texture, which texture
- id is given by textureId() and which size in pixels is given by
- textureSize(). hasAlphaChannel() reports if the texture contains
- opacity values and hasMipmaps() reports if the texture contains
- mipmap levels.
-
- To use a texture, call the bind() function. The texture parameters
- specifying how the texture is bound, can be specified with
- setMipmapFiltering(), setFiltering(), setHorizontalWrapMode() and
- setVerticalWrapMode(). The texture will internally try to store
- these values to minimize the OpenGL state changes when the texture
- is bound.
-
- \section1 Texture Atlasses
-
- Some scene graph backends use texture atlasses, grouping multiple
- small textures into one large texture. If this is the case, the
- function isAtlasTexture() will return true. Atlasses are used to
- aid the rendering algorithm to do better sorting which increases
- performance. The location of the texture inside the atlas is
- given with the normalizedTextureSubRect() function.
-
- If the texture is used in such a way that atlas is not preferable,
- the function removedFromAtlas() can be used to extract a
- non-atlassed copy.
-
- \note All classes with QSG prefix should be used solely on the scene graph's
- rendering thread. See \l {Scene Graph and Rendering} for more information.
-
- \sa {Scene Graph - Rendering FBOs}, {Scene Graph - Rendering FBOs in a thread}
- */
-
-/*!
- \enum QSGTexture::WrapMode
-
- Specifies how the texture should treat texture coordinates.
-
- \value Repeat Only the fractional part of the texture coordinate is
- used, causing values above 1 and below 0 to repeat.
-
- \value ClampToEdge Values above 1 are clamped to 1 and values
- below 0 are clamped to 0.
-
- \value MirroredRepeat When the texture coordinate is even, only the
- fractional part is used. When odd, the texture coordinate is set to
- \c{1 - fractional part}. This value has been introduced in Qt 5.10.
- */
-
-/*!
- \enum QSGTexture::Filtering
-
- Specifies how sampling of texels should filter when texture
- coordinates are not pixel aligned.
-
- \value None No filtering should occur. This value is only used
- together with setMipmapFiltering().
-
- \value Nearest Sampling returns the nearest texel.
-
- \value Linear Sampling returns a linear interpolation of the
- neighboring texels.
-*/
-
-/*!
- \enum QSGTexture::AnisotropyLevel
-
- Specifies the anisotropic filtering level to be used when
- the texture is not screen aligned.
-
- \value AnisotropyNone No anisotropic filtering.
-
- \value Anisotropy2x 2x anisotropic filtering.
-
- \value Anisotropy4x 4x anisotropic filtering.
-
- \value Anisotropy8x 8x anisotropic filtering.
-
- \value Anisotropy16x 16x anisotropic filtering.
-
- \since 5.9
-*/
-
-/*!
- \fn QSGTexture::QSGTexture(QSGTexturePrivate &dd)
- \internal
- */
-
-#ifndef QT_NO_DEBUG
-Q_GLOBAL_STATIC(QSet<QSGTexture *>, qsg_valid_texture_set)
-Q_GLOBAL_STATIC(QMutex, qsg_valid_texture_mutex)
-
-bool qsg_safeguard_texture(QSGTexture *texture)
-{
-#if QT_CONFIG(opengl)
- QMutexLocker locker(qsg_valid_texture_mutex());
- if (!qsg_valid_texture_set()->contains(texture)) {
- qWarning() << "Invalid texture accessed:" << (void *) texture;
- qsg_set_material_failure();
- QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, 0);
- return false;
- }
-#else
- Q_UNUSED(texture)
-#endif
- return true;
-}
-#endif
-
-/*!
- Constructs the QSGTexture base class.
- */
-QSGTexture::QSGTexture()
- : QObject(*(new QSGTexturePrivate))
-{
-#ifndef QT_NO_DEBUG
- if (qsg_leak_check)
- qt_debug_add_texture(this);
-
- QMutexLocker locker(qsg_valid_texture_mutex());
- qsg_valid_texture_set()->insert(this);
-#endif
-}
-
-/*!
- Destroys the QSGTexture.
- */
-QSGTexture::~QSGTexture()
-{
-#ifndef QT_NO_DEBUG
- if (qsg_leak_check)
- qt_debug_remove_texture(this);
-
- QMutexLocker locker(qsg_valid_texture_mutex());
- qsg_valid_texture_set()->remove(this);
-#endif
-}
-
-
-/*!
- \fn void QSGTexture::bind()
-
- Call this function to bind this texture to the current texture
- target.
-
- Binding a texture may also include uploading the texture data from
- a previously set QImage.
-
- \warning This function can only be called from the rendering thread.
- */
-
-/*!
- \fn QRectF QSGTexture::convertToNormalizedSourceRect(const QRectF &rect) const
-
- Returns \a rect converted to normalized coordinates.
-
- \sa normalizedTextureSubRect()
- */
-
-/*!
- This function returns a copy of the current texture which is removed
- from its atlas.
-
- The current texture remains unchanged, so texture coordinates do not
- need to be updated.
-
- Removing a texture from an atlas is primarily useful when passing
- it to a shader that operates on the texture coordinates 0-1 instead
- of the texture subrect inside the atlas.
-
- If the texture is not part of a texture atlas, this function returns \nullptr.
-
- Implementations of this function are recommended to return the same instance
- for multiple calls to limit memory usage.
-
- \warning This function can only be called from the rendering thread.
- */
-
-QSGTexture *QSGTexture::removedFromAtlas() const
-{
- Q_ASSERT_X(!isAtlasTexture(), "QSGTexture::removedFromAtlas()", "Called on a non-atlas texture");
- return nullptr;
-}
-
-/*!
- Returns weither this texture is part of an atlas or not.
-
- The default implementation returns false.
- */
-bool QSGTexture::isAtlasTexture() const
-{
- return false;
-}
-
-/*!
- \fn int QSGTexture::textureId() const
-
- Returns the OpenGL texture id for this texture.
-
- The default value is 0, indicating that it is an invalid texture id.
-
- The function should at all times return the correct texture id.
-
- \warning This function can only be called from the rendering thread.
- */
-
-/*!
- \fn QSize QSGTexture::textureSize() const
-
- Returns the size of the texture.
- */
-
-/*!
- Returns the rectangle inside textureSize() that this texture
- represents in normalized coordinates.
-
- The default implementation returns a rect at position (0, 0) with
- width and height of 1.
- */
-QRectF QSGTexture::normalizedTextureSubRect() const
-{
- return QRectF(0, 0, 1, 1);
-}
-
-/*!
- \fn bool QSGTexture::hasAlphaChannel() const
-
- Returns true if the texture data contains an alpha channel.
- */
-
-/*!
- \fn bool QSGTexture::hasMipmaps() const
-
- Returns true if the texture data contains mipmap levels.
- */
-
-
-/*!
- Sets the mipmap sampling mode to be used for the upcoming bind() call to \a filter.
-
- Setting the mipmap filtering has no effect it the texture does not have mipmaps.
-
- \sa hasMipmaps()
- */
-void QSGTexture::setMipmapFiltering(Filtering filter)
-{
- Q_D(QSGTexture);
- if (d->mipmapMode != (uint) filter) {
- d->mipmapMode = filter;
- d->filteringChanged = true;
- }
-}
-
-/*!
- Returns whether mipmapping should be used when sampling from this texture.
- */
-QSGTexture::Filtering QSGTexture::mipmapFiltering() const
-{
- return (QSGTexture::Filtering) d_func()->mipmapMode;
-}
-
-
-/*!
- Sets the sampling mode to be used for the upcoming bind() call to \a filter.
- */
-void QSGTexture::setFiltering(QSGTexture::Filtering filter)
-{
- Q_D(QSGTexture);
- if (d->filterMode != (uint) filter) {
- d->filterMode = filter;
- d->filteringChanged = true;
- }
-}
-
-/*!
- Returns the sampling mode to be used for this texture.
- */
-QSGTexture::Filtering QSGTexture::filtering() const
-{
- return (QSGTexture::Filtering) d_func()->filterMode;
-}
-
-/*!
- Sets the level of anisotropic filtering to be used for the upcoming bind() call to \a level.
- The default value is QSGTexture::AnisotropyNone, which means no anisotropic filtering is enabled.
-
- \since 5.9
- */
-void QSGTexture::setAnisotropyLevel(AnisotropyLevel level)
-{
- Q_D(QSGTexture);
- if (d->anisotropyLevel != (uint) level) {
- d->anisotropyLevel = level;
- d->anisotropyChanged = true;
- }
-}
-
-/*!
- Returns the anisotropy level in use for filtering this texture.
-
- \since 5.9
- */
-QSGTexture::AnisotropyLevel QSGTexture::anisotropyLevel() const
-{
- return (QSGTexture::AnisotropyLevel) d_func()->anisotropyLevel;
-}
-
-
-
-/*!
- Sets the horizontal wrap mode to be used for the upcoming bind() call to \a hwrap
- */
-
-void QSGTexture::setHorizontalWrapMode(WrapMode hwrap)
-{
- Q_D(QSGTexture);
- if ((uint) hwrap != d->horizontalWrap) {
- d->horizontalWrap = hwrap;
- d->wrapChanged = true;
- }
-}
-
-/*!
- Returns the horizontal wrap mode to be used for this texture.
- */
-QSGTexture::WrapMode QSGTexture::horizontalWrapMode() const
-{
- return (QSGTexture::WrapMode) d_func()->horizontalWrap;
-}
-
-
-
-/*!
- Sets the vertical wrap mode to be used for the upcoming bind() call to \a vwrap
- */
-void QSGTexture::setVerticalWrapMode(WrapMode vwrap)
-{
- Q_D(QSGTexture);
- if ((uint) vwrap != d->verticalWrap) {
- d->verticalWrap = vwrap;
- d->wrapChanged = true;
- }
-}
-
-/*!
- Returns the vertical wrap mode to be used for this texture.
- */
-QSGTexture::WrapMode QSGTexture::verticalWrapMode() const
-{
- return (QSGTexture::WrapMode) d_func()->verticalWrap;
-}
-
-
-/*!
- Update the texture state to match the filtering, mipmap and wrap options
- currently set.
-
- If \a force is true, all properties will be updated regardless of weither
- they have changed or not.
- */
-void QSGTexture::updateBindOptions(bool force)
-{
-#if QT_CONFIG(opengl)
- Q_D(QSGTexture);
- QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
- force |= isAtlasTexture();
-
- if (force || d->filteringChanged) {
- bool linear = d->filterMode == Linear;
- GLint minFilter = linear ? GL_LINEAR : GL_NEAREST;
- GLint magFilter = linear ? GL_LINEAR : GL_NEAREST;
-
- if (hasMipmaps()) {
- if (d->mipmapMode == Nearest)
- minFilter = linear ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST;
- else if (d->mipmapMode == Linear)
- minFilter = linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR;
- }
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
- d->filteringChanged = false;
- }
-
- if (force || d->anisotropyChanged) {
- d->anisotropyChanged = false;
- if (QOpenGLContext::currentContext()->hasExtension(QByteArrayLiteral("GL_EXT_texture_filter_anisotropic")))
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, float(1 << (d->anisotropyLevel)));
- }
-
- if (force || d->wrapChanged) {
-#ifndef QT_NO_DEBUG
- if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat
- || d->horizontalWrap == MirroredRepeat || d->verticalWrap == MirroredRepeat)
- {
- bool npotSupported = QOpenGLFunctions(QOpenGLContext::currentContext()).hasOpenGLFeature(QOpenGLFunctions::NPOTTextures);
- QSize size = textureSize();
- bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
- if (!npotSupported && isNpot)
- qWarning("Scene Graph: This system does not support the REPEAT wrap mode for non-power-of-two textures.");
- }
-#endif
- GLenum wrapS = GL_CLAMP_TO_EDGE;
- if (d->horizontalWrap == Repeat)
- wrapS = GL_REPEAT;
- else if (d->horizontalWrap == MirroredRepeat)
- wrapS = GL_MIRRORED_REPEAT;
- GLenum wrapT = GL_CLAMP_TO_EDGE;
- if (d->verticalWrap == Repeat)
- wrapT = GL_REPEAT;
- else if (d->verticalWrap == MirroredRepeat)
- wrapT = GL_MIRRORED_REPEAT;
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
- d->wrapChanged = false;
- }
-#else
- Q_UNUSED(force)
-#endif
-}
-
-QSGPlainTexture::QSGPlainTexture()
- : QSGTexture()
- , m_texture_id(0)
- , m_has_alpha(false)
- , m_dirty_texture(false)
- , m_dirty_bind_options(false)
- , m_owns_texture(true)
- , m_mipmaps_generated(false)
- , m_retain_image(false)
-{
-}
-
-
-QSGPlainTexture::~QSGPlainTexture()
-{
-#if QT_CONFIG(opengl)
- if (m_texture_id && m_owns_texture && QOpenGLContext::currentContext())
- QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
-#endif
-}
-
-void QSGPlainTexture::setImage(const QImage &image)
-{
- m_image = image;
- m_texture_size = image.size();
- m_has_alpha = image.hasAlphaChannel();
- m_dirty_texture = true;
- m_dirty_bind_options = true;
- m_mipmaps_generated = false;
- }
-
-int QSGPlainTexture::textureId() const
-{
- if (m_dirty_texture) {
- if (m_image.isNull()) {
- // The actual texture and id will be updated/deleted in a later bind()
- // or ~QSGPlainTexture so just keep it minimal here.
- return 0;
- } else if (m_texture_id == 0){
-#if QT_CONFIG(opengl)
- // Generate a texture id for use later and return it.
- QOpenGLContext::currentContext()->functions()->glGenTextures(1, &const_cast<QSGPlainTexture *>(this)->m_texture_id);
-#endif
- return m_texture_id;
- }
- }
- return m_texture_id;
-}
-
-void QSGPlainTexture::setTextureId(int id)
-{
-#if QT_CONFIG(opengl)
- if (m_texture_id && m_owns_texture)
- QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
-#endif
-
- m_texture_id = id;
- m_dirty_texture = false;
- m_dirty_bind_options = true;
- m_image = QImage();
- m_mipmaps_generated = false;
-}
-
-void QSGPlainTexture::bind()
-{
-#if QT_CONFIG(opengl)
- QOpenGLContext *context = QOpenGLContext::currentContext();
- QOpenGLFunctions *funcs = context->functions();
- if (!m_dirty_texture) {
- funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
- if (mipmapFiltering() != QSGTexture::None && !m_mipmaps_generated) {
- funcs->glGenerateMipmap(GL_TEXTURE_2D);
- m_mipmaps_generated = true;
- }
- updateBindOptions(m_dirty_bind_options);
- m_dirty_bind_options = false;
- return;
- }
-
- m_dirty_texture = false;
-
- bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled();
- if (profileFrames)
- qsg_renderer_timer.start();
- Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(QQuickProfiler::SceneGraphTexturePrepare,
- QQuickProfiler::SceneGraphTextureDeletion);
-
-
- if (m_image.isNull()) {
- if (m_texture_id && m_owns_texture) {
- funcs->glDeleteTextures(1, &m_texture_id);
- qCDebug(QSG_LOG_TIME_TEXTURE, "plain texture deleted in %dms - %dx%d",
- (int) qsg_renderer_timer.elapsed(),
- m_texture_size.width(),
- m_texture_size.height());
- Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphTextureDeletion,
- QQuickProfiler::SceneGraphTextureDeletionDelete);
- }
- m_texture_id = 0;
- m_texture_size = QSize();
- m_has_alpha = false;
-
- return;
- }
-
- if (m_texture_id == 0)
- funcs->glGenTextures(1, &m_texture_id);
- funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
-
- qint64 bindTime = 0;
- if (profileFrames)
- bindTime = qsg_renderer_timer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare,
- QQuickProfiler::SceneGraphTexturePrepareBind);
-
- // ### TODO: check for out-of-memory situations...
-
- QOpenGLTextureUploader::BindOptions options = QOpenGLTextureUploader::PremultipliedAlphaBindOption;
-
- // Downscale the texture to fit inside the max texture limit if it is too big.
- // It would be better if the image was already downscaled to the right size,
- // but this information is not always available at that time, so as a last
- // resort we can do it here. Texture coordinates are normalized, so it
- // won't cause any problems and actual texture sizes will be written
- // based on QSGTexture::textureSize which is updated after this, so that
- // should be ok.
- int max;
- if (auto rc = QSGDefaultRenderContext::from(context))
- max = rc->maxTextureSize();
- else
- funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
-
- m_texture_size = m_texture_size.boundedTo(QSize(max, max));
-
- // Scale to a power of two size if mipmapping is requested and the
- // texture is npot and npot textures are not properly supported.
- if (mipmapFiltering() != QSGTexture::None
- && !funcs->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures)) {
- options |= QOpenGLTextureUploader::PowerOfTwoBindOption;
- }
-
- updateBindOptions(m_dirty_bind_options);
-
- QOpenGLTextureUploader::textureImage(GL_TEXTURE_2D, m_image, options, QSize(max, max));
-
- qint64 uploadTime = 0;
- if (profileFrames)
- uploadTime = qsg_renderer_timer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare,
- QQuickProfiler::SceneGraphTexturePrepareUpload);
-
- if (mipmapFiltering() != QSGTexture::None) {
- funcs->glGenerateMipmap(GL_TEXTURE_2D);
- m_mipmaps_generated = true;
- }
-
- qint64 mipmapTime = 0;
- if (profileFrames) {
- mipmapTime = qsg_renderer_timer.nsecsElapsed();
- qCDebug(QSG_LOG_TIME_TEXTURE,
- "plain texture uploaded in: %dms (%dx%d), bind=%d, upload=%d, mipmap=%d%s",
- int(mipmapTime / 1000000),
- m_texture_size.width(), m_texture_size.height(),
- int(bindTime / 1000000),
- int((uploadTime - bindTime)/1000000),
- int((mipmapTime - uploadTime)/1000000),
- m_texture_size != m_image.size() ? " (scaled to GL_MAX_TEXTURE_SIZE)" : "");
- }
- Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphTexturePrepare,
- QQuickProfiler::SceneGraphTexturePrepareMipmap);
-
- m_texture_rect = QRectF(0, 0, 1, 1);
-
- m_dirty_bind_options = false;
- if (!m_retain_image)
- m_image = QImage();
-#endif
-}
-
-
-/*!
- \class QSGDynamicTexture
- \brief The QSGDynamicTexture class serves as a baseclass for dynamically changing textures,
- such as content that is rendered to FBO's.
- \inmodule QtQuick
-
- To update the content of the texture, call updateTexture() explicitly. Simply calling bind()
- will not update the texture.
-
- \note All classes with QSG prefix should be used solely on the scene graph's
- rendering thread. See \l {Scene Graph and Rendering} for more information.
- */
-
-
-/*!
- \fn bool QSGDynamicTexture::updateTexture()
-
- Call this function to explicitly update the dynamic texture. Calling bind() will bind
- the content that was previously updated.
-
- The function returns true if the texture was changed as a resul of the update; otherwise
- returns false.
- */
-
-
-
-QT_END_NAMESPACE
-
-#include "moc_qsgtexture.cpp"
-#include "moc_qsgtexture_p.cpp"
diff --git a/src/quick/scenegraph/util/qsgtexture.h b/src/quick/scenegraph/util/qsgtexture.h
deleted file mode 100644
index 7bd57a16e3..0000000000
--- a/src/quick/scenegraph/util/qsgtexture.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick 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$
-**
-****************************************************************************/
-
-#ifndef QSGTEXTURE_H
-#define QSGTEXTURE_H
-
-#include <QtQuick/qtquickglobal.h>
-#include <QtCore/QObject>
-#include <QtGui/QImage>
-
-QT_BEGIN_NAMESPACE
-
-class QSGTexturePrivate;
-class Q_QUICK_EXPORT QSGTexture : public QObject
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QSGTexture)
-
-public:
- QSGTexture();
- ~QSGTexture() override;
-
- enum WrapMode {
- Repeat,
- ClampToEdge,
- MirroredRepeat
- };
-
- enum Filtering {
- None,
- Nearest,
- Linear
- };
-
- enum AnisotropyLevel {
- AnisotropyNone,
- Anisotropy2x,
- Anisotropy4x,
- Anisotropy8x,
- Anisotropy16x
- };
-
- virtual int textureId() const = 0;
- virtual QSize textureSize() const = 0;
- virtual bool hasAlphaChannel() const = 0;
- virtual bool hasMipmaps() const = 0;
-
- virtual QRectF normalizedTextureSubRect() const;
-
- virtual bool isAtlasTexture() const;
-
- virtual QSGTexture *removedFromAtlas() const;
-
- virtual void bind() = 0;
- void updateBindOptions(bool force = false);
-
- void setMipmapFiltering(Filtering filter);
- QSGTexture::Filtering mipmapFiltering() const;
-
- void setFiltering(Filtering filter);
- QSGTexture::Filtering filtering() const;
-
- void setAnisotropyLevel(AnisotropyLevel level);
- QSGTexture::AnisotropyLevel anisotropyLevel() const;
-
- void setHorizontalWrapMode(WrapMode hwrap);
- QSGTexture::WrapMode horizontalWrapMode() const;
-
- void setVerticalWrapMode(WrapMode vwrap);
- QSGTexture::WrapMode verticalWrapMode() const;
-
- inline QRectF convertToNormalizedSourceRect(const QRectF &rect) const;
-
-protected:
- QSGTexture(QSGTexturePrivate &dd);
-};
-
-QRectF QSGTexture::convertToNormalizedSourceRect(const QRectF &rect) const
-{
- QSize s = textureSize();
- QRectF r = normalizedTextureSubRect();
-
- qreal sx = r.width() / s.width();
- qreal sy = r.height() / s.height();
-
- return QRectF(r.x() + rect.x() * sx,
- r.y() + rect.y() * sy,
- rect.width() * sx,
- rect.height() * sy);
-}
-
-
-class Q_QUICK_EXPORT QSGDynamicTexture : public QSGTexture
-{
- Q_OBJECT
-public:
- virtual bool updateTexture() = 0;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index 7b1d5abb26..67b8748119 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -38,23 +38,20 @@
****************************************************************************/
#include "qsgtexturematerial_p.h"
-#include "qsgtexture_p.h"
+#include <private/qsgtexture_p.h>
#if QT_CONFIG(opengl)
# include <QtGui/qopenglshaderprogram.h>
# include <QtGui/qopenglfunctions.h>
#endif
+#include <QtGui/private/qrhi_p.h>
QT_BEGIN_NAMESPACE
-#if QT_CONFIG(opengl)
inline static bool isPowerOfTwo(int x)
{
// Assumption: x >= 1
return x == (x & -x);
}
-#endif
-
-QSGMaterialType QSGOpaqueTextureMaterialShader::type;
QSGOpaqueTextureMaterialShader::QSGOpaqueTextureMaterialShader()
{
@@ -122,6 +119,60 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
}
+QSGOpaqueTextureMaterialRhiShader::QSGOpaqueTextureMaterialRhiShader()
+{
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/opaquetexture.vert.qsb"));
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/opaquetexture.frag.qsb"));
+}
+
+bool QSGOpaqueTextureMaterialRhiShader::updateUniformData(RenderState &state, QSGMaterial *, QSGMaterial *)
+{
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+
+ if (state.isMatrixDirty()) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ changed = true;
+ }
+
+ return changed;
+}
+
+void QSGOpaqueTextureMaterialRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+{
+ if (binding != 1)
+ return;
+
+#ifdef QT_NO_DEBUG
+ Q_UNUSED(oldMaterial);
+#endif
+ Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
+ QSGOpaqueTextureMaterial *tx = static_cast<QSGOpaqueTextureMaterial *>(newMaterial);
+ QSGTexture *t = tx->texture();
+
+ t->setFiltering(tx->filtering());
+ t->setMipmapFiltering(tx->mipmapFiltering());
+ t->setAnisotropyLevel(tx->anisotropyLevel());
+
+ t->setHorizontalWrapMode(tx->horizontalWrapMode());
+ t->setVerticalWrapMode(tx->verticalWrapMode());
+ if (!state.rhi()->isFeatureSupported(QRhi::NPOTTextureRepeat)) {
+ QSize size = t->textureSize();
+ const bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
+ if (isNpot) {
+ t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ t->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ t->setMipmapFiltering(QSGTexture::None);
+ }
+ }
+
+ t->updateRhiTexture(state.rhi(), state.resourceUpdateBatch());
+ *texture = t;
+}
+
+
/*!
\class QSGOpaqueTextureMaterial
\brief The QSGOpaqueTextureMaterial class provides a convenient way of
@@ -129,8 +180,8 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
\inmodule QtQuick
\ingroup qtquick-scenegraph-materials
- \warning This utility class is only functional when running with the OpenGL
- backend of the Qt Quick scenegraph.
+ \warning This utility class is only functional when running with the
+ default backend of the Qt Quick scenegraph.
The opaque textured material will fill every pixel in a geometry with
the supplied texture. The material does not respect the opacity of the
@@ -175,6 +226,7 @@ QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial()
, m_vertical_wrap(QSGTexture::ClampToEdge)
, m_anisotropy_level(QSGTexture::AnisotropyNone)
{
+ setFlag(SupportsRhiShader, true);
}
@@ -183,7 +235,8 @@ QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial()
*/
QSGMaterialType *QSGOpaqueTextureMaterial::type() const
{
- return &QSGOpaqueTextureMaterialShader::type;
+ static QSGMaterialType type;
+ return &type;
}
/*!
@@ -191,11 +244,13 @@ QSGMaterialType *QSGOpaqueTextureMaterial::type() const
*/
QSGMaterialShader *QSGOpaqueTextureMaterial::createShader() const
{
- return new QSGOpaqueTextureMaterialShader;
+ if (flags().testFlag(RhiShaderWanted))
+ return new QSGOpaqueTextureMaterialRhiShader;
+ else
+ return new QSGOpaqueTextureMaterialShader;
}
-
/*!
\fn QSGTexture *QSGOpaqueTextureMaterial::texture() const
@@ -323,7 +378,7 @@ int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const
{
Q_ASSERT(o && type() == o->type());
const QSGOpaqueTextureMaterial *other = static_cast<const QSGOpaqueTextureMaterial *>(o);
- if (int diff = m_texture->textureId() - other->texture()->textureId())
+ if (int diff = m_texture->comparisonKey() - other->texture()->comparisonKey())
return diff;
return int(m_filtering) - int(other->m_filtering);
}
@@ -337,8 +392,8 @@ int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const
\inmodule QtQuick
\ingroup qtquick-scenegraph-materials
- \warning This utility class is only functional when running with the OpenGL
- backend of the Qt Quick scenegraph.
+ \warning This utility class is only functional when running with the
+ default backend of the Qt Quick scenegraph.
The textured material will fill every pixel in a geometry with
the supplied texture.
@@ -363,32 +418,30 @@ int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const
a material in the scene graph.
*/
-QSGMaterialType QSGTextureMaterialShader::type;
-
-
-
/*!
\internal
*/
QSGMaterialType *QSGTextureMaterial::type() const
{
- return &QSGTextureMaterialShader::type;
+ static QSGMaterialType type;
+ return &type;
}
-
-
/*!
\internal
*/
QSGMaterialShader *QSGTextureMaterial::createShader() const
{
- return new QSGTextureMaterialShader;
+ if (flags().testFlag(RhiShaderWanted))
+ return new QSGTextureMaterialRhiShader;
+ else
+ return new QSGTextureMaterialShader;
}
+
QSGTextureMaterialShader::QSGTextureMaterialShader()
- : QSGOpaqueTextureMaterialShader()
{
#if QT_CONFIG(opengl)
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/texture.frag"));
@@ -413,4 +466,27 @@ void QSGTextureMaterialShader::initialize()
#endif
}
+
+QSGTextureMaterialRhiShader::QSGTextureMaterialRhiShader()
+{
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/texture.vert.qsb"));
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/texture.frag.qsb"));
+}
+
+bool QSGTextureMaterialRhiShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+{
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + 64, &opacity, 4);
+ changed = true;
+ }
+
+ changed |= QSGOpaqueTextureMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial);
+
+ return changed;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgtexturematerial_p.h b/src/quick/scenegraph/util/qsgtexturematerial_p.h
index a99e872580..d1ef7d1d7f 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial_p.h
+++ b/src/quick/scenegraph/util/qsgtexturematerial_p.h
@@ -64,15 +64,22 @@ public:
void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
char const *const *attributeNames() const override;
- static QSGMaterialType type;
-
protected:
void initialize() override;
int m_matrix_id;
};
-class Q_QUICK_PRIVATE_EXPORT QSGTextureMaterialShader : public QSGOpaqueTextureMaterialShader
+class Q_QUICK_PRIVATE_EXPORT QSGOpaqueTextureMaterialRhiShader : public QSGMaterialRhiShader
+{
+public:
+ QSGOpaqueTextureMaterialRhiShader();
+
+ bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
+ void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
+};
+
+class QSGTextureMaterialShader : public QSGOpaqueTextureMaterialShader
{
public:
QSGTextureMaterialShader();
@@ -80,12 +87,18 @@ public:
void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
void initialize() override;
- static QSGMaterialType type;
-
protected:
int m_opacity_id;
};
+class QSGTextureMaterialRhiShader : public QSGOpaqueTextureMaterialRhiShader
+{
+public:
+ QSGTextureMaterialRhiShader();
+
+ bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
+};
+
QT_END_NAMESPACE
#endif // QSGTEXTUREMATERIAL_P_H
diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
index cb61430e2e..c27dd7d1f0 100644
--- a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
@@ -51,8 +51,6 @@ public:
void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
char const *const *attributeNames() const override;
- static QSGMaterialType type;
-
private:
void initialize() override;
#if QT_CONFIG(opengl)
@@ -61,8 +59,6 @@ private:
#endif
};
-QSGMaterialType QSGVertexColorMaterialShader::type;
-
QSGVertexColorMaterialShader::QSGVertexColorMaterialShader()
{
#if QT_CONFIG(opengl)
@@ -99,6 +95,43 @@ void QSGVertexColorMaterialShader::initialize()
}
+class QSGVertexColorMaterialRhiShader : public QSGMaterialRhiShader
+{
+public:
+ QSGVertexColorMaterialRhiShader();
+
+ bool updateUniformData(RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+};
+
+QSGVertexColorMaterialRhiShader::QSGVertexColorMaterialRhiShader()
+{
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/vertexcolor.vert.qsb"));
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/vertexcolor.frag.qsb"));
+}
+
+bool QSGVertexColorMaterialRhiShader::updateUniformData(RenderState &state,
+ QSGMaterial * /*newEffect*/,
+ QSGMaterial * /*oldEffect*/)
+{
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+
+ if (state.isMatrixDirty()) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ changed = true;
+ }
+
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + 64, &opacity, 4);
+ changed = true;
+ }
+
+ return changed;
+}
+
+
/*!
\class QSGVertexColorMaterial
\brief The QSGVertexColorMaterial class provides a convenient way of rendering per-vertex
@@ -107,8 +140,8 @@ void QSGVertexColorMaterialShader::initialize()
\inmodule QtQuick
\ingroup qtquick-scenegraph-materials
- \warning This utility class is only functional when running with the OpenGL
- backend of the Qt Quick scenegraph.
+ \warning This utility class is only functional when running with the
+ default backend of the Qt Quick scenegraph.
The vertex color material will give each vertex in a geometry a color. Pixels between
vertices will be linearly interpolated. The colors can contain transparency.
@@ -135,6 +168,7 @@ void QSGVertexColorMaterialShader::initialize()
QSGVertexColorMaterial::QSGVertexColorMaterial()
{
setFlag(Blending, true);
+ setFlag(SupportsRhiShader, true);
}
@@ -158,7 +192,8 @@ int QSGVertexColorMaterial::compare(const QSGMaterial * /* other */) const
QSGMaterialType *QSGVertexColorMaterial::type() const
{
- return &QSGVertexColorMaterialShader::type;
+ static QSGMaterialType type;
+ return &type;
}
@@ -169,7 +204,10 @@ QSGMaterialType *QSGVertexColorMaterial::type() const
QSGMaterialShader *QSGVertexColorMaterial::createShader() const
{
- return new QSGVertexColorMaterialShader;
+ if (flags().testFlag(RhiShaderWanted))
+ return new QSGVertexColorMaterialRhiShader;
+ else
+ return new QSGVertexColorMaterialShader;
}
QT_END_NAMESPACE