diff options
Diffstat (limited to 'src/quickshapes')
19 files changed, 687 insertions, 149 deletions
diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp index 74cbf52a95..e8779debde 100644 --- a/src/quickshapes/qquickshape.cpp +++ b/src/quickshapes/qquickshape.cpp @@ -42,11 +42,12 @@ #include "qquickshapegenericrenderer_p.h" #include "qquickshapenvprrenderer_p.h" #include "qquickshapesoftwarerenderer_p.h" -#include <private/qsgtexture_p.h> +#include <private/qsgplaintexture_p.h> #include <private/qquicksvgparser_p.h> #include <QtGui/private/qdrawhelper_p.h> #include <QOpenGLFunctions> #include <QLoggingCategory> +#include <QtGui/private/qrhi_p.h> #if defined(QT_STATIC) static void initResources() @@ -582,12 +583,14 @@ void QQuickShapePath::resetFillGradient() \list - \li When running with the default, OpenGL backend of Qt Quick, both the - generic, triangulation-based and the NVIDIA-specific - \c{GL_NV_path_rendering} methods are available. By default only the generic - approach is used. Setting Shape.vendorExtensionsEnabled property to \c true - leads to using NV_path_rendering on NVIDIA systems, and the generic method - on others. + \li When running with the OpenGL backend of Qt Quick, both the generic, + triangulation-based and the NVIDIA-specific \c{GL_NV_path_rendering} + methods are available. By default only the generic approach is used. + Setting Shape.vendorExtensionsEnabled property to \c true leads to using + NV_path_rendering on NVIDIA systems when running directly on OpenGL, and + the generic method on others. When OpenGL is not used directly by the scene + graph, for example because it is using the graphics abstraction layer + (QRhi), only the generic shape renderer is available. \li The \c software backend is fully supported. The path is rendered via QPainter::strokePath() and QPainter::fillPath() in this case. @@ -1009,7 +1012,12 @@ void QQuickShapePrivate::createRenderer() renderer = new QQuickShapeSoftwareRenderer; break; default: - qWarning("No path backend for this graphics API yet"); + if (QSGRendererInterface::isApiRhiBased(ri->graphicsApi())) { + rendererType = QQuickShape::GeometryRenderer; + renderer = new QQuickShapeGenericRenderer(q); + } else { + qWarning("No path backend for this graphics API yet"); + } break; } } @@ -1045,7 +1053,13 @@ QSGNode *QQuickShapePrivate::createNode() static_cast<QQuickShapeSoftwareRenderNode *>(node)); break; default: - qWarning("No path backend for this graphics API yet"); + if (QSGRendererInterface::isApiRhiBased(ri->graphicsApi())) { + node = new QQuickShapeGenericNode; + static_cast<QQuickShapeGenericRenderer *>(renderer)->setRootNode( + static_cast<QQuickShapeGenericNode *>(node)); + } else { + qWarning("No path backend for this graphics API yet"); + } break; } @@ -1499,45 +1513,7 @@ void QQuickShapeConicalGradient::setAngle(qreal v) } } -#if QT_CONFIG(opengl) - -// contexts sharing with each other get the same cache instance -class QQuickShapeGradientCacheWrapper -{ -public: - QQuickShapeGradientCache *get(QOpenGLContext *context) - { - return m_resource.value<QQuickShapeGradientCache>(context); - } - -private: - QOpenGLMultiGroupSharedResource m_resource; -}; - -QQuickShapeGradientCache *QQuickShapeGradientCache::currentCache() -{ - static QQuickShapeGradientCacheWrapper qt_path_gradient_caches; - return qt_path_gradient_caches.get(QOpenGLContext::currentContext()); -} - -// let QOpenGLContext manage the lifetime of the cached textures -QQuickShapeGradientCache::~QQuickShapeGradientCache() -{ - m_cache.clear(); -} - -void QQuickShapeGradientCache::invalidateResource() -{ - m_cache.clear(); -} - -void QQuickShapeGradientCache::freeResource(QOpenGLContext *) -{ - qDeleteAll(m_cache); - m_cache.clear(); -} - -static void generateGradientColorTable(const QQuickShapeGradientCache::Key &gradient, +static void generateGradientColorTable(const QQuickShapeGradientCacheKey &gradient, uint *colorTable, int size, float opacity) { int pos = 0; @@ -1588,7 +1564,98 @@ static void generateGradientColorTable(const QQuickShapeGradientCache::Key &grad colorTable[size-1] = last_color; } -QSGTexture *QQuickShapeGradientCache::get(const Key &grad) +QQuickShapeGradientCache::~QQuickShapeGradientCache() +{ + qDeleteAll(m_textures); +} + +QQuickShapeGradientCache *QQuickShapeGradientCache::cacheForRhi(QRhi *rhi) +{ + static QHash<QRhi *, QQuickShapeGradientCache *> caches; + auto it = caches.constFind(rhi); + if (it != caches.constEnd()) + return *it; + + QQuickShapeGradientCache *cache = new QQuickShapeGradientCache; + rhi->addCleanupCallback([cache](QRhi *rhi) { + caches.remove(rhi); + delete cache; + }); + caches.insert(rhi, cache); + return cache; +} + +QSGTexture *QQuickShapeGradientCache::get(const QQuickShapeGradientCacheKey &grad) +{ + QSGPlainTexture *tx = m_textures[grad]; + if (!tx) { + static const int W = 1024; // texture size is 1024x1 + QImage gradTab(W, 1, QImage::Format_RGBA8888_Premultiplied); + generateGradientColorTable(grad, reinterpret_cast<uint *>(gradTab.bits()), W, 1.0f); + tx = new QSGPlainTexture; + tx->setImage(gradTab); + switch (grad.spread) { + case QQuickShapeGradient::PadSpread: + tx->setHorizontalWrapMode(QSGTexture::ClampToEdge); + tx->setVerticalWrapMode(QSGTexture::ClampToEdge); + break; + case QQuickShapeGradient::RepeatSpread: + tx->setHorizontalWrapMode(QSGTexture::Repeat); + tx->setVerticalWrapMode(QSGTexture::Repeat); + break; + case QQuickShapeGradient::ReflectSpread: + tx->setHorizontalWrapMode(QSGTexture::MirroredRepeat); + tx->setVerticalWrapMode(QSGTexture::MirroredRepeat); + break; + default: + qWarning("Unknown gradient spread mode %d", grad.spread); + break; + } + tx->setFiltering(QSGTexture::Linear); + m_textures[grad] = tx; + } + return tx; +} + +#if QT_CONFIG(opengl) + +// contexts sharing with each other get the same cache instance +class QQuickShapeGradientCacheWrapper +{ +public: + QQuickShapeGradientOpenGLCache *get(QOpenGLContext *context) + { + return m_resource.value<QQuickShapeGradientOpenGLCache>(context); + } + +private: + QOpenGLMultiGroupSharedResource m_resource; +}; + +QQuickShapeGradientOpenGLCache *QQuickShapeGradientOpenGLCache::currentCache() +{ + static QQuickShapeGradientCacheWrapper qt_path_gradient_caches; + return qt_path_gradient_caches.get(QOpenGLContext::currentContext()); +} + +// let QOpenGLContext manage the lifetime of the cached textures +QQuickShapeGradientOpenGLCache::~QQuickShapeGradientOpenGLCache() +{ + m_cache.clear(); +} + +void QQuickShapeGradientOpenGLCache::invalidateResource() +{ + m_cache.clear(); +} + +void QQuickShapeGradientOpenGLCache::freeResource(QOpenGLContext *) +{ + qDeleteAll(m_cache); + m_cache.clear(); +} + +QSGTexture *QQuickShapeGradientOpenGLCache::get(const QQuickShapeGradientCacheKey &grad) { QSGPlainTexture *tx = m_cache[grad]; if (!tx) { diff --git a/src/quickshapes/qquickshape_p_p.h b/src/quickshapes/qquickshape_p_p.h index bc06c8fde8..bfeb0d2f9f 100644 --- a/src/quickshapes/qquickshape_p_p.h +++ b/src/quickshapes/qquickshape_p_p.h @@ -63,6 +63,7 @@ QT_BEGIN_NAMESPACE class QSGPlainTexture; +class QRhi; class QQuickAbstractPathRenderer { @@ -186,45 +187,57 @@ public: bool syncTimingActive = false; }; -#if QT_CONFIG(opengl) +struct QQuickShapeGradientCacheKey +{ + QQuickShapeGradientCacheKey(const QGradientStops &stops, QQuickShapeGradient::SpreadMode spread) + : stops(stops), spread(spread) + { } + QGradientStops stops; + QQuickShapeGradient::SpreadMode spread; + bool operator==(const QQuickShapeGradientCacheKey &other) const + { + return spread == other.spread && stops == other.stops; + } +}; -class QQuickShapeGradientCache : public QOpenGLSharedResource +inline uint qHash(const QQuickShapeGradientCacheKey &v, uint seed = 0) { -public: - struct Key { - Key(const QGradientStops &stops, QQuickShapeGradient::SpreadMode spread) - : stops(stops), spread(spread) - { } - QGradientStops stops; - QQuickShapeGradient::SpreadMode spread; - bool operator==(const Key &other) const - { - return spread == other.spread && stops == other.stops; - } - }; + uint h = seed + v.spread; + for (int i = 0; i < 3 && i < v.stops.count(); ++i) + h += v.stops[i].second.rgba(); + return h; +} - QQuickShapeGradientCache(QOpenGLContext *context) : QOpenGLSharedResource(context->shareGroup()) { } +class QQuickShapeGradientCache +{ +public: ~QQuickShapeGradientCache(); + static QQuickShapeGradientCache *cacheForRhi(QRhi *rhi); + QSGTexture *get(const QQuickShapeGradientCacheKey &grad); + +private: + QHash<QQuickShapeGradientCacheKey, QSGPlainTexture *> m_textures; +}; + +#if QT_CONFIG(opengl) + +class QQuickShapeGradientOpenGLCache : public QOpenGLSharedResource +{ +public: + QQuickShapeGradientOpenGLCache(QOpenGLContext *context) : QOpenGLSharedResource(context->shareGroup()) { } + ~QQuickShapeGradientOpenGLCache(); void invalidateResource() override; void freeResource(QOpenGLContext *) override; - QSGTexture *get(const Key &grad); + QSGTexture *get(const QQuickShapeGradientCacheKey &grad); - static QQuickShapeGradientCache *currentCache(); + static QQuickShapeGradientOpenGLCache *currentCache(); private: - QHash<Key, QSGPlainTexture *> m_cache; + QHash<QQuickShapeGradientCacheKey, QSGPlainTexture *> m_cache; }; -inline uint qHash(const QQuickShapeGradientCache::Key &v, uint seed = 0) -{ - uint h = seed + v.spread; - for (int i = 0; i < 3 && i < v.stops.count(); ++i) - h += v.stops[i].second.rgba(); - return h; -} - #endif // QT_CONFIG(opengl) QT_END_NAMESPACE diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp index 68102f1e0a..6ddd055d85 100644 --- a/src/quickshapes/qquickshapegenericrenderer.cpp +++ b/src/quickshapes/qquickshapegenericrenderer.cpp @@ -40,13 +40,13 @@ #include "qquickshapegenericrenderer_p.h" #include <QtGui/private/qtriangulator_p.h> #include <QtGui/private/qtriangulatingstroker_p.h> +#include <QSGVertexColorMaterial> #if QT_CONFIG(thread) #include <QThreadPool> #endif #if QT_CONFIG(opengl) -#include <QSGVertexColorMaterial> #include <QOpenGLContext> #include <QOffscreenSurface> #include <QtGui/private/qopenglextensions_p.h> @@ -701,10 +701,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; @@ -715,12 +713,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; @@ -731,12 +725,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; @@ -747,12 +737,8 @@ 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; @@ -760,8 +746,6 @@ QSGMaterial *QQuickShapeGenericMaterialFactory::createConicalGradient(QQuickWind #if QT_CONFIG(opengl) -QSGMaterialType QQuickShapeLinearGradientShader::type; - QQuickShapeLinearGradientShader::QQuickShapeLinearGradientShader() { setShaderSourceFile(QOpenGLShader::Vertex, @@ -792,8 +776,8 @@ void QQuickShapeLinearGradientShader::updateState(const RenderState &state, QSGM program()->setUniformValue(m_gradStartLoc, QVector2D(node->m_fillGradient.a)); program()->setUniformValue(m_gradEndLoc, QVector2D(node->m_fillGradient.b)); - const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); - QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); + const QQuickShapeGradientCacheKey cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); + QSGTexture *tx = QQuickShapeGradientOpenGLCache::currentCache()->get(cacheKey); tx->bind(); } @@ -803,6 +787,73 @@ char const *const *QQuickShapeLinearGradientShader::attributeNames() const return attr; } +#endif // QT_CONFIG(opengl) + +QQuickShapeLinearGradientRhiShader::QQuickShapeLinearGradientRhiShader() +{ + setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/lineargradient.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/lineargradient.frag.qsb")); +} + +bool QQuickShapeLinearGradientRhiShader::updateUniformData(const RenderState &state, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) +{ + 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); + + if (state.isMatrixDirty()) { + const QMatrix4x4 m = state.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + changed = true; + } + + QQuickShapeGenericStrokeFillNode *node = m->node(); + + 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, &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() + 72, &m_gradB, 8); + changed = true; + } + + if (state.isOpacityDirty()) { + const float opacity = state.opacity(); + memcpy(buf->data() + 80, &opacity, 4); + changed = true; + } + + return changed; +} + +void QQuickShapeLinearGradientRhiShader::updateSampledImage(const RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) +{ + if (binding != 1) + return; + + QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial); + QQuickShapeGenericStrokeFillNode *node = m->node(); + const QQuickShapeGradientCacheKey cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); + QSGTexture *t = QQuickShapeGradientCache::cacheForRhi(state.rhi())->get(cacheKey); + t->updateRhiTexture(state.rhi(), state.resourceUpdateBatch()); + *texture = t; +} + +QSGMaterialType *QQuickShapeLinearGradientMaterial::type() const +{ + static QSGMaterialType type; + return &type; +} + int QQuickShapeLinearGradientMaterial::compare(const QSGMaterial *other) const { Q_ASSERT(other && type() == other->type()); @@ -842,7 +893,19 @@ int QQuickShapeLinearGradientMaterial::compare(const QSGMaterial *other) const return 0; } -QSGMaterialType QQuickShapeRadialGradientShader::type; +QSGMaterialShader *QQuickShapeLinearGradientMaterial::createShader() const +{ + if (flags().testFlag(RhiShaderWanted)) + return new QQuickShapeLinearGradientRhiShader; +#if QT_CONFIG(opengl) + else + return new QQuickShapeLinearGradientShader; +#else + return nullptr; +#endif +} + +#if QT_CONFIG(opengl) QQuickShapeRadialGradientShader::QQuickShapeRadialGradientShader() { @@ -886,8 +949,8 @@ void QQuickShapeRadialGradientShader::updateState(const RenderState &state, QSGM program()->setUniformValue(m_focalRadiusLoc, focalRadius); program()->setUniformValue(m_focalToCenterLoc, focalToCenter); - const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); - QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); + const QQuickShapeGradientCacheKey cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); + QSGTexture *tx = QQuickShapeGradientOpenGLCache::currentCache()->get(cacheKey); tx->bind(); } @@ -897,6 +960,92 @@ char const *const *QQuickShapeRadialGradientShader::attributeNames() const return attr; } +#endif // QT_CONFIG(opengl) + +QQuickShapeRadialGradientRhiShader::QQuickShapeRadialGradientRhiShader() +{ + setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/radialgradient.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/radialgradient.frag.qsb")); +} + +bool QQuickShapeRadialGradientRhiShader::updateUniformData(const RenderState &state, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) +{ + 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() >= 92); + + if (state.isMatrixDirty()) { + const QMatrix4x4 m = state.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + changed = true; + } + + QQuickShapeGenericStrokeFillNode *node = m->node(); + + const QPointF centerPoint = node->m_fillGradient.a; + const QPointF focalPoint = node->m_fillGradient.b; + const QPointF focalToCenter = centerPoint - focalPoint; + 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, &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() + 72, &m_focalToCenter, 8); + changed = true; + } + + if (!oldMaterial || m_centerRadius != centerRadius) { + m_centerRadius = centerRadius; + memcpy(buf->data() + 80, &m_centerRadius, 4); + changed = true; + } + + if (!oldMaterial || m_focalRadius != focalRadius) { + m_focalRadius = focalRadius; + memcpy(buf->data() + 84, &m_focalRadius, 4); + changed = true; + } + + if (state.isOpacityDirty()) { + const float opacity = state.opacity(); + memcpy(buf->data() + 88, &opacity, 4); + changed = true; + } + + return changed; +} + +void QQuickShapeRadialGradientRhiShader::updateSampledImage(const RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) +{ + if (binding != 1) + return; + + QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial); + QQuickShapeGenericStrokeFillNode *node = m->node(); + const QQuickShapeGradientCacheKey cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); + QSGTexture *t = QQuickShapeGradientCache::cacheForRhi(state.rhi())->get(cacheKey); + t->updateRhiTexture(state.rhi(), state.resourceUpdateBatch()); + *texture = t; +} + +QSGMaterialType *QQuickShapeRadialGradientMaterial::type() const +{ + static QSGMaterialType type; + return &type; +} + int QQuickShapeRadialGradientMaterial::compare(const QSGMaterial *other) const { Q_ASSERT(other && type() == other->type()); @@ -941,7 +1090,19 @@ int QQuickShapeRadialGradientMaterial::compare(const QSGMaterial *other) const return 0; } -QSGMaterialType QQuickShapeConicalGradientShader::type; +QSGMaterialShader *QQuickShapeRadialGradientMaterial::createShader() const +{ + if (flags().testFlag(RhiShaderWanted)) + return new QQuickShapeRadialGradientRhiShader; +#if QT_CONFIG(opengl) + else + return new QQuickShapeRadialGradientShader; +#else + return nullptr; +#endif +} + +#if QT_CONFIG(opengl) QQuickShapeConicalGradientShader::QQuickShapeConicalGradientShader() { @@ -978,8 +1139,8 @@ void QQuickShapeConicalGradientShader::updateState(const RenderState &state, QSG program()->setUniformValue(m_angleLoc, angle); program()->setUniformValue(m_translationPointLoc, centerPoint); - const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, QQuickShapeGradient::RepeatSpread); - QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); + const QQuickShapeGradientCacheKey cacheKey(node->m_fillGradient.stops, QQuickShapeGradient::RepeatSpread); + QSGTexture *tx = QQuickShapeGradientOpenGLCache::currentCache()->get(cacheKey); tx->bind(); } @@ -989,6 +1150,76 @@ char const *const *QQuickShapeConicalGradientShader::attributeNames() const return attr; } +#endif // QT_CONFIG(opengl) + +QQuickShapeConicalGradientRhiShader::QQuickShapeConicalGradientRhiShader() +{ + setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/conicalgradient.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/conicalgradient.frag.qsb")); +} + +bool QQuickShapeConicalGradientRhiShader::updateUniformData(const RenderState &state, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) +{ + 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() >= 80); + + if (state.isMatrixDirty()) { + const QMatrix4x4 m = state.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + changed = true; + } + + QQuickShapeGenericStrokeFillNode *node = m->node(); + + const QPointF centerPoint = node->m_fillGradient.a; + 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, &m_centerPoint, 8); + changed = true; + } + + if (!oldMaterial || m_angle != angle) { + m_angle = angle; + memcpy(buf->data() + 72, &m_angle, 4); + changed = true; + } + + if (state.isOpacityDirty()) { + const float opacity = state.opacity(); + memcpy(buf->data() + 76, &opacity, 4); + changed = true; + } + + return changed; +} + +void QQuickShapeConicalGradientRhiShader::updateSampledImage(const RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) +{ + if (binding != 1) + return; + + QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial); + QQuickShapeGenericStrokeFillNode *node = m->node(); + const QQuickShapeGradientCacheKey cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); + QSGTexture *t = QQuickShapeGradientCache::cacheForRhi(state.rhi())->get(cacheKey); + t->updateRhiTexture(state.rhi(), state.resourceUpdateBatch()); + *texture = t; +} + +QSGMaterialType *QQuickShapeConicalGradientMaterial::type() const +{ + static QSGMaterialType type; + return &type; +} + int QQuickShapeConicalGradientMaterial::compare(const QSGMaterial *other) const { Q_ASSERT(other && type() == other->type()); @@ -1024,6 +1255,16 @@ int QQuickShapeConicalGradientMaterial::compare(const QSGMaterial *other) const return 0; } -#endif // QT_CONFIG(opengl) +QSGMaterialShader *QQuickShapeConicalGradientMaterial::createShader() const +{ + if (flags().testFlag(RhiShaderWanted)) + return new QQuickShapeConicalGradientRhiShader; +#if QT_CONFIG(opengl) + else + return new QQuickShapeConicalGradientShader; +#else + return nullptr; +#endif +} QT_END_NAMESPACE diff --git a/src/quickshapes/qquickshapegenericrenderer_p.h b/src/quickshapes/qquickshapegenericrenderer_p.h index 9928d7ab72..3398159bf6 100644 --- a/src/quickshapes/qquickshapegenericrenderer_p.h +++ b/src/quickshapes/qquickshapegenericrenderer_p.h @@ -244,7 +244,7 @@ public: #if QT_CONFIG(opengl) -class QQuickShapeLinearGradientShader : public QSGMaterialShader + class QQuickShapeLinearGradientShader : public QSGMaterialShader { public: QQuickShapeLinearGradientShader(); @@ -253,8 +253,6 @@ public: void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; char const *const *attributeNames() const override; - static QSGMaterialType type; - private: int m_opacityLoc = -1; int m_matrixLoc = -1; @@ -262,6 +260,23 @@ private: int m_gradEndLoc = -1; }; +#endif // QT_CONFIG(opengl) + +class QQuickShapeLinearGradientRhiShader : public QSGMaterialRhiShader +{ +public: + QQuickShapeLinearGradientRhiShader(); + + bool updateUniformData(const RenderState &state, QSGMaterial *newMaterial, + QSGMaterial *oldMaterial) override; + void updateSampledImage(const RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; + +private: + QVector2D m_gradA; + QVector2D m_gradB; +}; + class QQuickShapeLinearGradientMaterial : public QSGMaterial { public: @@ -273,20 +288,12 @@ public: // the vertex data. The shader will rely on the fact that // vertexCoord.xy is the Shape-space coordinate and so no modifications // are welcome. - setFlag(Blending | RequiresFullMatrix); - } - - QSGMaterialType *type() const override - { - return &QQuickShapeLinearGradientShader::type; + setFlag(Blending | RequiresFullMatrix | SupportsRhiShader); } + QSGMaterialType *type() const override; int compare(const QSGMaterial *other) const override; - - QSGMaterialShader *createShader() const override - { - return new QQuickShapeLinearGradientShader; - } + QSGMaterialShader *createShader() const override; QQuickShapeGenericStrokeFillNode *node() const { return m_node; } @@ -294,6 +301,8 @@ private: QQuickShapeGenericStrokeFillNode *m_node; }; +#if QT_CONFIG(opengl) + class QQuickShapeRadialGradientShader : public QSGMaterialShader { public: @@ -303,8 +312,6 @@ public: void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; char const *const *attributeNames() const override; - static QSGMaterialType type; - private: int m_opacityLoc = -1; int m_matrixLoc = -1; @@ -314,26 +321,37 @@ private: int m_focalRadiusLoc = -1; }; +#endif // QT_CONFIG(opengl) + +class QQuickShapeRadialGradientRhiShader : public QSGMaterialRhiShader +{ +public: + QQuickShapeRadialGradientRhiShader(); + + bool updateUniformData(const RenderState &state, QSGMaterial *newMaterial, + QSGMaterial *oldMaterial) override; + void updateSampledImage(const RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; + +private: + QVector2D m_focalPoint; + QVector2D m_focalToCenter; + float m_centerRadius; + float m_focalRadius; +}; + class QQuickShapeRadialGradientMaterial : public QSGMaterial { public: QQuickShapeRadialGradientMaterial(QQuickShapeGenericStrokeFillNode *node) : m_node(node) { - setFlag(Blending | RequiresFullMatrix); - } - - QSGMaterialType *type() const override - { - return &QQuickShapeRadialGradientShader::type; + setFlag(Blending | RequiresFullMatrix | SupportsRhiShader); } + QSGMaterialType *type() const override; int compare(const QSGMaterial *other) const override; - - QSGMaterialShader *createShader() const override - { - return new QQuickShapeRadialGradientShader; - } + QSGMaterialShader *createShader() const override; QQuickShapeGenericStrokeFillNode *node() const { return m_node; } @@ -341,6 +359,8 @@ private: QQuickShapeGenericStrokeFillNode *m_node; }; +#if QT_CONFIG(opengl) + class QQuickShapeConicalGradientShader : public QSGMaterialShader { public: @@ -350,8 +370,6 @@ public: void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; char const *const *attributeNames() const override; - static QSGMaterialType type; - private: int m_opacityLoc = -1; int m_matrixLoc = -1; @@ -359,26 +377,35 @@ private: int m_translationPointLoc = -1; }; +#endif // QT_CONFIG(opengl) + +class QQuickShapeConicalGradientRhiShader : public QSGMaterialRhiShader +{ +public: + QQuickShapeConicalGradientRhiShader(); + + bool updateUniformData(const RenderState &state, QSGMaterial *newMaterial, + QSGMaterial *oldMaterial) override; + void updateSampledImage(const RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; + +private: + QVector2D m_centerPoint; + float m_angle; +}; + class QQuickShapeConicalGradientMaterial : public QSGMaterial { public: QQuickShapeConicalGradientMaterial(QQuickShapeGenericStrokeFillNode *node) : m_node(node) { - setFlag(Blending | RequiresFullMatrix); - } - - QSGMaterialType *type() const override - { - return &QQuickShapeConicalGradientShader::type; + setFlag(Blending | RequiresFullMatrix | SupportsRhiShader); } + QSGMaterialType *type() const override; int compare(const QSGMaterial *other) const override; - - QSGMaterialShader *createShader() const override - { - return new QQuickShapeConicalGradientShader; - } + QSGMaterialShader *createShader() const override; QQuickShapeGenericStrokeFillNode *node() const { return m_node; } @@ -386,8 +413,6 @@ private: QQuickShapeGenericStrokeFillNode *m_node; }; -#endif // QT_CONFIG(opengl) - QT_END_NAMESPACE #endif // QQUICKSHAPEGENERICRENDERER_P_H diff --git a/src/quickshapes/qquickshapenvprrenderer.cpp b/src/quickshapes/qquickshapenvprrenderer.cpp index 51af0d8961..a5b2a3467c 100644 --- a/src/quickshapes/qquickshapenvprrenderer.cpp +++ b/src/quickshapes/qquickshapenvprrenderer.cpp @@ -712,8 +712,8 @@ void QQuickShapeNvprRenderNode::renderFill(ShapePathRenderData *d) } else { Q_UNREACHABLE(); } - const QQuickShapeGradientCache::Key cacheKey(d->fillGradient.stops, spread); - QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); + const QQuickShapeGradientCacheKey cacheKey(d->fillGradient.stops, spread); + QSGTexture *tx = QQuickShapeGradientOpenGLCache::currentCache()->get(cacheKey); tx->bind(); } else { mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid); diff --git a/src/quickshapes/qtquickshapes.qrc b/src/quickshapes/qtquickshapes.qrc index f139861693..1e3dcdef4e 100644 --- a/src/quickshapes/qtquickshapes.qrc +++ b/src/quickshapes/qtquickshapes.qrc @@ -8,13 +8,19 @@ <file>shaders/lineargradient.frag</file> <file>shaders/lineargradient_core.vert</file> <file>shaders/lineargradient_core.frag</file> + <file>shaders_ng/lineargradient.vert.qsb</file> + <file>shaders_ng/lineargradient.frag.qsb</file> <file>shaders/radialgradient.vert</file> <file>shaders/radialgradient.frag</file> <file>shaders/radialgradient_core.vert</file> <file>shaders/radialgradient_core.frag</file> + <file>shaders_ng/radialgradient.vert.qsb</file> + <file>shaders_ng/radialgradient.frag.qsb</file> <file>shaders/conicalgradient.vert</file> <file>shaders/conicalgradient.frag</file> <file>shaders/conicalgradient_core.vert</file> <file>shaders/conicalgradient_core.frag</file> + <file>shaders_ng/conicalgradient.vert.qsb</file> + <file>shaders_ng/conicalgradient.frag.qsb</file> </qresource> </RCC> diff --git a/src/quickshapes/shaders_ng/compile.bat b/src/quickshapes/shaders_ng/compile.bat new file mode 100755 index 0000000000..860dc7a07a --- /dev/null +++ b/src/quickshapes/shaders_ng/compile.bat @@ -0,0 +1,45 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: 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$ +:: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o lineargradient.vert.qsb lineargradient.vert +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o lineargradient.frag.qsb lineargradient.frag +qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o radialgradient.vert.qsb radialgradient.vert +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o radialgradient.frag.qsb radialgradient.frag +qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o conicalgradient.vert.qsb conicalgradient.vert +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o conicalgradient.frag.qsb conicalgradient.frag diff --git a/src/quickshapes/shaders_ng/conicalgradient.frag b/src/quickshapes/shaders_ng/conicalgradient.frag new file mode 100644 index 0000000000..0b1e01bae2 --- /dev/null +++ b/src/quickshapes/shaders_ng/conicalgradient.frag @@ -0,0 +1,25 @@ +#version 440 + +layout(location = 0) in vec2 coord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D gradTabTexture; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + vec2 translationPoint; + float angle; + float opacity; +} ubuf; + +#define INVERSE_2PI 0.1591549430918953358 + +void main() +{ + float t; + if (abs(coord.y) == abs(coord.x)) + t = (atan(-coord.y + 0.002, coord.x) + ubuf.angle) * INVERSE_2PI; + else + t = (atan(-coord.y, coord.x) + ubuf.angle) * INVERSE_2PI; + fragColor = texture(gradTabTexture, vec2(t - floor(t), 0.5)) * ubuf.opacity; +} diff --git a/src/quickshapes/shaders_ng/conicalgradient.frag.qsb b/src/quickshapes/shaders_ng/conicalgradient.frag.qsb Binary files differnew file mode 100644 index 0000000000..9aa59ca651 --- /dev/null +++ b/src/quickshapes/shaders_ng/conicalgradient.frag.qsb diff --git a/src/quickshapes/shaders_ng/conicalgradient.vert b/src/quickshapes/shaders_ng/conicalgradient.vert new file mode 100644 index 0000000000..3db027294b --- /dev/null +++ b/src/quickshapes/shaders_ng/conicalgradient.vert @@ -0,0 +1,21 @@ +#version 440 + +layout(location = 0) in vec4 vertexCoord; +layout(location = 1) in vec4 vertexColor; + +layout(location = 0) out vec2 coord; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + vec2 translationPoint; + float angle; + float opacity; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + coord = vertexCoord.xy - ubuf.translationPoint; + gl_Position = ubuf.matrix * vertexCoord; +} diff --git a/src/quickshapes/shaders_ng/conicalgradient.vert.qsb b/src/quickshapes/shaders_ng/conicalgradient.vert.qsb Binary files differnew file mode 100644 index 0000000000..7f5985ef64 --- /dev/null +++ b/src/quickshapes/shaders_ng/conicalgradient.vert.qsb diff --git a/src/quickshapes/shaders_ng/lineargradient.frag b/src/quickshapes/shaders_ng/lineargradient.frag new file mode 100644 index 0000000000..16894fc764 --- /dev/null +++ b/src/quickshapes/shaders_ng/lineargradient.frag @@ -0,0 +1,18 @@ +#version 440 + +layout(location = 0) in float gradTabIndex; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D gradTabTexture; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + vec2 gradStart; + vec2 gradEnd; + float opacity; +} ubuf; + +void main() +{ + fragColor = texture(gradTabTexture, vec2(gradTabIndex, 0.5)) * ubuf.opacity; +} diff --git a/src/quickshapes/shaders_ng/lineargradient.frag.qsb b/src/quickshapes/shaders_ng/lineargradient.frag.qsb Binary files differnew file mode 100644 index 0000000000..470de007b5 --- /dev/null +++ b/src/quickshapes/shaders_ng/lineargradient.frag.qsb diff --git a/src/quickshapes/shaders_ng/lineargradient.vert b/src/quickshapes/shaders_ng/lineargradient.vert new file mode 100644 index 0000000000..b4eb868186 --- /dev/null +++ b/src/quickshapes/shaders_ng/lineargradient.vert @@ -0,0 +1,22 @@ +#version 440 + +layout(location = 0) in vec4 vertexCoord; +layout(location = 1) in vec4 vertexColor; + +layout(location = 0) out float gradTabIndex; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + vec2 gradStart; + vec2 gradEnd; + float opacity; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + vec2 gradVec = ubuf.gradEnd - ubuf.gradStart; + gradTabIndex = dot(gradVec, vertexCoord.xy - ubuf.gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y); + gl_Position = ubuf.matrix * vertexCoord; +} diff --git a/src/quickshapes/shaders_ng/lineargradient.vert.qsb b/src/quickshapes/shaders_ng/lineargradient.vert.qsb Binary files differnew file mode 100644 index 0000000000..8d054efbb4 --- /dev/null +++ b/src/quickshapes/shaders_ng/lineargradient.vert.qsb diff --git a/src/quickshapes/shaders_ng/radialgradient.frag b/src/quickshapes/shaders_ng/radialgradient.frag new file mode 100644 index 0000000000..411e589295 --- /dev/null +++ b/src/quickshapes/shaders_ng/radialgradient.frag @@ -0,0 +1,32 @@ +#version 440 + +layout(location = 0) in vec2 coord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D gradTabTexture; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + vec2 translationPoint; + vec2 focalToCenter; + float centerRadius; + float focalRadius; + float opacity; +} ubuf; + +void main() +{ + float rd = ubuf.centerRadius - ubuf.focalRadius; + float b = 2.0 * (rd * ubuf.focalRadius + dot(coord, ubuf.focalToCenter)); + float fmp2_m_radius2 = -ubuf.focalToCenter.x * ubuf.focalToCenter.x - ubuf.focalToCenter.y * ubuf.focalToCenter.y + rd * rd; + float inverse_2_fmp2_m_radius2 = 1.0 / (2.0 * fmp2_m_radius2); + float det = b * b - 4.0 * fmp2_m_radius2 * ((ubuf.focalRadius * ubuf.focalRadius) - dot(coord, coord)); + vec4 result = vec4(0.0); + if (det >= 0.0) { + float detSqrt = sqrt(det); + float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); + if (ubuf.focalRadius + w * (ubuf.centerRadius - ubuf.focalRadius) >= 0.0) + result = texture(gradTabTexture, vec2(w, 0.5)) * ubuf.opacity; + } + fragColor = result; +} diff --git a/src/quickshapes/shaders_ng/radialgradient.frag.qsb b/src/quickshapes/shaders_ng/radialgradient.frag.qsb Binary files differnew file mode 100644 index 0000000000..166eb2f92d --- /dev/null +++ b/src/quickshapes/shaders_ng/radialgradient.frag.qsb diff --git a/src/quickshapes/shaders_ng/radialgradient.vert b/src/quickshapes/shaders_ng/radialgradient.vert new file mode 100644 index 0000000000..08f15c4f8c --- /dev/null +++ b/src/quickshapes/shaders_ng/radialgradient.vert @@ -0,0 +1,23 @@ +#version 440 + +layout(location = 0) in vec4 vertexCoord; +layout(location = 1) in vec4 vertexColor; + +layout(location = 0) out vec2 coord; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + vec2 translationPoint; + vec2 focalToCenter; + float centerRadius; + float focalRadius; + float opacity; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + coord = vertexCoord.xy - ubuf.translationPoint; + gl_Position = ubuf.matrix * vertexCoord; +} diff --git a/src/quickshapes/shaders_ng/radialgradient.vert.qsb b/src/quickshapes/shaders_ng/radialgradient.vert.qsb Binary files differnew file mode 100644 index 0000000000..293e23947a --- /dev/null +++ b/src/quickshapes/shaders_ng/radialgradient.vert.qsb |