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);
709 QSSGRhiGraphicsPipelineState *ps,
710 const QVector2D *depthAdjust,
711 const QSSGRenderableObjectList &sortedOpaqueObjects,
712 QSSGRenderCamera &inCamera,
714 QSSGRenderTextureCubeFace cubeFace,
715 quint32 cascadeIndex)
717 QSSGShaderFeatures featureSet;
719 featureSet.set(QSSGShaderFeatures::Feature::OrthoShadowPass,
true);
721 featureSet.set(QSSGShaderFeatures::Feature::PerspectiveShadowPass,
true);
727 featureSet.set(QSSGShaderFeatures::Feature::DisableMultiView,
true);
729 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
730 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
731 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
733 for (
const auto &handle : sortedOpaqueObjects) {
734 QSSGRenderableObject *theObject = handle.obj;
735 QSSG_ASSERT(theObject->renderableFlags.castsShadows(),
continue);
737 QSSGShaderFeatures objectFeatureSet = featureSet;
738 const bool isOpaqueDepthPrePass = theObject->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
739 if (isOpaqueDepthPrePass)
740 objectFeatureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
742 QSSGRhiDrawCallData *dcd =
nullptr;
743 QMatrix4x4 modelViewProjection;
744 QSSGSubsetRenderable &renderable(
static_cast<QSSGSubsetRenderable &>(*theObject));
745 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
746 const bool hasSkinning = defaultMaterialShaderKeyProperties.m_boneCount.getValue(renderable.shaderDescription) > 0;
747 modelViewProjection = hasSkinning ? pEntry->m_lightViewProjection[cascadeIndex]
748 : pEntry->m_lightViewProjection[cascadeIndex] * renderable.modelContext.globalTransform;
752 const quintptr entryIdx = cascadeIndex + cubeFaceIdx + (quintptr(renderable.subset.offset) << 3);
753 dcd = &rhiCtxD->drawCallData({ passKey, &renderable.modelContext.model, pEntry, entryIdx });
756 QSSGRhiShaderResourceBindingList bindings;
757 QSSGRhiShaderPipelinePtr shaderPipeline;
758 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*theObject));
759 if (theObject->type == QSSGSubsetRenderable::Type::DefaultMaterialMeshSubset) {
760 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
761 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
762 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(subsetRenderable.shaderDescription);
764 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, objectFeatureSet);
767 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
768 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
770 QSSGRenderCameraList cameras({ &inCamera });
771 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, cameras, depthAdjust, &modelViewProjection);
773 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &subsetRenderable.modelContext.model, subsetRenderable.subset.offset);
774 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
776 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &subsetRenderable.modelContext.model);
777 }
else if (theObject->type == QSSGSubsetRenderable::Type::CustomMaterialMeshSubset) {
778 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
779 ps->cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
781 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
782 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), objectFeatureSet);
785 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
786 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
788 QSSGRenderCameraList cameras({ &inCamera });
789 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, material, subsetRenderable,
790 cameras, depthAdjust, &modelViewProjection);
791 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
794 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
796 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
797 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
798 ia = subsetRenderable.subset.rhi.ia;
799 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
800 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
801 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
804 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
807 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
809 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
811 if (isOpaqueDepthPrePass) {
812 addOpaqueDepthPrePassBindings(rhiCtx,
813 shaderPipeline.get(),
814 subsetRenderable.firstImage,
816 (theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
823 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
824 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
825 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
826 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
827 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
828 if (screenTextureBinding >= 0) {
829 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
830 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
831 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
832 bindings.addTexture(screenTextureBinding,
833 QRhiShaderResourceBinding::FragmentStage,
834 dummyTexture, sampler);
836 if (screenTextureArrayBinding >= 0) {
837 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
838 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates, QSize(64, 64), Qt::black, inData.layer.viewCount);
839 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
840 bindings.addTexture(screenTextureArrayBinding,
841 QRhiShaderResourceBinding::FragmentStage,
842 dummyTexture, sampler);
847 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
848 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
850 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
851 QRhiSampler::Nearest,
853 QRhiSampler::ClampToEdge,
854 QRhiSampler::ClampToEdge,
857 bindings.addTexture(binding,
858 QRhiShaderResourceBinding::VertexStage,
865 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
866 if (targetsTexture) {
867 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
869 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
870 QRhiSampler::Nearest,
872 QRhiSampler::ClampToEdge,
873 QRhiSampler::ClampToEdge,
874 QRhiSampler::ClampToEdge
876 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
880 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
881 subsetRenderable.rhiRenderData.shadowPass.pipeline = rhiCtxD->pipeline(*ps, pEntry->m_rhiRenderPassDesc[cascadeIndex], srb);
882 subsetRenderable.rhiRenderData.shadowPass.srb[cubeFaceIdx] = srb;
917 QRhiRenderPassDescriptor *renderPassDescriptor,
918 QSSGRhiGraphicsPipelineState *ps,
919 QSSGShaderFeatures featureSet,
923 QSSGRenderCamera *alteredCamera,
924 QMatrix4x4 *alteredModelViewProjection,
925 QSSGRenderTextureCubeFace cubeFace,
929 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
931 switch (inObject.type) {
932 case QSSGRenderableObject::Type::DefaultMaterialMeshSubset:
934 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
936 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
937 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
939 if ((cubeFace != QSSGRenderTextureCubeFaceNone)) {
941 featureSet.disableTonemapping();
944 if (subsetRenderable.renderableFlags.rendersWithLightmap())
945 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
947 const auto &shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
948 if (shaderPipeline) {
956 QSSGRhiShaderResourceBindingList bindings;
957 const auto &modelNode = subsetRenderable.modelContext.model;
958 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(subsetRenderable.shaderDescription);
965 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
966 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * (cubeFaceIdx + (quintptr(subsetRenderable.subset.offset) << 3));
968 const auto entryPartA =
reinterpret_cast<quintptr>(&subsetRenderable.material);
969 const auto entryPartB =
reinterpret_cast<quintptr>(entry);
970 const void *entryId =
reinterpret_cast<
const void *>(entryPartA ^ entryPartB);
972 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
973 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey, &modelNode, entryId, entryIdx });
975 shaderPipeline->ensureCombinedUniformBuffer(&dcd.ubuf);
976 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
978 Q_ASSERT(alteredModelViewProjection);
979 QSSGRenderCameraList cameras({ alteredCamera });
980 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, cameras,
nullptr, alteredModelViewProjection);
982 Q_ASSERT(!alteredModelViewProjection);
983 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
987 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &subsetRenderable.modelContext.model, subsetRenderable.subset.offset);
988 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
991 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &subsetRenderable.modelContext.model);
994 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
995 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
997 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
998 QRhiSampler::Nearest,
1000 QRhiSampler::ClampToEdge,
1001 QRhiSampler::ClampToEdge,
1004 bindings.addTexture(binding,
1005 QRhiShaderResourceBinding::VertexStage,
1011 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
1012 if (targetsTexture) {
1013 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
1015 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1016 QRhiSampler::Nearest,
1018 QRhiSampler::ClampToEdge,
1019 QRhiSampler::ClampToEdge,
1020 QRhiSampler::ClampToEdge
1022 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
1026 ps->samples = samples;
1027 ps->viewCount = viewCount;
1029 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
1030 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
1031 if (!oit || (oit && inData.layer.oitMethod == QSSGRenderLayer::OITMethod::None))
1032 fillTargetBlend(&ps->targetBlend[0], material.blendMode);
1034 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
1036 ia = subsetRenderable.subset.rhi.ia;
1037 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
1038 QVector3D cameraDirection = cameraDatas[0].direction;
1039 QVector3D cameraPosition = cameraDatas[0].position;
1040 if (alteredCamera) {
1041 const QMatrix4x4 camGlobalTranform = inData.getGlobalTransform(*alteredCamera);
1042 cameraDirection = QSSGRenderNode::getScalingCorrectDirection(camGlobalTranform);
1043 cameraPosition = QSSGRenderNode::getGlobalPos(camGlobalTranform);
1045 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDirection, cameraPosition);
1046 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
1048 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline->ub0Size());
1050 if (shaderPipeline->isLightingEnabled()) {
1051 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd.ubuf,
1052 shaderPipeline->ub0LightDataOffset(),
1053 sizeof(QSSGShaderLightsUniformData));
1054 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd.ubuf,
1055 shaderPipeline->ub0DirectionalLightDataOffset(),
1056 sizeof(QSSGShaderDirectionalLightsUniformData));
1061 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
1062 while (renderableImage) {
1063 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
1064 const int samplerHint =
int(renderableImage->m_mapType);
1065 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
1066 if (samplerBinding >= 0) {
1067 QRhiTexture *texture = renderableImage->m_texture.m_texture;
1068 if (samplerBinding >= 0 && texture) {
1069 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
1070 QSSGRhiSamplerDescription samplerDesc = {
1071 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
1072 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
1073 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
1074 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
1075 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
1076 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
1078 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
1079 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
1080 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
1083 renderableImage = renderableImage->m_nextImage;
1086 if (shaderPipeline->isLightingEnabled()) {
1088 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
1089 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
1092 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1093 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
1094 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1097 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1098 QRhiSampler::Linear,
1100 QRhiSampler::ClampToEdge,
1101 QRhiSampler::ClampToEdge,
1102 QRhiSampler::Repeat });
1104 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1108 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
1109 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
1110 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
1112 QRhiTexture *texture = shadowMapBlueNoise;
1113 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1114 QRhiSampler::Linear,
1116 QRhiSampler::Repeat,
1117 QRhiSampler::Repeat,
1118 QRhiSampler::Repeat });
1119 Q_ASSERT(texture && sampler);
1120 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1123 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1124 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
1125 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1126 QRhiSampler::Linear,
1128 QRhiSampler::Repeat,
1129 QRhiSampler::Repeat,
1130 QRhiSampler::Repeat });
1131 Q_ASSERT(texture && sampler);
1132 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1133 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1140 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
1141 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
1142 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
1143 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
1144 ? QRhiSampler::Linear
1145 : QRhiSampler::None;
1146 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1147 QRhiSampler::Linear,
1149 QRhiSampler::ClampToEdge,
1150 QRhiSampler::ClampToEdge,
1151 QRhiSampler::Repeat });
1152 if (reflectionSampler >= 0 && reflectionTexture)
1153 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
1156 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
1158 auto texture = shaderPipeline->lightProbeTexture();
1160 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1161 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
1162 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1166 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
1167 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
1168 QRhiSampler::Linear,
1169 QRhiSampler::Linear,
1170 QSSGRhiHelpers::toRhi(tiling.first),
1171 QSSGRhiHelpers::toRhi(tiling.second),
1172 QRhiSampler::Repeat });
1173 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
1177 if (shaderPipeline->screenTexture()) {
1178 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
1179 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
1180 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
1181 QRhiTexture *screenTexture = shaderPipeline->screenTexture();
1183 if (screenMapPass) {
1184 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
1186 const QRhiTexture::Flags flags = screenTexture->flags();
1188 screenTexture = rhiCtx->dummyTexture(flags, resourceUpdates);
1189 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
1196 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
1197 ? QRhiSampler::Linear : QRhiSampler::None;
1198 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
1199 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
1200 if (screenTextureBinding >= 0) {
1201 bindings.addTexture(screenTextureBinding,
1202 QRhiShaderResourceBinding::FragmentStage,
1203 screenTexture, sampler);
1205 if (screenTextureArrayBinding >= 0) {
1206 bindings.addTexture(screenTextureArrayBinding,
1207 QRhiShaderResourceBinding::FragmentStage,
1208 screenTexture, sampler);
1213 if (shaderPipeline->lightmapTexture()) {
1214 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
1216 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1217 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
1218 bindings.addTexture(binding,
1219 QRhiShaderResourceBinding::FragmentStage,
1220 shaderPipeline->lightmapTexture(), sampler);
1226 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1229 addNormalTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
1231 if (oit && inData.layer.oitMethod == QSSGRenderLayer::OITMethod::LinkedList)
1241 QRhiShaderResourceBindings *&srb = dcd.srb;
1242 bool srbChanged =
false;
1243 if (!srb || bindings != dcd.bindings) {
1244 srb = rhiCtxD->srb(bindings);
1245 rhiCtxD->releaseCachedSrb(dcd.bindings);
1246 dcd.bindings = bindings;
1250 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1251 subsetRenderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
1253 subsetRenderable.rhiRenderData.mainPass.srb = srb;
1255 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
1258 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
1259 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
1262 if (cubeFace != QSSGRenderTextureCubeFaceNone)
1263 subsetRenderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
1265 subsetRenderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
1267 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1268 subsetRenderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1269 renderPassDescriptor,
1271 dcd.pipeline = subsetRenderable.rhiRenderData.reflectionPass.pipeline;
1273 subsetRenderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
1274 renderPassDescriptor,
1276 dcd.pipeline = subsetRenderable.rhiRenderData.mainPass.pipeline;
1278 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
1279 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;
1285 case QSSGRenderableObject::Type::CustomMaterialMeshSubset:
1287 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(inObject));
1288 const QSSGRenderCustomMaterial &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
1289 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
1291 featureSet.set(QSSGShaderFeatures::Feature::LightProbe, inData.layer.lightProbe || material.m_iblProbe);
1293 if ((cubeFace == QSSGRenderTextureCubeFaceNone) && subsetRenderable.reflectionProbeIndex >= 0 && subsetRenderable.renderableFlags.testFlag(QSSGRenderableObjectFlag::ReceivesReflections))
1294 featureSet.set(QSSGShaderFeatures::Feature::ReflectionProbe,
true);
1296 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1298 featureSet.disableTonemapping();
1301 if (subsetRenderable.renderableFlags.rendersWithLightmap())
1302 featureSet.set(QSSGShaderFeatures::Feature::Lightmap,
true);
1304 customMaterialSystem.rhiPrepareRenderable(ps, passKey, subsetRenderable, featureSet,
1305 material, inData, renderPassDescriptor, samples, viewCount, screenMapPass,
1306 alteredCamera, cubeFace, alteredModelViewProjection, entry, oit);
1309 case QSSGRenderableObject::Type::Particles:
1312 const auto &shaderPipeline = shadersForParticleMaterial(ps, particleRenderable, featureSet);
1313 if (shaderPipeline) {
1314 QSSGParticleRenderer::rhiPrepareRenderable(*shaderPipeline, passKey, rhiCtx, ps, particleRenderable, inData, renderPassDescriptor, samples, viewCount,
1315 alteredCamera, cubeFace, entry, oit);
1361 const QSSGRhiGraphicsPipelineState &state,
1363 bool *needsSetViewport,
1364 QSSGRenderTextureCubeFace cubeFace,
1365 qsizetype userPassIndex)
1367 switch (object.type) {
1368 case QSSGRenderableObject::Type::DefaultMaterialMeshSubset:
1370 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(object));
1372 QSSG_ASSERT(QSSGUserRenderPassManager::maxUserPassSlots() == std::size(subsetRenderable.rhiRenderData.userPassData),
return);
1374 QRhiGraphicsPipeline *ps = (userPassIndex >= 0 && size_t(userPassIndex) < QSSGUserRenderPassManager::maxUserPassSlots())
1375 ? subsetRenderable.rhiRenderData.userPassData[userPassIndex].pipeline : subsetRenderable.rhiRenderData.mainPass.pipeline;
1376 QRhiShaderResourceBindings *srb = (userPassIndex >= 0 && size_t(userPassIndex) < QSSGUserRenderPassManager::maxUserPassSlots())
1377 ? subsetRenderable.rhiRenderData.userPassData[userPassIndex].srb : subsetRenderable.rhiRenderData.mainPass.srb;
1379 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
1380 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
1381 ps = subsetRenderable.rhiRenderData.reflectionPass.pipeline;
1382 srb = subsetRenderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx];
1388 QRhiBuffer *vertexBuffer = subsetRenderable.subset.rhi.vertexBuffer->buffer();
1389 QRhiBuffer *indexBuffer = subsetRenderable.subset.rhi.indexBuffer ? subsetRenderable.subset.rhi.indexBuffer->buffer() :
nullptr;
1391 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1393 cb->setGraphicsPipeline(ps);
1394 cb->setShaderResources(srb);
1396 if (*needsSetViewport) {
1397 cb->setViewport(state.viewport);
1398 if (state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor))
1399 cb->setScissor(state.scissor);
1400 *needsSetViewport =
false;
1403 QRhiCommandBuffer::VertexInput vertexBuffers[2];
1404 int vertexBufferCount = 1;
1405 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
1406 quint32 instances = 1;
1407 if ( subsetRenderable.modelContext.model.instancing()) {
1408 instances = subsetRenderable.modelContext.model.instanceCount();
1415 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(subsetRenderable.instanceBuffer, 0);
1416 vertexBufferCount = 2;
1418 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
1419 if (state.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef))
1420 cb->setStencilRef(state.stencilRef);
1422 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, subsetRenderable.subset.rhi.indexBuffer->indexFormat());
1423 cb->drawIndexed(subsetRenderable.subset.lodCount(subsetRenderable.subsetLevelOfDetail), instances, subsetRenderable.subset.lodOffset(subsetRenderable.subsetLevelOfDetail));
1424 QSSGRHICTX_STAT(rhiCtx, drawIndexed(subsetRenderable.subset.lodCount(subsetRenderable.subsetLevelOfDetail), instances));
1426 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
1427 cb->draw(subsetRenderable.subset.count, instances, subsetRenderable.subset.offset);
1428 QSSGRHICTX_STAT(rhiCtx, draw(subsetRenderable.subset.count, instances));
1430 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (subsetRenderable.subset.count | quint64(instances) << 32),
1431 QVector<
int>({subsetRenderable.modelContext.model.profilingId,
1432 subsetRenderable.material.profilingId}));
1435 case QSSGRenderableObject::Type::CustomMaterialMeshSubset:
1437 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(object));
1438 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
1439 customMaterialSystem.rhiRenderRenderable(rhiCtx, subsetRenderable, needsSetViewport, cubeFace, state, userPassIndex);
1442 case QSSGRenderableObject::Type::Particles:
1445 QSSGParticleRenderer::rhiRenderRenderable(rhiCtx, renderable, needsSetViewport, cubeFace, state);
1470 QSSGPassKey passKey,
1471 QSSGRhiGraphicsPipelineState &ps,
1472 QSSGRenderShadowMap &shadowMapManager,
1473 const QSSGRenderCamera &camera,
1474 QSSGRenderCamera *debugCamera,
1476 const QSSGRenderableObjectList &sortedOpaqueObjects,
1478 const QSSGBounds3 &castingObjectsBox,
1479 const QSSGBounds3 &receivingObjectsBox)
1482 QSSGDebugDrawSystem *debugDrawSystem = renderer.contextInterface()->debugDrawSystem().get();
1483 const bool drawDirectionalLightShadowBoxes = layerData.layer.drawDirectionalLightShadowBoxes;
1484 const bool drawPointLightShadowBoxes = layerData.layer.drawPointLightShadowBoxes;
1485 const bool drawShadowCastingBounds = layerData.layer.drawShadowCastingBounds;
1486 const bool drawShadowReceivingBounds = layerData.layer.drawShadowReceivingBounds;
1487 const bool drawCascades = layerData.layer.drawCascades;
1488 const bool drawSceneCascadeIntersection = layerData.layer.drawSceneCascadeIntersection;
1489 const bool disableShadowCameraUpdate = layerData.layer.disableShadowCameraUpdate;
1490 const bool drawCulledObjects = layerData.layer.drawCulledObjects;
1491 QVector<
bool> debugIsObjectCulled = drawCulledObjects ? QVector<
bool>(sortedOpaqueObjects.size(),
true) : QVector<
bool>();
1493 static const auto rhiRenderOneShadowMap = [](QSSGRhiContext *rhiCtx,
1494 QSSGRhiGraphicsPipelineState *ps,
1495 const QSSGRenderableObjectList &sortedOpaqueObjects,
1497 const QSSGBounds3 cameraBounds,
1498 QVector<
bool> &debugIsObjectCulled,
1499 bool drawCulledObjects) {
1500 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1501 bool needsSetViewport =
true;
1503 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1508 if (theObject->globalBoundsInstancing.isFinite() && theObject->globalBounds.isFinite()) {
1509 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1510 : theObject->globalBounds;
1511 if (!globalBounds.isEmpty() && !cameraBounds.intersects(globalBounds)) {
1516 if (Q_UNLIKELY(drawCulledObjects))
1517 debugIsObjectCulled[i] =
false;
1520 if (theObject->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || theObject->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
1521 QSSGSubsetRenderable *renderable(
static_cast<QSSGSubsetRenderable *>(theObject));
1523 QRhiBuffer *vertexBuffer = renderable->subset.rhi.vertexBuffer->buffer();
1524 QRhiBuffer *indexBuffer = renderable->subset.rhi.indexBuffer
1525 ? renderable->subset.rhi.indexBuffer->buffer()
1529 if (!renderable->rhiRenderData.shadowPass.pipeline)
1532 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
1534 cb->setGraphicsPipeline(renderable->rhiRenderData.shadowPass.pipeline);
1536 QRhiShaderResourceBindings *srb = renderable->rhiRenderData.shadowPass.srb[cubeFace];
1537 cb->setShaderResources(srb);
1539 if (needsSetViewport) {
1540 cb->setViewport(ps->viewport);
1541 needsSetViewport =
false;
1544 QRhiCommandBuffer::VertexInput vertexBuffers[2];
1545 int vertexBufferCount = 1;
1546 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
1547 quint32 instances = 1;
1548 if (renderable->modelContext.model.instancing()) {
1549 instances = renderable->modelContext.model.instanceCount();
1550 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(renderable->instanceBuffer, 0);
1551 vertexBufferCount = 2;
1554 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, renderable->subset.rhi.indexBuffer->indexFormat());
1555 cb->drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances, renderable->subset.lodOffset(renderable->subsetLevelOfDetail));
1556 QSSGRHICTX_STAT(rhiCtx, drawIndexed(renderable->subset.lodCount(renderable->subsetLevelOfDetail), instances));
1558 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
1559 cb->draw(renderable->subset.count, instances, renderable->subset.offset);
1560 QSSGRHICTX_STAT(rhiCtx, draw(renderable->subset.count, instances));
1562 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (renderable->subset.count | quint64(instances) << 32),
1563 QVector<
int>({renderable->modelContext.model.profilingId,
1564 renderable->material.profilingId}));
1569 static const auto rhiClearShadowMap = [](
QSSGRenderer &renderer, QSSGRenderShadowMap &shadowMapManager, QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QRhiRenderPassDescriptor *renderPassDesc) {
1570 auto clearShadowMapShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiClearShadowMapShader();
1571 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, clearShadowMapShaderPipeline.get());
1574 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
false);
1575 ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1576 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, shadowMapManager.shadowClearSrb(), renderPassDesc, {});
1578 ps->flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1581 QRhi *rhi = rhiCtx->rhi();
1582 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1586 QVector2D depthAdjust;
1587 if (rhi->isClipDepthZeroToOne()) {
1589 depthAdjust[0] = 0.0f;
1590 depthAdjust[1] = 1.0f;
1593 depthAdjust[0] = 1.0f;
1594 depthAdjust[1] = 0.5f;
1597 if (drawShadowCastingBounds)
1599 if (drawShadowReceivingBounds)
1603 const QSize atlasTextureSize = shadowMapManager.shadowMapAtlasTexture()->pixelSize();
1605 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
1606 for (
int i = 0, ie = globalLights.size(); i != ie; ++i) {
1607 if (!globalLights[i].shadows || globalLights[i].light->m_fullyBaked)
1614 const auto &light = globalLights[i].light;
1616 if (!shadowMapManager.shadowMapAtlasTexture())
1619 if (light->type == QSSGRenderLight::Type::DirectionalLight || light->type == QSSGRenderLight::Type::SpotLight) {
1620 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1624 if (!disableShadowCameraUpdate && debugCamera) {
1625 debugCamera->clipPlanes = camera.clipPlanes;
1626 debugCamera->projection = camera.projection;
1630 debugCamera->localTransform = layerData.getGlobalTransform(camera);
1633 QVarLengthArray<std::unique_ptr<QSSGRenderCamera>, 4> cascades;
1634 if (light->type == QSSGRenderLight::Type::DirectionalLight) {
1635 const float pcfRadius = light->m_softShadowQuality == QSSGRenderLight::SoftShadowQuality::Hard ? 0.f : light->m_pcfFactor;
1636 const float clipNear = camera.clipPlanes.clipNear();
1637 const float clipFar = qMin(light->m_shadowMapFar, camera.clipPlanes.clipFar());
1638 const float clipRange = clipFar - clipNear;
1639 cascades = setupCascadingCamerasForShadowMap(layerData,
1640 disableShadowCameraUpdate ? *debugCamera : camera,
1647 receivingObjectsBox,
1648 light->m_lockShadowmapTexels,
1651 drawSceneCascadeIntersection);
1654 pEntry->m_csmSplits[0] = clipNear + clipRange * (light->m_csmNumSplits > 0 ? light->m_csmSplit1 : 1.0f);
1655 pEntry->m_csmSplits[1] = clipNear + clipRange * (light->m_csmNumSplits > 1 ? light->m_csmSplit2 : 1.0f);
1656 pEntry->m_csmSplits[2] = clipNear + clipRange * (light->m_csmNumSplits > 2 ? light->m_csmSplit3 : 1.0f);
1657 pEntry->m_csmSplits[3] = clipNear + clipRange * 1.0f;
1658 pEntry->m_shadowMapFar = clipFar;
1659 }
else if (light->type == QSSGRenderLight::Type::SpotLight) {
1660 auto spotlightCamera =
std::make_unique<QSSGRenderCamera>(QSSGRenderCamera::Type::PerspectiveCamera);
1661 spotlightCamera->fov = QSSGRenderCamera::FieldOfView::fromDegrees(light->m_coneAngle * 2.0f);
1662 spotlightCamera->clipPlanes = { 1.0f, light->m_shadowMapFar };
1663 const QMatrix4x4 lightGlobalTransform = layerData.getGlobalTransform(*light);
1664 const QVector3D lightDir = QSSGRenderNode::getDirection(lightGlobalTransform);
1665 const QVector3D lightPos = QSSGRenderNode::getGlobalPos(lightGlobalTransform) - lightDir * spotlightCamera->clipPlanes.clipNear();
1666 const QVector3D lightPivot = light->pivot;
1667 const QVector3D forward = lightDir.normalized();
1668 const QVector3D right = qFuzzyCompare(qAbs(forward.y()), 1.0f)
1669 ? QVector3D::crossProduct(forward, QVector3D(1, 0, 0)).normalized()
1670 : QVector3D::crossProduct(forward, QVector3D(0, 1, 0)).normalized();
1671 const QVector3D up = QVector3D::crossProduct(right, forward).normalized();
1672 spotlightCamera->localTransform = QSSGRenderNode::calculateTransformMatrix(lightPos,
1673 QSSGRenderNode::initScale,
1675 QQuaternion::fromDirection(forward, up));
1676 QRectF theViewport(0.0f, 0.0f, (
float)light->m_shadowMapRes, (
float)light->m_shadowMapRes);
1677 QSSGRenderCamera::calculateProjectionInternal(*spotlightCamera, theViewport);
1678 cascades.push_back(
std::move(spotlightCamera));
1679 pEntry->m_shadowMapFar = light->m_shadowMapFar;
1684 memset(pEntry->m_csmActive, 0,
sizeof(pEntry->m_csmActive));
1686 QMatrix4x4 cascadeCameraGlobalTransforms(Qt::Uninitialized);
1687 const QMatrix4x4 bias = { 0.5, 0.0, 0.0, 0.5,
1690 0.0, 0.0, 0.0, 1.0 };
1692 for (
int cascadeIndex = 0; cascadeIndex < cascades.length(); cascadeIndex++) {
1693 const auto &cascadeCamera = cascades[cascadeIndex];
1697 cascadeCameraGlobalTransforms = layerData.getGlobalTransform(*cascadeCamera);
1698 pEntry->m_csmActive[cascadeIndex] = 1.f;
1699 QMatrix4x4 &viewProjection = pEntry->m_lightViewProjection[cascadeIndex];
1700 cascadeCamera->calculateViewProjectionMatrix(cascadeCameraGlobalTransforms, viewProjection);
1701 pEntry->m_lightViewProjection[cascadeIndex] = viewProjection;
1702 pEntry->m_fixedScaleBiasMatrix[cascadeIndex] = bias * viewProjection;
1703 const QMatrix4x4 inverted = viewProjection.inverted();
1704 const float x = 0.5f / (inverted * QVector4D(1, 0, 0, 0)).length();
1705 const float y = 0.5f / (inverted * QVector4D(0, 1, 0, 0)).length();
1706 const float z = 0.5f / (inverted * QVector4D(0, 0, 1, 0)).length();
1707 const QSSGBoxPoints frustumPoints = computeFrustumBounds(viewProjection);
1708 const QSSGBounds3 bounds = QSSGBounds3(frustumPoints);
1709 pEntry->m_dimensionsInverted[cascadeIndex] = QVector4D(x, y, z, 0.0f);
1710 pEntry->m_lightView = cascadeCameraGlobalTransforms.inverted();
1711 const bool isOrtho = cascadeCamera->type == QSSGRenderGraphObject::Type::OrthographicCamera;
1712 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[cascadeIndex], rhi->isYUpInFramebuffer());
1713 rhiPrepareResourcesForShadowMap(rhiCtx, layerData, passKey, pEntry, &ps, &depthAdjust, sortedOpaqueObjects, *cascadeCamera, isOrtho, QSSGRenderTextureCubeFaceNone, cascadeIndex);
1716 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[cascadeIndex];
1717 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1718 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1719 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1720 rhiClearShadowMap(renderer, shadowMapManager, rhiCtx, &ps, rt->renderPassDescriptor());
1721 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, 0, bounds, debugIsObjectCulled, drawCulledObjects);
1723 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1725 if (drawDirectionalLightShadowBoxes) {
1729 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"shadow_map"));
1731 const QSize size = atlasTextureSize * pEntry->m_atlasInfo[0].uvScale;
1732 ps.viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1734 QSSGRenderCamera theCameras[6] { 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 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1740 const float shadowMapFar = qMax<
float>(2.0f, light->m_shadowMapFar);
1741 setupCubeShadowCameras(layerData, light, shadowMapFar, theCameras);
1742 pEntry->m_lightView = QMatrix4x4();
1743 pEntry->m_shadowMapFar = shadowMapFar;
1745 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1746 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1747 for (
const auto face : QSSGRenderTextureCubeFaces) {
1748 cameraGlobalTransform = layerData.getGlobalTransform(theCameras[quint8(face)]);
1749 theCameras[quint8(face)].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_lightViewProjection[0]);
1750 pEntry->m_lightCubeView[quint8(face)] = cameraGlobalTransform.inverted();
1752 rhiPrepareResourcesForShadowMap(rhiCtx,
1758 sortedOpaqueObjects,
1759 theCameras[quint8(face)],
1766 const QVector3D center = QSSGRenderNode::getGlobalPos(layerData.getGlobalTransform(*light));
1767 const QSSGBounds3 bounds = QSSGBounds3(center - QVector3D(shadowMapFar, shadowMapFar, shadowMapFar),
1768 center + QVector3D(shadowMapFar, shadowMapFar, shadowMapFar));
1770 for (
const auto face : QSSGRenderTextureCubeFaces) {
1774 QSSGRenderTextureCubeFace outFace = face;
1792 if (outFace == QSSGRenderTextureCubeFace::PosY)
1793 outFace = QSSGRenderTextureCubeFace::NegY;
1794 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1795 outFace = QSSGRenderTextureCubeFace::PosY;
1797 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargetCube[quint8(outFace)];
1798 cb->beginPass(rt, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1799 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1800 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1801 rhiRenderOneShadowMap(rhiCtx, &ps, sortedOpaqueObjects, quint8(face), bounds, debugIsObjectCulled, drawCulledObjects);
1803 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1804 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_cube", 0, outFace));
1811 QRhiTextureRenderTarget *rtFront = pEntry->m_rhiRenderTargets[0];
1812 QRhiRenderPassDescriptor *frontDesc = pEntry->m_rhiRenderPassDesc[0];
1813 auto atlasShaderPipeline = renderer.contextInterface()->shaderCache()->getBuiltInRhiShaders().getRhiCubeMapToAtlasShader();
1814 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[0], rhi->isYUpInFramebuffer());
1815 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, atlasShaderPipeline.get());
1816 QRhiShaderResourceBindings *srb = pEntry->m_cubeToAtlasFrontSrb;
1817 cb->beginPass(rtFront, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1818 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtFront));
1819 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1821 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, frontDesc, QSSGRhiQuadRenderer::UvCoords);
1824 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1825 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 6, 0));
1828 QRhiTextureRenderTarget *rtBack = pEntry->m_rhiRenderTargets[1];
1829 QRhiRenderPassDescriptor *backDesc = pEntry->m_rhiRenderPassDesc[1];
1830 srb = pEntry->m_cubeToAtlasBackSrb;
1831 ps.viewport = calculateAtlasViewport(atlasTextureSize, pEntry->m_atlasInfo[1], rhi->isYUpInFramebuffer());
1832 cb->beginPass(rtBack, Qt::white, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1833 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rtBack));
1834 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1836 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, backDesc, QSSGRhiQuadRenderer::UvCoords);
1839 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1840 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"shadow_atlas", 7, 0));
1844 ps = layerData.getPipelineState();
1845 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
1847 ps.slopeScaledDepthBias = 1.5f;
1849 if (drawPointLightShadowBoxes) {
1855 if (Q_UNLIKELY(drawCulledObjects)) {
1856 for (
int i = 0, n = sortedOpaqueObjects.size(); i < n; ++i) {
1858 const QSSGBounds3 &globalBounds = !theObject->globalBoundsInstancing.isEmpty() ? theObject->globalBoundsInstancing
1859 : theObject->globalBounds;
1860 const QColor color = debugIsObjectCulled[i] ? QColorConstants::Red : QColorConstants::Green;
1867 QSSGPassKey passKey,
1869 QSSGRhiGraphicsPipelineState *ps,
1870 QSSGRenderReflectionMap &reflectionMapManager,
1871 const std::vector<QSSGRenderReflectionProbe *> &reflectionProbes,
1872 const QSSGRenderableObjectList &reflectionPassObjects,
1875 QSSGRhiContext *rhiCtx = context.rhiContext().get();
1876 QRhi *rhi = rhiCtx->rhi();
1877 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1879 const bool renderSkybox = (inData.layer.background == QSSGRenderLayer::Background::SkyBox
1880 || inData.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap
1881 || inData.layer.background == QSSGRenderLayer::Background::SkyMaterial)
1882 && rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch);
1884 for (
int i = 0, ie = reflectionProbes.size(); i != ie; ++i) {
1889 if (!pEntry->m_needsRender)
1892 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame && pEntry->m_rendered)
1895 if (reflectionProbes[i]->texture)
1898 Q_ASSERT(pEntry->m_rhiDepthStencil);
1899 Q_ASSERT(pEntry->m_rhiCube);
1901 const QSize size = pEntry->m_rhiCube->pixelSize();
1902 ps->viewport = QRhiViewport(0, 0,
float(size.width()),
float(size.height()));
1904 QSSGRenderCamera theCameras[6] { QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1905 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1906 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1907 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1908 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera},
1909 QSSGRenderCamera{QSSGRenderCamera::Type::PerspectiveCamera} };
1910 setupCubeReflectionCameras(inData, reflectionProbes[i], theCameras);
1911 const bool swapYFaces = !rhi->isYUpInFramebuffer();
1912 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1913 for (
const auto face : QSSGRenderTextureCubeFaces) {
1914 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(face);
1915 cameraGlobalTransform = inData.getGlobalTransform(theCameras[cubeFaceIdx]);
1916 theCameras[cubeFaceIdx].calculateViewProjectionMatrix(cameraGlobalTransform, pEntry->m_viewProjection);
1918 rhiPrepareResourcesForReflectionMap(context, passKey, inData, pEntry, ps, reflectionPassObjects, theCameras[cubeFaceIdx], renderer, face);
1920 QRhiRenderPassDescriptor *renderPassDesc =
nullptr;
1921 for (
auto face : QSSGRenderTextureCubeFaces) {
1922 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1923 face = pEntry->m_timeSliceFace;
1925 QSSGRenderTextureCubeFace outFace = face;
1929 if (outFace == QSSGRenderTextureCubeFace::PosY)
1930 outFace = QSSGRenderTextureCubeFace::NegY;
1931 else if (outFace == QSSGRenderTextureCubeFace::NegY)
1932 outFace = QSSGRenderTextureCubeFace::PosY;
1934 QRhiTextureRenderTarget *rt = pEntry->m_rhiRenderTargets[quint8(outFace)];
1935 cb->beginPass(rt, reflectionProbes[i]->clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
1936 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
1937 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1939 if (renderSkybox && pEntry->m_skyBoxSrbs[quint8(face)]) {
1940 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1941 const bool useSkyBoxQuad = inData.layer.background == QSSGRenderLayer::Background::SkyBox
1942 || inData.layer.background == QSSGRenderLayer::Background::SkyMaterial;
1943 const auto &shaderPipeline = useSkyBoxQuad
1944 ? shaderCache->getBuiltInRhiShaders().getRhiSkyBoxShader(QSSGRenderLayer::TonemapMode::None,
1945 inData.layer.skyBoxIsRgbe8,
1947 : shaderCache->getBuiltInRhiShaders().getRhiSkyBoxCubeShader(QSSGRenderLayer::TonemapMode::None,
1948 !inData.layer.skyBoxIsSrgb,
1950 Q_ASSERT(shaderPipeline);
1951 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
1952 QRhiShaderResourceBindings *srb = pEntry->m_skyBoxSrbs[quint8(face)];
1953 if (!renderPassDesc)
1954 renderPassDesc = rt->newCompatibleRenderPassDescriptor();
1955 rt->setRenderPassDescriptor(renderPassDesc);
1956 useSkyBoxQuad ? renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx, ps, srb, renderPassDesc, {})
1957 : renderer.rhiCubeRenderer()->recordRenderCube(rhiCtx, ps, srb, renderPassDesc, {});
1960 bool needsSetViewport =
true;
1961 for (
const auto &handle : reflectionPassObjects)
1962 rhiRenderRenderable(rhiCtx, *ps, *handle.obj, &needsSetViewport, face);
1965 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
1966 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QSSG_RENDERPASS_NAME(
"reflection_cube", 0, outFace));
1968 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1972 renderPassDesc->deleteLater();
1974 pEntry->renderMips(rhiCtx);
1976 if (pEntry->m_timeSlicing == QSSGRenderReflectionProbe::ReflectionTimeSlicing::IndividualFaces)
1977 pEntry->m_timeSliceFace = QSSGBaseTypeHelpers::next(pEntry->m_timeSliceFace);
1979 if (reflectionProbes[i]->refreshMode == QSSGRenderReflectionProbe::ReflectionRefreshMode::FirstFrame)
1980 pEntry->m_rendered =
true;
1982 reflectionProbes[i]->hasScheduledUpdate =
false;
1983 pEntry->m_needsRender =
false;
2034 QSSGPassKey passKey,
2036 QSSGRhiShaderPipeline &shaderPipeline,
2037 QSSGRhiGraphicsPipelineState &ps,
2038 const QSSGAmbientOcclusionSettings &ao,
2039 const QSSGRhiRenderableTexture &rhiAoTexture,
2040 const QSSGRhiRenderableTexture &rhiDepthTexture,
2041 const QSSGRenderCamera &camera)
2043 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2046 if (!rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2047 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
2049 cb->beginPass(rhiAoTexture.rt, Qt::white, { 1.0f, 0 });
2050 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rhiAoTexture.rt));
2052 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
2056 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, &shaderPipeline);
2058 const float R2 = ao.aoDistance * ao.aoDistance * 0.16f;
2059 const QSize textureSize = rhiAoTexture.texture->pixelSize();
2060 const float rw =
float(textureSize.width());
2061 const float rh =
float(textureSize.height());
2062 const float fov = camera.fov.asVerticalFov(rw / rh).radians();
2063 const float tanHalfFovY = tanf(0.5f * fov * (rh / rw));
2064 const float invFocalLenX = tanHalfFovY * (rw / rh);
2066 const QVector4D aoProps(ao.aoStrength * 0.01f, ao.aoDistance * 0.4f, ao.aoSoftness * 0.02f, ao.aoBias);
2067 const QVector4D aoProps2(
float(ao.aoSamplerate), (ao.aoDither) ? 1.0f : 0.0f, 0.0f, 0.0f);
2068 const QVector4D aoScreenConst(1.0f / R2, rh / (2.0f * tanHalfFovY), 1.0f / rw, 1.0f / rh);
2069 const QVector4D uvToEyeConst(2.0f * invFocalLenX, -2.0f * tanHalfFovY, -invFocalLenX, tanHalfFovY);
2070 const QVector2D cameraProps = camera.clipPlanes;
2079 const int UBUF_SIZE = 72;
2080 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ passKey,
nullptr,
nullptr, 0 }));
2082 dcd.ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE);
2086 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2087 memcpy(ubufData, &aoProps, 16);
2088 memcpy(ubufData + 16, &aoProps2, 16);
2089 memcpy(ubufData + 32, &aoScreenConst, 16);
2090 memcpy(ubufData + 48, &uvToEyeConst, 16);
2091 memcpy(ubufData + 64, &cameraProps, 8);
2092 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2094 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2095 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
2096 QSSGRhiShaderResourceBindingList bindings;
2097 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
2100 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiDepthTexture.texture, sampler);
2101 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2103 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
2104 renderer.rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, rhiAoTexture.rt, {});
2252 QSSGPassKey passKey,
2253 QSSGRenderLayer &layer,
2254 QSSGRenderCameraList &cameras,
2258 uint tonemapMode = 0)
2260 QSSG_ASSERT(layer.renderData,
return);
2262 const auto *renderData = layer.renderData;
2264 auto rhiCtx = context.rhiContext().get();
2266 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2268 QSSGRenderImageTexture lightProbeTexture;
2269 switch (layer.background) {
2270 case QSSGRenderLayer::Background::SkyBox:
2271 lightProbeTexture = renderer.contextInterface()->bufferManager()->loadRenderImage(layer.lightProbe,
2272 QSSGBufferManager::MipModeBsdf);
2274 case QSSGRenderLayer::Background::SkyBoxCubeMap:
2275 lightProbeTexture = renderer.contextInterface()->bufferManager()->loadRenderImage(layer.skyBoxCubeMap,
2276 QSSGBufferManager::MipModeDisable);
2278 case QSSGRenderLayer::Background::SkyMaterial:
2279 lightProbeTexture = renderData->skyMaterialTexture;
2282 Q_UNREACHABLE_RETURN();
2285 const bool hasValidInput = (lightProbeTexture.m_texture !=
nullptr);
2287 if (hasValidInput) {
2288 const bool cubeMapMode = layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap;
2290 if (cubeFace == QSSGRenderTextureCubeFaceNone)
2291 layer.skyBoxIsRgbe8 = lightProbeTexture.m_flags.isRgbe8();
2293 layer.skyBoxIsSrgb = !lightProbeTexture.m_flags.isLinear();
2295 QSSGRhiShaderResourceBindingList bindings;
2297 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
2298 QRhiSampler::Linear,
2299 cubeMapMode ? QRhiSampler::None : QRhiSampler::Linear,
2300 QRhiSampler::Repeat,
2301 QRhiSampler::ClampToEdge,
2302 QRhiSampler::Repeat });
2303 int samplerBinding = 1;
2304 bindings.addTexture(samplerBinding, QRhiShaderResourceBinding::FragmentStage, lightProbeTexture.m_texture, sampler);
2306 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2307 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * cubeFaceIdx;
2308 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey,
nullptr, entry, entryIdx });
2310 QRhi *rhi = rhiCtx->rhi();
2311 const quint32 ubufSize = cameras.count() >= 2 ? 416 : 240;
2312 if (!dcd.ubuf || dcd.ubuf->size() != ubufSize) {
2314 dcd.ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer,
int(ubufSize));
2318 float adjustY = rhi->isYUpInNDC() ? 1.0f : -1.0f;
2319 const float exposure = layer.lightProbeSettings.probeExposure;
2321 const QMatrix3x3 &rotationMatrix(layer.lightProbeSettings.probeOrientation);
2324 const float blurAmountOrSrgb = cubeMapMode ? layer.skyBoxIsSrgb : layer.skyboxBlurAmount;
2325 const float maxMipLevelOrTonemapMode = cubeMapMode ?
float(tonemapMode) :
float(lightProbeTexture.m_mipmapCount - 2);
2327 const QVector4D skyboxProperties = {
2331 maxMipLevelOrTonemapMode
2334 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2335 quint32 ubufOffset = 0;
2337 memcpy(ubufData + ubufOffset, &skyboxProperties, 16);
2340 memcpy(ubufData + ubufOffset, rotationMatrix.constData(), 12);
2342 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 12, 12);
2344 memcpy(ubufData + ubufOffset, (
char *)rotationMatrix.constData() + 24, 12);
2347 for (qsizetype viewIdx = 0; viewIdx < cameras.count(); ++viewIdx) {
2348 const QMatrix4x4 &inverseProjection = cameras[viewIdx]->projection.inverted();
2349 const QMatrix4x4 &viewMatrix = renderData->getGlobalTransform(*cameras[viewIdx]);
2350 QMatrix4x4 viewProjection(Qt::Uninitialized);
2351 cameras[viewIdx]->calculateViewProjectionWithoutTranslation(viewMatrix, 0.1f, 5.0f, viewProjection);
2353 quint32 viewDataOffset = ubufOffset;
2354 memcpy(ubufData + viewDataOffset + viewIdx * 64, viewProjection.constData(), 64);
2355 viewDataOffset += cameras.count() * 64;
2356 memcpy(ubufData + viewDataOffset + viewIdx * 64, inverseProjection.constData(), 64);
2357 viewDataOffset += cameras.count() * 64;
2358 memcpy(ubufData + viewDataOffset + viewIdx * 48, viewMatrix.constData(), 48);
2360 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2362 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd.ubuf);
2364 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
2365 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
2366 entry->m_skyBoxSrbs[cubeFaceIdx] = rhiCtxD->srb(bindings);
2368 layer.skyBoxSrb = rhiCtxD->srb(bindings);
2372 renderer.rhiCubeRenderer()->prepareCube(rhiCtx,
nullptr);
2374 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
2414 QSSGPassKey passKey,
2415 const QSSGRhiGraphicsPipelineState &basePipelineState,
2416 QRhiRenderPassDescriptor *rpDesc,
2418 const QSSGRenderableObjectList &sortedOpaqueObjects,
2419 const QSSGRenderableObjectList &sortedTransparentObjects,
2423 static const auto rhiPrepareDepthPassForObject = [](QSSGRhiContext *rhiCtx,
2424 QSSGPassKey passKey,
2427 QRhiRenderPassDescriptor *rpDesc,
2428 QSSGRhiGraphicsPipelineState *ps) {
2429 QSSGRhiShaderPipelinePtr shaderPipeline;
2430 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2432 const bool isOpaqueDepthPrePass = obj->depthWriteMode == QSSGDepthDrawMode::OpaquePrePass;
2433 QSSGShaderFeatures featureSet;
2434 featureSet.set(QSSGShaderFeatures::Feature::DepthPass,
true);
2435 if (isOpaqueDepthPrePass)
2436 featureSet.set(QSSGShaderFeatures::Feature::OpaqueDepthPrePass,
true);
2438 QSSGRhiDrawCallData *dcd =
nullptr;
2439 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2440 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2441 const void *modelNode = &subsetRenderable.modelContext.model;
2442 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
2445 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2446 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2447 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2448 ps->cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2450 shaderPipeline = shadersForDefaultMaterial(ps, subsetRenderable, featureSet);
2451 if (shaderPipeline) {
2452 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2453 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2454 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2455 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2459 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2460 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2462 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2464 ps->cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2466 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
2467 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2469 if (shaderPipeline) {
2470 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2471 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2472 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, ps, customMaterial, subsetRenderable,
2473 inData.renderedCameras,
nullptr,
nullptr);
2474 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2481 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2482 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2483 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
2484 ia = subsetRenderable.subset.rhi.ia;
2486 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2487 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2488 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2490 QSSGRhiShaderResourceBindingList bindings;
2491 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2494 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2496 if (isOpaqueDepthPrePass) {
2497 addOpaqueDepthPrePassBindings(rhiCtx,
2498 shaderPipeline.get(),
2499 subsetRenderable.firstImage,
2501 (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset));
2507 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2508 if (normalTextureBinding >= 0) {
2509 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2510 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2511 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2512 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2513 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2514 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2518 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2519 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2521 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2522 QRhiSampler::Nearest,
2524 QRhiSampler::ClampToEdge,
2525 QRhiSampler::ClampToEdge,
2528 bindings.addTexture(binding,
2529 QRhiShaderResourceBinding::VertexStage,
2536 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2537 if (targetsTexture) {
2538 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2540 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2541 QRhiSampler::Nearest,
2543 QRhiSampler::ClampToEdge,
2544 QRhiSampler::ClampToEdge,
2545 QRhiSampler::ClampToEdge
2547 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2551 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2553 subsetRenderable.rhiRenderData.depthPrePass.pipeline = rhiCtxD->pipeline(*ps,
2556 subsetRenderable.rhiRenderData.depthPrePass.srb = srb;
2567 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2572 ps.samples = samples;
2573 ps.viewCount = viewCount;
2574 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
2575 ps.targetBlend[0].colorWrite = {};
2577 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2578 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2582 for (
const QSSGRenderableObjectHandle &handle : sortedTransparentObjects) {
2583 if (!rhiPrepareDepthPassForObject(rhiCtx, passKey, inData, handle.obj, rpDesc, &ps))
2710 QSSGPassKey passKey,
2711 const QSSGRhiGraphicsPipelineState &basePipelineState,
2712 QRhiRenderPassDescriptor *rpDesc,
2714 const QSSGRenderableObjectList &sortedOpaqueObjects)
2716 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2717 ps.depthFunc = QRhiGraphicsPipeline::LessOrEqual;
2718 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
2720 for (
const QSSGRenderableObjectHandle &handle : sortedOpaqueObjects) {
2721 QSSGRenderableObject *obj = handle.obj;
2722 QSSGRhiShaderPipelinePtr shaderPipeline;
2723 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2725 QSSGShaderFeatures featureSet;
2726 featureSet.set(QSSGShaderFeatures::Feature::NormalPass,
true);
2728 QSSGRhiDrawCallData *dcd =
nullptr;
2729 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2730 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2731 const void *modelNode = &subsetRenderable.modelContext.model;
2732 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
2735 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
2736 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2737 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
2738 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
2740 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
2741 if (shaderPipeline) {
2742 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2743 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2744 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
2745 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2747 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2748 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2750 const auto &customMaterial =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
2752 ps.cullMode = QSSGRhiHelpers::toCullMode(customMaterial.m_cullMode);
2754 const auto &customMaterialSystem = subsetRenderable.renderer->contextInterface()->customMaterialSystem();
2755 shaderPipeline = customMaterialSystem->shadersForCustomMaterial(&ps, customMaterial, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
2757 if (shaderPipeline) {
2758 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
2759 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
2760 customMaterialSystem->updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, customMaterial, subsetRenderable,
2761 inData.renderedCameras,
nullptr,
nullptr);
2762 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
2767 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
2768 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
2769 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
2770 ia = subsetRenderable.subset.rhi.ia;
2772 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
2773 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
2774 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
2776 QSSGRhiShaderResourceBindingList bindings;
2777 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
2780 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
2781 while (renderableImage) {
2782 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
2783 const int samplerHint =
int(renderableImage->m_mapType);
2784 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
2785 if (samplerBinding >= 0) {
2786 QRhiTexture *texture = renderableImage->m_texture.m_texture;
2787 if (samplerBinding >= 0 && texture) {
2788 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
2789 QSSGRhiSamplerDescription samplerDesc = {
2790 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
2791 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
2792 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
2793 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
2794 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
2795 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
2797 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
2798 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
2799 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
2802 renderableImage = renderableImage->m_nextImage;
2805 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
2808 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
2809 if (normalTextureBinding >= 0) {
2810 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
2811 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
2812 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
2813 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
2814 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
2815 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
2821 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
2822 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
2824 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2825 QRhiSampler::Nearest,
2827 QRhiSampler::ClampToEdge,
2828 QRhiSampler::ClampToEdge,
2831 bindings.addTexture(binding,
2832 QRhiShaderResourceBinding::VertexStage,
2839 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
2840 if (targetsTexture) {
2841 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
2843 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2844 QRhiSampler::Nearest,
2846 QRhiSampler::ClampToEdge,
2847 QRhiSampler::ClampToEdge,
2848 QRhiSampler::ClampToEdge
2850 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
2854 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
2856 subsetRenderable.rhiRenderData.normalPass.pipeline = rhiCtxD->pipeline(ps,
2859 subsetRenderable.rhiRenderData.normalPass.srb = srb;
2928 QSSGPassKey passKey,
2929 const QSSGRhiGraphicsPipelineState &basePipelineState,
2930 QRhiRenderPassDescriptor *rpDesc,
2931 QSSGRenderGraphObject *overrideMaterial,
2933 QSSGRenderableObjectList &inObjects,
2934 QSSGShaderFeatures featureSet)
2937 const qsizetype index = overrideMaterial ? inData.getUserRenderPassManager()->acquireUserPassSlot() : -1;
2942 QSSGRhiGraphicsPipelineState ps = basePipelineState;
2943 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
2945 const bool isCustomMaterial = (overrideMaterial->type == QSSGRenderGraphObject::Type::CustomMaterial);
2946 const bool isDefaultMaterial = (overrideMaterial->type == QSSGRenderGraphObject::Type::DefaultMaterial ||
2947 overrideMaterial->type == QSSGRenderGraphObject::Type::PrincipledMaterial ||
2948 overrideMaterial->type == QSSGRenderGraphObject::Type::SpecularGlossyMaterial);
2950 if (!isCustomMaterial && !isDefaultMaterial) {
2951 qDebug() <<
"Override material must be a default or custom material.";
2955 for (
const QSSGRenderableObjectHandle &handle : std::as_const(inObjects)) {
2956 QSSGRenderableObject *obj = handle.obj;
2958 if (obj->type != QSSGRenderableObject::Type::DefaultMaterialMeshSubset &&
2959 obj->type != QSSGRenderableObject::Type::CustomMaterialMeshSubset)
2962 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
2963 const void *modelNode = &subsetRenderable.modelContext.model;
2964 QSSGRhiDrawCallData *dcd = &rhiCtxD->drawCallData({ passKey, modelNode, overrideMaterial, 0 });
2970 QSSGRenderableObjectFlags renderableFlags = subsetRenderable.renderableFlags;
2971 float opacity = subsetRenderable.opacity;
2974 const bool hasAnyLights = !subsetRenderable.lights.isEmpty();
2975 const bool anyLightHasShadows = std::any_of(subsetRenderable.lights.begin(),
2976 subsetRenderable.lights.end(),
2977 [](
const QSSGShaderLight &light) {
return light.shadows; });
2981 auto layerPrepFlags = inData.layerPrepResult.getFlags();
2983 if (isCustomMaterial) {
2984 auto &material =
static_cast<QSSGRenderCustomMaterial &>(*overrideMaterial);
2985 auto prepResult = inData.prepareCustomMaterialForRender(material, renderableFlags, opacity,
2986 false, hasAnyLights, anyLightHasShadows,
2988 subsetRenderable.shaderDescription = prepResult.materialKey;
2990 auto &material =
static_cast<QSSGRenderDefaultMaterial &>(*overrideMaterial);
2991 auto prepResult = inData.prepareDefaultMaterialForRender(material, renderableFlags, opacity,
2992 hasAnyLights, anyLightHasShadows,
2994 subsetRenderable.shaderDescription = prepResult.materialKey;
2998 QSSGRhiShaderPipelinePtr shaderPipeline;
3000 if (isCustomMaterial) {
3001 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(*overrideMaterial);
3002 if (!ps.userSetCullMode)
3003 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
3005 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
3006 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable,
3007 inData.getDefaultMaterialPropertyTable(), featureSet);
3008 if (shaderPipeline) {
3009 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3010 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3011 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3012 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3013 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3016 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(*overrideMaterial);
3017 if (!ps.userSetCullMode)
3018 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3020 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
3021 if (shaderPipeline) {
3022 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3023 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3024 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable,
3025 inData.renderedCameras,
nullptr,
nullptr, overrideMaterial);
3026 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3030 if (!shaderPipeline)
3033 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3034 ia = subsetRenderable.subset.rhi.ia;
3036 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3037 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3038 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3040 QSSGRhiShaderResourceBindingList bindings;
3041 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3044 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3045 while (renderableImage) {
3046 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3047 const int samplerHint =
int(renderableImage->m_mapType);
3048 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3049 if (samplerBinding >= 0) {
3050 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3052 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3053 QSSGRhiSamplerDescription samplerDesc = {
3054 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3055 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3056 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3057 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3058 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3059 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3061 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3062 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3063 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3066 renderableImage = renderableImage->m_nextImage;
3069 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3072 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3073 if (normalTextureBinding >= 0) {
3074 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3075 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3076 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3077 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3078 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3079 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3083 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3084 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3086 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3087 QRhiSampler::Nearest,
3089 QRhiSampler::ClampToEdge,
3090 QRhiSampler::ClampToEdge,
3093 bindings.addTexture(binding,
3094 QRhiShaderResourceBinding::VertexStage,
3101 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3102 if (targetsTexture) {
3103 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3105 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3106 QRhiSampler::Nearest,
3108 QRhiSampler::ClampToEdge,
3109 QRhiSampler::ClampToEdge,
3110 QRhiSampler::ClampToEdge
3112 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3117 if (shaderPipeline->isLightingEnabled()) {
3118 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3119 shaderPipeline->ub0LightDataOffset(),
3120 sizeof(QSSGShaderLightsUniformData));
3121 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3122 shaderPipeline->ub0DirectionalLightDataOffset(),
3123 sizeof(QSSGShaderDirectionalLightsUniformData));
3126 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3127 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3130 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3131 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
3132 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3135 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3136 QRhiSampler::Linear,
3138 QRhiSampler::ClampToEdge,
3139 QRhiSampler::ClampToEdge,
3140 QRhiSampler::Repeat });
3142 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3146 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3147 QRhiTexture *texture = shaderPipeline->shadowMapBlueNoiseTexture();
3150 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3151 texture = rhiCtx->dummyTexture({ }, resourceUpdates);
3152 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3155 QRhiSampler *sampler = rhiCtx->sampler(
3156 { QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3158 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3162 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3164 auto texture = shaderPipeline->lightProbeTexture();
3166 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3167 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
3168 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3172 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
3173 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3174 QRhiSampler::Linear,
3175 QRhiSampler::Linear,
3176 QSSGRhiHelpers::toRhi(tiling.first),
3177 QSSGRhiHelpers::toRhi(tiling.second),
3178 QRhiSampler::Repeat });
3179 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3183 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3185 QSSG_ASSERT(srb,
continue);
3186 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3187 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3188 rhiPassData.srb = srb;
3195 QSSGPassKey passKey,
3196 const QSSGRhiGraphicsPipelineState &basePipelineState,
3197 QRhiRenderPassDescriptor *rpDesc,
3199 QSSGRenderableObjectList &inObjects,
3200 QSSGShaderFeatures featureSet)
3202 const qsizetype index = inData.getUserRenderPassManager()->acquireUserPassSlot();
3207 QSSGRhiGraphicsPipelineState ps = basePipelineState;
3208 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3210 for (
const QSSGRenderableObjectHandle &handle : std::as_const(inObjects)) {
3211 QSSGRenderableObject *obj = handle.obj;
3212 QSSGRhiShaderPipelinePtr shaderPipeline;
3214 QSSGRhiDrawCallData *dcd =
nullptr;
3215 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset ||
3216 obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3217 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3218 const void *modelNode = &subsetRenderable.modelContext.model;
3219 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
3222 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
3223 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3224 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
3225 if (!ps.userSetCullMode)
3226 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3228 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet);
3229 if (shaderPipeline) {
3230 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3231 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3232 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable,
3233 inData.renderedCameras,
nullptr,
nullptr);
3234 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3236 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3237 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3238 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
3239 if (!ps.userSetCullMode)
3240 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
3242 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
3243 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable,
3244 inData.getDefaultMaterialPropertyTable(), featureSet);
3245 if (shaderPipeline) {
3246 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3247 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3248 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3249 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3250 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3254 if (!shaderPipeline)
3258 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset ||
3259 obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3260 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
3261 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3262 ia = subsetRenderable.subset.rhi.ia;
3264 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3265 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3266 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3268 QSSGRhiShaderResourceBindingList bindings;
3269 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3272 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3273 while (renderableImage) {
3274 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3275 const int samplerHint =
int(renderableImage->m_mapType);
3276 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3277 if (samplerBinding >= 0) {
3278 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3279 if (samplerBinding >= 0 && texture) {
3280 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3281 QSSGRhiSamplerDescription samplerDesc = {
3282 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3283 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3284 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3285 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3286 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3287 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3289 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3290 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3291 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3294 renderableImage = renderableImage->m_nextImage;
3297 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3300 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3301 if (normalTextureBinding >= 0) {
3302 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3303 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3304 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3305 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3306 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3307 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3311 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3312 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3314 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3315 QRhiSampler::Nearest,
3317 QRhiSampler::ClampToEdge,
3318 QRhiSampler::ClampToEdge,
3321 bindings.addTexture(binding,
3322 QRhiShaderResourceBinding::VertexStage,
3329 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3330 if (targetsTexture) {
3331 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3333 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3334 QRhiSampler::Nearest,
3336 QRhiSampler::ClampToEdge,
3337 QRhiSampler::ClampToEdge,
3338 QRhiSampler::ClampToEdge
3340 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3345 if (shaderPipeline->isLightingEnabled()) {
3346 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3347 shaderPipeline->ub0LightDataOffset(),
3348 sizeof(QSSGShaderLightsUniformData));
3349 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3350 shaderPipeline->ub0DirectionalLightDataOffset(),
3351 sizeof(QSSGShaderDirectionalLightsUniformData));
3354 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3355 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3358 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3359 texture = rhiCtx->dummyTexture({ }, resourceUpdates);
3360 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3363 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3364 QRhiSampler::Linear,
3366 QRhiSampler::ClampToEdge,
3367 QRhiSampler::ClampToEdge,
3368 QRhiSampler::Repeat });
3370 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3374 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3375 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
3376 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
3378 QRhiTexture *texture = shadowMapBlueNoise;
3379 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3380 QRhiSampler::Linear,
3382 QRhiSampler::Repeat,
3383 QRhiSampler::Repeat,
3384 QRhiSampler::Repeat });
3385 Q_ASSERT(texture && sampler);
3386 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3389 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3390 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
3391 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3392 QRhiSampler::Linear,
3394 QRhiSampler::Repeat,
3395 QRhiSampler::Repeat,
3396 QRhiSampler::Repeat });
3397 Q_ASSERT(texture && sampler);
3398 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3399 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3404 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
3405 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
3406 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
3407 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
3408 ? QRhiSampler::Linear
3409 : QRhiSampler::None;
3410 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3411 QRhiSampler::Linear,
3413 QRhiSampler::ClampToEdge,
3414 QRhiSampler::ClampToEdge,
3415 QRhiSampler::Repeat });
3416 if (reflectionSampler >= 0 && reflectionTexture)
3417 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
3420 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3422 auto texture = shaderPipeline->lightProbeTexture();
3424 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3425 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
3426 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3430 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
3431 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3432 QRhiSampler::Linear,
3433 QRhiSampler::Linear,
3434 QSSGRhiHelpers::toRhi(tiling.first),
3435 QSSGRhiHelpers::toRhi(tiling.second),
3436 QRhiSampler::Repeat });
3437 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3441 if (shaderPipeline->screenTexture()) {
3442 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
3443 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
3444 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
3445 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
3446 ? QRhiSampler::Linear : QRhiSampler::None;
3447 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
3448 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3449 if (screenTextureBinding >= 0) {
3450 bindings.addTexture(screenTextureBinding,
3451 QRhiShaderResourceBinding::FragmentStage,
3452 shaderPipeline->screenTexture(), sampler);
3454 if (screenTextureArrayBinding >= 0) {
3455 bindings.addTexture(screenTextureArrayBinding,
3456 QRhiShaderResourceBinding::FragmentStage,
3457 shaderPipeline->screenTexture(), sampler);
3462 if (shaderPipeline->lightmapTexture()) {
3463 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
3465 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
3466 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
3467 bindings.addTexture(binding,
3468 QRhiShaderResourceBinding::FragmentStage,
3469 shaderPipeline->lightmapTexture(), sampler);
3476 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3477 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3479 int maxSamplerBinding = -1;
3480 QVector<QShaderDescription::InOutVariable> samplerVars =
3481 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
3482 const auto combinedSamplers = shaderPipeline->vertexStage()->shader().description().combinedImageSamplers();
3483 for (
const QShaderDescription::InOutVariable &var : combinedSamplers) {
3484 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
3485 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
3486 if (it == samplerVars.cend())
3487 samplerVars.append(var);
3490 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
3491 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
3493 if (maxSamplerBinding >= 0) {
3494 int extraTexCount = shaderPipeline->extraTextureCount();
3495 for (
int i = 0; i < extraTexCount; ++i) {
3496 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
3497 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
3498 if (samplerBinding >= 0) {
3499 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
3500 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
3501 bindings.addTexture(samplerBinding,
3502 QRhiShaderResourceBinding::FragmentStage,
3510 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3512 QSSG_ASSERT(srb,
continue);
3514 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3515 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3516 rhiPassData.srb = srb;
3525 QSSGPassKey passKey,
3526 const QSSGRhiGraphicsPipelineState &basePipelineState,
3527 QRhiRenderPassDescriptor *rpDesc,
3530 QSSGRenderableObjectList &inObjects,
3531 QSSGShaderFeatures featureSet)
3533 const qsizetype index = inData.getUserRenderPassManager()->acquireUserPassSlot();
3539 QSSGRhiGraphicsPipelineState ps = basePipelineState;
3540 for (
const QSSGRenderableObjectHandle &handle : std::as_const(inObjects)) {
3541 QSSGRenderableObject *obj = handle.obj;
3542 QSSGRhiShaderPipelinePtr shaderPipeline;
3543 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3544 const auto &bufferManager = inData.contextInterface()->bufferManager();
3546 featureSet.set(QSSGShaderFeatures::Feature::UserRenderPass,
true);
3548 QSSGRhiDrawCallData *dcd =
nullptr;
3549 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3550 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3551 const void *modelNode = &subsetRenderable.modelContext.model;
3552 dcd = &rhiCtxD->drawCallData({ passKey, modelNode, &subsetRenderable.material, 0 });
3555 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset) {
3556 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3557 const auto &material =
static_cast<
const QSSGRenderDefaultMaterial &>(subsetRenderable.getMaterial());
3558 if (!ps.userSetCullMode)
3559 ps.cullMode = QSSGRhiHelpers::toCullMode(material.cullMode);
3561 shaderPipeline = shadersForDefaultMaterial(&ps, subsetRenderable, featureSet, shaderAugmentation);
3562 if (shaderPipeline) {
3563 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3564 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3566 for (
const auto &u : shaderAugmentation.propertyUniforms)
3567 shaderPipeline->setShaderResources(ubufData, *bufferManager, u.name, u.value, u.shaderDataType);
3568 updateUniformsForDefaultMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3569 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3571 }
else if (obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3572 QSSGSubsetRenderable &subsetRenderable(*
static_cast<QSSGSubsetRenderable *>(obj));
3573 const auto &material =
static_cast<
const QSSGRenderCustomMaterial &>(subsetRenderable.getMaterial());
3574 if (!ps.userSetCullMode)
3575 ps.cullMode = QSSGRhiHelpers::toCullMode(material.m_cullMode);
3577 QSSGCustomMaterialSystem &customMaterialSystem(*subsetRenderable.renderer->contextInterface()->customMaterialSystem().get());
3579 if (material.m_shadingMode == QSSGRenderCustomMaterial::ShadingMode::Unshaded)
3580 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet);
3582 shaderPipeline = customMaterialSystem.shadersForCustomMaterial(&ps, material, subsetRenderable, inData.getDefaultMaterialPropertyTable(), featureSet, shaderAugmentation);
3584 if (shaderPipeline) {
3585 shaderPipeline->ensureCombinedUniformBuffer(&dcd->ubuf);
3586 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
3588 for (
const auto &u : shaderAugmentation.propertyUniforms)
3589 shaderPipeline->setShaderResources(ubufData, *bufferManager, u.name, u.value, u.shaderDataType);
3590 customMaterialSystem.updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, inData, ubufData, &ps, material,
3591 subsetRenderable, inData.renderedCameras,
nullptr,
nullptr);
3592 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
3596 if (!shaderPipeline) {
3598 qDebug() <<
"Failed to prepare user augmented pass for object.";
3603 if (obj->type == QSSGRenderableObject::Type::DefaultMaterialMeshSubset || obj->type == QSSGRenderableObject::Type::CustomMaterialMeshSubset) {
3604 QSSGSubsetRenderable &subsetRenderable(
static_cast<QSSGSubsetRenderable &>(*obj));
3605 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps);
3606 ia = subsetRenderable.subset.rhi.ia;
3608 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
3609 int instanceBufferBinding = setupInstancing(&subsetRenderable, &ps, rhiCtx, cameraDatas[0].direction, cameraDatas[0].position);
3610 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
3612 QSSGRhiShaderResourceBindingList bindings;
3613 bindings.addUniformBuffer(0, RENDERER_VISIBILITY_ALL, dcd->ubuf);
3616 QSSGRenderableImage *renderableImage = subsetRenderable.firstImage;
3617 while (renderableImage) {
3618 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
3619 const int samplerHint =
int(renderableImage->m_mapType);
3620 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
3621 if (samplerBinding >= 0) {
3622 QRhiTexture *texture = renderableImage->m_texture.m_texture;
3623 if (samplerBinding >= 0 && texture) {
3624 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
3625 QSSGRhiSamplerDescription samplerDesc = {
3626 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
3627 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
3628 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
3629 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
3630 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
3631 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
3633 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
3634 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
3635 bindings.addTexture(samplerBinding, RENDERER_VISIBILITY_ALL, texture, sampler);
3638 renderableImage = renderableImage->m_nextImage;
3641 addDepthTextureBindings(rhiCtx, shaderPipeline.get(), bindings);
3644 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
3645 if (normalTextureBinding >= 0) {
3646 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
3647 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3648 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3649 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
3650 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3651 bindings.addTexture(normalTextureBinding, RENDERER_VISIBILITY_ALL, dummyTexture, sampler);
3657 if (QRhiTexture *boneTexture = inData.getBonemapTexture(subsetRenderable.modelContext)) {
3658 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
3660 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3661 QRhiSampler::Nearest,
3663 QRhiSampler::ClampToEdge,
3664 QRhiSampler::ClampToEdge,
3667 bindings.addTexture(binding,
3668 QRhiShaderResourceBinding::VertexStage,
3675 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
3676 if (targetsTexture) {
3677 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
3679 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
3680 QRhiSampler::Nearest,
3682 QRhiSampler::ClampToEdge,
3683 QRhiSampler::ClampToEdge,
3684 QRhiSampler::ClampToEdge
3686 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
3691 if (shaderPipeline->isLightingEnabled()) {
3692 bindings.addUniformBuffer(1, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3693 shaderPipeline->ub0LightDataOffset(),
3694 sizeof(QSSGShaderLightsUniformData));
3695 bindings.addUniformBuffer(2, RENDERER_VISIBILITY_ALL, dcd->ubuf,
3696 shaderPipeline->ub0DirectionalLightDataOffset(),
3697 sizeof(QSSGShaderDirectionalLightsUniformData));
3700 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture"); binding >= 0) {
3701 QRhiTexture *texture = shaderPipeline->shadowMapAtlasTexture();
3704 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3705 texture = rhiCtx->dummyTexture({ }, resourceUpdates, QSize(1, 1), Qt::black, 2);
3706 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3709 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3710 QRhiSampler::Linear,
3712 QRhiSampler::ClampToEdge,
3713 QRhiSampler::ClampToEdge,
3714 QRhiSampler::Repeat });
3716 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3720 if (
int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture"); binding >= 0) {
3721 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
3722 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
3724 QRhiTexture *texture = shadowMapBlueNoise;
3725 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3726 QRhiSampler::Linear,
3728 QRhiSampler::Repeat,
3729 QRhiSampler::Repeat,
3730 QRhiSampler::Repeat });
3731 Q_ASSERT(texture && sampler);
3732 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3735 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3736 QRhiTexture *texture = rhiCtx->dummyTexture({}, resourceUpdates);
3737 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3738 QRhiSampler::Linear,
3740 QRhiSampler::Repeat,
3741 QRhiSampler::Repeat,
3742 QRhiSampler::Repeat });
3743 Q_ASSERT(texture && sampler);
3744 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3745 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3752 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
3753 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
3754 QRhiTexture* reflectionTexture = inData.getReflectionMapManager()->reflectionMapEntry(subsetRenderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
3755 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
3756 ? QRhiSampler::Linear
3757 : QRhiSampler::None;
3758 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3759 QRhiSampler::Linear,
3761 QRhiSampler::ClampToEdge,
3762 QRhiSampler::ClampToEdge,
3763 QRhiSampler::Repeat });
3764 if (reflectionSampler >= 0 && reflectionTexture)
3765 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
3767 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
3769 auto texture = shaderPipeline->lightProbeTexture();
3771 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3772 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
3773 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3777 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
3778 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
3779 QRhiSampler::Linear,
3780 QRhiSampler::Linear,
3781 QSSGRhiHelpers::toRhi(tiling.first),
3782 QSSGRhiHelpers::toRhi(tiling.second),
3783 QRhiSampler::Repeat });
3784 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
3788 if (shaderPipeline->screenTexture()) {
3789 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
3790 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
3791 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
3796 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
3797 ? QRhiSampler::Linear : QRhiSampler::None;
3798 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
3799 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
3800 if (screenTextureBinding >= 0) {
3801 bindings.addTexture(screenTextureBinding,
3802 QRhiShaderResourceBinding::FragmentStage,
3803 shaderPipeline->screenTexture(), sampler);
3805 if (screenTextureArrayBinding >= 0) {
3806 bindings.addTexture(screenTextureArrayBinding,
3807 QRhiShaderResourceBinding::FragmentStage,
3808 shaderPipeline->screenTexture(), sampler);
3813 if (shaderPipeline->lightmapTexture()) {
3814 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
3816 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
3817 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
3818 bindings.addTexture(binding,
3819 QRhiShaderResourceBinding::FragmentStage,
3820 shaderPipeline->lightmapTexture(), sampler);
3827 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
3828 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
3830 QVector<QShaderDescription::InOutVariable> samplerVars =
3831 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
3832 const auto combinedSamplers = shaderPipeline->vertexStage()->shader().description().combinedImageSamplers();
3833 for (
const QShaderDescription::InOutVariable &var : combinedSamplers) {
3834 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
3835 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
3836 if (it == samplerVars.cend())
3837 samplerVars.append(var);
3840 int maxSamplerBinding = -1;
3841 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
3842 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
3851 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
3853 if (maxSamplerBinding >= 0) {
3855 int extraTexCount = shaderPipeline->extraTextureCount();
3856 for (
int i = 0; i < extraTexCount; ++i) {
3857 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
3858 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
3859 if (samplerBinding >= 0) {
3860 samplerBindingsSpecified.setBit(samplerBinding);
3861 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
3862 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
3863 bindings.addTexture(samplerBinding,
3864 QRhiShaderResourceBinding::FragmentStage,
3872 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
3873 QSSG_ASSERT(srb,
return -1);
3874 auto &rhiPassData = subsetRenderable.rhiRenderData.userPassData[index];
3875 rhiPassData.pipeline = rhiCtxD->pipeline(ps, rpDesc, srb);
3876 rhiPassData.srb = srb;
3940 QSSGPassKey passKey,
3942 const QMatrix4x4 &viewProjection,
3944 QRhiRenderPassDescriptor *renderPassDescriptor,
3945 QSSGRhiGraphicsPipelineState *ps,
3946 QSSGRenderMotionVectorMap &motionVectorMapManager)
3948 if (inObject.type != QSSGRenderableObject::Type::DefaultMaterialMeshSubset &&
3949 inObject.type != QSSGRenderableObject::Type::CustomMaterialMeshSubset)
3952 QSSGSubsetRenderable &subsetRenderable =
static_cast<QSSGSubsetRenderable &>(inObject);
3953 auto &modelNode = subsetRenderable.modelContext.model;
3955 bool skin = modelNode.usesBoneTexture();
3956 bool instance = modelNode.instanceCount() > 0;
3957 bool morph = modelNode.morphTargets.size() > 0;
3959 QSSGRhiShaderPipelinePtr shaderPipeline = inData.contextInterface()->shaderCache()->
3960 getBuiltInRhiShaders().getRhiMotionVectorShader(skin, instance, morph);
3962 if (!shaderPipeline)
3965 QSSGRhiShaderResourceBindingList bindings;
3967 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
3968 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({ passKey, &modelNode,
nullptr, 0 });
3971 QSSGRenderTextureData *boneTextureData =
nullptr;
3973 boneTextureData = modelNode.skin;
3974 else if (modelNode.skeleton)
3975 boneTextureData = &modelNode.skeleton->boneTexData;
3977 QMatrix4x4 modelViewProjection = subsetRenderable.modelContext.modelViewProjections[0];
3978 QMatrix4x4 instanceLocal;
3979 QMatrix4x4 instanceGlobal;
3982 instanceLocal = inData.getInstanceTransforms(modelNode).local;
3983 instanceGlobal = inData.getInstanceTransforms(modelNode).global;
3985 modelViewProjection = viewProjection;
3987 auto motionData = motionVectorMapManager.trackMotionData(&modelNode,
3988 modelViewProjection,
3992 modelNode.instanceTable,
3993 modelNode.morphWeights);
3994 float velocityAmount = subsetRenderable.modelContext.model.motionVectorScale;
3995 int morphTargetCount = modelNode.morphWeights.count();
4007 const int ubufSize = 416;
4010 dcd.ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic,
4011 QRhiBuffer::UniformBuffer,
4016 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
4018 memcpy(ubufData, modelViewProjection.constData(), 64);
4020 memcpy(ubufData + ubufOffset, motionData.prevModelViewProjection.constData(), 64);
4022 memcpy(ubufData + ubufOffset, instanceLocal.constData(), 64);
4024 memcpy(ubufData + ubufOffset, instanceGlobal.constData(), 64);
4026 memcpy(ubufData + ubufOffset, motionData.prevInstanceLocal.constData(), 64);
4028 memcpy(ubufData + ubufOffset, motionData.prevInstanceGlobal.constData(), 64);
4030 memcpy(ubufData + ubufOffset, &inData.layer.currentAndLastJitter, 16);
4032 memcpy(ubufData + ubufOffset, &velocityAmount, 4);
4034 memcpy(ubufData + ubufOffset, &morphTargetCount, 4);
4035 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
4037 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::VertexStage |
4038 QRhiShaderResourceBinding::FragmentStage, dcd.ubuf);
4040 QRhiSampler *nearestSampler =
nullptr;
4042 if (skin || instance) {
4043 nearestSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
4044 QRhiSampler::Nearest,
4046 QRhiSampler::ClampToEdge,
4047 QRhiSampler::ClampToEdge,
4053 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
4056 bindings.addTexture(binding,
4057 QRhiShaderResourceBinding::VertexStage,
4058 inData.getBonemapTexture(subsetRenderable.modelContext),
4060 binding = shaderPipeline->bindingForTexture(
"lastBoneTexture");
4062 bindings.addTexture(binding,
4063 QRhiShaderResourceBinding::VertexStage,
4064 motionData.prevBoneTexture.m_texture,
4071 int binding = shaderPipeline->bindingForTexture(
"lastInstanceTexture");
4073 bindings.addTexture(binding,
4074 QRhiShaderResourceBinding::VertexStage,
4075 motionData.prevInstanceTexture.m_texture,
4080 auto *targetsTexture = subsetRenderable.subset.rhi.targetsTexture;
4081 if (targetsTexture) {
4082 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
4084 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
4085 QRhiSampler::Nearest,
4087 QRhiSampler::ClampToEdge,
4088 QRhiSampler::ClampToEdge,
4089 QRhiSampler::ClampToEdge
4091 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, subsetRenderable.subset.rhi.targetsTexture, targetsSampler);
4093 if ((binding = shaderPipeline->bindingForTexture(
"morphWeightTexture")) >= 0)
4094 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, motionData.currentMorphWeightTexture.m_texture, targetsSampler);
4096 if ((binding = shaderPipeline->bindingForTexture(
"lastMorphWeightTexture")) >= 0)
4097 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, motionData.prevMorphWeightTexture.m_texture, targetsSampler);
4101 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
4102 ia = subsetRenderable.subset.rhi.ia;
4103 const QSSGRenderCameraDataList &cameraDatas(*inData.renderedCameraData);
4104 QVector3D cameraDirection = cameraDatas[0].direction;
4105 QVector3D cameraPosition = cameraDatas[0].position;
4106 int instanceBufferBinding = setupInstancing(&subsetRenderable, ps, rhiCtx, cameraDirection, cameraPosition);
4107 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
4108 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(*ps, shaderPipeline.get());
4110 QRhiShaderResourceBindings *&srb = dcd.srb;
4111 bool srbChanged =
false;
4112 if (!srb || bindings != dcd.bindings) {
4113 srb = rhiCtxD->srb(bindings);
4114 rhiCtxD->releaseCachedSrb(dcd.bindings);
4115 dcd.bindings = bindings;
4119 subsetRenderable.rhiRenderData.motionVectorPass.srb = srb;
4121 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
4124 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
4125 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
4128 subsetRenderable.rhiRenderData.motionVectorPass.pipeline = dcd.pipeline;
4131 subsetRenderable.rhiRenderData.motionVectorPass.pipeline = rhiCtxD->pipeline(pipelineKey,
4132 renderPassDescriptor,
4134 dcd.pipeline = subsetRenderable.rhiRenderData.motionVectorPass.pipeline;
4135 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
4136 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;