249 const QSSGRenderCamera &inCamera,
250 const QSSGRenderLight *inLight,
251 const int shadowMapResolution,
252 const float pcfRadius,
253 const float clipNear,
255 const QSSGBounds3 &castingObjectsBox,
256 const QSSGBounds3 &receivingObjectsBox,
257 bool lockShadowmapTexels,
258 QSSGDebugDrawSystem *debugDrawSystem,
260 bool drawSceneCascadeIntersection)
262 Q_ASSERT(inLight->type == QSSGRenderLight::Type::DirectionalLight);
263 QVarLengthArray<std::unique_ptr<QSSGRenderCamera>, 4> result;
265 if (clipNear >= clipFar || qFuzzyCompare(clipNear, clipFar))
268 const QMatrix4x4 lightGlobalTransform = data.getGlobalTransform(*inLight);
269 const QVector3D lightDir = inLight->getDirection(lightGlobalTransform);
270 const QVector3D lightPivot = inLight->pivot;
272 const QVector3D forward = lightDir.normalized();
273 const QVector3D right = qFuzzyCompare(qAbs(forward.y()), 1.0f)
274 ? QVector3D::crossProduct(forward, QVector3D(1, 0, 0)).normalized()
275 : QVector3D::crossProduct(forward, QVector3D(0, 1, 0)).normalized();
276 const QVector3D up = QVector3D::crossProduct(right, forward).normalized();
278 QMatrix4x4 lightMatrix;
279 lightMatrix.setRow(0, QVector4D(right, 0.0f));
280 lightMatrix.setRow(1, QVector4D(up, 0.0f));
281 lightMatrix.setRow(2, QVector4D(forward, 0.0f));
282 lightMatrix.setRow(3, QVector4D(0.0f, 0.0f, 0.0f, 1.0f));
283 QMatrix4x4 lightMatrixInverted = lightMatrix.inverted();
285 const float farScale = (clipFar - clipNear) / (inCamera.clipPlanes.clipFar() - inCamera.clipPlanes.clipNear());
287 const QMatrix4x4 cameraGlobalTransform = data.getGlobalTransform(inCamera);
288 QMatrix4x4 viewProjection(Qt::Uninitialized);
289 inCamera.calculateViewProjectionMatrix(cameraGlobalTransform, viewProjection);
290 const QSSGBoxPoints frustum = computeFrustumBounds(viewProjection);
291 const QSSGBoxPoints frustumUntransformed = lockShadowmapTexels ? computeFrustumBounds(inCamera.projection) : QSSGBoxPoints();
295 const auto calcFrustumRadius = [&](
float t0,
float t1) ->
float {
296 const QSSGBoxPoints pts = sliceFrustum(frustumUntransformed, t0 * farScale, t1 * farScale);
298 QVector3D center = QVector3D(0.f, 0.f, 0.f);
299 for (QVector3D point : pts) {
302 center = center * 0.125f;
304 float radiusSquared = 0;
305 for (QVector3D point : pts) {
306 radiusSquared = qMax(radiusSquared, (point - center).lengthSquared());
309 return std::sqrt(radiusSquared);
312 const auto computeSplitRanges = [inLight](
const QVarLengthArray<
float, 3> &splits) -> QVarLengthArray<QPair<
float,
float>, 4> {
313 QVarLengthArray<QPair<
float,
float>, 4> ranges;
314 const float csmBlendRatio = inLight->m_csmBlendRatio;
316 for (qsizetype i = 0; i < splits.length(); i++) {
317 const float tI = qBound(qMin(t0 + 0.01f, 1.0f), splits[i], 1.0f);
318 ranges.emplace_back(t0, qMin(1.0f, tI + csmBlendRatio));
321 ranges.emplace_back(t0, 1.0f);
325 const auto computeFrustums = [&](
const QVarLengthArray<
float, 3> &splits) {
326 for (
const auto &range : computeSplitRanges(splits)) {
327 const float frustumRadius = lockShadowmapTexels ? calcFrustumRadius(range.first, range.second) : 0.0f;
328 auto camera = computeShadowCameraFromFrustum(lightMatrix,
336 range.first * farScale,
337 range.second * farScale,
344 drawSceneCascadeIntersection);
345 result.emplace_back(std::move(camera));
349 switch (inLight->m_csmNumSplits) {
355 computeFrustums({ inLight->m_csmSplit1 });
359 computeFrustums({ inLight->m_csmSplit1, inLight->m_csmSplit2 });
363 computeFrustums({ inLight->m_csmSplit1, inLight->m_csmSplit2, inLight->m_csmSplit3 });
405 QSSGRhiShaderPipeline *shaderPipeline,
406 QSSGRenderableImage *renderableImage,
407 QSSGRhiShaderResourceBindingList &bindings,
408 bool isCustomMaterialMeshSubset =
false)
410 static const auto imageAffectsAlpha = [](QSSGRenderableImage::Type mapType) {
411 return mapType == QSSGRenderableImage::Type::BaseColor ||
412 mapType == QSSGRenderableImage::Type::Diffuse ||
413 mapType == QSSGRenderableImage::Type::Translucency ||
414 mapType == QSSGRenderableImage::Type::Opacity;
417 while (renderableImage) {
418 const auto mapType = renderableImage->m_mapType;
419 if (imageAffectsAlpha(mapType)) {
420 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(mapType);
421 const int samplerHint =
int(mapType);
422 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
423 if (samplerBinding >= 0) {
424 QRhiTexture *texture = renderableImage->m_texture.m_texture;
425 if (samplerBinding >= 0 && texture) {
426 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
427 QRhiSampler *sampler = rhiCtx->sampler({ QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
428 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
429 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
430 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
431 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
432 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
434 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
438 renderableImage = renderableImage->m_nextImage;
441 if (isCustomMaterialMeshSubset) {
442 QVector<QShaderDescription::InOutVariable> samplerVars =
443 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
444 for (
const QShaderDescription::InOutVariable &var : shaderPipeline->vertexStage()->shader().description().combinedImageSamplers()) {
445 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
446 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
447 if (it == samplerVars.cend())
448 samplerVars.append(var);
451 int maxSamplerBinding = -1;
452 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
453 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
462 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
464 if (maxSamplerBinding >= 0) {
466 int customTexCount = shaderPipeline->extraTextureCount();
467 for (
int i = 0; i < customTexCount; ++i) {
468 const QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
469 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
470 if (samplerBinding >= 0) {
471 samplerBindingsSpecified.setBit(samplerBinding);
472 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
473 bindings.addTexture(samplerBinding,
474 RENDERER_VISIBILITY_ALL,
482 QRhiSampler *dummySampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
483 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
484 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
485 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
486 QRhiTexture *dummyCubeTexture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
487 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
489 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars)) {
490 if (!samplerBindingsSpecified.testBit(var.binding)) {
491 QRhiTexture *t = var.type == QShaderDescription::SamplerCube ? dummyCubeTexture : dummyTexture;
492 bindings.addTexture(var.binding, RENDERER_VISIBILITY_ALL, t, dummySampler);
704 QSSGRhiGraphicsPipelineState *ps,
705 const QVector2D *depthAdjust,
706 const QSSGRenderableObjectList &sortedOpaqueObjects,
707 QSSGRenderCamera &inCamera,
709 QSSGRenderTextureCubeFace cubeFace,
710 quint32 cascadeIndex)
712 QSSGShaderFeatures featureSet;
714 featureSet.set(QSSGShaderFeatures::Feature::OrthoShadowPass,
true);
716 featureSet.set(QSSGShaderFeatures::Feature::PerspectiveShadowPass,
true);
722 featureSet.set(QSSGShaderFeatures::Feature::DisableMultiView,
true);
724 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
725 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
726 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
728 for (
const auto &handle : sortedOpaqueObjects) {
729 QSSGRenderableObject *theObject = handle.obj;
730 QSSG_ASSERT(theObject->renderableFlags.castsShadows(),
continue);
732 QSSGShaderFeatures objectFeatureSet = featureSet;
733 const bool isOpaqueDepthPrePass = theObject->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
734 if (isOpaqueDepthPrePass)
735 objectFeatureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
737 QSSGRhiDrawCallData *dcd =
nullptr;
738 QMatrix4x4 modelViewProjection;
739 QSSGSubsetRenderable &renderable(
static_cast<QSSGSubsetRenderable &>(*theObject));
740 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
741 const bool hasSkinning = defaultMaterialShaderKeyProperties.m_boneCount.getValue(renderable.shaderDescription) > 0;
742 modelViewProjection = hasSkinning ? pEntry->m_lightViewProjection[cascadeIndex]
743 : pEntry->m_lightViewProjection[cascadeIndex] * renderable.modelContext.globalTransform;
747 const quintptr entryIdx = cascadeIndex + cubeFaceIdx + (quintptr(renderable.subset.offset) << 3);
748 dcd = &rhiCtxD->drawCallData({ passKey, &renderable.modelContext.model, pEntry, entryIdx });
751 QSSGRhiShaderResourceBindingList bindings;
752 QSSGRhiShaderPipelinePtr shaderPipeline;
753 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*theObject));
754 if (theObject->type == QSSGSubsetRenderable::Type::DefaultMaterialMeshSubset) {
755 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
756 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
757 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(subsetRenderable.shaderDescription);
759 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, objectFeatureSet);
762 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
763 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
765 QSSGRenderCameraList cameras({ &inCamera });
766 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, cameras, depthAdjust, &modelViewProjection);
768 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &subsetRenderable.modelContext.model, subsetRenderable.subset.offset);
769 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
771 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &subsetRenderable.modelContext.model);
772 }
else if (theObject->type == QSSGSubsetRenderable::Type::CustomMaterialMeshSubset) {
773 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
774 ps->cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
776 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
777 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), objectFeatureSet);
780 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
781 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
783 QSSGRenderCameraList cameras({ &inCamera });
784 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, material, subsetRenderable,
785 cameras, depthAdjust, &modelViewProjection);
786 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
789 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
791 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
792 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
793 ia = subsetRenderable.subset.rhi.ia;
794 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
795 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
796 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
799 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
802 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
804 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
806 if (isOpaqueDepthPrePass) {
807 addOpaqueDepthPrePassBindings(rhiCtx,
808 shaderPipeline.get(),
809 subsetRenderable.firstImage,
811 (theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
818 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
819 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
820 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
821 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
822 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
823 if (screenTextureBinding >= 0) {
824 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
825 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
826 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
827 bindings.addTexture(screenTextureBinding,
828 QRhiShaderResourceBinding::FragmentStage,
829 dummyTexture, sampler);
831 if (screenTextureArrayBinding >= 0) {
832 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
833 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates, QSize(64, 64), Qt::black, inData.layer.viewCount);
834 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
835 bindings.addTexture(screenTextureArrayBinding,
836 QRhiShaderResourceBinding::FragmentStage,
837 dummyTexture, sampler);
842 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
843 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
845 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
846 QRhiSampler::Nearest,
848 QRhiSampler::ClampToEdge,
849 QRhiSampler::ClampToEdge,
852 bindings.addTexture(binding,
853 QRhiShaderResourceBinding::VertexStage,
860 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
861 if (targetsTexture) {
862 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
864 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
865 QRhiSampler::Nearest,
867 QRhiSampler::ClampToEdge,
868 QRhiSampler::ClampToEdge,
869 QRhiSampler::ClampToEdge
871 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
875 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
876 subsetRenderable.rhiRenderData.shadowPass.pipeline = rhiCtxD->pipeline(*ps, pEntry->m_rhiRenderPassDesc[cascadeIndex], srb);
877 subsetRenderable.rhiRenderData.shadowPass.srb[cubeFaceIdx] = srb;
912 QRhiRenderPassDescriptor *renderPassDescriptor,
913 QSSGRhiGraphicsPipelineState *ps,
914 QSSGShaderFeatures featureSet,
918 QSSGRenderCamera *alteredCamera,
919 QMatrix4x4 *alteredModelViewProjection,
920 QSSGRenderTextureCubeFace cubeFace,
924 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
926 switch (inObject.type) {
927 case QSSGRenderableObject::Type::DefaultMaterialMeshSubset:
929 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
931 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
932 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
934 if ((cubeFace != QSSGRenderTextureCubeFaceNone)) {
936 featureSet.disableTonemapping();
939 if (subsetRenderable.renderableFlags.rendersWithLightmap())
940 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
942 const auto &shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
943 if (shaderPipeline) {
951 QSSGRhiShaderResourceBindingList bindings;
952 const auto &modelNode = subsetRenderable.modelContext.model;
953 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(subsetRenderable.shaderDescription);
960 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
961 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * (cubeFaceIdx + (quintptr(subsetRenderable.subset.offset) << 3));
963 const auto entryPartA =
reinterpret_cast<quintptr>(&subsetRenderable.material);
964 const auto entryPartB =
reinterpret_cast<quintptr>(entry);
965 const void *entryId =
reinterpret_cast<
const void *>(entryPartA ^ entryPartB);
967 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
968 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey, &modelNode, entryId, entryIdx });
970 shaderPipeline->ensureCombinedUniformBuffer(&dcd.ubuf);
971 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
973 Q_ASSERT(alteredModelViewProjection);
974 QSSGRenderCameraList cameras({ alteredCamera });
975 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, cameras,
nullptr, alteredModelViewProjection);
977 Q_ASSERT(!alteredModelViewProjection);
978 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
982 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &subsetRenderable.modelContext.model, subsetRenderable.subset.offset);
983 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
986 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &subsetRenderable.modelContext.model);
989 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
990 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
992 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
993 QRhiSampler::Nearest,
995 QRhiSampler::ClampToEdge,
996 QRhiSampler::ClampToEdge,
999 bindings.addTexture(binding,
1000 QRhiShaderResourceBinding::VertexStage,
1006 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
1007 if (targetsTexture) {
1008 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
1010 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1011 QRhiSampler::Nearest,
1013 QRhiSampler::ClampToEdge,
1014 QRhiSampler::ClampToEdge,
1015 QRhiSampler::ClampToEdge
1017 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
1021 ps->samples = samples;
1022 ps->viewCount = viewCount;
1024 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
1025 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
1026 if (!oit || (oit && inData.layer.oitMethod == QSSGRenderLayer::OITMethod::None))
1027 fillTargetBlend(&ps->targetBlend[0], material.blendMode);
1029 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
1031 ia = subsetRenderable.subset.rhi.ia;
1032 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
1033 QVector3D cameraDirection = cameraDatas[0].direction;
1034 QVector3D cameraPosition = cameraDatas[0].position;
1035 if (alteredCamera) {
1036 const QMatrix4x4 camGlobalTranform = inData.getGlobalTransform(*alteredCamera);
1037 cameraDirection = QSSGRenderNode::getScalingCorrectDirection(camGlobalTranform);
1038 cameraPosition = QSSGRenderNode::getGlobalPos(camGlobalTranform);
1040 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDirection, cameraPosition);
1041 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
1043 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline->ub0Size());
1045 if (shaderPipeline->isLightingEnabled()) {
1046 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd.ubuf,
1047 shaderPipeline->ub0LightDataOffset(),
1048 sizeof(QSSGShaderLightsUniformData));
1049 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd.ubuf,
1050 shaderPipeline->ub0DirectionalLightDataOffset(),
1051 sizeof(QSSGShaderDirectionalLightsUniformData));
1056 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
1057 while (renderableImage) {
1058 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
1059 const int samplerHint =
int(renderableImage->m_mapType);
1060 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
1061 if (samplerBinding >= 0) {
1062 QRhiTexture *texture = renderableImage->m_texture.m_texture;
1063 if (samplerBinding >= 0 && texture) {
1064 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
1065 QSSGRhiSamplerDescription samplerDesc = {
1066 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
1067 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
1068 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
1069 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
1070 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
1071 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
1073 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
1074 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
1075 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
1078 renderableImage = renderableImage->m_nextImage;
1081 if (shaderPipeline->isLightingEnabled()) {
1083 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
1084 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
1087 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1088 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
1089 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1092 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1093 QRhiSampler::Linear,
1095 QRhiSampler::ClampToEdge,
1096 QRhiSampler::ClampToEdge,
1097 QRhiSampler::Repeat });
1099 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1103 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
1104 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
1105 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
1107 QRhiTexture *texture = shadowMapBlueNoise;
1108 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1109 QRhiSampler::Linear,
1111 QRhiSampler::Repeat,
1112 QRhiSampler::Repeat,
1113 QRhiSampler::Repeat });
1114 Q_ASSERT(texture && sampler);
1115 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1118 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1119 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
1120 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1121 QRhiSampler::Linear,
1123 QRhiSampler::Repeat,
1124 QRhiSampler::Repeat,
1125 QRhiSampler::Repeat });
1126 Q_ASSERT(texture && sampler);
1127 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1128 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1135 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
1136 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
1137 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
1138 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
1139 ? QRhiSampler::Linear
1140 : QRhiSampler::None;
1141 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1142 QRhiSampler::Linear,
1144 QRhiSampler::ClampToEdge,
1145 QRhiSampler::ClampToEdge,
1146 QRhiSampler::Repeat });
1147 if (reflectionSampler >= 0 && reflectionTexture)
1148 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
1149 }
else if (shaderPipeline->lightProbeTexture()) {
1150 int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
1152 auto tiling = shaderPipeline->lightProbeTiling();
1153 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
1154 QSSGRhiHelpers::toRhi(tiling.first), QSSGRhiHelpers::toRhi(tiling.second), QRhiSampler::Repeat });
1155 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage,
1156 shaderPipeline->lightProbeTexture(), sampler);
1161 if (shaderPipeline->screenTexture()) {
1162 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
1163 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
1164 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
1165 QRhiTexture *screenTexture = shaderPipeline->screenTexture();
1167 if (screenMapPass) {
1168 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1170 const QRhiTexture::Flags flags = screenTexture->flags();
1172 screenTexture = rhiCtx->dummyTexture(flags, resourceUpdates);
1173 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1180 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
1181 ? QRhiSampler::Linear : QRhiSampler::None;
1182 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
1183 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
1184 if (screenTextureBinding >= 0) {
1185 bindings.addTexture(screenTextureBinding,
1186 QRhiShaderResourceBinding::FragmentStage,
1187 screenTexture, sampler);
1189 if (screenTextureArrayBinding >= 0) {
1190 bindings.addTexture(screenTextureArrayBinding,
1191 QRhiShaderResourceBinding::FragmentStage,
1192 screenTexture, sampler);
1197 if (shaderPipeline->lightmapTexture()) {
1198 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
1200 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1201 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
1202 bindings.addTexture(binding,
1203 QRhiShaderResourceBinding::FragmentStage,
1204 shaderPipeline->lightmapTexture(), sampler);
1210 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1213 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1215 if (oit && inData.layer.oitMethod == QSSGRenderLayer::OITMethod::LinkedList)
1225 QRhiShaderResourceBindings *&srb = dcd.srb;
1226 bool srbChanged =
false;
1227 if (!srb || bindings != dcd.bindings) {
1228 srb = rhiCtxD->srb(bindings);
1229 rhiCtxD->releaseCachedSrb(dcd.bindings);
1230 dcd.bindings = bindings;
1234 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1235 subsetRenderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
1237 subsetRenderable.rhiRenderData.mainPass.srb = srb;
1239 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
1242 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
1243 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
1246 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1247 subsetRenderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
1249 subsetRenderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
1251 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1252 subsetRenderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1253 renderPassDescriptor,
1255 dcd.pipeline = subsetRenderable.rhiRenderData.reflectionPass.pipeline;
1257 subsetRenderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1258 renderPassDescriptor,
1260 dcd.pipeline = subsetRenderable.rhiRenderData.mainPass.pipeline;
1262 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
1263 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;
1269 case QSSGRenderableObject::Type::CustomMaterialMeshSubset:
1271 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
1272 const QSSGRenderCustomMaterial &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
1273 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
1275 featureSet.set(QSSGShaderFeatures::Feature::LightProbe, inData.layer.lightProbe || material.m_iblProbe);
1277 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
1278 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
1280 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1282 featureSet.disableTonemapping();
1285 if (subsetRenderable.renderableFlags.rendersWithLightmap())
1286 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
1288 customMaterialSystem.rhiPrepareRenderable(ps, passKey, subsetRenderable, featureSet,
1289 material, inData, renderPassDescriptor, samples, viewCount, screenMapPass,
1290 alteredCamera, cubeFace, alteredModelViewProjection, entry, oit);
1293 case QSSGRenderableObject::Type::Particles:
1296 const auto &shaderPipeline = shadersForParticleMaterial(ps, particleRenderable, featureSet);
1297 if (shaderPipeline) {
1298 QSSGParticleRenderer::rhiPrepareRenderable(*shaderPipeline, passKey, rhiCtx, ps, particleRenderable, inData, renderPassDescriptor, samples, viewCount,
1299 alteredCamera, cubeFace, entry, oit);
1345 const QSSGRhiGraphicsPipelineState &state,
1347 bool *needsSetViewport,
1348 QSSGRenderTextureCubeFace cubeFace,
1349 qsizetype userPassIndex)
1351 switch (object.type) {
1352 case QSSGRenderableObject::Type::DefaultMaterialMeshSubset:
1354 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(object));
1356 QSSG_ASSERT(QSSGUserRenderPassManager::maxUserPassSlots() == std::size(subsetRenderable.rhiRenderData.userPassData),
return);
1358 QRhiGraphicsPipeline *ps = (userPassIndex >= 0 && size_t(userPassIndex) < QSSGUserRenderPassManager::maxUserPassSlots())
1359 ? subsetRenderable.rhiRenderData.userPassData[userPassIndex].pipeline : subsetRenderable.rhiRenderData.mainPass.pipeline;
1360 QRhiShaderResourceBindings *srb = (userPassIndex >= 0 && size_t(userPassIndex) < QSSGUserRenderPassManager::maxUserPassSlots())
1361 ? subsetRenderable.rhiRenderData.userPassData[userPassIndex].srb : subsetRenderable.rhiRenderData.mainPass.srb;
1363 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1364 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
1365 ps = subsetRenderable.rhiRenderData.reflectionPass.pipeline;
1366 srb = subsetRenderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx];
1372 QRhiBuffer *vertexBuffer = subsetRenderable.subset.rhi.vertexBuffer->buffer();
1373 QRhiBuffer *indexBuffer = subsetRenderable.subset.rhi.indexBuffer ? subsetRenderable.subset.rhi.indexBuffer->buffer() :
nullptr;
1375 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1377 cb->setGraphicsPipeline(ps);
1378 cb->setShaderResources(srb);
1380 if (*needsSetViewport) {
1381 cb->setViewport(state.viewport);
1382 if (state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor))
1383 cb->setScissor(state.scissor);
1384 *needsSetViewport =
false;
1387 QRhiCommandBuffer::VertexInput vertexBuffers[2];
1388 int vertexBufferCount = 1;
1389 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
1390 quint32 instances = 1;
1391 if ( subsetRenderable.modelContext.model.instancing()) {
1392 instances = subsetRenderable.modelContext.model.instanceCount();
1399 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(subsetRenderable.instanceBuffer, 0);
1400 vertexBufferCount = 2;
1402 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
1403 if (state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef))
1404 cb->setStencilRef(state.stencilRef);
1406 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, subsetRenderable.subset.rhi.indexBuffer->indexFormat());
1407 cb->drawIndexed(subsetRenderable.subset.lodCount(subsetRenderable.subsetLevelOfDetail), instances, subsetRenderable.subset.lodOffset(subsetRenderable.subsetLevelOfDetail));
1408 QSSGRHICTX_STAT(rhiCtx, drawIndexed(subsetRenderable.subset.lodCount(subsetRenderable.subsetLevelOfDetail), instances));
1410 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
1411 cb->draw(subsetRenderable.subset.count, instances, subsetRenderable.subset.offset);
1412 QSSGRHICTX_STAT(rhiCtx, draw(subsetRenderable.subset.count, instances));
1414 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (subsetRenderable.subset.count | quint64(instances) << 32),
1415 QVector<
int>({subsetRenderable.modelContext.model.profilingId,
1416 subsetRenderable.material.profilingId}));
1419 case QSSGRenderableObject::Type::CustomMaterialMeshSubset:
1421 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(object));
1422 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
1423 customMaterialSystem.rhiRenderRenderable(rhiCtx, subsetRenderable, needsSetViewport, cubeFace, state, userPassIndex);
1426 case QSSGRenderableObject::Type::Particles:
1429 QSSGParticleRenderer::rhiRenderRenderable(rhiCtx, renderable, needsSetViewport, cubeFace, state);
1454 QSSGPassKey passKey,
1455 QSSGRhiGraphicsPipelineState &ps,
1456 QSSGRenderShadowMap &shadowMapManager,
1457 const QSSGRenderCamera &camera,
1458 QSSGRenderCamera *debugCamera,
1460 const QSSGRenderableObjectList &sortedOpaqueObjects,
1462 const QSSGBounds3 &castingObjectsBox,
1463 const QSSGBounds3 &receivingObjectsBox)
1466 QSSGDebugDrawSystem *debugDrawSystem = renderer.contextInterface()->debugDrawSystem().get();
1467 const bool drawDirectionalLightShadowBoxes = layerData.layer.drawDirectionalLightShadowBoxes;
1468 const bool drawPointLightShadowBoxes = layerData.layer.drawPointLightShadowBoxes;
1469 const bool drawShadowCastingBounds = layerData.layer.drawShadowCastingBounds;
1470 const bool drawShadowReceivingBounds = layerData.layer.drawShadowReceivingBounds;
1471 const bool drawCascades = layerData.layer.drawCascades;
1472 const bool drawSceneCascadeIntersection = layerData.layer.drawSceneCascadeIntersection;
1473 const bool disableShadowCameraUpdate = layerData.layer.disableShadowCameraUpdate;
1474 const bool drawCulledObjects = layerData.layer.drawCulledObjects;
1475 QVector<
bool> debugIsObjectCulled = drawCulledObjects ? QVector<
bool>(sortedOpaqueObjects.size(),
true) : QVector<
bool>();
1477 static const auto rhiRenderOneShadowMap = [](QSSGRhiContext *rhiCtx,
1478 QSSGRhiGraphicsPipelineState *ps,
1479 const QSSGRenderableObjectList &sortedOpaqueObjects,
1481 const QSSGBounds3 cameraBounds,
1482 QVector<
bool> &debugIsObjectCulled,
1483 bool drawCulledObjects) {
1484 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1485 bool needsSetViewport =
true;
1487 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1492 if (theObject->globalBoundsInstancing.isFinite() && theObject->globalBounds.isFinite()) {
1493 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1494 : theObject->globalBounds;
1495 if (!globalBounds.isEmpty() && !cameraBounds.intersects(globalBounds)) {
1500 if (Q_UNLIKELY(drawCulledObjects))
1501 debugIsObjectCulled[i] =
false;
1504 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
1505 QSSGSubsetRenderable *renderable(
static_cast<QSSGSubsetRenderable *>(theObject));
1507 QRhiBuffer *vertexBuffer = renderable->subset.rhi.vertexBuffer->buffer();
1508 QRhiBuffer *indexBuffer = renderable->subset.rhi.indexBuffer
1509 ? renderable->subset.rhi.indexBuffer->buffer()
1513 if (!renderable->rhiRenderData.shadowPass.pipeline)
1516 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
1518 cb->setGraphicsPipeline(renderable->rhiRenderData.shadowPass.pipeline);
1520 QRhiShaderResourceBindings *srb = renderable->rhiRenderData.shadowPass.srb[cubeFace];
1521 cb->setShaderResources(srb);
1523 if (needsSetViewport) {
1524 cb->setViewport(ps->viewport);
1525 needsSetViewport =
false;
1528 QRhiCommandBuffer::VertexInput vertexBuffers[2];
1529 int vertexBufferCount = 1;
1530 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
1531 quint32 instances = 1;
1532 if (renderable->modelContext.model.instancing()) {
1533 instances = renderable->modelContext.model.instanceCount();
1534 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(renderable->instanceBuffer, 0);
1535 vertexBufferCount = 2;
1538 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, renderable->subset.rhi.indexBuffer->indexFormat());
1539 cb->drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances, renderable->subset.lodOffset(renderable->subsetLevelOfDetail));
1540 QSSGRHICTX_STAT(rhiCtx, drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances));
1542 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
1543 cb->draw(renderable->subset.count, instances, renderable->subset.offset);
1544 QSSGRHICTX_STAT(rhiCtx, draw(renderable->subset.count, instances));
1546 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (renderable->subset.count | quint64(instances) << 32),
1547 QVector<
int>({renderable->modelContext.model.profilingId,
1548 renderable->material.profilingId}));
1553 static const auto rhiClearShadowMap = [](
QSSGRenderer &renderer, QSSGRenderShadowMap &shadowMapManager, QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QRhiRenderPassDescriptor *renderPassDesc) {
1554 auto clearShadowMapShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiClearShadowMapShader();
1555 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, clearShadowMapShaderPipeline.get());
1558 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
false);
1559 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1560 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, shadowMapManager.shadowClearSrb(), renderPassDesc, {});
1562 ps->flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1565 QRhi *rhi = rhiCtx->rhi();
1566 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1570 QVector2D depthAdjust;
1571 if (rhi->isClipDepthZeroToOne()) {
1573 depthAdjust[0] = 0.0f;
1574 depthAdjust[1] = 1.0f;
1577 depthAdjust[0] = 1.0f;
1578 depthAdjust[1] = 0.5f;
1581 if (drawShadowCastingBounds)
1583 if (drawShadowReceivingBounds)
1587 const QSize atlasTextureSize = shadowMapManager.shadowMapAtlasTexture()->pixelSize();
1589 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
1590 for (
int i = 0, ie = globalLights.size(); i != ie; ++i) {
1591 if (!globalLights[i].shadows || globalLights[i].light->m_fullyBaked)
1598 const auto &light = globalLights[i].light;
1600 if (!shadowMapManager.shadowMapAtlasTexture())
1603 if (light->type == QSSGRenderLight::Type::DirectionalLight || light->type == QSSGRenderLight::Type::SpotLight) {
1604 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1608 if (!disableShadowCameraUpdate && debugCamera) {
1609 debugCamera->clipPlanes = camera.clipPlanes;
1610 debugCamera->projection = camera.projection;
1614 debugCamera->localTransform = layerData.getGlobalTransform(camera);
1617 QVarLengthArray<std::unique_ptr<QSSGRenderCamera>, 4> cascades;
1618 if (light->type == QSSGRenderLight::Type::DirectionalLight) {
1619 const float pcfRadius = light->m_softShadowQuality == QSSGRenderLight::SoftShadowQuality::Hard ? 0.f : light->m_pcfFactor;
1620 const float clipNear = camera.clipPlanes.clipNear();
1621 const float clipFar = qMin(light->m_shadowMapFar, camera.clipPlanes.clipFar());
1622 const float clipRange = clipFar - clipNear;
1623 cascades = setupCascadingCamerasForShadowMap(layerData,
1624 disableShadowCameraUpdate ? *debugCamera : camera,
1631 receivingObjectsBox,
1632 light->m_lockShadowmapTexels,
1635 drawSceneCascadeIntersection);
1638 pEntry->m_csmSplits[0] = clipNear + clipRange * (light->m_csmNumSplits > 0 ? light->m_csmSplit1 : 1.0f);
1639 pEntry->m_csmSplits[1] = clipNear + clipRange * (light->m_csmNumSplits > 1 ? light->m_csmSplit2 : 1.0f);
1640 pEntry->m_csmSplits[2] = clipNear + clipRange * (light->m_csmNumSplits > 2 ? light->m_csmSplit3 : 1.0f);
1641 pEntry->m_csmSplits[3] = clipNear + clipRange * 1.0f;
1642 pEntry->m_shadowMapFar = clipFar;
1643 }
else if (light->type == QSSGRenderLight::Type::SpotLight) {
1644 auto spotlightCamera =
std::make_unique<QSSGRenderCamera>(QSSGRenderCamera::Type::PerspectiveCamera);
1645 spotlightCamera->fov = QSSGRenderCamera::FieldOfView::fromDegrees(light->m_coneAngle * 2.0f);
1646 spotlightCamera->clipPlanes = { 1.0f, light->m_shadowMapFar };
1647 const QMatrix4x4 lightGlobalTransform = layerData.getGlobalTransform(*light);
1648 const QVector3D lightDir = QSSGRenderNode::getDirection(lightGlobalTransform);
1649 const QVector3D lightPos = QSSGRenderNode::getGlobalPos(lightGlobalTransform) - lightDir * spotlightCamera->clipPlanes.clipNear();
1650 const QVector3D lightPivot = light->pivot;
1651 const QVector3D forward = lightDir.normalized();
1652 const QVector3D right = qFuzzyCompare(qAbs(forward.y()), 1.0f)
1653 ? QVector3D::crossProduct(forward, QVector3D(1, 0, 0)).normalized()
1654 : QVector3D::crossProduct(forward, QVector3D(0, 1, 0)).normalized();
1655 const QVector3D up = QVector3D::crossProduct(right, forward).normalized();
1656 spotlightCamera->localTransform = QSSGRenderNode::calculateTransformMatrix(lightPos,
1657 QSSGRenderNode::initScale,
1659 QQuaternion::fromDirection(forward, up));
1660 QRectF theViewport(0.0f, 0.0f, (
float)light->m_shadowMapRes, (
float)light->m_shadowMapRes);
1661 QSSGRenderCamera::calculateProjectionInternal(*spotlightCamera, theViewport);
1662 cascades.push_back(
std::move(spotlightCamera));
1663 pEntry->m_shadowMapFar = light->m_shadowMapFar;
1668 memset(pEntry->m_csmActive, 0,
sizeof(pEntry->m_csmActive));
1670 QMatrix4x4 cascadeCameraGlobalTransforms(Qt::Uninitialized);
1671 const QMatrix4x4 bias = { 0.5, 0.0, 0.0, 0.5,
1674 0.0, 0.0, 0.0, 1.0 };
1676 for (
int cascadeIndex = 0; cascadeIndex < cascades.length(); cascadeIndex++) {
1677 const auto &cascadeCamera = cascades[cascadeIndex];
1681 cascadeCameraGlobalTransforms = layerData.getGlobalTransform(*cascadeCamera);
1682 pEntry->m_csmActive[cascadeIndex] = 1.f;
1683 QMatrix4x4 &viewProjection = pEntry->m_lightViewProjection[cascadeIndex];
1684 cascadeCamera->calculateViewProjectionMatrix(cascadeCameraGlobalTransforms, viewProjection);
1685 pEntry->m_lightViewProjection[cascadeIndex] = viewProjection;
1686 pEntry->m_fixedScaleBiasMatrix[cascadeIndex] = bias * viewProjection;
1687 const QMatrix4x4 inverted = viewProjection.inverted();
1688 const float x = 0.5f / (inverted * QVector4D(1, 0, 0, 0)).length();
1689 const float y = 0.5f / (inverted * QVector4D(0, 1, 0, 0)).length();
1690 const float z = 0.5f / (inverted * QVector4D(0, 0, 1, 0)).length();
1691 const QSSGBoxPoints frustumPoints = computeFrustumBounds(viewProjection);
1692 const QSSGBounds3 bounds = QSSGBounds3(frustumPoints);
1693 pEntry->m_dimensionsInverted[cascadeIndex] = QVector4D(x, y, z, 0.0f);
1694 pEntry->m_lightView = cascadeCameraGlobalTransforms.inverted();
1695 const bool isOrtho = cascadeCamera->type == QSSGRenderGraphObject::Type::OrthographicCamera;
1696 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[cascadeIndex], rhi->isYUpInFramebuffer());
1697 rhiPrepareResourcesForShadowMap(rhiCtx, layerData, passKey, pEntry, &ps, &depthAdjust, sortedOpaqueObjects, *cascadeCamera, isOrtho, QSSGRenderTextureCubeFaceNone, cascadeIndex);
1700 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[cascadeIndex];
1701 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1702 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1703 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1704 rhiClearShadowMap(renderer, shadowMapManager, rhiCtx, &ps, rt->renderPassDescriptor());
1705 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, 0, bounds, debugIsObjectCulled, drawCulledObjects);
1707 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1709 if (drawDirectionalLightShadowBoxes) {
1713 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"shadow_map"));
1715 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1716 ps.viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1718 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1719 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1720 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1721 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1722 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1723 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1724 const float shadowMapFar = qMax<
float>(2.0f, light->m_shadowMapFar);
1725 setupCubeShadowCameras(layerData, light, shadowMapFar, theCameras);
1726 pEntry->m_lightView = QMatrix4x4();
1727 pEntry->m_shadowMapFar = shadowMapFar;
1729 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1730 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1731 for (
const auto face : QSSGRenderTextureCubeFaces) {
1732 cameraGlobalTransform = layerData.getGlobalTransform(theCameras[quint8(face)]);
1733 theCameras[quint8(face)].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_lightViewProjection[0]);
1734 pEntry->m_lightCubeView[quint8(face)] = cameraGlobalTransform.inverted();
1736 rhiPrepareResourcesForShadowMap(rhiCtx,
1742 sortedOpaqueObjects,
1743 theCameras[quint8(face)],
1750 const QVector3D center = QSSGRenderNode::getGlobalPos(layerData.getGlobalTransform(*light));
1751 const QSSGBounds3 bounds = QSSGBounds3(center - QVector3D(shadowMapFar, shadowMapFar, shadowMapFar),
1752 center + QVector3D(shadowMapFar, shadowMapFar, shadowMapFar));
1754 for (
const auto face : QSSGRenderTextureCubeFaces) {
1758 QSSGRenderTextureCubeFace outFace = face;
1776 if (outFace == QSSGRenderTextureCubeFace::PosY)
1777 outFace = QSSGRenderTextureCubeFace::NegY;
1778 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1779 outFace = QSSGRenderTextureCubeFace::PosY;
1781 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargetCube[quint8(outFace)];
1782 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1783 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1784 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1785 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, quint8(face), bounds, debugIsObjectCulled, drawCulledObjects);
1787 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1788 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_cube", 0, outFace));
1795 QRhiTextureRenderTarget *rtFront = pEntry->m_rhiRenderTargets[0];
1796 QRhiRenderPassDescriptor *frontDesc = pEntry->m_rhiRenderPassDesc[0];
1797 auto atlasShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiCubeMapToAtlasShader();
1798 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[0], rhi->isYUpInFramebuffer());
1799 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, atlasShaderPipeline.get());
1800 QRhiShaderResourceBindings *srb = pEntry->m_cubeToAtlasFrontSrb;
1801 cb->beginPass(rtFront, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1802 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtFront));
1803 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1805 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, frontDesc, QSSGRhiQuadRenderer::UvCoords);
1808 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1809 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 6, 0));
1812 QRhiTextureRenderTarget *rtBack = pEntry->m_rhiRenderTargets[1];
1813 QRhiRenderPassDescriptor *backDesc = pEntry->m_rhiRenderPassDesc[1];
1814 srb = pEntry->m_cubeToAtlasBackSrb;
1815 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[1], rhi->isYUpInFramebuffer());
1816 cb->beginPass(rtBack, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1817 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtBack));
1818 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1820 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, backDesc, QSSGRhiQuadRenderer::UvCoords);
1823 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1824 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 7, 0));
1828 ps = layerData.getPipelineState();
1829 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1831 ps.slopeScaledDepthBias = 1.5f;
1833 if (drawPointLightShadowBoxes) {
1839 if (Q_UNLIKELY(drawCulledObjects)) {
1840 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1842 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1843 : theObject->globalBounds;
1844 const QColor color = debugIsObjectCulled[i] ? QColorConstants::Red : QColorConstants::Green;
1851 QSSGPassKey passKey,
1853 QSSGRhiGraphicsPipelineState *ps,
1854 QSSGRenderReflectionMap &reflectionMapManager,
1855 const QVector<QSSGRenderReflectionProbe *> &reflectionProbes,
1856 const QSSGRenderableObjectList &reflectionPassObjects,
1859 QRhi *rhi = rhiCtx->rhi();
1860 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1862 const bool renderSkybox = (inData.layer.background == QSSGRenderLayer::Background::SkyBox ||
1863 inData.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap)
1864 && rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch);
1866 for (
int i = 0, ie = reflectionProbes.size(); i != ie; ++i) {
1871 if (!pEntry->m_needsRender)
1874 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame && pEntry->m_rendered)
1877 if (reflectionProbes[i]->texture)
1880 Q_ASSERT(pEntry->m_rhiDepthStencil);
1881 Q_ASSERT(pEntry->m_rhiCube);
1883 const QSize size = pEntry->m_rhiCube->pixelSize();
1884 ps->viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1886 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1887 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1888 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1889 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1890 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1891 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1892 setupCubeReflectionCameras(inData, reflectionProbes[i], theCameras);
1893 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1894 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1895 for (
const auto face : QSSGRenderTextureCubeFaces) {
1896 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(face);
1897 cameraGlobalTransform = inData.getGlobalTransform(theCameras[cubeFaceIdx]);
1898 theCameras[cubeFaceIdx].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_viewProjection);
1900 rhiPrepareResourcesForReflectionMap(rhiCtx, passKey, inData, pEntry, ps,
1901 reflectionPassObjects, theCameras[cubeFaceIdx], renderer, face);
1903 QRhiRenderPassDescriptor *renderPassDesc =
nullptr;
1904 for (
auto face : QSSGRenderTextureCubeFaces) {
1905 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1906 face = pEntry->m_timeSliceFace;
1908 QSSGRenderTextureCubeFace outFace = face;
1912 if (outFace == QSSGRenderTextureCubeFace::PosY)
1913 outFace = QSSGRenderTextureCubeFace::NegY;
1914 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1915 outFace = QSSGRenderTextureCubeFace::PosY;
1917 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[quint8(outFace)];
1918 cb->beginPass(rt, reflectionProbes[i]->clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1919 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1920 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1922 if (renderSkybox && pEntry->m_skyBoxSrbs[quint8(face)]) {
1923 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1924 const bool isSkyBox = inData.layer.background == QSSGRenderLayer::Background::SkyBox;
1925 const auto &shaderPipeline = isSkyBox ? shaderCache->getBuiltInRhiShaders().getRhiSkyBoxShader(QSSGRenderLayer::TonemapMode::None, inData.layer.skyBoxIsRgbe8, 1)
1926 : shaderCache->getBuiltInRhiShaders().getRhiSkyBoxCubeShader(QSSGRenderLayer::TonemapMode::None, !inData.layer.skyBoxIsSrgb, 1);
1927 Q_ASSERT(shaderPipeline);
1928 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
1929 QRhiShaderResourceBindings *srb = pEntry->m_skyBoxSrbs[quint8(face)];
1930 if (!renderPassDesc)
1931 renderPassDesc = rt->newCompatibleRenderPassDescriptor();
1932 rt->setRenderPassDescriptor(renderPassDesc);
1933 isSkyBox ? renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, srb, renderPassDesc, {})
1934 : renderer.rhiCubeRenderer()->recordRenderCube(rhiCtx, ps, srb, renderPassDesc, {});
1937 bool needsSetViewport =
true;
1938 for (
const auto &handle : reflectionPassObjects)
1939 rhiRenderRenderable(rhiCtx, *ps, *handle.obj, &needsSetViewport, face);
1942 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1943 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"reflection_cube", 0, outFace));
1945 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1949 renderPassDesc->deleteLater();
1951 pEntry->renderMips(rhiCtx);
1953 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1954 pEntry->m_timeSliceFace = QSSGBaseTypeHelpers::next(pEntry->m_timeSliceFace);
1956 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame)
1957 pEntry->m_rendered =
true;
1959 reflectionProbes[i]->hasScheduledUpdate =
false;
1960 pEntry->m_needsRender =
false;
2011 QSSGPassKey passKey,
2013 QSSGRhiShaderPipeline &shaderPipeline,
2014 QSSGRhiGraphicsPipelineState &ps,
2015 const QSSGAmbientOcclusionSettings &ao,
2016 const QSSGRhiRenderableTexture &rhiAoTexture,
2017 const QSSGRhiRenderableTexture &rhiDepthTexture,
2018 const QSSGRenderCamera &camera)
2020 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2023 if (!rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2024 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
2026 cb->beginPass(rhiAoTexture.rt, Qt::white, { 1.0f, 0 });
2027 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rhiAoTexture.rt));
2029 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
2033 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, &shaderPipeline);
2035 const float R2 = ao.aoDistance * ao.aoDistance * 0.16f;
2036 const QSize textureSize = rhiAoTexture.texture->pixelSize();
2037 const float rw =
float(textureSize.width());
2038 const float rh =
float(textureSize.height());
2039 const float fov = camera.fov.asVerticalFov(rw / rh).radians();
2040 const float tanHalfFovY = tanf(0.5f * fov * (rh / rw));
2041 const float invFocalLenX = tanHalfFovY * (rw / rh);
2043 const QVector4D aoProps(ao.aoStrength * 0.01f, ao.aoDistance * 0.4f, ao.aoSoftness * 0.02f, ao.aoBias);
2044 const QVector4D aoProps2(
float(ao.aoSamplerate), (ao.aoDither) ? 1.0f : 0.0f, 0.0f, 0.0f);
2045 const QVector4D aoScreenConst(1.0f / R2, rh / (2.0f * tanHalfFovY), 1.0f / rw, 1.0f / rh);
2046 const QVector4D uvToEyeConst(2.0f * invFocalLenX, -2.0f * tanHalfFovY, -invFocalLenX, tanHalfFovY);
2047 const QVector2D cameraProps = camera.clipPlanes;
2056 const int UBUF_SIZE = 72;
2057 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ passKey,
nullptr,
nullptr, 0 }));
2059 dcd.ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE);
2063 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2064 memcpy(ubufData, &aoProps, 16);
2065 memcpy(ubufData + 16, &aoProps2, 16);
2066 memcpy(ubufData + 32, &aoScreenConst, 16);
2067 memcpy(ubufData + 48, &uvToEyeConst, 16);
2068 memcpy(ubufData + 64, &cameraProps, 8);
2069 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2071 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2072 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
2073 QSSGRhiShaderResourceBindingList bindings;
2074 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
2077 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiDepthTexture.texture, sampler);
2078 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2080 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
2081 renderer.rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, rhiAoTexture.rt, {});
2229 QSSGPassKey passKey,
2230 QSSGRenderLayer &layer,
2231 QSSGRenderCameraList &cameras,
2235 uint tonemapMode = 0)
2237 QSSG_ASSERT(layer.renderData,
return);
2239 const auto *renderData = layer.renderData;
2241 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2242 const bool cubeMapMode = layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap;
2243 const QSSGRenderImageTexture lightProbeTexture =
2244 cubeMapMode ? renderer.contextInterface()->bufferManager()->loadRenderImage(layer.skyBoxCubeMap, QSSGBufferManager::MipModeDisable)
2245 : renderer.contextInterface()->bufferManager()->loadRenderImage(layer.lightProbe, QSSGBufferManager::MipModeBsdf);
2246 const bool hasValidTexture = lightProbeTexture.m_texture !=
nullptr;
2247 if (hasValidTexture) {
2248 if (cubeFace == QSSGRenderTextureCubeFaceNone)
2249 layer.skyBoxIsRgbe8 = lightProbeTexture.m_flags.isRgbe8();
2251 layer.skyBoxIsSrgb = !lightProbeTexture.m_flags.isLinear();
2253 QSSGRhiShaderResourceBindingList bindings;
2255 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
2256 QRhiSampler::Linear,
2257 cubeMapMode ? QRhiSampler::None : QRhiSampler::Linear,
2258 QRhiSampler::Repeat,
2259 QRhiSampler::ClampToEdge,
2260 QRhiSampler::Repeat });
2261 int samplerBinding = 1;
2262 const quint32 ubufSize = cameras.count() >= 2 ? 416 : 240;
2263 bindings.addTexture(samplerBinding,
2264 QRhiShaderResourceBinding::FragmentStage,
2265 lightProbeTexture.m_texture, sampler);
2267 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2268 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * cubeFaceIdx;
2269 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey,
nullptr, entry, entryIdx });
2271 QRhi *rhi = rhiCtx->rhi();
2273 dcd.ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
2277 float adjustY = rhi->isYUpInNDC() ? 1.0f : -1.0f;
2278 const float exposure = layer.lightProbeSettings.probeExposure;
2280 const QMatrix3x3 &rotationMatrix(layer.lightProbeSettings.probeOrientation);
2283 const float blurAmountOrSrgb = cubeMapMode ? layer.skyBoxIsSrgb : layer.skyboxBlurAmount;
2284 const float maxMipLevelOrTonemapMode = cubeMapMode ?
float(tonemapMode) :
float(lightProbeTexture.m_mipmapCount - 2);
2286 const QVector4D skyboxProperties = {
2290 maxMipLevelOrTonemapMode
2293 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2294 quint32 ubufOffset = 0;
2296 memcpy(ubufData + ubufOffset, &skyboxProperties, 16);
2299 memcpy(ubufData + ubufOffset, rotationMatrix.constData(), 12);
2301 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 12, 12);
2303 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 24, 12);
2306 for (qsizetype viewIdx = 0; viewIdx < cameras.count(); ++viewIdx) {
2307 const QMatrix4x4 &inverseProjection = cameras[viewIdx]->projection.inverted();
2308 const QMatrix4x4 &viewMatrix = renderData->getGlobalTransform(*cameras[viewIdx]);
2309 QMatrix4x4 viewProjection(Qt::Uninitialized);
2310 cameras[viewIdx]->calculateViewProjectionWithoutTranslation(viewMatrix, 0.1f, 5.0f, viewProjection);
2312 quint32 viewDataOffset = ubufOffset;
2313 memcpy(ubufData + viewDataOffset + viewIdx * 64, viewProjection.constData(), 64);
2314 viewDataOffset += cameras.count() * 64;
2315 memcpy(ubufData + viewDataOffset + viewIdx * 64, inverseProjection.constData(), 64);
2316 viewDataOffset += cameras.count() * 64;
2317 memcpy(ubufData + viewDataOffset + viewIdx * 48, viewMatrix.constData(), 48);
2319 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2321 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
2323 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
2324 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2325 entry->m_skyBoxSrbs[cubeFaceIdx] = rhiCtxD->srb(bindings);
2327 layer.skyBoxSrb = rhiCtxD->srb(bindings);
2331 renderer.rhiCubeRenderer()->prepareCube(rhiCtx,
nullptr);
2333 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
2370 QSSGPassKey passKey,
2371 const QSSGRhiGraphicsPipelineState &basePipelineState,
2372 QRhiRenderPassDescriptor *rpDesc,
2374 const QSSGRenderableObjectList &sortedOpaqueObjects,
2375 const QSSGRenderableObjectList &sortedTransparentObjects,
2379 static const auto rhiPrepareDepthPassForObject = [](QSSGRhiContext *rhiCtx,
2380 QSSGPassKey passKey,
2383 QRhiRenderPassDescriptor *rpDesc,
2384 QSSGRhiGraphicsPipelineState *ps) {
2385 QSSGRhiShaderPipelinePtr shaderPipeline;
2386 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2388 const bool isOpaqueDepthPrePass = obj->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
2389 QSSGShaderFeatures featureSet;
2390 featureSet.set(QSSGShaderFeatures::Feature::DepthPass,
true);
2391 if (isOpaqueDepthPrePass)
2392 featureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
2394 QSSGRhiDrawCallData *dcd =
nullptr;
2395 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2396 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2397 const void *modelNode = &subsetRenderable.modelContext.model;
2398 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
2401 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2402 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2403 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2404 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2406 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
2407 if (shaderPipeline) {
2408 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2409 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2410 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2411 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2415 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2416 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2418 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2420 ps->cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2422 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
2423 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2425 if (shaderPipeline) {
2426 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2427 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2428 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, customMaterial, subsetRenderable,
2429 inData.renderedCameras,
nullptr,
nullptr);
2430 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2437 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2438 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2439 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
2440 ia = subsetRenderable.subset.rhi.ia;
2442 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2443 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2444 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2446 QSSGRhiShaderResourceBindingList bindings;
2447 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2450 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2452 if (isOpaqueDepthPrePass) {
2453 addOpaqueDepthPrePassBindings(rhiCtx,
2454 shaderPipeline.get(),
2455 subsetRenderable.firstImage,
2457 (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
2463 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2464 if (normalTextureBinding >= 0) {
2465 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2466 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2467 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2468 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2469 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2470 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2474 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2475 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2477 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2478 QRhiSampler::Nearest,
2480 QRhiSampler::ClampToEdge,
2481 QRhiSampler::ClampToEdge,
2484 bindings.addTexture(binding,
2485 QRhiShaderResourceBinding::VertexStage,
2492 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2493 if (targetsTexture) {
2494 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2496 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2497 QRhiSampler::Nearest,
2499 QRhiSampler::ClampToEdge,
2500 QRhiSampler::ClampToEdge,
2501 QRhiSampler::ClampToEdge
2503 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2507 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2509 subsetRenderable.rhiRenderData.depthPrePass.pipeline = rhiCtxD->pipeline(*ps,
2512 subsetRenderable.rhiRenderData.depthPrePass.srb = srb;
2523 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2528 ps.samples = samples;
2529 ps.viewCount = viewCount;
2530 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
2531 ps.targetBlend[0].colorWrite = {};
2533 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2534 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2538 for (
const QSSGRenderableObjectHandle &handle : sortedTransparentObjects) {
2539 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2666 QSSGPassKey passKey,
2667 const QSSGRhiGraphicsPipelineState &basePipelineState,
2668 QRhiRenderPassDescriptor *rpDesc,
2670 const QSSGRenderableObjectList &sortedOpaqueObjects)
2672 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2673 ps.depthFunc = QRhiGraphicsPipeline::LessOrEqual;
2674 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
2676 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2677 QSSGRenderableObject *obj = handle.obj;
2678 QSSGRhiShaderPipelinePtr shaderPipeline;
2679 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2681 QSSGShaderFeatures featureSet;
2682 featureSet.set(QSSGShaderFeatures::Feature::NormalPass,
true);
2684 QSSGRhiDrawCallData *dcd =
nullptr;
2685 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2686 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2687 const void *modelNode = &subsetRenderable.modelContext.model;
2688 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
2691 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2692 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2693 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2694 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2696 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
2697 if (shaderPipeline) {
2698 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2699 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2700 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2701 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2703 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2704 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2706 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2708 ps.cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2710 const auto &customMaterialSystem = subsetRenderable.renderer->contextInterface()->customMaterialSystem();
2711 shaderPipeline = customMaterialSystem->shadersForCustomMaterial(&ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2713 if (shaderPipeline) {
2714 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2715 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2716 customMaterialSystem->updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, customMaterial, subsetRenderable,
2717 inData.renderedCameras,
nullptr,
nullptr);
2718 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2723 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2724 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2725 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
2726 ia = subsetRenderable.subset.rhi.ia;
2728 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2729 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2730 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2732 QSSGRhiShaderResourceBindingList bindings;
2733 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2736 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
2737 while (renderableImage) {
2738 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
2739 const int samplerHint =
int(renderableImage->m_mapType);
2740 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
2741 if (samplerBinding >= 0) {
2742 QRhiTexture *texture = renderableImage->m_texture.m_texture;
2743 if (samplerBinding >= 0 && texture) {
2744 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
2745 QSSGRhiSamplerDescription samplerDesc = {
2746 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
2747 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
2748 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
2749 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
2750 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
2751 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
2753 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
2754 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
2755 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
2758 renderableImage = renderableImage->m_nextImage;
2761 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2764 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2765 if (normalTextureBinding >= 0) {
2766 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2767 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2768 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2769 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2770 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2771 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2777 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2778 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2780 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2781 QRhiSampler::Nearest,
2783 QRhiSampler::ClampToEdge,
2784 QRhiSampler::ClampToEdge,
2787 bindings.addTexture(binding,
2788 QRhiShaderResourceBinding::VertexStage,
2795 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2796 if (targetsTexture) {
2797 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2799 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2800 QRhiSampler::Nearest,
2802 QRhiSampler::ClampToEdge,
2803 QRhiSampler::ClampToEdge,
2804 QRhiSampler::ClampToEdge
2806 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2810 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2812 subsetRenderable.rhiRenderData.normalPass.pipeline = rhiCtxD->pipeline(ps,
2815 subsetRenderable.rhiRenderData.normalPass.srb = srb;
2884 QSSGPassKey passKey,
2885 const QSSGRhiGraphicsPipelineState &basePipelineState,
2886 QRhiRenderPassDescriptor *rpDesc,
2887 QSSGRenderGraphObject *overrideMaterial,
2889 QSSGRenderableObjectList &inObjects,
2890 QSSGShaderFeatures featureSet)
2893 const qsizetype index = overrideMaterial ? inData.getUserRenderPassManager()->acquireUserPassSlot() : -1;
2898 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2899 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2901 const bool isCustomMaterial = (overrideMaterial->type == QSSGRenderGraphObject::Type::CustomMaterial);
2902 const bool isDefaultMaterial = (overrideMaterial->type == QSSGRenderGraphObject::Type::DefaultMaterial ||
2903 overrideMaterial->type == QSSGRenderGraphObject::Type::PrincipledMaterial ||
2904 overrideMaterial->type == QSSGRenderGraphObject::Type::SpecularGlossyMaterial);
2906 if (!isCustomMaterial && !isDefaultMaterial) {
2907 qDebug() <<
"Override material must be a default or custom material.";
2911 for (
const QSSGRenderableObjectHandle &handle : inObjects) {
2912 QSSGRenderableObject *obj = handle.obj;
2914 if (obj->type != QSSGRenderableObject::Type::DefaultMaterialMeshSubset &&
2915 obj->type != QSSGRenderableObject::Type::CustomMaterialMeshSubset)
2918 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2919 const void *modelNode = &subsetRenderable.modelContext.model;
2920 QSSGRhiDrawCallData *dcd = &rhiCtxD->drawCallData({ passKey, modelNode, overrideMaterial, 0 });
2926 QSSGRenderableObjectFlags renderableFlags = subsetRenderable.renderableFlags;
2927 float opacity = subsetRenderable.opacity;
2930 const bool hasAnyLights = !subsetRenderable.lights.isEmpty();
2931 const bool anyLightHasShadows = std::any_of(subsetRenderable.lights.begin(),
2932 subsetRenderable.lights.end(),
2933 [](
const QSSGShaderLight &light) {
return light.shadows; });
2937 auto layerPrepFlags = inData.layerPrepResult.getFlags();
2939 if (isCustomMaterial) {
2940 auto &material =
static_cast<QSSGRenderCustomMaterial &>(*overrideMaterial);
2941 auto prepResult = inData.prepareCustomMaterialForRender(material, renderableFlags, opacity,
2942 false, hasAnyLights, anyLightHasShadows,
2944 subsetRenderable.shaderDescription = prepResult.materialKey;
2946 auto &material =
static_cast<QSSGRenderDefaultMaterial &>(*overrideMaterial);
2947 auto prepResult = inData.prepareDefaultMaterialForRender(material, renderableFlags, opacity,
2948 hasAnyLights, anyLightHasShadows,
2950 subsetRenderable.shaderDescription = prepResult.materialKey;
2954 QSSGRhiShaderPipelinePtr shaderPipeline;
2956 if (isCustomMaterial) {
2957 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(*overrideMaterial);
2958 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
2960 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
2961 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable,
2962 inData.getDefaultMaterialPropertyTable(), featureSet);
2963 if (shaderPipeline) {
2964 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2965 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2966 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
2967 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2968 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2971 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(*overrideMaterial);
2972 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2974 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
2975 if (shaderPipeline) {
2976 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2977 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2978 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable,
2979 inData.renderedCameras,
nullptr,
nullptr, overrideMaterial);
2980 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2984 if (!shaderPipeline)
2987 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
2988 ia = subsetRenderable.subset.rhi.ia;
2990 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2991 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2992 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2994 QSSGRhiShaderResourceBindingList bindings;
2995 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2998 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
2999 while (renderableImage) {
3000 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3001 const int samplerHint =
int(renderableImage->m_mapType);
3002 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3003 if (samplerBinding >= 0) {
3004 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3006 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3007 QSSGRhiSamplerDescription samplerDesc = {
3008 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3009 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3010 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3011 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3012 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3013 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3015 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3016 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3017 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3020 renderableImage = renderableImage->m_nextImage;
3023 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3026 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3027 if (normalTextureBinding >= 0) {
3028 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3029 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3030 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3031 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3032 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3033 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3037 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3038 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3040 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3041 QRhiSampler::Nearest,
3043 QRhiSampler::ClampToEdge,
3044 QRhiSampler::ClampToEdge,
3047 bindings.addTexture(binding,
3048 QRhiShaderResourceBinding::VertexStage,
3055 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3056 if (targetsTexture) {
3057 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3059 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3060 QRhiSampler::Nearest,
3062 QRhiSampler::ClampToEdge,
3063 QRhiSampler::ClampToEdge,
3064 QRhiSampler::ClampToEdge
3066 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3071 if (shaderPipeline->isLightingEnabled()) {
3072 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3073 shaderPipeline->ub0LightDataOffset(),
3074 sizeof(QSSGShaderLightsUniformData));
3075 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3076 shaderPipeline->ub0DirectionalLightDataOffset(),
3077 sizeof(QSSGShaderDirectionalLightsUniformData));
3080 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3081 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3084 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3085 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
3086 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3089 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3090 QRhiSampler::Linear,
3092 QRhiSampler::ClampToEdge,
3093 QRhiSampler::ClampToEdge,
3094 QRhiSampler::Repeat });
3096 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3100 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3101 QRhiTexture *texture = shaderPipeline->shadowMapBlueNoiseTexture();
3104 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3105 texture = rhiCtx->dummyTexture({ }, resourceUpdates);
3106 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3109 QRhiSampler *sampler = rhiCtx->sampler(
3110 { QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3112 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3116 if (shaderPipeline->lightProbeTexture()) {
3117 int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3119 auto tiling = shaderPipeline->lightProbeTiling();
3120 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
3121 QSSGRhiHelpers::toRhi(tiling.first), QSSGRhiHelpers::toRhi(tiling.second), QRhiSampler::Repeat });
3122 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage,
3123 shaderPipeline->lightProbeTexture(), sampler);
3128 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3130 QSSG_ASSERT(srb,
continue);
3131 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3132 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3133 rhiPassData.srb = srb;
3140 QSSGPassKey passKey,
3141 const QSSGRhiGraphicsPipelineState &basePipelineState,
3142 QRhiRenderPassDescriptor *rpDesc,
3144 QSSGRenderableObjectList &inObjects,
3145 QSSGShaderFeatures featureSet)
3147 const qsizetype index = inData.getUserRenderPassManager()->acquireUserPassSlot();
3152 QSSGRhiGraphicsPipelineState ps = basePipelineState;
3153 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3155 for (
const QSSGRenderableObjectHandle &handle : inObjects) {
3156 QSSGRenderableObject *obj = handle.obj;
3157 QSSGRhiShaderPipelinePtr shaderPipeline;
3159 QSSGRhiDrawCallData *dcd =
nullptr;
3160 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset ||
3161 obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3162 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3163 const void *modelNode = &subsetRenderable.modelContext.model;
3164 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
3167 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
3168 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3169 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
3170 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3172 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
3173 if (shaderPipeline) {
3174 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3175 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3176 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable,
3177 inData.renderedCameras,
nullptr,
nullptr);
3178 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3180 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3181 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3182 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
3183 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
3185 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
3186 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable,
3187 inData.getDefaultMaterialPropertyTable(), featureSet);
3188 if (shaderPipeline) {
3189 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3190 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3191 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3192 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3193 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3197 if (!shaderPipeline)
3201 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset ||
3202 obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3203 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
3204 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3205 ia = subsetRenderable.subset.rhi.ia;
3207 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3208 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3209 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3211 QSSGRhiShaderResourceBindingList bindings;
3212 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3215 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3216 while (renderableImage) {
3217 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3218 const int samplerHint =
int(renderableImage->m_mapType);
3219 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3220 if (samplerBinding >= 0) {
3221 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3222 if (samplerBinding >= 0 && texture) {
3223 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3224 QSSGRhiSamplerDescription samplerDesc = {
3225 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3226 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3227 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3228 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3229 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3230 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3232 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3233 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3234 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3237 renderableImage = renderableImage->m_nextImage;
3240 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3243 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3244 if (normalTextureBinding >= 0) {
3245 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3246 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3247 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3248 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3249 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3250 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3254 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3255 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3257 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3258 QRhiSampler::Nearest,
3260 QRhiSampler::ClampToEdge,
3261 QRhiSampler::ClampToEdge,
3264 bindings.addTexture(binding,
3265 QRhiShaderResourceBinding::VertexStage,
3272 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3273 if (targetsTexture) {
3274 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3276 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3277 QRhiSampler::Nearest,
3279 QRhiSampler::ClampToEdge,
3280 QRhiSampler::ClampToEdge,
3281 QRhiSampler::ClampToEdge
3283 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3288 if (shaderPipeline->isLightingEnabled()) {
3289 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3290 shaderPipeline->ub0LightDataOffset(),
3291 sizeof(QSSGShaderLightsUniformData));
3292 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3293 shaderPipeline->ub0DirectionalLightDataOffset(),
3294 sizeof(QSSGShaderDirectionalLightsUniformData));
3297 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3298 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3301 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3302 texture = rhiCtx->dummyTexture({ }, resourceUpdates);
3303 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3306 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3307 QRhiSampler::Linear,
3309 QRhiSampler::ClampToEdge,
3310 QRhiSampler::ClampToEdge,
3311 QRhiSampler::Repeat });
3313 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3317 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3318 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
3319 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
3321 QRhiTexture *texture = shadowMapBlueNoise;
3322 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3323 QRhiSampler::Linear,
3325 QRhiSampler::Repeat,
3326 QRhiSampler::Repeat,
3327 QRhiSampler::Repeat });
3328 Q_ASSERT(texture && sampler);
3329 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3332 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3333 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
3334 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3335 QRhiSampler::Linear,
3337 QRhiSampler::Repeat,
3338 QRhiSampler::Repeat,
3339 QRhiSampler::Repeat });
3340 Q_ASSERT(texture && sampler);
3341 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3342 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3347 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
3348 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
3349 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
3350 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
3351 ? QRhiSampler::Linear
3352 : QRhiSampler::None;
3353 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3354 QRhiSampler::Linear,
3356 QRhiSampler::ClampToEdge,
3357 QRhiSampler::ClampToEdge,
3358 QRhiSampler::Repeat });
3359 if (reflectionSampler >= 0 && reflectionTexture)
3360 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
3361 }
else if (shaderPipeline->lightProbeTexture()) {
3362 int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3364 auto tiling = shaderPipeline->lightProbeTiling();
3365 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
3366 QSSGRhiHelpers::toRhi(tiling.first), QSSGRhiHelpers::toRhi(tiling.second), QRhiSampler::Repeat });
3367 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage,
3368 shaderPipeline->lightProbeTexture(), sampler);
3373 if (shaderPipeline->screenTexture()) {
3374 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
3375 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
3376 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
3377 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
3378 ? QRhiSampler::Linear : QRhiSampler::None;
3379 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
3380 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3381 if (screenTextureBinding >= 0) {
3382 bindings.addTexture(screenTextureBinding,
3383 QRhiShaderResourceBinding::FragmentStage,
3384 shaderPipeline->screenTexture(), sampler);
3386 if (screenTextureArrayBinding >= 0) {
3387 bindings.addTexture(screenTextureArrayBinding,
3388 QRhiShaderResourceBinding::FragmentStage,
3389 shaderPipeline->screenTexture(), sampler);
3394 if (shaderPipeline->lightmapTexture()) {
3395 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
3397 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
3398 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
3399 bindings.addTexture(binding,
3400 QRhiShaderResourceBinding::FragmentStage,
3401 shaderPipeline->lightmapTexture(), sampler);
3408 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3409 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3411 int maxSamplerBinding = -1;
3412 QVector<QShaderDescription::InOutVariable> samplerVars =
3413 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
3414 for (
const QShaderDescription::InOutVariable &var : shaderPipeline->vertexStage()->shader().description().combinedImageSamplers()) {
3415 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
3416 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
3417 if (it == samplerVars.cend())
3418 samplerVars.append(var);
3421 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
3422 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
3424 if (maxSamplerBinding >= 0) {
3425 int extraTexCount = shaderPipeline->extraTextureCount();
3426 for (
int i = 0; i < extraTexCount; ++i) {
3427 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
3428 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
3429 if (samplerBinding >= 0) {
3430 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
3431 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
3432 bindings.addTexture(samplerBinding,
3433 QRhiShaderResourceBinding::FragmentStage,
3441 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3443 QSSG_ASSERT(srb,
continue);
3445 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3446 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3447 rhiPassData.srb = srb;
3456 QSSGPassKey passKey,
3457 const QSSGRhiGraphicsPipelineState &basePipelineState,
3458 QRhiRenderPassDescriptor *rpDesc,
3461 QSSGRenderableObjectList &inObjects,
3462 QSSGShaderFeatures featureSet)
3464 const qsizetype index = inData.getUserRenderPassManager()->acquireUserPassSlot();
3470 QSSGRhiGraphicsPipelineState ps = basePipelineState;
3471 for (
const QSSGRenderableObjectHandle &handle : inObjects) {
3472 QSSGRenderableObject *obj = handle.obj;
3473 QSSGRhiShaderPipelinePtr shaderPipeline;
3474 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3475 const auto &bufferManager = inData.contextInterface()->bufferManager();
3477 featureSet.set(QSSGShaderFeatures::Feature::UserRenderPass,
true);
3479 QSSGRhiDrawCallData *dcd =
nullptr;
3480 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3481 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3482 const void *modelNode = &subsetRenderable.modelContext.model;
3483 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
3486 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
3487 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3488 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
3489 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3491 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet, shaderAugmentation);
3492 if (shaderPipeline) {
3493 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3494 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3496 for (
const auto &u : shaderAugmentation.propertyUniforms)
3497 shaderPipeline->setShaderResources(ubufData, *bufferManager, u.name, u.value, u.shaderDataType);
3498 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3499 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3501 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3502 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3503 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
3504 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
3506 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
3508 if (material.m_shadingMode == QSSGRenderCustomMaterial::ShadingMode::Unshaded)
3509 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
3511 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet, shaderAugmentation);
3513 if (shaderPipeline) {
3514 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3515 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3517 for (
const auto &u : shaderAugmentation.propertyUniforms)
3518 shaderPipeline->setShaderResources(ubufData, *bufferManager, u.name, u.value, u.shaderDataType);
3519 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3520 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3521 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3525 if (!shaderPipeline) {
3527 qDebug() <<
"Failed to prepare user augmented pass for object.";
3532 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3533 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
3534 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3535 ia = subsetRenderable.subset.rhi.ia;
3537 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3538 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3539 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3541 QSSGRhiShaderResourceBindingList bindings;
3542 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3545 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3546 while (renderableImage) {
3547 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3548 const int samplerHint =
int(renderableImage->m_mapType);
3549 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3550 if (samplerBinding >= 0) {
3551 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3552 if (samplerBinding >= 0 && texture) {
3553 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3554 QSSGRhiSamplerDescription samplerDesc = {
3555 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3556 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3557 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3558 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3559 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3560 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3562 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3563 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3564 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3567 renderableImage = renderableImage->m_nextImage;
3570 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3573 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3574 if (normalTextureBinding >= 0) {
3575 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3576 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3577 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3578 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3579 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3580 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3586 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3587 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3589 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3590 QRhiSampler::Nearest,
3592 QRhiSampler::ClampToEdge,
3593 QRhiSampler::ClampToEdge,
3596 bindings.addTexture(binding,
3597 QRhiShaderResourceBinding::VertexStage,
3604 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3605 if (targetsTexture) {
3606 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3608 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3609 QRhiSampler::Nearest,
3611 QRhiSampler::ClampToEdge,
3612 QRhiSampler::ClampToEdge,
3613 QRhiSampler::ClampToEdge
3615 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3620 if (shaderPipeline->isLightingEnabled()) {
3621 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3622 shaderPipeline->ub0LightDataOffset(),
3623 sizeof(QSSGShaderLightsUniformData));
3624 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3625 shaderPipeline->ub0DirectionalLightDataOffset(),
3626 sizeof(QSSGShaderDirectionalLightsUniformData));
3629 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3630 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3633 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3634 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
3635 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3638 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3639 QRhiSampler::Linear,
3641 QRhiSampler::ClampToEdge,
3642 QRhiSampler::ClampToEdge,
3643 QRhiSampler::Repeat });
3645 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3649 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3650 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
3651 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
3653 QRhiTexture *texture = shadowMapBlueNoise;
3654 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3655 QRhiSampler::Linear,
3657 QRhiSampler::Repeat,
3658 QRhiSampler::Repeat,
3659 QRhiSampler::Repeat });
3660 Q_ASSERT(texture && sampler);
3661 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3664 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3665 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
3666 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3667 QRhiSampler::Linear,
3669 QRhiSampler::Repeat,
3670 QRhiSampler::Repeat,
3671 QRhiSampler::Repeat });
3672 Q_ASSERT(texture && sampler);
3673 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3674 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3681 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
3682 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
3683 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
3684 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
3685 ? QRhiSampler::Linear
3686 : QRhiSampler::None;
3687 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3688 QRhiSampler::Linear,
3690 QRhiSampler::ClampToEdge,
3691 QRhiSampler::ClampToEdge,
3692 QRhiSampler::Repeat });
3693 if (reflectionSampler >= 0 && reflectionTexture)
3694 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
3695 }
else if (shaderPipeline->lightProbeTexture()) {
3696 int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3698 auto tiling = shaderPipeline->lightProbeTiling();
3699 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
3700 QSSGRhiHelpers::toRhi(tiling.first), QSSGRhiHelpers::toRhi(tiling.second), QRhiSampler::Repeat });
3701 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage,
3702 shaderPipeline->lightProbeTexture(), sampler);
3707 if (shaderPipeline->screenTexture()) {
3708 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
3709 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
3710 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
3715 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
3716 ? QRhiSampler::Linear : QRhiSampler::None;
3717 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
3718 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3719 if (screenTextureBinding >= 0) {
3720 bindings.addTexture(screenTextureBinding,
3721 QRhiShaderResourceBinding::FragmentStage,
3722 shaderPipeline->screenTexture(), sampler);
3724 if (screenTextureArrayBinding >= 0) {
3725 bindings.addTexture(screenTextureArrayBinding,
3726 QRhiShaderResourceBinding::FragmentStage,
3727 shaderPipeline->screenTexture(), sampler);
3732 if (shaderPipeline->lightmapTexture()) {
3733 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
3735 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
3736 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
3737 bindings.addTexture(binding,
3738 QRhiShaderResourceBinding::FragmentStage,
3739 shaderPipeline->lightmapTexture(), sampler);
3746 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3747 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3749 QVector<QShaderDescription::InOutVariable> samplerVars =
3750 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
3751 for (
const QShaderDescription::InOutVariable &var : shaderPipeline->vertexStage()->shader().description().combinedImageSamplers()) {
3752 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
3753 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
3754 if (it == samplerVars.cend())
3755 samplerVars.append(var);
3758 int maxSamplerBinding = -1;
3759 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
3760 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
3769 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
3771 if (maxSamplerBinding >= 0) {
3773 int extraTexCount = shaderPipeline->extraTextureCount();
3774 for (
int i = 0; i < extraTexCount; ++i) {
3775 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
3776 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
3777 if (samplerBinding >= 0) {
3778 samplerBindingsSpecified.setBit(samplerBinding);
3779 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
3780 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
3781 bindings.addTexture(samplerBinding,
3782 QRhiShaderResourceBinding::FragmentStage,
3790 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3791 QSSG_ASSERT(srb,
return -1);
3792 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3793 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3794 rhiPassData.srb = srb;
3858 QSSGPassKey passKey,
3860 const QMatrix4x4 &viewProjection,
3862 QRhiRenderPassDescriptor *renderPassDescriptor,
3863 QSSGRhiGraphicsPipelineState *ps,
3864 QSSGRenderMotionVectorMap &motionVectorMapManager)
3866 if (inObject.type != QSSGRenderableObject::Type::DefaultMaterialMeshSubset &&
3867 inObject.type != QSSGRenderableObject::Type::CustomMaterialMeshSubset)
3870 QSSGSubsetRenderable &subsetRenderable =
static_cast<QSSGSubsetRenderable &>(inObject);
3871 auto &modelNode = subsetRenderable.modelContext.model;
3873 bool skin = modelNode.usesBoneTexture();
3874 bool instance = modelNode.instanceCount() > 0;
3875 bool morph = modelNode.morphTargets.size() > 0;
3877 QSSGRhiShaderPipelinePtr shaderPipeline = inData.contextInterface()->shaderCache()->
3878 getBuiltInRhiShaders().getRhiMotionVectorShader(skin, instance, morph);
3880 if (!shaderPipeline)
3883 QSSGRhiShaderResourceBindingList bindings;
3885 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3886 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey, &modelNode,
nullptr, 0 });
3889 QSSGRenderTextureData *boneTextureData =
nullptr;
3891 boneTextureData = modelNode.skin;
3892 else if (modelNode.skeleton)
3893 boneTextureData = &modelNode.skeleton->boneTexData;
3895 QMatrix4x4 modelViewProjection = subsetRenderable.modelContext.modelViewProjections[0];
3896 QMatrix4x4 instanceLocal;
3897 QMatrix4x4 instanceGlobal;
3900 instanceLocal = inData.getInstanceTransforms(modelNode).local;
3901 instanceGlobal = inData.getInstanceTransforms(modelNode).global;
3903 modelViewProjection = viewProjection;
3905 auto motionData = motionVectorMapManager.trackMotionData(&modelNode,
3906 modelViewProjection,
3910 modelNode.instanceTable,
3911 modelNode.morphWeights);
3912 float velocityAmount = subsetRenderable.modelContext.model.motionVectorScale;
3913 int morphTargetCount = modelNode.morphWeights.count();
3925 const int ubufSize = 416;
3928 dcd.ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic,
3929 QRhiBuffer::UniformBuffer,
3934 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3936 memcpy(ubufData, modelViewProjection.constData(), 64);
3938 memcpy(ubufData + ubufOffset, motionData.prevModelViewProjection.constData(), 64);
3940 memcpy(ubufData + ubufOffset, instanceLocal.constData(), 64);
3942 memcpy(ubufData + ubufOffset, instanceGlobal.constData(), 64);
3944 memcpy(ubufData + ubufOffset, motionData.prevInstanceLocal.constData(), 64);
3946 memcpy(ubufData + ubufOffset, motionData.prevInstanceGlobal.constData(), 64);
3948 memcpy(ubufData + ubufOffset, &inData.layer.currentAndLastJitter, 16);
3950 memcpy(ubufData + ubufOffset, &velocityAmount, 4);
3952 memcpy(ubufData + ubufOffset, &morphTargetCount, 4);
3953 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3955 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::VertexStage |
3956 QRhiShaderResourceBinding::FragmentStage, dcd.ubuf);
3958 QRhiSampler *nearestSampler =
nullptr;
3960 if (skin || instance) {
3961 nearestSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3962 QRhiSampler::Nearest,
3964 QRhiSampler::ClampToEdge,
3965 QRhiSampler::ClampToEdge,
3971 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3974 bindings.addTexture(binding,
3975 QRhiShaderResourceBinding::VertexStage,
3976 inData.getBonemapTexture(subsetRenderable.modelContext),
3978 binding = shaderPipeline->bindingForTexture(
"lastBoneTexture");
3980 bindings.addTexture(binding,
3981 QRhiShaderResourceBinding::VertexStage,
3982 motionData.prevBoneTexture.m_texture,
3989 int binding = shaderPipeline->bindingForTexture(
"lastInstanceTexture");
3991 bindings.addTexture(binding,
3992 QRhiShaderResourceBinding::VertexStage,
3993 motionData.prevInstanceTexture.m_texture,
3998 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3999 if (targetsTexture) {
4000 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
4002 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
4003 QRhiSampler::Nearest,
4005 QRhiSampler::ClampToEdge,
4006 QRhiSampler::ClampToEdge,
4007 QRhiSampler::ClampToEdge
4009 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
4011 if ((binding = shaderPipeline->bindingForTexture(
"morphWeightTexture")) >= 0)
4012 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, motionData.currentMorphWeightTexture.m_texture, targetsSampler);
4014 if ((binding = shaderPipeline->bindingForTexture(
"lastMorphWeightTexture")) >= 0)
4015 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, motionData.prevMorphWeightTexture.m_texture, targetsSampler);
4019 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
4020 ia = subsetRenderable.subset.rhi.ia;
4021 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
4022 QVector3D cameraDirection = cameraDatas[0].direction;
4023 QVector3D cameraPosition = cameraDatas[0].position;
4024 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDirection, cameraPosition);
4025 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
4026 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
4028 QRhiShaderResourceBindings *&srb = dcd.srb;
4029 bool srbChanged =
false;
4030 if (!srb || bindings != dcd.bindings) {
4031 srb = rhiCtxD->srb(bindings);
4032 rhiCtxD->releaseCachedSrb(dcd.bindings);
4033 dcd.bindings = bindings;
4037 subsetRenderable.rhiRenderData.motionVectorPass.srb = srb;
4039 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
4042 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
4043 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
4046 subsetRenderable.rhiRenderData.motionVectorPass.pipeline = dcd.pipeline;
4049 subsetRenderable.rhiRenderData.motionVectorPass.pipeline = rhiCtxD->pipeline(pipelineKey,
4050 renderPassDescriptor,
4052 dcd.pipeline = subsetRenderable.rhiRenderData.motionVectorPass.pipeline;
4053 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
4054 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;