aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-04-26 12:47:59 +0200
committerLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-04-29 09:36:36 +0000
commit96cdc5be2aa0cf87033591cfd76661291b3f6933 (patch)
treefeac67a35952fcaf9b64db0a4b227957852b66d0 /src
parente88e2940598086b57e6c844afa2eca4153d0f528 (diff)
D3D12: Long Live Wobble!
D3D12 shader effect node. Cull mode, atlas (qt_SubRect_*) support, and some nice-to-haves are currently missing. The built-in shaders won't yet work due to not sending 'source' down the stack so both have to be application-supplied. Nonetheless..the wobble test works! Change-Id: If4cd0143fa5794a8d5f89b576ffcfb084efeb343 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials_p.h10
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp3
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp608
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h76
-rw-r--r--src/plugins/scenegraph/d3d12/shaders/shadereffectdefault.hlsl27
-rw-r--r--src/plugins/scenegraph/d3d12/shaders/shaders.pri13
-rw-r--r--src/quick/items/qquickgenericshadereffect.cpp27
-rw-r--r--src/quick/items/qquickgenericshadereffect_p.h2
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp15
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h29
10 files changed, 769 insertions, 41 deletions
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials_p.h
index 8a475ddb77..6786d8fc06 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12builtinmaterials_p.h
@@ -66,7 +66,7 @@ public:
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
- virtual int constantBufferSize() const override;
+ int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const RenderState &state,
QSGD3D12PipelineState *pipelineState,
@@ -84,7 +84,7 @@ public:
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
- virtual int constantBufferSize() const override;
+ int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const RenderState &state,
QSGD3D12PipelineState *pipelineState,
@@ -101,7 +101,7 @@ public:
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
- virtual int constantBufferSize() const override;
+ int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const RenderState &state,
QSGD3D12PipelineState *pipelineState,
@@ -141,7 +141,7 @@ public:
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
- virtual int constantBufferSize() const override;
+ int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const RenderState &state,
QSGD3D12PipelineState *pipelineState,
@@ -189,7 +189,7 @@ public:
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
- virtual int constantBufferSize() const override;
+ int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const RenderState &state,
QSGD3D12PipelineState *pipelineState,
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
index 2c05ce01c6..83ba443800 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
@@ -41,6 +41,7 @@
#include "qsgd3d12engine_p.h"
#include "qsgd3d12context_p.h"
#include "qsgd3d12rendercontext_p.h"
+#include "qsgd3d12shadereffectnode_p.h"
#include <private/qsgrenderer_p.h>
#include <private/qquickwindow_p.h>
#include <private/qquickprofiler_p.h>
@@ -336,6 +337,7 @@ bool QSGD3D12RenderThread::event(QEvent *e)
engine->waitGPU();
// Bye bye nodes...
wd->cleanupNodesOnShutdown();
+ QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
}
rc->invalidate();
QCoreApplication::processEvents();
@@ -486,6 +488,7 @@ void QSGD3D12RenderThread::sync(bool inExpose)
if (Q_UNLIKELY(debug_loop()))
qDebug("RT - sync - device was lost, resetting scenegraph");
QQuickWindowPrivate::get(exposedWindow)->cleanupNodesOnShutdown();
+ QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
rc->invalidate();
}
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp
index 49f517f877..a94cdf2827 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp
@@ -42,10 +42,14 @@
#include "qsgd3d12engine_p.h"
#include <QtCore/qfile.h>
#include <QtQml/qqmlfile.h>
+#include <qsgtextureprovider.h>
#include <d3d12shader.h>
#include <d3dcompiler.h>
+#include "vs_shadereffectdefault.hlslh"
+#include "ps_shadereffectdefault.hlslh"
+
QT_BEGIN_NAMESPACE
// NOTE: Avoid categorized logging. It is slow.
@@ -56,19 +60,432 @@ QT_BEGIN_NAMESPACE
DECLARE_DEBUG_VAR(render)
+void QSGD3D12ShaderLinker::reset(const QByteArray &vertBlob, const QByteArray &fragBlob)
+{
+ Q_ASSERT(!vertBlob.isEmpty() && !fragBlob.isEmpty());
+ vs = vertBlob;
+ fs = fragBlob;
+
+ error = false;
+
+ constantBufferSize = 0;
+ constants.clear();
+ samplers.clear();
+ textures.clear();
+}
+
+void QSGD3D12ShaderLinker::feedVertexInput(const QSGShaderEffectNode::ShaderData &shader)
+{
+ bool foundPos = false, foundTexCoord = false;
+
+ for (const auto &ip : qAsConst(shader.shaderInfo.inputParameters)) {
+ if (ip.semanticName == QByteArrayLiteral("POSITION"))
+ foundPos = true;
+ else if (ip.semanticName == QByteArrayLiteral("TEXCOORD"))
+ foundTexCoord = true;
+ }
+
+ if (!foundPos) {
+ qWarning("ShaderEffect: No POSITION input found.");
+ error = true;
+ }
+ if (!foundTexCoord) {
+ qWarning("ShaderEffect: No TEXCOORD input found.");
+ error = true;
+ }
+
+ // Nothing else to do here, the QSGGeometry::AttributeSet decides anyway
+ // and that is already generated by QQuickShaderEffectMesh via
+ // QSGGeometry::defaultAttributes_TexturedPoint2D() and has the semantics
+ // so it will just work.
+}
+
+void QSGD3D12ShaderLinker::feedConstants(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices)
+{
+ Q_ASSERT(shader.shaderInfo.variables.count() == shader.varData.count());
+ if (!dirtyIndices) {
+ constantBufferSize = qMax(constantBufferSize, shader.shaderInfo.constantDataSize);
+ for (int i = 0; i < shader.shaderInfo.variables.count(); ++i) {
+ const auto &var(shader.shaderInfo.variables.at(i));
+ if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Constant) {
+ const auto &vd(shader.varData.at(i));
+ Constant c;
+ c.size = var.size;
+ c.specialType = vd.specialType;
+ c.value = vd.value;
+ constants[var.offset] = c;
+ }
+ }
+ } else {
+ for (int idx : *dirtyIndices)
+ constants[shader.shaderInfo.variables.at(idx).offset].value = shader.varData.at(idx).value;
+ }
+}
+
+void QSGD3D12ShaderLinker::feedSamplers(const QSGShaderEffectNode::ShaderData &shader)
+{
+ for (int i = 0; i < shader.shaderInfo.variables.count(); ++i) {
+ const auto &var(shader.shaderInfo.variables.at(i));
+ if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
+ const auto &vd(shader.varData.at(i));
+ Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Unused);
+ samplers.insert(var.bindPoint);
+ }
+ }
+}
+
+void QSGD3D12ShaderLinker::feedTextures(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices)
+{
+ if (!dirtyIndices) {
+ for (int i = 0; i < shader.shaderInfo.variables.count(); ++i) {
+ const auto &var(shader.shaderInfo.variables.at(i));
+ const auto &vd(shader.varData.at(i));
+ if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Texture) {
+ Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Source);
+ textures.insert(var.bindPoint, vd.value);
+ }
+ }
+ } else {
+ for (int idx : *dirtyIndices)
+ textures.insert(shader.shaderInfo.variables.at(idx).bindPoint, shader.varData.at(idx).value);
+ }
+}
+
+void QSGD3D12ShaderLinker::dump()
+{
+ if (error) {
+ qDebug() << "Failed to generate program data";
+ return;
+ }
+ qDebug() << "Combined shader data" << vs.size() << fs.size() << "cbuffer size" << constantBufferSize;
+ qDebug() << " - constants" << constants;
+ qDebug() << " - samplers" << samplers;
+ qDebug() << " - textures" << textures;
+}
+
+QDebug operator<<(QDebug debug, const QSGD3D12ShaderLinker::Constant &c)
+{
+ QDebugStateSaver saver(debug);
+ debug.space();
+ debug << "size" << c.size;
+ if (c.specialType != QSGShaderEffectNode::VariableData::None)
+ debug << "special" << c.specialType;
+ else
+ debug << "value" << c.value;
+ return debug;
+}
+
+QSGD3D12ShaderEffectMaterial::QSGD3D12ShaderEffectMaterial(QSGD3D12ShaderEffectNode *node)
+ : node(node)
+{
+ setFlag(Blending | RequiresFullMatrix, true); // may be changed in sync()
+}
+
+struct QSGD3D12ShaderMaterialTypeCache
+{
+ QSGMaterialType *get(const QByteArray &vs, const QByteArray &fs);
+ void reset() { qDeleteAll(m_types); m_types.clear(); }
+
+ struct Key {
+ QByteArray blob[2];
+ Key() { }
+ Key(const QByteArray &vs, const QByteArray &fs) { blob[0] = vs; blob[1] = fs; }
+ bool operator==(const Key &other) const {
+ return blob[0] == other.blob[0] && blob[1] == other.blob[1];
+ }
+ };
+ QHash<Key, QSGMaterialType *> m_types;
+};
+
+uint qHash(const QSGD3D12ShaderMaterialTypeCache::Key &key, uint seed = 0)
+{
+ uint hash = seed;
+ for (int i = 0; i < 2; ++i)
+ hash = hash * 31337 + qHash(key.blob[i]);
+ return hash;
+}
+
+QSGMaterialType *QSGD3D12ShaderMaterialTypeCache::get(const QByteArray &vs, const QByteArray &fs)
+{
+ const Key k(vs, fs);
+ if (m_types.contains(k))
+ return m_types.value(k);
+
+ QSGMaterialType *t = new QSGMaterialType;
+ m_types.insert(k, t);
+ return t;
+}
+
+Q_GLOBAL_STATIC(QSGD3D12ShaderMaterialTypeCache, shaderMaterialTypeCache)
+
+void QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache()
+{
+ shaderMaterialTypeCache()->reset();
+}
+
+QSGMaterialType *QSGD3D12ShaderEffectMaterial::type() const
+{
+ return mtype;
+}
+
+int QSGD3D12ShaderEffectMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ const QSGD3D12ShaderEffectMaterial *o = static_cast<const QSGD3D12ShaderEffectMaterial *>(other);
+
+ if (int diff = cullMode - o->cullMode)
+ return diff;
+
+ if (int diff = textureProviders.count() - o->textureProviders.count())
+ return diff;
+
+ if (linker.constants != o->linker.constants)
+ return 1;
+
+ for (int i = 0; i < textureProviders.count(); ++i) {
+ QSGTextureProvider *tp1 = textureProviders.at(i);
+ QSGTextureProvider *tp2 = o->textureProviders.at(i);
+ if (!tp1 || !tp2)
+ return tp1 == tp2 ? 0 : 1;
+ QSGTexture *t1 = tp1->texture();
+ QSGTexture *t2 = tp2->texture();
+ if (!t1 || !t2)
+ return t1 == t2 ? 0 : 1;
+ if (int diff = t1->textureId() - t2->textureId())
+ return diff;
+ }
+
+ return 0;
+}
+
+int QSGD3D12ShaderEffectMaterial::constantBufferSize() const
+{
+ return linker.constantBufferSize;
+}
+
+void QSGD3D12ShaderEffectMaterial::preparePipeline(QSGD3D12PipelineState *pipelineState)
+{
+ pipelineState->shaders.vs = reinterpret_cast<const quint8 *>(linker.vs.constData());
+ pipelineState->shaders.vsSize = linker.vs.size();
+ pipelineState->shaders.ps = reinterpret_cast<const quint8 *>(linker.fs.constData());
+ pipelineState->shaders.psSize = linker.fs.size();
+
+ pipelineState->shaders.rootSig.textureViews.resize(textureProviders.count());
+}
+
+static inline QColor qsg_premultiply_color(const QColor &c)
+{
+ return QColor::fromRgbF(c.redF() * c.alphaF(), c.greenF() * c.alphaF(), c.blueF() * c.alphaF(), c.alphaF());
+}
+
+QSGD3D12Material::UpdateResults QSGD3D12ShaderEffectMaterial::updatePipeline(const RenderState &state,
+ QSGD3D12PipelineState *,
+ ExtraState *,
+ quint8 *constantBuffer)
+{
+ QSGD3D12Material::UpdateResults r = 0;
+ quint8 *p = constantBuffer;
+
+ for (auto it = linker.constants.constBegin(), itEnd = linker.constants.constEnd(); it != itEnd; ++it) {
+ quint8 *dst = p + it.key();
+ const QSGD3D12ShaderLinker::Constant &c(it.value());
+ if (c.specialType == QSGShaderEffectNode::VariableData::Opacity) {
+ if (state.isOpacityDirty()) {
+ const float f = state.opacity();
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, &f, sizeof(f));
+ r |= UpdatedConstantBuffer;
+ }
+ } else if (c.specialType == QSGShaderEffectNode::VariableData::Matrix) {
+ if (state.isMatrixDirty()) {
+ const int sz = 16 * sizeof(float);
+ Q_ASSERT(sz == c.size);
+ memcpy(dst, state.combinedMatrix().constData(), sz);
+ r |= UpdatedConstantBuffer;
+ }
+ } else if (c.specialType == QSGShaderEffectNode::VariableData::None) {
+ r |= UpdatedConstantBuffer;
+ switch (c.value.type()) {
+ case QMetaType::QColor: {
+ const QColor v = qsg_premultiply_color(qvariant_cast<QColor>(c.value));
+ const float f[4] = { float(v.redF()), float(v.greenF()), float(v.blueF()), float(v.alphaF()) };
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, f, sizeof(f));
+ break;
+ }
+ case QMetaType::Float: {
+ const float f = qvariant_cast<float>(c.value);
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, &f, sizeof(f));
+ break;
+ }
+ case QMetaType::Double: {
+ const float f = float(qvariant_cast<double>(c.value));
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, &f, sizeof(f));
+ break;
+ }
+ case QMetaType::Int: {
+ const int i = c.value.toInt();
+ Q_ASSERT(sizeof(i) == c.size);
+ memcpy(dst, &i, sizeof(i));
+ break;
+ }
+ case QMetaType::Bool: {
+ const bool b = c.value.toBool();
+ Q_ASSERT(sizeof(b) == c.size);
+ memcpy(dst, &b, sizeof(b));
+ break;
+ }
+ case QMetaType::QTransform: { // float3x3
+ const QTransform v = qvariant_cast<QTransform>(c.value);
+ const float m[3][3] = {
+ { float(v.m11()), float(v.m12()), float(v.m13()) },
+ { float(v.m21()), float(v.m22()), float(v.m23()) },
+ { float(v.m31()), float(v.m32()), float(v.m33()) }
+ };
+ Q_ASSERT(sizeof(m) == c.size);
+ memcpy(dst, m[0], sizeof(m));
+ break;
+ }
+ case QMetaType::QSize:
+ case QMetaType::QSizeF: { // float2
+ const QSizeF v = c.value.toSizeF();
+ const float f[2] = { float(v.width()), float(v.height()) };
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, f, sizeof(f));
+ break;
+ }
+ case QMetaType::QPoint:
+ case QMetaType::QPointF: { // float2
+ const QPointF v = c.value.toPointF();
+ const float f[2] = { float(v.x()), float(v.y()) };
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, f, sizeof(f));
+ break;
+ }
+ case QMetaType::QRect:
+ case QMetaType::QRectF: { // float4
+ const QRectF v = c.value.toRectF();
+ const float f[4] = { float(v.x()), float(v.y()), float(v.width()), float(v.height()) };
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, f, sizeof(f));
+ break;
+ }
+ case QMetaType::QVector2D: { // float2
+ const QVector2D v = qvariant_cast<QVector2D>(c.value);
+ const float f[2] = { float(v.x()), float(v.y()) };
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, f, sizeof(f));
+ break;
+ }
+ case QMetaType::QVector3D: { // float3
+ const QVector3D v = qvariant_cast<QVector3D>(c.value);
+ const float f[3] = { float(v.x()), float(v.y()), float(v.z()) };
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, f, sizeof(f));
+ break;
+ }
+ case QMetaType::QVector4D: { // float4
+ const QVector4D v = qvariant_cast<QVector4D>(c.value);
+ const float f[4] = { float(v.x()), float(v.y()), float(v.z()), float(v.w()) };
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, f, sizeof(f));
+ break;
+ }
+ case QMetaType::QQuaternion: { // float4
+ const QQuaternion v = qvariant_cast<QQuaternion>(c.value);
+ const float f[4] = { float(v.x()), float(v.y()), float(v.z()), float(v.scalar()) };
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, f, sizeof(f));
+ break;
+ }
+ case QMetaType::QMatrix4x4: { // float4x4
+ const QMatrix4x4 v = qvariant_cast<QMatrix4x4>(c.value);
+ const int sz = 16 * sizeof(float);
+ Q_ASSERT(sz == c.size);
+ memcpy(dst, v.constData(), sz);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ for (QSGTextureProvider *tp : textureProviders) {
+ if (tp) {
+ if (QSGTexture *t = tp->texture())
+ t->bind();
+ }
+ // ### have a dummy in case the texture provider is null
+ }
+
+ // ### cull mode
+
+ return r;
+}
+
+void QSGD3D12ShaderEffectMaterial::updateTextureProviders(bool layoutChange)
+{
+ if (layoutChange) {
+ for (QSGTextureProvider *tp : textureProviders) {
+ if (tp) {
+ QObject::disconnect(tp, SIGNAL(textureChanged()), node,
+ SLOT(handleTextureChange()));
+ QObject::disconnect(tp, SIGNAL(destroyed(QObject*)), node,
+ SLOT(handleTextureProviderDestroyed(QObject*)));
+ }
+ }
+
+ textureProviders.fill(nullptr, linker.textures.count());
+ }
+
+ for (auto it = linker.textures.constBegin(), itEnd = linker.textures.constEnd(); it != itEnd; ++it) {
+ const int bindPoint = it.key();
+ // Now that the linker has merged the textures, we can switch over to a
+ // simple vector indexed by the binding point for textureProviders.
+ Q_ASSERT(bindPoint >= 0 && bindPoint < textureProviders.count());
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(it.value()));
+ QSGTextureProvider *newProvider = source && source->isTextureProvider() ? source->textureProvider() : nullptr;
+ QSGTextureProvider *&activeProvider(textureProviders[bindPoint]);
+ if (newProvider != activeProvider) {
+ if (activeProvider) {
+ QObject::disconnect(activeProvider, SIGNAL(textureChanged()), node,
+ SLOT(handleTextureChange()));
+ QObject::disconnect(activeProvider, SIGNAL(destroyed(QObject*)), node,
+ SLOT(handleTextureProviderDestroyed(QObject*)));
+ }
+ if (newProvider) {
+ Q_ASSERT_X(newProvider->thread() == QThread::currentThread(),
+ "QSGD3D12ShaderEffectMaterial::updateTextureProviders",
+ "Texture provider must belong to the rendering thread");
+ QObject::connect(newProvider, SIGNAL(textureChanged()), node, SLOT(handleTextureChange()));
+ QObject::connect(newProvider, SIGNAL(destroyed(QObject*)), node,
+ SLOT(handleTextureProviderDestroyed(QObject*)));
+ } else {
+ const char *typeName = source ? source->metaObject()->className() : it.value().typeName();
+ qWarning("ShaderEffect: Texture t%d is not assigned a valid texture provider (%s).",
+ bindPoint, typeName);
+ }
+ activeProvider = newProvider;
+ }
+ }
+}
+
QSGD3D12ShaderEffectNode::QSGD3D12ShaderEffectNode(QSGD3D12RenderContext *rc, QSGD3D12GuiThreadShaderEffectManager *mgr)
: QSGShaderEffectNode(mgr),
m_rc(rc),
- m_mgr(mgr)
+ m_mgr(mgr),
+ m_material(this)
{
- // ### no material yet, it will just crash
- //setMaterial(&m_material);
+ setFlag(UsePreprocess, true);
+ setMaterial(&m_material);
}
QRectF QSGD3D12ShaderEffectNode::normalizedTextureSubRect() const
{
- return QRectF(0, 0, 1, 1);
- // ###
+ return QRectF(0, 1, 1, -1); // ###
}
void QSGD3D12ShaderEffectNode::sync(SyncData *syncData)
@@ -76,7 +493,170 @@ void QSGD3D12ShaderEffectNode::sync(SyncData *syncData)
if (Q_UNLIKELY(debug_render()))
qDebug() << "shadereffect node sync" << syncData->dirty;
- // ###
+ if (bool(m_material.flags() & QSGMaterial::Blending) != syncData->blending) {
+ m_material.setFlag(QSGMaterial::Blending, syncData->blending);
+ markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (m_material.cullMode != syncData->cullMode) {
+ m_material.cullMode = syncData->cullMode;
+ markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (syncData->dirty & QSGShaderEffectNode::DirtyShaders) {
+ QByteArray vertBlob, fragBlob;
+
+ m_material.hasCustomVertexShader = syncData->vertex.shader->valid;
+ if (m_material.hasCustomVertexShader) {
+ vertBlob = syncData->vertex.shader->shaderInfo.blob;
+ } else {
+ vertBlob = QByteArray::fromRawData(reinterpret_cast<const char *>(g_VS_DefaultShaderEffect),
+ sizeof(g_VS_DefaultShaderEffect));
+ }
+
+ m_material.hasCustomFragmentShader = syncData->fragment.shader->valid;
+ if (m_material.hasCustomFragmentShader) {
+ fragBlob = syncData->fragment.shader->shaderInfo.blob;
+ } else {
+ fragBlob = QByteArray::fromRawData(reinterpret_cast<const char *>(g_PS_DefaultShaderEffect),
+ sizeof(g_PS_DefaultShaderEffect));
+ }
+
+ m_material.mtype = shaderMaterialTypeCache()->get(vertBlob, fragBlob);
+ m_material.linker.reset(vertBlob, fragBlob);
+
+ if (m_material.hasCustomVertexShader) {
+ m_material.linker.feedVertexInput(*syncData->vertex.shader);
+ m_material.linker.feedConstants(*syncData->vertex.shader);
+ m_material.linker.feedSamplers(*syncData->vertex.shader);
+ m_material.linker.feedTextures(*syncData->vertex.shader);
+ } else {
+ QSGShaderEffectNode::ShaderData defaultSD;
+ defaultSD.valid = true;
+ defaultSD.shaderInfo.blob = vertBlob;
+ defaultSD.shaderInfo.type = QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex;
+
+ QSGGuiThreadShaderEffectManager::ShaderInfo::InputParameter ip;
+ ip.semanticName = QByteArrayLiteral("POSITION");
+ defaultSD.shaderInfo.inputParameters.append(ip);
+ ip.semanticName = QByteArrayLiteral("TEXCOORD");
+ defaultSD.shaderInfo.inputParameters.append(ip);
+
+ // { float4x4 qt_Matrix; float qt_Opacity; } where only the matrix is used
+ QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
+ v.name = QByteArrayLiteral("qt_Matrix");
+ v.offset = 0;
+ v.size = 16 * sizeof(float);
+ defaultSD.shaderInfo.variables.append(v);
+ QSGShaderEffectNode::VariableData vd;
+ vd.specialType = QSGShaderEffectNode::VariableData::Matrix;
+ defaultSD.varData.append(vd);
+
+ defaultSD.shaderInfo.constantDataSize = (16 + 1) * sizeof(float);
+
+ m_material.linker.feedVertexInput(defaultSD);
+ m_material.linker.feedConstants(defaultSD);
+ }
+
+ if (m_material.hasCustomFragmentShader) {
+ m_material.linker.feedConstants(*syncData->fragment.shader);
+ m_material.linker.feedSamplers(*syncData->fragment.shader);
+ m_material.linker.feedTextures(*syncData->fragment.shader);
+ } else {
+ QSGShaderEffectNode::ShaderData defaultSD;
+ defaultSD.valid = true;
+ defaultSD.shaderInfo.blob = fragBlob;
+ defaultSD.shaderInfo.type = QSGGuiThreadShaderEffectManager::ShaderInfo::TypeFragment;
+
+ // { float4x4 qt_Matrix; float qt_Opacity; } where only the opacity is used
+ QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
+ v.name = QByteArrayLiteral("qt_Opacity");
+ v.offset = 16 * sizeof(float);
+ v.size = sizeof(float);
+ defaultSD.shaderInfo.variables.append(v);
+ QSGShaderEffectNode::VariableData vd;
+ vd.specialType = QSGShaderEffectNode::VariableData::Opacity;
+ defaultSD.varData.append(vd);
+
+ v.name = QByteArrayLiteral("source");
+ v.bindPoint = 0;
+ v.type = QSGGuiThreadShaderEffectManager::ShaderInfo::Texture;
+ defaultSD.shaderInfo.variables.append(v);
+ vd.specialType = QSGShaderEffectNode::VariableData::Source;
+ defaultSD.varData.append(vd);
+
+ v.name = QByteArrayLiteral("sourceSampler");
+ v.bindPoint = 0;
+ v.type = QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
+ defaultSD.shaderInfo.variables.append(v);
+ vd.specialType = QSGShaderEffectNode::VariableData::Unused;
+ defaultSD.varData.append(vd);
+
+ defaultSD.shaderInfo.constantDataSize = (16 + 1) * sizeof(float);
+
+ m_material.linker.feedConstants(defaultSD);
+ m_material.linker.feedSamplers(defaultSD);
+ m_material.linker.feedTextures(defaultSD);
+ }
+
+ m_material.updateTextureProviders(true);
+ markDirty(QSGNode::DirtyMaterial);
+
+ if (Q_UNLIKELY(debug_render()))
+ m_material.linker.dump();
+ } else {
+ if (syncData->dirty & QSGShaderEffectNode::DirtyShaderConstant) {
+ if (!syncData->vertex.dirtyConstants->isEmpty())
+ m_material.linker.feedConstants(*syncData->vertex.shader, syncData->vertex.dirtyConstants);
+ if (!syncData->fragment.dirtyConstants->isEmpty())
+ m_material.linker.feedConstants(*syncData->fragment.shader, syncData->fragment.dirtyConstants);
+ markDirty(QSGNode::DirtyMaterial);
+ if (Q_UNLIKELY(debug_render()))
+ m_material.linker.dump();
+ }
+
+ if (syncData->dirty & QSGShaderEffectNode::DirtyShaderTexture) {
+ if (!syncData->vertex.dirtyTextures->isEmpty())
+ m_material.linker.feedTextures(*syncData->vertex.shader, syncData->vertex.dirtyTextures);
+ if (!syncData->fragment.dirtyTextures->isEmpty())
+ m_material.linker.feedTextures(*syncData->fragment.shader, syncData->fragment.dirtyTextures);
+ m_material.updateTextureProviders(false);
+ markDirty(QSGNode::DirtyMaterial);
+ if (Q_UNLIKELY(debug_render()))
+ m_material.linker.dump();
+ }
+ }
+
+ if (bool(m_material.flags() & QSGMaterial::RequiresFullMatrix) != m_material.hasCustomVertexShader) {
+ m_material.setFlag(QSGMaterial::RequiresFullMatrix, m_material.hasCustomVertexShader);
+ markDirty(QSGNode::DirtyMaterial);
+ }
+
+ // ### texture subrect
+}
+
+void QSGD3D12ShaderEffectNode::handleTextureChange()
+{
+ markDirty(QSGNode::DirtyMaterial);
+ emit m_mgr->textureChanged();
+}
+
+void QSGD3D12ShaderEffectNode::handleTextureProviderDestroyed(QObject *object)
+{
+ for (QSGTextureProvider *&tp : m_material.textureProviders) {
+ if (tp == object)
+ tp = nullptr;
+ }
+}
+
+void QSGD3D12ShaderEffectNode::preprocess()
+{
+ for (QSGTextureProvider *tp : m_material.textureProviders) {
+ if (tp) {
+ if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(tp->texture()))
+ texture->updateTexture();
+ }
+ }
}
QSGGuiThreadShaderEffectManager::ShaderType QSGD3D12GuiThreadShaderEffectManager::shaderType() const
@@ -163,6 +743,8 @@ bool QSGD3D12GuiThreadShaderEffectManager::reflect(const QByteArray &src, Shader
const int cbufferCount = shaderDesc.ConstantBuffers;
const int boundResCount = shaderDesc.BoundResources;
+ result->constantDataSize = 0;
+
if (ieCount < 1) {
qWarning("Invalid shader: Not enough input parameters (%d)", ieCount);
return false;
@@ -213,6 +795,7 @@ bool QSGD3D12GuiThreadShaderEffectManager::reflect(const QByteArray &src, Shader
continue;
}
gotCBuffer = true;
+ result->constantDataSize = bufDesc.Size;
for (uint cbIdx = 0; cbIdx < bufDesc.Variables; ++cbIdx) {
ID3D12ShaderReflectionVariable *cvar = cbuf->GetVariableByIndex(cbIdx);
D3D12_SHADER_VARIABLE_DESC varDesc;
@@ -220,6 +803,9 @@ bool QSGD3D12GuiThreadShaderEffectManager::reflect(const QByteArray &src, Shader
qWarning("D3D reflection: Failed to query constant buffer variable %d", cbIdx);
return false;
}
+ // we report the full size of the buffer but only return variables that are actually used by this shader
+ if (!(varDesc.uFlags & D3D_SVF_USED))
+ continue;
ShaderInfo::Variable v;
v.type = ShaderInfo::Constant;
v.name = QByteArray(varDesc.Name);
@@ -270,14 +856,8 @@ bool QSGD3D12GuiThreadShaderEffectManager::reflect(const QByteArray &src, Shader
}
if (Q_UNLIKELY(debug_render())) {
- for (int i = 0; i < result->inputParameters.count(); ++i) {
- const ShaderInfo::InputParameter &p(result->inputParameters.at(i));
- qDebug() << "input" << i << p;
- }
- for (int i = 0; i < result->variables.count(); ++i) {
- const ShaderInfo::Variable &v(result->variables.at(i));
- qDebug() << "var" << i << v;
- }
+ qDebug() << "Input:" << result->inputParameters;
+ qDebug() << "Variables:" << result->variables << "cbuffer size" << result->constantDataSize;
}
return true;
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h
index f88e028b35..d58233481a 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h
@@ -52,24 +52,96 @@
//
#include <private/qsgadaptationlayer_p.h>
-#include "qsgd3d12builtinmaterials_p.h"
+#include "qsgd3d12material_p.h"
QT_BEGIN_NAMESPACE
class QSGD3D12RenderContext;
class QSGD3D12GuiThreadShaderEffectManager;
+class QSGD3D12ShaderEffectNode;
-class QSGD3D12ShaderEffectNode : public QSGShaderEffectNode
+class QSGD3D12ShaderLinker
{
public:
+ void reset(const QByteArray &vertBlob, const QByteArray &fragBlob);
+
+ void feedVertexInput(const QSGShaderEffectNode::ShaderData &shader);
+ void feedConstants(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices = nullptr);
+ void feedSamplers(const QSGShaderEffectNode::ShaderData &shader);
+ void feedTextures(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices = nullptr);
+
+ void dump();
+
+ struct Constant {
+ uint size;
+ QSGShaderEffectNode::VariableData::SpecialType specialType;
+ QVariant value;
+ bool operator==(const Constant &other) const {
+ return size == other.size && specialType == other.specialType
+ && (specialType == QSGShaderEffectNode::VariableData::None ? value == other.value : true);
+ }
+ };
+
+ bool error;
+ QByteArray vs;
+ QByteArray fs;
+ uint constantBufferSize;
+ QHash<uint, Constant> constants; // offset -> Constant
+ QSet<int> samplers; // bindpoint
+ QHash<int, QVariant> textures; // bindpoint -> value (source ref)
+};
+
+QDebug operator<<(QDebug debug, const QSGD3D12ShaderLinker::Constant &c);
+
+class QSGD3D12ShaderEffectMaterial : public QSGD3D12Material
+{
+public:
+ QSGD3D12ShaderEffectMaterial(QSGD3D12ShaderEffectNode *node);
+
+ QSGMaterialType *type() const override;
+ int compare(const QSGMaterial *other) const override;
+
+ int constantBufferSize() const override;
+ void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
+ UpdateResults updatePipeline(const RenderState &state,
+ QSGD3D12PipelineState *pipelineState,
+ ExtraState *extraState,
+ quint8 *constantBuffer) override;
+
+ void updateTextureProviders(bool layoutChange);
+
+ QSGD3D12ShaderEffectNode *node;
+ bool valid = false;
+ QSGShaderEffectNode::CullMode cullMode = QSGShaderEffectNode::NoCulling;
+ bool hasCustomVertexShader = false;
+ bool hasCustomFragmentShader = false;
+ QSGD3D12ShaderLinker linker;
+ QSGMaterialType *mtype = nullptr;
+ QVector<QSGTextureProvider *> textureProviders;
+};
+
+class QSGD3D12ShaderEffectNode : public QObject, public QSGShaderEffectNode
+{
+ Q_OBJECT
+
+public:
QSGD3D12ShaderEffectNode(QSGD3D12RenderContext *rc, QSGD3D12GuiThreadShaderEffectManager *mgr);
QRectF normalizedTextureSubRect() const override;
void sync(SyncData *syncData) override;
+ static void cleanupMaterialTypeCache();
+
+ void preprocess() override;
+
+private Q_SLOTS:
+ void handleTextureChange();
+ void handleTextureProviderDestroyed(QObject *object);
+
private:
QSGD3D12RenderContext *m_rc;
QSGD3D12GuiThreadShaderEffectManager *m_mgr;
+ QSGD3D12ShaderEffectMaterial m_material;
};
class QSGD3D12GuiThreadShaderEffectManager : public QSGGuiThreadShaderEffectManager
diff --git a/src/plugins/scenegraph/d3d12/shaders/shadereffectdefault.hlsl b/src/plugins/scenegraph/d3d12/shaders/shadereffectdefault.hlsl
new file mode 100644
index 0000000000..94672d6267
--- /dev/null
+++ b/src/plugins/scenegraph/d3d12/shaders/shadereffectdefault.hlsl
@@ -0,0 +1,27 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+ float2 coord : TEXCOORD0;
+};
+
+Texture2D source : register(t0);
+SamplerState sourceSampler : register(s0);
+
+PSInput VS_DefaultShaderEffect(float4 position : POSITION, float2 coord : TEXCOORD0)
+{
+ PSInput result;
+ result.position = mul(qt_Matrix, position);
+ result.coord = coord;
+ return result;
+}
+
+float4 PS_DefaultShaderEffect(PSInput input) : SV_TARGET
+{
+ return source.Sample(sourceSampler, input.coord) * qt_Opacity;
+}
diff --git a/src/plugins/scenegraph/d3d12/shaders/shaders.pri b/src/plugins/scenegraph/d3d12/shaders/shaders.pri
index 02786e2606..296e119cb2 100644
--- a/src/plugins/scenegraph/d3d12/shaders/shaders.pri
+++ b/src/plugins/scenegraph/d3d12/shaders/shaders.pri
@@ -88,6 +88,16 @@ outlinedtext_pshader.header = ps_outlinedtext.hlslh
outlinedtext_pshader.entry = PS_OutlinedText
outlinedtext_pshader.type = ps_5_0
+shadereffectdefault_VSPS = $$PWD/shadereffectdefault.hlsl
+shadereffectdefault_vshader.input = shadereffectdefault_VSPS
+shadereffectdefault_vshader.header = vs_shadereffectdefault.hlslh
+shadereffectdefault_vshader.entry = VS_DefaultShaderEffect
+shadereffectdefault_vshader.type = vs_5_0
+shadereffectdefault_pshader.input = shadereffectdefault_VSPS
+shadereffectdefault_pshader.header = ps_shadereffectdefault.hlslh
+shadereffectdefault_pshader.entry = PS_DefaultShaderEffect
+shadereffectdefault_pshader.type = ps_5_0
+
HLSL_SHADERS = \
vertexcolor_vshader vertexcolor_pshader \
stencilclip_vshader stencilclip_pshader \
@@ -96,6 +106,7 @@ HLSL_SHADERS = \
smoothtexture_vshader smoothtexture_pshader \
mipmapgen_cshader \
textmask_vshader textmask_pshader24 textmask_pshader32 textmask_pshader8 \
- styledtext_vshader styledtext_pshader outlinedtext_vshader outlinedtext_pshader
+ styledtext_vshader styledtext_pshader outlinedtext_vshader outlinedtext_pshader \
+ shadereffectdefault_vshader shadereffectdefault_pshader
load(hlsl_bytecode_header)
diff --git a/src/quick/items/qquickgenericshadereffect.cpp b/src/quick/items/qquickgenericshadereffect.cpp
index 769c408672..0e88868aea 100644
--- a/src/quick/items/qquickgenericshadereffect.cpp
+++ b/src/quick/items/qquickgenericshadereffect.cpp
@@ -80,7 +80,7 @@ void QQuickGenericShaderEffect::setFragmentShader(const QByteArray &src)
return;
m_fragShader = src;
- m_dirty |= QSGShaderEffectNode::DirtyShaderFragment;
+ m_dirty |= QSGShaderEffectNode::DirtyShaders;
if (m_item->isComponentComplete())
updateShader(Fragment, src);
@@ -95,7 +95,7 @@ void QQuickGenericShaderEffect::setVertexShader(const QByteArray &src)
return;
m_vertShader = src;
- m_dirty |= QSGShaderEffectNode::DirtyShaderVertex;
+ m_dirty |= QSGShaderEffectNode::DirtyShaders;
if (m_item->isComponentComplete())
updateShader(Vertex, src);
@@ -264,9 +264,7 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
if (!node) {
QSGRenderContext *rc = QQuickWindowPrivate::get(m_item->window())->context;
node = rc->sceneGraphContext()->createShaderEffectNode(rc, mgr);
- m_dirty = QSGShaderEffectNode::DirtyShaderVertex | QSGShaderEffectNode::DirtyShaderFragment
- | QSGShaderEffectNode::DirtyShaderConstant | QSGShaderEffectNode::DirtyShaderTexture
- | QSGShaderEffectNode::DirtyShaderGeometry | QSGShaderEffectNode::DirtyShaderMesh;
+ m_dirty = QSGShaderEffectNode::DirtyShaderAll;
}
// Dirty mesh and geometry are handled here, the rest is passed on to the node.
@@ -295,12 +293,20 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
sd.blending = m_blending;
sd.supportsAtlasTextures = m_supportsAtlasTextures;
- sd.vertexShader = (m_dirty & QSGShaderEffectNode::DirtyShaderVertex) ? &m_shaders[Vertex] : nullptr;
- sd.fragmentShader = (m_dirty & QSGShaderEffectNode::DirtyShaderFragment) ? &m_shaders[Fragment] : nullptr;
+ sd.vertex.shader = &m_shaders[Vertex];
+ sd.vertex.dirtyConstants = &m_dirtyConstants[Vertex];
+ sd.vertex.dirtyTextures = &m_dirtyTextures[Vertex];
+ sd.fragment.shader = &m_shaders[Fragment];
+ sd.fragment.dirtyConstants = &m_dirtyConstants[Fragment];
+ sd.fragment.dirtyTextures = &m_dirtyTextures[Fragment];
node->sync(&sd);
m_dirty = 0;
+ for (int i = 0; i < NShader; ++i) {
+ m_dirtyConstants[i].clear();
+ m_dirtyTextures[i].clear();
+ }
return node;
}
@@ -396,6 +402,7 @@ void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray
// For file-based shader source/bytecode this is where the data is pulled
// in from the file.
QSGGuiThreadShaderEffectManager::ShaderInfo shaderInfo;
+ // ### this will need some sort of caching mechanism
if (!mgr->reflect(src, &shaderInfo)) {
qWarning("ShaderEffect: shader reflection failed for %s", src.constData());
m_shaders[shaderType].valid = false;
@@ -416,7 +423,7 @@ void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray
const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
// Hook up the signals to get notified about changes for properties that
- // correspond to variables in the shader.
+ // correspond to variables in the shader. Store also the values.
for (int i = 0; i < varCount; ++i) {
const auto &v(shaderInfo.variables.at(i));
QSGShaderEffectNode::VariableData &vd(m_shaders[shaderType].varData[i]);
@@ -433,7 +440,7 @@ void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray
// The value of a property corresponding to a sampler is the source
// item ref, unless there are separate texture objects in which case
- // the sampler is ignored.
+ // the sampler is ignored (here).
if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
if (texturesSeparate) {
vd.specialType = QSGShaderEffectNode::VariableData::Unused;
@@ -532,10 +539,12 @@ void QQuickGenericShaderEffect::propertyChanged(int mappedId)
}
m_dirty |= QSGShaderEffectNode::DirtyShaderTexture;
+ m_dirtyTextures[type].insert(idx);
} else {
vd.value = m_item->property(v.name.constData());
m_dirty |= QSGShaderEffectNode::DirtyShaderConstant;
+ m_dirtyConstants[type].insert(idx);
}
m_item->update();
diff --git a/src/quick/items/qquickgenericshadereffect_p.h b/src/quick/items/qquickgenericshadereffect_p.h
index bc90b493ca..5f6652ec32 100644
--- a/src/quick/items/qquickgenericshadereffect_p.h
+++ b/src/quick/items/qquickgenericshadereffect_p.h
@@ -132,6 +132,8 @@ private:
QSGShaderEffectNode::ShaderData m_shaders[NShader];
QSGShaderEffectNode::DirtyShaderFlags m_dirty;
+ QSet<int> m_dirtyConstants[NShader];
+ QSet<int> m_dirtyTextures[NShader];
struct SignalMapper {
SignalMapper() : mapper(nullptr), active(false) { }
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index b0259c50b0..50986e2528 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -522,11 +522,16 @@ void QSGNodeVisitorEx::visitChildren(QSGNode *node)
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const QSGGuiThreadShaderEffectManager::ShaderInfo::InputParameter &p)
{
- debug << p.semanticName << p.semanticIndex;
+ QDebugStateSaver saver(debug);
+ debug.space();
+ debug << p.semanticName << "semindex" << p.semanticIndex;
return debug;
}
+
QDebug operator<<(QDebug debug, const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &v)
{
+ QDebugStateSaver saver(debug);
+ debug.space();
debug << v.name;
switch (v.type) {
case QSGGuiThreadShaderEffectManager::ShaderInfo::Constant:
@@ -543,6 +548,14 @@ QDebug operator<<(QDebug debug, const QSGGuiThreadShaderEffectManager::ShaderInf
}
return debug;
}
+
+QDebug operator<<(QDebug debug, const QSGShaderEffectNode::VariableData &vd)
+{
+ QDebugStateSaver saver(debug);
+ debug.space();
+ debug << vd.specialType;
+ return debug;
+}
#endif
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 5155cdd719..c06e681d30 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -289,6 +289,7 @@ public:
Type type;
QVector<InputParameter> inputParameters;
QVector<Variable> variables;
+ uint constantDataSize;
};
virtual bool reflect(const QByteArray &src, ShaderInfo *result) = 0;
@@ -307,12 +308,13 @@ class Q_QUICK_PRIVATE_EXPORT QSGShaderEffectNode : public QSGVisitableNode
{
public:
enum DirtyShaderFlag {
- DirtyShaderVertex = 0x01,
- DirtyShaderFragment = 0x02,
- DirtyShaderConstant = 0x04,
- DirtyShaderTexture = 0x08,
- DirtyShaderGeometry = 0x10,
- DirtyShaderMesh = 0x20
+ DirtyShaders = 0x01,
+ DirtyShaderConstant = 0x02,
+ DirtyShaderTexture = 0x04,
+ DirtyShaderGeometry = 0x08,
+ DirtyShaderMesh = 0x10,
+
+ DirtyShaderAll = 0xFF
};
Q_DECLARE_FLAGS(DirtyShaderFlags, DirtyShaderFlag)
@@ -323,7 +325,7 @@ public:
};
struct VariableData {
- enum SpecialType { None, Unused, SubRect, Opacity, Matrix, Source };
+ enum SpecialType { None, Unused, Source, SubRect, Opacity, Matrix };
QVariant value;
SpecialType specialType;
@@ -341,8 +343,13 @@ public:
CullMode cullMode;
bool blending;
bool supportsAtlasTextures;
- ShaderData *vertexShader;
- ShaderData *fragmentShader;
+ struct ShaderSyncData {
+ const ShaderData *shader;
+ const QSet<int> *dirtyConstants;
+ const QSet<int> *dirtyTextures;
+ };
+ ShaderSyncData vertex;
+ ShaderSyncData fragment;
};
// Each ShaderEffect item has one node (render thread) and one manager (gui thread).
@@ -356,6 +363,10 @@ public:
Q_DECLARE_OPERATORS_FOR_FLAGS(QSGShaderEffectNode::DirtyShaderFlags)
+#ifndef QT_NO_DEBUG_STREAM
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug debug, const QSGShaderEffectNode::VariableData &vd);
+#endif
+
class Q_QUICK_PRIVATE_EXPORT QSGGlyphNode : public QSGVisitableNode
{
public: