250 const QSSGRenderCamera &inCamera,
251 const QSSGRenderLight *inLight,
252 const int shadowMapResolution,
253 const float pcfRadius,
254 const float clipNear,
256 const QSSGBounds3 &castingObjectsBox,
257 const QSSGBounds3 &receivingObjectsBox,
258 bool lockShadowmapTexels,
259 QSSGDebugDrawSystem *debugDrawSystem,
261 bool drawSceneCascadeIntersection)
263 Q_ASSERT(inLight->type == QSSGRenderLight::Type::DirectionalLight);
264 QVarLengthArray<std::unique_ptr<QSSGRenderCamera>, 4> result;
266 if (clipNear >= clipFar || qFuzzyCompare(clipNear, clipFar))
269 const QMatrix4x4 lightGlobalTransform = data.getGlobalTransform(*inLight);
270 const QVector3D lightDir = inLight->getDirection(lightGlobalTransform);
271 const QVector3D lightPivot = inLight->pivot;
273 const QVector3D forward = lightDir.normalized();
274 const QVector3D right = qFuzzyCompare(qAbs(forward.y()), 1.0f)
275 ? QVector3D::crossProduct(forward, QVector3D(1, 0, 0)).normalized()
276 : QVector3D::crossProduct(forward, QVector3D(0, 1, 0)).normalized();
277 const QVector3D up = QVector3D::crossProduct(right, forward).normalized();
279 QMatrix4x4 lightMatrix;
280 lightMatrix.setRow(0, QVector4D(right, 0.0f));
281 lightMatrix.setRow(1, QVector4D(up, 0.0f));
282 lightMatrix.setRow(2, QVector4D(forward, 0.0f));
283 lightMatrix.setRow(3, QVector4D(0.0f, 0.0f, 0.0f, 1.0f));
284 QMatrix4x4 lightMatrixInverted = lightMatrix.inverted();
286 const float farScale = (clipFar - clipNear) / (inCamera.clipPlanes.clipFar() - inCamera.clipPlanes.clipNear());
288 const QMatrix4x4 cameraGlobalTransform = data.getGlobalTransform(inCamera);
289 QMatrix4x4 viewProjection(Qt::Uninitialized);
290 inCamera.calculateViewProjectionMatrix(cameraGlobalTransform, viewProjection);
291 const QSSGBoxPoints frustum = computeFrustumBounds(viewProjection);
292 const QSSGBoxPoints frustumUntransformed = lockShadowmapTexels ? computeFrustumBounds(inCamera.projection) : QSSGBoxPoints();
296 const auto calcFrustumRadius = [&](
float t0,
float t1) ->
float {
297 const QSSGBoxPoints pts = sliceFrustum(frustumUntransformed, t0 * farScale, t1 * farScale);
299 QVector3D center = QVector3D(0.f, 0.f, 0.f);
300 for (QVector3D point : pts) {
303 center = center * 0.125f;
305 float radiusSquared = 0;
306 for (QVector3D point : pts) {
307 radiusSquared = qMax(radiusSquared, (point - center).lengthSquared());
310 return std::sqrt(radiusSquared);
313 const auto computeSplitRanges = [inLight](
const QVarLengthArray<
float, 3> &splits) -> QVarLengthArray<QPair<
float,
float>, 4> {
314 QVarLengthArray<QPair<
float,
float>, 4> ranges;
315 const float csmBlendRatio = inLight->m_csmBlendRatio;
317 for (qsizetype i = 0; i < splits.length(); i++) {
318 const float tI = qBound(qMin(t0 + 0.01f, 1.0f), splits[i], 1.0f);
319 ranges.emplace_back(t0, qMin(1.0f, tI + csmBlendRatio));
322 ranges.emplace_back(t0, 1.0f);
326 const auto computeFrustums = [&](
const QVarLengthArray<
float, 3> &splits) {
327 for (
const auto &range : computeSplitRanges(splits)) {
328 const float frustumRadius = lockShadowmapTexels ? calcFrustumRadius(range.first, range.second) : 0.0f;
329 auto camera = computeShadowCameraFromFrustum(lightMatrix,
337 range.first * farScale,
338 range.second * farScale,
345 drawSceneCascadeIntersection);
346 result.emplace_back(std::move(camera));
350 switch (inLight->m_csmNumSplits) {
356 computeFrustums({ inLight->m_csmSplit1 });
360 computeFrustums({ inLight->m_csmSplit1, inLight->m_csmSplit2 });
364 computeFrustums({ inLight->m_csmSplit1, inLight->m_csmSplit2, inLight->m_csmSplit3 });
406 QSSGRhiShaderPipeline *shaderPipeline,
407 QSSGRenderableImage *renderableImage,
408 QSSGRhiShaderResourceBindingList &bindings,
409 bool isCustomMaterialMeshSubset =
false)
411 static const auto imageAffectsAlpha = [](QSSGRenderableImage::Type mapType) {
412 return mapType == QSSGRenderableImage::Type::BaseColor ||
413 mapType == QSSGRenderableImage::Type::Diffuse ||
414 mapType == QSSGRenderableImage::Type::Translucency ||
415 mapType == QSSGRenderableImage::Type::Opacity;
418 while (renderableImage) {
419 const auto mapType = renderableImage->m_mapType;
420 if (imageAffectsAlpha(mapType)) {
421 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(mapType);
422 const int samplerHint =
int(mapType);
423 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
424 if (samplerBinding >= 0) {
425 QRhiTexture *texture = renderableImage->m_texture.m_texture;
426 if (samplerBinding >= 0 && texture) {
427 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
428 QRhiSampler *sampler = rhiCtx->sampler({ QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
429 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
430 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
431 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
432 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
433 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
435 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
439 renderableImage = renderableImage->m_nextImage;
442 if (isCustomMaterialMeshSubset) {
443 QVector<QShaderDescription::InOutVariable> samplerVars =
444 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
445 const auto combinedSamplers = shaderPipeline->vertexStage()->shader().description().combinedImageSamplers();
446 for (
const QShaderDescription::InOutVariable &var : combinedSamplers) {
447 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
448 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
449 if (it == samplerVars.cend())
450 samplerVars.append(var);
453 int maxSamplerBinding = -1;
454 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
455 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
464 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
466 if (maxSamplerBinding >= 0) {
468 int customTexCount = shaderPipeline->extraTextureCount();
469 for (
int i = 0; i < customTexCount; ++i) {
470 const QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
471 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
472 if (samplerBinding >= 0) {
473 samplerBindingsSpecified.setBit(samplerBinding);
474 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
475 bindings.addTexture(samplerBinding,
476 RENDERER_VISIBILITY_ALL,
484 QRhiSampler *dummySampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
485 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
486 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
487 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
488 QRhiTexture *dummyCubeTexture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
489 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
491 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars)) {
492 if (!samplerBindingsSpecified.testBit(var.binding)) {
493 QRhiTexture *t = var.type == QShaderDescription::SamplerCube ? dummyCubeTexture : dummyTexture;
494 bindings.addTexture(var.binding, RENDERER_VISIBILITY_ALL, t, dummySampler);
721 QSSGRhiGraphicsPipelineState *ps,
722 const QVector2D *depthAdjust,
723 const QSSGRenderableObjectList &sortedOpaqueObjects,
724 QSSGRenderCamera &inCamera,
726 QSSGRenderTextureCubeFace cubeFace,
727 quint32 cascadeIndex)
729 QSSGShaderFeatures featureSet;
731 featureSet.set(QSSGShaderFeatures::Feature::OrthoShadowPass,
true);
733 featureSet.set(QSSGShaderFeatures::Feature::PerspectiveShadowPass,
true);
739 featureSet.set(QSSGShaderFeatures::Feature::DisableMultiView,
true);
741 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
742 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
743 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
745 for (
const auto &handle : sortedOpaqueObjects) {
746 QSSGRenderableObject *theObject = handle.obj;
747 QSSG_ASSERT(theObject->renderableFlags.castsShadows(),
continue);
749 QSSGShaderFeatures objectFeatureSet = featureSet;
750 const bool isOpaqueDepthPrePass = theObject->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
751 if (isOpaqueDepthPrePass)
752 objectFeatureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
754 QSSGRhiDrawCallData *dcd =
nullptr;
755 QMatrix4x4 modelViewProjection;
756 QSSGSubsetRenderable &renderable(
static_cast<QSSGSubsetRenderable &>(*theObject));
757 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
758 const bool hasSkinning = defaultMaterialShaderKeyProperties.m_boneCount.getValue(renderable.shaderDescription) > 0;
759 modelViewProjection = hasSkinning ? pEntry->m_lightViewProjection[cascadeIndex]
760 : pEntry->m_lightViewProjection[cascadeIndex] * renderable.modelContext.globalTransform;
767 const quintptr entryIdx = cascadeIndex + cubeFaceIdx + (quintptr(renderable.subset.offset) << 3);
768 dcd = &rhiCtxD->drawCallData({ passKey, &renderable.modelContext.model,
nullptr, pEntry, entryIdx });
771 QSSGRhiShaderResourceBindingList bindings;
772 QSSGRhiShaderPipelinePtr shaderPipeline;
773 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*theObject));
774 if (theObject->type == QSSGSubsetRenderable::Type::DefaultMaterialMeshSubset) {
775 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
776 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
777 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(subsetRenderable.shaderDescription);
779 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, objectFeatureSet);
782 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
783 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
785 QSSGRenderCameraList cameras({ &inCamera });
786 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, cameras, depthAdjust, &modelViewProjection);
788 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &subsetRenderable.modelContext.model, subsetRenderable.subset.offset);
789 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
791 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &subsetRenderable.modelContext.model);
792 }
else if (theObject->type == QSSGSubsetRenderable::Type::CustomMaterialMeshSubset) {
793 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
794 ps->cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
796 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
797 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), objectFeatureSet);
800 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
801 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
803 QSSGRenderCameraList cameras({ &inCamera });
804 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, material, subsetRenderable,
805 cameras, depthAdjust, &modelViewProjection);
806 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
809 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
811 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
812 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
813 ia = subsetRenderable.subset.rhi.ia;
814 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
815 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
816 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
819 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
822 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
824 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
826 if (isOpaqueDepthPrePass) {
827 addOpaqueDepthPrePassBindings(rhiCtx,
828 shaderPipeline.get(),
829 subsetRenderable.firstImage,
831 (theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
838 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
839 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
840 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
841 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
842 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
843 if (screenTextureBinding >= 0) {
844 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
845 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
846 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
847 bindings.addTexture(screenTextureBinding,
848 QRhiShaderResourceBinding::FragmentStage,
849 dummyTexture, sampler);
851 if (screenTextureArrayBinding >= 0) {
852 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
853 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates, QSize(64, 64), Qt::black, inData.layer.viewCount);
854 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
855 bindings.addTexture(screenTextureArrayBinding,
856 QRhiShaderResourceBinding::FragmentStage,
857 dummyTexture, sampler);
862 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
863 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
865 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
866 QRhiSampler::Nearest,
868 QRhiSampler::ClampToEdge,
869 QRhiSampler::ClampToEdge,
872 bindings.addTexture(binding,
873 QRhiShaderResourceBinding::VertexStage,
880 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
881 if (targetsTexture) {
882 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
884 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
885 QRhiSampler::Nearest,
887 QRhiSampler::ClampToEdge,
888 QRhiSampler::ClampToEdge,
889 QRhiSampler::ClampToEdge
891 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
895 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
896 subsetRenderable.rhiRenderData.shadowPass.pipeline = rhiCtxD->pipeline(*ps, pEntry->m_rhiRenderPassDesc[cascadeIndex], srb);
897 subsetRenderable.rhiRenderData.shadowPass.srb[cubeFaceIdx] = srb;
932 QRhiRenderPassDescriptor *renderPassDescriptor,
933 QSSGRhiGraphicsPipelineState *ps,
934 QSSGShaderFeatures featureSet,
938 QSSGRenderCamera *alteredCamera,
939 QMatrix4x4 *alteredModelViewProjection,
940 QSSGRenderTextureCubeFace cubeFace,
944 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
946 switch (inObject.type) {
947 case QSSGRenderableObject::Type::DefaultMaterialMeshSubset:
949 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
951 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
952 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
954 if ((cubeFace != QSSGRenderTextureCubeFaceNone)) {
956 featureSet.disableTonemapping();
959 if (subsetRenderable.renderableFlags.rendersWithLightmap())
960 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
962 const auto &shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
963 if (shaderPipeline) {
971 QSSGRhiShaderResourceBindingList bindings;
972 const auto &modelNode = subsetRenderable.modelContext.model;
973 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(subsetRenderable.shaderDescription);
984 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
985 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone)
986 * (cubeFaceIdx + (quintptr(subsetRenderable.subset.offset) << 3));
988 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
989 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey, &modelNode, &subsetRenderable.material, entry,
992 shaderPipeline->ensureCombinedUniformBuffer(&dcd.ubuf);
993 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
995 Q_ASSERT(alteredModelViewProjection);
996 QSSGRenderCameraList cameras({ alteredCamera });
997 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, cameras,
nullptr, alteredModelViewProjection);
999 Q_ASSERT(!alteredModelViewProjection);
1000 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
1004 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &subsetRenderable.modelContext.model, subsetRenderable.subset.offset);
1005 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
1008 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &subsetRenderable.modelContext.model);
1011 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
1012 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
1014 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1015 QRhiSampler::Nearest,
1017 QRhiSampler::ClampToEdge,
1018 QRhiSampler::ClampToEdge,
1021 bindings.addTexture(binding,
1022 QRhiShaderResourceBinding::VertexStage,
1028 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
1029 if (targetsTexture) {
1030 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
1032 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1033 QRhiSampler::Nearest,
1035 QRhiSampler::ClampToEdge,
1036 QRhiSampler::ClampToEdge,
1037 QRhiSampler::ClampToEdge
1039 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
1043 ps->samples = samples;
1044 ps->viewCount = viewCount;
1046 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
1047 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
1048 if (!oit || (oit && inData.layer.oitMethod == QSSGRenderLayer::OITMethod::None))
1049 fillTargetBlend(&ps->targetBlend[0], material.blendMode);
1051 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
1053 ia = subsetRenderable.subset.rhi.ia;
1054 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
1055 QVector3D cameraDirection = cameraDatas[0].direction;
1056 QVector3D cameraPosition = cameraDatas[0].position;
1057 if (alteredCamera) {
1058 const QMatrix4x4 camGlobalTranform = inData.getGlobalTransform(*alteredCamera);
1059 cameraDirection = QSSGRenderNode::getScalingCorrectDirection(camGlobalTranform);
1060 cameraPosition = QSSGRenderNode::getGlobalPos(camGlobalTranform);
1062 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDirection, cameraPosition);
1063 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
1065 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline->ub0Size());
1067 if (shaderPipeline->isLightingEnabled()) {
1068 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd.ubuf,
1069 shaderPipeline->ub0LightDataOffset(),
1070 sizeof(QSSGShaderLightsUniformData));
1071 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd.ubuf,
1072 shaderPipeline->ub0DirectionalLightDataOffset(),
1073 sizeof(QSSGShaderDirectionalLightsUniformData));
1078 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
1079 while (renderableImage) {
1080 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
1081 const int samplerHint =
int(renderableImage->m_mapType);
1082 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
1083 if (samplerBinding >= 0) {
1084 QRhiTexture *texture = renderableImage->m_texture.m_texture;
1085 if (samplerBinding >= 0 && texture) {
1086 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
1087 QSSGRhiSamplerDescription samplerDesc = {
1088 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
1089 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
1090 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
1091 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
1092 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
1093 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
1095 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
1096 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
1097 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
1100 renderableImage = renderableImage->m_nextImage;
1103 if (shaderPipeline->isLightingEnabled()) {
1105 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
1106 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
1109 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1110 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
1111 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1114 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1115 QRhiSampler::Linear,
1117 QRhiSampler::ClampToEdge,
1118 QRhiSampler::ClampToEdge,
1119 QRhiSampler::Repeat });
1121 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1125 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
1126 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
1127 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
1129 QRhiTexture *texture = shadowMapBlueNoise;
1130 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1131 QRhiSampler::Linear,
1133 QRhiSampler::Repeat,
1134 QRhiSampler::Repeat,
1135 QRhiSampler::Repeat });
1136 Q_ASSERT(texture && sampler);
1137 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1140 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1141 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
1142 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1143 QRhiSampler::Linear,
1145 QRhiSampler::Repeat,
1146 QRhiSampler::Repeat,
1147 QRhiSampler::Repeat });
1148 Q_ASSERT(texture && sampler);
1149 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1150 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1157 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
1158 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
1159 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
1160 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
1161 ? QRhiSampler::Linear
1162 : QRhiSampler::None;
1163 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1164 QRhiSampler::Linear,
1166 QRhiSampler::ClampToEdge,
1167 QRhiSampler::ClampToEdge,
1168 QRhiSampler::Repeat });
1169 if (reflectionSampler >= 0 && reflectionTexture)
1170 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
1173 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
1175 auto texture = shaderPipeline->lightProbeTexture();
1177 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1178 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
1179 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1183 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
1184 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1185 QRhiSampler::Linear,
1186 QRhiSampler::Linear,
1187 QSSGRhiHelpers::toRhi(tiling.first),
1188 QSSGRhiHelpers::toRhi(tiling.second),
1189 QRhiSampler::Repeat });
1190 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1194 if (shaderPipeline->screenTexture()) {
1195 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
1196 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
1197 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
1198 QRhiTexture *screenTexture = shaderPipeline->screenTexture();
1200 if (screenMapPass) {
1201 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1203 const QRhiTexture::Flags flags = screenTexture->flags();
1205 screenTexture = rhiCtx->dummyTexture(flags, resourceUpdates);
1206 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1213 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
1214 ? QRhiSampler::Linear : QRhiSampler::None;
1215 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
1216 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
1217 if (screenTextureBinding >= 0) {
1218 bindings.addTexture(screenTextureBinding,
1219 QRhiShaderResourceBinding::FragmentStage,
1220 screenTexture, sampler);
1222 if (screenTextureArrayBinding >= 0) {
1223 bindings.addTexture(screenTextureArrayBinding,
1224 QRhiShaderResourceBinding::FragmentStage,
1225 screenTexture, sampler);
1230 if (shaderPipeline->lightmapTexture()) {
1231 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
1233 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1234 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
1235 bindings.addTexture(binding,
1236 QRhiShaderResourceBinding::FragmentStage,
1237 shaderPipeline->lightmapTexture(), sampler);
1243 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1246 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1248 if (oit && inData.layer.oitMethod == QSSGRenderLayer::OITMethod::LinkedList)
1258 QRhiShaderResourceBindings *&srb = dcd.srb;
1259 bool srbChanged =
false;
1260 if (!srb || bindings != dcd.bindings) {
1261 srb = rhiCtxD->srb(bindings);
1262 rhiCtxD->releaseCachedSrb(dcd.bindings);
1263 dcd.bindings = bindings;
1267 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1268 subsetRenderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
1270 subsetRenderable.rhiRenderData.mainPass.srb = srb;
1272 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
1275 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
1276 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
1279 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1280 subsetRenderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
1282 subsetRenderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
1284 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1285 subsetRenderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1286 renderPassDescriptor,
1288 dcd.pipeline = subsetRenderable.rhiRenderData.reflectionPass.pipeline;
1290 subsetRenderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1291 renderPassDescriptor,
1293 dcd.pipeline = subsetRenderable.rhiRenderData.mainPass.pipeline;
1295 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
1296 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;
1302 case QSSGRenderableObject::Type::CustomMaterialMeshSubset:
1304 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
1305 const QSSGRenderCustomMaterial &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
1306 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
1308 featureSet.set(QSSGShaderFeatures::Feature::LightProbe, inData.layer.lightProbe || material.m_iblProbe);
1310 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
1311 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
1313 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1315 featureSet.disableTonemapping();
1318 if (subsetRenderable.renderableFlags.rendersWithLightmap())
1319 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
1321 customMaterialSystem.rhiPrepareRenderable(ps, passKey, subsetRenderable, featureSet,
1322 material, inData, renderPassDescriptor, samples, viewCount, screenMapPass,
1323 alteredCamera, cubeFace, alteredModelViewProjection, entry, oit);
1326 case QSSGRenderableObject::Type::Particles:
1329 const auto &shaderPipeline = shadersForParticleMaterial(ps, particleRenderable, featureSet);
1330 if (shaderPipeline) {
1331 QSSGParticleRenderer::rhiPrepareRenderable(*shaderPipeline, passKey, rhiCtx, ps, particleRenderable, inData, renderPassDescriptor, samples, viewCount,
1332 alteredCamera, cubeFace, entry, oit);
1378 const QSSGRhiGraphicsPipelineState &state,
1380 bool *needsSetViewport,
1381 QSSGRenderTextureCubeFace cubeFace,
1382 qsizetype userPassIndex)
1384 switch (object.type) {
1385 case QSSGRenderableObject::Type::DefaultMaterialMeshSubset:
1387 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(object));
1389 QSSG_ASSERT(QSSGUserRenderPassManager::maxUserPassSlots() == std::size(subsetRenderable.rhiRenderData.userPassData),
return);
1391 QRhiGraphicsPipeline *ps = (userPassIndex >= 0 && size_t(userPassIndex) < QSSGUserRenderPassManager::maxUserPassSlots())
1392 ? subsetRenderable.rhiRenderData.userPassData[userPassIndex].pipeline : subsetRenderable.rhiRenderData.mainPass.pipeline;
1393 QRhiShaderResourceBindings *srb = (userPassIndex >= 0 && size_t(userPassIndex) < QSSGUserRenderPassManager::maxUserPassSlots())
1394 ? subsetRenderable.rhiRenderData.userPassData[userPassIndex].srb : subsetRenderable.rhiRenderData.mainPass.srb;
1396 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1397 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
1398 ps = subsetRenderable.rhiRenderData.reflectionPass.pipeline;
1399 srb = subsetRenderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx];
1405 QRhiBuffer *vertexBuffer = subsetRenderable.subset.rhi.vertexBuffer->buffer();
1406 QRhiBuffer *indexBuffer = subsetRenderable.subset.rhi.indexBuffer ? subsetRenderable.subset.rhi.indexBuffer->buffer() :
nullptr;
1408 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1410 cb->setGraphicsPipeline(ps);
1411 cb->setShaderResources(srb);
1413 if (*needsSetViewport) {
1414 cb->setViewport(state.viewport);
1415 if (state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor))
1416 cb->setScissor(state.scissor);
1417 *needsSetViewport =
false;
1420 QRhiCommandBuffer::VertexInput vertexBuffers[2];
1421 int vertexBufferCount = 1;
1422 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
1423 quint32 instances = 1;
1424 if ( subsetRenderable.modelContext.model.instancing()) {
1425 instances = subsetRenderable.modelContext.model.instanceCount();
1432 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(subsetRenderable.instanceBuffer, 0);
1433 vertexBufferCount = 2;
1435 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
1436 if (state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef))
1437 cb->setStencilRef(state.stencilRef);
1439 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, subsetRenderable.subset.rhi.indexBuffer->indexFormat());
1440 cb->drawIndexed(subsetRenderable.subset.lodCount(subsetRenderable.subsetLevelOfDetail), instances, subsetRenderable.subset.lodOffset(subsetRenderable.subsetLevelOfDetail));
1441 QSSGRHICTX_STAT(rhiCtx, drawIndexed(subsetRenderable.subset.lodCount(subsetRenderable.subsetLevelOfDetail), instances));
1443 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
1444 cb->draw(subsetRenderable.subset.count, instances, subsetRenderable.subset.offset);
1445 QSSGRHICTX_STAT(rhiCtx, draw(subsetRenderable.subset.count, instances));
1447 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (subsetRenderable.subset.count | quint64(instances) << 32),
1448 QVector<
int>({subsetRenderable.modelContext.model.profilingId,
1449 subsetRenderable.material.profilingId}));
1452 case QSSGRenderableObject::Type::CustomMaterialMeshSubset:
1454 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(object));
1455 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
1456 customMaterialSystem.rhiRenderRenderable(rhiCtx, subsetRenderable, needsSetViewport, cubeFace, state, userPassIndex);
1459 case QSSGRenderableObject::Type::Particles:
1462 QSSGParticleRenderer::rhiRenderRenderable(rhiCtx, renderable, needsSetViewport, cubeFace, state);
1487 QSSGPassKey passKey,
1488 QSSGRhiGraphicsPipelineState &ps,
1489 QSSGRenderShadowMap &shadowMapManager,
1490 const QSSGRenderCamera &camera,
1491 QSSGRenderCamera *debugCamera,
1493 const QSSGRenderableObjectList &sortedOpaqueObjects,
1495 const QSSGBounds3 &castingObjectsBox,
1496 const QSSGBounds3 &receivingObjectsBox)
1499 QSSGDebugDrawSystem *debugDrawSystem = renderer.contextInterface()->debugDrawSystem().get();
1500 const bool drawDirectionalLightShadowBoxes = layerData.layer.drawDirectionalLightShadowBoxes;
1501 const bool drawPointLightShadowBoxes = layerData.layer.drawPointLightShadowBoxes;
1502 const bool drawShadowCastingBounds = layerData.layer.drawShadowCastingBounds;
1503 const bool drawShadowReceivingBounds = layerData.layer.drawShadowReceivingBounds;
1504 const bool drawCascades = layerData.layer.drawCascades;
1505 const bool drawSceneCascadeIntersection = layerData.layer.drawSceneCascadeIntersection;
1506 const bool disableShadowCameraUpdate = layerData.layer.disableShadowCameraUpdate;
1507 const bool drawCulledObjects = layerData.layer.drawCulledObjects;
1508 QVector<
bool> debugIsObjectCulled = drawCulledObjects ? QVector<
bool>(sortedOpaqueObjects.size(),
true) : QVector<
bool>();
1510 static const auto rhiRenderOneShadowMap = [](QSSGRhiContext *rhiCtx,
1511 QSSGRhiGraphicsPipelineState *ps,
1512 const QSSGRenderableObjectList &sortedOpaqueObjects,
1514 const QSSGBounds3 cameraBounds,
1515 QVector<
bool> &debugIsObjectCulled,
1516 bool drawCulledObjects) {
1517 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1518 bool needsSetViewport =
true;
1520 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1525 if (theObject->globalBoundsInstancing.isFinite() && theObject->globalBounds.isFinite()) {
1526 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1527 : theObject->globalBounds;
1528 if (!globalBounds.isEmpty() && !cameraBounds.intersects(globalBounds)) {
1533 if (Q_UNLIKELY(drawCulledObjects))
1534 debugIsObjectCulled[i] =
false;
1537 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
1538 QSSGSubsetRenderable *renderable(
static_cast<QSSGSubsetRenderable *>(theObject));
1540 QRhiBuffer *vertexBuffer = renderable->subset.rhi.vertexBuffer->buffer();
1541 QRhiBuffer *indexBuffer = renderable->subset.rhi.indexBuffer
1542 ? renderable->subset.rhi.indexBuffer->buffer()
1546 if (!renderable->rhiRenderData.shadowPass.pipeline)
1549 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
1551 cb->setGraphicsPipeline(renderable->rhiRenderData.shadowPass.pipeline);
1553 QRhiShaderResourceBindings *srb = renderable->rhiRenderData.shadowPass.srb[cubeFace];
1554 cb->setShaderResources(srb);
1556 if (needsSetViewport) {
1557 cb->setViewport(ps->viewport);
1558 needsSetViewport =
false;
1561 QRhiCommandBuffer::VertexInput vertexBuffers[2];
1562 int vertexBufferCount = 1;
1563 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
1564 quint32 instances = 1;
1565 if (renderable->modelContext.model.instancing()) {
1566 instances = renderable->modelContext.model.instanceCount();
1567 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(renderable->instanceBuffer, 0);
1568 vertexBufferCount = 2;
1571 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, renderable->subset.rhi.indexBuffer->indexFormat());
1572 cb->drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances, renderable->subset.lodOffset(renderable->subsetLevelOfDetail));
1573 QSSGRHICTX_STAT(rhiCtx, drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances));
1575 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
1576 cb->draw(renderable->subset.count, instances, renderable->subset.offset);
1577 QSSGRHICTX_STAT(rhiCtx, draw(renderable->subset.count, instances));
1579 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (renderable->subset.count | quint64(instances) << 32),
1580 QVector<
int>({renderable->modelContext.model.profilingId,
1581 renderable->material.profilingId}));
1586 static const auto rhiClearShadowMap = [](
QSSGRenderer &renderer, QSSGRenderShadowMap &shadowMapManager, QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QRhiRenderPassDescriptor *renderPassDesc) {
1587 auto clearShadowMapShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiClearShadowMapShader();
1588 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, clearShadowMapShaderPipeline.get());
1591 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
false);
1592 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1593 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, shadowMapManager.shadowClearSrb(), renderPassDesc, {});
1595 ps->flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1598 QRhi *rhi = rhiCtx->rhi();
1599 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1603 QVector2D depthAdjust;
1604 if (rhi->isClipDepthZeroToOne()) {
1606 depthAdjust[0] = 0.0f;
1607 depthAdjust[1] = 1.0f;
1610 depthAdjust[0] = 1.0f;
1611 depthAdjust[1] = 0.5f;
1614 if (drawShadowCastingBounds)
1616 if (drawShadowReceivingBounds)
1620 const QSize atlasTextureSize = shadowMapManager.shadowMapAtlasTexture()->pixelSize();
1622 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
1623 for (
int i = 0, ie = globalLights.size(); i != ie; ++i) {
1624 if (!globalLights[i].shadows || globalLights[i].light->m_fullyBaked)
1631 const auto &light = globalLights[i].light;
1633 if (!shadowMapManager.shadowMapAtlasTexture())
1636 if (light->type == QSSGRenderLight::Type::DirectionalLight || light->type == QSSGRenderLight::Type::SpotLight) {
1637 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1641 if (!disableShadowCameraUpdate && debugCamera) {
1642 debugCamera->clipPlanes = camera.clipPlanes;
1643 debugCamera->projection = camera.projection;
1647 debugCamera->localTransform = layerData.getGlobalTransform(camera);
1650 QVarLengthArray<std::unique_ptr<QSSGRenderCamera>, 4> cascades;
1651 if (light->type == QSSGRenderLight::Type::DirectionalLight) {
1652 const float pcfRadius = light->m_softShadowQuality == QSSGRenderLight::SoftShadowQuality::Hard ? 0.f : light->m_pcfFactor;
1653 const float clipNear = camera.clipPlanes.clipNear();
1654 const float clipFar = qMin(light->m_shadowMapFar, camera.clipPlanes.clipFar());
1655 const float clipRange = clipFar - clipNear;
1656 cascades = setupCascadingCamerasForShadowMap(layerData,
1657 disableShadowCameraUpdate ? *debugCamera : camera,
1664 receivingObjectsBox,
1665 light->m_lockShadowmapTexels,
1668 drawSceneCascadeIntersection);
1671 pEntry->m_csmSplits[0] = clipNear + clipRange * (light->m_csmNumSplits > 0 ? light->m_csmSplit1 : 1.0f);
1672 pEntry->m_csmSplits[1] = clipNear + clipRange * (light->m_csmNumSplits > 1 ? light->m_csmSplit2 : 1.0f);
1673 pEntry->m_csmSplits[2] = clipNear + clipRange * (light->m_csmNumSplits > 2 ? light->m_csmSplit3 : 1.0f);
1674 pEntry->m_csmSplits[3] = clipNear + clipRange * 1.0f;
1675 pEntry->m_shadowMapFar = clipFar;
1676 }
else if (light->type == QSSGRenderLight::Type::SpotLight) {
1677 auto spotlightCamera =
std::make_unique<QSSGRenderCamera>(QSSGRenderCamera::Type::PerspectiveCamera);
1678 spotlightCamera->fov = QSSGRenderCamera::FieldOfView::fromDegrees(light->m_coneAngle * 2.0f);
1679 spotlightCamera->clipPlanes = { 1.0f, light->m_shadowMapFar };
1680 const QMatrix4x4 lightGlobalTransform = layerData.getGlobalTransform(*light);
1681 const QVector3D lightDir = QSSGRenderNode::getDirection(lightGlobalTransform);
1682 const QVector3D lightPos = QSSGRenderNode::getGlobalPos(lightGlobalTransform) - lightDir * spotlightCamera->clipPlanes.clipNear();
1683 const QVector3D lightPivot = light->pivot;
1684 const QVector3D forward = lightDir.normalized();
1685 const QVector3D right = qFuzzyCompare(qAbs(forward.y()), 1.0f)
1686 ? QVector3D::crossProduct(forward, QVector3D(1, 0, 0)).normalized()
1687 : QVector3D::crossProduct(forward, QVector3D(0, 1, 0)).normalized();
1688 const QVector3D up = QVector3D::crossProduct(right, forward).normalized();
1689 spotlightCamera->localTransform = QSSGRenderNode::calculateTransformMatrix(lightPos,
1690 QSSGRenderNode::initScale,
1692 QQuaternion::fromDirection(forward, up));
1693 QRectF theViewport(0.0f, 0.0f, (
float)light->m_shadowMapRes, (
float)light->m_shadowMapRes);
1694 QSSGRenderCamera::calculateProjectionInternal(*spotlightCamera, theViewport);
1695 cascades.push_back(
std::move(spotlightCamera));
1696 pEntry->m_shadowMapFar = light->m_shadowMapFar;
1701 memset(pEntry->m_csmActive, 0,
sizeof(pEntry->m_csmActive));
1703 QMatrix4x4 cascadeCameraGlobalTransforms(Qt::Uninitialized);
1704 const QMatrix4x4 bias = { 0.5, 0.0, 0.0, 0.5,
1707 0.0, 0.0, 0.0, 1.0 };
1709 for (
int cascadeIndex = 0; cascadeIndex < cascades.length(); cascadeIndex++) {
1710 const auto &cascadeCamera = cascades[cascadeIndex];
1714 cascadeCameraGlobalTransforms = layerData.getGlobalTransform(*cascadeCamera);
1715 pEntry->m_csmActive[cascadeIndex] = 1.f;
1716 QMatrix4x4 &viewProjection = pEntry->m_lightViewProjection[cascadeIndex];
1717 cascadeCamera->calculateViewProjectionMatrix(cascadeCameraGlobalTransforms, viewProjection);
1718 pEntry->m_lightViewProjection[cascadeIndex] = viewProjection;
1719 pEntry->m_fixedScaleBiasMatrix[cascadeIndex] = bias * viewProjection;
1720 const QMatrix4x4 inverted = viewProjection.inverted();
1721 const float x = 0.5f / (inverted * QVector4D(1, 0, 0, 0)).length();
1722 const float y = 0.5f / (inverted * QVector4D(0, 1, 0, 0)).length();
1723 const float z = 0.5f / (inverted * QVector4D(0, 0, 1, 0)).length();
1724 const QSSGBoxPoints frustumPoints = computeFrustumBounds(viewProjection);
1725 const QSSGBounds3 bounds = QSSGBounds3(frustumPoints);
1726 pEntry->m_dimensionsInverted[cascadeIndex] = QVector4D(x, y, z, 0.0f);
1727 pEntry->m_lightView = cascadeCameraGlobalTransforms.inverted();
1728 const bool isOrtho = cascadeCamera->type == QSSGRenderGraphObject::Type::OrthographicCamera;
1729 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[cascadeIndex], rhi->isYUpInFramebuffer());
1730 rhiPrepareResourcesForShadowMap(rhiCtx, layerData, passKey, pEntry, &ps, &depthAdjust, sortedOpaqueObjects, *cascadeCamera, isOrtho, QSSGRenderTextureCubeFaceNone, cascadeIndex);
1733 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[cascadeIndex];
1734 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1735 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1736 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1737 rhiClearShadowMap(renderer, shadowMapManager, rhiCtx, &ps, rt->renderPassDescriptor());
1738 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, 0, bounds, debugIsObjectCulled, drawCulledObjects);
1740 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1742 if (drawDirectionalLightShadowBoxes) {
1746 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"shadow_map"));
1748 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1749 ps.viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1751 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1752 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1753 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1754 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1755 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1756 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1757 const float shadowMapFar = qMax<
float>(2.0f, light->m_shadowMapFar);
1758 setupCubeShadowCameras(layerData, light, shadowMapFar, theCameras);
1759 pEntry->m_lightView = QMatrix4x4();
1760 pEntry->m_shadowMapFar = shadowMapFar;
1762 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1763 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1764 for (
const auto face : QSSGRenderTextureCubeFaces) {
1765 cameraGlobalTransform = layerData.getGlobalTransform(theCameras[quint8(face)]);
1766 theCameras[quint8(face)].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_lightViewProjection[0]);
1767 pEntry->m_lightCubeView[quint8(face)] = cameraGlobalTransform.inverted();
1769 rhiPrepareResourcesForShadowMap(rhiCtx,
1775 sortedOpaqueObjects,
1776 theCameras[quint8(face)],
1783 const QVector3D center = QSSGRenderNode::getGlobalPos(layerData.getGlobalTransform(*light));
1784 const QSSGBounds3 bounds = QSSGBounds3(center - QVector3D(shadowMapFar, shadowMapFar, shadowMapFar),
1785 center + QVector3D(shadowMapFar, shadowMapFar, shadowMapFar));
1787 for (
const auto face : QSSGRenderTextureCubeFaces) {
1791 QSSGRenderTextureCubeFace outFace = face;
1809 if (outFace == QSSGRenderTextureCubeFace::PosY)
1810 outFace = QSSGRenderTextureCubeFace::NegY;
1811 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1812 outFace = QSSGRenderTextureCubeFace::PosY;
1814 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargetCube[quint8(outFace)];
1815 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1816 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1817 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1818 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, quint8(face), bounds, debugIsObjectCulled, drawCulledObjects);
1820 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1821 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_cube", 0, outFace));
1828 QRhiTextureRenderTarget *rtFront = pEntry->m_rhiRenderTargets[0];
1829 QRhiRenderPassDescriptor *frontDesc = pEntry->m_rhiRenderPassDesc[0];
1830 auto atlasShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiCubeMapToAtlasShader();
1831 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[0], rhi->isYUpInFramebuffer());
1832 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, atlasShaderPipeline.get());
1833 QRhiShaderResourceBindings *srb = pEntry->m_cubeToAtlasFrontSrb;
1834 cb->beginPass(rtFront, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1835 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtFront));
1836 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1838 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, frontDesc, QSSGRhiQuadRenderer::UvCoords);
1841 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1842 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 6, 0));
1845 QRhiTextureRenderTarget *rtBack = pEntry->m_rhiRenderTargets[1];
1846 QRhiRenderPassDescriptor *backDesc = pEntry->m_rhiRenderPassDesc[1];
1847 srb = pEntry->m_cubeToAtlasBackSrb;
1848 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[1], rhi->isYUpInFramebuffer());
1849 cb->beginPass(rtBack, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1850 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtBack));
1851 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1853 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, backDesc, QSSGRhiQuadRenderer::UvCoords);
1856 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1857 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 7, 0));
1861 ps = layerData.getPipelineState();
1862 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1864 ps.slopeScaledDepthBias = 1.5f;
1866 if (drawPointLightShadowBoxes) {
1872 if (Q_UNLIKELY(drawCulledObjects)) {
1873 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1875 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1876 : theObject->globalBounds;
1877 const QColor color = debugIsObjectCulled[i] ? QColorConstants::Red : QColorConstants::Green;
1884 QSSGPassKey passKey,
1886 QSSGRhiGraphicsPipelineState *ps,
1887 QSSGRenderReflectionMap &reflectionMapManager,
1888 const std::vector<QSSGRenderReflectionProbe *> &reflectionProbes,
1889 const QSSGRenderableObjectList &reflectionPassObjects,
1892 QSSGRhiContext *rhiCtx = context.rhiContext().get();
1893 QRhi *rhi = rhiCtx->rhi();
1894 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1896 const bool renderSkybox = (inData.layer.background == QSSGRenderLayer::Background::SkyBox
1897 || inData.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap
1898 || inData.layer.background == QSSGRenderLayer::Background::SkyMaterial)
1899 && rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch);
1901 for (size_t i = 0, ie = reflectionProbes.size(); i != ie; ++i) {
1902 QSSGReflectionMapEntry *pEntry = reflectionMapManager.reflectionMapEntry(
int(i));
1906 if (!pEntry->m_needsRender)
1909 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame && pEntry->m_rendered)
1912 if (reflectionProbes[i]->texture)
1915 Q_ASSERT(pEntry->m_rhiDepthStencil);
1916 Q_ASSERT(pEntry->m_rhiCube);
1918 const QSize size = pEntry->m_rhiCube->pixelSize();
1919 ps->viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1921 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1922 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1923 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1924 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1925 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1926 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1927 setupCubeReflectionCameras(inData, reflectionProbes[i], theCameras);
1928 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1929 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1930 for (
const auto face : QSSGRenderTextureCubeFaces) {
1931 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(face);
1932 cameraGlobalTransform = inData.getGlobalTransform(theCameras[cubeFaceIdx]);
1933 theCameras[cubeFaceIdx].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_viewProjection);
1935 rhiPrepareResourcesForReflectionMap(context, passKey, inData, pEntry, ps, reflectionPassObjects, theCameras[cubeFaceIdx], renderer, face);
1937 QRhiRenderPassDescriptor *renderPassDesc =
nullptr;
1938 for (
auto face : QSSGRenderTextureCubeFaces) {
1939 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1940 face = pEntry->m_timeSliceFace;
1942 QSSGRenderTextureCubeFace outFace = face;
1946 if (outFace == QSSGRenderTextureCubeFace::PosY)
1947 outFace = QSSGRenderTextureCubeFace::NegY;
1948 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1949 outFace = QSSGRenderTextureCubeFace::PosY;
1951 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[quint8(outFace)];
1952 cb->beginPass(rt, reflectionProbes[i]->clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1953 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1954 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1956 if (renderSkybox && pEntry->m_skyBoxSrbs[quint8(face)]) {
1957 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1958 const bool useSkyBoxQuad = inData.layer.background == QSSGRenderLayer::Background::SkyBox
1959 || inData.layer.background == QSSGRenderLayer::Background::SkyMaterial;
1960 const auto &shaderPipeline = useSkyBoxQuad
1961 ? shaderCache->getBuiltInRhiShaders().getRhiSkyBoxShader(QSSGRenderLayer::TonemapMode::None,
1962 inData.layer.skyBoxIsRgbe8,
1964 : shaderCache->getBuiltInRhiShaders().getRhiSkyBoxCubeShader(QSSGRenderLayer::TonemapMode::None,
1965 !inData.layer.skyBoxIsSrgb,
1967 Q_ASSERT(shaderPipeline);
1968 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
1969 QRhiShaderResourceBindings *srb = pEntry->m_skyBoxSrbs[quint8(face)];
1970 if (!renderPassDesc)
1971 renderPassDesc = rt->newCompatibleRenderPassDescriptor();
1972 rt->setRenderPassDescriptor(renderPassDesc);
1973 useSkyBoxQuad ? renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, srb, renderPassDesc, {})
1974 : renderer.rhiCubeRenderer()->recordRenderCube(rhiCtx, ps, srb, renderPassDesc, {});
1977 bool needsSetViewport =
true;
1978 for (
const auto &handle : reflectionPassObjects)
1979 rhiRenderRenderable(rhiCtx, *ps, *handle.obj, &needsSetViewport, face);
1982 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1983 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"reflection_cube", 0, outFace));
1985 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1989 renderPassDesc->deleteLater();
1991 pEntry->renderMips(rhiCtx);
1993 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1994 pEntry->m_timeSliceFace = QSSGBaseTypeHelpers::next(pEntry->m_timeSliceFace);
1996 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame)
1997 pEntry->m_rendered =
true;
1999 reflectionProbes[i]->hasScheduledUpdate =
false;
2000 pEntry->m_needsRender =
false;
2051 QSSGPassKey passKey,
2053 QSSGRhiShaderPipeline &shaderPipeline,
2054 QSSGRhiGraphicsPipelineState &ps,
2055 const QSSGAmbientOcclusionSettings &ao,
2056 const QSSGRhiRenderableTexture &rhiAoTexture,
2057 const QSSGRhiRenderableTexture &rhiDepthTexture,
2058 const QSSGRenderCamera &camera)
2060 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2063 if (!rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2064 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
2066 cb->beginPass(rhiAoTexture.rt, Qt::white, { 1.0f, 0 });
2067 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rhiAoTexture.rt));
2069 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
2073 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, &shaderPipeline);
2075 const float R2 = ao.aoDistance * ao.aoDistance * 0.16f;
2076 const QSize textureSize = rhiAoTexture.texture->pixelSize();
2077 const float rw =
float(textureSize.width());
2078 const float rh =
float(textureSize.height());
2079 const float fov = camera.fov.asVerticalFov(rw / rh).radians();
2080 const float tanHalfFovY = tanf(0.5f * fov * (rh / rw));
2081 const float invFocalLenX = tanHalfFovY * (rw / rh);
2083 const QVector4D aoProps(ao.aoStrength * 0.01f, ao.aoDistance * 0.4f, ao.aoSoftness * 0.02f, ao.aoBias);
2084 const QVector4D aoProps2(
float(ao.aoSamplerate), (ao.aoDither) ? 1.0f : 0.0f, 0.0f, 0.0f);
2085 const QVector4D aoScreenConst(1.0f / R2, rh / (2.0f * tanHalfFovY), 1.0f / rw, 1.0f / rh);
2086 const QVector4D uvToEyeConst(2.0f * invFocalLenX, -2.0f * tanHalfFovY, -invFocalLenX, tanHalfFovY);
2087 const QVector2D cameraProps = camera.clipPlanes;
2096 const int UBUF_SIZE = 72;
2097 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ passKey,
nullptr,
nullptr,
nullptr, 0 }));
2099 dcd.ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE);
2103 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2104 memcpy(ubufData, &aoProps, 16);
2105 memcpy(ubufData + 16, &aoProps2, 16);
2106 memcpy(ubufData + 32, &aoScreenConst, 16);
2107 memcpy(ubufData + 48, &uvToEyeConst, 16);
2108 memcpy(ubufData + 64, &cameraProps, 8);
2109 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2111 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2112 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
2113 QSSGRhiShaderResourceBindingList bindings;
2114 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
2117 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiDepthTexture.texture, sampler);
2118 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2120 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
2121 renderer.rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, rhiAoTexture.rt, {});
2269 QSSGPassKey passKey,
2270 QSSGRenderLayer &layer,
2271 QSSGRenderCameraList &cameras,
2275 uint tonemapMode = 0)
2277 QSSG_ASSERT(layer.renderData,
return);
2279 const auto *renderData = layer.renderData;
2281 auto rhiCtx = context.rhiContext().get();
2283 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2285 QSSGRenderImageTexture lightProbeTexture;
2286 switch (layer.background) {
2287 case QSSGRenderLayer::Background::SkyBox:
2288 lightProbeTexture = renderer.contextInterface()->bufferManager()->loadRenderImage(layer.lightProbe,
2289 QSSGBufferManager::MipModeBsdf);
2291 case QSSGRenderLayer::Background::SkyBoxCubeMap:
2292 lightProbeTexture = renderer.contextInterface()->bufferManager()->loadRenderImage(layer.skyBoxCubeMap,
2293 QSSGBufferManager::MipModeDisable);
2295 case QSSGRenderLayer::Background::SkyMaterial:
2296 lightProbeTexture = renderData->skyMaterialTexture;
2299 Q_UNREACHABLE_RETURN();
2302 if (lightProbeTexture.m_texture ==
nullptr) {
2305 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
2308 for (QRhiShaderResourceBindings *&srb : entry->m_skyBoxSrbs)
2311 layer.skyBoxSrb =
nullptr;
2316 const bool cubeMapMode = layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap;
2318 if (cubeFace == QSSGRenderTextureCubeFaceNone)
2319 layer.skyBoxIsRgbe8 = lightProbeTexture.m_flags.isRgbe8();
2321 layer.skyBoxIsSrgb = !lightProbeTexture.m_flags.isLinear();
2323 QSSGRhiShaderResourceBindingList bindings;
2325 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
2326 QRhiSampler::Linear,
2327 cubeMapMode ? QRhiSampler::None : QRhiSampler::Linear,
2328 QRhiSampler::Repeat,
2329 QRhiSampler::ClampToEdge,
2330 QRhiSampler::Repeat });
2331 int samplerBinding = 1;
2332 bindings.addTexture(samplerBinding, QRhiShaderResourceBinding::FragmentStage, lightProbeTexture.m_texture, sampler);
2334 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2335 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * cubeFaceIdx;
2336 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey,
nullptr,
nullptr, entry, entryIdx });
2338 QRhi *rhi = rhiCtx->rhi();
2339 const quint32 ubufSize = cameras.count() >= 2 ? 416 : 240;
2340 if (!dcd.ubuf || dcd.ubuf->size() != ubufSize) {
2342 dcd.ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer,
int(ubufSize));
2346 float adjustY = rhi->isYUpInNDC() ? 1.0f : -1.0f;
2347 const float exposure = layer.lightProbeSettings.probeExposure;
2349 const QMatrix3x3 &rotationMatrix(layer.lightProbeSettings.probeOrientation);
2352 const float blurAmountOrSrgb = cubeMapMode ? layer.skyBoxIsSrgb : layer.skyboxBlurAmount;
2353 const float maxMipLevelOrTonemapMode = cubeMapMode ?
float(tonemapMode) :
float(lightProbeTexture.m_mipmapCount - 2);
2355 const QVector4D skyboxProperties = {
2359 maxMipLevelOrTonemapMode
2362 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2363 quint32 ubufOffset = 0;
2365 memcpy(ubufData + ubufOffset, &skyboxProperties, 16);
2368 memcpy(ubufData + ubufOffset, rotationMatrix.constData(), 12);
2370 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 12, 12);
2372 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 24, 12);
2375 for (qsizetype viewIdx = 0; viewIdx < cameras.count(); ++viewIdx) {
2376 const QMatrix4x4 &inverseProjection = cameras[viewIdx]->projection.inverted();
2377 const QMatrix4x4 &viewMatrix = renderData->getGlobalTransform(*cameras[viewIdx]);
2378 QMatrix4x4 viewProjection(Qt::Uninitialized);
2379 cameras[viewIdx]->calculateViewProjectionWithoutTranslation(viewMatrix, 0.1f, 5.0f, viewProjection);
2381 quint32 viewDataOffset = ubufOffset;
2382 memcpy(ubufData + viewDataOffset + viewIdx * 64, viewProjection.constData(), 64);
2383 viewDataOffset += cameras.count() * 64;
2384 memcpy(ubufData + viewDataOffset + viewIdx * 64, inverseProjection.constData(), 64);
2385 viewDataOffset += cameras.count() * 64;
2386 memcpy(ubufData + viewDataOffset + viewIdx * 48, viewMatrix.constData(), 48);
2388 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2390 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
2392 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
2393 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2394 entry->m_skyBoxSrbs[cubeFaceIdx] = rhiCtxD->srb(bindings);
2396 layer.skyBoxSrb = rhiCtxD->srb(bindings);
2400 renderer.rhiCubeRenderer()->prepareCube(rhiCtx,
nullptr);
2402 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
2441 QSSGPassKey passKey,
2442 const QSSGRhiGraphicsPipelineState &basePipelineState,
2443 QRhiRenderPassDescriptor *rpDesc,
2445 const QSSGRenderableObjectList &sortedOpaqueObjects,
2446 const QSSGRenderableObjectList &sortedTransparentObjects,
2450 static const auto rhiPrepareDepthPassForObject = [](QSSGRhiContext *rhiCtx,
2451 QSSGPassKey passKey,
2454 QRhiRenderPassDescriptor *rpDesc,
2455 QSSGRhiGraphicsPipelineState *ps) {
2456 QSSGRhiShaderPipelinePtr shaderPipeline;
2457 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2459 const bool isOpaqueDepthPrePass = obj->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
2460 QSSGShaderFeatures featureSet;
2461 featureSet.set(QSSGShaderFeatures::Feature::DepthPass,
true);
2462 if (isOpaqueDepthPrePass)
2463 featureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
2465 QSSGRhiDrawCallData *dcd =
nullptr;
2466 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2467 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2468 const void *modelNode = &subsetRenderable.modelContext.model;
2469 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material,
nullptr, 0 });
2472 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2473 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2474 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2475 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2477 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
2478 if (shaderPipeline) {
2479 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2480 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2481 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2482 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2486 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2487 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2489 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2491 ps->cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2493 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
2494 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2496 if (shaderPipeline) {
2497 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2498 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2499 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, customMaterial, subsetRenderable,
2500 inData.renderedCameras,
nullptr,
nullptr);
2501 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2508 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2509 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2510 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
2511 ia = subsetRenderable.subset.rhi.ia;
2513 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2514 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2515 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2517 QSSGRhiShaderResourceBindingList bindings;
2518 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2521 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2523 if (isOpaqueDepthPrePass) {
2524 addOpaqueDepthPrePassBindings(rhiCtx,
2525 shaderPipeline.get(),
2526 subsetRenderable.firstImage,
2528 (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
2534 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2535 if (normalTextureBinding >= 0) {
2536 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2537 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2538 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2539 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2540 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2541 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2545 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2546 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2548 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2549 QRhiSampler::Nearest,
2551 QRhiSampler::ClampToEdge,
2552 QRhiSampler::ClampToEdge,
2555 bindings.addTexture(binding,
2556 QRhiShaderResourceBinding::VertexStage,
2563 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2564 if (targetsTexture) {
2565 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2567 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2568 QRhiSampler::Nearest,
2570 QRhiSampler::ClampToEdge,
2571 QRhiSampler::ClampToEdge,
2572 QRhiSampler::ClampToEdge
2574 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2578 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2580 subsetRenderable.rhiRenderData.depthPrePass.pipeline = rhiCtxD->pipeline(*ps,
2583 subsetRenderable.rhiRenderData.depthPrePass.srb = srb;
2594 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2599 ps.samples = samples;
2600 ps.viewCount = viewCount;
2601 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
2602 ps.targetBlend[0].colorWrite = {};
2604 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2605 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2609 for (
const QSSGRenderableObjectHandle &handle : sortedTransparentObjects) {
2610 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2737 QSSGPassKey passKey,
2738 const QSSGRhiGraphicsPipelineState &basePipelineState,
2739 QRhiRenderPassDescriptor *rpDesc,
2741 const QSSGRenderableObjectList &sortedOpaqueObjects)
2743 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2744 ps.depthFunc = QRhiGraphicsPipeline::LessOrEqual;
2745 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
2747 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2748 QSSGRenderableObject *obj = handle.obj;
2749 QSSGRhiShaderPipelinePtr shaderPipeline;
2750 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2752 QSSGShaderFeatures featureSet;
2753 featureSet.set(QSSGShaderFeatures::Feature::NormalPass,
true);
2755 QSSGRhiDrawCallData *dcd =
nullptr;
2756 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2757 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2758 const void *modelNode = &subsetRenderable.modelContext.model;
2759 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material,
nullptr, 0 });
2762 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2763 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2764 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2765 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2767 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
2768 if (shaderPipeline) {
2769 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2770 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2771 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2772 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2774 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2775 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2777 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2779 ps.cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2781 const auto &customMaterialSystem = subsetRenderable.renderer->contextInterface()->customMaterialSystem();
2782 shaderPipeline = customMaterialSystem->shadersForCustomMaterial(&ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2784 if (shaderPipeline) {
2785 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2786 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2787 customMaterialSystem->updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, customMaterial, subsetRenderable,
2788 inData.renderedCameras,
nullptr,
nullptr);
2789 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2794 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2795 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2796 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
2797 ia = subsetRenderable.subset.rhi.ia;
2799 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2800 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2801 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2803 QSSGRhiShaderResourceBindingList bindings;
2804 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2807 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
2808 while (renderableImage) {
2809 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
2810 const int samplerHint =
int(renderableImage->m_mapType);
2811 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
2812 if (samplerBinding >= 0) {
2813 QRhiTexture *texture = renderableImage->m_texture.m_texture;
2814 if (samplerBinding >= 0 && texture) {
2815 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
2816 QSSGRhiSamplerDescription samplerDesc = {
2817 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
2818 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
2819 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
2820 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
2821 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
2822 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
2824 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
2825 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
2826 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
2829 renderableImage = renderableImage->m_nextImage;
2832 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2835 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2836 if (normalTextureBinding >= 0) {
2837 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2838 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2839 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2840 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2841 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2842 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2848 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2849 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2851 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2852 QRhiSampler::Nearest,
2854 QRhiSampler::ClampToEdge,
2855 QRhiSampler::ClampToEdge,
2858 bindings.addTexture(binding,
2859 QRhiShaderResourceBinding::VertexStage,
2866 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2867 if (targetsTexture) {
2868 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2870 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2871 QRhiSampler::Nearest,
2873 QRhiSampler::ClampToEdge,
2874 QRhiSampler::ClampToEdge,
2875 QRhiSampler::ClampToEdge
2877 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2881 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2883 subsetRenderable.rhiRenderData.normalPass.pipeline = rhiCtxD->pipeline(ps,
2886 subsetRenderable.rhiRenderData.normalPass.srb = srb;
2955 QSSGPassKey passKey,
2956 const QSSGRhiGraphicsPipelineState &basePipelineState,
2957 QRhiRenderPassDescriptor *rpDesc,
2958 QSSGRenderGraphObject *overrideMaterial,
2960 QSSGRenderableObjectList &inObjects,
2961 QSSGShaderFeatures featureSet)
2964 const qsizetype index = overrideMaterial ? inData.getUserRenderPassManager()->acquireUserPassSlot() : -1;
2969 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2970 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2972 const bool isCustomMaterial = (overrideMaterial->type == QSSGRenderGraphObject::Type::CustomMaterial);
2973 const bool isDefaultMaterial = (overrideMaterial->type == QSSGRenderGraphObject::Type::DefaultMaterial ||
2974 overrideMaterial->type == QSSGRenderGraphObject::Type::PrincipledMaterial ||
2975 overrideMaterial->type == QSSGRenderGraphObject::Type::SpecularGlossyMaterial);
2977 if (!isCustomMaterial && !isDefaultMaterial) {
2978 qDebug() <<
"Override material must be a default or custom material.";
2982 for (
const QSSGRenderableObjectHandle &handle : std::as_const(inObjects)) {
2983 QSSGRenderableObject *obj = handle.obj;
2985 if (obj->type != QSSGRenderableObject::Type::DefaultMaterialMeshSubset &&
2986 obj->type != QSSGRenderableObject::Type::CustomMaterialMeshSubset)
2989 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2990 const void *modelNode = &subsetRenderable.modelContext.model;
2991 QSSGRhiDrawCallData *dcd = &rhiCtxD->drawCallData({ passKey, modelNode, overrideMaterial,
nullptr, 0 });
2997 QSSGRenderableObjectFlags renderableFlags = subsetRenderable.renderableFlags;
2998 float opacity = subsetRenderable.opacity;
3001 const bool hasAnyLights = !subsetRenderable.lights.isEmpty();
3002 const bool anyLightHasShadows = std::any_of(subsetRenderable.lights.begin(),
3003 subsetRenderable.lights.end(),
3004 [](
const QSSGShaderLight &light) {
return light.shadows; });
3008 auto layerPrepFlags = inData.layerPrepResult.getFlags();
3010 if (isCustomMaterial) {
3011 auto &material =
static_cast<QSSGRenderCustomMaterial &>(*overrideMaterial);
3012 auto prepResult = inData.prepareCustomMaterialForRender(material, renderableFlags, opacity,
3013 false, hasAnyLights, anyLightHasShadows,
3015 subsetRenderable.shaderDescription = prepResult.materialKey;
3017 auto &material =
static_cast<QSSGRenderDefaultMaterial &>(*overrideMaterial);
3018 auto prepResult = inData.prepareDefaultMaterialForRender(material, renderableFlags, opacity,
3019 hasAnyLights, anyLightHasShadows,
3021 subsetRenderable.shaderDescription = prepResult.materialKey;
3025 QSSGRhiShaderPipelinePtr shaderPipeline;
3027 if (isCustomMaterial) {
3028 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(*overrideMaterial);
3029 if (!ps.userSetCullMode)
3030 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
3032 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
3033 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable,
3034 inData.getDefaultMaterialPropertyTable(), featureSet);
3035 if (shaderPipeline) {
3036 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3037 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3038 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3039 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3040 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3043 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(*overrideMaterial);
3044 if (!ps.userSetCullMode)
3045 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3047 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
3048 if (shaderPipeline) {
3049 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3050 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3051 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable,
3052 inData.renderedCameras,
nullptr,
nullptr, overrideMaterial);
3053 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3057 if (!shaderPipeline)
3060 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3061 ia = subsetRenderable.subset.rhi.ia;
3063 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3064 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3065 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3067 QSSGRhiShaderResourceBindingList bindings;
3068 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3071 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3072 while (renderableImage) {
3073 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3074 const int samplerHint =
int(renderableImage->m_mapType);
3075 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3076 if (samplerBinding >= 0) {
3077 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3079 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3080 QSSGRhiSamplerDescription samplerDesc = {
3081 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3082 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3083 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3084 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3085 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3086 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3088 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3089 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3090 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3093 renderableImage = renderableImage->m_nextImage;
3096 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3099 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3100 if (normalTextureBinding >= 0) {
3101 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3102 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3103 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3104 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3105 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3106 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3110 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3111 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3113 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3114 QRhiSampler::Nearest,
3116 QRhiSampler::ClampToEdge,
3117 QRhiSampler::ClampToEdge,
3120 bindings.addTexture(binding,
3121 QRhiShaderResourceBinding::VertexStage,
3128 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3129 if (targetsTexture) {
3130 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3132 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3133 QRhiSampler::Nearest,
3135 QRhiSampler::ClampToEdge,
3136 QRhiSampler::ClampToEdge,
3137 QRhiSampler::ClampToEdge
3139 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3144 if (shaderPipeline->isLightingEnabled()) {
3145 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3146 shaderPipeline->ub0LightDataOffset(),
3147 sizeof(QSSGShaderLightsUniformData));
3148 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3149 shaderPipeline->ub0DirectionalLightDataOffset(),
3150 sizeof(QSSGShaderDirectionalLightsUniformData));
3153 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3154 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3157 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3158 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
3159 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3162 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3163 QRhiSampler::Linear,
3165 QRhiSampler::ClampToEdge,
3166 QRhiSampler::ClampToEdge,
3167 QRhiSampler::Repeat });
3169 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3173 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3174 QRhiTexture *texture = shaderPipeline->shadowMapBlueNoiseTexture();
3177 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3178 texture = rhiCtx->dummyTexture({ }, resourceUpdates);
3179 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3182 QRhiSampler *sampler = rhiCtx->sampler(
3183 { QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3185 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3189 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3191 auto texture = shaderPipeline->lightProbeTexture();
3193 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3194 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
3195 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3199 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
3200 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3201 QRhiSampler::Linear,
3202 QRhiSampler::Linear,
3203 QSSGRhiHelpers::toRhi(tiling.first),
3204 QSSGRhiHelpers::toRhi(tiling.second),
3205 QRhiSampler::Repeat });
3206 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3210 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3212 QSSG_ASSERT(srb,
continue);
3213 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3214 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3215 rhiPassData.srb = srb;
3222 QSSGPassKey passKey,
3223 const QSSGRhiGraphicsPipelineState &basePipelineState,
3224 QRhiRenderPassDescriptor *rpDesc,
3226 QSSGRenderableObjectList &inObjects,
3227 QSSGShaderFeatures featureSet)
3229 const qsizetype index = inData.getUserRenderPassManager()->acquireUserPassSlot();
3234 QSSGRhiGraphicsPipelineState ps = basePipelineState;
3235 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3237 for (
const QSSGRenderableObjectHandle &handle : std::as_const(inObjects)) {
3238 QSSGRenderableObject *obj = handle.obj;
3239 QSSGRhiShaderPipelinePtr shaderPipeline;
3241 QSSGRhiDrawCallData *dcd =
nullptr;
3242 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset ||
3243 obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3244 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3245 const void *modelNode = &subsetRenderable.modelContext.model;
3246 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material,
nullptr, 0 });
3249 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
3250 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3251 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
3252 if (!ps.userSetCullMode)
3253 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3255 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
3256 if (shaderPipeline) {
3257 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3258 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3259 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable,
3260 inData.renderedCameras,
nullptr,
nullptr);
3261 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3263 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3264 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3265 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
3266 if (!ps.userSetCullMode)
3267 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
3269 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
3270 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable,
3271 inData.getDefaultMaterialPropertyTable(), featureSet);
3272 if (shaderPipeline) {
3273 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3274 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3275 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3276 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3277 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3281 if (!shaderPipeline)
3285 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset ||
3286 obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3287 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
3288 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3289 ia = subsetRenderable.subset.rhi.ia;
3291 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3292 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3293 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3295 QSSGRhiShaderResourceBindingList bindings;
3296 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3299 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3300 while (renderableImage) {
3301 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3302 const int samplerHint =
int(renderableImage->m_mapType);
3303 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3304 if (samplerBinding >= 0) {
3305 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3306 if (samplerBinding >= 0 && texture) {
3307 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3308 QSSGRhiSamplerDescription samplerDesc = {
3309 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3310 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3311 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3312 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3313 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3314 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3316 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3317 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3318 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3321 renderableImage = renderableImage->m_nextImage;
3324 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3327 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3328 if (normalTextureBinding >= 0) {
3329 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3330 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3331 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3332 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3333 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3334 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3338 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3339 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3341 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3342 QRhiSampler::Nearest,
3344 QRhiSampler::ClampToEdge,
3345 QRhiSampler::ClampToEdge,
3348 bindings.addTexture(binding,
3349 QRhiShaderResourceBinding::VertexStage,
3356 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3357 if (targetsTexture) {
3358 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3360 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3361 QRhiSampler::Nearest,
3363 QRhiSampler::ClampToEdge,
3364 QRhiSampler::ClampToEdge,
3365 QRhiSampler::ClampToEdge
3367 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3372 if (shaderPipeline->isLightingEnabled()) {
3373 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3374 shaderPipeline->ub0LightDataOffset(),
3375 sizeof(QSSGShaderLightsUniformData));
3376 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3377 shaderPipeline->ub0DirectionalLightDataOffset(),
3378 sizeof(QSSGShaderDirectionalLightsUniformData));
3381 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3382 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3385 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3386 texture = rhiCtx->dummyTexture({ }, resourceUpdates);
3387 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3390 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3391 QRhiSampler::Linear,
3393 QRhiSampler::ClampToEdge,
3394 QRhiSampler::ClampToEdge,
3395 QRhiSampler::Repeat });
3397 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3401 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3402 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
3403 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
3405 QRhiTexture *texture = shadowMapBlueNoise;
3406 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3407 QRhiSampler::Linear,
3409 QRhiSampler::Repeat,
3410 QRhiSampler::Repeat,
3411 QRhiSampler::Repeat });
3412 Q_ASSERT(texture && sampler);
3413 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3416 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3417 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
3418 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3419 QRhiSampler::Linear,
3421 QRhiSampler::Repeat,
3422 QRhiSampler::Repeat,
3423 QRhiSampler::Repeat });
3424 Q_ASSERT(texture && sampler);
3425 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3426 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3431 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
3432 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
3433 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
3434 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
3435 ? QRhiSampler::Linear
3436 : QRhiSampler::None;
3437 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3438 QRhiSampler::Linear,
3440 QRhiSampler::ClampToEdge,
3441 QRhiSampler::ClampToEdge,
3442 QRhiSampler::Repeat });
3443 if (reflectionSampler >= 0 && reflectionTexture)
3444 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
3447 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3449 auto texture = shaderPipeline->lightProbeTexture();
3451 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3452 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
3453 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3457 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
3458 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3459 QRhiSampler::Linear,
3460 QRhiSampler::Linear,
3461 QSSGRhiHelpers::toRhi(tiling.first),
3462 QSSGRhiHelpers::toRhi(tiling.second),
3463 QRhiSampler::Repeat });
3464 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3468 if (shaderPipeline->screenTexture()) {
3469 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
3470 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
3471 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
3472 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
3473 ? QRhiSampler::Linear : QRhiSampler::None;
3474 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
3475 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3476 if (screenTextureBinding >= 0) {
3477 bindings.addTexture(screenTextureBinding,
3478 QRhiShaderResourceBinding::FragmentStage,
3479 shaderPipeline->screenTexture(), sampler);
3481 if (screenTextureArrayBinding >= 0) {
3482 bindings.addTexture(screenTextureArrayBinding,
3483 QRhiShaderResourceBinding::FragmentStage,
3484 shaderPipeline->screenTexture(), sampler);
3489 if (shaderPipeline->lightmapTexture()) {
3490 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
3492 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
3493 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
3494 bindings.addTexture(binding,
3495 QRhiShaderResourceBinding::FragmentStage,
3496 shaderPipeline->lightmapTexture(), sampler);
3503 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3504 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3506 int maxSamplerBinding = -1;
3507 QVector<QShaderDescription::InOutVariable> samplerVars =
3508 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
3509 const auto combinedSamplers = shaderPipeline->vertexStage()->shader().description().combinedImageSamplers();
3510 for (
const QShaderDescription::InOutVariable &var : combinedSamplers) {
3511 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
3512 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
3513 if (it == samplerVars.cend())
3514 samplerVars.append(var);
3517 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
3518 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
3520 if (maxSamplerBinding >= 0) {
3521 int extraTexCount = shaderPipeline->extraTextureCount();
3522 for (
int i = 0; i < extraTexCount; ++i) {
3523 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
3524 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
3525 if (samplerBinding >= 0) {
3526 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
3527 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
3528 bindings.addTexture(samplerBinding,
3529 QRhiShaderResourceBinding::FragmentStage,
3537 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3539 QSSG_ASSERT(srb,
continue);
3541 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3542 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3543 rhiPassData.srb = srb;
3552 QSSGPassKey passKey,
3553 const QSSGRhiGraphicsPipelineState &basePipelineState,
3554 QRhiRenderPassDescriptor *rpDesc,
3557 QSSGRenderableObjectList &inObjects,
3558 QSSGShaderFeatures featureSet)
3560 const qsizetype index = inData.getUserRenderPassManager()->acquireUserPassSlot();
3566 QSSGRhiGraphicsPipelineState ps = basePipelineState;
3567 for (
const QSSGRenderableObjectHandle &handle : std::as_const(inObjects)) {
3568 QSSGRenderableObject *obj = handle.obj;
3569 QSSGRhiShaderPipelinePtr shaderPipeline;
3570 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3571 const auto &bufferManager = inData.contextInterface()->bufferManager();
3573 featureSet.set(QSSGShaderFeatures::Feature::UserRenderPass,
true);
3575 QSSGRhiDrawCallData *dcd =
nullptr;
3576 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3577 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3578 const void *modelNode = &subsetRenderable.modelContext.model;
3579 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material,
nullptr, 0 });
3582 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
3583 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3584 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
3585 if (!ps.userSetCullMode)
3586 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3588 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet, shaderAugmentation);
3589 if (shaderPipeline) {
3590 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3591 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3593 for (
const auto &u : shaderAugmentation.propertyUniforms)
3594 shaderPipeline->setShaderResources(ubufData, *bufferManager, u.name, u.value, u.shaderDataType);
3595 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3596 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3598 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3599 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3600 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
3601 if (!ps.userSetCullMode)
3602 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
3604 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
3606 if (material.m_shadingMode == QSSGRenderCustomMaterial::ShadingMode::Unshaded)
3607 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
3609 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet, shaderAugmentation);
3611 if (shaderPipeline) {
3612 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3613 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3615 for (
const auto &u : shaderAugmentation.propertyUniforms)
3616 shaderPipeline->setShaderResources(ubufData, *bufferManager, u.name, u.value, u.shaderDataType);
3617 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3618 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3619 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3623 if (!shaderPipeline) {
3625 qDebug() <<
"Failed to prepare user augmented pass for object.";
3630 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3631 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
3632 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3633 ia = subsetRenderable.subset.rhi.ia;
3635 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3636 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3637 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3639 QSSGRhiShaderResourceBindingList bindings;
3640 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3647 QVector<QShaderDescription::InOutVariable> samplerVars =
3648 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
3649 const auto combinedSamplers = shaderPipeline->vertexStage()->shader().description().combinedImageSamplers();
3650 for (
const QShaderDescription::InOutVariable &var : combinedSamplers) {
3651 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
3652 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
3653 if (it == samplerVars.cend())
3654 samplerVars.append(var);
3657 int maxSamplerBinding = -1;
3658 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
3659 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
3661 QBitArray specifiedBindings(maxSamplerBinding + 1);
3662 const auto addTrackedTexture = [&](
int binding, QRhiShaderResourceBinding::StageFlags stage,
3663 QRhiTexture *texture, QRhiSampler *sampler) {
3664 specifiedBindings.setBit(binding);
3665 bindings.addTexture(binding, stage, texture, sampler);
3669 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3670 while (renderableImage) {
3671 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3672 const int samplerHint =
int(renderableImage->m_mapType);
3673 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3674 if (samplerBinding >= 0) {
3675 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3676 if (samplerBinding >= 0 && texture) {
3677 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3678 QSSGRhiSamplerDescription samplerDesc = {
3679 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3680 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3681 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3682 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3683 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3684 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3686 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3687 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3688 addTrackedTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3691 renderableImage = renderableImage->m_nextImage;
3694 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings, &specifiedBindings);
3697 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3698 if (normalTextureBinding >= 0) {
3699 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3700 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3701 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3702 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3703 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3704 addTrackedTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3710 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3711 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3713 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3714 QRhiSampler::Nearest,
3716 QRhiSampler::ClampToEdge,
3717 QRhiSampler::ClampToEdge,
3720 addTrackedTexture(binding,
3721 QRhiShaderResourceBinding::VertexStage,
3728 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3729 if (targetsTexture) {
3730 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3732 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3733 QRhiSampler::Nearest,
3735 QRhiSampler::ClampToEdge,
3736 QRhiSampler::ClampToEdge,
3737 QRhiSampler::ClampToEdge
3739 addTrackedTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3744 if (shaderPipeline->isLightingEnabled()) {
3745 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3746 shaderPipeline->ub0LightDataOffset(),
3747 sizeof(QSSGShaderLightsUniformData));
3748 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3749 shaderPipeline->ub0DirectionalLightDataOffset(),
3750 sizeof(QSSGShaderDirectionalLightsUniformData));
3753 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3754 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3757 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3758 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
3759 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3762 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3763 QRhiSampler::Linear,
3765 QRhiSampler::ClampToEdge,
3766 QRhiSampler::ClampToEdge,
3767 QRhiSampler::Repeat });
3769 addTrackedTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3773 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3774 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
3775 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
3777 QRhiTexture *texture = shadowMapBlueNoise;
3778 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3779 QRhiSampler::Linear,
3781 QRhiSampler::Repeat,
3782 QRhiSampler::Repeat,
3783 QRhiSampler::Repeat });
3784 Q_ASSERT(texture && sampler);
3785 addTrackedTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3788 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3789 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
3790 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3791 QRhiSampler::Linear,
3793 QRhiSampler::Repeat,
3794 QRhiSampler::Repeat,
3795 QRhiSampler::Repeat });
3796 Q_ASSERT(texture && sampler);
3797 addTrackedTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3798 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3805 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
3806 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
3807 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
3808 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
3809 ? QRhiSampler::Linear
3810 : QRhiSampler::None;
3811 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3812 QRhiSampler::Linear,
3814 QRhiSampler::ClampToEdge,
3815 QRhiSampler::ClampToEdge,
3816 QRhiSampler::Repeat });
3817 if (reflectionSampler >= 0 && reflectionTexture)
3818 addTrackedTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
3820 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3822 auto texture = shaderPipeline->lightProbeTexture();
3824 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3825 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
3826 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3830 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
3831 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3832 QRhiSampler::Linear,
3833 QRhiSampler::Linear,
3834 QSSGRhiHelpers::toRhi(tiling.first),
3835 QSSGRhiHelpers::toRhi(tiling.second),
3836 QRhiSampler::Repeat });
3837 addTrackedTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3841 if (shaderPipeline->screenTexture()) {
3842 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
3843 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
3844 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
3849 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
3850 ? QRhiSampler::Linear : QRhiSampler::None;
3851 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
3852 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3853 if (screenTextureBinding >= 0) {
3854 addTrackedTexture(screenTextureBinding,
3855 QRhiShaderResourceBinding::FragmentStage,
3856 shaderPipeline->screenTexture(), sampler);
3858 if (screenTextureArrayBinding >= 0) {
3859 addTrackedTexture(screenTextureArrayBinding,
3860 QRhiShaderResourceBinding::FragmentStage,
3861 shaderPipeline->screenTexture(), sampler);
3866 if (shaderPipeline->lightmapTexture()) {
3867 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
3869 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
3870 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
3871 addTrackedTexture(binding,
3872 QRhiShaderResourceBinding::FragmentStage,
3873 shaderPipeline->lightmapTexture(), sampler);
3880 if (maxSamplerBinding >= 0) {
3882 int extraTexCount = shaderPipeline->extraTextureCount();
3883 for (
int i = 0; i < extraTexCount; ++i) {
3884 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
3885 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
3886 if (samplerBinding >= 0) {
3887 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
3888 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
3889 addTrackedTexture(samplerBinding,
3890 QRhiShaderResourceBinding::FragmentStage,
3898 QRhiSampler *dummySampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3899 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
3900 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3901 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3902 QRhiTexture *dummyTextureArray = rhiCtx->dummyTexture({}, resourceUpdates, QSize(64, 64), Qt::black, qMax(2u, inData.layer.viewCount));
3903 QRhiTexture *dummyTexture3D = rhiCtx->dummyTexture(QRhiTexture::ThreeDimensional, resourceUpdates);
3904 QRhiTexture *dummyCubeTexture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
3905 QRhiTexture *dummyCubeTextureArray = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates, QSize(64, 64), Qt::black, qMax(2u, inData.layer.viewCount));
3906 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3908 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars)) {
3909 if (!specifiedBindings.testBit(var.binding)) {
3910 QRhiTexture *t =
nullptr;
3911 if (var.type == QShaderDescription::SamplerCube)
3912 t = dummyCubeTexture;
3913 else if (var.type == QShaderDescription::Sampler3D)
3915 else if (var.type == QShaderDescription::Sampler2DArray)
3916 t = dummyTextureArray;
3917 else if (var.type == QShaderDescription::SamplerCubeArray)
3918 t = dummyCubeTextureArray;
3921 bindings.addTexture(var.binding, RENDERER_VISIBILITY_ALL, t, dummySampler);
3926 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3927 QSSG_ASSERT(srb,
return -1);
3928 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3929 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3930 rhiPassData.srb = srb;
3994 QSSGPassKey passKey,
3996 const QMatrix4x4 &viewProjection,
3998 QRhiRenderPassDescriptor *renderPassDescriptor,
3999 QSSGRhiGraphicsPipelineState *ps,
4000 QSSGRenderMotionVectorMap &motionVectorMapManager)
4002 if (inObject.type != QSSGRenderableObject::Type::DefaultMaterialMeshSubset &&
4003 inObject.type != QSSGRenderableObject::Type::CustomMaterialMeshSubset)
4006 QSSGSubsetRenderable &subsetRenderable =
static_cast<QSSGSubsetRenderable &>(inObject);
4007 auto &modelNode = subsetRenderable.modelContext.model;
4009 bool skin = modelNode.usesBoneTexture();
4010 bool instance = modelNode.instanceCount() > 0;
4011 bool morph = modelNode.morphTargets.size() > 0;
4013 QSSGRhiShaderPipelinePtr shaderPipeline = inData.contextInterface()->shaderCache()->
4014 getBuiltInRhiShaders().getRhiMotionVectorShader(skin, instance, morph);
4016 if (!shaderPipeline)
4019 QSSGRhiShaderResourceBindingList bindings;
4021 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
4022 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey, &modelNode,
nullptr,
nullptr, 0 });
4025 QSSGRenderTextureData *boneTextureData =
nullptr;
4027 boneTextureData = modelNode.skin;
4028 else if (modelNode.skeleton)
4029 boneTextureData = &modelNode.skeleton->boneTexData;
4031 QMatrix4x4 modelViewProjection = subsetRenderable.modelContext.modelViewProjections[0];
4032 QMatrix4x4 instanceLocal;
4033 QMatrix4x4 instanceGlobal;
4036 instanceLocal = inData.getInstanceTransforms(modelNode).local;
4037 instanceGlobal = inData.getInstanceTransforms(modelNode).global;
4039 modelViewProjection = viewProjection;
4041 auto motionData = motionVectorMapManager.trackMotionData(&modelNode,
4042 modelViewProjection,
4046 modelNode.instanceTable,
4047 modelNode.morphWeights);
4048 float velocityAmount = subsetRenderable.modelContext.model.motionVectorScale;
4049 int morphTargetCount = modelNode.morphWeights.count();
4061 const int ubufSize = 416;
4064 dcd.ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic,
4065 QRhiBuffer::UniformBuffer,
4070 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
4072 memcpy(ubufData, modelViewProjection.constData(), 64);
4074 memcpy(ubufData + ubufOffset, motionData.prevModelViewProjection.constData(), 64);
4076 memcpy(ubufData + ubufOffset, instanceLocal.constData(), 64);
4078 memcpy(ubufData + ubufOffset, instanceGlobal.constData(), 64);
4080 memcpy(ubufData + ubufOffset, motionData.prevInstanceLocal.constData(), 64);
4082 memcpy(ubufData + ubufOffset, motionData.prevInstanceGlobal.constData(), 64);
4084 memcpy(ubufData + ubufOffset, &inData.layer.currentAndLastJitter, 16);
4086 memcpy(ubufData + ubufOffset, &velocityAmount, 4);
4088 memcpy(ubufData + ubufOffset, &morphTargetCount, 4);
4089 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
4091 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::VertexStage |
4092 QRhiShaderResourceBinding::FragmentStage, dcd.ubuf);
4094 QRhiSampler *nearestSampler =
nullptr;
4096 if (skin || instance) {
4097 nearestSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
4098 QRhiSampler::Nearest,
4100 QRhiSampler::ClampToEdge,
4101 QRhiSampler::ClampToEdge,
4107 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
4110 bindings.addTexture(binding,
4111 QRhiShaderResourceBinding::VertexStage,
4112 inData.getBonemapTexture(subsetRenderable.modelContext),
4114 binding = shaderPipeline->bindingForTexture(
"lastBoneTexture");
4116 bindings.addTexture(binding,
4117 QRhiShaderResourceBinding::VertexStage,
4118 motionData.prevBoneTexture.m_texture,
4125 int binding = shaderPipeline->bindingForTexture(
"lastInstanceTexture");
4127 bindings.addTexture(binding,
4128 QRhiShaderResourceBinding::VertexStage,
4129 motionData.prevInstanceTexture.m_texture,
4134 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
4135 if (targetsTexture) {
4136 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
4138 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
4139 QRhiSampler::Nearest,
4141 QRhiSampler::ClampToEdge,
4142 QRhiSampler::ClampToEdge,
4143 QRhiSampler::ClampToEdge
4145 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
4147 if ((binding = shaderPipeline->bindingForTexture(
"morphWeightTexture")) >= 0)
4148 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, motionData.currentMorphWeightTexture.m_texture, targetsSampler);
4150 if ((binding = shaderPipeline->bindingForTexture(
"lastMorphWeightTexture")) >= 0)
4151 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, motionData.prevMorphWeightTexture.m_texture, targetsSampler);
4155 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
4156 ia = subsetRenderable.subset.rhi.ia;
4157 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
4158 QVector3D cameraDirection = cameraDatas[0].direction;
4159 QVector3D cameraPosition = cameraDatas[0].position;
4160 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDirection, cameraPosition);
4161 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
4162 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
4164 QRhiShaderResourceBindings *&srb = dcd.srb;
4165 bool srbChanged =
false;
4166 if (!srb || bindings != dcd.bindings) {
4167 srb = rhiCtxD->srb(bindings);
4168 rhiCtxD->releaseCachedSrb(dcd.bindings);
4169 dcd.bindings = bindings;
4173 subsetRenderable.rhiRenderData.motionVectorPass.srb = srb;
4175 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
4178 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
4179 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
4182 subsetRenderable.rhiRenderData.motionVectorPass.pipeline = dcd.pipeline;
4185 subsetRenderable.rhiRenderData.motionVectorPass.pipeline = rhiCtxD->pipeline(pipelineKey,
4186 renderPassDescriptor,
4188 dcd.pipeline = subsetRenderable.rhiRenderData.motionVectorPass.pipeline;
4189 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
4190 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;