aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-04-29 13:27:02 +0200
committerAndy Nichols <andy.nichols@qt.io>2016-04-30 20:22:20 +0000
commitdc5b2fd31ccf36f5f6e0ec3a7222bda023c6b1eb (patch)
tree72900fdd6fc301a72ec7cc527d64cf456212acc3 /src
parent5568a79fdd742761bae660137b3e6d4795100ff0 (diff)
D3D12: qt_SubRect_<name> support
Change-Id: I2b5d1211ed97909a03d92d115eb057ce9e710d12 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp90
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h7
-rw-r--r--src/quick/items/qquickgenericshadereffect.cpp30
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h5
4 files changed, 103 insertions, 29 deletions
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp
index 856b49d2ac..dbdc876930 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp
@@ -73,6 +73,7 @@ void QSGD3D12ShaderLinker::reset(const QByteArray &vertBlob, const QByteArray &f
constants.clear();
samplers.clear();
textures.clear();
+ textureNameMap.clear();
}
void QSGD3D12ShaderLinker::feedVertexInput(const QSGShaderEffectNode::ShaderData &shader)
@@ -113,7 +114,12 @@ void QSGD3D12ShaderLinker::feedConstants(const QSGShaderEffectNode::ShaderData &
Constant c;
c.size = var.size;
c.specialType = vd.specialType;
- c.value = vd.value;
+ if (c.specialType != QSGShaderEffectNode::VariableData::SubRect) {
+ c.value = vd.value;
+ } else {
+ Q_ASSERT(var.name.startsWith(QByteArrayLiteral("qt_SubRect_")));
+ c.value = var.name.mid(11);
+ }
constants[var.offset] = c;
}
}
@@ -144,11 +150,33 @@ void QSGD3D12ShaderLinker::feedTextures(const QSGShaderEffectNode::ShaderData &s
if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Texture) {
Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Source);
textures.insert(var.bindPoint, vd.value);
+ textureNameMap.insert(var.name, var.bindPoint);
}
}
} else {
- for (int idx : *dirtyIndices)
- textures.insert(shader.shaderInfo.variables.at(idx).bindPoint, shader.varData.at(idx).value);
+ for (int idx : *dirtyIndices) {
+ const auto &var(shader.shaderInfo.variables.at(idx));
+ const auto &vd(shader.varData.at(idx));
+ textures.insert(var.bindPoint, vd.value);
+ textureNameMap.insert(var.name, var.bindPoint);
+ }
+ }
+}
+
+void QSGD3D12ShaderLinker::linkTextureSubRects()
+{
+ // feedConstants stores <name> in Constant::value for subrect entries. Now
+ // that both constants and textures are known, replace the name with the
+ // texture bind point.
+ for (Constant &c : constants) {
+ if (c.specialType == QSGShaderEffectNode::VariableData::SubRect) {
+ if (c.value.type() == QMetaType::QByteArray) {
+ const QByteArray name = c.value.toByteArray();
+ if (!textureNameMap.contains(name))
+ qWarning("ShaderEffect: qt_SubRect_%s refers to unknown source texture", qPrintable(name));
+ c.value = textureNameMap[name];
+ }
+ }
}
}
@@ -234,6 +262,16 @@ QSGMaterialType *QSGD3D12ShaderEffectMaterial::type() const
return mtype;
}
+static bool hasAtlasTexture(const QVector<QSGTextureProvider *> &textureProviders)
+{
+ for (int i = 0; i < textureProviders.count(); ++i) {
+ QSGTextureProvider *t = textureProviders.at(i);
+ if (t && t->texture() && t->texture()->isAtlasTexture())
+ return true;
+ }
+ return false;
+}
+
int QSGD3D12ShaderEffectMaterial::compare(const QSGMaterial *other) const
{
Q_ASSERT(other && type() == other->type());
@@ -248,6 +286,10 @@ int QSGD3D12ShaderEffectMaterial::compare(const QSGMaterial *other) const
if (linker.constants != o->linker.constants)
return 1;
+ if ((hasAtlasTexture(textureProviders) && !geometryUsesTextureSubRect)
+ || (hasAtlasTexture(o->textureProviders) && !o->geometryUsesTextureSubRect))
+ return 1;
+
for (int i = 0; i < textureProviders.count(); ++i) {
QSGTextureProvider *tp1 = textureProviders.at(i);
QSGTextureProvider *tp2 = o->textureProviders.at(i);
@@ -309,6 +351,16 @@ QSGD3D12Material::UpdateResults QSGD3D12ShaderEffectMaterial::updatePipeline(con
memcpy(dst, state.combinedMatrix().constData(), sz);
r |= UpdatedConstantBuffer;
}
+ } else if (c.specialType == QSGShaderEffectNode::VariableData::SubRect) {
+ // float4
+ QRectF subRect(0, 0, 1, 1);
+ int srcBindPoint = c.value.toInt(); // filled in by linkTextureSubRects
+ if (QSGTexture *t = textureProviders.at(srcBindPoint)->texture())
+ subRect = t->normalizedTextureSubRect();
+ const float f[4] = { float(subRect.x()), float(subRect.y()),
+ float(subRect.width()), float(subRect.height()) };
+ Q_ASSERT(sizeof(f) == c.size);
+ memcpy(dst, f, sizeof(f));
} else if (c.specialType == QSGShaderEffectNode::VariableData::None) {
r |= UpdatedConstantBuffer;
switch (c.value.type()) {
@@ -424,6 +476,11 @@ QSGD3D12Material::UpdateResults QSGD3D12ShaderEffectMaterial::updatePipeline(con
QSGD3D12TextureView &tv(pipelineState->shaders.rootSig.textureViews[i]);
if (tp) {
if (QSGTexture *t = tp->texture()) {
+ if (t->isAtlasTexture() && !geometryUsesTextureSubRect) {
+ QSGTexture *newTexture = t->removedFromAtlas();
+ if (newTexture)
+ t = newTexture;
+ }
tv.filter = t->filtering() == QSGTexture::Linear
? QSGD3D12TextureView::FilterLinear : QSGD3D12TextureView::FilterNearest;
tv.addressModeHoriz = t->horizontalWrapMode() == QSGTexture::ClampToEdge
@@ -518,12 +575,27 @@ QSGD3D12ShaderEffectNode::QSGD3D12ShaderEffectNode(QSGD3D12RenderContext *rc, QS
setMaterial(&m_material);
}
-QRectF QSGD3D12ShaderEffectNode::normalizedTextureSubRect() const
+QRectF QSGD3D12ShaderEffectNode::updateNormalizedTextureSubRect(bool supportsAtlasTextures)
{
- return QRectF(0, 0, 1, 1);
+ QRectF srcRect(0, 0, 1, 1);
+ bool geometryUsesTextureSubRect = false;
+ if (supportsAtlasTextures && m_material.textureProviders.count() == 1) {
+ QSGTextureProvider *provider = m_material.textureProviders.at(0);
+ if (provider->texture()) {
+ srcRect = provider->texture()->normalizedTextureSubRect();
+ geometryUsesTextureSubRect = true;
+ }
+ }
+
+ if (m_material.geometryUsesTextureSubRect != geometryUsesTextureSubRect) {
+ m_material.geometryUsesTextureSubRect = geometryUsesTextureSubRect;
+ markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return srcRect;
}
-void QSGD3D12ShaderEffectNode::sync(SyncData *syncData)
+void QSGD3D12ShaderEffectNode::syncMaterial(SyncData *syncData)
{
if (Q_UNLIKELY(debug_render()))
qDebug() << "shadereffect node sync" << syncData->dirty;
@@ -636,7 +708,10 @@ void QSGD3D12ShaderEffectNode::sync(SyncData *syncData)
m_material.linker.feedSamplers(*syncData->fragment.shader);
m_material.linker.feedTextures(*syncData->fragment.shader);
+ m_material.linker.linkTextureSubRects();
+
m_material.updateTextureProviders(true);
+
markDirty(QSGNode::DirtyMaterial);
if (Q_UNLIKELY(debug_render()))
@@ -657,6 +732,7 @@ void QSGD3D12ShaderEffectNode::sync(SyncData *syncData)
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.linker.linkTextureSubRects();
m_material.updateTextureProviders(false);
markDirty(QSGNode::DirtyMaterial);
if (Q_UNLIKELY(debug_render()))
@@ -668,8 +744,6 @@ void QSGD3D12ShaderEffectNode::sync(SyncData *syncData)
m_material.setFlag(QSGMaterial::RequiresFullMatrix, m_material.hasCustomVertexShader);
markDirty(QSGNode::DirtyMaterial);
}
-
- // ### texture subrect
}
void QSGD3D12ShaderEffectNode::handleTextureChange()
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h
index d3e51e5dce..c8994a78dd 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h
@@ -70,6 +70,7 @@ public:
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 linkTextureSubRects();
void dump();
@@ -90,6 +91,7 @@ public:
QHash<uint, Constant> constants; // offset -> Constant
QSet<int> samplers; // bindpoint
QHash<int, QVariant> textures; // bindpoint -> value (source ref)
+ QHash<QByteArray, int> textureNameMap; // name -> bindpoint
};
QDebug operator<<(QDebug debug, const QSGD3D12ShaderLinker::Constant &c);
@@ -121,6 +123,7 @@ public:
QSGMaterialType *mtype = nullptr;
QVector<QSGTextureProvider *> textureProviders;
QSGD3D12Texture *dummy = nullptr;
+ bool geometryUsesTextureSubRect = false;
};
class QSGD3D12ShaderEffectNode : public QObject, public QSGShaderEffectNode
@@ -130,8 +133,8 @@ class QSGD3D12ShaderEffectNode : public QObject, public QSGShaderEffectNode
public:
QSGD3D12ShaderEffectNode(QSGD3D12RenderContext *rc, QSGD3D12GuiThreadShaderEffectManager *mgr);
- QRectF normalizedTextureSubRect() const override;
- void sync(SyncData *syncData) override;
+ QRectF updateNormalizedTextureSubRect(bool supportsAtlasTextures) override;
+ void syncMaterial(SyncData *syncData) override;
static void cleanupMaterialTypeCache();
diff --git a/src/quick/items/qquickgenericshadereffect.cpp b/src/quick/items/qquickgenericshadereffect.cpp
index c6b90e3499..cad3520ed1 100644
--- a/src/quick/items/qquickgenericshadereffect.cpp
+++ b/src/quick/items/qquickgenericshadereffect.cpp
@@ -272,7 +272,18 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
m_dirty = QSGShaderEffectNode::DirtyShaderAll;
}
- // Dirty mesh and geometry are handled here, the rest is passed on to the node.
+ QSGShaderEffectNode::SyncData sd;
+ sd.dirty = m_dirty;
+ sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
+ sd.blending = m_blending;
+ 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->syncMaterial(&sd);
+
if (m_dirty & QSGShaderEffectNode::DirtyShaderMesh) {
node->setGeometry(nullptr);
m_dirty &= ~QSGShaderEffectNode::DirtyShaderMesh;
@@ -284,7 +295,8 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
QSGGeometry *geometry = node->geometry();
- geometry = mesh->updateGeometry(geometry, 2, 0, node->normalizedTextureSubRect(), rect);
+ const QRectF srcRect = node->updateNormalizedTextureSubRect(m_supportsAtlasTextures);
+ geometry = mesh->updateGeometry(geometry, 2, 0, srcRect, rect);
node->setFlag(QSGNode::OwnsGeometry, false);
node->setGeometry(geometry);
@@ -293,20 +305,6 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
m_dirty &= ~QSGShaderEffectNode::DirtyShaderGeometry;
}
- QSGShaderEffectNode::SyncData sd;
- sd.dirty = m_dirty;
- sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
- sd.blending = m_blending;
- sd.supportsAtlasTextures = m_supportsAtlasTextures;
- 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();
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 296068e78b..0df42c2aa8 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -342,7 +342,6 @@ public:
DirtyShaderFlags dirty;
CullMode cullMode;
bool blending;
- bool supportsAtlasTextures;
struct ShaderSyncData {
const ShaderData *shader;
const QSet<int> *dirtyConstants;
@@ -355,8 +354,8 @@ public:
// Each ShaderEffect item has one node (render thread) and one manager (gui thread).
QSGShaderEffectNode(QSGGuiThreadShaderEffectManager *) { }
- virtual QRectF normalizedTextureSubRect() const = 0;
- virtual void sync(SyncData *syncData) = 0;
+ virtual QRectF updateNormalizedTextureSubRect(bool supportsAtlasTextures) = 0;
+ virtual void syncMaterial(SyncData *syncData) = 0;
void accept(QSGNodeVisitorEx *visitor) override { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
};