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());
449 const QVector<QShaderDescription::StorageBlock> storageBlocks = stage.shader().description().storageBlocks();
450 for (
const QShaderDescription::StorageBlock &blk : storageBlocks) {
452 m_storageBuffers[blk.blockName] = blk;
455 const QVector<QShaderDescription::InOutVariable> combinedImageSamplers = stage.shader().description().combinedImageSamplers();
456 for (
const QShaderDescription::InOutVariable &var : combinedImageSamplers)
457 m_combinedImageSamplers[var.name] = var;
459 const QVector<QShaderDescription::InOutVariable> storageImages = stage.shader().description().storageImages() + stage.shader().description().separateImages();
460 for (
const QShaderDescription::InOutVariable &var : storageImages)
461 m_storageImages[var.name] = var;
463 std::fill(m_materialImageSamplerBindings,
464 m_materialImageSamplerBindings + size_t(QSSGRhiSamplerBindingHints::BindingMapSize),
509void QSSGRhiShaderPipeline::setUniformValue(
char *ubufData,
const char *name,
const QVariant &inValue, QSSGRenderShaderValue::Type inType)
511 using namespace QSSGRenderShaderValue;
513 case QSSGRenderShaderValue::Integer:
515 const qint32 v = inValue.toInt();
516 setUniform(ubufData, name, &v,
sizeof(qint32));
519 case QSSGRenderShaderValue::IntegerVec2:
521 const ivec2 v = inValue.value<ivec2>();
522 setUniform(ubufData, name, &v, 2 *
sizeof(qint32));
525 case QSSGRenderShaderValue::IntegerVec3:
527 const ivec3 v = inValue.value<ivec3>();
528 setUniform(ubufData, name, &v, 3 *
sizeof(qint32));
531 case QSSGRenderShaderValue::IntegerVec4:
533 const ivec4 v = inValue.value<ivec4>();
534 setUniform(ubufData, name, &v, 4 *
sizeof(qint32));
537 case QSSGRenderShaderValue::Boolean:
540 const qint32 v = inValue.value<
bool>();
541 setUniform(ubufData, name, &v,
sizeof(qint32));
544 case QSSGRenderShaderValue::BooleanVec2:
546 const bvec2 b = inValue.value<bvec2>();
547 const ivec2 v(b.x, b.y);
548 setUniform(ubufData, name, &v, 2 *
sizeof(qint32));
551 case QSSGRenderShaderValue::BooleanVec3:
553 const bvec3 b = inValue.value<bvec3>();
554 const ivec3 v(b.x, b.y, b.z);
555 setUniform(ubufData, name, &v, 3 *
sizeof(qint32));
558 case QSSGRenderShaderValue::BooleanVec4:
560 const bvec4 b = inValue.value<bvec4>();
561 const ivec4 v(b.x, b.y, b.z, b.w);
562 setUniform(ubufData, name, &v, 4 *
sizeof(qint32));
565 case QSSGRenderShaderValue::Float:
567 const float v = inValue.value<
float>();
568 setUniform(ubufData, name, &v,
sizeof(
float));
571 case QSSGRenderShaderValue::Vec2:
573 const QVector2D v = inValue.value<QVector2D>();
574 setUniform(ubufData, name, &v, 2 *
sizeof(
float));
577 case QSSGRenderShaderValue::Vec3:
579 const QVector3D v = inValue.value<QVector3D>();
580 setUniform(ubufData, name, &v, 3 *
sizeof(
float));
583 case QSSGRenderShaderValue::Vec4:
585 const QVector4D v = inValue.value<QVector4D>();
586 setUniform(ubufData, name, &v, 4 *
sizeof(
float));
589 case QSSGRenderShaderValue::Rgba:
591 const QVector4D v = QSSGUtils::color::sRGBToLinear(inValue.value<QColor>());
592 setUniform(ubufData, name, &v, 4 *
sizeof(
float));
595 case QSSGRenderShaderValue::UnsignedInteger:
597 const quint32 v = inValue.value<quint32>();
598 setUniform(ubufData, name, &v,
sizeof(quint32));
601 case QSSGRenderShaderValue::UnsignedIntegerVec2:
603 const uvec2 v = inValue.value<uvec2>();
604 setUniform(ubufData, name, &v, 2 *
sizeof(quint32));
607 case QSSGRenderShaderValue::UnsignedIntegerVec3:
609 const uvec3 v = inValue.value<uvec3>();
610 setUniform(ubufData, name, &v, 3 *
sizeof(quint32));
613 case QSSGRenderShaderValue::UnsignedIntegerVec4:
615 const uvec4 v = inValue.value<uvec4>();
616 setUniform(ubufData, name, &v, 4 *
sizeof(quint32));
619 case QSSGRenderShaderValue::Matrix3x3:
621 const QMatrix3x3 m = inValue.value<QMatrix3x3>();
622 setUniform(ubufData, name, m.constData(), 12 *
sizeof(
float),
nullptr, QSSGRhiShaderPipeline::UniformFlag::Mat3);
625 case QSSGRenderShaderValue::Matrix4x4:
627 const QMatrix4x4 v = inValue.value<QMatrix4x4>();
628 setUniform(ubufData, name, v.constData(), 16 *
sizeof(
float));
631 case QSSGRenderShaderValue::Size:
633 const QSize s = inValue.value<QSize>();
634 float v[2] = {
float(s.width()),
float(s.height()) };
635 setUniform(ubufData, name, v, 2 *
sizeof(
float));
638 case QSSGRenderShaderValue::SizeF:
640 const QSizeF s = inValue.value<QSizeF>();
641 float v[2] = {
float(s.width()),
float(s.height()) };
642 setUniform(ubufData, name, v, 2 *
sizeof(
float));
645 case QSSGRenderShaderValue::Point:
647 const QPoint p = inValue.value<QPoint>();
648 float v[2] = {
float(p.x()),
float(p.y()) };
649 setUniform(ubufData, name, v, 2 *
sizeof(
float));
652 case QSSGRenderShaderValue::PointF:
654 const QPointF p = inValue.value<QPointF>();
655 float v[2] = {
float(p.x()),
float(p.y()) };
656 setUniform(ubufData, name, v, 2 *
sizeof(
float));
659 case QSSGRenderShaderValue::Rect:
661 const QRect r = inValue.value<QRect>();
662 float v[4] = {
float(r.x()),
float(r.y()),
float(r.width()),
float(r.height()) };
663 setUniform(ubufData, name, v, 4 *
sizeof(
float));
666 case QSSGRenderShaderValue::RectF:
668 const QRectF r = inValue.value<QRectF>();
669 float v[4] = {
float(r.x()),
float(r.y()),
float(r.width()),
float(r.height()) };
670 setUniform(ubufData, name, v, 4 *
sizeof(
float));
673 case QSSGRenderShaderValue::Quaternion:
675 const QQuaternion q = inValue.value<QQuaternion>();
676 float v[4] = {
float(q.x()),
float(q.y()),
float(q.z()),
float(q.scalar()) };
677 setUniform(ubufData, name, v, 4 *
sizeof(
float));
681 qWarning(
"Attempted to set uniform %s value with unsupported data type %i",
762void QSSGRhiShaderPipeline::setUniformArray(
char *ubufData,
const char *name,
const void *data, size_t itemCount, QSSGRenderShaderValue::Type type,
int *storeIndex)
764 using namespace QSSGRenderShaderValue;
766 QSSGRhiShaderUniformArray *ua =
nullptr;
767 constexpr size_t std140BaseTypeSize = 4 *
sizeof(
float);
769 static const auto checkSize = [std140BaseTypeSize](QSSGRhiShaderUniformArray *ua) ->
bool {
770 Q_UNUSED(std140BaseTypeSize);
771 const size_t uniformSize = std140BaseTypeSize < ua->typeSize ? ua->typeSize * ua->itemCount : std140BaseTypeSize * ua->itemCount;
772 QSSG_ASSERT_X(uniformSize == ua->size, qPrintable(getUBMemberSizeWarning(QLatin1StringView(ua->name), uniformSize, ua->size)),
return false);
776 if (!storeIndex || *storeIndex == -1) {
778 const QByteArray ba = QByteArray::fromRawData(name, strlen(name));
779 auto it = m_uniformIndex.constFind(ba);
780 if (it != m_uniformIndex.cend()) {
782 ua = &m_uniformArrays[index];
783 }
else if (ba.size() < qsizetype(
sizeof(QSSGRhiShaderUniformArray::name))) {
784 index = m_uniformArrays.size();
785 m_uniformArrays.push_back(QSSGRhiShaderUniformArray());
786 m_uniformIndex[name] = index;
787 ua = &m_uniformArrays.last();
788 memcpy(ua->name, name, ba.size() + 1);
790 qWarning(
"Attempted to set uniform array with too long name: %s", name);
796 ua = &m_uniformArrays[*storeIndex];
802 if (ua->offset == SIZE_MAX && ua->maybeExists) {
803 auto it = m_ub0.constFind(QByteArray::fromRawData(ua->name, strlen(ua->name)));
804 if (it != m_ub0.constEnd()) {
805 ua->offset = it->offset;
809 if (ua->offset == SIZE_MAX) {
811 ua->maybeExists =
false;
815 char *p = ubufData + ua->offset;
818 case QSSGRenderShaderValue::Integer:
820 const qint32 *v =
static_cast<
const qint32 *>(data);
821 if (
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
822 ua->typeSize =
sizeof(qint32);
823 ua->itemCount = itemCount;
826 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
828 for (size_t i = 0; i < itemCount; ++i)
829 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
832 case QSSGRenderShaderValue::IntegerVec2:
834 const ivec2 *v =
static_cast<
const ivec2 *>(data);
835 if (2 *
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
836 ua->typeSize = 2 *
sizeof(qint32);
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::IntegerVec3:
848 const QSSGRenderShaderValue::ivec3 *v =
static_cast<
const QSSGRenderShaderValue::ivec3 *>(data);
849 if (3 *
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
850 ua->typeSize = 3 *
sizeof(qint32);
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::IntegerVec4:
862 const ivec4 *v =
static_cast<
const ivec4 *>(data);
863 if (4 *
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
864 ua->typeSize = 4 *
sizeof(qint32);
865 ua->itemCount = itemCount;
868 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
870 memcpy(p, v, ua->typeSize * ua->itemCount);
873 case QSSGRenderShaderValue::Float:
875 const float *v =
static_cast<
const float *>(data);
876 if (
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
877 ua->typeSize =
sizeof(
float);
878 ua->itemCount = itemCount;
881 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
883 for (size_t i = 0; i < itemCount; ++i)
884 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
887 case QSSGRenderShaderValue::Vec2:
889 const QVector2D *v =
static_cast<
const QVector2D *>(data);
890 if (2 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
891 ua->typeSize = 2 *
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 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
901 case QSSGRenderShaderValue::Vec3:
903 const QVector3D *v =
static_cast<
const QVector3D *>(data);
904 if (3 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
905 ua->typeSize = 3 *
sizeof(
float);
906 ua->itemCount = itemCount;
909 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
911 for (size_t i = 0; i < itemCount; ++i)
912 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
915 case QSSGRenderShaderValue::Vec4:
917 const QVector4D *v =
static_cast<
const QVector4D *>(data);
918 if (4 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
919 ua->typeSize = 4 *
sizeof(
float);
920 ua->itemCount = itemCount;
923 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
925 memcpy(p, v, ua->typeSize * ua->itemCount);
928 case QSSGRenderShaderValue::Rgba:
930 const QColor *v =
static_cast<
const QColor *>(data);
931 if (4 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
932 ua->typeSize = 4 *
sizeof(
float);
933 ua->itemCount = itemCount;
936 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
938 for (size_t i = 0; i < itemCount; ++i) {
939 const QVector4D vi = QSSGUtils::color::sRGBToLinear(v[i]);
940 memcpy(p + i * std140BaseTypeSize, &vi, ua->typeSize);
944 case QSSGRenderShaderValue::UnsignedInteger:
946 const quint32 *v =
static_cast<
const quint32 *>(data);
947 if (
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
948 ua->typeSize =
sizeof(quint32);
949 ua->itemCount = itemCount;
952 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
954 for (size_t i = 0; i < itemCount; ++i)
955 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
958 case QSSGRenderShaderValue::UnsignedIntegerVec2:
960 const uvec2 *v =
static_cast<
const uvec2 *>(data);
961 if (2 *
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
962 ua->typeSize = 2 *
sizeof(quint32);
963 ua->itemCount = itemCount;
966 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
968 for (size_t i = 0; i < itemCount; ++i)
969 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
972 case QSSGRenderShaderValue::UnsignedIntegerVec3:
974 const uvec3 *v =
static_cast<
const uvec3 *>(data);
975 if (3 *
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
976 ua->typeSize = 3 *
sizeof(quint32);
977 ua->itemCount = itemCount;
980 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
982 for (size_t i = 0; i < itemCount; ++i)
983 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
986 case QSSGRenderShaderValue::UnsignedIntegerVec4:
988 const uvec4 *v =
static_cast<
const uvec4 *>(data);
989 if (4 *
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
990 ua->typeSize = 4 *
sizeof(quint32);
991 ua->itemCount = itemCount;
994 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
996 memcpy(p, v, ua->typeSize * ua->itemCount);
999 case QSSGRenderShaderValue::Matrix3x3:
1001 const QMatrix3x3 *v =
static_cast<
const QMatrix3x3 *>(data);
1002 if (12 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
1003 ua->typeSize = 12 *
sizeof(
float);
1004 ua->itemCount = itemCount;
1007 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
1009 for (uint i = 0; i < ua->itemCount; ++i) {
1010 memcpy(p + i * ua->typeSize, v[i].constData(), 3 *
sizeof(
float));
1011 memcpy(p + i * ua->typeSize + 4 *
sizeof(
float), v[i].constData() + 3, 3 *
sizeof(
float));
1012 memcpy(p + i * ua->typeSize + 8 *
sizeof(
float), v[i].constData() + 6, 3 *
sizeof(
float));
1016 case QSSGRenderShaderValue::Matrix4x4:
1018 const QMatrix4x4 *v =
static_cast<
const QMatrix4x4 *>(data);
1019 if (16 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
1020 ua->typeSize = 16 *
sizeof(
float);
1021 ua->itemCount = itemCount;
1024 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
1026 for (uint i = 0; i < ua->itemCount; ++i)
1027 memcpy(p + i * ua->typeSize, &v[i] , ua->typeSize);
1030 case QSSGRenderShaderValue::Boolean:
1031 case QSSGRenderShaderValue::BooleanVec2:
1032 case QSSGRenderShaderValue::BooleanVec3:
1033 case QSSGRenderShaderValue::BooleanVec4:
1034 case QSSGRenderShaderValue::Size:
1035 case QSSGRenderShaderValue::SizeF:
1036 case QSSGRenderShaderValue::Point:
1037 case QSSGRenderShaderValue::PointF:
1038 case QSSGRenderShaderValue::Rect:
1039 case QSSGRenderShaderValue::RectF:
1040 case QSSGRenderShaderValue::Quaternion:
1042 qWarning(
"Attempted to set uniform %s value with type %d that is unsupported for uniform arrays",
1850QRhiGraphicsPipeline *QSSGRhiContextPrivate::pipeline(
const QSSGGraphicsPipelineStateKey &key,
1851 QRhiRenderPassDescriptor *rpDesc,
1852 QRhiShaderResourceBindings *srb)
1854 auto it = m_pipelines.constFind(key);
1855 if (it != m_pipelines.constEnd())
1859 QRhiGraphicsPipeline *ps = m_rhi->newGraphicsPipeline();
1860 const auto &ia = QSSGRhiInputAssemblerStatePrivate::get(key.state);
1862 const auto *shaderPipeline = QSSGRhiGraphicsPipelineStatePrivate::getShaderPipeline(key.state);
1863 ps->setShaderStages(shaderPipeline->cbeginStages(), shaderPipeline->cendStages());
1864 ps->setVertexInputLayout(ia.inputLayout);
1865 ps->setShaderResourceBindings(srb);
1866 ps->setRenderPassDescriptor(rpDesc);
1868 QRhiGraphicsPipeline::Flags flags;
1869 if (key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor))
1870 flags |= QRhiGraphicsPipeline::UsesScissor;
1872 static const bool shaderDebugInfo = qEnvironmentVariableIntValue(
"QT_QUICK3D_SHADER_DEBUG_INFO");
1873 if (shaderDebugInfo)
1874 flags |= QRhiGraphicsPipeline::CompileShadersWithDebugInfo;
1875 ps->setFlags(flags);
1877 ps->setTopology(ia.topology);
1878 ps->setCullMode(key.state.cullMode);
1879 if (ia.topology == QRhiGraphicsPipeline::Lines || ia.topology == QRhiGraphicsPipeline::LineStrip)
1880 ps->setLineWidth(key.state.lineWidth);
1882 const bool blendEnabled = key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled);
1883 QVarLengthArray<QRhiGraphicsPipeline::TargetBlend, 8> targetBlends(key.state.colorAttachmentCount);
1884 for (
int i = 0; i < key.state.colorAttachmentCount; ++i) {
1885 targetBlends[i] = key.state.targetBlend[i];
1886 targetBlends[i].enable = blendEnabled;
1888 ps->setTargetBlends(targetBlends.cbegin(), targetBlends.cend());
1890 ps->setSampleCount(key.state.samples);
1891 ps->setMultiViewCount(key.state.viewCount);
1893 ps->setDepthTest(key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled));
1894 ps->setDepthWrite(key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled));
1895 ps->setDepthOp(key.state.depthFunc);
1897 ps->setDepthBias(key.state.depthBias);
1898 ps->setSlopeScaledDepthBias(key.state.slopeScaledDepthBias);
1899 ps->setPolygonMode(key.state.polygonMode);
1901 const bool usesStencilRef = (key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef));
1903 flags |= QRhiGraphicsPipeline::UsesStencilRef;
1904 ps->setFlags(flags);
1905 ps->setStencilFront(key.state.stencilOpFrontState);
1906 ps->setStencilTest(usesStencilRef);
1907 ps->setStencilWriteMask(key.state.stencilWriteMask);
1909 if (!ps->create()) {
1910 qWarning(
"Failed to build graphics pipeline state");
1915 m_pipelines.insert(key, ps);