180void QSSGCustomMaterialSystem::rhiPrepareRenderable(QSSGRhiGraphicsPipelineState *ps,
182 QSSGSubsetRenderable &renderable,
183 const QSSGShaderFeatures &featureSet,
184 const QSSGRenderCustomMaterial &material,
185 const QSSGLayerRenderData &layerData,
186 QRhiRenderPassDescriptor *renderPassDescriptor,
189 QSSGRenderCamera *alteredCamera,
190 QSSGRenderTextureCubeFace cubeFace,
191 QMatrix4x4 *alteredModelViewProjection,
192 QSSGReflectionMapEntry *entry,
195 QSSGRhiContext *rhiCtx = context->rhiContext().get();
197 QRhiGraphicsPipeline::TargetBlend blend;
198 if (material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Blending)) {
200 blend.srcColor = material.m_srcBlend;
201 blend.srcAlpha = material.m_srcAlphaBlend;
202 blend.dstColor = material.m_dstBlend;
203 blend.dstAlpha = material.m_dstAlphaBlend;
206 const QSSGCullFaceMode cullMode = material.m_cullMode;
208 const auto &defaultMaterialShaderKeyProperties = layerData.getDefaultMaterialPropertyTable();
210 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(renderable.shaderDescription);
212 const auto &shaderPipeline = shadersForCustomMaterial(ps, material, renderable, defaultMaterialShaderKeyProperties, featureSet);
214 if (shaderPipeline) {
215 QSSGRhiShaderResourceBindingList bindings;
216 const auto &modelNode = renderable.modelContext.model;
222 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
223 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * (cubeFaceIdx + (quintptr(renderable.subset.offset) << 3));
225 const auto entryPartA =
reinterpret_cast<quintptr>(&material);
226 const auto entryPartB =
reinterpret_cast<quintptr>(entry);
227 const void *entryKey =
reinterpret_cast<
const void *>(entryPartA ^ entryPartB);
229 QSSGRhiDrawCallData &dcd = QSSGRhiContextPrivate::get(rhiCtx)->drawCallData({ passKey, &modelNode, entryKey, entryIdx });
231 shaderPipeline->ensureCombinedUniformBuffer(&dcd.ubuf);
232 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
233 if (!alteredCamera) {
234 updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, layerData, ubufData, ps, material, renderable, layerData.renderedCameras,
nullptr,
nullptr);
236 QSSGRenderCameraList cameras({ alteredCamera });
237 updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, layerData, ubufData, ps, material, renderable, cameras,
nullptr, alteredModelViewProjection);
240 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &renderable.modelContext.model, renderable.subset.offset);
241 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
244 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &renderable.modelContext.model);
245 bool instancing =
false;
246 if (!alteredCamera) {
247 const QSSGRenderCameraDataList &cameraDatas(*layerData.renderedCameraData);
248 instancing = QSSGLayerRenderData::prepareInstancing(rhiCtx, &renderable, cameraDatas[0].direction, cameraDatas[0].position, renderable.instancingLodMin, renderable.instancingLodMax);
250 const auto &altCamTransform = layerData.getGlobalTransform(*alteredCamera);
251 instancing = QSSGLayerRenderData::prepareInstancing(rhiCtx, &renderable, QSSGRenderNode::getScalingCorrectDirection(altCamTransform), QSSGRenderNode::getGlobalPos(altCamTransform), renderable.instancingLodMin, renderable.instancingLodMax);
254 ps->samples = samples;
255 ps->viewCount = viewCount;
257 ps->cullMode = QSSGRhiHelpers::toCullMode(cullMode);
260 ps->targetBlend[0] = blend;
262 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps);
264 ia = renderable.subset.rhi.ia;
267 int instanceBufferBinding = 0;
270 const quint32 stride = renderable.modelContext.model.instanceTable->stride();
271 QVarLengthArray<QRhiVertexInputBinding, 8> bindings;
272 std::copy(ia.inputLayout.cbeginBindings(),
273 ia.inputLayout.cendBindings(),
274 std::back_inserter(bindings));
275 bindings.append({ stride, QRhiVertexInputBinding::PerInstance });
276 instanceBufferBinding = bindings.size() - 1;
277 ia.inputLayout.setBindings(bindings.cbegin(), bindings.cend());
280 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
282 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
283 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
284 QRhiTexture *dummyTexture3D = rhiCtx->dummyTexture(QRhiTexture::ThreeDimensional, resourceUpdates);
285 QRhiTexture *dummyCubeTexture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
286 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
288 bindings.addUniformBuffer(0, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline->ub0Size());
289 bindings.addUniformBuffer(1, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, shaderPipeline->ub0LightDataOffset(),
sizeof(QSSGShaderLightsUniformData));
290 bindings.addUniformBuffer(2, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, shaderPipeline->ub0DirectionalLightDataOffset(),
sizeof(QSSGShaderDirectionalLightsUniformData));
292 QVector<QShaderDescription::InOutVariable> samplerVars =
293 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
294 for (
const QShaderDescription::InOutVariable &var : shaderPipeline->vertexStage()->shader().description().combinedImageSamplers()) {
295 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
296 [&var](
const QShaderDescription::InOutVariable &v) {
return var.binding == v.binding; });
297 if (it == samplerVars.cend())
298 samplerVars.append(var);
301 int maxSamplerBinding = -1;
302 for (
const QShaderDescription::InOutVariable &var : samplerVars)
303 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
312 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
315 samplerBindingsSpecified.setBit(shaderPipeline->bindingForTexture(
"qt_particleTexture"));
318 if (QRhiTexture *boneTexture = layerData.getBonemapTexture(renderable.modelContext)) {
319 int binding = shaderPipeline->bindingForTexture(
"qt_boneTexture");
321 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
322 QRhiSampler::Nearest,
324 QRhiSampler::ClampToEdge,
325 QRhiSampler::ClampToEdge,
328 bindings.addTexture(binding,
329 QRhiShaderResourceBinding::VertexStage,
332 samplerBindingsSpecified.setBit(binding);
337 auto *targetsTexture = renderable.subset.rhi.targetsTexture;
338 if (targetsTexture) {
339 int binding = shaderPipeline->bindingForTexture(
"qt_morphTargetTexture");
341 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
342 QRhiSampler::Nearest,
344 QRhiSampler::ClampToEdge,
345 QRhiSampler::ClampToEdge,
346 QRhiSampler::ClampToEdge
348 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, renderable.subset.rhi.targetsTexture, targetsSampler);
349 samplerBindingsSpecified.setBit(binding);
356 if (featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe)) {
357 int reflectionSampler = shaderPipeline->bindingForTexture(
"qt_reflectionMap");
358 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
359 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
360 QRhiTexture* reflectionTexture = layerData.getReflectionMapManager()->reflectionMapEntry(renderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
361 if (reflectionSampler >= 0 && reflectionTexture) {
362 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
363 samplerBindingsSpecified.setBit(reflectionSampler);
365 }
else if (shaderPipeline->lightProbeTexture()) {
366 int binding = shaderPipeline->bindingForTexture(
"qt_lightProbe",
int(QSSGRhiSamplerBindingHints::LightProbe));
368 samplerBindingsSpecified.setBit(binding);
369 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
370 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::Linear,
371 QSSGRhiHelpers::toRhi(tiling.first), QSSGRhiHelpers::toRhi(tiling.second), QRhiSampler::Repeat });
372 bindings.addTexture(binding,
373 QRhiShaderResourceBinding::FragmentStage,
374 shaderPipeline->lightProbeTexture(), sampler);
378 if (shaderPipeline->screenTexture()) {
379 const int screenTextureBinding = shaderPipeline->bindingForTexture(
"qt_screenTexture",
int(QSSGRhiSamplerBindingHints::ScreenTexture));
380 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_screenTextureArray",
int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
381 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
386 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
387 ? QRhiSampler::Linear : QRhiSampler::None;
388 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, mipFilter,
389 QRhiSampler::Repeat, QRhiSampler::Repeat, QRhiSampler::Repeat });
390 if (screenTextureBinding >= 0) {
391 samplerBindingsSpecified.setBit(screenTextureBinding);
392 bindings.addTexture(screenTextureBinding,
393 QRhiShaderResourceBinding::FragmentStage,
394 shaderPipeline->screenTexture(), sampler);
396 if (screenTextureArrayBinding >= 0) {
397 samplerBindingsSpecified.setBit(screenTextureArrayBinding);
398 bindings.addTexture(screenTextureArrayBinding,
399 QRhiShaderResourceBinding::FragmentStage,
400 shaderPipeline->screenTexture(), sampler);
405 if (shaderPipeline->depthTexture()) {
406 const int depthTextureBinding = shaderPipeline->bindingForTexture(
"qt_depthTexture",
int(QSSGRhiSamplerBindingHints::DepthTexture));
407 const int depthTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_depthTextureArray",
int(QSSGRhiSamplerBindingHints::DepthTextureArray));
408 if (depthTextureBinding >= 0 || depthTextureArrayBinding >= 0) {
410 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
411 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
412 if (depthTextureBinding >= 0) {
413 samplerBindingsSpecified.setBit(depthTextureBinding);
414 bindings.addTexture(depthTextureBinding,
415 CUSTOM_MATERIAL_VISIBILITY_ALL,
416 shaderPipeline->depthTexture(), sampler);
418 if (depthTextureArrayBinding >= 0) {
419 samplerBindingsSpecified.setBit(depthTextureArrayBinding);
420 bindings.addTexture(depthTextureArrayBinding,
421 CUSTOM_MATERIAL_VISIBILITY_ALL,
422 shaderPipeline->depthTexture(), sampler);
427 if (shaderPipeline->normalTexture()) {
428 const int normalTextureBinding = shaderPipeline->bindingForTexture(
"qt_normalTexture",
int(QSSGRhiSamplerBindingHints::NormalTexture));
429 if (normalTextureBinding >= 0) {
431 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
432 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
433 samplerBindingsSpecified.setBit(normalTextureBinding);
434 bindings.addTexture(normalTextureBinding, CUSTOM_MATERIAL_VISIBILITY_ALL, shaderPipeline->normalTexture(), sampler);
438 if (shaderPipeline->ssaoTexture()) {
439 const int ssaoTextureBinding = shaderPipeline->bindingForTexture(
"qt_aoTexture",
int(QSSGRhiSamplerBindingHints::AoTexture));
440 const int ssaoTextureArrayBinding = shaderPipeline->bindingForTexture(
"qt_aoTextureArray",
int(QSSGRhiSamplerBindingHints::AoTextureArray));
441 if (ssaoTextureBinding >= 0 || ssaoTextureArrayBinding >= 0) {
443 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
444 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
445 if (ssaoTextureBinding >= 0) {
446 samplerBindingsSpecified.setBit(ssaoTextureBinding);
447 bindings.addTexture(ssaoTextureBinding,
448 QRhiShaderResourceBinding::FragmentStage,
449 shaderPipeline->ssaoTexture(), sampler);
451 if (ssaoTextureArrayBinding >= 0) {
452 samplerBindingsSpecified.setBit(ssaoTextureArrayBinding);
453 bindings.addTexture(ssaoTextureArrayBinding,
454 QRhiShaderResourceBinding::FragmentStage,
455 shaderPipeline->ssaoTexture(), sampler);
460 if (shaderPipeline->lightmapTexture()) {
461 int binding = shaderPipeline->bindingForTexture(
"qt_lightmap",
int(QSSGRhiSamplerBindingHints::LightmapTexture));
463 samplerBindingsSpecified.setBit(binding);
464 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
465 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
466 bindings.addTexture(binding,
467 QRhiShaderResourceBinding::FragmentStage,
468 shaderPipeline->lightmapTexture(), sampler);
473 auto shadowMapAtlas = shaderPipeline->shadowMapAtlasTexture();
474 if (shadowMapAtlas) {
475 int binding = shaderPipeline->bindingForTexture(
"qt_shadowmap_texture");
477 samplerBindingsSpecified.setBit(binding);
478 QRhiTexture *texture = shadowMapAtlas;
479 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
480 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
481 Q_ASSERT(texture && sampler);
482 bindings.addTexture(binding, QRhiShaderResourceBinding::FragmentStage, texture, sampler);
486 QSSGRenderableImage *renderableImage = renderable.firstImage;
487 while (renderableImage) {
488 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
489 const int samplerHint =
int(renderableImage->m_mapType);
490 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
491 if (samplerBinding >= 0) {
492 QRhiTexture *texture = renderableImage->m_texture.m_texture;
493 if (samplerBinding >= 0 && texture) {
494 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
495 QSSGRhiSamplerDescription samplerDesc = {
496 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
497 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
498 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
499 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
500 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
501 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
503 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
504 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
505 samplerBindingsSpecified.setBit(samplerBinding);
506 bindings.addTexture(samplerBinding,
507 CUSTOM_MATERIAL_VISIBILITY_ALL,
511 renderableImage = renderableImage->m_nextImage;
514 if (maxSamplerBinding >= 0) {
516 int customTexCount = shaderPipeline->extraTextureCount();
517 for (
int i = 0; i < customTexCount; ++i) {
518 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
519 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
520 if (samplerBinding >= 0) {
521 samplerBindingsSpecified.setBit(samplerBinding);
522 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
523 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
524 bindings.addTexture(samplerBinding,
525 CUSTOM_MATERIAL_VISIBILITY_ALL,
532 QRhiSampler *dummySampler = rhiCtx->sampler({ QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
533 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
535 for (
const QShaderDescription::InOutVariable &var : samplerVars) {
536 if (!samplerBindingsSpecified.testBit(var.binding)) {
537 QRhiTexture *t =
nullptr;
538 if (var.type == QShaderDescription::SamplerCube)
539 t = dummyCubeTexture;
540 else if (var.type == QShaderDescription::Sampler3D)
544 bindings.addTexture(var.binding, CUSTOM_MATERIAL_VISIBILITY_ALL, t, dummySampler);
549 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
552 QRhiShaderResourceBindings *&srb = dcd.srb;
553 bool srbChanged =
false;
554 if (!srb || bindings != dcd.bindings) {
555 srb = rhiCtxD->srb(bindings);
556 rhiCtxD->releaseCachedSrb(dcd.bindings);
557 dcd.bindings = bindings;
561 if (cubeFace == QSSGRenderTextureCubeFaceNone)
562 renderable.rhiRenderData.mainPass.srb = srb;
564 renderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
566 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
569 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
570 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
573 if (cubeFace == QSSGRenderTextureCubeFaceNone)
574 renderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
576 renderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
578 if (cubeFace == QSSGRenderTextureCubeFaceNone) {
579 renderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
580 renderPassDescriptor,
582 dcd.pipeline = renderable.rhiRenderData.mainPass.pipeline;
584 renderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
585 renderPassDescriptor,
587 dcd.pipeline = renderable.rhiRenderData.reflectionPass.pipeline;
590 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
591 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;