192void QSSGCustomMaterialSystem::rhiPrepareRenderable(QSSGRhiGraphicsPipelineState *ps,
194 QSSGSubsetRenderable &renderable,
195 const QSSGShaderFeatures &featureSet,
196 const QSSGRenderCustomMaterial &material,
197 const QSSGLayerRenderData &layerData,
198 QRhiRenderPassDescriptor *renderPassDescriptor,
202 QSSGRenderCamera *alteredCamera,
203 QSSGRenderTextureCubeFace cubeFace,
204 QMatrix4x4 *alteredModelViewProjection,
205 QSSGReflectionMapEntry *entry,
208 QSSGRhiContext *rhiCtx = context->rhiContext().get();
210 QRhiGraphicsPipeline::TargetBlend blend;
211 if (material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Blending)) {
213 blend.srcColor = material.m_srcBlend;
214 blend.srcAlpha = material.m_srcAlphaBlend;
215 blend.dstColor = material.m_dstBlend;
216 blend.dstAlpha = material.m_dstAlphaBlend;
219 const QSSGCullFaceMode cullMode = material.m_cullMode;
221 const auto &defaultMaterialShaderKeyProperties = layerData.getDefaultMaterialPropertyTable();
223 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(renderable.shaderDescription);
225 const auto &shaderPipeline = shadersForCustomMaterial(ps, material, renderable, defaultMaterialShaderKeyProperties, featureSet);
227 if (shaderPipeline) {
228 QSSGRhiShaderResourceBindingList bindings;
229 const auto &modelNode = renderable.modelContext.model;
239 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
240 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone)
241 * (cubeFaceIdx + (quintptr(renderable.subset.offset) << 3));
245 const auto *materialResource =
static_cast<
const QSSGRenderGraphObject *>(&material);
246 QSSGRhiDrawCallData &dcd = QSSGRhiContextPrivate::get(rhiCtx)->drawCallData({ passKey, &modelNode,
247 materialResource, entry,
250 shaderPipeline->ensureCombinedUniformBuffer(&dcd.ubuf);
251 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
252 if (!alteredCamera) {
253 updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, layerData, ubufData, ps, material, renderable, layerData.renderedCameras,
nullptr,
nullptr);
255 QSSGRenderCameraList cameras({ alteredCamera });
256 updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, layerData, ubufData, ps, material, renderable, cameras,
nullptr, alteredModelViewProjection);
259 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &renderable.modelContext.model, renderable.subset.offset);
260 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
263 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &renderable.modelContext.model);
264 bool instancing =
false;
265 if (!alteredCamera) {
266 const QSSGRenderCameraDataList &cameraDatas(*layerData.renderedCameraData);
267 instancing = QSSGLayerRenderData::prepareInstancing(rhiCtx, &renderable, cameraDatas[0].direction, cameraDatas[0].position, renderable.instancingLodMin, renderable.instancingLodMax);
269 const auto &altCamTransform = layerData.getGlobalTransform(*alteredCamera);
270 instancing = QSSGLayerRenderData::prepareInstancing(rhiCtx, &renderable, QSSGRenderNode::getScalingCorrectDirection(altCamTransform), QSSGRenderNode::getGlobalPos(altCamTransform), renderable.instancingLodMin, renderable.instancingLodMax);
273 ps->samples = samples;
274 ps->viewCount = viewCount;
276 ps->cullMode = QSSGRhiHelpers::toCullMode(cullMode);
279 ps->targetBlend[0] = blend;
281 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
283 ia = renderable.subset.rhi.ia;
286 int instanceBufferBinding = 0;
289 const quint32 stride = renderable.modelContext.model.instanceTable->stride();
290 QVarLengthArray<QRhiVertexInputBinding, 8> bindings;
291 std::copy(ia.inputLayout.cbeginBindings(),
292 ia.inputLayout.cendBindings(),
293 std::back_inserter(bindings));
294 bindings.append({ stride, QRhiVertexInputBinding::PerInstance });
295 instanceBufferBinding = bindings.size() - 1;
296 ia.inputLayout.setBindings(bindings.cbegin(), bindings.cend());
299 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
301 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
302 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
303 QRhiTexture *dummyTextureArray = rhiCtx->dummyTexture({}, resourceUpdates, QSize(64, 64), Qt::black, qMax(2, viewCount));
304 QRhiTexture *dummyTexture3D = rhiCtx->dummyTexture(QRhiTexture::ThreeDimensional, resourceUpdates);
305 QRhiTexture *dummyCubeTexture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
306 QRhiTexture *dummyCubeTextureArray = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates, QSize(64, 64), Qt::black, qMax(2, viewCount));
308 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
310 bindings.addUniformBuffer(0, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline->ub0Size());
311 bindings.addUniformBuffer(1, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, shaderPipeline->ub0LightDataOffset(),
sizeof(QSSGShaderLightsUniformData));
312 bindings.addUniformBuffer(2, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, shaderPipeline->ub0DirectionalLightDataOffset(),
sizeof(QSSGShaderDirectionalLightsUniformData));
314 QVector<QShaderDescription::InOutVariable> samplerVars =
315 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
316 const auto combinedSamplers = shaderPipeline->vertexStage()->shader().description().combinedImageSamplers();
317 for (
const QShaderDescription::InOutVariable &var : combinedSamplers) {
318 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
319 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
320 if (it == samplerVars.cend())
321 samplerVars.append(var);
324 int maxSamplerBinding = -1;
325 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
326 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
335 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
338 samplerBindingsSpecified.setBit(shaderPipeline->bindingForTexture(
"qt_particleTexture"));
341 if (QRhiTexture *boneTexture = layerData.getBonemapTexture(renderable.modelContext)) {
342 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
344 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
345 QRhiSampler::Nearest,
347 QRhiSampler::ClampToEdge,
348 QRhiSampler::ClampToEdge,
351 bindings.addTexture(binding,
352 QRhiShaderResourceBinding::VertexStage,
355 samplerBindingsSpecified.setBit(binding);
360 auto *targetsTexture = renderable.subset.rhi.targetsTexture;
361 if (targetsTexture) {
362 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
364 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
365 QRhiSampler::Nearest,
367 QRhiSampler::ClampToEdge,
368 QRhiSampler::ClampToEdge,
369 QRhiSampler::ClampToEdge
371 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, renderable.subset.rhi.targetsTexture, targetsSampler);
372 samplerBindingsSpecified.setBit(binding);
379 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
380 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
381 QRhiTexture* reflectionTexture = layerData.getReflectionMapManager()->reflectionMapEntry(renderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
382 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
383 ? QRhiSampler::Linear
385 QRhiSampler *sampler = rhiCtx->sampler(
386 { QRhiSampler::Linear, QRhiSampler::Linear, mipMapFilter, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
387 if (reflectionSampler >= 0 && reflectionTexture) {
388 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
389 samplerBindingsSpecified.setBit(reflectionSampler);
393 if (
int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
395 auto texture = shaderPipeline->lightProbeTexture();
397 texture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
400 samplerBindingsSpecified.setBit(binding);
401 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
402 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear,
405 QSSGRhiHelpers::toRhi(tiling.first),
406 QSSGRhiHelpers::toRhi(tiling.second),
407 QRhiSampler::Repeat });
408 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
411 if (shaderPipeline->screenTexture()) {
412 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
413 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
414 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
415 QRhiTexture *screenTexture = shaderPipeline->screenTexture();
418 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
420 const QRhiTexture::Flags flags = screenTexture->flags();
422 screenTexture = rhiCtx->dummyTexture(flags, resourceUpdates);
423 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
429 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
430 ? QRhiSampler::Linear : QRhiSampler::None;
431 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
432 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
433 if (screenTextureBinding >= 0) {
434 samplerBindingsSpecified.setBit(screenTextureBinding);
435 bindings.addTexture(screenTextureBinding,
436 QRhiShaderResourceBinding::FragmentStage,
437 screenTexture, sampler);
439 if (screenTextureArrayBinding >= 0) {
440 samplerBindingsSpecified.setBit(screenTextureArrayBinding);
441 bindings.addTexture(screenTextureArrayBinding,
442 QRhiShaderResourceBinding::FragmentStage,
443 screenTexture, sampler);
448 if (shaderPipeline->depthTexture()) {
449 const int depthTextureBinding = shaderPipeline->bindingForTexture(
"qt_depthTexture",
int(QSSGRhiSamplerBindingHints::DepthTexture));
450 const int depthTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_depthTextureArray",
int(QSSGRhiSamplerBindingHints::DepthTextureArray));
451 if (depthTextureBinding >= 0 || depthTextureArrayBinding >= 0) {
453 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
454 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
455 if (depthTextureBinding >= 0) {
456 samplerBindingsSpecified.setBit(depthTextureBinding);
457 bindings.addTexture(depthTextureBinding,
458 CUSTOM_MATERIAL_VISIBILITY_ALL,
459 shaderPipeline->depthTexture(), sampler);
461 if (depthTextureArrayBinding >= 0) {
462 samplerBindingsSpecified.setBit(depthTextureArrayBinding);
463 bindings.addTexture(depthTextureArrayBinding,
464 CUSTOM_MATERIAL_VISIBILITY_ALL,
465 shaderPipeline->depthTexture(), sampler);
470 if (shaderPipeline->normalTexture()) {
471 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
472 if (normalTextureBinding >= 0) {
474 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
475 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
476 samplerBindingsSpecified.setBit(normalTextureBinding);
477 bindings.addTexture(normalTextureBinding, CUSTOM_MATERIAL_VISIBILITY_ALL, shaderPipeline->normalTexture(), sampler);
481 if (shaderPipeline->ssaoTexture()) {
482 const int ssaoTextureBinding = shaderPipeline->bindingForTexture(
"qt_aoTexture",
int(QSSGRhiSamplerBindingHints::AoTexture));
483 const int ssaoTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_aoTextureArray",
int(QSSGRhiSamplerBindingHints::AoTextureArray));
484 if (ssaoTextureBinding >= 0 || ssaoTextureArrayBinding >= 0) {
486 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
487 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
488 if (ssaoTextureBinding >= 0) {
489 samplerBindingsSpecified.setBit(ssaoTextureBinding);
490 bindings.addTexture(ssaoTextureBinding,
491 QRhiShaderResourceBinding::FragmentStage,
492 shaderPipeline->ssaoTexture(), sampler);
494 if (ssaoTextureArrayBinding >= 0) {
495 samplerBindingsSpecified.setBit(ssaoTextureArrayBinding);
496 bindings.addTexture(ssaoTextureArrayBinding,
497 QRhiShaderResourceBinding::FragmentStage,
498 shaderPipeline->ssaoTexture(), sampler);
503 if (shaderPipeline->lightmapTexture()) {
504 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
506 samplerBindingsSpecified.setBit(binding);
507 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
508 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
509 bindings.addTexture(binding,
510 QRhiShaderResourceBinding::FragmentStage,
511 shaderPipeline->lightmapTexture(), sampler);
515 if (shaderPipeline->MotionVectorTexture()) {
516 int binding = shaderPipeline->bindingForTexture(
"qt_motionVectorTexture",
int(QSSGRhiSamplerBindingHints::MotionVectorTexture));
518 samplerBindingsSpecified.setBit(binding);
519 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
520 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
521 bindings.addTexture(binding,
522 QRhiShaderResourceBinding::FragmentStage,
523 shaderPipeline->MotionVectorTexture(), sampler);
529 auto shadowMapAtlas = shaderPipeline->shadowMapAtlasTexture();
530 if (shadowMapAtlas) {
531 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture");
533 samplerBindingsSpecified.setBit(binding);
534 QRhiTexture *texture = shadowMapAtlas;
535 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
536 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
537 Q_ASSERT(texture && sampler);
538 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
543 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
544 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
546 samplerBindingsSpecified.setBit(binding);
547 QRhiTexture *texture = shadowMapBlueNoise;
548 QRhiSampler *sampler = rhiCtx->sampler(
549 { QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
550 Q_ASSERT(texture && sampler);
551 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
555 QSSGRenderableImage *renderableImage = renderable.firstImage;
556 while (renderableImage) {
557 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
558 const int samplerHint =
int(renderableImage->m_mapType);
559 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
560 if (samplerBinding >= 0) {
561 QRhiTexture *texture = renderableImage->m_texture.m_texture;
562 if (samplerBinding >= 0 && texture) {
563 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
564 QSSGRhiSamplerDescription samplerDesc = {
565 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
566 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
567 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
568 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
569 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
570 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
572 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
573 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
574 samplerBindingsSpecified.setBit(samplerBinding);
575 bindings.addTexture(samplerBinding,
576 CUSTOM_MATERIAL_VISIBILITY_ALL,
580 renderableImage = renderableImage->m_nextImage;
583 if (maxSamplerBinding >= 0) {
585 int customTexCount = shaderPipeline->extraTextureCount();
586 for (
int i = 0; i < customTexCount; ++i) {
587 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
588 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
589 if (samplerBinding >= 0) {
590 samplerBindingsSpecified.setBit(samplerBinding);
591 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
592 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
593 bindings.addTexture(samplerBinding,
594 CUSTOM_MATERIAL_VISIBILITY_ALL,
601 QRhiSampler *dummySampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
602 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
604 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars)) {
605 if (!samplerBindingsSpecified.testBit(var.binding)) {
606 QRhiTexture *t =
nullptr;
607 if (var.type == QShaderDescription::SamplerCube)
608 t = dummyCubeTexture;
609 else if (var.type == QShaderDescription::Sampler3D)
611 else if (var.type == QShaderDescription::Sampler2DArray)
612 t = dummyTextureArray;
613 else if (var.type == QShaderDescription::SamplerCubeArray)
614 t = dummyCubeTextureArray;
617 bindings.addTexture(var.binding, CUSTOM_MATERIAL_VISIBILITY_ALL, t, dummySampler);
622 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
624 if (oit && layerData.layer.oitMethod == QSSGRenderLayer::OITMethod::LinkedList)
625 RenderHelpers::addAccumulatorImageBindings(shaderPipeline.get(), bindings);
628 QRhiShaderResourceBindings *&srb = dcd.srb;
629 bool srbChanged =
false;
630 if (!srb || bindings != dcd.bindings) {
631 srb = rhiCtxD->srb(bindings);
632 rhiCtxD->releaseCachedSrb(dcd.bindings);
633 dcd.bindings = bindings;
637 if (cubeFace == QSSGRenderTextureCubeFaceNone)
638 renderable.rhiRenderData.mainPass.srb = srb;
640 renderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
642 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
645 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
646 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
649 if (cubeFace == QSSGRenderTextureCubeFaceNone)
650 renderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
652 renderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
654 if (cubeFace == QSSGRenderTextureCubeFaceNone) {
655 renderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
656 renderPassDescriptor,
658 dcd.pipeline = renderable.rhiRenderData.mainPass.pipeline;
660 renderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
661 renderPassDescriptor,
663 dcd.pipeline = renderable.rhiRenderData.reflectionPass.pipeline;
666 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
667 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;