diff options
author | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2016-04-29 13:27:02 +0200 |
---|---|---|
committer | Andy Nichols <andy.nichols@qt.io> | 2016-04-30 20:22:20 +0000 |
commit | dc5b2fd31ccf36f5f6e0ec3a7222bda023c6b1eb (patch) | |
tree | 72900fdd6fc301a72ec7cc527d64cf456212acc3 | |
parent | 5568a79fdd742761bae660137b3e6d4795100ff0 (diff) |
D3D12: qt_SubRect_<name> support
Change-Id: I2b5d1211ed97909a03d92d115eb057ce9e710d12
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
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); } }; |