42 Q_ASSERT(shader.shaderInfo.variables.size() == shader.varData.size());
43 static bool shaderEffectDebug = qEnvironmentVariableIntValue(
"QSG_RHI_SHADEREFFECT_DEBUG");
45 for (
int i = 0; i < shader.shaderInfo.variables.size(); ++i) {
46 const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &var(shader.shaderInfo.variables.at(i));
47 if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Constant) {
48 const QSGShaderEffectNode::VariableData &vd(shader.varData.at(i));
51 c.specialType = vd.specialType;
52 if (c.specialType != QSGShaderEffectNode::VariableData::SubRect) {
54 if (shaderEffectDebug) {
55 if (c.specialType == QSGShaderEffectNode::VariableData::None) {
56 qDebug() <<
"cbuf prepare" << shader.shaderInfo.name << var.name
57 <<
"offset" << var.offset <<
"value" << c.value;
59 qDebug() <<
"cbuf prepare" << shader.shaderInfo.name << var.name
60 <<
"offset" << var.offset <<
"special" << c.specialType;
64 Q_ASSERT(var.name.startsWith(QByteArrayLiteral(
"qt_SubRect_")));
65 c.value = var.name.mid(11);
67 m_constants[var.offset] = c;
71 for (
int idx : *dirtyIndices) {
72 const int offset = shader.shaderInfo.variables.at(idx).offset;
73 const QVariant value = shader.varData.at(idx).value;
74 m_constants[offset].value = value;
75 if (shaderEffectDebug) {
76 qDebug() <<
"cbuf update" << shader.shaderInfo.name
77 <<
"offset" << offset <<
"value" << value;
86 for (
int i = 0; i < shader.shaderInfo.variables.size(); ++i) {
87 const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &var(shader.shaderInfo.variables.at(i));
88 const QSGShaderEffectNode::VariableData &vd(shader.varData.at(i));
89 if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
90 Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Source);
93 int existingBindPoint = m_samplerNameMap.value(var.name, -1);
94 Q_ASSERT(existingBindPoint < 0 || existingBindPoint == var.bindPoint);
97 m_samplers.insert(var.bindPoint, vd.value);
98 m_samplerNameMap.insert(var.name, var.bindPoint);
102 for (
int idx : *dirtyIndices) {
103 const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &var(shader.shaderInfo.variables.at(idx));
104 const QSGShaderEffectNode::VariableData &vd(shader.varData.at(idx));
107 int existingBindPoint = m_samplerNameMap.value(var.name, -1);
108 Q_ASSERT(existingBindPoint < 0 || existingBindPoint == var.bindPoint);
111 m_samplers.insert(var.bindPoint, vd.value);
112 m_samplerNameMap.insert(var.name, var.bindPoint);
292 Q_UNUSED(oldMaterial);
295 bool changed =
false;
296 QByteArray *buf = state.uniformData();
298 for (
auto it = mat->m_linker.m_constants.constBegin(), itEnd = mat->m_linker.m_constants.constEnd(); it != itEnd; ++it) {
299 const int offset = it.key();
300 char *dst = buf->data() + offset;
302 if (c.specialType == QSGShaderEffectNode::VariableData::Opacity) {
303 if (state.isOpacityDirty()) {
304 const float f = state.opacity();
305 fillUniformBlockMember<
float>(dst, &f, 1, c.size);
308 }
else if (c.specialType == QSGShaderEffectNode::VariableData::Matrix) {
309 if (state.isMatrixDirty()) {
310 Q_ASSERT(state.projectionMatrixCount() == mat->viewCount());
311 const int rendererViewCount = state.projectionMatrixCount();
312 const int shaderMatrixCount = c.size / 64;
313 if (shaderMatrixCount < mat->viewCount() && mat->viewCount() >= 2) {
314 qWarning(
"qt_Matrix uniform block member size is wrong: expected at least view_count * 64 bytes, "
315 "where view_count is %d, meaning %d bytes in total, but got only %d bytes. "
316 "This may be due to the ShaderEffect and its shaders not being multiview-capable, "
317 "or they are used with an unexpected render target. "
318 "Check if the shaders declare qt_Matrix as appropriate, "
319 "and if gl_ViewIndex is used correctly in the vertex shader.",
320 mat->viewCount(), mat->viewCount() * 64, c.size);
322 const int matrixCount = qMin(rendererViewCount, shaderMatrixCount);
324 for (
int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
325 const QMatrix4x4 m = state.combinedMatrix(viewIndex);
326 fillUniformBlockMember<
float>(dst + offset, m.constData(), 16, 64);
330 memset(dst + offset, 0, c.size - offset);
333 }
else if (c.specialType == QSGShaderEffectNode::VariableData::SubRect) {
335 QRectF subRect(0, 0, 1, 1);
336 const int binding = c.value.toInt();
338 if (QSGTextureProvider *tp = mat->m_textureProviders.at(binding)) {
339 if (QSGTexture *t = tp->texture())
340 subRect = t->normalizedTextureSubRect();
343 const float f[4] = {
float(subRect.x()),
float(subRect.y()),
344 float(subRect.width()),
float(subRect.height()) };
345 fillUniformBlockMember<
float>(dst, f, 4, c.size);
346 }
else if (c.specialType == QSGShaderEffectNode::VariableData::None) {
348 switch (
int(c.value.userType())) {
349 case QMetaType::QColor: {
350 const QColor v = qsg_premultiply_color(qvariant_cast<QColor>(c.value)).toRgb();
351 const float f[4] = {
float(v.redF()),
float(v.greenF()),
float(v.blueF()),
float(v.alphaF()) };
352 fillUniformBlockMember<
float>(dst, f, 4, c.size);
355 case QMetaType::Float: {
356 const float f = qvariant_cast<
float>(c.value);
357 fillUniformBlockMember<
float>(dst, &f, 1, c.size);
360 case QMetaType::Double: {
361 const float f =
float(qvariant_cast<
double>(c.value));
362 fillUniformBlockMember<
float>(dst, &f, 1, c.size);
365 case QMetaType::Int: {
366 const qint32 i = c.value.toInt();
367 fillUniformBlockMember<qint32>(dst, &i, 1, c.size);
370 case QMetaType::Bool: {
371 const qint32 b = c.value.toBool();
372 fillUniformBlockMember<qint32>(dst, &b, 1, c.size);
375 case QMetaType::QTransform: {
376 const QTransform v = qvariant_cast<QTransform>(c.value);
377 const float m[3][3] = {
378 {
float(v.m11()),
float(v.m12()),
float(v.m13()) },
379 {
float(v.m21()),
float(v.m22()),
float(v.m23()) },
380 {
float(v.m31()),
float(v.m32()),
float(v.m33()) }
383 memset(dst, 0, c.size);
384 const size_t bytesPerColumn = 4 *
sizeof(
float);
385 if (c.size >= bytesPerColumn)
386 fillUniformBlockMember<
float>(dst, m[0], 3, 3 *
sizeof(
float));
387 if (c.size >= 2 * bytesPerColumn)
388 fillUniformBlockMember<
float>(dst + bytesPerColumn, m[1], 3, 3 *
sizeof(
float));
389 if (c.size >= 3 * bytesPerColumn)
390 fillUniformBlockMember<
float>(dst + 2 * bytesPerColumn, m[2], 3, 3 *
sizeof(
float));
393 case QMetaType::QSize:
394 case QMetaType::QSizeF: {
395 const QSizeF v = c.value.toSizeF();
396 const float f[2] = {
float(v.width()),
float(v.height()) };
397 fillUniformBlockMember<
float>(dst, f, 2, c.size);
400 case QMetaType::QPoint:
401 case QMetaType::QPointF: {
402 const QPointF v = c.value.toPointF();
403 const float f[2] = {
float(v.x()),
float(v.y()) };
404 fillUniformBlockMember<
float>(dst, f, 2, c.size);
407 case QMetaType::QRect:
408 case QMetaType::QRectF: {
409 const QRectF v = c.value.toRectF();
410 const float f[4] = {
float(v.x()),
float(v.y()),
float(v.width()),
float(v.height()) };
411 fillUniformBlockMember<
float>(dst, f, 4, c.size);
414 case QMetaType::QVector2D: {
415 const QVector2D v = qvariant_cast<QVector2D>(c.value);
416 const float f[2] = {
float(v.x()),
float(v.y()) };
417 fillUniformBlockMember<
float>(dst, f, 2, c.size);
420 case QMetaType::QVector3D: {
421 const QVector3D v = qvariant_cast<QVector3D>(c.value);
422 const float f[3] = {
float(v.x()),
float(v.y()),
float(v.z()) };
423 fillUniformBlockMember<
float>(dst, f, 3, c.size);
426 case QMetaType::QVector4D: {
427 const QVector4D v = qvariant_cast<QVector4D>(c.value);
428 const float f[4] = {
float(v.x()),
float(v.y()),
float(v.z()),
float(v.w()) };
429 fillUniformBlockMember<
float>(dst, f, 4, c.size);
432 case QMetaType::QQuaternion: {
433 const QQuaternion v = qvariant_cast<QQuaternion>(c.value);
434 const float f[4] = {
float(v.x()),
float(v.y()),
float(v.z()),
float(v.scalar()) };
435 fillUniformBlockMember<
float>(dst, f, 4, c.size);
438 case QMetaType::QMatrix4x4: {
439 const QMatrix4x4 m = qvariant_cast<QMatrix4x4>(c.value);
440 fillUniformBlockMember<
float>(dst, m.constData(), 16, c.size);
601 for (QSGTextureProvider *tp : m_textureProviders) {
603 QObject::disconnect(tp, SIGNAL(textureChanged()), m_node,
604 SLOT(handleTextureChange()));
605 QObject::disconnect(tp, SIGNAL(destroyed(QObject*)), m_node,
606 SLOT(handleTextureProviderDestroyed(QObject*)));
609 m_textureProviders.fill(
nullptr, MAX_BINDINGS);
612 for (
auto it = m_linker.m_samplers.constBegin(), itEnd = m_linker.m_samplers.constEnd(); it != itEnd; ++it) {
613 const int binding = it.key();
614 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(it.value()));
615 QSGTextureProvider *newProvider = source && source->isTextureProvider() ? source->textureProvider() :
nullptr;
617 qWarning(
"Sampler at binding %d exceeds the available ShaderEffect binding slots; ignored",
621 QSGTextureProvider *&activeProvider(m_textureProviders[binding]);
622 if (newProvider != activeProvider) {
623 if (activeProvider) {
624 QObject::disconnect(activeProvider, SIGNAL(textureChanged()), m_node,
625 SLOT(handleTextureChange()));
626 QObject::disconnect(activeProvider, SIGNAL(destroyed(QObject*)), m_node,
627 SLOT(handleTextureProviderDestroyed(QObject*)));
630 Q_ASSERT_X(newProvider->thread() == QThread::currentThread(),
631 "QSGRhiShaderEffectMaterial::updateTextureProviders",
632 "Texture provider must belong to the rendering thread");
633 QObject::connect(newProvider, SIGNAL(textureChanged()), m_node, SLOT(handleTextureChange()));
634 QObject::connect(newProvider, SIGNAL(destroyed(QObject*)), m_node,
635 SLOT(handleTextureProviderDestroyed(QObject*)));
637 const char *typeName = source ? source->metaObject()->className() : it.value().typeName();
638 qWarning(
"ShaderEffect: Texture t%d is not assigned a valid texture provider (%s).",
641 activeProvider = newProvider;
720 static const int defaultVertexShaderCount = 2;
722 QSGRhiShaderEffectDefaultShader::create(QStringLiteral(
":/qt-project.org/scenegraph/shaders_ng/shadereffect.vert.qsb"), 1),
723 QSGRhiShaderEffectDefaultShader::create(QStringLiteral(
":/qt-project.org/scenegraph/shaders_ng/shadereffect.vert.qsb.mv2qsb"), 2)
725 static const int defaultFragmentShaderCount = 2;
727 QSGRhiShaderEffectDefaultShader::create(QStringLiteral(
":/qt-project.org/scenegraph/shaders_ng/shadereffect.frag.qsb"), 1),
728 QSGRhiShaderEffectDefaultShader::create(QStringLiteral(
":/qt-project.org/scenegraph/shaders_ng/shadereffect.frag.qsb.mv2qsb"), 2)
731 if (
bool(m_material.flags() & QSGMaterial::Blending) != syncData->blending) {
732 m_material.setFlag(QSGMaterial::Blending, syncData->blending);
733 markDirty(QSGNode::DirtyMaterial);
736 if (m_material.m_cullMode != syncData->cullMode) {
737 m_material.m_cullMode = syncData->cullMode;
738 markDirty(QSGNode::DirtyMaterial);
741 if (syncData->dirty & QSGShaderEffectNode::DirtyShaders) {
742 if (m_material.m_materialType) {
743 shaderMaterialTypeCache[m_material.m_materialTypeCacheKey].unref(m_material.m_vertexShader,
744 m_material.m_fragmentShader);
747 m_material.m_hasCustomVertexShader = syncData->vertex.shader->hasShaderCode;
748 quint32 defaultMatrixArrayByteSize = 0;
749 if (m_material.m_hasCustomVertexShader) {
750 m_material.m_vertexShader = syncData->vertex.shader->shaderInfo.rhiShader;
753 for (
int i = 0; i < defaultVertexShaderCount; ++i) {
754 if (defaultVertexShaders[i].viewCount == syncData->viewCount) {
755 m_material.m_vertexShader = defaultVertexShaders[i].shader;
756 defaultMatrixArrayByteSize = defaultVertexShaders[i].matrixArrayByteSize;
762 qWarning(
"No default vertex shader found for view count %d", syncData->viewCount);
763 m_material.m_vertexShader = defaultVertexShaders[0].shader;
764 defaultMatrixArrayByteSize = 64;
768 m_material.m_hasCustomFragmentShader = syncData->fragment.shader->hasShaderCode;
769 quint32 defaultOpacityOffset = 0;
770 if (m_material.m_hasCustomFragmentShader) {
771 m_material.m_fragmentShader = syncData->fragment.shader->shaderInfo.rhiShader;
774 for (
int i = 0; i < defaultFragmentShaderCount; ++i) {
775 if (defaultFragmentShaders[i].viewCount == syncData->viewCount) {
776 m_material.m_fragmentShader = defaultFragmentShaders[i].shader;
777 defaultOpacityOffset = defaultFragmentShaders[i].opacityOffset;
783 qWarning(
"No default fragment shader found for view count %d", syncData->viewCount);
784 m_material.m_fragmentShader = defaultFragmentShaders[0].shader;
785 defaultOpacityOffset = 64;
789 m_material.m_materialType = shaderMaterialTypeCache[syncData->materialTypeCacheKey].ref(m_material.m_vertexShader,
790 m_material.m_fragmentShader);
791 m_material.m_materialTypeCacheKey = syncData->materialTypeCacheKey;
793 m_material.m_linker.reset(m_material.m_vertexShader, m_material.m_fragmentShader);
795 if (m_material.m_hasCustomVertexShader) {
796 m_material.m_linker.feedConstants(*syncData->vertex.shader);
797 m_material.m_linker.feedSamplers(*syncData->vertex.shader);
799 QSGShaderEffectNode::ShaderData defaultSD;
800 defaultSD.shaderInfo.name = QLatin1String(
"Default ShaderEffect vertex shader");
801 defaultSD.shaderInfo.rhiShader = m_material.m_vertexShader;
802 defaultSD.shaderInfo.type = QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex;
805 QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
806 v.name = QByteArrayLiteral(
"qt_Matrix");
808 v.size = defaultMatrixArrayByteSize;
809 defaultSD.shaderInfo.variables.append(v);
810 QSGShaderEffectNode::VariableData vd;
811 vd.specialType = QSGShaderEffectNode::VariableData::Matrix;
812 defaultSD.varData.append(vd);
813 m_material.m_linker.feedConstants(defaultSD);
816 if (m_material.m_hasCustomFragmentShader) {
817 m_material.m_linker.feedConstants(*syncData->fragment.shader);
818 m_material.m_linker.feedSamplers(*syncData->fragment.shader);
820 QSGShaderEffectNode::ShaderData defaultSD;
821 defaultSD.shaderInfo.name = QLatin1String(
"Default ShaderEffect fragment shader");
822 defaultSD.shaderInfo.rhiShader = m_material.m_fragmentShader;
823 defaultSD.shaderInfo.type = QSGGuiThreadShaderEffectManager::ShaderInfo::TypeFragment;
826 QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
827 v.name = QByteArrayLiteral(
"qt_Opacity");
828 v.offset = defaultOpacityOffset;
829 v.size =
sizeof(
float);
830 defaultSD.shaderInfo.variables.append(v);
831 QSGShaderEffectNode::VariableData vd;
832 vd.specialType = QSGShaderEffectNode::VariableData::Opacity;
833 defaultSD.varData.append(vd);
835 v.name = QByteArrayLiteral(
"source");
837 v.type = QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
838 defaultSD.shaderInfo.variables.append(v);
839 for (
const QSGShaderEffectNode::VariableData &extVarData : std::as_const(syncData->fragment.shader->varData)) {
840 if (extVarData.specialType == QSGShaderEffectNode::VariableData::Source) {
841 vd.value = extVarData.value;
845 vd.specialType = QSGShaderEffectNode::VariableData::Source;
846 defaultSD.varData.append(vd);
848 m_material.m_linker.feedConstants(defaultSD);
849 m_material.m_linker.feedSamplers(defaultSD);
852 m_material.m_linker.linkTextureSubRects();
853 m_material.updateTextureProviders(
true);
854 markDirty(QSGNode::DirtyMaterial);
858 if (syncData->dirty & QSGShaderEffectNode::DirtyShaderConstant) {
859 if (!syncData->vertex.dirtyConstants->isEmpty())
860 m_material.m_linker.feedConstants(*syncData->vertex.shader, syncData->vertex.dirtyConstants);
861 if (!syncData->fragment.dirtyConstants->isEmpty())
862 m_material.m_linker.feedConstants(*syncData->fragment.shader, syncData->fragment.dirtyConstants);
863 markDirty(QSGNode::DirtyMaterial);
866 if (syncData->dirty & QSGShaderEffectNode::DirtyShaderTexture) {
867 if (!syncData->vertex.dirtyTextures->isEmpty())
868 m_material.m_linker.feedSamplers(*syncData->vertex.shader, syncData->vertex.dirtyTextures);
869 if (!syncData->fragment.dirtyTextures->isEmpty())
870 m_material.m_linker.feedSamplers(*syncData->fragment.shader, syncData->fragment.dirtyTextures);
871 m_material.m_linker.linkTextureSubRects();
872 m_material.updateTextureProviders(
false);
873 markDirty(QSGNode::DirtyMaterial);
877 if (
bool(m_material.flags() & QSGMaterial::RequiresFullMatrix) != m_material.m_hasCustomVertexShader) {
878 m_material.setFlag(QSGMaterial::RequiresFullMatrix, m_material.m_hasCustomVertexShader);
879 markDirty(QSGNode::DirtyMaterial);