43 Q_ASSERT(shader.shaderInfo.variables.size() == shader.varData.size());
44 static bool shaderEffectDebug = qEnvironmentVariableIntValue(
"QSG_RHI_SHADEREFFECT_DEBUG");
46 for (
int i = 0; i < shader.shaderInfo.variables.size(); ++i) {
47 const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &var(shader.shaderInfo.variables.at(i));
48 if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Constant) {
49 const QSGShaderEffectNode::VariableData &vd(shader.varData.at(i));
52 c.specialType = vd.specialType;
53 if (c.specialType != QSGShaderEffectNode::VariableData::SubRect) {
55 if (shaderEffectDebug) {
56 if (c.specialType == QSGShaderEffectNode::VariableData::None) {
57 qDebug() <<
"cbuf prepare" << shader.shaderInfo.name << var.name
58 <<
"offset" << var.offset <<
"value" << c.value;
60 qDebug() <<
"cbuf prepare" << shader.shaderInfo.name << var.name
61 <<
"offset" << var.offset <<
"special" << c.specialType;
65 Q_ASSERT(var.name.startsWith(QByteArrayLiteral(
"qt_SubRect_")));
66 c.value = var.name.mid(11);
68 m_constants[var.offset] = c;
72 for (
int idx : *dirtyIndices) {
73 const int offset = shader.shaderInfo.variables.at(idx).offset;
74 const QVariant value = shader.varData.at(idx).value;
75 m_constants[offset].value = value;
76 if (shaderEffectDebug) {
77 qDebug() <<
"cbuf update" << shader.shaderInfo.name
78 <<
"offset" << offset <<
"value" << value;
87 for (
int i = 0; i < shader.shaderInfo.variables.size(); ++i) {
88 const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &var(shader.shaderInfo.variables.at(i));
89 const QSGShaderEffectNode::VariableData &vd(shader.varData.at(i));
90 if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
91 Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Source);
94 int existingBindPoint = m_samplerNameMap.value(var.name, -1);
95 Q_ASSERT(existingBindPoint < 0 || existingBindPoint == var.bindPoint);
98 m_samplers.insert(var.bindPoint, vd.value);
99 m_samplerNameMap.insert(var.name, var.bindPoint);
103 for (
int idx : *dirtyIndices) {
104 const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &var(shader.shaderInfo.variables.at(idx));
105 const QSGShaderEffectNode::VariableData &vd(shader.varData.at(idx));
108 int existingBindPoint = m_samplerNameMap.value(var.name, -1);
109 Q_ASSERT(existingBindPoint < 0 || existingBindPoint == var.bindPoint);
112 m_samplers.insert(var.bindPoint, vd.value);
113 m_samplerNameMap.insert(var.name, var.bindPoint);
293 Q_UNUSED(oldMaterial);
296 bool changed =
false;
297 QByteArray *buf = state.uniformData();
299 for (
auto it = mat->m_linker.m_constants.constBegin(), itEnd = mat->m_linker.m_constants.constEnd(); it != itEnd; ++it) {
300 const int offset = it.key();
301 char *dst = buf->data() + offset;
303 if (c.specialType == QSGShaderEffectNode::VariableData::Opacity) {
304 if (state.isOpacityDirty()) {
305 const float f = state.opacity();
306 fillUniformBlockMember<
float>(dst, &f, 1, c.size);
309 }
else if (c.specialType == QSGShaderEffectNode::VariableData::Matrix) {
310 if (state.isMatrixDirty()) {
311 Q_ASSERT(state.projectionMatrixCount() == mat->viewCount());
312 const int rendererViewCount = state.projectionMatrixCount();
313 const int shaderMatrixCount = c.size / 64;
314 if (shaderMatrixCount < mat->viewCount() && mat->viewCount() >= 2) {
315 qWarning(
"qt_Matrix uniform block member size is wrong: expected at least view_count * 64 bytes, "
316 "where view_count is %d, meaning %d bytes in total, but got only %d bytes. "
317 "This may be due to the ShaderEffect and its shaders not being multiview-capable, "
318 "or they are used with an unexpected render target. "
319 "Check if the shaders declare qt_Matrix as appropriate, "
320 "and if gl_ViewIndex is used correctly in the vertex shader.",
321 mat->viewCount(), mat->viewCount() * 64, c.size);
323 const int matrixCount = qMin(rendererViewCount, shaderMatrixCount);
325 for (
int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
326 const QMatrix4x4 m = state.combinedMatrix(viewIndex);
327 fillUniformBlockMember<
float>(dst + offset, m.constData(), 16, 64);
331 memset(dst + offset, 0, c.size - offset);
334 }
else if (c.specialType == QSGShaderEffectNode::VariableData::SubRect) {
336 QRectF subRect(0, 0, 1, 1);
337 const int binding = c.value.toInt();
339 if (QSGTextureProvider *tp = mat->m_textureProviders.at(binding)) {
340 if (QSGTexture *t = tp->texture())
341 subRect = t->normalizedTextureSubRect();
344 const float f[4] = {
float(subRect.x()),
float(subRect.y()),
345 float(subRect.width()),
float(subRect.height()) };
346 fillUniformBlockMember<
float>(dst, f, 4, c.size);
347 }
else if (c.specialType == QSGShaderEffectNode::VariableData::None) {
349 switch (
int(c.value.userType())) {
350 case QMetaType::QColor: {
351 const QColor v = qsg_premultiply_color(qvariant_cast<QColor>(c.value)).toRgb();
352 const float f[4] = {
float(v.redF()),
float(v.greenF()),
float(v.blueF()),
float(v.alphaF()) };
353 fillUniformBlockMember<
float>(dst, f, 4, c.size);
356 case QMetaType::Float: {
357 const float f = qvariant_cast<
float>(c.value);
358 fillUniformBlockMember<
float>(dst, &f, 1, c.size);
361 case QMetaType::Double: {
362 const float f =
float(qvariant_cast<
double>(c.value));
363 fillUniformBlockMember<
float>(dst, &f, 1, c.size);
366 case QMetaType::Int: {
367 const qint32 i = c.value.toInt();
368 fillUniformBlockMember<qint32>(dst, &i, 1, c.size);
371 case QMetaType::Bool: {
372 const qint32 b = c.value.toBool();
373 fillUniformBlockMember<qint32>(dst, &b, 1, c.size);
376 case QMetaType::QTransform: {
377 const QTransform v = qvariant_cast<QTransform>(c.value);
378 const float m[3][3] = {
379 {
float(v.m11()),
float(v.m12()),
float(v.m13()) },
380 {
float(v.m21()),
float(v.m22()),
float(v.m23()) },
381 {
float(v.m31()),
float(v.m32()),
float(v.m33()) }
384 memset(dst, 0, c.size);
385 const size_t bytesPerColumn = 4 *
sizeof(
float);
386 if (c.size >= bytesPerColumn)
387 fillUniformBlockMember<
float>(dst, m[0], 3, 3 *
sizeof(
float));
388 if (c.size >= 2 * bytesPerColumn)
389 fillUniformBlockMember<
float>(dst + bytesPerColumn, m[1], 3, 3 *
sizeof(
float));
390 if (c.size >= 3 * bytesPerColumn)
391 fillUniformBlockMember<
float>(dst + 2 * bytesPerColumn, m[2], 3, 3 *
sizeof(
float));
394 case QMetaType::QSize:
395 case QMetaType::QSizeF: {
396 const QSizeF v = c.value.toSizeF();
397 const float f[2] = {
float(v.width()),
float(v.height()) };
398 fillUniformBlockMember<
float>(dst, f, 2, c.size);
401 case QMetaType::QPoint:
402 case QMetaType::QPointF: {
403 const QPointF v = c.value.toPointF();
404 const float f[2] = {
float(v.x()),
float(v.y()) };
405 fillUniformBlockMember<
float>(dst, f, 2, c.size);
408 case QMetaType::QRect:
409 case QMetaType::QRectF: {
410 const QRectF v = c.value.toRectF();
411 const float f[4] = {
float(v.x()),
float(v.y()),
float(v.width()),
float(v.height()) };
412 fillUniformBlockMember<
float>(dst, f, 4, c.size);
415 case QMetaType::QVector2D: {
416 const QVector2D v = qvariant_cast<QVector2D>(c.value);
417 const float f[2] = {
float(v.x()),
float(v.y()) };
418 fillUniformBlockMember<
float>(dst, f, 2, c.size);
421 case QMetaType::QVector3D: {
422 const QVector3D v = qvariant_cast<QVector3D>(c.value);
423 const float f[3] = {
float(v.x()),
float(v.y()),
float(v.z()) };
424 fillUniformBlockMember<
float>(dst, f, 3, c.size);
427 case QMetaType::QVector4D: {
428 const QVector4D v = qvariant_cast<QVector4D>(c.value);
429 const float f[4] = {
float(v.x()),
float(v.y()),
float(v.z()),
float(v.w()) };
430 fillUniformBlockMember<
float>(dst, f, 4, c.size);
433 case QMetaType::QQuaternion: {
434 const QQuaternion v = qvariant_cast<QQuaternion>(c.value);
435 const float f[4] = {
float(v.x()),
float(v.y()),
float(v.z()),
float(v.scalar()) };
436 fillUniformBlockMember<
float>(dst, f, 4, c.size);
439 case QMetaType::QMatrix4x4: {
440 const QMatrix4x4 m = qvariant_cast<QMatrix4x4>(c.value);
441 fillUniformBlockMember<
float>(dst, m.constData(), 16, c.size);
602 for (QSGTextureProvider *tp : m_textureProviders) {
604 QObject::disconnect(tp, SIGNAL(textureChanged()), m_node,
605 SLOT(handleTextureChange()));
606 QObject::disconnect(tp, SIGNAL(destroyed(QObject*)), m_node,
607 SLOT(handleTextureProviderDestroyed(QObject*)));
610 m_textureProviders.fill(
nullptr, MAX_BINDINGS);
613 for (
auto it = m_linker.m_samplers.constBegin(), itEnd = m_linker.m_samplers.constEnd(); it != itEnd; ++it) {
614 const int binding = it.key();
615 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(it.value()));
616 QSGTextureProvider *newProvider = source && source->isTextureProvider() ? source->textureProvider() :
nullptr;
618 qWarning(
"Sampler at binding %d exceeds the available ShaderEffect binding slots; ignored",
622 QSGTextureProvider *&activeProvider(m_textureProviders[binding]);
623 if (newProvider != activeProvider) {
624 if (activeProvider) {
625 QObject::disconnect(activeProvider, SIGNAL(textureChanged()), m_node,
626 SLOT(handleTextureChange()));
627 QObject::disconnect(activeProvider, SIGNAL(destroyed(QObject*)), m_node,
628 SLOT(handleTextureProviderDestroyed(QObject*)));
631 Q_ASSERT_X(newProvider->thread() == QThread::currentThread(),
632 "QSGRhiShaderEffectMaterial::updateTextureProviders",
633 "Texture provider must belong to the rendering thread");
634 QObject::connect(newProvider, SIGNAL(textureChanged()), m_node, SLOT(handleTextureChange()));
635 QObject::connect(newProvider, SIGNAL(destroyed(QObject*)), m_node,
636 SLOT(handleTextureProviderDestroyed(QObject*)));
638 const char *typeName = source ? source->metaObject()->className() : it.value().typeName();
639 qWarning(
"ShaderEffect: Texture t%d is not assigned a valid texture provider (%s).",
642 activeProvider = newProvider;
721 static const int defaultVertexShaderCount = 2;
723 QSGRhiShaderEffectDefaultShader::create(QStringLiteral(
":/qt-project.org/scenegraph/shaders_ng/shadereffect.vert.qsb"), 1),
724 QSGRhiShaderEffectDefaultShader::create(QStringLiteral(
":/qt-project.org/scenegraph/shaders_ng/shadereffect.vert.qsb.mv2qsb"), 2)
726 static const int defaultFragmentShaderCount = 2;
728 QSGRhiShaderEffectDefaultShader::create(QStringLiteral(
":/qt-project.org/scenegraph/shaders_ng/shadereffect.frag.qsb"), 1),
729 QSGRhiShaderEffectDefaultShader::create(QStringLiteral(
":/qt-project.org/scenegraph/shaders_ng/shadereffect.frag.qsb.mv2qsb"), 2)
732 if (
bool(m_material.flags() & QSGMaterial::Blending) != syncData->blending) {
733 m_material.setFlag(QSGMaterial::Blending, syncData->blending);
734 markDirty(QSGNode::DirtyMaterial);
737 if (m_material.m_cullMode != syncData->cullMode) {
738 m_material.m_cullMode = syncData->cullMode;
739 markDirty(QSGNode::DirtyMaterial);
742 if (syncData->dirty & QSGShaderEffectNode::DirtyShaders) {
743 if (m_material.m_materialType) {
744 shaderMaterialTypeCache[m_material.m_materialTypeCacheKey].unref(m_material.m_vertexShader,
745 m_material.m_fragmentShader);
748 m_material.m_hasCustomVertexShader = syncData->vertex.shader->hasShaderCode;
749 quint32 defaultMatrixArrayByteSize = 0;
750 if (m_material.m_hasCustomVertexShader) {
751 m_material.m_vertexShader = syncData->vertex.shader->shaderInfo.rhiShader;
754 for (
int i = 0; i < defaultVertexShaderCount; ++i) {
755 if (defaultVertexShaders[i].viewCount == syncData->viewCount) {
756 m_material.m_vertexShader = defaultVertexShaders[i].shader;
757 defaultMatrixArrayByteSize = defaultVertexShaders[i].matrixArrayByteSize;
763 qWarning(
"No default vertex shader found for view count %d", syncData->viewCount);
764 m_material.m_vertexShader = defaultVertexShaders[0].shader;
765 defaultMatrixArrayByteSize = 64;
769 m_material.m_hasCustomFragmentShader = syncData->fragment.shader->hasShaderCode;
770 quint32 defaultOpacityOffset = 0;
771 if (m_material.m_hasCustomFragmentShader) {
772 m_material.m_fragmentShader = syncData->fragment.shader->shaderInfo.rhiShader;
775 for (
int i = 0; i < defaultFragmentShaderCount; ++i) {
776 if (defaultFragmentShaders[i].viewCount == syncData->viewCount) {
777 m_material.m_fragmentShader = defaultFragmentShaders[i].shader;
778 defaultOpacityOffset = defaultFragmentShaders[i].opacityOffset;
784 qWarning(
"No default fragment shader found for view count %d", syncData->viewCount);
785 m_material.m_fragmentShader = defaultFragmentShaders[0].shader;
786 defaultOpacityOffset = 64;
790 m_material.m_materialType = shaderMaterialTypeCache[syncData->materialTypeCacheKey].ref(m_material.m_vertexShader,
791 m_material.m_fragmentShader);
792 m_material.m_materialTypeCacheKey = syncData->materialTypeCacheKey;
794 m_material.m_linker.reset(m_material.m_vertexShader, m_material.m_fragmentShader);
796 if (m_material.m_hasCustomVertexShader) {
797 m_material.m_linker.feedConstants(*syncData->vertex.shader);
798 m_material.m_linker.feedSamplers(*syncData->vertex.shader);
800 QSGShaderEffectNode::ShaderData defaultSD;
801 defaultSD.shaderInfo.name = QLatin1String(
"Default ShaderEffect vertex shader");
802 defaultSD.shaderInfo.rhiShader = m_material.m_vertexShader;
803 defaultSD.shaderInfo.type = QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex;
806 QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
807 v.name = QByteArrayLiteral(
"qt_Matrix");
809 v.size = defaultMatrixArrayByteSize;
810 defaultSD.shaderInfo.variables.append(v);
811 QSGShaderEffectNode::VariableData vd;
812 vd.specialType = QSGShaderEffectNode::VariableData::Matrix;
813 defaultSD.varData.append(vd);
814 m_material.m_linker.feedConstants(defaultSD);
817 if (m_material.m_hasCustomFragmentShader) {
818 m_material.m_linker.feedConstants(*syncData->fragment.shader);
819 m_material.m_linker.feedSamplers(*syncData->fragment.shader);
821 QSGShaderEffectNode::ShaderData defaultSD;
822 defaultSD.shaderInfo.name = QLatin1String(
"Default ShaderEffect fragment shader");
823 defaultSD.shaderInfo.rhiShader = m_material.m_fragmentShader;
824 defaultSD.shaderInfo.type = QSGGuiThreadShaderEffectManager::ShaderInfo::TypeFragment;
827 QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
828 v.name = QByteArrayLiteral(
"qt_Opacity");
829 v.offset = defaultOpacityOffset;
830 v.size =
sizeof(
float);
831 defaultSD.shaderInfo.variables.append(v);
832 QSGShaderEffectNode::VariableData vd;
833 vd.specialType = QSGShaderEffectNode::VariableData::Opacity;
834 defaultSD.varData.append(vd);
836 v.name = QByteArrayLiteral(
"source");
838 v.type = QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
839 defaultSD.shaderInfo.variables.append(v);
840 for (
const QSGShaderEffectNode::VariableData &extVarData : std::as_const(syncData->fragment.shader->varData)) {
841 if (extVarData.specialType == QSGShaderEffectNode::VariableData::Source) {
842 vd.value = extVarData.value;
846 vd.specialType = QSGShaderEffectNode::VariableData::Source;
847 defaultSD.varData.append(vd);
849 m_material.m_linker.feedConstants(defaultSD);
850 m_material.m_linker.feedSamplers(defaultSD);
853 m_material.m_linker.linkTextureSubRects();
854 m_material.updateTextureProviders(
true);
855 markDirty(QSGNode::DirtyMaterial);
859 if (syncData->dirty & QSGShaderEffectNode::DirtyShaderConstant) {
860 if (!syncData->vertex.dirtyConstants->isEmpty())
861 m_material.m_linker.feedConstants(*syncData->vertex.shader, syncData->vertex.dirtyConstants);
862 if (!syncData->fragment.dirtyConstants->isEmpty())
863 m_material.m_linker.feedConstants(*syncData->fragment.shader, syncData->fragment.dirtyConstants);
864 markDirty(QSGNode::DirtyMaterial);
867 if (syncData->dirty & QSGShaderEffectNode::DirtyShaderTexture) {
868 if (!syncData->vertex.dirtyTextures->isEmpty())
869 m_material.m_linker.feedSamplers(*syncData->vertex.shader, syncData->vertex.dirtyTextures);
870 if (!syncData->fragment.dirtyTextures->isEmpty())
871 m_material.m_linker.feedSamplers(*syncData->fragment.shader, syncData->fragment.dirtyTextures);
872 m_material.m_linker.linkTextureSubRects();
873 m_material.updateTextureProviders(
false);
874 markDirty(QSGNode::DirtyMaterial);
878 if (
bool(m_material.flags() & QSGMaterial::RequiresFullMatrix) != m_material.m_hasCustomVertexShader) {
879 m_material.setFlag(QSGMaterial::RequiresFullMatrix, m_material.m_hasCustomVertexShader);
880 markDirty(QSGNode::DirtyMaterial);