185void QSSGCustomMaterialSystem::rhiPrepareRenderable(QSSGRhiGraphicsPipelineState *ps,
187 QSSGSubsetRenderable &renderable,
188 const QSSGShaderFeatures &featureSet,
189 const QSSGRenderCustomMaterial &material,
190 const QSSGLayerRenderData &layerData,
191 QRhiRenderPassDescriptor *renderPassDescriptor,
194 QSSGRenderCamera *alteredCamera,
195 QSSGRenderTextureCubeFace cubeFace,
196 QMatrix4x4 *alteredModelViewProjection,
197 QSSGReflectionMapEntry *entry,
200 QSSGRhiContext *rhiCtx = context->rhiContext().get();
202 QRhiGraphicsPipeline::TargetBlend blend;
203 if (material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Blending)) {
205 blend.srcColor = material.m_srcBlend;
206 blend.srcAlpha = material.m_srcAlphaBlend;
207 blend.dstColor = material.m_dstBlend;
208 blend.dstAlpha = material.m_dstAlphaBlend;
211 const QSSGCullFaceMode cullMode = material.m_cullMode;
213 const auto &defaultMaterialShaderKeyProperties = layerData.getDefaultMaterialPropertyTable();
215 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(renderable.shaderDescription);
217 const auto &shaderPipeline = shadersForCustomMaterial(ps, material, renderable, defaultMaterialShaderKeyProperties, featureSet);
219 if (shaderPipeline) {
220 QSSGRhiShaderResourceBindingList bindings;
221 const auto &modelNode = renderable.modelContext.model;
227 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
228 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * (cubeFaceIdx + (quintptr(renderable.subset.offset) << 3));
230 const auto entryPartA =
reinterpret_cast<quintptr>(&material);
231 const auto entryPartB =
reinterpret_cast<quintptr>(entry);
232 const void *entryKey =
reinterpret_cast<
const void *>(entryPartA ^ entryPartB);
234 QSSGRhiDrawCallData &dcd = QSSGRhiContextPrivate::get(rhiCtx)->drawCallData({ passKey, &modelNode, entryKey, entryIdx });
236 shaderPipeline->ensureCombinedUniformBuffer(&dcd.ubuf);
237 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
238 if (!alteredCamera) {
239 updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, layerData, ubufData, ps, material, renderable, layerData.renderedCameras,
nullptr,
nullptr);
241 QSSGRenderCameraList cameras({ alteredCamera });
242 updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, layerData, ubufData, ps, material, renderable, cameras,
nullptr, alteredModelViewProjection);
245 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &renderable.modelContext.model, renderable.subset.offset);
246 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
249 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &renderable.modelContext.model);
250 bool instancing =
false;
251 if (!alteredCamera) {
252 const QSSGRenderCameraDataList &cameraDatas(*layerData.renderedCameraData);
253 instancing = QSSGLayerRenderData::prepareInstancing(rhiCtx, &renderable, cameraDatas[0].direction, cameraDatas[0].position, renderable.instancingLodMin, renderable.instancingLodMax);
255 const auto &altCamTransform = layerData.getGlobalTransform(*alteredCamera);
256 instancing = QSSGLayerRenderData::prepareInstancing(rhiCtx, &renderable, QSSGRenderNode::getScalingCorrectDirection(altCamTransform), QSSGRenderNode::getGlobalPos(altCamTransform), renderable.instancingLodMin, renderable.instancingLodMax);
259 ps->samples = samples;
260 ps->viewCount = viewCount;
262 ps->cullMode = QSSGRhiHelpers::toCullMode(cullMode);
265 ps->targetBlend[0] = blend;
267 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
269 ia = renderable.subset.rhi.ia;
272 int instanceBufferBinding = 0;
275 const quint32 stride = renderable.modelContext.model.instanceTable->stride();
276 QVarLengthArray<QRhiVertexInputBinding, 8> bindings;
277 std::copy(ia.inputLayout.cbeginBindings(),
278 ia.inputLayout.cendBindings(),
279 std::back_inserter(bindings));
280 bindings.append({ stride, QRhiVertexInputBinding::PerInstance });
281 instanceBufferBinding = bindings.size() - 1;
282 ia.inputLayout.setBindings(bindings.cbegin(), bindings.cend());
285 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
287 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
288 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
289 QRhiTexture *dummyTexture3D = rhiCtx->dummyTexture(QRhiTexture::ThreeDimensional, resourceUpdates);
290 QRhiTexture *dummyCubeTexture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
291 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
293 bindings.addUniformBuffer(0, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline->ub0Size());
294 bindings.addUniformBuffer(1, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, shaderPipeline->ub0LightDataOffset(),
sizeof(QSSGShaderLightsUniformData));
295 bindings.addUniformBuffer(2, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, shaderPipeline->ub0DirectionalLightDataOffset(),
sizeof(QSSGShaderDirectionalLightsUniformData));
297 QVector<QShaderDescription::InOutVariable> samplerVars =
298 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
299 for (
const QShaderDescription::InOutVariable &var : shaderPipeline->vertexStage()->shader().description().combinedImageSamplers()) {
300 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
301 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
302 if (it == samplerVars.cend())
303 samplerVars.append(var);
306 int maxSamplerBinding = -1;
307 for (
const QShaderDescription::InOutVariable &var : samplerVars)
308 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
317 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
320 samplerBindingsSpecified.setBit(shaderPipeline->bindingForTexture(
"qt_particleTexture"));
323 if (QRhiTexture *boneTexture = layerData.getBonemapTexture(renderable.modelContext)) {
324 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
326 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
327 QRhiSampler::Nearest,
329 QRhiSampler::ClampToEdge,
330 QRhiSampler::ClampToEdge,
333 bindings.addTexture(binding,
334 QRhiShaderResourceBinding::VertexStage,
337 samplerBindingsSpecified.setBit(binding);
342 auto *targetsTexture = renderable.subset.rhi.targetsTexture;
343 if (targetsTexture) {
344 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
346 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
347 QRhiSampler::Nearest,
349 QRhiSampler::ClampToEdge,
350 QRhiSampler::ClampToEdge,
351 QRhiSampler::ClampToEdge
353 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, renderable.subset.rhi.targetsTexture, targetsSampler);
354 samplerBindingsSpecified.setBit(binding);
361 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
362 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
363 QRhiTexture* reflectionTexture = layerData.getReflectionMapManager()->reflectionMapEntry(renderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
364 const auto mipMapFilter = reflectionTexture && reflectionTexture->flags().testFlag(QRhiTexture::Flag::MipMapped)
365 ? QRhiSampler::Linear
367 QRhiSampler *sampler = rhiCtx->sampler(
368 { QRhiSampler::Linear, QRhiSampler::Linear, mipMapFilter, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
369 if (reflectionSampler >= 0 && reflectionTexture) {
370 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
371 samplerBindingsSpecified.setBit(reflectionSampler);
373 }
else if (shaderPipeline->lightProbeTexture()) {
374 int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
376 samplerBindingsSpecified.setBit(binding);
377 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
378 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
379 QSSGRhiHelpers::toRhi(tiling.first), QSSGRhiHelpers::toRhi(tiling.second), QRhiSampler::Repeat });
380 bindings.addTexture(binding,
381 QRhiShaderResourceBinding::FragmentStage,
382 shaderPipeline->lightProbeTexture(), sampler);
386 if (shaderPipeline->screenTexture()) {
387 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
388 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
389 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
394 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
395 ? QRhiSampler::Linear : QRhiSampler::None;
396 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
397 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
398 if (screenTextureBinding >= 0) {
399 samplerBindingsSpecified.setBit(screenTextureBinding);
400 bindings.addTexture(screenTextureBinding,
401 QRhiShaderResourceBinding::FragmentStage,
402 shaderPipeline->screenTexture(), sampler);
404 if (screenTextureArrayBinding >= 0) {
405 samplerBindingsSpecified.setBit(screenTextureArrayBinding);
406 bindings.addTexture(screenTextureArrayBinding,
407 QRhiShaderResourceBinding::FragmentStage,
408 shaderPipeline->screenTexture(), sampler);
413 if (shaderPipeline->depthTexture()) {
414 const int depthTextureBinding = shaderPipeline->bindingForTexture(
"qt_depthTexture",
int(QSSGRhiSamplerBindingHints::DepthTexture));
415 const int depthTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_depthTextureArray",
int(QSSGRhiSamplerBindingHints::DepthTextureArray));
416 if (depthTextureBinding >= 0 || depthTextureArrayBinding >= 0) {
418 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
419 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
420 if (depthTextureBinding >= 0) {
421 samplerBindingsSpecified.setBit(depthTextureBinding);
422 bindings.addTexture(depthTextureBinding,
423 CUSTOM_MATERIAL_VISIBILITY_ALL,
424 shaderPipeline->depthTexture(), sampler);
426 if (depthTextureArrayBinding >= 0) {
427 samplerBindingsSpecified.setBit(depthTextureArrayBinding);
428 bindings.addTexture(depthTextureArrayBinding,
429 CUSTOM_MATERIAL_VISIBILITY_ALL,
430 shaderPipeline->depthTexture(), sampler);
435 if (shaderPipeline->normalTexture()) {
436 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
437 if (normalTextureBinding >= 0) {
439 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
440 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
441 samplerBindingsSpecified.setBit(normalTextureBinding);
442 bindings.addTexture(normalTextureBinding, CUSTOM_MATERIAL_VISIBILITY_ALL, shaderPipeline->normalTexture(), sampler);
446 if (shaderPipeline->ssaoTexture()) {
447 const int ssaoTextureBinding = shaderPipeline->bindingForTexture(
"qt_aoTexture",
int(QSSGRhiSamplerBindingHints::AoTexture));
448 const int ssaoTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_aoTextureArray",
int(QSSGRhiSamplerBindingHints::AoTextureArray));
449 if (ssaoTextureBinding >= 0 || ssaoTextureArrayBinding >= 0) {
451 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
452 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
453 if (ssaoTextureBinding >= 0) {
454 samplerBindingsSpecified.setBit(ssaoTextureBinding);
455 bindings.addTexture(ssaoTextureBinding,
456 QRhiShaderResourceBinding::FragmentStage,
457 shaderPipeline->ssaoTexture(), sampler);
459 if (ssaoTextureArrayBinding >= 0) {
460 samplerBindingsSpecified.setBit(ssaoTextureArrayBinding);
461 bindings.addTexture(ssaoTextureArrayBinding,
462 QRhiShaderResourceBinding::FragmentStage,
463 shaderPipeline->ssaoTexture(), sampler);
468 if (shaderPipeline->lightmapTexture()) {
469 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
471 samplerBindingsSpecified.setBit(binding);
472 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
473 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
474 bindings.addTexture(binding,
475 QRhiShaderResourceBinding::FragmentStage,
476 shaderPipeline->lightmapTexture(), sampler);
480 if (shaderPipeline->MotionVectorTexture()) {
481 int binding = shaderPipeline->bindingForTexture(
"qt_motionVectorTexture",
int(QSSGRhiSamplerBindingHints::MotionVectorTexture));
483 samplerBindingsSpecified.setBit(binding);
484 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
485 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
486 bindings.addTexture(binding,
487 QRhiShaderResourceBinding::FragmentStage,
488 shaderPipeline->MotionVectorTexture(), sampler);
494 auto shadowMapAtlas = shaderPipeline->shadowMapAtlasTexture();
495 if (shadowMapAtlas) {
496 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture");
498 samplerBindingsSpecified.setBit(binding);
499 QRhiTexture *texture = shadowMapAtlas;
500 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
501 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
502 Q_ASSERT(texture && sampler);
503 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
508 if (
auto shadowMapBlueNoise = shaderPipeline->shadowMapBlueNoiseTexture()) {
509 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_blue_noise_texture");
511 samplerBindingsSpecified.setBit(binding);
512 QRhiTexture *texture = shadowMapBlueNoise;
513 QRhiSampler *sampler = rhiCtx->sampler(
514 { QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
515 Q_ASSERT(texture && sampler);
516 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
520 QSSGRenderableImage *renderableImage = renderable.firstImage;
521 while (renderableImage) {
522 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
523 const int samplerHint =
int(renderableImage->m_mapType);
524 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
525 if (samplerBinding >= 0) {
526 QRhiTexture *texture = renderableImage->m_texture.m_texture;
527 if (samplerBinding >= 0 && texture) {
528 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
529 QSSGRhiSamplerDescription samplerDesc = {
530 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
531 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
532 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
533 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
534 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
535 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
537 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
538 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
539 samplerBindingsSpecified.setBit(samplerBinding);
540 bindings.addTexture(samplerBinding,
541 CUSTOM_MATERIAL_VISIBILITY_ALL,
545 renderableImage = renderableImage->m_nextImage;
548 if (maxSamplerBinding >= 0) {
550 int customTexCount = shaderPipeline->extraTextureCount();
551 for (
int i = 0; i < customTexCount; ++i) {
552 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
553 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
554 if (samplerBinding >= 0) {
555 samplerBindingsSpecified.setBit(samplerBinding);
556 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
557 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
558 bindings.addTexture(samplerBinding,
559 CUSTOM_MATERIAL_VISIBILITY_ALL,
566 QRhiSampler *dummySampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
567 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
569 for (
const QShaderDescription::InOutVariable &var : samplerVars) {
570 if (!samplerBindingsSpecified.testBit(var.binding)) {
571 QRhiTexture *t =
nullptr;
572 if (var.type == QShaderDescription::SamplerCube)
573 t = dummyCubeTexture;
574 else if (var.type == QShaderDescription::Sampler3D)
578 bindings.addTexture(var.binding, CUSTOM_MATERIAL_VISIBILITY_ALL, t, dummySampler);
583 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
585 if (oit && layerData.layer.oitMethod == QSSGRenderLayer::OITMethod::LinkedList)
586 RenderHelpers::addAccumulatorImageBindings(shaderPipeline.get(), bindings);
589 QRhiShaderResourceBindings *&srb = dcd.srb;
590 bool srbChanged =
false;
591 if (!srb || bindings != dcd.bindings) {
592 srb = rhiCtxD->srb(bindings);
593 rhiCtxD->releaseCachedSrb(dcd.bindings);
594 dcd.bindings = bindings;
598 if (cubeFace == QSSGRenderTextureCubeFaceNone)
599 renderable.rhiRenderData.mainPass.srb = srb;
601 renderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
603 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
606 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
607 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
610 if (cubeFace == QSSGRenderTextureCubeFaceNone)
611 renderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
613 renderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
615 if (cubeFace == QSSGRenderTextureCubeFaceNone) {
616 renderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
617 renderPassDescriptor,
619 dcd.pipeline = renderable.rhiRenderData.mainPass.pipeline;
621 renderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
622 renderPassDescriptor,
624 dcd.pipeline = renderable.rhiRenderData.reflectionPass.pipeline;
627 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
628 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;