aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickshadereffect.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2020-06-16 13:57:10 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2020-06-18 10:23:17 +0200
commitb976a12940b52c4a5c20972802828fc50674f60f (patch)
tree77ac9d9ee622cb1521b127620b276936db90ebb9 /src/quick/items/qquickshadereffect.cpp
parentd62f11f1d04851ac07491aa3994e20607b2e2adc (diff)
ShaderEffect: vertexShader and fragmentShader are now URLs
..and so fully compatible in behavior with properties like Image.source. The main improvement here is that unlike with the old code, which incorrectly handled local file URLs, one can now write fragmentShader: "myshader.frag.qsb" which leads to picking up the file relative to the component (the .qml file), as expected. Existing code (that uses file: or qrc: URLs) will continue to work as-is. Change-Id: I89dd84b998b59ae6d5b6cb3d8a6353961ee8bb4a Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io> Reviewed-by: Christian Strømme <christian.stromme@qt.io>
Diffstat (limited to 'src/quick/items/qquickshadereffect.cpp')
-rw-r--r--src/quick/items/qquickshadereffect.cpp96
1 files changed, 46 insertions, 50 deletions
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index a19d881419..c8a43a84aa 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -45,6 +45,7 @@
#include <private/qquickwindow_p.h>
#include <private/qquickitem_p.h>
#include "qquickshadereffectmesh_p.h"
+#include <QQmlAbstractUrlInterceptor>
QT_BEGIN_NAMESPACE
@@ -330,11 +331,11 @@ public:
QQuickShaderEffectImpl(QQuickShaderEffect *item);
~QQuickShaderEffectImpl();
- QByteArray fragmentShader() const { return m_fragShader; }
- void setFragmentShader(const QByteArray &src);
+ QUrl fragmentShader() const { return m_fragShader; }
+ void setFragmentShader(const QUrl &src);
- QByteArray vertexShader() const { return m_vertShader; }
- void setVertexShader(const QByteArray &src);
+ QUrl vertexShader() const { return m_vertShader; }
+ void setVertexShader(const QUrl &src);
bool blending() const { return m_blending; }
void setBlending(bool enable);
@@ -366,7 +367,7 @@ private slots:
void markGeometryDirtyAndUpdate();
void markGeometryDirtyAndUpdateIfSupportsAtlas();
void shaderCodePrepared(bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
- const QByteArray &src, QSGGuiThreadShaderEffectManager::ShaderInfo *result);
+ const QUrl &src, QSGGuiThreadShaderEffectManager::ShaderInfo *result);
private:
QSGGuiThreadShaderEffectManager *shaderEffectManager() const;
@@ -377,7 +378,7 @@ private:
NShader
};
- bool updateShader(Shader shaderType, const QByteArray &src);
+ bool updateShader(Shader shaderType, const QUrl &src);
void updateShaderVars(Shader shaderType);
void disconnectSignals(Shader shaderType);
void clearMappers(Shader shaderType);
@@ -392,9 +393,9 @@ private:
bool m_blending;
bool m_supportsAtlasTextures;
mutable QSGGuiThreadShaderEffectManager *m_mgr;
- QByteArray m_fragShader;
+ QUrl m_fragShader;
bool m_fragNeedsUpdate;
- QByteArray m_vertShader;
+ QUrl m_vertShader;
bool m_vertNeedsUpdate;
QSGShaderEffectNode::ShaderData m_shaders[NShader];
@@ -436,56 +437,47 @@ QQuickShaderEffect::~QQuickShaderEffect()
}
/*!
- \qmlproperty string QtQuick::ShaderEffect::fragmentShader
+ \qmlproperty url QtQuick::ShaderEffect::fragmentShader
- This property holds the fragment (pixel) shader's source code or a
- reference to the pre-compiled bytecode. Some APIs, like OpenGL, always
- support runtime compilation and therefore the traditional Qt Quick way of
- inlining shader source strings is functional. Qt Quick backends for other
- APIs may however limit support to pre-compiled bytecode like SPIR-V or D3D
- shader bytecode. There the string is simply a filename, which may be a file
- in the filesystem or bundled with the executable via Qt's resource system.
+ This property contains a reference to a file with the preprocessed fragment
+ shader package, typically with an extension of \c{.qsb}. The value is
+ treated as a \l{QUrl}{URL}, similarly to other QML types, such as Image. It
+ must either be a local file or use the qrc scheme to access files embedded
+ via the Qt resource system. The URL may be absolute, or relative to the URL
+ of the component.
- With GLSL the default shader expects the texture coordinate to be passed
- from the vertex shader as \c{varying highp vec2 qt_TexCoord0}, and it
- samples from a sampler2D named \c source.
-
- \sa vertexShader, GraphicsInfo
+ \sa vertexShader
*/
-QByteArray QQuickShaderEffect::fragmentShader() const
+QUrl QQuickShaderEffect::fragmentShader() const
{
return m_impl->fragmentShader();
}
-void QQuickShaderEffect::setFragmentShader(const QByteArray &code)
+void QQuickShaderEffect::setFragmentShader(const QUrl &code)
{
m_impl->setFragmentShader(code);
}
/*!
- \qmlproperty string QtQuick::ShaderEffect::vertexShader
-
- This property holds the vertex shader's source code or a reference to the
- pre-compiled bytecode. Some APIs, like OpenGL, always support runtime
- compilation and therefore the traditional Qt Quick way of inlining shader
- source strings is functional. Qt Quick backends for other APIs may however
- limit support to pre-compiled bytecode like SPIR-V or D3D shader bytecode.
- There the string is simply a filename, which may be a file in the
- filesystem or bundled with the executable via Qt's resource system.
+ \qmlproperty url QtQuick::ShaderEffect::vertexShader
- With GLSL the default shader passes the texture coordinate along to the
- fragment shader as \c{varying highp vec2 qt_TexCoord0}.
+ This property contains a reference to a file with the preprocessed vertex
+ shader package, typically with an extension of \c{.qsb}. The value is
+ treated as a \l{QUrl}{URL}, similarly to other QML types, such as Image. It
+ must either be a local file or use the qrc scheme to access files embedded
+ via the Qt resource system. The URL may be absolute, or relative to the URL
+ of the component.
- \sa fragmentShader, GraphicsInfo
+ \sa fragmentShader
*/
-QByteArray QQuickShaderEffect::vertexShader() const
+QUrl QQuickShaderEffect::vertexShader() const
{
return m_impl->vertexShader();
}
-void QQuickShaderEffect::setVertexShader(const QByteArray &code)
+void QQuickShaderEffect::setVertexShader(const QUrl &code)
{
m_impl->setVertexShader(code);
}
@@ -708,7 +700,7 @@ QQuickShaderEffectImpl::~QQuickShaderEffectImpl()
delete m_mgr;
}
-void QQuickShaderEffectImpl::setFragmentShader(const QByteArray &src)
+void QQuickShaderEffectImpl::setFragmentShader(const QUrl &src)
{
// Compare the actual values since they are often just filenames.
// Optimizing by comparing constData() is a bad idea since seemingly static
@@ -726,7 +718,7 @@ void QQuickShaderEffectImpl::setFragmentShader(const QByteArray &src)
emit m_item->fragmentShaderChanged();
}
-void QQuickShaderEffectImpl::setVertexShader(const QByteArray &src)
+void QQuickShaderEffectImpl::setVertexShader(const QUrl &src)
{
if (m_vertShader == src)
return;
@@ -1034,27 +1026,27 @@ static inline QVariant getValueFromProperty(QObject *item, const QMetaObject *it
struct ShaderInfoCache
{
- bool contains(const QByteArray &key) const
+ bool contains(const QUrl &key) const
{
return m_shaderInfoCache.contains(key);
}
- QSGGuiThreadShaderEffectManager::ShaderInfo value(const QByteArray &key) const
+ QSGGuiThreadShaderEffectManager::ShaderInfo value(const QUrl &key) const
{
return m_shaderInfoCache.value(key);
}
- void insert(const QByteArray &key, const QSGGuiThreadShaderEffectManager::ShaderInfo &value)
+ void insert(const QUrl &key, const QSGGuiThreadShaderEffectManager::ShaderInfo &value)
{
m_shaderInfoCache.insert(key, value);
}
- QHash<QByteArray, QSGGuiThreadShaderEffectManager::ShaderInfo> m_shaderInfoCache;
+ QHash<QUrl, QSGGuiThreadShaderEffectManager::ShaderInfo> m_shaderInfoCache;
};
Q_GLOBAL_STATIC(ShaderInfoCache, shaderInfoCache)
-bool QQuickShaderEffectImpl::updateShader(Shader shaderType, const QByteArray &src)
+bool QQuickShaderEffectImpl::updateShader(Shader shaderType, const QUrl &src)
{
QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
if (!mgr)
@@ -1080,11 +1072,14 @@ bool QQuickShaderEffectImpl::updateShader(Shader shaderType, const QByteArray &s
const QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint =
shaderType == Vertex ? QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex
: QSGGuiThreadShaderEffectManager::ShaderInfo::TypeFragment;
+ QUrl loadUrl = src;
+ if (const QQmlEngine *engine = qmlEngine(m_item))
+ loadUrl = engine->interceptUrl(loadUrl, QQmlAbstractUrlInterceptor::UrlString);
// Figure out what input parameters and variables are used in the
- // shader. For file-based shader source/bytecode this is where the data
- // is pulled in from the file. Some backends may choose to do
- // source->bytecode compilation as well in this step.
- mgr->prepareShaderCode(typeHint, src, m_inProgress[shaderType]);
+ // shader. This is where the data is pulled in from the file.
+ // (however, if there is compilation involved, that happens at a
+ // later stage, up to the QRhi backend)
+ mgr->prepareShaderCode(typeHint, loadUrl, m_inProgress[shaderType]);
// the rest is handled in shaderCodePrepared()
return true;
}
@@ -1112,7 +1107,7 @@ bool QQuickShaderEffectImpl::updateShader(Shader shaderType, const QByteArray &s
}
void QQuickShaderEffectImpl::shaderCodePrepared(bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
- const QByteArray &src, QSGGuiThreadShaderEffectManager::ShaderInfo *result)
+ const QUrl &src, QSGGuiThreadShaderEffectManager::ShaderInfo *result)
{
const Shader shaderType = typeHint == QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex ? Vertex : Fragment;
@@ -1128,7 +1123,8 @@ void QQuickShaderEffectImpl::shaderCodePrepared(bool ok, QSGGuiThreadShaderEffec
m_inProgress[shaderType] = nullptr;
if (!ok) {
- qWarning("ShaderEffect: shader preparation failed for %s\n%s\n", src.constData(), qPrintable(log()));
+ qWarning("ShaderEffect: shader preparation failed for %s\n%s\n",
+ qPrintable(src.toString()), qPrintable(log()));
m_shaders[shaderType].hasShaderCode = false;
return;
}