diff options
Diffstat (limited to 'src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp')
-rw-r--r-- | src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp | 995 |
1 files changed, 0 insertions, 995 deletions
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp deleted file mode 100644 index 1f574a9802..0000000000 --- a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp +++ /dev/null @@ -1,995 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ - -#include "qsgd3d12shadereffectnode_p.h" -#include "qsgd3d12rendercontext_p.h" -#include "qsgd3d12texture_p.h" -#include "qsgd3d12engine_p.h" -#include <QtCore/qthreadpool.h> -#include <QtCore/qfile.h> -#include <QtCore/qfileselector.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. - -#define DECLARE_DEBUG_VAR(variable) \ - static bool debug_ ## variable() \ - { static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; } - -DECLARE_DEBUG_VAR(shader) - -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(); - textureNameMap.clear(); -} - -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; - 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; - } - } - } 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) { - Q_ASSERT(shader.varData.at(i).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); - textureNameMap.insert(var.name, var.bindPoint); - } - } - } else { - 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() == QVariant::ByteArray) { - 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]; - } - } - } -} - -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() -} - -QSGD3D12ShaderEffectMaterial::~QSGD3D12ShaderEffectMaterial() -{ - delete dummy; -} - -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; -} - -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()); - 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; - - 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); - 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 QSGD3D12Engine::alignedConstantBufferSize(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.textureViewCount = 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 QSGD3D12MaterialRenderState &state, - QSGD3D12PipelineState *pipelineState, - 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::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()) { - 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 (int i = 0; i < textureProviders.count(); ++i) { - QSGTextureProvider *tp = textureProviders[i]; - 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 - ? QSGD3D12TextureView::AddressClamp : QSGD3D12TextureView::AddressWrap; - tv.addressModeVert = t->verticalWrapMode() == QSGTexture::ClampToEdge - ? QSGD3D12TextureView::AddressClamp : QSGD3D12TextureView::AddressWrap; - t->bind(); - continue; - } - } - if (!dummy) { - dummy = new QSGD3D12Texture(node->renderContext()->engine()); - QImage img(128, 128, QImage::Format_ARGB32_Premultiplied); - img.fill(0); - dummy->create(img, QSGRenderContext::CreateTexture_Alpha); - } - tv.filter = QSGD3D12TextureView::FilterNearest; - tv.addressModeHoriz = QSGD3D12TextureView::AddressWrap; - tv.addressModeVert = QSGD3D12TextureView::AddressWrap; - dummy->bind(); - } - - switch (cullMode) { - case QSGShaderEffectNode::FrontFaceCulling: - pipelineState->cullMode = QSGD3D12PipelineState::CullFront; - break; - case QSGShaderEffectNode::BackFaceCulling: - pipelineState->cullMode = QSGD3D12PipelineState::CullBack; - break; - default: - pipelineState->cullMode = QSGD3D12PipelineState::CullNone; - break; - } - - 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_material(this) -{ - setFlag(UsePreprocess, true); - setMaterial(&m_material); -} - -QRectF QSGD3D12ShaderEffectNode::updateNormalizedTextureSubRect(bool supportsAtlasTextures) -{ - 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::syncMaterial(SyncData *syncData) -{ - if (Q_UNLIKELY(debug_shader())) - 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->hasShaderCode; - 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->hasShaderCode; - 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.feedConstants(*syncData->vertex.shader); - } else { - QSGShaderEffectNode::ShaderData defaultSD; - defaultSD.shaderInfo.blob = vertBlob; - defaultSD.shaderInfo.type = QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex; - - // { 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.feedConstants(defaultSD); - } - - m_material.linker.feedSamplers(*syncData->vertex.shader); - m_material.linker.feedTextures(*syncData->vertex.shader); - - if (m_material.hasCustomFragmentShader) { - m_material.linker.feedConstants(*syncData->fragment.shader); - } else { - QSGShaderEffectNode::ShaderData defaultSD; - 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); - } - - // While this may seem unnecessary for the built-in shaders, the value - // of 'source' is still in there and we have to process it. - 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_shader())) - 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_shader())) - 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.linker.linkTextureSubRects(); - m_material.updateTextureProviders(false); - markDirty(QSGNode::DirtyMaterial); - if (Q_UNLIKELY(debug_shader())) - 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); - } -} - -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(); - } - } -} - -bool QSGD3D12GuiThreadShaderEffectManager::hasSeparateSamplerAndTextureObjects() const -{ - return true; -} - -QString QSGD3D12GuiThreadShaderEffectManager::log() const -{ - return m_log; -} - -QSGGuiThreadShaderEffectManager::Status QSGD3D12GuiThreadShaderEffectManager::status() const -{ - return m_status; -} - -struct RefGuard { - RefGuard(IUnknown *p) : p(p) { } - ~RefGuard() { p->Release(); } - IUnknown *p; -}; - -class QSGD3D12ShaderCompileTask : public QRunnable -{ -public: - QSGD3D12ShaderCompileTask(QSGD3D12GuiThreadShaderEffectManager *mgr, - QSGD3D12GuiThreadShaderEffectManager::ShaderInfo::Type typeHint, - const QByteArray &src, - QSGD3D12GuiThreadShaderEffectManager::ShaderInfo *result) - : mgr(mgr), typeHint(typeHint), src(src), result(result) { } - - void run() override; - -private: - QSGD3D12GuiThreadShaderEffectManager *mgr; - QSGD3D12GuiThreadShaderEffectManager::ShaderInfo::Type typeHint; - QByteArray src; - QSGD3D12GuiThreadShaderEffectManager::ShaderInfo *result; -}; - -void QSGD3D12ShaderCompileTask::run() -{ - const char *target = typeHint == QSGD3D12GuiThreadShaderEffectManager::ShaderInfo::TypeVertex ? "vs_5_0" : "ps_5_0"; - ID3DBlob *bytecode = nullptr; - ID3DBlob *errors = nullptr; - HRESULT hr = D3DCompile(src.constData(), src.size(), nullptr, nullptr, nullptr, - "main", target, 0, 0, &bytecode, &errors); - if (FAILED(hr) || !bytecode) { - qWarning("HLSL shader compilation failed: 0x%x", hr); - if (errors) { - mgr->m_log += QString::fromUtf8(static_cast<const char *>(errors->GetBufferPointer()), errors->GetBufferSize()); - errors->Release(); - } - mgr->m_status = QSGGuiThreadShaderEffectManager::Error; - emit mgr->shaderCodePrepared(false, typeHint, src, result); - emit mgr->logAndStatusChanged(); - return; - } - - result->blob.resize(bytecode->GetBufferSize()); - memcpy(result->blob.data(), bytecode->GetBufferPointer(), result->blob.size()); - bytecode->Release(); - - const bool ok = mgr->reflect(result); - mgr->m_status = ok ? QSGGuiThreadShaderEffectManager::Compiled : QSGGuiThreadShaderEffectManager::Error; - emit mgr->shaderCodePrepared(ok, typeHint, src, result); - emit mgr->logAndStatusChanged(); -} - -static const int BYTECODE_MAGIC = 0x43425844; // 'DXBC' - -void QSGD3D12GuiThreadShaderEffectManager::prepareShaderCode(ShaderInfo::Type typeHint, const QByteArray &src, ShaderInfo *result) -{ - // The D3D12 backend's ShaderEffect implementation supports both HLSL - // source strings and bytecode or source in files as input. Bytecode is - // strongly recommended, but in order to make ShaderEffect users' (and - // anything that stiches shader strings together dynamically, e.g. - // qtgraphicaleffects) life easier, and since we link to d3dcompiler - // anyways, compiling from source is also supported. - - QByteArray shaderSourceCode = src; - QUrl srcUrl(QString::fromUtf8(src)); - if (!srcUrl.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) || srcUrl.isLocalFile()) { - if (!m_fileSelector) { - m_fileSelector = new QFileSelector(this); - m_fileSelector->setExtraSelectors(QStringList() << QStringLiteral("hlsl")); - } - const QString fn = m_fileSelector->select(QQmlFile::urlToLocalFileOrQrc(srcUrl)); - QFile f(fn); - if (!f.open(QIODevice::ReadOnly)) { - qWarning("ShaderEffect: Failed to read %s", qPrintable(fn)); - emit shaderCodePrepared(false, typeHint, src, result); - return; - } - QByteArray blob = f.readAll(); - f.close(); - if (blob.size() > 4) { - const quint32 *p = reinterpret_cast<const quint32 *>(blob.constData()); - if (*p == BYTECODE_MAGIC) { - // already compiled D3D bytecode, skip straight to reflection - result->blob = blob; - const bool ok = reflect(result); - m_status = ok ? Compiled : Error; - emit shaderCodePrepared(ok, typeHint, src, result); - emit logAndStatusChanged(); - return; - } - // assume the file contained HLSL source code - shaderSourceCode = blob; - } - } - - QThreadPool::globalInstance()->start(new QSGD3D12ShaderCompileTask(this, typeHint, shaderSourceCode, result)); -} - -bool QSGD3D12GuiThreadShaderEffectManager::reflect(ShaderInfo *result) -{ - ID3D12ShaderReflection *reflector; - HRESULT hr = D3DReflect(result->blob.constData(), result->blob.size(), IID_PPV_ARGS(&reflector)); - if (FAILED(hr)) { - qWarning("D3D shader reflection failed: 0x%x", hr); - return false; - } - RefGuard rg(reflector); - - D3D12_SHADER_DESC shaderDesc; - reflector->GetDesc(&shaderDesc); - - const uint progType = (shaderDesc.Version & 0xFFFF0000) >> 16; - const uint major = (shaderDesc.Version & 0x000000F0) >> 4; - const uint minor = (shaderDesc.Version & 0x0000000F); - - switch (progType) { - case D3D12_SHVER_VERTEX_SHADER: - result->type = ShaderInfo::TypeVertex; - break; - case D3D12_SHVER_PIXEL_SHADER: - result->type = ShaderInfo::TypeFragment; - break; - default: - result->type = ShaderInfo::TypeOther; - qWarning("D3D shader is of unknown type 0x%x", shaderDesc.Version); - return false; - } - - if (major < 5) { - qWarning("D3D shader model version %u.%u is too low", major, minor); - return false; - } - - const int ieCount = shaderDesc.InputParameters; - 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; - } - if (cbufferCount < 1) { - qWarning("Invalid shader: Shader has no constant buffers"); - return false; - } - if (boundResCount < 1) { - qWarning("Invalid shader: No resources bound. Expected to have at least a constant buffer bound."); - return false; - } - - if (Q_UNLIKELY(debug_shader())) - qDebug("Shader reflection size %d type %d v%u.%u input elems %d cbuffers %d boundres %d", - result->blob.size(), result->type, major, minor, ieCount, cbufferCount, boundResCount); - - for (int i = 0; i < boundResCount; ++i) { - D3D12_SHADER_INPUT_BIND_DESC desc; - if (FAILED(reflector->GetResourceBindingDesc(i, &desc))) { - qWarning("D3D reflection: Failed to query resource binding %d", i); - continue; - } - bool gotCBuffer = false; - if (desc.Type == D3D_SIT_CBUFFER) { - ID3D12ShaderReflectionConstantBuffer *cbuf = reflector->GetConstantBufferByName(desc.Name); - D3D12_SHADER_BUFFER_DESC bufDesc; - if (FAILED(cbuf->GetDesc(&bufDesc))) { - qWarning("D3D reflection: Failed to query constant buffer description"); - continue; - } - if (gotCBuffer) { - qWarning("D3D reflection: Found more than one constant buffers. Only the first one is used."); - 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; - if (FAILED(cvar->GetDesc(&varDesc))) { - 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); - v.offset = varDesc.StartOffset; - v.size = varDesc.Size; - result->variables.append(v); - } - } else if (desc.Type == D3D_SIT_TEXTURE) { - if (desc.Dimension != D3D_SRV_DIMENSION_TEXTURE2D) { - qWarning("D3D reflection: Texture %s is not a 2D texture, ignoring.", qPrintable(desc.Name)); - continue; - } - if (desc.NumSamples != (UINT) -1) { - qWarning("D3D reflection: Texture %s is multisample (%u), ignoring.", qPrintable(desc.Name), desc.NumSamples); - continue; - } - if (desc.BindCount != 1) { - qWarning("D3D reflection: Texture %s is an array, ignoring.", qPrintable(desc.Name)); - continue; - } - if (desc.Space != 0) { - qWarning("D3D reflection: Texture %s is not using register space 0, ignoring.", qPrintable(desc.Name)); - continue; - } - ShaderInfo::Variable v; - v.type = ShaderInfo::Texture; - v.name = QByteArray(desc.Name); - v.bindPoint = desc.BindPoint; - result->variables.append(v); - } else if (desc.Type == D3D_SIT_SAMPLER) { - if (desc.BindCount != 1) { - qWarning("D3D reflection: Sampler %s is an array, ignoring.", qPrintable(desc.Name)); - continue; - } - if (desc.Space != 0) { - qWarning("D3D reflection: Sampler %s is not using register space 0, ignoring.", qPrintable(desc.Name)); - continue; - } - ShaderInfo::Variable v; - v.type = ShaderInfo::Sampler; - v.name = QByteArray(desc.Name); - v.bindPoint = desc.BindPoint; - result->variables.append(v); - } else { - qWarning("D3D reflection: Resource binding %d has an unknown type of %d and will be ignored.", i, desc.Type); - continue; - } - } - - if (Q_UNLIKELY(debug_shader())) - qDebug() << "Variables:" << result->variables << "cbuffer size" << result->constantDataSize; - - return true; -} - -QT_END_NAMESPACE |