181void QSSGCustomMaterialSystem::rhiPrepareRenderable(QSSGRhiGraphicsPipelineState *ps,
183 QSSGSubsetRenderable &renderable,
184 const QSSGShaderFeatures &featureSet,
185 const QSSGRenderCustomMaterial &material,
186 const QSSGLayerRenderData &layerData,
187 QRhiRenderPassDescriptor *renderPassDescriptor,
190 QSSGRenderCamera *alteredCamera,
191 QSSGRenderTextureCubeFace cubeFace,
192 QMatrix4x4 *alteredModelViewProjection,
193 QSSGReflectionMapEntry *entry,
196 QSSGRhiContext *rhiCtx = context->rhiContext().get();
198 QRhiGraphicsPipeline::TargetBlend blend;
199 if (material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Blending)) {
201 blend.srcColor = material.m_srcBlend;
202 blend.srcAlpha = material.m_srcAlphaBlend;
203 blend.dstColor = material.m_dstBlend;
204 blend.dstAlpha = material.m_dstAlphaBlend;
207 const QSSGCullFaceMode cullMode = material.m_cullMode;
209 const auto &defaultMaterialShaderKeyProperties = layerData.getDefaultMaterialPropertyTable();
211 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(renderable.shaderDescription);
213 const auto &shaderPipeline = shadersForCustomMaterial(ps, material, renderable, defaultMaterialShaderKeyProperties, featureSet);
215 if (shaderPipeline) {
216 QSSGRhiShaderResourceBindingList bindings;
217 const auto &modelNode = renderable.modelContext.model;
223 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
224 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * (cubeFaceIdx + (quintptr(renderable.subset.offset) << 3));
226 const auto entryPartA =
reinterpret_cast<quintptr>(&material);
227 const auto entryPartB =
reinterpret_cast<quintptr>(entry);
228 const void *entryKey =
reinterpret_cast<
const void *>(entryPartA ^ entryPartB);
230 QSSGRhiDrawCallData &dcd = QSSGRhiContextPrivate::get(rhiCtx)->drawCallData({ passKey, &modelNode, entryKey, entryIdx });
232 shaderPipeline->ensureCombinedUniformBuffer(&dcd.ubuf);
233 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
234 if (!alteredCamera) {
235 updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, layerData, ubufData, ps, material, renderable, layerData.renderedCameras,
nullptr,
nullptr);
237 QSSGRenderCameraList cameras({ alteredCamera });
238 updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, layerData, ubufData, ps, material, renderable, cameras,
nullptr, alteredModelViewProjection);
241 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &renderable.modelContext.model, renderable.subset.offset);
242 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
245 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &renderable.modelContext.model);
246 bool instancing =
false;
247 if (!alteredCamera) {
248 const QSSGRenderCameraDataList &cameraDatas(*layerData.renderedCameraData);
249 instancing = QSSGLayerRenderData::prepareInstancing(rhiCtx, &renderable, cameraDatas[0].direction, cameraDatas[0].position, renderable.instancingLodMin, renderable.instancingLodMax);
251 const auto &altCamTransform = layerData.getGlobalTransform(*alteredCamera);
252 instancing = QSSGLayerRenderData::prepareInstancing(rhiCtx, &renderable, QSSGRenderNode::getScalingCorrectDirection(altCamTransform), QSSGRenderNode::getGlobalPos(altCamTransform), renderable.instancingLodMin, renderable.instancingLodMax);
255 ps->samples = samples;
256 ps->viewCount = viewCount;
258 ps->cullMode = QSSGRhiHelpers::toCullMode(cullMode);
261 ps->targetBlend[0] = blend;
263 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
265 ia = renderable.subset.rhi.ia;
268 int instanceBufferBinding = 0;
271 const quint32 stride = renderable.modelContext.model.instanceTable->stride();
272 QVarLengthArray<QRhiVertexInputBinding, 8> bindings;
273 std::copy(ia.inputLayout.cbeginBindings(),
274 ia.inputLayout.cendBindings(),
275 std::back_inserter(bindings));
276 bindings.append({ stride, QRhiVertexInputBinding::PerInstance });
277 instanceBufferBinding = bindings.size() - 1;
278 ia.inputLayout.setBindings(bindings.cbegin(), bindings.cend());
281 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
283 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
284 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
285 QRhiTexture *dummyTexture3D = rhiCtx->dummyTexture(QRhiTexture::ThreeDimensional, resourceUpdates);
286 QRhiTexture *dummyCubeTexture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
287 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
289 bindings.addUniformBuffer(0, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline->ub0Size());
290 bindings.addUniformBuffer(1, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, shaderPipeline->ub0LightDataOffset(),
sizeof(QSSGShaderLightsUniformData));
291 bindings.addUniformBuffer(2, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, shaderPipeline->ub0DirectionalLightDataOffset(),
sizeof(QSSGShaderDirectionalLightsUniformData));
293 QVector<QShaderDescription::InOutVariable> samplerVars =
294 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
295 for (
const QShaderDescription::InOutVariable &var : shaderPipeline->vertexStage()->shader().description().combinedImageSamplers()) {
296 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
297 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
298 if (it == samplerVars.cend())
299 samplerVars.append(var);
302 int maxSamplerBinding = -1;
303 for (
const QShaderDescription::InOutVariable &var : samplerVars)
304 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
313 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
316 samplerBindingsSpecified.setBit(shaderPipeline->bindingForTexture(
"qt_particleTexture"));
319 if (QRhiTexture *boneTexture = layerData.getBonemapTexture(renderable.modelContext)) {
320 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
322 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
323 QRhiSampler::Nearest,
325 QRhiSampler::ClampToEdge,
326 QRhiSampler::ClampToEdge,
329 bindings.addTexture(binding,
330 QRhiShaderResourceBinding::VertexStage,
333 samplerBindingsSpecified.setBit(binding);
338 auto *targetsTexture = renderable.subset.rhi.targetsTexture;
339 if (targetsTexture) {
340 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
342 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
343 QRhiSampler::Nearest,
345 QRhiSampler::ClampToEdge,
346 QRhiSampler::ClampToEdge,
347 QRhiSampler::ClampToEdge
349 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, renderable.subset.rhi.targetsTexture, targetsSampler);
350 samplerBindingsSpecified.setBit(binding);
357 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
358 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
359 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
360 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
361 QRhiTexture* reflectionTexture = layerData.getReflectionMapManager()->reflectionMapEntry(renderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
362 if (reflectionSampler >= 0 && reflectionTexture) {
363 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
364 samplerBindingsSpecified.setBit(reflectionSampler);
366 }
else if (shaderPipeline->lightProbeTexture()) {
367 int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
369 samplerBindingsSpecified.setBit(binding);
370 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
371 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
372 QSSGRhiHelpers::toRhi(tiling.first), QSSGRhiHelpers::toRhi(tiling.second), QRhiSampler::Repeat });
373 bindings.addTexture(binding,
374 QRhiShaderResourceBinding::FragmentStage,
375 shaderPipeline->lightProbeTexture(), sampler);
379 if (shaderPipeline->screenTexture()) {
380 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
381 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
382 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
387 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
388 ? QRhiSampler::Linear : QRhiSampler::None;
389 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
390 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
391 if (screenTextureBinding >= 0) {
392 samplerBindingsSpecified.setBit(screenTextureBinding);
393 bindings.addTexture(screenTextureBinding,
394 QRhiShaderResourceBinding::FragmentStage,
395 shaderPipeline->screenTexture(), sampler);
397 if (screenTextureArrayBinding >= 0) {
398 samplerBindingsSpecified.setBit(screenTextureArrayBinding);
399 bindings.addTexture(screenTextureArrayBinding,
400 QRhiShaderResourceBinding::FragmentStage,
401 shaderPipeline->screenTexture(), sampler);
406 if (shaderPipeline->depthTexture()) {
407 const int depthTextureBinding = shaderPipeline->bindingForTexture(
"qt_depthTexture",
int(QSSGRhiSamplerBindingHints::DepthTexture));
408 const int depthTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_depthTextureArray",
int(QSSGRhiSamplerBindingHints::DepthTextureArray));
409 if (depthTextureBinding >= 0 || depthTextureArrayBinding >= 0) {
411 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
412 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
413 if (depthTextureBinding >= 0) {
414 samplerBindingsSpecified.setBit(depthTextureBinding);
415 bindings.addTexture(depthTextureBinding,
416 CUSTOM_MATERIAL_VISIBILITY_ALL,
417 shaderPipeline->depthTexture(), sampler);
419 if (depthTextureArrayBinding >= 0) {
420 samplerBindingsSpecified.setBit(depthTextureArrayBinding);
421 bindings.addTexture(depthTextureArrayBinding,
422 CUSTOM_MATERIAL_VISIBILITY_ALL,
423 shaderPipeline->depthTexture(), sampler);
428 if (shaderPipeline->normalTexture()) {
429 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
430 if (normalTextureBinding >= 0) {
432 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
433 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
434 samplerBindingsSpecified.setBit(normalTextureBinding);
435 bindings.addTexture(normalTextureBinding, CUSTOM_MATERIAL_VISIBILITY_ALL, shaderPipeline->normalTexture(), sampler);
439 if (shaderPipeline->ssaoTexture()) {
440 const int ssaoTextureBinding = shaderPipeline->bindingForTexture(
"qt_aoTexture",
int(QSSGRhiSamplerBindingHints::AoTexture));
441 const int ssaoTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_aoTextureArray",
int(QSSGRhiSamplerBindingHints::AoTextureArray));
442 if (ssaoTextureBinding >= 0 || ssaoTextureArrayBinding >= 0) {
444 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
445 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
446 if (ssaoTextureBinding >= 0) {
447 samplerBindingsSpecified.setBit(ssaoTextureBinding);
448 bindings.addTexture(ssaoTextureBinding,
449 QRhiShaderResourceBinding::FragmentStage,
450 shaderPipeline->ssaoTexture(), sampler);
452 if (ssaoTextureArrayBinding >= 0) {
453 samplerBindingsSpecified.setBit(ssaoTextureArrayBinding);
454 bindings.addTexture(ssaoTextureArrayBinding,
455 QRhiShaderResourceBinding::FragmentStage,
456 shaderPipeline->ssaoTexture(), sampler);
461 if (shaderPipeline->lightmapTexture()) {
462 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
464 samplerBindingsSpecified.setBit(binding);
465 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
466 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
467 bindings.addTexture(binding,
468 QRhiShaderResourceBinding::FragmentStage,
469 shaderPipeline->lightmapTexture(), sampler);
474 auto shadowMapAtlas = shaderPipeline->shadowMapAtlasTexture();
475 if (shadowMapAtlas) {
476 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture");
478 samplerBindingsSpecified.setBit(binding);
479 QRhiTexture *texture = shadowMapAtlas;
480 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
481 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
482 Q_ASSERT(texture && sampler);
483 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
487 QSSGRenderableImage *renderableImage = renderable.firstImage;
488 while (renderableImage) {
489 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
490 const int samplerHint =
int(renderableImage->m_mapType);
491 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
492 if (samplerBinding >= 0) {
493 QRhiTexture *texture = renderableImage->m_texture.m_texture;
494 if (samplerBinding >= 0 && texture) {
495 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
496 QSSGRhiSamplerDescription samplerDesc = {
497 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
498 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
499 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
500 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
501 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
502 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
504 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
505 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
506 samplerBindingsSpecified.setBit(samplerBinding);
507 bindings.addTexture(samplerBinding,
508 CUSTOM_MATERIAL_VISIBILITY_ALL,
512 renderableImage = renderableImage->m_nextImage;
515 if (maxSamplerBinding >= 0) {
517 int customTexCount = shaderPipeline->extraTextureCount();
518 for (
int i = 0; i < customTexCount; ++i) {
519 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
520 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
521 if (samplerBinding >= 0) {
522 samplerBindingsSpecified.setBit(samplerBinding);
523 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
524 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
525 bindings.addTexture(samplerBinding,
526 CUSTOM_MATERIAL_VISIBILITY_ALL,
533 QRhiSampler *dummySampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
534 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
536 for (
const QShaderDescription::InOutVariable &var : samplerVars) {
537 if (!samplerBindingsSpecified.testBit(var.binding)) {
538 QRhiTexture *t =
nullptr;
539 if (var.type == QShaderDescription::SamplerCube)
540 t = dummyCubeTexture;
541 else if (var.type == QShaderDescription::Sampler3D)
545 bindings.addTexture(var.binding, CUSTOM_MATERIAL_VISIBILITY_ALL, t, dummySampler);
550 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
553 QRhiShaderResourceBindings *&srb = dcd.srb;
554 bool srbChanged =
false;
555 if (!srb || bindings != dcd.bindings) {
556 srb = rhiCtxD->srb(bindings);
557 rhiCtxD->releaseCachedSrb(dcd.bindings);
558 dcd.bindings = bindings;
562 if (cubeFace == QSSGRenderTextureCubeFaceNone)
563 renderable.rhiRenderData.mainPass.srb = srb;
565 renderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
567 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
570 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
571 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
574 if (cubeFace == QSSGRenderTextureCubeFaceNone)
575 renderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
577 renderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
579 if (cubeFace == QSSGRenderTextureCubeFaceNone) {
580 renderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
581 renderPassDescriptor,
583 dcd.pipeline = renderable.rhiRenderData.mainPass.pipeline;
585 renderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
586 renderPassDescriptor,
588 dcd.pipeline = renderable.rhiRenderData.reflectionPass.pipeline;
591 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
592 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;