aboutsummaryrefslogtreecommitdiffstats
path: root/src/quickshapes/qquickshapegenericrenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quickshapes/qquickshapegenericrenderer.cpp')
-rw-r--r--src/quickshapes/qquickshapegenericrenderer.cpp803
1 files changed, 559 insertions, 244 deletions
diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp
index 604da2a889..34c7fa96a0 100644
--- a/src/quickshapes/qquickshapegenericrenderer.cpp
+++ b/src/quickshapes/qquickshapegenericrenderer.cpp
@@ -1,61 +1,22 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickshapegenericrenderer_p.h"
#include <QtGui/private/qtriangulator_p.h>
#include <QtGui/private/qtriangulatingstroker_p.h>
+#include <rhi/qrhi.h>
+#include <QSGVertexColorMaterial>
+#include <QSGTextureProvider>
+#include <private/qsgplaintexture_p.h>
+
+#include <QtQuick/private/qsggradientcache_p.h>
#if QT_CONFIG(thread)
#include <QThreadPool>
#endif
-#if QT_CONFIG(opengl)
-#include <QSGVertexColorMaterial>
-#include <QOpenGLContext>
-#include <QOffscreenSurface>
-#include <QtGui/private/qopenglextensions_p.h>
-#endif
-
QT_BEGIN_NAMESPACE
-static const qreal TRI_SCALE = 1;
-
struct ColoredVertex // must match QSGGeometry::ColoredPoint2D
{
float x, y;
@@ -68,11 +29,13 @@ struct ColoredVertex // must match QSGGeometry::ColoredPoint2D
static inline QQuickShapeGenericRenderer::Color4ub colorToColor4ub(const QColor &c)
{
+ float r, g, b, a;
+ c.getRgbF(&r, &g, &b, &a);
QQuickShapeGenericRenderer::Color4ub color = {
- uchar(qRound(c.redF() * c.alphaF() * 255)),
- uchar(qRound(c.greenF() * c.alphaF() * 255)),
- uchar(qRound(c.blueF() * c.alphaF() * 255)),
- uchar(qRound(c.alphaF() * 255))
+ uchar(qRound(r * a * 255)),
+ uchar(qRound(g * a * 255)),
+ uchar(qRound(b * a * 255)),
+ uchar(qRound(a * 255))
};
return color;
}
@@ -81,6 +44,7 @@ QQuickShapeGenericStrokeFillNode::QQuickShapeGenericStrokeFillNode(QQuickWindow
: m_material(nullptr)
{
setFlag(QSGNode::OwnsGeometry, true);
+ setFlag(QSGNode::UsePreprocess, true);
setGeometry(new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0));
activateMaterial(window, MatSolidColor);
#ifdef QSG_RUNTIME_DESCRIPTION
@@ -105,6 +69,9 @@ void QQuickShapeGenericStrokeFillNode::activateMaterial(QQuickWindow *window, Ma
case MatConicalGradient:
m_material.reset(QQuickShapeGenericMaterialFactory::createConicalGradient(window, this));
break;
+ case MatTextureFill:
+ m_material.reset(QQuickShapeGenericMaterialFactory::createTextureFill(window, this));
+ break;
default:
qWarning("Unknown material %d", m);
return;
@@ -114,37 +81,23 @@ void QQuickShapeGenericStrokeFillNode::activateMaterial(QQuickWindow *window, Ma
setMaterial(m_material.data());
}
-static bool q_supportsElementIndexUint(QSGRendererInterface::GraphicsApi api)
-{
- static bool elementIndexUint = true;
-#if QT_CONFIG(opengl)
- if (api == QSGRendererInterface::OpenGL) {
- static bool elementIndexUintChecked = false;
- if (!elementIndexUintChecked) {
- elementIndexUintChecked = true;
- QOpenGLContext *context = QOpenGLContext::currentContext();
- QScopedPointer<QOpenGLContext> dummyContext;
- QScopedPointer<QOffscreenSurface> dummySurface;
- bool ok = true;
- if (!context) {
- dummyContext.reset(new QOpenGLContext);
- dummyContext->create();
- context = dummyContext.data();
- dummySurface.reset(new QOffscreenSurface);
- dummySurface->setFormat(context->format());
- dummySurface->create();
- ok = context->makeCurrent(dummySurface.data());
- }
- if (ok) {
- elementIndexUint = static_cast<QOpenGLExtensions *>(context->functions())->hasOpenGLExtension(
- QOpenGLExtensions::ElementIndexUint);
- }
- }
+void QQuickShapeGenericStrokeFillNode::preprocess()
+{
+ if (m_fillTextureProvider != nullptr) {
+ if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(m_fillTextureProvider->texture()))
+ texture->updateTexture();
}
-#else
- Q_UNUSED(api);
-#endif
- return elementIndexUint;
+}
+
+void QQuickShapeGenericStrokeFillNode::handleTextureChanged()
+{
+ markDirty(QSGNode::DirtyMaterial);
+}
+
+void QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed()
+{
+ m_fillTextureProvider = nullptr;
+ markDirty(QSGNode::DirtyMaterial);
}
QQuickShapeGenericRenderer::~QQuickShapeGenericRenderer()
@@ -160,11 +113,14 @@ QQuickShapeGenericRenderer::~QQuickShapeGenericRenderer()
// sync, and so triangulation too, happens on the gui thread
// - except when async is set, in which case triangulation is moved to worker threads
-void QQuickShapeGenericRenderer::beginSync(int totalCount)
+void QQuickShapeGenericRenderer::beginSync(int totalCount, bool *countChanged)
{
- if (m_sp.count() != totalCount) {
+ if (m_sp.size() != totalCount) {
m_sp.resize(totalCount);
m_accDirty |= DirtyList;
+ *countChanged = true;
+ } else {
+ *countChanged = false;
}
for (ShapePathData &d : m_sp)
d.syncDirty = 0;
@@ -180,8 +136,12 @@ void QQuickShapeGenericRenderer::setPath(int index, const QQuickPath *path)
void QQuickShapeGenericRenderer::setStrokeColor(int index, const QColor &color)
{
ShapePathData &d(m_sp[index]);
+ const bool wasTransparent = d.strokeColor.a == 0;
d.strokeColor = colorToColor4ub(color);
+ const bool isTransparent = d.strokeColor.a == 0;
d.syncDirty |= DirtyColor;
+ if (wasTransparent && !isTransparent)
+ d.syncDirty |= DirtyStrokeGeom;
}
void QQuickShapeGenericRenderer::setStrokeWidth(int index, qreal w)
@@ -196,8 +156,12 @@ void QQuickShapeGenericRenderer::setStrokeWidth(int index, qreal w)
void QQuickShapeGenericRenderer::setFillColor(int index, const QColor &color)
{
ShapePathData &d(m_sp[index]);
+ const bool wasTransparent = d.fillColor.a == 0;
d.fillColor = colorToColor4ub(color);
+ const bool isTransparent = d.fillColor.a == 0;
d.syncDirty |= DirtyColor;
+ if (wasTransparent && !isTransparent)
+ d.syncDirty |= DirtyFillGeom;
}
void QQuickShapeGenericRenderer::setFillRule(int index, QQuickShapePath::FillRule fillRule)
@@ -239,7 +203,7 @@ void QQuickShapeGenericRenderer::setFillGradient(int index, QQuickShapeGradient
ShapePathData &d(m_sp[index]);
if (gradient) {
d.fillGradient.stops = gradient->gradientStops(); // sorted
- d.fillGradient.spread = gradient->spread();
+ d.fillGradient.spread = QGradient::Spread(gradient->spread());
if (QQuickShapeLinearGradient *g = qobject_cast<QQuickShapeLinearGradient *>(gradient)) {
d.fillGradientActive = LinearGradient;
d.fillGradient.a = QPointF(g->x1(), g->y1());
@@ -263,15 +227,55 @@ void QQuickShapeGenericRenderer::setFillGradient(int index, QQuickShapeGradient
d.syncDirty |= DirtyFillGradient;
}
+void QQuickShapeGenericRenderer::setFillTextureProvider(int index, QQuickItem *textureProviderItem)
+{
+ ShapePathData &d(m_sp[index]);
+ if ((d.fillTextureProviderItem == nullptr) != (textureProviderItem == nullptr))
+ d.syncDirty |= DirtyFillGeom;
+ if (d.fillTextureProviderItem != nullptr)
+ QQuickItemPrivate::get(d.fillTextureProviderItem)->derefWindow();
+ d.fillTextureProviderItem = textureProviderItem;
+ if (d.fillTextureProviderItem != nullptr)
+ QQuickItemPrivate::get(d.fillTextureProviderItem)->refWindow(m_item->window());
+ d.syncDirty |= DirtyFillTexture;
+}
+
+void QQuickShapeGenericRenderer::handleSceneChange(QQuickWindow *window)
+{
+ for (auto &pathData : m_sp) {
+ if (pathData.fillTextureProviderItem != nullptr) {
+ if (window == nullptr)
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->derefWindow();
+ else
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->refWindow(window);
+ }
+ }
+}
+
+
+void QQuickShapeGenericRenderer::setFillTransform(int index, const QSGTransform &transform)
+{
+ ShapePathData &d(m_sp[index]);
+ d.fillTransform = transform;
+ d.syncDirty |= DirtyFillTransform;
+}
+
+void QQuickShapeGenericRenderer::setTriangulationScale(qreal scale)
+{
+ // No dirty, this is called at the start of every sync. Just store the value.
+ m_triangulationScale = scale;
+}
+
void QQuickShapeFillRunnable::run()
{
- QQuickShapeGenericRenderer::triangulateFill(path, fillColor, &fillVertices, &fillIndices, &indexType, supportsElementIndexUint);
+ QQuickShapeGenericRenderer::triangulateFill(path, fillColor, &fillVertices, &fillIndices, &indexType,
+ supportsElementIndexUint, triangulationScale);
emit done(this);
}
void QQuickShapeStrokeRunnable::run()
{
- QQuickShapeGenericRenderer::triangulateStroke(path, pen, strokeColor, &strokeVertices, clipSize);
+ QQuickShapeGenericRenderer::triangulateStroke(path, pen, strokeColor, &strokeVertices, clipSize, triangulationScale);
emit done(this);
}
@@ -301,7 +305,7 @@ void QQuickShapeGenericRenderer::endSync(bool async)
bool didKickOffAsync = false;
- for (int i = 0; i < m_sp.count(); ++i) {
+ for (int i = 0; i < m_sp.size(); ++i) {
ShapePathData &d(m_sp[i]);
if (!d.syncDirty)
continue;
@@ -330,6 +334,14 @@ void QQuickShapeGenericRenderer::endSync(bool async)
pathWorkThreadPool->setMaxThreadCount(idealCount > 0 ? idealCount * 2 : 4);
}
#endif
+ auto testFeatureIndexUint = [](QQuickItem *item) -> bool {
+ if (auto *w = item->window()) {
+ if (auto *rhi = QQuickWindowPrivate::get(w)->rhi)
+ return rhi->isFeatureSupported(QRhi::ElementIndexUint);
+ }
+ return true;
+ };
+ static bool supportsElementIndexUint = testFeatureIndexUint(m_item);
if ((d.syncDirty & DirtyFillGeom) && d.fillColor.a) {
d.path.setFillRule(d.fillRule);
if (m_api == QSGRendererInterface::Unknown)
@@ -342,13 +354,14 @@ void QQuickShapeGenericRenderer::endSync(bool async)
d.pendingFill = r;
r->path = d.path;
r->fillColor = d.fillColor;
- r->supportsElementIndexUint = q_supportsElementIndexUint(m_api);
+ r->supportsElementIndexUint = supportsElementIndexUint;
+ r->triangulationScale = m_triangulationScale;
// Unlikely in practice but in theory m_sp could be
// resized. Therefore, capture 'i' instead of 'd'.
QObject::connect(r, &QQuickShapeFillRunnable::done, qApp, [this, i](QQuickShapeFillRunnable *r) {
// Bail out when orphaned (meaning either another run was
// started after this one, or the renderer got destroyed).
- if (!r->orphaned && i < m_sp.count()) {
+ if (!r->orphaned && i < m_sp.size()) {
ShapePathData &d(m_sp[i]);
d.fillVertices = r->fillVertices;
d.fillIndices = r->fillIndices;
@@ -361,10 +374,15 @@ void QQuickShapeGenericRenderer::endSync(bool async)
});
didKickOffAsync = true;
#if QT_CONFIG(thread)
+ // qtVectorPathForPath() initializes a unique_ptr without locking.
+ // Do that before starting the threads as otherwise we get a race condition.
+ qtVectorPathForPath(r->path);
pathWorkThreadPool->start(r);
#endif
} else {
- triangulateFill(d.path, d.fillColor, &d.fillVertices, &d.fillIndices, &d.indexType, q_supportsElementIndexUint(m_api));
+ triangulateFill(d.path, d.fillColor, &d.fillVertices, &d.fillIndices, &d.indexType,
+ supportsElementIndexUint,
+ m_triangulationScale);
}
}
@@ -379,8 +397,9 @@ void QQuickShapeGenericRenderer::endSync(bool async)
r->pen = d.pen;
r->strokeColor = d.strokeColor;
r->clipSize = QSize(m_item->width(), m_item->height());
+ r->triangulationScale = m_triangulationScale;
QObject::connect(r, &QQuickShapeStrokeRunnable::done, qApp, [this, i](QQuickShapeStrokeRunnable *r) {
- if (!r->orphaned && i < m_sp.count()) {
+ if (!r->orphaned && i < m_sp.size()) {
ShapePathData &d(m_sp[i]);
d.strokeVertices = r->strokeVertices;
d.pendingStroke = nullptr;
@@ -391,11 +410,14 @@ void QQuickShapeGenericRenderer::endSync(bool async)
});
didKickOffAsync = true;
#if QT_CONFIG(thread)
+ // qtVectorPathForPath() initializes a unique_ptr without locking.
+ // Do that before starting the threads as otherwise we get a race condition.
+ qtVectorPathForPath(r->path);
pathWorkThreadPool->start(r);
#endif
} else {
triangulateStroke(d.path, d.pen, d.strokeColor, &d.strokeVertices,
- QSize(m_item->width(), m_item->height()));
+ QSize(m_item->width(), m_item->height()), m_triangulationScale);
}
}
}
@@ -406,7 +428,7 @@ void QQuickShapeGenericRenderer::endSync(bool async)
void QQuickShapeGenericRenderer::maybeUpdateAsyncItem()
{
- for (const ShapePathData &d : qAsConst(m_sp)) {
+ for (const ShapePathData &d : std::as_const(m_sp)) {
if (d.pendingFill || d.pendingStroke)
return;
}
@@ -419,21 +441,22 @@ void QQuickShapeGenericRenderer::maybeUpdateAsyncItem()
// the stroke/fill triangulation functions may be invoked either on the gui
// thread or some worker thread and must thus be self-contained.
void QQuickShapeGenericRenderer::triangulateFill(const QPainterPath &path,
- const Color4ub &fillColor,
- VertexContainerType *fillVertices,
- IndexContainerType *fillIndices,
- QSGGeometry::Type *indexType,
- bool supportsElementIndexUint)
+ const Color4ub &fillColor,
+ VertexContainerType *fillVertices,
+ IndexContainerType *fillIndices,
+ QSGGeometry::Type *indexType,
+ bool supportsElementIndexUint,
+ qreal triangulationScale)
{
const QVectorPath &vp = qtVectorPathForPath(path);
- QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(TRI_SCALE, TRI_SCALE), 1, supportsElementIndexUint);
- const int vertexCount = ts.vertices.count() / 2; // just a qreal vector with x,y hence the / 2
+ QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(triangulationScale, triangulationScale), 1, supportsElementIndexUint);
+ const int vertexCount = ts.vertices.size() / 2; // just a qreal vector with x,y hence the / 2
fillVertices->resize(vertexCount);
ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(fillVertices->data());
const qreal *vsrc = ts.vertices.constData();
for (int i = 0; i < vertexCount; ++i)
- vdst[i].set(vsrc[i * 2] / TRI_SCALE, vsrc[i * 2 + 1] / TRI_SCALE, fillColor);
+ vdst[i].set(vsrc[i * 2] / triangulationScale, vsrc[i * 2 + 1] / triangulationScale, fillColor);
size_t indexByteSize;
if (ts.indices.type() == QVertexIndexVector::UnsignedShort) {
@@ -451,27 +474,28 @@ void QQuickShapeGenericRenderer::triangulateFill(const QPainterPath &path,
}
void QQuickShapeGenericRenderer::triangulateStroke(const QPainterPath &path,
- const QPen &pen,
- const Color4ub &strokeColor,
- VertexContainerType *strokeVertices,
- const QSize &clipSize)
+ const QPen &pen,
+ const Color4ub &strokeColor,
+ VertexContainerType *strokeVertices,
+ const QSize &clipSize,
+ qreal triangulationScale)
{
const QVectorPath &vp = qtVectorPathForPath(path);
const QRectF clip(QPointF(0, 0), clipSize);
- const qreal inverseScale = 1.0 / TRI_SCALE;
+ const qreal inverseScale = 1.0 / triangulationScale;
QTriangulatingStroker stroker;
stroker.setInvScale(inverseScale);
if (pen.style() == Qt::SolidLine) {
- stroker.process(vp, pen, clip, nullptr);
+ stroker.process(vp, pen, clip, {});
} else {
QDashedStrokeProcessor dashStroker;
dashStroker.setInvScale(inverseScale);
- dashStroker.process(vp, pen, clip, nullptr);
+ dashStroker.process(vp, pen, clip, {});
QVectorPath dashStroke(dashStroker.points(), dashStroker.elementCount(),
dashStroker.elementTypes(), 0);
- stroker.process(dashStroke, pen, clip, nullptr);
+ stroker.process(dashStroke, pen, clip, {});
}
if (!stroker.vertexCount()) {
@@ -525,7 +549,7 @@ void QQuickShapeGenericRenderer::updateNode()
QQuickShapeGenericNode *node = *nodePtr;
if (m_accDirty & DirtyList)
- d.effectiveDirty |= DirtyFillGeom | DirtyStrokeGeom | DirtyColor | DirtyFillGradient;
+ d.effectiveDirty |= DirtyFillGeom | DirtyStrokeGeom | DirtyColor | DirtyFillGradient | DirtyFillTransform | DirtyFillTexture;
if (!d.effectiveDirty) {
prevNode = node;
@@ -579,13 +603,43 @@ void QQuickShapeGenericRenderer::updateShadowDataInNode(ShapePathData *d, QQuick
if (d->effectiveDirty & DirtyFillGradient)
n->m_fillGradient = d->fillGradient;
}
+ if (d->effectiveDirty & DirtyFillTexture) {
+ bool needsUpdate = d->fillTextureProviderItem == nullptr && n->m_fillTextureProvider != nullptr;
+ if (!needsUpdate
+ && d->fillTextureProviderItem != nullptr
+ && n->m_fillTextureProvider != d->fillTextureProviderItem->textureProvider()) {
+ needsUpdate = true;
+ }
+
+ if (needsUpdate) {
+ if (n->m_fillTextureProvider != nullptr) {
+ QObject::disconnect(n->m_fillTextureProvider, &QSGTextureProvider::textureChanged,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureChanged);
+ QObject::disconnect(n->m_fillTextureProvider, &QSGTextureProvider::destroyed,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed);
+ }
+
+ n->m_fillTextureProvider = d->fillTextureProviderItem == nullptr
+ ? nullptr
+ : d->fillTextureProviderItem->textureProvider();
+
+ if (n->m_fillTextureProvider != nullptr) {
+ QObject::connect(n->m_fillTextureProvider, &QSGTextureProvider::textureChanged,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureChanged);
+ QObject::connect(n->m_fillTextureProvider, &QSGTextureProvider::destroyed,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed);
+ }
+ }
+ }
+ if (d->effectiveDirty & DirtyFillTransform)
+ n->m_fillTransform = d->fillTransform;
}
void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node)
{
if (!node->m_fillNode)
return;
- if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient)))
+ if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient | DirtyFillTransform | DirtyFillTexture)))
return;
// Make a copy of the data that will be accessed by the material on
@@ -615,21 +669,24 @@ void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGen
gradMat = QQuickShapeGenericStrokeFillNode::MatConicalGradient;
break;
default:
- Q_UNREACHABLE();
- return;
+ Q_UNREACHABLE_RETURN();
}
n->activateMaterial(m_item->window(), gradMat);
- if (d->effectiveDirty & DirtyFillGradient) {
+ if (d->effectiveDirty & (DirtyFillGradient | DirtyFillTransform)) {
// Gradients are implemented via a texture-based material.
n->markDirty(QSGNode::DirtyMaterial);
- // stop here if only the gradient changed; no need to touch the geometry
+ // stop here if only the gradient or filltransform changed; no need to touch the geometry
if (!(d->effectiveDirty & DirtyFillGeom))
return;
}
+ } else if (d->fillTextureProviderItem != nullptr) {
+ n->activateMaterial(m_item->window(), QQuickShapeGenericStrokeFillNode::MatTextureFill);
+ if (d->effectiveDirty & DirtyFillTexture)
+ n->markDirty(QSGNode::DirtyMaterial);
} else {
n->activateMaterial(m_item->window(), QQuickShapeGenericStrokeFillNode::MatSolidColor);
// fast path for updating only color values when no change in vertex positions
- if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom)) {
+ if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom) && d->fillTextureProviderItem == nullptr) {
ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
for (int i = 0; i < g->vertexCount(); ++i)
vdst[i].set(vdst[i].x, vdst[i].y, d->fillColor);
@@ -639,15 +696,16 @@ void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGen
}
const int indexCount = d->indexType == QSGGeometry::UnsignedShortType
- ? d->fillIndices.count() * 2 : d->fillIndices.count();
+ ? d->fillIndices.size() * 2 : d->fillIndices.size();
if (g->indexType() != d->indexType) {
g = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(),
- d->fillVertices.count(), indexCount, d->indexType);
+ d->fillVertices.size(), indexCount, d->indexType);
n->setGeometry(g);
} else {
- g->allocate(d->fillVertices.count(), indexCount);
+ g->allocate(d->fillVertices.size(), indexCount);
}
g->setDrawingMode(QSGGeometry::DrawTriangles);
+
memcpy(g->vertexData(), d->fillVertices.constData(), g->vertexCount() * g->sizeOfVertex());
memcpy(g->indexData(), d->fillIndices.constData(), g->indexCount() * g->sizeOfIndex());
@@ -686,7 +744,7 @@ void QQuickShapeGenericRenderer::updateStrokeNode(ShapePathData *d, QQuickShapeG
return;
}
- g->allocate(d->strokeVertices.count(), 0);
+ g->allocate(d->strokeVertices.size(), 0);
g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
memcpy(g->vertexData(), d->strokeVertices.constData(), g->vertexCount() * g->sizeOfVertex());
}
@@ -695,10 +753,8 @@ QSGMaterial *QQuickShapeGenericMaterialFactory::createVertexColor(QQuickWindow *
{
QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
-#if QT_CONFIG(opengl)
- if (api == QSGRendererInterface::OpenGL)
+ if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
return new QSGVertexColorMaterial;
-#endif
qWarning("Vertex-color material: Unsupported graphics API %d", api);
return nullptr;
@@ -709,12 +765,8 @@ QSGMaterial *QQuickShapeGenericMaterialFactory::createLinearGradient(QQuickWindo
{
QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
-#if QT_CONFIG(opengl)
- if (api == QSGRendererInterface::OpenGL)
+ if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
return new QQuickShapeLinearGradientMaterial(node);
-#else
- Q_UNUSED(node);
-#endif
qWarning("Linear gradient material: Unsupported graphics API %d", api);
return nullptr;
@@ -725,12 +777,8 @@ QSGMaterial *QQuickShapeGenericMaterialFactory::createRadialGradient(QQuickWindo
{
QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
-#if QT_CONFIG(opengl)
- if (api == QSGRendererInterface::OpenGL)
+ if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
return new QQuickShapeRadialGradientMaterial(node);
-#else
- Q_UNUSED(node);
-#endif
qWarning("Radial gradient material: Unsupported graphics API %d", api);
return nullptr;
@@ -741,60 +789,98 @@ QSGMaterial *QQuickShapeGenericMaterialFactory::createConicalGradient(QQuickWind
{
QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
-#if QT_CONFIG(opengl)
- if (api == QSGRendererInterface::OpenGL)
+ if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
return new QQuickShapeConicalGradientMaterial(node);
-#else
- Q_UNUSED(node);
-#endif
qWarning("Conical gradient material: Unsupported graphics API %d", api);
return nullptr;
}
-#if QT_CONFIG(opengl)
+QSGMaterial *QQuickShapeGenericMaterialFactory::createTextureFill(QQuickWindow *window,
+ QQuickShapeGenericStrokeFillNode *node)
+{
+ QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
-QSGMaterialType QQuickShapeLinearGradientShader::type;
+ if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
+ return new QQuickShapeTextureFillMaterial(node);
-QQuickShapeLinearGradientShader::QQuickShapeLinearGradientShader()
-{
- setShaderSourceFile(QOpenGLShader::Vertex,
- QStringLiteral(":/qt-project.org/shapes/shaders/lineargradient.vert"));
- setShaderSourceFile(QOpenGLShader::Fragment,
- QStringLiteral(":/qt-project.org/shapes/shaders/lineargradient.frag"));
+ qWarning("Texture fill material: Unsupported graphics API %d", api);
+ return nullptr;
}
-void QQuickShapeLinearGradientShader::initialize()
+QQuickShapeLinearGradientRhiShader::QQuickShapeLinearGradientRhiShader(int viewCount)
{
- m_opacityLoc = program()->uniformLocation("opacity");
- m_matrixLoc = program()->uniformLocation("matrix");
- m_gradStartLoc = program()->uniformLocation("gradStart");
- m_gradEndLoc = program()->uniformLocation("gradEnd");
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/lineargradient.vert.qsb"), viewCount);
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/lineargradient.frag.qsb"), viewCount);
}
-void QQuickShapeLinearGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *)
+bool QQuickShapeLinearGradientRhiShader::updateUniformData(RenderState &state,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
{
- QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(mat);
+ Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
+ QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial);
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+ Q_ASSERT(buf->size() >= 84 + 64);
+ const int shaderMatrixCount = newMaterial->viewCount();
+ const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
+
+ if (state.isMatrixDirty()) {
+ for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
+ changed = true;
+ }
+ }
- if (state.isOpacityDirty())
- program()->setUniformValue(m_opacityLoc, state.opacity());
+ QQuickShapeGenericStrokeFillNode *node = m->node();
- if (state.isMatrixDirty())
- program()->setUniformValue(m_matrixLoc, state.combinedMatrix());
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
- QQuickShapeGenericStrokeFillNode *node = m->node();
- program()->setUniformValue(m_gradStartLoc, QVector2D(node->m_fillGradient.a));
- program()->setUniformValue(m_gradEndLoc, QVector2D(node->m_fillGradient.b));
+ if (!oldMaterial || m_gradA.x() != node->m_fillGradient.a.x() || m_gradA.y() != node->m_fillGradient.a.y()) {
+ m_gradA = QVector2D(node->m_fillGradient.a.x(), node->m_fillGradient.a.y());
+ Q_ASSERT(sizeof(m_gradA) == 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_gradA, 8);
+ changed = true;
+ }
+
+ if (!oldMaterial || m_gradB.x() != node->m_fillGradient.b.x() || m_gradB.y() != node->m_fillGradient.b.y()) {
+ m_gradB = QVector2D(node->m_fillGradient.b.x(), node->m_fillGradient.b.y());
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_gradB, 8);
+ changed = true;
+ }
+
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8, &opacity, 4);
+ changed = true;
+ }
- const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread);
- QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey);
- tx->bind();
+ return changed;
}
-char const *const *QQuickShapeLinearGradientShader::attributeNames() const
+void QQuickShapeLinearGradientRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *)
{
- static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr };
- return attr;
+ if (binding != 1)
+ return;
+
+ QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial);
+ QQuickShapeGenericStrokeFillNode *node = m->node();
+ const QSGGradientCacheKey cacheKey(node->m_fillGradient.stops, QGradient::Spread(node->m_fillGradient.spread));
+ QSGTexture *t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
+ t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+ *texture = t;
+}
+
+QSGMaterialType *QQuickShapeLinearGradientMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
}
int QQuickShapeLinearGradientMaterial::compare(const QSGMaterial *other) const
@@ -808,8 +894,8 @@ int QQuickShapeLinearGradientMaterial::compare(const QSGMaterial *other) const
if (a == b)
return 0;
- const QQuickAbstractPathRenderer::GradientDesc *ga = &a->m_fillGradient;
- const QQuickAbstractPathRenderer::GradientDesc *gb = &b->m_fillGradient;
+ const QSGGradientCache::GradientDesc *ga = &a->m_fillGradient;
+ const QSGGradientCache::GradientDesc *gb = &b->m_fillGradient;
if (int d = ga->spread - gb->spread)
return d;
@@ -823,72 +909,120 @@ int QQuickShapeLinearGradientMaterial::compare(const QSGMaterial *other) const
if (int d = ga->b.y() - gb->b.y())
return d;
- if (int d = ga->stops.count() - gb->stops.count())
+ if (int d = ga->stops.size() - gb->stops.size())
return d;
- for (int i = 0; i < ga->stops.count(); ++i) {
+ for (int i = 0; i < ga->stops.size(); ++i) {
if (int d = ga->stops[i].first - gb->stops[i].first)
return d;
if (int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
return d;
}
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
return 0;
}
-QSGMaterialType QQuickShapeRadialGradientShader::type;
-
-QQuickShapeRadialGradientShader::QQuickShapeRadialGradientShader()
+QSGMaterialShader *QQuickShapeLinearGradientMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
{
- setShaderSourceFile(QOpenGLShader::Vertex,
- QStringLiteral(":/qt-project.org/shapes/shaders/radialgradient.vert"));
- setShaderSourceFile(QOpenGLShader::Fragment,
- QStringLiteral(":/qt-project.org/shapes/shaders/radialgradient.frag"));
+ Q_UNUSED(renderMode);
+ return new QQuickShapeLinearGradientRhiShader(viewCount());
}
-void QQuickShapeRadialGradientShader::initialize()
+QQuickShapeRadialGradientRhiShader::QQuickShapeRadialGradientRhiShader(int viewCount)
{
- QOpenGLShaderProgram *prog = program();
- m_opacityLoc = prog->uniformLocation("opacity");
- m_matrixLoc = prog->uniformLocation("matrix");
- m_translationPointLoc = prog->uniformLocation("translationPoint");
- m_focalToCenterLoc = prog->uniformLocation("focalToCenter");
- m_centerRadiusLoc = prog->uniformLocation("centerRadius");
- m_focalRadiusLoc = prog->uniformLocation("focalRadius");
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/radialgradient.vert.qsb"), viewCount);
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/radialgradient.frag.qsb"), viewCount);
}
-void QQuickShapeRadialGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *)
+bool QQuickShapeRadialGradientRhiShader::updateUniformData(RenderState &state,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
{
- QQuickShapeRadialGradientMaterial *m = static_cast<QQuickShapeRadialGradientMaterial *>(mat);
-
- if (state.isOpacityDirty())
- program()->setUniformValue(m_opacityLoc, state.opacity());
-
- if (state.isMatrixDirty())
- program()->setUniformValue(m_matrixLoc, state.combinedMatrix());
+ Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
+ QQuickShapeRadialGradientMaterial *m = static_cast<QQuickShapeRadialGradientMaterial *>(newMaterial);
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+ Q_ASSERT(buf->size() >= 92 + 64);
+ const int shaderMatrixCount = newMaterial->viewCount();
+ const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
+
+ if (state.isMatrixDirty()) {
+ for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
+ changed = true;
+ }
+ }
QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
const QPointF centerPoint = node->m_fillGradient.a;
const QPointF focalPoint = node->m_fillGradient.b;
const QPointF focalToCenter = centerPoint - focalPoint;
- const GLfloat centerRadius = node->m_fillGradient.v0;
- const GLfloat focalRadius = node->m_fillGradient.v1;
+ const float centerRadius = node->m_fillGradient.v0;
+ const float focalRadius = node->m_fillGradient.v1;
+
+ if (!oldMaterial || m_focalPoint.x() != focalPoint.x() || m_focalPoint.y() != focalPoint.y()) {
+ m_focalPoint = QVector2D(focalPoint.x(), focalPoint.y());
+ Q_ASSERT(sizeof(m_focalPoint) == 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_focalPoint, 8);
+ changed = true;
+ }
+
+ if (!oldMaterial || m_focalToCenter.x() != focalToCenter.x() || m_focalToCenter.y() != focalToCenter.y()) {
+ m_focalToCenter = QVector2D(focalToCenter.x(), focalToCenter.y());
+ Q_ASSERT(sizeof(m_focalToCenter) == 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_focalToCenter, 8);
+ changed = true;
+ }
+
+ if (!oldMaterial || m_centerRadius != centerRadius) {
+ m_centerRadius = centerRadius;
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8, &m_centerRadius, 4);
+ changed = true;
+ }
+
+ if (!oldMaterial || m_focalRadius != focalRadius) {
+ m_focalRadius = focalRadius;
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8 + 4, &m_focalRadius, 4);
+ changed = true;
+ }
- program()->setUniformValue(m_translationPointLoc, focalPoint);
- program()->setUniformValue(m_centerRadiusLoc, centerRadius);
- program()->setUniformValue(m_focalRadiusLoc, focalRadius);
- program()->setUniformValue(m_focalToCenterLoc, focalToCenter);
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8 + 4 + 4, &opacity, 4);
+ changed = true;
+ }
- const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread);
- QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey);
- tx->bind();
+ return changed;
}
-char const *const *QQuickShapeRadialGradientShader::attributeNames() const
+void QQuickShapeRadialGradientRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *)
{
- static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr };
- return attr;
+ if (binding != 1)
+ return;
+
+ QQuickShapeRadialGradientMaterial *m = static_cast<QQuickShapeRadialGradientMaterial *>(newMaterial);
+ QQuickShapeGenericStrokeFillNode *node = m->node();
+ const QSGGradientCacheKey cacheKey(node->m_fillGradient.stops, QGradient::Spread(node->m_fillGradient.spread));
+ QSGTexture *t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
+ t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+ *texture = t;
+}
+
+QSGMaterialType *QQuickShapeRadialGradientMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
}
int QQuickShapeRadialGradientMaterial::compare(const QSGMaterial *other) const
@@ -902,8 +1036,8 @@ int QQuickShapeRadialGradientMaterial::compare(const QSGMaterial *other) const
if (a == b)
return 0;
- const QQuickAbstractPathRenderer::GradientDesc *ga = &a->m_fillGradient;
- const QQuickAbstractPathRenderer::GradientDesc *gb = &b->m_fillGradient;
+ const QSGGradientCache::GradientDesc *ga = &a->m_fillGradient;
+ const QSGGradientCache::GradientDesc *gb = &b->m_fillGradient;
if (int d = ga->spread - gb->spread)
return d;
@@ -922,65 +1056,104 @@ int QQuickShapeRadialGradientMaterial::compare(const QSGMaterial *other) const
if (int d = ga->v1 - gb->v1)
return d;
- if (int d = ga->stops.count() - gb->stops.count())
+ if (int d = ga->stops.size() - gb->stops.size())
return d;
- for (int i = 0; i < ga->stops.count(); ++i) {
+ for (int i = 0; i < ga->stops.size(); ++i) {
if (int d = ga->stops[i].first - gb->stops[i].first)
return d;
if (int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
return d;
}
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
return 0;
}
-QSGMaterialType QQuickShapeConicalGradientShader::type;
-
-QQuickShapeConicalGradientShader::QQuickShapeConicalGradientShader()
+QSGMaterialShader *QQuickShapeRadialGradientMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
{
- setShaderSourceFile(QOpenGLShader::Vertex,
- QStringLiteral(":/qt-project.org/shapes/shaders/conicalgradient.vert"));
- setShaderSourceFile(QOpenGLShader::Fragment,
- QStringLiteral(":/qt-project.org/shapes/shaders/conicalgradient.frag"));
+ Q_UNUSED(renderMode);
+ return new QQuickShapeRadialGradientRhiShader(viewCount());
}
-void QQuickShapeConicalGradientShader::initialize()
+QQuickShapeConicalGradientRhiShader::QQuickShapeConicalGradientRhiShader(int viewCount)
{
- QOpenGLShaderProgram *prog = program();
- m_opacityLoc = prog->uniformLocation("opacity");
- m_matrixLoc = prog->uniformLocation("matrix");
- m_angleLoc = prog->uniformLocation("angle");
- m_translationPointLoc = prog->uniformLocation("translationPoint");
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/conicalgradient.vert.qsb"), viewCount);
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/conicalgradient.frag.qsb"), viewCount);
}
-void QQuickShapeConicalGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *)
+bool QQuickShapeConicalGradientRhiShader::updateUniformData(RenderState &state,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
{
- QQuickShapeConicalGradientMaterial *m = static_cast<QQuickShapeConicalGradientMaterial *>(mat);
-
- if (state.isOpacityDirty())
- program()->setUniformValue(m_opacityLoc, state.opacity());
-
- if (state.isMatrixDirty())
- program()->setUniformValue(m_matrixLoc, state.combinedMatrix());
+ Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
+ QQuickShapeConicalGradientMaterial *m = static_cast<QQuickShapeConicalGradientMaterial *>(newMaterial);
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+ Q_ASSERT(buf->size() >= 80 + 64);
+ const int shaderMatrixCount = newMaterial->viewCount();
+ const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
+
+ if (state.isMatrixDirty()) {
+ for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
+ changed = true;
+ }
+ }
QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
const QPointF centerPoint = node->m_fillGradient.a;
- const GLfloat angle = -qDegreesToRadians(node->m_fillGradient.v0);
+ const float angle = -qDegreesToRadians(node->m_fillGradient.v0);
+
+ if (!oldMaterial || m_centerPoint.x() != centerPoint.x() || m_centerPoint.y() != centerPoint.y()) {
+ m_centerPoint = QVector2D(centerPoint.x(), centerPoint.y());
+ Q_ASSERT(sizeof(m_centerPoint) == 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_centerPoint, 8);
+ changed = true;
+ }
+
+ if (!oldMaterial || m_angle != angle) {
+ m_angle = angle;
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_angle, 4);
+ changed = true;
+ }
+
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 4, &opacity, 4);
+ changed = true;
+ }
+
+ return changed;
+}
- program()->setUniformValue(m_angleLoc, angle);
- program()->setUniformValue(m_translationPointLoc, centerPoint);
+void QQuickShapeConicalGradientRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *)
+{
+ if (binding != 1)
+ return;
- const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, QQuickShapeGradient::RepeatSpread);
- QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey);
- tx->bind();
+ QQuickShapeConicalGradientMaterial *m = static_cast<QQuickShapeConicalGradientMaterial *>(newMaterial);
+ QQuickShapeGenericStrokeFillNode *node = m->node();
+ const QSGGradientCacheKey cacheKey(node->m_fillGradient.stops, QGradient::Spread(node->m_fillGradient.spread));
+ QSGTexture *t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
+ t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+ *texture = t;
}
-char const *const *QQuickShapeConicalGradientShader::attributeNames() const
+QSGMaterialType *QQuickShapeConicalGradientMaterial::type() const
{
- static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr };
- return attr;
+ static QSGMaterialType type;
+ return &type;
}
int QQuickShapeConicalGradientMaterial::compare(const QSGMaterial *other) const
@@ -994,8 +1167,8 @@ int QQuickShapeConicalGradientMaterial::compare(const QSGMaterial *other) const
if (a == b)
return 0;
- const QQuickAbstractPathRenderer::GradientDesc *ga = &a->m_fillGradient;
- const QQuickAbstractPathRenderer::GradientDesc *gb = &b->m_fillGradient;
+ const QSGGradientCache::GradientDesc *ga = &a->m_fillGradient;
+ const QSGGradientCache::GradientDesc *gb = &b->m_fillGradient;
if (int d = ga->a.x() - gb->a.x())
return d;
@@ -1005,19 +1178,161 @@ int QQuickShapeConicalGradientMaterial::compare(const QSGMaterial *other) const
if (int d = ga->v0 - gb->v0)
return d;
- if (int d = ga->stops.count() - gb->stops.count())
+ if (int d = ga->stops.size() - gb->stops.size())
return d;
- for (int i = 0; i < ga->stops.count(); ++i) {
+ for (int i = 0; i < ga->stops.size(); ++i) {
if (int d = ga->stops[i].first - gb->stops[i].first)
return d;
if (int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
return d;
}
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
return 0;
}
-#endif // QT_CONFIG(opengl)
+QSGMaterialShader *QQuickShapeConicalGradientMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
+{
+ Q_UNUSED(renderMode);
+ return new QQuickShapeConicalGradientRhiShader(viewCount());
+}
+
+QQuickShapeTextureFillRhiShader::QQuickShapeTextureFillRhiShader(int viewCount)
+{
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/texturefill.vert.qsb"), viewCount);
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/texturefill.frag.qsb"), viewCount);
+}
+
+bool QQuickShapeTextureFillRhiShader::updateUniformData(RenderState &state,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+{
+ Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
+ QQuickShapeTextureFillMaterial *m = static_cast<QQuickShapeTextureFillMaterial *>(newMaterial);
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+ const int shaderMatrixCount = newMaterial->viewCount();
+ const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
+ Q_ASSERT(buf->size() >= 64 * shaderMatrixCount + 64 + 8 + 4);
+
+ if (state.isMatrixDirty()) {
+ for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
+ changed = true;
+ }
+ }
+
+ QQuickShapeGenericStrokeFillNode *node = m->node();
+
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
+ const QSizeF boundsSize = node->m_fillTextureProvider != nullptr && node->m_fillTextureProvider->texture() != nullptr
+ ? node->m_fillTextureProvider->texture()->textureSize()
+ : QSizeF(0, 0);
+
+
+ const QVector2D boundsVector(boundsSize.width() / state.devicePixelRatio(),
+ boundsSize.height() / state.devicePixelRatio());
+ if (!oldMaterial || m_boundsSize != boundsVector) {
+ m_boundsSize = boundsVector;
+ Q_ASSERT(sizeof(m_boundsSize) == 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_boundsSize, 8);
+ changed = true;
+ }
+
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &opacity, 4);
+ changed = true;
+ }
+
+ return changed;
+}
+
+void QQuickShapeTextureFillRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *)
+{
+ if (binding != 1)
+ return;
+
+ QQuickShapeTextureFillMaterial *m = static_cast<QQuickShapeTextureFillMaterial *>(newMaterial);
+ QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (node->m_fillTextureProvider != nullptr) {
+ QSGTexture *providedTexture = node->m_fillTextureProvider->texture();
+ if (providedTexture != nullptr) {
+ if (providedTexture->isAtlasTexture()) {
+ // Create a non-atlas copy to make texture coordinate wrapping work. This
+ // texture copy is owned by the QSGTexture so memory is managed with the original
+ // texture provider.
+ QSGTexture *newTexture = providedTexture->removedFromAtlas(state.resourceUpdateBatch());
+ if (newTexture != nullptr)
+ providedTexture = newTexture;
+ }
+
+ providedTexture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+ *texture = providedTexture;
+ return;
+ }
+ }
+
+ if (m->dummyTexture() == nullptr) {
+ QSGPlainTexture *dummyTexture = new QSGPlainTexture;
+ dummyTexture->setFiltering(QSGTexture::Nearest);
+ dummyTexture->setHorizontalWrapMode(QSGTexture::Repeat);
+ dummyTexture->setVerticalWrapMode(QSGTexture::Repeat);
+ QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+ dummyTexture->setImage(img);
+ dummyTexture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+
+ m->setDummyTexture(dummyTexture);
+ }
+
+ *texture = m->dummyTexture();
+}
+
+QQuickShapeTextureFillMaterial::~QQuickShapeTextureFillMaterial()
+{
+ delete m_dummyTexture;
+}
+
+QSGMaterialType *QQuickShapeTextureFillMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+int QQuickShapeTextureFillMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ const QQuickShapeTextureFillMaterial *m = static_cast<const QQuickShapeTextureFillMaterial *>(other);
+
+ QQuickShapeGenericStrokeFillNode *a = node();
+ QQuickShapeGenericStrokeFillNode *b = m->node();
+ Q_ASSERT(a && b);
+ if (a == b)
+ return 0;
+
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
+ const qintptr diff = qintptr(a->m_fillTextureProvider) - qintptr(b->m_fillTextureProvider);
+ return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
+}
+
+QSGMaterialShader *QQuickShapeTextureFillMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
+{
+ Q_UNUSED(renderMode);
+ return new QQuickShapeTextureFillRhiShader(viewCount());
+}
QT_END_NAMESPACE
+
+#include "moc_qquickshapegenericrenderer_p.cpp"