250 const QSSGRenderCamera &inCamera,
251 const QSSGRenderLight *inLight,
252 const int shadowMapResolution,
253 const float pcfRadius,
254 const float clipNear,
256 const QSSGBounds3 &castingObjectsBox,
257 const QSSGBounds3 &receivingObjectsBox,
258 bool lockShadowmapTexels,
259 QSSGDebugDrawSystem *debugDrawSystem,
261 bool drawSceneCascadeIntersection)
263 Q_ASSERT(inLight->type == QSSGRenderLight::Type::DirectionalLight);
264 QVarLengthArray<std::unique_ptr<QSSGRenderCamera>, 4> result;
266 if (clipNear >= clipFar || qFuzzyCompare(clipNear, clipFar))
269 const QMatrix4x4 lightGlobalTransform = data.getGlobalTransform(*inLight);
270 const QVector3D lightDir = inLight->getDirection(lightGlobalTransform);
271 const QVector3D lightPivot = inLight->pivot;
273 const QVector3D forward = lightDir.normalized();
274 const QVector3D right = qFuzzyCompare(qAbs(forward.y()), 1.0f)
275 ? QVector3D::crossProduct(forward, QVector3D(1, 0, 0)).normalized()
276 : QVector3D::crossProduct(forward, QVector3D(0, 1, 0)).normalized();
277 const QVector3D up = QVector3D::crossProduct(right, forward).normalized();
279 QMatrix4x4 lightMatrix;
280 lightMatrix.setRow(0, QVector4D(right, 0.0f));
281 lightMatrix.setRow(1, QVector4D(up, 0.0f));
282 lightMatrix.setRow(2, QVector4D(forward, 0.0f));
283 lightMatrix.setRow(3, QVector4D(0.0f, 0.0f, 0.0f, 1.0f));
284 QMatrix4x4 lightMatrixInverted = lightMatrix.inverted();
286 const float farScale = (clipFar - clipNear) / (inCamera.clipPlanes.clipFar() - inCamera.clipPlanes.clipNear());
288 const QMatrix4x4 cameraGlobalTransform = data.getGlobalTransform(inCamera);
289 QMatrix4x4 viewProjection(Qt::Uninitialized);
290 inCamera.calculateViewProjectionMatrix(cameraGlobalTransform, viewProjection);
291 const QSSGBoxPoints frustum = computeFrustumBounds(viewProjection);
292 const QSSGBoxPoints frustumUntransformed = lockShadowmapTexels ? computeFrustumBounds(inCamera.projection) : QSSGBoxPoints();
296 const auto calcFrustumRadius = [&](
float t0,
float t1) ->
float {
297 const QSSGBoxPoints pts = sliceFrustum(frustumUntransformed, t0 * farScale, t1 * farScale);
299 QVector3D center = QVector3D(0.f, 0.f, 0.f);
300 for (QVector3D point : pts) {
303 center = center * 0.125f;
305 float radiusSquared = 0;
306 for (QVector3D point : pts) {
307 radiusSquared = qMax(radiusSquared, (point - center).lengthSquared());
310 return std::sqrt(radiusSquared);
313 const auto computeSplitRanges = [inLight](
const QVarLengthArray<
float, 3> &splits) -> QVarLengthArray<QPair<
float,
float>, 4> {
314 QVarLengthArray<QPair<
float,
float>, 4> ranges;
315 const float csmBlendRatio = inLight->m_csmBlendRatio;
317 for (qsizetype i = 0; i < splits.length(); i++) {
318 const float tI = qBound(qMin(t0 + 0.01f, 1.0f), splits[i], 1.0f);
319 ranges.emplace_back(t0, qMin(1.0f, tI + csmBlendRatio));
322 ranges.emplace_back(t0, 1.0f);
326 const auto computeFrustums = [&](
const QVarLengthArray<
float, 3> &splits) {
327 for (
const auto &range : computeSplitRanges(splits)) {
328 const float frustumRadius = lockShadowmapTexels ? calcFrustumRadius(range.first, range.second) : 0.0f;
329 auto camera = computeShadowCameraFromFrustum(lightMatrix,
337 range.first * farScale,
338 range.second * farScale,
345 drawSceneCascadeIntersection);
346 result.emplace_back(std::move(camera));
350 switch (inLight->m_csmNumSplits) {
356 computeFrustums({ inLight->m_csmSplit1 });
360 computeFrustums({ inLight->m_csmSplit1, inLight->m_csmSplit2 });
364 computeFrustums({ inLight->m_csmSplit1, inLight->m_csmSplit2, inLight->m_csmSplit3 });
406 QSSGRhiShaderPipeline *shaderPipeline,
407 QSSGRenderableImage *renderableImage,
408 QSSGRhiShaderResourceBindingList &bindings,
409 bool isCustomMaterialMeshSubset =
false)
411 static const auto imageAffectsAlpha = [](QSSGRenderableImage::Type mapType) {
412 return mapType == QSSGRenderableImage::Type::BaseColor ||
413 mapType == QSSGRenderableImage::Type::Diffuse ||
414 mapType == QSSGRenderableImage::Type::Translucency ||
415 mapType == QSSGRenderableImage::Type::Opacity;
418 while (renderableImage) {
419 const auto mapType = renderableImage->m_mapType;
420 if (imageAffectsAlpha(mapType)) {
421 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(mapType);
422 const int samplerHint =
int(mapType);
423 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
424 if (samplerBinding >= 0) {
425 QRhiTexture *texture = renderableImage->m_texture.m_texture;
426 if (samplerBinding >= 0 && texture) {
427 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
428 QRhiSampler *sampler = rhiCtx->sampler({ QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
429 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
430 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
431 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
432 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
433 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
435 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
439 renderableImage = renderableImage->m_nextImage;
442 if (isCustomMaterialMeshSubset) {
443 QVector<QShaderDescription::InOutVariable> samplerVars =
444 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
445 const auto combinedSamplers = shaderPipeline->vertexStage()->shader().description().combinedImageSamplers();
446 for (
const QShaderDescription::InOutVariable &var : combinedSamplers) {
447 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
448 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
449 if (it == samplerVars.cend())
450 samplerVars.append(var);
453 int maxSamplerBinding = -1;
454 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
455 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
464 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
466 if (maxSamplerBinding >= 0) {
468 int customTexCount = shaderPipeline->extraTextureCount();
469 for (
int i = 0; i < customTexCount; ++i) {
470 const QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
471 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
472 if (samplerBinding >= 0) {
473 samplerBindingsSpecified.setBit(samplerBinding);
474 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
475 bindings.addTexture(samplerBinding,
476 RENDERER_VISIBILITY_ALL,
484 QRhiSampler *dummySampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
485 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
486 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
487 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
488 QRhiTexture *dummyCubeTexture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
489 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
491 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars)) {
492 if (!samplerBindingsSpecified.testBit(var.binding)) {
493 QRhiTexture *t = var.type == QShaderDescription::SamplerCube ? dummyCubeTexture : dummyTexture;
494 bindings.addTexture(var.binding, RENDERER_VISIBILITY_ALL, t, dummySampler);
708 QSSGRhiGraphicsPipelineState *ps,
709 const QVector2D *depthAdjust,
710 const QSSGRenderableObjectList &sortedOpaqueObjects,
711 QSSGRenderCamera &inCamera,
713 QSSGRenderTextureCubeFace cubeFace,
714 quint32 cascadeIndex)
716 QSSGShaderFeatures featureSet;
718 featureSet.set(QSSGShaderFeatures::Feature::OrthoShadowPass,
true);
720 featureSet.set(QSSGShaderFeatures::Feature::PerspectiveShadowPass,
true);
726 featureSet.set(QSSGShaderFeatures::Feature::DisableMultiView,
true);
728 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
729 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
730 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
732 for (
const auto &handle : sortedOpaqueObjects) {
733 QSSGRenderableObject *theObject = handle.obj;
734 QSSG_ASSERT(theObject->renderableFlags.castsShadows(),
continue);
736 QSSGShaderFeatures objectFeatureSet = featureSet;
737 const bool isOpaqueDepthPrePass = theObject->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
738 if (isOpaqueDepthPrePass)
739 objectFeatureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
741 QSSGRhiDrawCallData *dcd =
nullptr;
742 QMatrix4x4 modelViewProjection;
743 QSSGSubsetRenderable &renderable(
static_cast<QSSGSubsetRenderable &>(*theObject));
744 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
745 const bool hasSkinning = defaultMaterialShaderKeyProperties.m_boneCount.getValue(renderable.shaderDescription) > 0;
746 modelViewProjection = hasSkinning ? pEntry->m_lightViewProjection[cascadeIndex]
747 : pEntry->m_lightViewProjection[cascadeIndex] * renderable.modelContext.globalTransform;
751 const quintptr entryIdx = cascadeIndex + cubeFaceIdx + (quintptr(renderable.subset.offset) << 3);
752 dcd = &rhiCtxD->drawCallData({ passKey, &renderable.modelContext.model, pEntry, entryIdx });
755 QSSGRhiShaderResourceBindingList bindings;
756 QSSGRhiShaderPipelinePtr shaderPipeline;
757 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*theObject));
758 if (theObject->type == QSSGSubsetRenderable::Type::DefaultMaterialMeshSubset) {
759 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
760 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
761 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(subsetRenderable.shaderDescription);
763 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, objectFeatureSet);
766 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
767 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
769 QSSGRenderCameraList cameras({ &inCamera });
770 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, cameras, depthAdjust, &modelViewProjection);
772 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &subsetRenderable.modelContext.model, subsetRenderable.subset.offset);
773 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
775 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &subsetRenderable.modelContext.model);
776 }
else if (theObject->type == QSSGSubsetRenderable::Type::CustomMaterialMeshSubset) {
777 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
778 ps->cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
780 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
781 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), objectFeatureSet);
784 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
785 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
787 QSSGRenderCameraList cameras({ &inCamera });
788 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, material, subsetRenderable,
789 cameras, depthAdjust, &modelViewProjection);
790 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
793 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
795 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
796 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
797 ia = subsetRenderable.subset.rhi.ia;
798 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
799 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
800 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
803 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
806 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
808 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
810 if (isOpaqueDepthPrePass) {
811 addOpaqueDepthPrePassBindings(rhiCtx,
812 shaderPipeline.get(),
813 subsetRenderable.firstImage,
815 (theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
822 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
823 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
824 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
825 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
826 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
827 if (screenTextureBinding >= 0) {
828 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
829 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
830 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
831 bindings.addTexture(screenTextureBinding,
832 QRhiShaderResourceBinding::FragmentStage,
833 dummyTexture, sampler);
835 if (screenTextureArrayBinding >= 0) {
836 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
837 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates, QSize(64, 64), Qt::black, inData.layer.viewCount);
838 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
839 bindings.addTexture(screenTextureArrayBinding,
840 QRhiShaderResourceBinding::FragmentStage,
841 dummyTexture, sampler);
846 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
847 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
849 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
850 QRhiSampler::Nearest,
852 QRhiSampler::ClampToEdge,
853 QRhiSampler::ClampToEdge,
856 bindings.addTexture(binding,
857 QRhiShaderResourceBinding::VertexStage,
864 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
865 if (targetsTexture) {
866 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
868 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
869 QRhiSampler::Nearest,
871 QRhiSampler::ClampToEdge,
872 QRhiSampler::ClampToEdge,
873 QRhiSampler::ClampToEdge
875 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
879 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
880 subsetRenderable.rhiRenderData.shadowPass.pipeline = rhiCtxD->pipeline(*ps, pEntry->m_rhiRenderPassDesc[cascadeIndex], srb);
881 subsetRenderable.rhiRenderData.shadowPass.srb[cubeFaceIdx] = srb;
916 QRhiRenderPassDescriptor *renderPassDescriptor,
917 QSSGRhiGraphicsPipelineState *ps,
918 QSSGShaderFeatures featureSet,
922 QSSGRenderCamera *alteredCamera,
923 QMatrix4x4 *alteredModelViewProjection,
924 QSSGRenderTextureCubeFace cubeFace,
928 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
930 switch (inObject.type) {
931 case QSSGRenderableObject::Type::DefaultMaterialMeshSubset:
933 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
935 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
936 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
938 if ((cubeFace != QSSGRenderTextureCubeFaceNone)) {
940 featureSet.disableTonemapping();
943 if (subsetRenderable.renderableFlags.rendersWithLightmap())
944 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
946 const auto &shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
947 if (shaderPipeline) {
955 QSSGRhiShaderResourceBindingList bindings;
956 const auto &modelNode = subsetRenderable.modelContext.model;
957 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(subsetRenderable.shaderDescription);
964 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
965 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * (cubeFaceIdx + (quintptr(subsetRenderable.subset.offset) << 3));
967 const auto entryPartA =
reinterpret_cast<quintptr>(&subsetRenderable.material);
968 const auto entryPartB =
reinterpret_cast<quintptr>(entry);
969 const void *entryId =
reinterpret_cast<
const void *>(entryPartA ^ entryPartB);
971 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
972 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey, &modelNode, entryId, entryIdx });
974 shaderPipeline->ensureCombinedUniformBuffer(&dcd.ubuf);
975 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
977 Q_ASSERT(alteredModelViewProjection);
978 QSSGRenderCameraList cameras({ alteredCamera });
979 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, cameras,
nullptr, alteredModelViewProjection);
981 Q_ASSERT(!alteredModelViewProjection);
982 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
986 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &subsetRenderable.modelContext.model, subsetRenderable.subset.offset);
987 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
990 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &subsetRenderable.modelContext.model);
993 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
994 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
996 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
997 QRhiSampler::Nearest,
999 QRhiSampler::ClampToEdge,
1000 QRhiSampler::ClampToEdge,
1003 bindings.addTexture(binding,
1004 QRhiShaderResourceBinding::VertexStage,
1010 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
1011 if (targetsTexture) {
1012 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
1014 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1015 QRhiSampler::Nearest,
1017 QRhiSampler::ClampToEdge,
1018 QRhiSampler::ClampToEdge,
1019 QRhiSampler::ClampToEdge
1021 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
1025 ps->samples = samples;
1026 ps->viewCount = viewCount;
1028 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
1029 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
1030 if (!oit || (oit && inData.layer.oitMethod == QSSGRenderLayer::OITMethod::None))
1031 fillTargetBlend(&ps->targetBlend[0], material.blendMode);
1033 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
1035 ia = subsetRenderable.subset.rhi.ia;
1036 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
1037 QVector3D cameraDirection = cameraDatas[0].direction;
1038 QVector3D cameraPosition = cameraDatas[0].position;
1039 if (alteredCamera) {
1040 const QMatrix4x4 camGlobalTranform = inData.getGlobalTransform(*alteredCamera);
1041 cameraDirection = QSSGRenderNode::getScalingCorrectDirection(camGlobalTranform);
1042 cameraPosition = QSSGRenderNode::getGlobalPos(camGlobalTranform);
1044 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDirection, cameraPosition);
1045 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
1047 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline->ub0Size());
1049 if (shaderPipeline->isLightingEnabled()) {
1050 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd.ubuf,
1051 shaderPipeline->ub0LightDataOffset(),
1052 sizeof(QSSGShaderLightsUniformData));
1053 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd.ubuf,
1054 shaderPipeline->ub0DirectionalLightDataOffset(),
1055 sizeof(QSSGShaderDirectionalLightsUniformData));
1060 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
1061 while (renderableImage) {
1062 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
1063 const int samplerHint =
int(renderableImage->m_mapType);
1064 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
1065 if (samplerBinding >= 0) {
1066 QRhiTexture *texture = renderableImage->m_texture.m_texture;
1067 if (samplerBinding >= 0 && texture) {
1068 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
1069 QSSGRhiSamplerDescription samplerDesc = {
1070 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
1071 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
1072 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
1073 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
1074 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
1075 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
1077 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
1078 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
1079 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
1082 renderableImage = renderableImage->m_nextImage;
1085 if (shaderPipeline->isLightingEnabled()) {
1087 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
1088 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
1091 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1092 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
1093 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1096 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1097 QRhiSampler::Linear,
1099 QRhiSampler::ClampToEdge,
1100 QRhiSampler::ClampToEdge,
1101 QRhiSampler::Repeat });
1103 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1107 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
1108 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
1109 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
1111 QRhiTexture *texture = shadowMapBlueNoise;
1112 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1113 QRhiSampler::Linear,
1115 QRhiSampler::Repeat,
1116 QRhiSampler::Repeat,
1117 QRhiSampler::Repeat });
1118 Q_ASSERT(texture && sampler);
1119 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1122 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1123 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
1124 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1125 QRhiSampler::Linear,
1127 QRhiSampler::Repeat,
1128 QRhiSampler::Repeat,
1129 QRhiSampler::Repeat });
1130 Q_ASSERT(texture && sampler);
1131 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1132 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1139 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
1140 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
1141 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
1142 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
1143 ? QRhiSampler::Linear
1144 : QRhiSampler::None;
1145 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1146 QRhiSampler::Linear,
1148 QRhiSampler::ClampToEdge,
1149 QRhiSampler::ClampToEdge,
1150 QRhiSampler::Repeat });
1151 if (reflectionSampler >= 0 && reflectionTexture)
1152 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
1155 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
1157 auto texture = shaderPipeline->lightProbeTexture();
1159 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1160 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
1161 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1165 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
1166 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1167 QRhiSampler::Linear,
1168 QRhiSampler::Linear,
1169 QSSGRhiHelpers::toRhi(tiling.first),
1170 QSSGRhiHelpers::toRhi(tiling.second),
1171 QRhiSampler::Repeat });
1172 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1176 if (shaderPipeline->screenTexture()) {
1177 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
1178 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
1179 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
1180 QRhiTexture *screenTexture = shaderPipeline->screenTexture();
1182 if (screenMapPass) {
1183 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1185 const QRhiTexture::Flags flags = screenTexture->flags();
1187 screenTexture = rhiCtx->dummyTexture(flags, resourceUpdates);
1188 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1195 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
1196 ? QRhiSampler::Linear : QRhiSampler::None;
1197 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
1198 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
1199 if (screenTextureBinding >= 0) {
1200 bindings.addTexture(screenTextureBinding,
1201 QRhiShaderResourceBinding::FragmentStage,
1202 screenTexture, sampler);
1204 if (screenTextureArrayBinding >= 0) {
1205 bindings.addTexture(screenTextureArrayBinding,
1206 QRhiShaderResourceBinding::FragmentStage,
1207 screenTexture, sampler);
1212 if (shaderPipeline->lightmapTexture()) {
1213 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
1215 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1216 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
1217 bindings.addTexture(binding,
1218 QRhiShaderResourceBinding::FragmentStage,
1219 shaderPipeline->lightmapTexture(), sampler);
1225 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1228 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1230 if (oit && inData.layer.oitMethod == QSSGRenderLayer::OITMethod::LinkedList)
1240 QRhiShaderResourceBindings *&srb = dcd.srb;
1241 bool srbChanged =
false;
1242 if (!srb || bindings != dcd.bindings) {
1243 srb = rhiCtxD->srb(bindings);
1244 rhiCtxD->releaseCachedSrb(dcd.bindings);
1245 dcd.bindings = bindings;
1249 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1250 subsetRenderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
1252 subsetRenderable.rhiRenderData.mainPass.srb = srb;
1254 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
1257 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
1258 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
1261 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1262 subsetRenderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
1264 subsetRenderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
1266 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1267 subsetRenderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1268 renderPassDescriptor,
1270 dcd.pipeline = subsetRenderable.rhiRenderData.reflectionPass.pipeline;
1272 subsetRenderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1273 renderPassDescriptor,
1275 dcd.pipeline = subsetRenderable.rhiRenderData.mainPass.pipeline;
1277 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
1278 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;
1284 case QSSGRenderableObject::Type::CustomMaterialMeshSubset:
1286 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
1287 const QSSGRenderCustomMaterial &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
1288 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
1290 featureSet.set(QSSGShaderFeatures::Feature::LightProbe, inData.layer.lightProbe || material.m_iblProbe);
1292 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
1293 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
1295 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1297 featureSet.disableTonemapping();
1300 if (subsetRenderable.renderableFlags.rendersWithLightmap())
1301 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
1303 customMaterialSystem.rhiPrepareRenderable(ps, passKey, subsetRenderable, featureSet,
1304 material, inData, renderPassDescriptor, samples, viewCount, screenMapPass,
1305 alteredCamera, cubeFace, alteredModelViewProjection, entry, oit);
1308 case QSSGRenderableObject::Type::Particles:
1311 const auto &shaderPipeline = shadersForParticleMaterial(ps, particleRenderable, featureSet);
1312 if (shaderPipeline) {
1313 QSSGParticleRenderer::rhiPrepareRenderable(*shaderPipeline, passKey, rhiCtx, ps, particleRenderable, inData, renderPassDescriptor, samples, viewCount,
1314 alteredCamera, cubeFace, entry, oit);
1360 const QSSGRhiGraphicsPipelineState &state,
1362 bool *needsSetViewport,
1363 QSSGRenderTextureCubeFace cubeFace,
1364 qsizetype userPassIndex)
1366 switch (object.type) {
1367 case QSSGRenderableObject::Type::DefaultMaterialMeshSubset:
1369 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(object));
1371 QSSG_ASSERT(QSSGUserRenderPassManager::maxUserPassSlots() == std::size(subsetRenderable.rhiRenderData.userPassData),
return);
1373 QRhiGraphicsPipeline *ps = (userPassIndex >= 0 && size_t(userPassIndex) < QSSGUserRenderPassManager::maxUserPassSlots())
1374 ? subsetRenderable.rhiRenderData.userPassData[userPassIndex].pipeline : subsetRenderable.rhiRenderData.mainPass.pipeline;
1375 QRhiShaderResourceBindings *srb = (userPassIndex >= 0 && size_t(userPassIndex) < QSSGUserRenderPassManager::maxUserPassSlots())
1376 ? subsetRenderable.rhiRenderData.userPassData[userPassIndex].srb : subsetRenderable.rhiRenderData.mainPass.srb;
1378 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1379 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
1380 ps = subsetRenderable.rhiRenderData.reflectionPass.pipeline;
1381 srb = subsetRenderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx];
1387 QRhiBuffer *vertexBuffer = subsetRenderable.subset.rhi.vertexBuffer->buffer();
1388 QRhiBuffer *indexBuffer = subsetRenderable.subset.rhi.indexBuffer ? subsetRenderable.subset.rhi.indexBuffer->buffer() :
nullptr;
1390 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1392 cb->setGraphicsPipeline(ps);
1393 cb->setShaderResources(srb);
1395 if (*needsSetViewport) {
1396 cb->setViewport(state.viewport);
1397 if (state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor))
1398 cb->setScissor(state.scissor);
1399 *needsSetViewport =
false;
1402 QRhiCommandBuffer::VertexInput vertexBuffers[2];
1403 int vertexBufferCount = 1;
1404 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
1405 quint32 instances = 1;
1406 if ( subsetRenderable.modelContext.model.instancing()) {
1407 instances = subsetRenderable.modelContext.model.instanceCount();
1414 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(subsetRenderable.instanceBuffer, 0);
1415 vertexBufferCount = 2;
1417 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
1418 if (state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef))
1419 cb->setStencilRef(state.stencilRef);
1421 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, subsetRenderable.subset.rhi.indexBuffer->indexFormat());
1422 cb->drawIndexed(subsetRenderable.subset.lodCount(subsetRenderable.subsetLevelOfDetail), instances, subsetRenderable.subset.lodOffset(subsetRenderable.subsetLevelOfDetail));
1423 QSSGRHICTX_STAT(rhiCtx, drawIndexed(subsetRenderable.subset.lodCount(subsetRenderable.subsetLevelOfDetail), instances));
1425 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
1426 cb->draw(subsetRenderable.subset.count, instances, subsetRenderable.subset.offset);
1427 QSSGRHICTX_STAT(rhiCtx, draw(subsetRenderable.subset.count, instances));
1429 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (subsetRenderable.subset.count | quint64(instances) << 32),
1430 QVector<
int>({subsetRenderable.modelContext.model.profilingId,
1431 subsetRenderable.material.profilingId}));
1434 case QSSGRenderableObject::Type::CustomMaterialMeshSubset:
1436 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(object));
1437 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
1438 customMaterialSystem.rhiRenderRenderable(rhiCtx, subsetRenderable, needsSetViewport, cubeFace, state, userPassIndex);
1441 case QSSGRenderableObject::Type::Particles:
1444 QSSGParticleRenderer::rhiRenderRenderable(rhiCtx, renderable, needsSetViewport, cubeFace, state);
1469 QSSGPassKey passKey,
1470 QSSGRhiGraphicsPipelineState &ps,
1471 QSSGRenderShadowMap &shadowMapManager,
1472 const QSSGRenderCamera &camera,
1473 QSSGRenderCamera *debugCamera,
1475 const QSSGRenderableObjectList &sortedOpaqueObjects,
1477 const QSSGBounds3 &castingObjectsBox,
1478 const QSSGBounds3 &receivingObjectsBox)
1481 QSSGDebugDrawSystem *debugDrawSystem = renderer.contextInterface()->debugDrawSystem().get();
1482 const bool drawDirectionalLightShadowBoxes = layerData.layer.drawDirectionalLightShadowBoxes;
1483 const bool drawPointLightShadowBoxes = layerData.layer.drawPointLightShadowBoxes;
1484 const bool drawShadowCastingBounds = layerData.layer.drawShadowCastingBounds;
1485 const bool drawShadowReceivingBounds = layerData.layer.drawShadowReceivingBounds;
1486 const bool drawCascades = layerData.layer.drawCascades;
1487 const bool drawSceneCascadeIntersection = layerData.layer.drawSceneCascadeIntersection;
1488 const bool disableShadowCameraUpdate = layerData.layer.disableShadowCameraUpdate;
1489 const bool drawCulledObjects = layerData.layer.drawCulledObjects;
1490 QVector<
bool> debugIsObjectCulled = drawCulledObjects ? QVector<
bool>(sortedOpaqueObjects.size(),
true) : QVector<
bool>();
1492 static const auto rhiRenderOneShadowMap = [](QSSGRhiContext *rhiCtx,
1493 QSSGRhiGraphicsPipelineState *ps,
1494 const QSSGRenderableObjectList &sortedOpaqueObjects,
1496 const QSSGBounds3 cameraBounds,
1497 QVector<
bool> &debugIsObjectCulled,
1498 bool drawCulledObjects) {
1499 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1500 bool needsSetViewport =
true;
1502 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1507 if (theObject->globalBoundsInstancing.isFinite() && theObject->globalBounds.isFinite()) {
1508 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1509 : theObject->globalBounds;
1510 if (!globalBounds.isEmpty() && !cameraBounds.intersects(globalBounds)) {
1515 if (Q_UNLIKELY(drawCulledObjects))
1516 debugIsObjectCulled[i] =
false;
1519 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
1520 QSSGSubsetRenderable *renderable(
static_cast<QSSGSubsetRenderable *>(theObject));
1522 QRhiBuffer *vertexBuffer = renderable->subset.rhi.vertexBuffer->buffer();
1523 QRhiBuffer *indexBuffer = renderable->subset.rhi.indexBuffer
1524 ? renderable->subset.rhi.indexBuffer->buffer()
1528 if (!renderable->rhiRenderData.shadowPass.pipeline)
1531 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
1533 cb->setGraphicsPipeline(renderable->rhiRenderData.shadowPass.pipeline);
1535 QRhiShaderResourceBindings *srb = renderable->rhiRenderData.shadowPass.srb[cubeFace];
1536 cb->setShaderResources(srb);
1538 if (needsSetViewport) {
1539 cb->setViewport(ps->viewport);
1540 needsSetViewport =
false;
1543 QRhiCommandBuffer::VertexInput vertexBuffers[2];
1544 int vertexBufferCount = 1;
1545 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
1546 quint32 instances = 1;
1547 if (renderable->modelContext.model.instancing()) {
1548 instances = renderable->modelContext.model.instanceCount();
1549 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(renderable->instanceBuffer, 0);
1550 vertexBufferCount = 2;
1553 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, renderable->subset.rhi.indexBuffer->indexFormat());
1554 cb->drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances, renderable->subset.lodOffset(renderable->subsetLevelOfDetail));
1555 QSSGRHICTX_STAT(rhiCtx, drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances));
1557 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
1558 cb->draw(renderable->subset.count, instances, renderable->subset.offset);
1559 QSSGRHICTX_STAT(rhiCtx, draw(renderable->subset.count, instances));
1561 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (renderable->subset.count | quint64(instances) << 32),
1562 QVector<
int>({renderable->modelContext.model.profilingId,
1563 renderable->material.profilingId}));
1568 static const auto rhiClearShadowMap = [](
QSSGRenderer &renderer, QSSGRenderShadowMap &shadowMapManager, QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QRhiRenderPassDescriptor *renderPassDesc) {
1569 auto clearShadowMapShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiClearShadowMapShader();
1570 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, clearShadowMapShaderPipeline.get());
1573 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
false);
1574 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1575 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, shadowMapManager.shadowClearSrb(), renderPassDesc, {});
1577 ps->flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1580 QRhi *rhi = rhiCtx->rhi();
1581 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1585 QVector2D depthAdjust;
1586 if (rhi->isClipDepthZeroToOne()) {
1588 depthAdjust[0] = 0.0f;
1589 depthAdjust[1] = 1.0f;
1592 depthAdjust[0] = 1.0f;
1593 depthAdjust[1] = 0.5f;
1596 if (drawShadowCastingBounds)
1598 if (drawShadowReceivingBounds)
1602 const QSize atlasTextureSize = shadowMapManager.shadowMapAtlasTexture()->pixelSize();
1604 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
1605 for (
int i = 0, ie = globalLights.size(); i != ie; ++i) {
1606 if (!globalLights[i].shadows || globalLights[i].light->m_fullyBaked)
1613 const auto &light = globalLights[i].light;
1615 if (!shadowMapManager.shadowMapAtlasTexture())
1618 if (light->type == QSSGRenderLight::Type::DirectionalLight || light->type == QSSGRenderLight::Type::SpotLight) {
1619 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1623 if (!disableShadowCameraUpdate && debugCamera) {
1624 debugCamera->clipPlanes = camera.clipPlanes;
1625 debugCamera->projection = camera.projection;
1629 debugCamera->localTransform = layerData.getGlobalTransform(camera);
1632 QVarLengthArray<std::unique_ptr<QSSGRenderCamera>, 4> cascades;
1633 if (light->type == QSSGRenderLight::Type::DirectionalLight) {
1634 const float pcfRadius = light->m_softShadowQuality == QSSGRenderLight::SoftShadowQuality::Hard ? 0.f : light->m_pcfFactor;
1635 const float clipNear = camera.clipPlanes.clipNear();
1636 const float clipFar = qMin(light->m_shadowMapFar, camera.clipPlanes.clipFar());
1637 const float clipRange = clipFar - clipNear;
1638 cascades = setupCascadingCamerasForShadowMap(layerData,
1639 disableShadowCameraUpdate ? *debugCamera : camera,
1646 receivingObjectsBox,
1647 light->m_lockShadowmapTexels,
1650 drawSceneCascadeIntersection);
1653 pEntry->m_csmSplits[0] = clipNear + clipRange * (light->m_csmNumSplits > 0 ? light->m_csmSplit1 : 1.0f);
1654 pEntry->m_csmSplits[1] = clipNear + clipRange * (light->m_csmNumSplits > 1 ? light->m_csmSplit2 : 1.0f);
1655 pEntry->m_csmSplits[2] = clipNear + clipRange * (light->m_csmNumSplits > 2 ? light->m_csmSplit3 : 1.0f);
1656 pEntry->m_csmSplits[3] = clipNear + clipRange * 1.0f;
1657 pEntry->m_shadowMapFar = clipFar;
1658 }
else if (light->type == QSSGRenderLight::Type::SpotLight) {
1659 auto spotlightCamera =
std::make_unique<QSSGRenderCamera>(QSSGRenderCamera::Type::PerspectiveCamera);
1660 spotlightCamera->fov = QSSGRenderCamera::FieldOfView::fromDegrees(light->m_coneAngle * 2.0f);
1661 spotlightCamera->clipPlanes = { 1.0f, light->m_shadowMapFar };
1662 const QMatrix4x4 lightGlobalTransform = layerData.getGlobalTransform(*light);
1663 const QVector3D lightDir = QSSGRenderNode::getDirection(lightGlobalTransform);
1664 const QVector3D lightPos = QSSGRenderNode::getGlobalPos(lightGlobalTransform) - lightDir * spotlightCamera->clipPlanes.clipNear();
1665 const QVector3D lightPivot = light->pivot;
1666 const QVector3D forward = lightDir.normalized();
1667 const QVector3D right = qFuzzyCompare(qAbs(forward.y()), 1.0f)
1668 ? QVector3D::crossProduct(forward, QVector3D(1, 0, 0)).normalized()
1669 : QVector3D::crossProduct(forward, QVector3D(0, 1, 0)).normalized();
1670 const QVector3D up = QVector3D::crossProduct(right, forward).normalized();
1671 spotlightCamera->localTransform = QSSGRenderNode::calculateTransformMatrix(lightPos,
1672 QSSGRenderNode::initScale,
1674 QQuaternion::fromDirection(forward, up));
1675 QRectF theViewport(0.0f, 0.0f, (
float)light->m_shadowMapRes, (
float)light->m_shadowMapRes);
1676 QSSGRenderCamera::calculateProjectionInternal(*spotlightCamera, theViewport);
1677 cascades.push_back(
std::move(spotlightCamera));
1678 pEntry->m_shadowMapFar = light->m_shadowMapFar;
1683 memset(pEntry->m_csmActive, 0,
sizeof(pEntry->m_csmActive));
1685 QMatrix4x4 cascadeCameraGlobalTransforms(Qt::Uninitialized);
1686 const QMatrix4x4 bias = { 0.5, 0.0, 0.0, 0.5,
1689 0.0, 0.0, 0.0, 1.0 };
1691 for (
int cascadeIndex = 0; cascadeIndex < cascades.length(); cascadeIndex++) {
1692 const auto &cascadeCamera = cascades[cascadeIndex];
1696 cascadeCameraGlobalTransforms = layerData.getGlobalTransform(*cascadeCamera);
1697 pEntry->m_csmActive[cascadeIndex] = 1.f;
1698 QMatrix4x4 &viewProjection = pEntry->m_lightViewProjection[cascadeIndex];
1699 cascadeCamera->calculateViewProjectionMatrix(cascadeCameraGlobalTransforms, viewProjection);
1700 pEntry->m_lightViewProjection[cascadeIndex] = viewProjection;
1701 pEntry->m_fixedScaleBiasMatrix[cascadeIndex] = bias * viewProjection;
1702 const QMatrix4x4 inverted = viewProjection.inverted();
1703 const float x = 0.5f / (inverted * QVector4D(1, 0, 0, 0)).length();
1704 const float y = 0.5f / (inverted * QVector4D(0, 1, 0, 0)).length();
1705 const float z = 0.5f / (inverted * QVector4D(0, 0, 1, 0)).length();
1706 const QSSGBoxPoints frustumPoints = computeFrustumBounds(viewProjection);
1707 const QSSGBounds3 bounds = QSSGBounds3(frustumPoints);
1708 pEntry->m_dimensionsInverted[cascadeIndex] = QVector4D(x, y, z, 0.0f);
1709 pEntry->m_lightView = cascadeCameraGlobalTransforms.inverted();
1710 const bool isOrtho = cascadeCamera->type == QSSGRenderGraphObject::Type::OrthographicCamera;
1711 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[cascadeIndex], rhi->isYUpInFramebuffer());
1712 rhiPrepareResourcesForShadowMap(rhiCtx, layerData, passKey, pEntry, &ps, &depthAdjust, sortedOpaqueObjects, *cascadeCamera, isOrtho, QSSGRenderTextureCubeFaceNone, cascadeIndex);
1715 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[cascadeIndex];
1716 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1717 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1718 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1719 rhiClearShadowMap(renderer, shadowMapManager, rhiCtx, &ps, rt->renderPassDescriptor());
1720 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, 0, bounds, debugIsObjectCulled, drawCulledObjects);
1722 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1724 if (drawDirectionalLightShadowBoxes) {
1728 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"shadow_map"));
1730 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1731 ps.viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1733 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1734 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1735 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1736 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1737 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1738 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1739 const float shadowMapFar = qMax<
float>(2.0f, light->m_shadowMapFar);
1740 setupCubeShadowCameras(layerData, light, shadowMapFar, theCameras);
1741 pEntry->m_lightView = QMatrix4x4();
1742 pEntry->m_shadowMapFar = shadowMapFar;
1744 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1745 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1746 for (
const auto face : QSSGRenderTextureCubeFaces) {
1747 cameraGlobalTransform = layerData.getGlobalTransform(theCameras[quint8(face)]);
1748 theCameras[quint8(face)].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_lightViewProjection[0]);
1749 pEntry->m_lightCubeView[quint8(face)] = cameraGlobalTransform.inverted();
1751 rhiPrepareResourcesForShadowMap(rhiCtx,
1757 sortedOpaqueObjects,
1758 theCameras[quint8(face)],
1765 const QVector3D center = QSSGRenderNode::getGlobalPos(layerData.getGlobalTransform(*light));
1766 const QSSGBounds3 bounds = QSSGBounds3(center - QVector3D(shadowMapFar, shadowMapFar, shadowMapFar),
1767 center + QVector3D(shadowMapFar, shadowMapFar, shadowMapFar));
1769 for (
const auto face : QSSGRenderTextureCubeFaces) {
1773 QSSGRenderTextureCubeFace outFace = face;
1791 if (outFace == QSSGRenderTextureCubeFace::PosY)
1792 outFace = QSSGRenderTextureCubeFace::NegY;
1793 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1794 outFace = QSSGRenderTextureCubeFace::PosY;
1796 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargetCube[quint8(outFace)];
1797 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1798 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1799 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1800 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, quint8(face), bounds, debugIsObjectCulled, drawCulledObjects);
1802 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1803 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_cube", 0, outFace));
1810 QRhiTextureRenderTarget *rtFront = pEntry->m_rhiRenderTargets[0];
1811 QRhiRenderPassDescriptor *frontDesc = pEntry->m_rhiRenderPassDesc[0];
1812 auto atlasShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiCubeMapToAtlasShader();
1813 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[0], rhi->isYUpInFramebuffer());
1814 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, atlasShaderPipeline.get());
1815 QRhiShaderResourceBindings *srb = pEntry->m_cubeToAtlasFrontSrb;
1816 cb->beginPass(rtFront, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1817 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtFront));
1818 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1820 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, frontDesc, QSSGRhiQuadRenderer::UvCoords);
1823 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1824 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 6, 0));
1827 QRhiTextureRenderTarget *rtBack = pEntry->m_rhiRenderTargets[1];
1828 QRhiRenderPassDescriptor *backDesc = pEntry->m_rhiRenderPassDesc[1];
1829 srb = pEntry->m_cubeToAtlasBackSrb;
1830 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[1], rhi->isYUpInFramebuffer());
1831 cb->beginPass(rtBack, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1832 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtBack));
1833 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1835 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, backDesc, QSSGRhiQuadRenderer::UvCoords);
1838 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1839 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 7, 0));
1843 ps = layerData.getPipelineState();
1844 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1846 ps.slopeScaledDepthBias = 1.5f;
1848 if (drawPointLightShadowBoxes) {
1854 if (Q_UNLIKELY(drawCulledObjects)) {
1855 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1857 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1858 : theObject->globalBounds;
1859 const QColor color = debugIsObjectCulled[i] ? QColorConstants::Red : QColorConstants::Green;
1866 QSSGPassKey passKey,
1868 QSSGRhiGraphicsPipelineState *ps,
1869 QSSGRenderReflectionMap &reflectionMapManager,
1870 const QVector<QSSGRenderReflectionProbe *> &reflectionProbes,
1871 const QSSGRenderableObjectList &reflectionPassObjects,
1874 QSSGRhiContext *rhiCtx = context.rhiContext().get();
1875 QRhi *rhi = rhiCtx->rhi();
1876 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1878 const bool renderSkybox = (inData.layer.background == QSSGRenderLayer::Background::SkyBox ||
1879 inData.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap)
1880 && rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch);
1882 for (
int i = 0, ie = reflectionProbes.size(); i != ie; ++i) {
1887 if (!pEntry->m_needsRender)
1890 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame && pEntry->m_rendered)
1893 if (reflectionProbes[i]->texture)
1896 Q_ASSERT(pEntry->m_rhiDepthStencil);
1897 Q_ASSERT(pEntry->m_rhiCube);
1899 const QSize size = pEntry->m_rhiCube->pixelSize();
1900 ps->viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1902 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1903 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1904 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1905 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1906 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1907 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1908 setupCubeReflectionCameras(inData, reflectionProbes[i], theCameras);
1909 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1910 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1911 for (
const auto face : QSSGRenderTextureCubeFaces) {
1912 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(face);
1913 cameraGlobalTransform = inData.getGlobalTransform(theCameras[cubeFaceIdx]);
1914 theCameras[cubeFaceIdx].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_viewProjection);
1916 rhiPrepareResourcesForReflectionMap(context, passKey, inData, pEntry, ps, reflectionPassObjects, theCameras[cubeFaceIdx], renderer, face);
1918 QRhiRenderPassDescriptor *renderPassDesc =
nullptr;
1919 for (
auto face : QSSGRenderTextureCubeFaces) {
1920 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1921 face = pEntry->m_timeSliceFace;
1923 QSSGRenderTextureCubeFace outFace = face;
1927 if (outFace == QSSGRenderTextureCubeFace::PosY)
1928 outFace = QSSGRenderTextureCubeFace::NegY;
1929 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1930 outFace = QSSGRenderTextureCubeFace::PosY;
1932 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[quint8(outFace)];
1933 cb->beginPass(rt, reflectionProbes[i]->clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1934 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1935 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1937 if (renderSkybox && pEntry->m_skyBoxSrbs[quint8(face)]) {
1938 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1939 const bool isSkyBox = inData.layer.background == QSSGRenderLayer::Background::SkyBox;
1940 const auto &shaderPipeline = isSkyBox ? shaderCache->getBuiltInRhiShaders().getRhiSkyBoxShader(QSSGRenderLayer::TonemapMode::None, inData.layer.skyBoxIsRgbe8, 1)
1941 : shaderCache->getBuiltInRhiShaders().getRhiSkyBoxCubeShader(QSSGRenderLayer::TonemapMode::None, !inData.layer.skyBoxIsSrgb, 1);
1942 Q_ASSERT(shaderPipeline);
1943 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
1944 QRhiShaderResourceBindings *srb = pEntry->m_skyBoxSrbs[quint8(face)];
1945 if (!renderPassDesc)
1946 renderPassDesc = rt->newCompatibleRenderPassDescriptor();
1947 rt->setRenderPassDescriptor(renderPassDesc);
1948 isSkyBox ? renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, srb, renderPassDesc, {})
1949 : renderer.rhiCubeRenderer()->recordRenderCube(rhiCtx, ps, srb, renderPassDesc, {});
1952 bool needsSetViewport =
true;
1953 for (
const auto &handle : reflectionPassObjects)
1954 rhiRenderRenderable(rhiCtx, *ps, *handle.obj, &needsSetViewport, face);
1957 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1958 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"reflection_cube", 0, outFace));
1960 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1964 renderPassDesc->deleteLater();
1966 pEntry->renderMips(rhiCtx);
1968 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1969 pEntry->m_timeSliceFace = QSSGBaseTypeHelpers::next(pEntry->m_timeSliceFace);
1971 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame)
1972 pEntry->m_rendered =
true;
1974 reflectionProbes[i]->hasScheduledUpdate =
false;
1975 pEntry->m_needsRender =
false;
2026 QSSGPassKey passKey,
2028 QSSGRhiShaderPipeline &shaderPipeline,
2029 QSSGRhiGraphicsPipelineState &ps,
2030 const QSSGAmbientOcclusionSettings &ao,
2031 const QSSGRhiRenderableTexture &rhiAoTexture,
2032 const QSSGRhiRenderableTexture &rhiDepthTexture,
2033 const QSSGRenderCamera &camera)
2035 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2038 if (!rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2039 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
2041 cb->beginPass(rhiAoTexture.rt, Qt::white, { 1.0f, 0 });
2042 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rhiAoTexture.rt));
2044 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
2048 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, &shaderPipeline);
2050 const float R2 = ao.aoDistance * ao.aoDistance * 0.16f;
2051 const QSize textureSize = rhiAoTexture.texture->pixelSize();
2052 const float rw =
float(textureSize.width());
2053 const float rh =
float(textureSize.height());
2054 const float fov = camera.fov.asVerticalFov(rw / rh).radians();
2055 const float tanHalfFovY = tanf(0.5f * fov * (rh / rw));
2056 const float invFocalLenX = tanHalfFovY * (rw / rh);
2058 const QVector4D aoProps(ao.aoStrength * 0.01f, ao.aoDistance * 0.4f, ao.aoSoftness * 0.02f, ao.aoBias);
2059 const QVector4D aoProps2(
float(ao.aoSamplerate), (ao.aoDither) ? 1.0f : 0.0f, 0.0f, 0.0f);
2060 const QVector4D aoScreenConst(1.0f / R2, rh / (2.0f * tanHalfFovY), 1.0f / rw, 1.0f / rh);
2061 const QVector4D uvToEyeConst(2.0f * invFocalLenX, -2.0f * tanHalfFovY, -invFocalLenX, tanHalfFovY);
2062 const QVector2D cameraProps = camera.clipPlanes;
2071 const int UBUF_SIZE = 72;
2072 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ passKey,
nullptr,
nullptr, 0 }));
2074 dcd.ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE);
2078 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2079 memcpy(ubufData, &aoProps, 16);
2080 memcpy(ubufData + 16, &aoProps2, 16);
2081 memcpy(ubufData + 32, &aoScreenConst, 16);
2082 memcpy(ubufData + 48, &uvToEyeConst, 16);
2083 memcpy(ubufData + 64, &cameraProps, 8);
2084 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2086 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2087 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
2088 QSSGRhiShaderResourceBindingList bindings;
2089 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
2092 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiDepthTexture.texture, sampler);
2093 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2095 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
2096 renderer.rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, rhiAoTexture.rt, {});
2244 QSSGPassKey passKey,
2245 QSSGRenderLayer &layer,
2246 QSSGRenderCameraList &cameras,
2250 uint tonemapMode = 0)
2252 QSSG_ASSERT(layer.renderData,
return);
2254 const auto *renderData = layer.renderData;
2256 auto rhiCtx = context.rhiContext().get();
2258 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2260 QSSGRenderImageTexture lightProbeTexture;
2261 switch (layer.background) {
2262 case QSSGRenderLayer::Background::SkyBox:
2263 lightProbeTexture = renderer.contextInterface()->bufferManager()->loadRenderImage(layer.lightProbe,
2264 QSSGBufferManager::MipModeBsdf);
2266 case QSSGRenderLayer::Background::SkyBoxCubeMap:
2267 lightProbeTexture = renderer.contextInterface()->bufferManager()->loadRenderImage(layer.skyBoxCubeMap,
2268 QSSGBufferManager::MipModeDisable);
2270 case QSSGRenderLayer::Background::SkyMaterial:
2271 lightProbeTexture = renderData->skyMaterialTexture;
2274 Q_UNREACHABLE_RETURN();
2277 const bool hasValidInput = (lightProbeTexture.m_texture !=
nullptr);
2279 if (hasValidInput) {
2280 const bool cubeMapMode = layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap;
2282 if (cubeFace == QSSGRenderTextureCubeFaceNone)
2283 layer.skyBoxIsRgbe8 = lightProbeTexture.m_flags.isRgbe8();
2285 layer.skyBoxIsSrgb = !lightProbeTexture.m_flags.isLinear();
2287 QSSGRhiShaderResourceBindingList bindings;
2289 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
2290 QRhiSampler::Linear,
2291 cubeMapMode ? QRhiSampler::None : QRhiSampler::Linear,
2292 QRhiSampler::Repeat,
2293 QRhiSampler::ClampToEdge,
2294 QRhiSampler::Repeat });
2295 int samplerBinding = 1;
2296 bindings.addTexture(samplerBinding, QRhiShaderResourceBinding::FragmentStage, lightProbeTexture.m_texture, sampler);
2298 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2299 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * cubeFaceIdx;
2300 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey,
nullptr, entry, entryIdx });
2302 QRhi *rhi = rhiCtx->rhi();
2303 const quint32 ubufSize = cameras.count() >= 2 ? 416 : 240;
2304 if (!dcd.ubuf || dcd.ubuf->size() != ubufSize) {
2306 dcd.ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer,
int(ubufSize));
2310 float adjustY = rhi->isYUpInNDC() ? 1.0f : -1.0f;
2311 const float exposure = layer.lightProbeSettings.probeExposure;
2313 const QMatrix3x3 &rotationMatrix(layer.lightProbeSettings.probeOrientation);
2316 const float blurAmountOrSrgb = cubeMapMode ? layer.skyBoxIsSrgb : layer.skyboxBlurAmount;
2317 const float maxMipLevelOrTonemapMode = cubeMapMode ?
float(tonemapMode) :
float(lightProbeTexture.m_mipmapCount - 2);
2319 const QVector4D skyboxProperties = {
2323 maxMipLevelOrTonemapMode
2326 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2327 quint32 ubufOffset = 0;
2329 memcpy(ubufData + ubufOffset, &skyboxProperties, 16);
2332 memcpy(ubufData + ubufOffset, rotationMatrix.constData(), 12);
2334 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 12, 12);
2336 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 24, 12);
2339 for (qsizetype viewIdx = 0; viewIdx < cameras.count(); ++viewIdx) {
2340 const QMatrix4x4 &inverseProjection = cameras[viewIdx]->projection.inverted();
2341 const QMatrix4x4 &viewMatrix = renderData->getGlobalTransform(*cameras[viewIdx]);
2342 QMatrix4x4 viewProjection(Qt::Uninitialized);
2343 cameras[viewIdx]->calculateViewProjectionWithoutTranslation(viewMatrix, 0.1f, 5.0f, viewProjection);
2345 quint32 viewDataOffset = ubufOffset;
2346 memcpy(ubufData + viewDataOffset + viewIdx * 64, viewProjection.constData(), 64);
2347 viewDataOffset += cameras.count() * 64;
2348 memcpy(ubufData + viewDataOffset + viewIdx * 64, inverseProjection.constData(), 64);
2349 viewDataOffset += cameras.count() * 64;
2350 memcpy(ubufData + viewDataOffset + viewIdx * 48, viewMatrix.constData(), 48);
2352 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2354 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
2356 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
2357 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2358 entry->m_skyBoxSrbs[cubeFaceIdx] = rhiCtxD->srb(bindings);
2360 layer.skyBoxSrb = rhiCtxD->srb(bindings);
2364 renderer.rhiCubeRenderer()->prepareCube(rhiCtx,
nullptr);
2366 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
2406 QSSGPassKey passKey,
2407 const QSSGRhiGraphicsPipelineState &basePipelineState,
2408 QRhiRenderPassDescriptor *rpDesc,
2410 const QSSGRenderableObjectList &sortedOpaqueObjects,
2411 const QSSGRenderableObjectList &sortedTransparentObjects,
2415 static const auto rhiPrepareDepthPassForObject = [](QSSGRhiContext *rhiCtx,
2416 QSSGPassKey passKey,
2419 QRhiRenderPassDescriptor *rpDesc,
2420 QSSGRhiGraphicsPipelineState *ps) {
2421 QSSGRhiShaderPipelinePtr shaderPipeline;
2422 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2424 const bool isOpaqueDepthPrePass = obj->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
2425 QSSGShaderFeatures featureSet;
2426 featureSet.set(QSSGShaderFeatures::Feature::DepthPass,
true);
2427 if (isOpaqueDepthPrePass)
2428 featureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
2430 QSSGRhiDrawCallData *dcd =
nullptr;
2431 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2432 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2433 const void *modelNode = &subsetRenderable.modelContext.model;
2434 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
2437 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2438 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2439 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2440 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2442 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
2443 if (shaderPipeline) {
2444 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2445 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2446 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2447 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2451 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2452 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2454 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2456 ps->cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2458 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
2459 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2461 if (shaderPipeline) {
2462 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2463 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2464 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, customMaterial, subsetRenderable,
2465 inData.renderedCameras,
nullptr,
nullptr);
2466 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2473 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2474 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2475 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
2476 ia = subsetRenderable.subset.rhi.ia;
2478 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2479 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2480 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2482 QSSGRhiShaderResourceBindingList bindings;
2483 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2486 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2488 if (isOpaqueDepthPrePass) {
2489 addOpaqueDepthPrePassBindings(rhiCtx,
2490 shaderPipeline.get(),
2491 subsetRenderable.firstImage,
2493 (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
2499 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2500 if (normalTextureBinding >= 0) {
2501 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2502 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2503 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2504 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2505 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2506 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2510 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2511 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2513 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2514 QRhiSampler::Nearest,
2516 QRhiSampler::ClampToEdge,
2517 QRhiSampler::ClampToEdge,
2520 bindings.addTexture(binding,
2521 QRhiShaderResourceBinding::VertexStage,
2528 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2529 if (targetsTexture) {
2530 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2532 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2533 QRhiSampler::Nearest,
2535 QRhiSampler::ClampToEdge,
2536 QRhiSampler::ClampToEdge,
2537 QRhiSampler::ClampToEdge
2539 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2543 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2545 subsetRenderable.rhiRenderData.depthPrePass.pipeline = rhiCtxD->pipeline(*ps,
2548 subsetRenderable.rhiRenderData.depthPrePass.srb = srb;
2559 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2564 ps.samples = samples;
2565 ps.viewCount = viewCount;
2566 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
2567 ps.targetBlend[0].colorWrite = {};
2569 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2570 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2574 for (
const QSSGRenderableObjectHandle &handle : sortedTransparentObjects) {
2575 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2702 QSSGPassKey passKey,
2703 const QSSGRhiGraphicsPipelineState &basePipelineState,
2704 QRhiRenderPassDescriptor *rpDesc,
2706 const QSSGRenderableObjectList &sortedOpaqueObjects)
2708 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2709 ps.depthFunc = QRhiGraphicsPipeline::LessOrEqual;
2710 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
2712 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2713 QSSGRenderableObject *obj = handle.obj;
2714 QSSGRhiShaderPipelinePtr shaderPipeline;
2715 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2717 QSSGShaderFeatures featureSet;
2718 featureSet.set(QSSGShaderFeatures::Feature::NormalPass,
true);
2720 QSSGRhiDrawCallData *dcd =
nullptr;
2721 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2722 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2723 const void *modelNode = &subsetRenderable.modelContext.model;
2724 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
2727 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2728 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2729 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2730 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2732 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
2733 if (shaderPipeline) {
2734 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2735 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2736 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2737 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2739 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2740 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2742 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2744 ps.cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2746 const auto &customMaterialSystem = subsetRenderable.renderer->contextInterface()->customMaterialSystem();
2747 shaderPipeline = customMaterialSystem->shadersForCustomMaterial(&ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2749 if (shaderPipeline) {
2750 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2751 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2752 customMaterialSystem->updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, customMaterial, subsetRenderable,
2753 inData.renderedCameras,
nullptr,
nullptr);
2754 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2759 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2760 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2761 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
2762 ia = subsetRenderable.subset.rhi.ia;
2764 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2765 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2766 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2768 QSSGRhiShaderResourceBindingList bindings;
2769 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2772 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
2773 while (renderableImage) {
2774 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
2775 const int samplerHint =
int(renderableImage->m_mapType);
2776 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
2777 if (samplerBinding >= 0) {
2778 QRhiTexture *texture = renderableImage->m_texture.m_texture;
2779 if (samplerBinding >= 0 && texture) {
2780 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
2781 QSSGRhiSamplerDescription samplerDesc = {
2782 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
2783 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
2784 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
2785 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
2786 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
2787 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
2789 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
2790 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
2791 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
2794 renderableImage = renderableImage->m_nextImage;
2797 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2800 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2801 if (normalTextureBinding >= 0) {
2802 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2803 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2804 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2805 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2806 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2807 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2813 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2814 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2816 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2817 QRhiSampler::Nearest,
2819 QRhiSampler::ClampToEdge,
2820 QRhiSampler::ClampToEdge,
2823 bindings.addTexture(binding,
2824 QRhiShaderResourceBinding::VertexStage,
2831 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2832 if (targetsTexture) {
2833 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2835 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2836 QRhiSampler::Nearest,
2838 QRhiSampler::ClampToEdge,
2839 QRhiSampler::ClampToEdge,
2840 QRhiSampler::ClampToEdge
2842 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2846 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2848 subsetRenderable.rhiRenderData.normalPass.pipeline = rhiCtxD->pipeline(ps,
2851 subsetRenderable.rhiRenderData.normalPass.srb = srb;
2920 QSSGPassKey passKey,
2921 const QSSGRhiGraphicsPipelineState &basePipelineState,
2922 QRhiRenderPassDescriptor *rpDesc,
2923 QSSGRenderGraphObject *overrideMaterial,
2925 QSSGRenderableObjectList &inObjects,
2926 QSSGShaderFeatures featureSet)
2929 const qsizetype index = overrideMaterial ? inData.getUserRenderPassManager()->acquireUserPassSlot() : -1;
2934 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2935 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2937 const bool isCustomMaterial = (overrideMaterial->type == QSSGRenderGraphObject::Type::CustomMaterial);
2938 const bool isDefaultMaterial = (overrideMaterial->type == QSSGRenderGraphObject::Type::DefaultMaterial ||
2939 overrideMaterial->type == QSSGRenderGraphObject::Type::PrincipledMaterial ||
2940 overrideMaterial->type == QSSGRenderGraphObject::Type::SpecularGlossyMaterial);
2942 if (!isCustomMaterial && !isDefaultMaterial) {
2943 qDebug() <<
"Override material must be a default or custom material.";
2947 for (
const QSSGRenderableObjectHandle &handle : std::as_const(inObjects)) {
2948 QSSGRenderableObject *obj = handle.obj;
2950 if (obj->type != QSSGRenderableObject::Type::DefaultMaterialMeshSubset &&
2951 obj->type != QSSGRenderableObject::Type::CustomMaterialMeshSubset)
2954 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2955 const void *modelNode = &subsetRenderable.modelContext.model;
2956 QSSGRhiDrawCallData *dcd = &rhiCtxD->drawCallData({ passKey, modelNode, overrideMaterial, 0 });
2962 QSSGRenderableObjectFlags renderableFlags = subsetRenderable.renderableFlags;
2963 float opacity = subsetRenderable.opacity;
2966 const bool hasAnyLights = !subsetRenderable.lights.isEmpty();
2967 const bool anyLightHasShadows = std::any_of(subsetRenderable.lights.begin(),
2968 subsetRenderable.lights.end(),
2969 [](
const QSSGShaderLight &light) {
return light.shadows; });
2973 auto layerPrepFlags = inData.layerPrepResult.getFlags();
2975 if (isCustomMaterial) {
2976 auto &material =
static_cast<QSSGRenderCustomMaterial &>(*overrideMaterial);
2977 auto prepResult = inData.prepareCustomMaterialForRender(material, renderableFlags, opacity,
2978 false, hasAnyLights, anyLightHasShadows,
2980 subsetRenderable.shaderDescription = prepResult.materialKey;
2982 auto &material =
static_cast<QSSGRenderDefaultMaterial &>(*overrideMaterial);
2983 auto prepResult = inData.prepareDefaultMaterialForRender(material, renderableFlags, opacity,
2984 hasAnyLights, anyLightHasShadows,
2986 subsetRenderable.shaderDescription = prepResult.materialKey;
2990 QSSGRhiShaderPipelinePtr shaderPipeline;
2992 if (isCustomMaterial) {
2993 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(*overrideMaterial);
2994 if (!ps.userSetCullMode)
2995 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
2997 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
2998 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable,
2999 inData.getDefaultMaterialPropertyTable(), featureSet);
3000 if (shaderPipeline) {
3001 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3002 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3003 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3004 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3005 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3008 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(*overrideMaterial);
3009 if (!ps.userSetCullMode)
3010 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3012 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
3013 if (shaderPipeline) {
3014 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3015 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3016 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable,
3017 inData.renderedCameras,
nullptr,
nullptr, overrideMaterial);
3018 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3022 if (!shaderPipeline)
3025 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3026 ia = subsetRenderable.subset.rhi.ia;
3028 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3029 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3030 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3032 QSSGRhiShaderResourceBindingList bindings;
3033 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3036 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3037 while (renderableImage) {
3038 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3039 const int samplerHint =
int(renderableImage->m_mapType);
3040 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3041 if (samplerBinding >= 0) {
3042 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3044 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3045 QSSGRhiSamplerDescription samplerDesc = {
3046 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3047 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3048 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3049 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3050 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3051 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3053 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3054 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3055 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3058 renderableImage = renderableImage->m_nextImage;
3061 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3064 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3065 if (normalTextureBinding >= 0) {
3066 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3067 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3068 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3069 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3070 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3071 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3075 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3076 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3078 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3079 QRhiSampler::Nearest,
3081 QRhiSampler::ClampToEdge,
3082 QRhiSampler::ClampToEdge,
3085 bindings.addTexture(binding,
3086 QRhiShaderResourceBinding::VertexStage,
3093 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3094 if (targetsTexture) {
3095 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3097 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3098 QRhiSampler::Nearest,
3100 QRhiSampler::ClampToEdge,
3101 QRhiSampler::ClampToEdge,
3102 QRhiSampler::ClampToEdge
3104 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3109 if (shaderPipeline->isLightingEnabled()) {
3110 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3111 shaderPipeline->ub0LightDataOffset(),
3112 sizeof(QSSGShaderLightsUniformData));
3113 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3114 shaderPipeline->ub0DirectionalLightDataOffset(),
3115 sizeof(QSSGShaderDirectionalLightsUniformData));
3118 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3119 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3122 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3123 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
3124 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3127 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3128 QRhiSampler::Linear,
3130 QRhiSampler::ClampToEdge,
3131 QRhiSampler::ClampToEdge,
3132 QRhiSampler::Repeat });
3134 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3138 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3139 QRhiTexture *texture = shaderPipeline->shadowMapBlueNoiseTexture();
3142 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3143 texture = rhiCtx->dummyTexture({ }, resourceUpdates);
3144 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3147 QRhiSampler *sampler = rhiCtx->sampler(
3148 { QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3150 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3154 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3156 auto texture = shaderPipeline->lightProbeTexture();
3158 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3159 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
3160 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3164 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
3165 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3166 QRhiSampler::Linear,
3167 QRhiSampler::Linear,
3168 QSSGRhiHelpers::toRhi(tiling.first),
3169 QSSGRhiHelpers::toRhi(tiling.second),
3170 QRhiSampler::Repeat });
3171 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3175 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3177 QSSG_ASSERT(srb,
continue);
3178 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3179 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3180 rhiPassData.srb = srb;
3187 QSSGPassKey passKey,
3188 const QSSGRhiGraphicsPipelineState &basePipelineState,
3189 QRhiRenderPassDescriptor *rpDesc,
3191 QSSGRenderableObjectList &inObjects,
3192 QSSGShaderFeatures featureSet)
3194 const qsizetype index = inData.getUserRenderPassManager()->acquireUserPassSlot();
3199 QSSGRhiGraphicsPipelineState ps = basePipelineState;
3200 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3202 for (
const QSSGRenderableObjectHandle &handle : std::as_const(inObjects)) {
3203 QSSGRenderableObject *obj = handle.obj;
3204 QSSGRhiShaderPipelinePtr shaderPipeline;
3206 QSSGRhiDrawCallData *dcd =
nullptr;
3207 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset ||
3208 obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3209 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3210 const void *modelNode = &subsetRenderable.modelContext.model;
3211 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
3214 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
3215 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3216 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
3217 if (!ps.userSetCullMode)
3218 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3220 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
3221 if (shaderPipeline) {
3222 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3223 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3224 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable,
3225 inData.renderedCameras,
nullptr,
nullptr);
3226 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3228 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3229 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3230 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
3231 if (!ps.userSetCullMode)
3232 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
3234 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
3235 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable,
3236 inData.getDefaultMaterialPropertyTable(), featureSet);
3237 if (shaderPipeline) {
3238 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3239 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3240 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3241 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3242 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3246 if (!shaderPipeline)
3250 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset ||
3251 obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3252 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
3253 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3254 ia = subsetRenderable.subset.rhi.ia;
3256 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3257 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3258 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3260 QSSGRhiShaderResourceBindingList bindings;
3261 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3264 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3265 while (renderableImage) {
3266 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3267 const int samplerHint =
int(renderableImage->m_mapType);
3268 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3269 if (samplerBinding >= 0) {
3270 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3271 if (samplerBinding >= 0 && texture) {
3272 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3273 QSSGRhiSamplerDescription samplerDesc = {
3274 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3275 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3276 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3277 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3278 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3279 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3281 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3282 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3283 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3286 renderableImage = renderableImage->m_nextImage;
3289 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3292 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3293 if (normalTextureBinding >= 0) {
3294 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3295 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3296 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3297 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3298 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3299 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3303 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3304 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3306 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3307 QRhiSampler::Nearest,
3309 QRhiSampler::ClampToEdge,
3310 QRhiSampler::ClampToEdge,
3313 bindings.addTexture(binding,
3314 QRhiShaderResourceBinding::VertexStage,
3321 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3322 if (targetsTexture) {
3323 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3325 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3326 QRhiSampler::Nearest,
3328 QRhiSampler::ClampToEdge,
3329 QRhiSampler::ClampToEdge,
3330 QRhiSampler::ClampToEdge
3332 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3337 if (shaderPipeline->isLightingEnabled()) {
3338 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3339 shaderPipeline->ub0LightDataOffset(),
3340 sizeof(QSSGShaderLightsUniformData));
3341 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3342 shaderPipeline->ub0DirectionalLightDataOffset(),
3343 sizeof(QSSGShaderDirectionalLightsUniformData));
3346 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3347 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3350 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3351 texture = rhiCtx->dummyTexture({ }, resourceUpdates);
3352 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3355 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3356 QRhiSampler::Linear,
3358 QRhiSampler::ClampToEdge,
3359 QRhiSampler::ClampToEdge,
3360 QRhiSampler::Repeat });
3362 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3366 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3367 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
3368 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
3370 QRhiTexture *texture = shadowMapBlueNoise;
3371 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3372 QRhiSampler::Linear,
3374 QRhiSampler::Repeat,
3375 QRhiSampler::Repeat,
3376 QRhiSampler::Repeat });
3377 Q_ASSERT(texture && sampler);
3378 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3381 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3382 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
3383 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3384 QRhiSampler::Linear,
3386 QRhiSampler::Repeat,
3387 QRhiSampler::Repeat,
3388 QRhiSampler::Repeat });
3389 Q_ASSERT(texture && sampler);
3390 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3391 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3396 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
3397 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
3398 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
3399 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
3400 ? QRhiSampler::Linear
3401 : QRhiSampler::None;
3402 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3403 QRhiSampler::Linear,
3405 QRhiSampler::ClampToEdge,
3406 QRhiSampler::ClampToEdge,
3407 QRhiSampler::Repeat });
3408 if (reflectionSampler >= 0 && reflectionTexture)
3409 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
3412 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3414 auto texture = shaderPipeline->lightProbeTexture();
3416 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3417 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
3418 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3422 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
3423 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3424 QRhiSampler::Linear,
3425 QRhiSampler::Linear,
3426 QSSGRhiHelpers::toRhi(tiling.first),
3427 QSSGRhiHelpers::toRhi(tiling.second),
3428 QRhiSampler::Repeat });
3429 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3433 if (shaderPipeline->screenTexture()) {
3434 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
3435 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
3436 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
3437 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
3438 ? QRhiSampler::Linear : QRhiSampler::None;
3439 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
3440 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3441 if (screenTextureBinding >= 0) {
3442 bindings.addTexture(screenTextureBinding,
3443 QRhiShaderResourceBinding::FragmentStage,
3444 shaderPipeline->screenTexture(), sampler);
3446 if (screenTextureArrayBinding >= 0) {
3447 bindings.addTexture(screenTextureArrayBinding,
3448 QRhiShaderResourceBinding::FragmentStage,
3449 shaderPipeline->screenTexture(), sampler);
3454 if (shaderPipeline->lightmapTexture()) {
3455 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
3457 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
3458 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
3459 bindings.addTexture(binding,
3460 QRhiShaderResourceBinding::FragmentStage,
3461 shaderPipeline->lightmapTexture(), sampler);
3468 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3469 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3471 int maxSamplerBinding = -1;
3472 QVector<QShaderDescription::InOutVariable> samplerVars =
3473 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
3474 const auto combinedSamplers = shaderPipeline->vertexStage()->shader().description().combinedImageSamplers();
3475 for (
const QShaderDescription::InOutVariable &var : combinedSamplers) {
3476 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
3477 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
3478 if (it == samplerVars.cend())
3479 samplerVars.append(var);
3482 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
3483 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
3485 if (maxSamplerBinding >= 0) {
3486 int extraTexCount = shaderPipeline->extraTextureCount();
3487 for (
int i = 0; i < extraTexCount; ++i) {
3488 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
3489 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
3490 if (samplerBinding >= 0) {
3491 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
3492 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
3493 bindings.addTexture(samplerBinding,
3494 QRhiShaderResourceBinding::FragmentStage,
3502 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3504 QSSG_ASSERT(srb,
continue);
3506 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3507 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3508 rhiPassData.srb = srb;
3517 QSSGPassKey passKey,
3518 const QSSGRhiGraphicsPipelineState &basePipelineState,
3519 QRhiRenderPassDescriptor *rpDesc,
3522 QSSGRenderableObjectList &inObjects,
3523 QSSGShaderFeatures featureSet)
3525 const qsizetype index = inData.getUserRenderPassManager()->acquireUserPassSlot();
3531 QSSGRhiGraphicsPipelineState ps = basePipelineState;
3532 for (
const QSSGRenderableObjectHandle &handle : std::as_const(inObjects)) {
3533 QSSGRenderableObject *obj = handle.obj;
3534 QSSGRhiShaderPipelinePtr shaderPipeline;
3535 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3536 const auto &bufferManager = inData.contextInterface()->bufferManager();
3538 featureSet.set(QSSGShaderFeatures::Feature::UserRenderPass,
true);
3540 QSSGRhiDrawCallData *dcd =
nullptr;
3541 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3542 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3543 const void *modelNode = &subsetRenderable.modelContext.model;
3544 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
3547 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
3548 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3549 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
3550 if (!ps.userSetCullMode)
3551 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3553 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet, shaderAugmentation);
3554 if (shaderPipeline) {
3555 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3556 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3558 for (
const auto &u : shaderAugmentation.propertyUniforms)
3559 shaderPipeline->setShaderResources(ubufData, *bufferManager, u.name, u.value, u.shaderDataType);
3560 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3561 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3563 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3564 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3565 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
3566 if (!ps.userSetCullMode)
3567 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
3569 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
3571 if (material.m_shadingMode == QSSGRenderCustomMaterial::ShadingMode::Unshaded)
3572 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
3574 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet, shaderAugmentation);
3576 if (shaderPipeline) {
3577 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3578 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3580 for (
const auto &u : shaderAugmentation.propertyUniforms)
3581 shaderPipeline->setShaderResources(ubufData, *bufferManager, u.name, u.value, u.shaderDataType);
3582 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3583 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3584 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3588 if (!shaderPipeline) {
3590 qDebug() <<
"Failed to prepare user augmented pass for object.";
3595 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3596 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
3597 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3598 ia = subsetRenderable.subset.rhi.ia;
3600 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3601 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3602 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3604 QSSGRhiShaderResourceBindingList bindings;
3605 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3608 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3609 while (renderableImage) {
3610 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3611 const int samplerHint =
int(renderableImage->m_mapType);
3612 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3613 if (samplerBinding >= 0) {
3614 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3615 if (samplerBinding >= 0 && texture) {
3616 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3617 QSSGRhiSamplerDescription samplerDesc = {
3618 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3619 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3620 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3621 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3622 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3623 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3625 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3626 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3627 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3630 renderableImage = renderableImage->m_nextImage;
3633 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3636 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3637 if (normalTextureBinding >= 0) {
3638 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3639 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3640 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3641 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3642 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3643 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3649 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3650 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3652 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3653 QRhiSampler::Nearest,
3655 QRhiSampler::ClampToEdge,
3656 QRhiSampler::ClampToEdge,
3659 bindings.addTexture(binding,
3660 QRhiShaderResourceBinding::VertexStage,
3667 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3668 if (targetsTexture) {
3669 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3671 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3672 QRhiSampler::Nearest,
3674 QRhiSampler::ClampToEdge,
3675 QRhiSampler::ClampToEdge,
3676 QRhiSampler::ClampToEdge
3678 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3683 if (shaderPipeline->isLightingEnabled()) {
3684 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3685 shaderPipeline->ub0LightDataOffset(),
3686 sizeof(QSSGShaderLightsUniformData));
3687 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3688 shaderPipeline->ub0DirectionalLightDataOffset(),
3689 sizeof(QSSGShaderDirectionalLightsUniformData));
3692 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3693 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3696 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3697 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
3698 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3701 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3702 QRhiSampler::Linear,
3704 QRhiSampler::ClampToEdge,
3705 QRhiSampler::ClampToEdge,
3706 QRhiSampler::Repeat });
3708 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3712 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3713 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
3714 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
3716 QRhiTexture *texture = shadowMapBlueNoise;
3717 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3718 QRhiSampler::Linear,
3720 QRhiSampler::Repeat,
3721 QRhiSampler::Repeat,
3722 QRhiSampler::Repeat });
3723 Q_ASSERT(texture && sampler);
3724 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3727 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3728 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
3729 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3730 QRhiSampler::Linear,
3732 QRhiSampler::Repeat,
3733 QRhiSampler::Repeat,
3734 QRhiSampler::Repeat });
3735 Q_ASSERT(texture && sampler);
3736 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3737 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3744 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
3745 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
3746 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
3747 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
3748 ? QRhiSampler::Linear
3749 : QRhiSampler::None;
3750 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3751 QRhiSampler::Linear,
3753 QRhiSampler::ClampToEdge,
3754 QRhiSampler::ClampToEdge,
3755 QRhiSampler::Repeat });
3756 if (reflectionSampler >= 0 && reflectionTexture)
3757 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
3759 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3761 auto texture = shaderPipeline->lightProbeTexture();
3763 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3764 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
3765 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3769 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
3770 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3771 QRhiSampler::Linear,
3772 QRhiSampler::Linear,
3773 QSSGRhiHelpers::toRhi(tiling.first),
3774 QSSGRhiHelpers::toRhi(tiling.second),
3775 QRhiSampler::Repeat });
3776 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3780 if (shaderPipeline->screenTexture()) {
3781 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
3782 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
3783 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
3788 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
3789 ? QRhiSampler::Linear : QRhiSampler::None;
3790 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
3791 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3792 if (screenTextureBinding >= 0) {
3793 bindings.addTexture(screenTextureBinding,
3794 QRhiShaderResourceBinding::FragmentStage,
3795 shaderPipeline->screenTexture(), sampler);
3797 if (screenTextureArrayBinding >= 0) {
3798 bindings.addTexture(screenTextureArrayBinding,
3799 QRhiShaderResourceBinding::FragmentStage,
3800 shaderPipeline->screenTexture(), sampler);
3805 if (shaderPipeline->lightmapTexture()) {
3806 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
3808 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
3809 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
3810 bindings.addTexture(binding,
3811 QRhiShaderResourceBinding::FragmentStage,
3812 shaderPipeline->lightmapTexture(), sampler);
3819 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3820 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3822 QVector<QShaderDescription::InOutVariable> samplerVars =
3823 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
3824 const auto combinedSamplers = shaderPipeline->vertexStage()->shader().description().combinedImageSamplers();
3825 for (
const QShaderDescription::InOutVariable &var : combinedSamplers) {
3826 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
3827 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
3828 if (it == samplerVars.cend())
3829 samplerVars.append(var);
3832 int maxSamplerBinding = -1;
3833 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
3834 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
3843 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
3845 if (maxSamplerBinding >= 0) {
3847 int extraTexCount = shaderPipeline->extraTextureCount();
3848 for (
int i = 0; i < extraTexCount; ++i) {
3849 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
3850 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
3851 if (samplerBinding >= 0) {
3852 samplerBindingsSpecified.setBit(samplerBinding);
3853 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
3854 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
3855 bindings.addTexture(samplerBinding,
3856 QRhiShaderResourceBinding::FragmentStage,
3864 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3865 QSSG_ASSERT(srb,
return -1);
3866 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3867 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3868 rhiPassData.srb = srb;
3932 QSSGPassKey passKey,
3934 const QMatrix4x4 &viewProjection,
3936 QRhiRenderPassDescriptor *renderPassDescriptor,
3937 QSSGRhiGraphicsPipelineState *ps,
3938 QSSGRenderMotionVectorMap &motionVectorMapManager)
3940 if (inObject.type != QSSGRenderableObject::Type::DefaultMaterialMeshSubset &&
3941 inObject.type != QSSGRenderableObject::Type::CustomMaterialMeshSubset)
3944 QSSGSubsetRenderable &subsetRenderable =
static_cast<QSSGSubsetRenderable &>(inObject);
3945 auto &modelNode = subsetRenderable.modelContext.model;
3947 bool skin = modelNode.usesBoneTexture();
3948 bool instance = modelNode.instanceCount() > 0;
3949 bool morph = modelNode.morphTargets.size() > 0;
3951 QSSGRhiShaderPipelinePtr shaderPipeline = inData.contextInterface()->shaderCache()->
3952 getBuiltInRhiShaders().getRhiMotionVectorShader(skin, instance, morph);
3954 if (!shaderPipeline)
3957 QSSGRhiShaderResourceBindingList bindings;
3959 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3960 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey, &modelNode,
nullptr, 0 });
3963 QSSGRenderTextureData *boneTextureData =
nullptr;
3965 boneTextureData = modelNode.skin;
3966 else if (modelNode.skeleton)
3967 boneTextureData = &modelNode.skeleton->boneTexData;
3969 QMatrix4x4 modelViewProjection = subsetRenderable.modelContext.modelViewProjections[0];
3970 QMatrix4x4 instanceLocal;
3971 QMatrix4x4 instanceGlobal;
3974 instanceLocal = inData.getInstanceTransforms(modelNode).local;
3975 instanceGlobal = inData.getInstanceTransforms(modelNode).global;
3977 modelViewProjection = viewProjection;
3979 auto motionData = motionVectorMapManager.trackMotionData(&modelNode,
3980 modelViewProjection,
3984 modelNode.instanceTable,
3985 modelNode.morphWeights);
3986 float velocityAmount = subsetRenderable.modelContext.model.motionVectorScale;
3987 int morphTargetCount = modelNode.morphWeights.count();
3999 const int ubufSize = 416;
4002 dcd.ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic,
4003 QRhiBuffer::UniformBuffer,
4008 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
4010 memcpy(ubufData, modelViewProjection.constData(), 64);
4012 memcpy(ubufData + ubufOffset, motionData.prevModelViewProjection.constData(), 64);
4014 memcpy(ubufData + ubufOffset, instanceLocal.constData(), 64);
4016 memcpy(ubufData + ubufOffset, instanceGlobal.constData(), 64);
4018 memcpy(ubufData + ubufOffset, motionData.prevInstanceLocal.constData(), 64);
4020 memcpy(ubufData + ubufOffset, motionData.prevInstanceGlobal.constData(), 64);
4022 memcpy(ubufData + ubufOffset, &inData.layer.currentAndLastJitter, 16);
4024 memcpy(ubufData + ubufOffset, &velocityAmount, 4);
4026 memcpy(ubufData + ubufOffset, &morphTargetCount, 4);
4027 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
4029 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::VertexStage |
4030 QRhiShaderResourceBinding::FragmentStage, dcd.ubuf);
4032 QRhiSampler *nearestSampler =
nullptr;
4034 if (skin || instance) {
4035 nearestSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
4036 QRhiSampler::Nearest,
4038 QRhiSampler::ClampToEdge,
4039 QRhiSampler::ClampToEdge,
4045 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
4048 bindings.addTexture(binding,
4049 QRhiShaderResourceBinding::VertexStage,
4050 inData.getBonemapTexture(subsetRenderable.modelContext),
4052 binding = shaderPipeline->bindingForTexture(
"lastBoneTexture");
4054 bindings.addTexture(binding,
4055 QRhiShaderResourceBinding::VertexStage,
4056 motionData.prevBoneTexture.m_texture,
4063 int binding = shaderPipeline->bindingForTexture(
"lastInstanceTexture");
4065 bindings.addTexture(binding,
4066 QRhiShaderResourceBinding::VertexStage,
4067 motionData.prevInstanceTexture.m_texture,
4072 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
4073 if (targetsTexture) {
4074 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
4076 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
4077 QRhiSampler::Nearest,
4079 QRhiSampler::ClampToEdge,
4080 QRhiSampler::ClampToEdge,
4081 QRhiSampler::ClampToEdge
4083 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
4085 if ((binding = shaderPipeline->bindingForTexture(
"morphWeightTexture")) >= 0)
4086 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, motionData.currentMorphWeightTexture.m_texture, targetsSampler);
4088 if ((binding = shaderPipeline->bindingForTexture(
"lastMorphWeightTexture")) >= 0)
4089 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, motionData.prevMorphWeightTexture.m_texture, targetsSampler);
4093 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
4094 ia = subsetRenderable.subset.rhi.ia;
4095 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
4096 QVector3D cameraDirection = cameraDatas[0].direction;
4097 QVector3D cameraPosition = cameraDatas[0].position;
4098 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDirection, cameraPosition);
4099 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
4100 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
4102 QRhiShaderResourceBindings *&srb = dcd.srb;
4103 bool srbChanged =
false;
4104 if (!srb || bindings != dcd.bindings) {
4105 srb = rhiCtxD->srb(bindings);
4106 rhiCtxD->releaseCachedSrb(dcd.bindings);
4107 dcd.bindings = bindings;
4111 subsetRenderable.rhiRenderData.motionVectorPass.srb = srb;
4113 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
4116 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
4117 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
4120 subsetRenderable.rhiRenderData.motionVectorPass.pipeline = dcd.pipeline;
4123 subsetRenderable.rhiRenderData.motionVectorPass.pipeline = rhiCtxD->pipeline(pipelineKey,
4124 renderPassDescriptor,
4126 dcd.pipeline = subsetRenderable.rhiRenderData.motionVectorPass.pipeline;
4127 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
4128 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;