388void QSSGRhiShaderPipeline::addStage(
const QRhiShaderStage &stage, StageFlags flags)
390 m_stages.append(stage);
394 if (stage.type() == QRhiShaderStage::Vertex) {
399 const QVector<QShaderDescription::UniformBlock> uniformBlocks = stage.shader().description().uniformBlocks();
400 for (
const QShaderDescription::UniformBlock &blk : uniformBlocks) {
401 if (blk.binding == 0) {
402 m_ub0Size = blk.size;
403 m_ub0NextUBufOffset = m_context.rhi()->ubufAligned(m_ub0Size);
404 for (
const QShaderDescription::BlockVariable &var : blk.members)
405 m_ub0[var.name] = var;
410 if (!flags.testFlag(UsedWithoutIa)) {
411 const QVector<QShaderDescription::InOutVariable> inputs = stage.shader().description().inputVariables();
412 for (
const QShaderDescription::InOutVariable &var : inputs) {
413 if (var.name == QSSGMesh::MeshInternal::getPositionAttrName()) {
414 m_vertexInputs[QSSGRhiInputAssemblerState::PositionSemantic] = var;
415 }
else if (var.name == QSSGMesh::MeshInternal::getNormalAttrName()) {
416 m_vertexInputs[QSSGRhiInputAssemblerState::NormalSemantic] = var;
417 }
else if (var.name == QSSGMesh::MeshInternal::getUV0AttrName()) {
418 m_vertexInputs[QSSGRhiInputAssemblerState::TexCoord0Semantic] = var;
419 }
else if (var.name == QSSGMesh::MeshInternal::getUV1AttrName()) {
420 m_vertexInputs[QSSGRhiInputAssemblerState::TexCoord1Semantic] = var;
421 }
else if (var.name == QSSGMesh::MeshInternal::getLightmapUVAttrName()) {
422 m_vertexInputs[QSSGRhiInputAssemblerState::TexCoordLightmapSemantic] = var;
423 }
else if (var.name == QSSGMesh::MeshInternal::getTexTanAttrName()) {
424 m_vertexInputs[QSSGRhiInputAssemblerState::TangentSemantic] = var;
425 }
else if (var.name == QSSGMesh::MeshInternal::getTexBinormalAttrName()) {
426 m_vertexInputs[QSSGRhiInputAssemblerState::BinormalSemantic] = var;
427 }
else if (var.name == QSSGMesh::MeshInternal::getColorAttrName()) {
428 m_vertexInputs[QSSGRhiInputAssemblerState::ColorSemantic] = var;
429 }
else if (var.name == QSSGMesh::MeshInternal::getJointAttrName()) {
430 m_vertexInputs[QSSGRhiInputAssemblerState::JointSemantic] = var;
431 }
else if (var.name == QSSGMesh::MeshInternal::getWeightAttrName()) {
432 m_vertexInputs[QSSGRhiInputAssemblerState::WeightSemantic] = var;
433 }
else if (var.name ==
"qt_instanceTransform0") {
434 instanceLocations.transform0 = var.location;
435 }
else if (var.name ==
"qt_instanceTransform1") {
436 instanceLocations.transform1 = var.location;
437 }
else if (var.name ==
"qt_instanceTransform2") {
438 instanceLocations.transform2 = var.location;
439 }
else if (var.name ==
"qt_instanceColor") {
440 instanceLocations.color = var.location;
441 }
else if (var.name ==
"qt_instanceData") {
442 instanceLocations.data = var.location;
444 qWarning(
"Ignoring vertex input %s in shader", var.name.constData());
450 const QVector<QShaderDescription::InOutVariable> combinedImageSamplers = stage.shader().description().combinedImageSamplers();
451 for (
const QShaderDescription::InOutVariable &var : combinedImageSamplers)
452 m_combinedImageSamplers[var.name] = var;
454 const QVector<QShaderDescription::InOutVariable> storageImages = stage.shader().description().storageImages() + stage.shader().description().separateImages();
455 for (
const QShaderDescription::InOutVariable &var : storageImages)
456 m_storageImages[var.name] = var;
458 std::fill(m_materialImageSamplerBindings,
459 m_materialImageSamplerBindings + size_t(QSSGRhiSamplerBindingHints::BindingMapSize),
468void QSSGRhiShaderPipeline::setUniformValue(
char *ubufData,
const char *name,
const QVariant &inValue, QSSGRenderShaderValue::Type inType)
470 using namespace QSSGRenderShaderValue;
472 case QSSGRenderShaderValue::Integer:
474 const qint32 v = inValue.toInt();
475 setUniform(ubufData, name, &v,
sizeof(qint32));
478 case QSSGRenderShaderValue::IntegerVec2:
480 const ivec2 v = inValue.value<ivec2>();
481 setUniform(ubufData, name, &v, 2 *
sizeof(qint32));
484 case QSSGRenderShaderValue::IntegerVec3:
486 const ivec3 v = inValue.value<ivec3>();
487 setUniform(ubufData, name, &v, 3 *
sizeof(qint32));
490 case QSSGRenderShaderValue::IntegerVec4:
492 const ivec4 v = inValue.value<ivec4>();
493 setUniform(ubufData, name, &v, 4 *
sizeof(qint32));
496 case QSSGRenderShaderValue::Boolean:
499 const qint32 v = inValue.value<
bool>();
500 setUniform(ubufData, name, &v,
sizeof(qint32));
503 case QSSGRenderShaderValue::BooleanVec2:
505 const bvec2 b = inValue.value<bvec2>();
506 const ivec2 v(b.x, b.y);
507 setUniform(ubufData, name, &v, 2 *
sizeof(qint32));
510 case QSSGRenderShaderValue::BooleanVec3:
512 const bvec3 b = inValue.value<bvec3>();
513 const ivec3 v(b.x, b.y, b.z);
514 setUniform(ubufData, name, &v, 3 *
sizeof(qint32));
517 case QSSGRenderShaderValue::BooleanVec4:
519 const bvec4 b = inValue.value<bvec4>();
520 const ivec4 v(b.x, b.y, b.z, b.w);
521 setUniform(ubufData, name, &v, 4 *
sizeof(qint32));
524 case QSSGRenderShaderValue::Float:
526 const float v = inValue.value<
float>();
527 setUniform(ubufData, name, &v,
sizeof(
float));
530 case QSSGRenderShaderValue::Vec2:
532 const QVector2D v = inValue.value<QVector2D>();
533 setUniform(ubufData, name, &v, 2 *
sizeof(
float));
536 case QSSGRenderShaderValue::Vec3:
538 const QVector3D v = inValue.value<QVector3D>();
539 setUniform(ubufData, name, &v, 3 *
sizeof(
float));
542 case QSSGRenderShaderValue::Vec4:
544 const QVector4D v = inValue.value<QVector4D>();
545 setUniform(ubufData, name, &v, 4 *
sizeof(
float));
548 case QSSGRenderShaderValue::Rgba:
550 const QVector4D v = QSSGUtils::color::sRGBToLinear(inValue.value<QColor>());
551 setUniform(ubufData, name, &v, 4 *
sizeof(
float));
554 case QSSGRenderShaderValue::UnsignedInteger:
556 const quint32 v = inValue.value<quint32>();
557 setUniform(ubufData, name, &v,
sizeof(quint32));
560 case QSSGRenderShaderValue::UnsignedIntegerVec2:
562 const uvec2 v = inValue.value<uvec2>();
563 setUniform(ubufData, name, &v, 2 *
sizeof(quint32));
566 case QSSGRenderShaderValue::UnsignedIntegerVec3:
568 const uvec3 v = inValue.value<uvec3>();
569 setUniform(ubufData, name, &v, 3 *
sizeof(quint32));
572 case QSSGRenderShaderValue::UnsignedIntegerVec4:
574 const uvec4 v = inValue.value<uvec4>();
575 setUniform(ubufData, name, &v, 4 *
sizeof(quint32));
578 case QSSGRenderShaderValue::Matrix3x3:
580 const QMatrix3x3 m = inValue.value<QMatrix3x3>();
581 setUniform(ubufData, name, m.constData(), 12 *
sizeof(
float),
nullptr, QSSGRhiShaderPipeline::UniformFlag::Mat3);
584 case QSSGRenderShaderValue::Matrix4x4:
586 const QMatrix4x4 v = inValue.value<QMatrix4x4>();
587 setUniform(ubufData, name, v.constData(), 16 *
sizeof(
float));
590 case QSSGRenderShaderValue::Size:
592 const QSize s = inValue.value<QSize>();
593 float v[2] = {
float(s.width()),
float(s.height()) };
594 setUniform(ubufData, name, v, 2 *
sizeof(
float));
597 case QSSGRenderShaderValue::SizeF:
599 const QSizeF s = inValue.value<QSizeF>();
600 float v[2] = {
float(s.width()),
float(s.height()) };
601 setUniform(ubufData, name, v, 2 *
sizeof(
float));
604 case QSSGRenderShaderValue::Point:
606 const QPoint p = inValue.value<QPoint>();
607 float v[2] = {
float(p.x()),
float(p.y()) };
608 setUniform(ubufData, name, v, 2 *
sizeof(
float));
611 case QSSGRenderShaderValue::PointF:
613 const QPointF p = inValue.value<QPointF>();
614 float v[2] = {
float(p.x()),
float(p.y()) };
615 setUniform(ubufData, name, v, 2 *
sizeof(
float));
618 case QSSGRenderShaderValue::Rect:
620 const QRect r = inValue.value<QRect>();
621 float v[4] = {
float(r.x()),
float(r.y()),
float(r.width()),
float(r.height()) };
622 setUniform(ubufData, name, v, 4 *
sizeof(
float));
625 case QSSGRenderShaderValue::RectF:
627 const QRectF r = inValue.value<QRectF>();
628 float v[4] = {
float(r.x()),
float(r.y()),
float(r.width()),
float(r.height()) };
629 setUniform(ubufData, name, v, 4 *
sizeof(
float));
632 case QSSGRenderShaderValue::Quaternion:
634 const QQuaternion q = inValue.value<QQuaternion>();
635 float v[4] = {
float(q.x()),
float(q.y()),
float(q.z()),
float(q.scalar()) };
636 setUniform(ubufData, name, v, 4 *
sizeof(
float));
640 qWarning(
"Attempted to set uniform %s value with unsupported data type %i",
721void QSSGRhiShaderPipeline::setUniformArray(
char *ubufData,
const char *name,
const void *data, size_t itemCount, QSSGRenderShaderValue::Type type,
int *storeIndex)
723 using namespace QSSGRenderShaderValue;
725 QSSGRhiShaderUniformArray *ua =
nullptr;
726 constexpr size_t std140BaseTypeSize = 4 *
sizeof(
float);
728 static const auto checkSize = [std140BaseTypeSize](QSSGRhiShaderUniformArray *ua) ->
bool {
729 Q_UNUSED(std140BaseTypeSize);
730 const size_t uniformSize = std140BaseTypeSize < ua->typeSize ? ua->typeSize * ua->itemCount : std140BaseTypeSize * ua->itemCount;
731 QSSG_ASSERT_X(uniformSize == ua->size, qPrintable(getUBMemberSizeWarning(QLatin1StringView(ua->name), uniformSize, ua->size)),
return false);
735 if (!storeIndex || *storeIndex == -1) {
737 const QByteArray ba = QByteArray::fromRawData(name, strlen(name));
738 auto it = m_uniformIndex.constFind(ba);
739 if (it != m_uniformIndex.cend()) {
741 ua = &m_uniformArrays[index];
742 }
else if (ba.size() < qsizetype(
sizeof(QSSGRhiShaderUniformArray::name))) {
743 index = m_uniformArrays.size();
744 m_uniformArrays.push_back(QSSGRhiShaderUniformArray());
745 m_uniformIndex[name] = index;
746 ua = &m_uniformArrays.last();
747 memcpy(ua->name, name, ba.size() + 1);
749 qWarning(
"Attempted to set uniform array with too long name: %s", name);
755 ua = &m_uniformArrays[*storeIndex];
761 if (ua->offset == SIZE_MAX && ua->maybeExists) {
762 auto it = m_ub0.constFind(QByteArray::fromRawData(ua->name, strlen(ua->name)));
763 if (it != m_ub0.constEnd()) {
764 ua->offset = it->offset;
768 if (ua->offset == SIZE_MAX) {
770 ua->maybeExists =
false;
774 char *p = ubufData + ua->offset;
777 case QSSGRenderShaderValue::Integer:
779 const qint32 *v =
static_cast<
const qint32 *>(data);
780 if (
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
781 ua->typeSize =
sizeof(qint32);
782 ua->itemCount = itemCount;
785 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
787 for (size_t i = 0; i < itemCount; ++i)
788 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
791 case QSSGRenderShaderValue::IntegerVec2:
793 const ivec2 *v =
static_cast<
const ivec2 *>(data);
794 if (2 *
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
795 ua->typeSize = 2 *
sizeof(qint32);
796 ua->itemCount = itemCount;
799 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
801 for (size_t i = 0; i < itemCount; ++i)
802 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
805 case QSSGRenderShaderValue::IntegerVec3:
807 const QSSGRenderShaderValue::ivec3 *v =
static_cast<
const QSSGRenderShaderValue::ivec3 *>(data);
808 if (3 *
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
809 ua->typeSize = 3 *
sizeof(qint32);
810 ua->itemCount = itemCount;
813 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
815 for (size_t i = 0; i < itemCount; ++i)
816 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
819 case QSSGRenderShaderValue::IntegerVec4:
821 const ivec4 *v =
static_cast<
const ivec4 *>(data);
822 if (4 *
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
823 ua->typeSize = 4 *
sizeof(qint32);
824 ua->itemCount = itemCount;
827 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
829 memcpy(p, v, ua->typeSize * ua->itemCount);
832 case QSSGRenderShaderValue::Float:
834 const float *v =
static_cast<
const float *>(data);
835 if (
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
836 ua->typeSize =
sizeof(
float);
837 ua->itemCount = itemCount;
840 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
842 for (size_t i = 0; i < itemCount; ++i)
843 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
846 case QSSGRenderShaderValue::Vec2:
848 const QVector2D *v =
static_cast<
const QVector2D *>(data);
849 if (2 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
850 ua->typeSize = 2 *
sizeof(
float);
851 ua->itemCount = itemCount;
854 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
856 for (size_t i = 0; i < itemCount; ++i)
857 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
860 case QSSGRenderShaderValue::Vec3:
862 const QVector3D *v =
static_cast<
const QVector3D *>(data);
863 if (3 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
864 ua->typeSize = 3 *
sizeof(
float);
865 ua->itemCount = itemCount;
868 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
870 for (size_t i = 0; i < itemCount; ++i)
871 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
874 case QSSGRenderShaderValue::Vec4:
876 const QVector4D *v =
static_cast<
const QVector4D *>(data);
877 if (4 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
878 ua->typeSize = 4 *
sizeof(
float);
879 ua->itemCount = itemCount;
882 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
884 memcpy(p, v, ua->typeSize * ua->itemCount);
887 case QSSGRenderShaderValue::Rgba:
889 const QColor *v =
static_cast<
const QColor *>(data);
890 if (4 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
891 ua->typeSize = 4 *
sizeof(
float);
892 ua->itemCount = itemCount;
895 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
897 for (size_t i = 0; i < itemCount; ++i) {
898 const QVector4D vi = QSSGUtils::color::sRGBToLinear(v[i]);
899 memcpy(p + i * std140BaseTypeSize, &vi, ua->typeSize);
903 case QSSGRenderShaderValue::UnsignedInteger:
905 const quint32 *v =
static_cast<
const quint32 *>(data);
906 if (
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
907 ua->typeSize =
sizeof(quint32);
908 ua->itemCount = itemCount;
911 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
913 for (size_t i = 0; i < itemCount; ++i)
914 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
917 case QSSGRenderShaderValue::UnsignedIntegerVec2:
919 const uvec2 *v =
static_cast<
const uvec2 *>(data);
920 if (2 *
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
921 ua->typeSize = 2 *
sizeof(quint32);
922 ua->itemCount = itemCount;
925 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
927 for (size_t i = 0; i < itemCount; ++i)
928 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
931 case QSSGRenderShaderValue::UnsignedIntegerVec3:
933 const uvec3 *v =
static_cast<
const uvec3 *>(data);
934 if (3 *
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
935 ua->typeSize = 3 *
sizeof(quint32);
936 ua->itemCount = itemCount;
939 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
941 for (size_t i = 0; i < itemCount; ++i)
942 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
945 case QSSGRenderShaderValue::UnsignedIntegerVec4:
947 const uvec4 *v =
static_cast<
const uvec4 *>(data);
948 if (4 *
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
949 ua->typeSize = 4 *
sizeof(quint32);
950 ua->itemCount = itemCount;
953 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
955 memcpy(p, v, ua->typeSize * ua->itemCount);
958 case QSSGRenderShaderValue::Matrix3x3:
960 const QMatrix3x3 *v =
static_cast<
const QMatrix3x3 *>(data);
961 if (12 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
962 ua->typeSize = 12 *
sizeof(
float);
963 ua->itemCount = itemCount;
966 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
968 for (uint i = 0; i < ua->itemCount; ++i) {
969 memcpy(p + i * ua->typeSize, v[i].constData(), 3 *
sizeof(
float));
970 memcpy(p + i * ua->typeSize + 4 *
sizeof(
float), v[i].constData() + 3, 3 *
sizeof(
float));
971 memcpy(p + i * ua->typeSize + 8 *
sizeof(
float), v[i].constData() + 6, 3 *
sizeof(
float));
975 case QSSGRenderShaderValue::Matrix4x4:
977 const QMatrix4x4 *v =
static_cast<
const QMatrix4x4 *>(data);
978 if (16 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
979 ua->typeSize = 16 *
sizeof(
float);
980 ua->itemCount = itemCount;
983 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
985 for (uint i = 0; i < ua->itemCount; ++i)
986 memcpy(p + i * ua->typeSize, &v[i] , ua->typeSize);
989 case QSSGRenderShaderValue::Boolean:
990 case QSSGRenderShaderValue::BooleanVec2:
991 case QSSGRenderShaderValue::BooleanVec3:
992 case QSSGRenderShaderValue::BooleanVec4:
993 case QSSGRenderShaderValue::Size:
994 case QSSGRenderShaderValue::SizeF:
995 case QSSGRenderShaderValue::Point:
996 case QSSGRenderShaderValue::PointF:
997 case QSSGRenderShaderValue::Rect:
998 case QSSGRenderShaderValue::RectF:
999 case QSSGRenderShaderValue::Quaternion:
1001 qWarning(
"Attempted to set uniform %s value with type %d that is unsupported for uniform arrays",
1799QRhiGraphicsPipeline *QSSGRhiContextPrivate::pipeline(
const QSSGGraphicsPipelineStateKey &key,
1800 QRhiRenderPassDescriptor *rpDesc,
1801 QRhiShaderResourceBindings *srb)
1803 auto it = m_pipelines.constFind(key);
1804 if (it != m_pipelines.constEnd())
1808 QRhiGraphicsPipeline *ps = m_rhi->newGraphicsPipeline();
1809 const auto &ia = QSSGRhiInputAssemblerStatePrivate::get(key.state);
1811 const auto *shaderPipeline = QSSGRhiGraphicsPipelineStatePrivate::getShaderPipeline(key.state);
1812 ps->setShaderStages(shaderPipeline->cbeginStages(), shaderPipeline->cendStages());
1813 ps->setVertexInputLayout(ia.inputLayout);
1814 ps->setShaderResourceBindings(srb);
1815 ps->setRenderPassDescriptor(rpDesc);
1817 QRhiGraphicsPipeline::Flags flags;
1818 if (key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor))
1819 flags |= QRhiGraphicsPipeline::UsesScissor;
1821 static const bool shaderDebugInfo = qEnvironmentVariableIntValue(
"QT_QUICK3D_SHADER_DEBUG_INFO");
1822 if (shaderDebugInfo)
1823 flags |= QRhiGraphicsPipeline::CompileShadersWithDebugInfo;
1824 ps->setFlags(flags);
1826 ps->setTopology(ia.topology);
1827 ps->setCullMode(key.state.cullMode);
1828 if (ia.topology == QRhiGraphicsPipeline::Lines || ia.topology == QRhiGraphicsPipeline::LineStrip)
1829 ps->setLineWidth(key.state.lineWidth);
1831 const bool blendEnabled = key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled);
1832 QVarLengthArray<QRhiGraphicsPipeline::TargetBlend, 8> targetBlends(key.state.colorAttachmentCount);
1833 for (
int i = 0; i < key.state.colorAttachmentCount; ++i) {
1834 targetBlends[i] = key.state.targetBlend[i];
1835 targetBlends[i].enable = blendEnabled;
1837 ps->setTargetBlends(targetBlends.cbegin(), targetBlends.cend());
1839 ps->setSampleCount(key.state.samples);
1840 ps->setMultiViewCount(key.state.viewCount);
1842 ps->setDepthTest(key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled));
1843 ps->setDepthWrite(key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled));
1844 ps->setDepthOp(key.state.depthFunc);
1846 ps->setDepthBias(key.state.depthBias);
1847 ps->setSlopeScaledDepthBias(key.state.slopeScaledDepthBias);
1848 ps->setPolygonMode(key.state.polygonMode);
1850 const bool usesStencilRef = (key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef));
1852 flags |= QRhiGraphicsPipeline::UsesStencilRef;
1853 ps->setFlags(flags);
1854 ps->setStencilFront(key.state.stencilOpFrontState);
1855 ps->setStencilTest(usesStencilRef);
1856 ps->setStencilWriteMask(key.state.stencilWriteMask);
1858 if (!ps->create()) {
1859 qWarning(
"Failed to build graphics pipeline state");
1864 m_pipelines.insert(key, ps);