aboutsummaryrefslogtreecommitdiffstats
path: root/src/quickshapes
diff options
context:
space:
mode:
Diffstat (limited to 'src/quickshapes')
-rw-r--r--src/quickshapes/CMakeLists.txt9
-rw-r--r--src/quickshapes/qquickshape.cpp174
-rw-r--r--src/quickshapes/qquickshape_p.h1
-rw-r--r--src/quickshapes/qquickshape_p_p.h65
-rw-r--r--src/quickshapes/qquickshapegenericrenderer.cpp307
-rw-r--r--src/quickshapes/qquickshapegenericrenderer_p.h109
-rw-r--r--src/quickshapes/qquickshapenvprrenderer.cpp4
-rw-r--r--src/quickshapes/qtquickshapes.qrc6
-rwxr-xr-xsrc/quickshapes/shaders_ng/compile.bat45
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.frag25
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.frag.qsbbin0 -> 2228 bytes
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.vert21
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.vert.qsbbin0 -> 1994 bytes
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.frag18
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.frag.qsbbin0 -> 1762 bytes
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.vert22
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.vert.qsbbin0 -> 2225 bytes
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.frag32
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.frag.qsbbin0 -> 2931 bytes
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.vert23
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.vert.qsbbin0 -> 2115 bytes
21 files changed, 710 insertions, 151 deletions
diff --git a/src/quickshapes/CMakeLists.txt b/src/quickshapes/CMakeLists.txt
index bad619a806..9c13042db8 100644
--- a/src/quickshapes/CMakeLists.txt
+++ b/src/quickshapes/CMakeLists.txt
@@ -5,6 +5,7 @@
#####################################################################
add_qt_module(QuickShapes
+ INTERNAL_MODULE
SOURCES
qquickshape.cpp qquickshape_p.h
qquickshape_p_p.h
@@ -38,7 +39,13 @@ add_qt_resource(QuickShapes "qtquickshapes" PREFIX "/qt-project.org/shapes" FILE
shaders/radialgradient.frag
shaders/radialgradient.vert
shaders/radialgradient_core.frag
- shaders/radialgradient_core.vert)
+ shaders/radialgradient_core.vert
+ shaders_ng/conicalgradient.frag.qsb
+ shaders_ng/conicalgradient.vert.qsb
+ shaders_ng/lineargradient.frag.qsb
+ shaders_ng/lineargradient.vert.qsb
+ shaders_ng/radialgradient.frag.qsb
+ shaders_ng/radialgradient.vert.qsb)
#### Keys ignored in scope 1:.:.:quickshapes.pro:<TRUE>:
diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp
index 262d0b3e9a..e8779debde 100644
--- a/src/quickshapes/qquickshape.cpp
+++ b/src/quickshapes/qquickshape.cpp
@@ -42,11 +42,19 @@
#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()
+{
+ Q_INIT_RESOURCE(qtquickshapes);
+}
+#endif
QT_BEGIN_NAMESPACE
@@ -575,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.
@@ -662,7 +672,7 @@ struct QQuickShapeResourceInitializer
QQuickShapeResourceInitializer()
{
#if defined(QT_STATIC)
- Q_INIT_RESOURCE(qtquickshapes);
+ initResources();
#endif
}
};
@@ -1002,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;
}
}
@@ -1038,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;
}
@@ -1492,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;
@@ -1581,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.h b/src/quickshapes/qquickshape_p.h
index cd242cafc3..7066ea0709 100644
--- a/src/quickshapes/qquickshape_p.h
+++ b/src/quickshapes/qquickshape_p.h
@@ -213,6 +213,7 @@ class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapePath : public QQuickPath
Q_PROPERTY(qreal dashOffset READ dashOffset WRITE setDashOffset NOTIFY dashOffsetChanged)
Q_PROPERTY(QVector<qreal> dashPattern READ dashPattern WRITE setDashPattern NOTIFY dashPatternChanged)
Q_PROPERTY(QQuickShapeGradient *fillGradient READ fillGradient WRITE setFillGradient RESET resetFillGradient)
+ Q_PROPERTY(QSizeF scale READ scale WRITE setScale NOTIFY scaleChanged REVISION 14)
public:
enum FillRule {
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 604da2a889..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>
@@ -361,6 +361,9 @@ 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 {
@@ -391,6 +394,9 @@ 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 {
@@ -695,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;
@@ -709,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;
@@ -725,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;
@@ -741,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;
@@ -754,8 +746,6 @@ QSGMaterial *QQuickShapeGenericMaterialFactory::createConicalGradient(QQuickWind
#if QT_CONFIG(opengl)
-QSGMaterialType QQuickShapeLinearGradientShader::type;
-
QQuickShapeLinearGradientShader::QQuickShapeLinearGradientShader()
{
setShaderSourceFile(QOpenGLShader::Vertex,
@@ -786,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();
}
@@ -797,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());
@@ -836,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()
{
@@ -880,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();
}
@@ -891,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());
@@ -935,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()
{
@@ -972,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();
}
@@ -983,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());
@@ -1018,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
new file mode 100644
index 0000000000..9aa59ca651
--- /dev/null
+++ b/src/quickshapes/shaders_ng/conicalgradient.frag.qsb
Binary files differ
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
new file mode 100644
index 0000000000..7f5985ef64
--- /dev/null
+++ b/src/quickshapes/shaders_ng/conicalgradient.vert.qsb
Binary files differ
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
new file mode 100644
index 0000000000..470de007b5
--- /dev/null
+++ b/src/quickshapes/shaders_ng/lineargradient.frag.qsb
Binary files differ
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
new file mode 100644
index 0000000000..8d054efbb4
--- /dev/null
+++ b/src/quickshapes/shaders_ng/lineargradient.vert.qsb
Binary files differ
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
new file mode 100644
index 0000000000..166eb2f92d
--- /dev/null
+++ b/src/quickshapes/shaders_ng/radialgradient.frag.qsb
Binary files differ
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
new file mode 100644
index 0000000000..293e23947a
--- /dev/null
+++ b/src/quickshapes/shaders_ng/radialgradient.vert.qsb
Binary files differ