386void QSSGRhiShaderPipeline::addStage(
const QRhiShaderStage &stage, StageFlags flags)
388 m_stages.append(stage);
392 if (stage.type() == QRhiShaderStage::Vertex) {
397 const QVector<QShaderDescription::UniformBlock> uniformBlocks = stage.shader().description().uniformBlocks();
398 for (
const QShaderDescription::UniformBlock &blk : uniformBlocks) {
399 if (blk.binding == 0) {
400 m_ub0Size = blk.size;
401 m_ub0NextUBufOffset = m_context.rhi()->ubufAligned(m_ub0Size);
402 for (
const QShaderDescription::BlockVariable &var : blk.members)
403 m_ub0[var.name] = var;
408 if (!flags.testFlag(UsedWithoutIa)) {
409 const QVector<QShaderDescription::InOutVariable> inputs = stage.shader().description().inputVariables();
410 for (
const QShaderDescription::InOutVariable &var : inputs) {
411 if (var.name == QSSGMesh::MeshInternal::getPositionAttrName()) {
412 m_vertexInputs[QSSGRhiInputAssemblerState::PositionSemantic] = var;
413 }
else if (var.name == QSSGMesh::MeshInternal::getNormalAttrName()) {
414 m_vertexInputs[QSSGRhiInputAssemblerState::NormalSemantic] = var;
415 }
else if (var.name == QSSGMesh::MeshInternal::getUV0AttrName()) {
416 m_vertexInputs[QSSGRhiInputAssemblerState::TexCoord0Semantic] = var;
417 }
else if (var.name == QSSGMesh::MeshInternal::getUV1AttrName()) {
418 m_vertexInputs[QSSGRhiInputAssemblerState::TexCoord1Semantic] = var;
419 }
else if (var.name == QSSGMesh::MeshInternal::getLightmapUVAttrName()) {
420 m_vertexInputs[QSSGRhiInputAssemblerState::TexCoordLightmapSemantic] = var;
421 }
else if (var.name == QSSGMesh::MeshInternal::getTexTanAttrName()) {
422 m_vertexInputs[QSSGRhiInputAssemblerState::TangentSemantic] = var;
423 }
else if (var.name == QSSGMesh::MeshInternal::getTexBinormalAttrName()) {
424 m_vertexInputs[QSSGRhiInputAssemblerState::BinormalSemantic] = var;
425 }
else if (var.name == QSSGMesh::MeshInternal::getColorAttrName()) {
426 m_vertexInputs[QSSGRhiInputAssemblerState::ColorSemantic] = var;
427 }
else if (var.name == QSSGMesh::MeshInternal::getJointAttrName()) {
428 m_vertexInputs[QSSGRhiInputAssemblerState::JointSemantic] = var;
429 }
else if (var.name == QSSGMesh::MeshInternal::getWeightAttrName()) {
430 m_vertexInputs[QSSGRhiInputAssemblerState::WeightSemantic] = var;
431 }
else if (var.name ==
"qt_instanceTransform0") {
432 instanceLocations.transform0 = var.location;
433 }
else if (var.name ==
"qt_instanceTransform1") {
434 instanceLocations.transform1 = var.location;
435 }
else if (var.name ==
"qt_instanceTransform2") {
436 instanceLocations.transform2 = var.location;
437 }
else if (var.name ==
"qt_instanceColor") {
438 instanceLocations.color = var.location;
439 }
else if (var.name ==
"qt_instanceData") {
440 instanceLocations.data = var.location;
442 qWarning(
"Ignoring vertex input %s in shader", var.name.constData());
448 const QVector<QShaderDescription::InOutVariable> combinedImageSamplers = stage.shader().description().combinedImageSamplers();
449 for (
const QShaderDescription::InOutVariable &var : combinedImageSamplers)
450 m_combinedImageSamplers[var.name] = var;
452 const QVector<QShaderDescription::InOutVariable> storageImages = stage.shader().description().storageImages() + stage.shader().description().separateImages();
453 for (
const QShaderDescription::InOutVariable &var : storageImages)
454 m_storageImages[var.name] = var;
456 std::fill(m_materialImageSamplerBindings,
457 m_materialImageSamplerBindings + size_t(QSSGRhiSamplerBindingHints::BindingMapSize),
466void QSSGRhiShaderPipeline::setUniformValue(
char *ubufData,
const char *name,
const QVariant &inValue, QSSGRenderShaderValue::Type inType)
468 using namespace QSSGRenderShaderValue;
470 case QSSGRenderShaderValue::Integer:
472 const qint32 v = inValue.toInt();
473 setUniform(ubufData, name, &v,
sizeof(qint32));
476 case QSSGRenderShaderValue::IntegerVec2:
478 const ivec2 v = inValue.value<ivec2>();
479 setUniform(ubufData, name, &v, 2 *
sizeof(qint32));
482 case QSSGRenderShaderValue::IntegerVec3:
484 const ivec3 v = inValue.value<ivec3>();
485 setUniform(ubufData, name, &v, 3 *
sizeof(qint32));
488 case QSSGRenderShaderValue::IntegerVec4:
490 const ivec4 v = inValue.value<ivec4>();
491 setUniform(ubufData, name, &v, 4 *
sizeof(qint32));
494 case QSSGRenderShaderValue::Boolean:
497 const qint32 v = inValue.value<
bool>();
498 setUniform(ubufData, name, &v,
sizeof(qint32));
501 case QSSGRenderShaderValue::BooleanVec2:
503 const bvec2 b = inValue.value<bvec2>();
504 const ivec2 v(b.x, b.y);
505 setUniform(ubufData, name, &v, 2 *
sizeof(qint32));
508 case QSSGRenderShaderValue::BooleanVec3:
510 const bvec3 b = inValue.value<bvec3>();
511 const ivec3 v(b.x, b.y, b.z);
512 setUniform(ubufData, name, &v, 3 *
sizeof(qint32));
515 case QSSGRenderShaderValue::BooleanVec4:
517 const bvec4 b = inValue.value<bvec4>();
518 const ivec4 v(b.x, b.y, b.z, b.w);
519 setUniform(ubufData, name, &v, 4 *
sizeof(qint32));
522 case QSSGRenderShaderValue::Float:
524 const float v = inValue.value<
float>();
525 setUniform(ubufData, name, &v,
sizeof(
float));
528 case QSSGRenderShaderValue::Vec2:
530 const QVector2D v = inValue.value<QVector2D>();
531 setUniform(ubufData, name, &v, 2 *
sizeof(
float));
534 case QSSGRenderShaderValue::Vec3:
536 const QVector3D v = inValue.value<QVector3D>();
537 setUniform(ubufData, name, &v, 3 *
sizeof(
float));
540 case QSSGRenderShaderValue::Vec4:
542 const QVector4D v = inValue.value<QVector4D>();
543 setUniform(ubufData, name, &v, 4 *
sizeof(
float));
546 case QSSGRenderShaderValue::Rgba:
548 const QVector4D v = QSSGUtils::color::sRGBToLinear(inValue.value<QColor>());
549 setUniform(ubufData, name, &v, 4 *
sizeof(
float));
552 case QSSGRenderShaderValue::UnsignedInteger:
554 const quint32 v = inValue.value<quint32>();
555 setUniform(ubufData, name, &v,
sizeof(quint32));
558 case QSSGRenderShaderValue::UnsignedIntegerVec2:
560 const uvec2 v = inValue.value<uvec2>();
561 setUniform(ubufData, name, &v, 2 *
sizeof(quint32));
564 case QSSGRenderShaderValue::UnsignedIntegerVec3:
566 const uvec3 v = inValue.value<uvec3>();
567 setUniform(ubufData, name, &v, 3 *
sizeof(quint32));
570 case QSSGRenderShaderValue::UnsignedIntegerVec4:
572 const uvec4 v = inValue.value<uvec4>();
573 setUniform(ubufData, name, &v, 4 *
sizeof(quint32));
576 case QSSGRenderShaderValue::Matrix3x3:
578 const QMatrix3x3 m = inValue.value<QMatrix3x3>();
579 setUniform(ubufData, name, m.constData(), 12 *
sizeof(
float),
nullptr, QSSGRhiShaderPipeline::UniformFlag::Mat3);
582 case QSSGRenderShaderValue::Matrix4x4:
584 const QMatrix4x4 v = inValue.value<QMatrix4x4>();
585 setUniform(ubufData, name, v.constData(), 16 *
sizeof(
float));
588 case QSSGRenderShaderValue::Size:
590 const QSize s = inValue.value<QSize>();
591 float v[2] = {
float(s.width()),
float(s.height()) };
592 setUniform(ubufData, name, v, 2 *
sizeof(
float));
595 case QSSGRenderShaderValue::SizeF:
597 const QSizeF s = inValue.value<QSizeF>();
598 float v[2] = {
float(s.width()),
float(s.height()) };
599 setUniform(ubufData, name, v, 2 *
sizeof(
float));
602 case QSSGRenderShaderValue::Point:
604 const QPoint p = inValue.value<QPoint>();
605 float v[2] = {
float(p.x()),
float(p.y()) };
606 setUniform(ubufData, name, v, 2 *
sizeof(
float));
609 case QSSGRenderShaderValue::PointF:
611 const QPointF p = inValue.value<QPointF>();
612 float v[2] = {
float(p.x()),
float(p.y()) };
613 setUniform(ubufData, name, v, 2 *
sizeof(
float));
616 case QSSGRenderShaderValue::Rect:
618 const QRect r = inValue.value<QRect>();
619 float v[4] = {
float(r.x()),
float(r.y()),
float(r.width()),
float(r.height()) };
620 setUniform(ubufData, name, v, 4 *
sizeof(
float));
623 case QSSGRenderShaderValue::RectF:
625 const QRectF r = inValue.value<QRectF>();
626 float v[4] = {
float(r.x()),
float(r.y()),
float(r.width()),
float(r.height()) };
627 setUniform(ubufData, name, v, 4 *
sizeof(
float));
630 case QSSGRenderShaderValue::Quaternion:
632 const QQuaternion q = inValue.value<QQuaternion>();
633 float v[4] = {
float(q.x()),
float(q.y()),
float(q.z()),
float(q.scalar()) };
634 setUniform(ubufData, name, v, 4 *
sizeof(
float));
638 qWarning(
"Attempted to set uniform %s value with unsupported data type %i",
719void QSSGRhiShaderPipeline::setUniformArray(
char *ubufData,
const char *name,
const void *data, size_t itemCount, QSSGRenderShaderValue::Type type,
int *storeIndex)
721 using namespace QSSGRenderShaderValue;
723 QSSGRhiShaderUniformArray *ua =
nullptr;
724 constexpr size_t std140BaseTypeSize = 4 *
sizeof(
float);
726 static const auto checkSize = [std140BaseTypeSize](QSSGRhiShaderUniformArray *ua) ->
bool {
727 Q_UNUSED(std140BaseTypeSize);
728 const size_t uniformSize = std140BaseTypeSize < ua->typeSize ? ua->typeSize * ua->itemCount : std140BaseTypeSize * ua->itemCount;
729 QSSG_ASSERT_X(uniformSize == ua->size, qPrintable(getUBMemberSizeWarning(QLatin1StringView(ua->name), uniformSize, ua->size)),
return false);
733 if (!storeIndex || *storeIndex == -1) {
735 const QByteArray ba = QByteArray::fromRawData(name, strlen(name));
736 auto it = m_uniformIndex.constFind(ba);
737 if (it != m_uniformIndex.cend()) {
739 ua = &m_uniformArrays[index];
740 }
else if (ba.size() < qsizetype(
sizeof(QSSGRhiShaderUniformArray::name))) {
741 index = m_uniformArrays.size();
742 m_uniformArrays.push_back(QSSGRhiShaderUniformArray());
743 m_uniformIndex[name] = index;
744 ua = &m_uniformArrays.last();
745 memcpy(ua->name, name, ba.size() + 1);
747 qWarning(
"Attempted to set uniform array with too long name: %s", name);
753 ua = &m_uniformArrays[*storeIndex];
759 if (ua->offset == SIZE_MAX && ua->maybeExists) {
760 auto it = m_ub0.constFind(QByteArray::fromRawData(ua->name, strlen(ua->name)));
761 if (it != m_ub0.constEnd()) {
762 ua->offset = it->offset;
766 if (ua->offset == SIZE_MAX) {
768 ua->maybeExists =
false;
772 char *p = ubufData + ua->offset;
775 case QSSGRenderShaderValue::Integer:
777 const qint32 *v =
static_cast<
const qint32 *>(data);
778 if (
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
779 ua->typeSize =
sizeof(qint32);
780 ua->itemCount = itemCount;
783 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
785 for (size_t i = 0; i < itemCount; ++i)
786 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
789 case QSSGRenderShaderValue::IntegerVec2:
791 const ivec2 *v =
static_cast<
const ivec2 *>(data);
792 if (2 *
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
793 ua->typeSize = 2 *
sizeof(qint32);
794 ua->itemCount = itemCount;
797 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
799 for (size_t i = 0; i < itemCount; ++i)
800 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
803 case QSSGRenderShaderValue::IntegerVec3:
805 const QSSGRenderShaderValue::ivec3 *v =
static_cast<
const QSSGRenderShaderValue::ivec3 *>(data);
806 if (3 *
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
807 ua->typeSize = 3 *
sizeof(qint32);
808 ua->itemCount = itemCount;
811 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
813 for (size_t i = 0; i < itemCount; ++i)
814 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
817 case QSSGRenderShaderValue::IntegerVec4:
819 const ivec4 *v =
static_cast<
const ivec4 *>(data);
820 if (4 *
sizeof(qint32) != ua->typeSize || itemCount != ua->itemCount) {
821 ua->typeSize = 4 *
sizeof(qint32);
822 ua->itemCount = itemCount;
825 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
827 memcpy(p, v, ua->typeSize * ua->itemCount);
830 case QSSGRenderShaderValue::Float:
832 const float *v =
static_cast<
const float *>(data);
833 if (
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
834 ua->typeSize =
sizeof(
float);
835 ua->itemCount = itemCount;
838 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
840 for (size_t i = 0; i < itemCount; ++i)
841 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
844 case QSSGRenderShaderValue::Vec2:
846 const QVector2D *v =
static_cast<
const QVector2D *>(data);
847 if (2 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
848 ua->typeSize = 2 *
sizeof(
float);
849 ua->itemCount = itemCount;
852 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
854 for (size_t i = 0; i < itemCount; ++i)
855 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
858 case QSSGRenderShaderValue::Vec3:
860 const QVector3D *v =
static_cast<
const QVector3D *>(data);
861 if (3 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
862 ua->typeSize = 3 *
sizeof(
float);
863 ua->itemCount = itemCount;
866 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
868 for (size_t i = 0; i < itemCount; ++i)
869 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
872 case QSSGRenderShaderValue::Vec4:
874 const QVector4D *v =
static_cast<
const QVector4D *>(data);
875 if (4 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
876 ua->typeSize = 4 *
sizeof(
float);
877 ua->itemCount = itemCount;
880 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
882 memcpy(p, v, ua->typeSize * ua->itemCount);
885 case QSSGRenderShaderValue::Rgba:
887 const QColor *v =
static_cast<
const QColor *>(data);
888 if (4 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
889 ua->typeSize = 4 *
sizeof(
float);
890 ua->itemCount = itemCount;
893 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
895 for (size_t i = 0; i < itemCount; ++i) {
896 const QVector4D vi = QSSGUtils::color::sRGBToLinear(v[i]);
897 memcpy(p + i * std140BaseTypeSize, &vi, ua->typeSize);
901 case QSSGRenderShaderValue::UnsignedInteger:
903 const quint32 *v =
static_cast<
const quint32 *>(data);
904 if (
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
905 ua->typeSize =
sizeof(quint32);
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::UnsignedIntegerVec2:
917 const uvec2 *v =
static_cast<
const uvec2 *>(data);
918 if (2 *
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
919 ua->typeSize = 2 *
sizeof(quint32);
920 ua->itemCount = itemCount;
923 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
925 for (size_t i = 0; i < itemCount; ++i)
926 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
929 case QSSGRenderShaderValue::UnsignedIntegerVec3:
931 const uvec3 *v =
static_cast<
const uvec3 *>(data);
932 if (3 *
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
933 ua->typeSize = 3 *
sizeof(quint32);
934 ua->itemCount = itemCount;
937 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
939 for (size_t i = 0; i < itemCount; ++i)
940 memcpy(p + i * std140BaseTypeSize, &v[i], ua->typeSize);
943 case QSSGRenderShaderValue::UnsignedIntegerVec4:
945 const uvec4 *v =
static_cast<
const uvec4 *>(data);
946 if (4 *
sizeof(quint32) != ua->typeSize || itemCount != ua->itemCount) {
947 ua->typeSize = 4 *
sizeof(quint32);
948 ua->itemCount = itemCount;
951 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
953 memcpy(p, v, ua->typeSize * ua->itemCount);
956 case QSSGRenderShaderValue::Matrix3x3:
958 const QMatrix3x3 *v =
static_cast<
const QMatrix3x3 *>(data);
959 if (12 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
960 ua->typeSize = 12 *
sizeof(
float);
961 ua->itemCount = itemCount;
964 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
966 for (uint i = 0; i < ua->itemCount; ++i) {
967 memcpy(p + i * ua->typeSize, v[i].constData(), 3 *
sizeof(
float));
968 memcpy(p + i * ua->typeSize + 4 *
sizeof(
float), v[i].constData() + 3, 3 *
sizeof(
float));
969 memcpy(p + i * ua->typeSize + 8 *
sizeof(
float), v[i].constData() + 6, 3 *
sizeof(
float));
973 case QSSGRenderShaderValue::Matrix4x4:
975 const QMatrix4x4 *v =
static_cast<
const QMatrix4x4 *>(data);
976 if (16 *
sizeof(
float) != ua->typeSize || itemCount != ua->itemCount) {
977 ua->typeSize = 16 *
sizeof(
float);
978 ua->itemCount = itemCount;
981 QSSG_ASSERT(QSSG_DEBUG_COND(checkSize(ua)),
return);
983 for (uint i = 0; i < ua->itemCount; ++i)
984 memcpy(p + i * ua->typeSize, &v[i] , ua->typeSize);
987 case QSSGRenderShaderValue::Boolean:
988 case QSSGRenderShaderValue::BooleanVec2:
989 case QSSGRenderShaderValue::BooleanVec3:
990 case QSSGRenderShaderValue::BooleanVec4:
991 case QSSGRenderShaderValue::Size:
992 case QSSGRenderShaderValue::SizeF:
993 case QSSGRenderShaderValue::Point:
994 case QSSGRenderShaderValue::PointF:
995 case QSSGRenderShaderValue::Rect:
996 case QSSGRenderShaderValue::RectF:
997 case QSSGRenderShaderValue::Quaternion:
999 qWarning(
"Attempted to set uniform %s value with type %d that is unsupported for uniform arrays",
1744QRhiGraphicsPipeline *QSSGRhiContextPrivate::pipeline(
const QSSGGraphicsPipelineStateKey &key,
1745 QRhiRenderPassDescriptor *rpDesc,
1746 QRhiShaderResourceBindings *srb)
1748 auto it = m_pipelines.constFind(key);
1749 if (it != m_pipelines.constEnd())
1753 QRhiGraphicsPipeline *ps = m_rhi->newGraphicsPipeline();
1754 const auto &ia = QSSGRhiInputAssemblerStatePrivate::get(key.state);
1756 const auto *shaderPipeline = QSSGRhiGraphicsPipelineStatePrivate::getShaderPipeline(key.state);
1757 ps->setShaderStages(shaderPipeline->cbeginStages(), shaderPipeline->cendStages());
1758 ps->setVertexInputLayout(ia.inputLayout);
1759 ps->setShaderResourceBindings(srb);
1760 ps->setRenderPassDescriptor(rpDesc);
1762 QRhiGraphicsPipeline::Flags flags;
1763 if (key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor))
1764 flags |= QRhiGraphicsPipeline::UsesScissor;
1766 static const bool shaderDebugInfo = qEnvironmentVariableIntValue(
"QT_QUICK3D_SHADER_DEBUG_INFO");
1767 if (shaderDebugInfo)
1768 flags |= QRhiGraphicsPipeline::CompileShadersWithDebugInfo;
1769 ps->setFlags(flags);
1771 ps->setTopology(ia.topology);
1772 ps->setCullMode(key.state.cullMode);
1773 if (ia.topology == QRhiGraphicsPipeline::Lines || ia.topology == QRhiGraphicsPipeline::LineStrip)
1774 ps->setLineWidth(key.state.lineWidth);
1776 const bool blendEnabled = key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled);
1777 QVarLengthArray<QRhiGraphicsPipeline::TargetBlend, 8> targetBlends(key.state.colorAttachmentCount);
1778 for (
int i = 0; i < key.state.colorAttachmentCount; ++i) {
1779 targetBlends[i] = key.state.targetBlend[i];
1780 targetBlends[i].enable = blendEnabled;
1782 ps->setTargetBlends(targetBlends.cbegin(), targetBlends.cend());
1784 ps->setSampleCount(key.state.samples);
1785 ps->setMultiViewCount(key.state.viewCount);
1787 ps->setDepthTest(key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled));
1788 ps->setDepthWrite(key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled));
1789 ps->setDepthOp(key.state.depthFunc);
1791 ps->setDepthBias(key.state.depthBias);
1792 ps->setSlopeScaledDepthBias(key.state.slopeScaledDepthBias);
1793 ps->setPolygonMode(key.state.polygonMode);
1795 const bool usesStencilRef = (key.state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef));
1797 flags |= QRhiGraphicsPipeline::UsesStencilRef;
1798 ps->setFlags(flags);
1799 ps->setStencilFront(key.state.stencilOpFrontState);
1800 ps->setStencilTest(usesStencilRef);
1801 ps->setStencilWriteMask(key.state.stencilWriteMask);
1803 if (!ps->create()) {
1804 qWarning(
"Failed to build graphics pipeline state");
1809 m_pipelines.insert(key, ps);