• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "render_node_default_material_render_slot.h"
17 
18 #include <algorithm>
19 
20 #include <3d/render/default_material_constants.h>
21 #include <3d/render/intf_render_data_store_default_camera.h>
22 #include <3d/render/intf_render_data_store_default_light.h>
23 #include <3d/render/intf_render_data_store_default_material.h>
24 #include <3d/render/intf_render_data_store_default_scene.h>
25 #include <base/math/matrix_util.h>
26 #include <base/math/vector.h>
27 #include <core/log.h>
28 #include <core/namespace.h>
29 #include <render/datastore/intf_render_data_store.h>
30 #include <render/datastore/intf_render_data_store_manager.h>
31 #include <render/datastore/intf_render_data_store_pod.h>
32 #include <render/datastore/render_data_store_render_pods.h>
33 #include <render/device/intf_gpu_resource_manager.h>
34 #include <render/device/intf_shader_manager.h>
35 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
36 #include <render/nodecontext/intf_node_context_pso_manager.h>
37 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
38 #include <render/nodecontext/intf_render_command_list.h>
39 #include <render/nodecontext/intf_render_node_context_manager.h>
40 #include <render/nodecontext/intf_render_node_parser_util.h>
41 #include <render/nodecontext/intf_render_node_util.h>
42 #include <render/resource_handle.h>
43 
44 #include "render/default_constants.h"
45 #include "render/render_node_scene_util.h"
46 
47 #if (CORE3D_DEV_ENABLED == 1)
48 #include "render/datastore/render_data_store_default_material.h"
49 #endif
50 
51 namespace {
52 #include <3d/shaders/common/3d_dm_structures_common.h>
53 #include <render/shaders/common/render_post_process_structs_common.h>
54 } // namespace
55 
56 CORE3D_BEGIN_NAMESPACE()
57 using namespace BASE_NS;
58 using namespace RENDER_NS;
59 
60 namespace {
61 constexpr string_view POST_PROCESS_DATA_STORE_TYPE_NAME { "RenderDataStorePod" };
62 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
63 constexpr DynamicStateEnum DYNAMIC_STATES_FSR[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR,
64     CORE_DYNAMIC_STATE_ENUM_FRAGMENT_SHADING_RATE };
65 
66 constexpr uint32_t UBO_BIND_OFFSET_ALIGNMENT { PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE };
67 
68 static constexpr uint64_t LIGHTING_FLAGS_SHIFT { 32ULL };
69 static constexpr uint64_t LIGHTING_FLAGS_MASK { 0xF00000000ULL };
70 static constexpr uint64_t POST_PROCESS_FLAGS_SHIFT { 36ULL };
71 static constexpr uint64_t POST_PROCESS_FLAGS_MASK { 0xF000000000ULL };
72 static constexpr uint64_t CAMERA_FLAGS_SHIFT { 40ULL };
73 static constexpr uint64_t CAMERA_FLAGS_MASK { 0xF0000000000ULL };
74 static constexpr uint64_t RENDER_HASH_FLAGS_MASK { 0xFFFFffffULL };
75 static constexpr uint64_t PRIMITIVE_TOPOLOGY_SHIFT { 44ULL };
76 // CORE_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10
77 // CORE_PRIMITIVE_TOPOLOGY_MAX_ENUM is ignored in hashing
78 static constexpr uint64_t PRIMITIVE_TOPOLOGY_MASK { 0xF00000000000ULL };
79 
80 // our light weight straight to screen post processes are only interested in these
81 static constexpr uint32_t POST_PROCESS_IMPORTANT_FLAGS_MASK { 0xffu };
82 
83 static constexpr uint32_t FIXED_CUSTOM_SET3 { 3u };
84 static constexpr uint32_t CUSTOM_SET_DESCRIPTOR_SET_COUNT { 4u };
85 
GetMultiViewCameraIndices(const IRenderDataStoreDefaultCamera & rds,const RenderCamera & cam,vector<uint32_t> & mvIndices)86 inline void GetMultiViewCameraIndices(
87     const IRenderDataStoreDefaultCamera& rds, const RenderCamera& cam, vector<uint32_t>& mvIndices)
88 {
89     CORE_STATIC_ASSERT(RenderSceneDataConstants::MAX_MULTI_VIEW_LAYER_CAMERA_COUNT == 7U);
90     const uint32_t inputCount =
91         Math::min(cam.multiViewCameraCount, RenderSceneDataConstants::MAX_MULTI_VIEW_LAYER_CAMERA_COUNT);
92     mvIndices.clear();
93     mvIndices.reserve(inputCount);
94     for (uint32_t idx = 0U; idx < inputCount; ++idx) {
95         const uint64_t id = cam.multiViewCameraIds[idx];
96         if (id != RenderSceneDataConstants::INVALID_ID) {
97             mvIndices.push_back(Math::min(rds.GetCameraIndex(id), CORE_DEFAULT_MATERIAL_MAX_CAMERA_COUNT - 1U));
98         }
99     }
100 }
101 
HashShaderDataAndSubmesh(const uint64_t shaderDataHash,const uint32_t renderHash,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags & cameraShaderFlags,const PostProcessConfiguration::PostProcessEnableFlags postProcessFlags,const GraphicsState::InputAssembly & ia)102 inline uint64_t HashShaderDataAndSubmesh(const uint64_t shaderDataHash, const uint32_t renderHash,
103     const IRenderDataStoreDefaultLight::LightingFlags lightingFlags, const RenderCamera::ShaderFlags& cameraShaderFlags,
104     const PostProcessConfiguration::PostProcessEnableFlags postProcessFlags, const GraphicsState::InputAssembly& ia)
105 {
106     const uint32_t ppEnabled = (postProcessFlags > 0);
107     const uint64_t iaHash = uint32_t(ia.enablePrimitiveRestart) | (ia.primitiveTopology << 1U);
108     uint64_t hash = ((uint64_t)renderHash & RENDER_HASH_FLAGS_MASK) |
109                     (((uint64_t)lightingFlags << LIGHTING_FLAGS_SHIFT) & LIGHTING_FLAGS_MASK) |
110                     (((uint64_t)ppEnabled << POST_PROCESS_FLAGS_SHIFT) & POST_PROCESS_FLAGS_MASK) |
111                     (((uint64_t)cameraShaderFlags << CAMERA_FLAGS_SHIFT) & CAMERA_FLAGS_MASK) |
112                     (((uint64_t)iaHash << PRIMITIVE_TOPOLOGY_SHIFT) & PRIMITIVE_TOPOLOGY_MASK);
113     HashCombine(hash, shaderDataHash);
114     return hash;
115 }
116 
IsInverseWinding(const RenderSubmeshFlags submeshFlags,const RenderSceneFlags sceneRenderingFlags,const RenderCamera::Flags cameraRenderingFlags)117 inline bool IsInverseWinding(const RenderSubmeshFlags submeshFlags, const RenderSceneFlags sceneRenderingFlags,
118     const RenderCamera::Flags cameraRenderingFlags)
119 {
120     const bool flipWinding = (sceneRenderingFlags & RENDER_SCENE_FLIP_WINDING_BIT) |
121                              (cameraRenderingFlags & RenderCamera::CAMERA_FLAG_INVERSE_WINDING_BIT);
122     const bool isNegative = flipWinding
123                                 ? !((submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_INVERSE_WINDING_BIT) > 0)
124                                 : ((submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_INVERSE_WINDING_BIT) > 0);
125     return isNegative;
126 }
127 
BindVertextBufferAndDraw(IRenderCommandList & cmdList,const RenderSubmesh & currSubmesh)128 void BindVertextBufferAndDraw(IRenderCommandList& cmdList, const RenderSubmesh& currSubmesh)
129 {
130     // vertex buffers and draw
131     if (currSubmesh.buffers.vertexBufferCount > 0U) {
132         cmdList.BindVertexBuffers({ currSubmesh.buffers.vertexBuffers, currSubmesh.buffers.vertexBufferCount });
133     }
134     const auto& dc = currSubmesh.drawCommand;
135     const VertexBuffer& iArgs = currSubmesh.buffers.indirectArgsBuffer;
136     const bool indirectDraw = RenderHandleUtil::IsValid(iArgs.bufferHandle);
137     if ((currSubmesh.buffers.indexBuffer.byteSize > 0U) &&
138         RenderHandleUtil::IsValid(currSubmesh.buffers.indexBuffer.bufferHandle)) {
139         cmdList.BindIndexBuffer(currSubmesh.buffers.indexBuffer);
140         if (indirectDraw) {
141             cmdList.DrawIndexedIndirect(
142                 iArgs.bufferHandle, iArgs.bufferOffset, dc.drawCountIndirect, dc.strideIndirect);
143         } else {
144             cmdList.DrawIndexed(dc.indexCount, dc.instanceCount, 0, 0, 0);
145         }
146     } else {
147         if (indirectDraw) {
148             cmdList.DrawIndirect(iArgs.bufferHandle, iArgs.bufferOffset, dc.drawCountIndirect, dc.strideIndirect);
149         } else {
150             cmdList.Draw(dc.vertexCount, dc.instanceCount, 0, 0);
151         }
152     }
153 }
154 
GetSubmeshMaterialFlags(const RenderDataDefaultMaterial::SubmeshMaterialFlags & submeshMaterialFlags,const IRenderDataStoreDefaultMaterial & dataStoreMaterial,const bool instanced,const bool hasShadows)155 RenderDataDefaultMaterial::SubmeshMaterialFlags GetSubmeshMaterialFlags(
156     const RenderDataDefaultMaterial::SubmeshMaterialFlags& submeshMaterialFlags,
157     const IRenderDataStoreDefaultMaterial& dataStoreMaterial, const bool instanced, const bool hasShadows)
158 {
159     // create a new copy and modify if needed (force instancing on and off)
160     RenderDataDefaultMaterial::SubmeshMaterialFlags materialFlags = submeshMaterialFlags;
161     if (!hasShadows) { // remove shadow if not in scene
162         materialFlags.renderMaterialFlags &= (~RenderMaterialFlagBits::RENDER_MATERIAL_SHADOW_RECEIVER_BIT);
163         materialFlags.renderHash = dataStoreMaterial.GenerateRenderHash(materialFlags);
164     }
165     return materialFlags;
166 }
167 
GetFrameGlobalDescriptorSets(IRenderNodeContextManager * rncm,const SceneRenderDataStores & stores,const string & cameraName)168 RenderNodeDefaultMaterialRenderSlot::FrameGlobalDescriptorSets GetFrameGlobalDescriptorSets(
169     IRenderNodeContextManager* rncm, const SceneRenderDataStores& stores, const string& cameraName)
170 {
171     RenderNodeDefaultMaterialRenderSlot::FrameGlobalDescriptorSets fgds;
172     if (rncm) {
173         // re-fetch global descriptor sets every frame
174         const INodeContextDescriptorSetManager& dsMgr = rncm->GetDescriptorSetManager();
175         const string_view us = stores.dataStoreNameScene;
176         fgds.set0 = dsMgr.GetGlobalDescriptorSet(
177             us + DefaultMaterialMaterialConstants::MATERIAL_SET0_GLOBAL_DESCRIPTOR_SET_PREFIX_NAME + cameraName);
178         fgds.set1 = dsMgr.GetGlobalDescriptorSet(
179             us + DefaultMaterialMaterialConstants::MATERIAL_SET1_GLOBAL_DESCRIPTOR_SET_NAME);
180         fgds.set2 = dsMgr.GetGlobalDescriptorSets(
181             us + DefaultMaterialMaterialConstants::MATERIAL_RESOURCES_GLOBAL_DESCRIPTOR_SET_NAME);
182         fgds.set2Default = dsMgr.GetGlobalDescriptorSet(
183             us + DefaultMaterialMaterialConstants::MATERIAL_DEFAULT_RESOURCE_GLOBAL_DESCRIPTOR_SET_NAME);
184 #if (CORE3D_VALIDATION_ENABLED == 1)
185         if (fgds.set2.empty()) {
186             CORE_LOG_ONCE_W("core3d_global_descriptor_set_render_slot_issues",
187                 "CORE3D_VALIDATION: Global descriptor set for default material env not found");
188         }
189 #endif
190         fgds.valid = RenderHandleUtil::IsValid(fgds.set0) && RenderHandleUtil::IsValid(fgds.set1) &&
191                      RenderHandleUtil::IsValid(fgds.set2Default);
192         if (!fgds.valid) {
193             CORE_LOG_ONCE_E("core3d_global_descriptor_set_rs_all_issues",
194                 "Global descriptor set 0/1/2 for default material not "
195                 "found (RenderNodeDefaultCameraController needed)");
196         }
197     }
198     return fgds;
199 }
200 } // namespace
201 
InitNode(IRenderNodeContextManager & renderNodeContextMgr)202 void RenderNodeDefaultMaterialRenderSlot::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
203 {
204     renderNodeContextMgr_ = &renderNodeContextMgr;
205     ParseRenderNodeInputs();
206 
207     const auto& renderNodeGraphData = renderNodeContextMgr_->GetRenderNodeGraphData();
208     stores_ = RenderNodeSceneUtil::GetSceneRenderDataStores(
209         renderNodeContextMgr, renderNodeGraphData.renderNodeGraphDataStoreName);
210 
211     // reset
212     currentScene_ = {};
213     allShaderData_ = {};
214 
215     if ((jsonInputs_.nodeFlags & RenderSceneFlagBits::RENDER_SCENE_DIRECT_POST_PROCESS_BIT) &&
216         jsonInputs_.renderDataStore.dataStoreName.empty()) {
217         CORE_LOG_V("%s: render data store post process configuration not set in render node graph",
218             renderNodeContextMgr_->GetName().data());
219     }
220     rngRenderPass_ = renderNodeContextMgr_->GetRenderNodeUtil().CreateRenderPass(inputRenderPass_);
221     CreateDefaultShaderData();
222 
223     auto& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
224     defaultSamplers_.cubemapHandle =
225         gpuResourceMgr.GetSamplerHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_RADIANCE_CUBEMAP_SAMPLER);
226     defaultSamplers_.linearHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_CLAMP");
227     defaultSamplers_.nearestHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_NEAREST_CLAMP");
228     defaultSamplers_.linearMipHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_CLAMP");
229     defaultColorPrePassHandle_ = gpuResourceMgr.GetImageHandle("CORE_DEFAULT_GPU_IMAGE");
230 }
231 
PreExecuteFrame()232 void RenderNodeDefaultMaterialRenderSlot::PreExecuteFrame()
233 {
234     // re-create needed gpu resources
235 }
236 
ExecuteFrame(IRenderCommandList & cmdList)237 void RenderNodeDefaultMaterialRenderSlot::ExecuteFrame(IRenderCommandList& cmdList)
238 {
239     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
240     const auto* dataStoreScene =
241         static_cast<IRenderDataStoreDefaultScene*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameScene));
242     const auto* dataStoreMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(
243         renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameMaterial));
244     const auto* dataStoreCamera =
245         static_cast<IRenderDataStoreDefaultCamera*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameCamera));
246     const auto* dataStoreLight =
247         static_cast<IRenderDataStoreDefaultLight*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameLight));
248 
249     const bool validRenderDataStore = dataStoreScene && dataStoreMaterial && dataStoreCamera && dataStoreLight;
250     if (validRenderDataStore) {
251         UpdateCurrentScene(*dataStoreScene, *dataStoreCamera, *dataStoreLight);
252     } else {
253         CORE_LOG_E("invalid render data stores in RenderNodeDefaultMaterialRenderSlot");
254     }
255 
256 #if (CORE3D_VALIDATION_ENABLED == 1)
257     RENDER_DEBUG_MARKER_COL_SCOPE(
258         cmdList, "3DMaterial" + jsonInputs_.renderSlotName, DefaultDebugConstants::DEFAULT_DEBUG_COLOR);
259 #else
260     RENDER_DEBUG_MARKER_COL_SCOPE(cmdList, "3DMaterial", DefaultDebugConstants::DEFAULT_DEBUG_COLOR);
261 #endif
262 
263     cmdList.BeginRenderPass(renderPass_.renderPassDesc, renderPass_.subpassStartIndex, renderPass_.subpassDesc);
264 
265     if (validRenderDataStore) {
266         const auto cameras = dataStoreCamera->GetCameras();
267         const auto scene = dataStoreScene->GetScene();
268 
269         const bool hasShaders = allShaderData_.slotHasShaders;
270         const bool hasCamera =
271             (!cameras.empty() && (currentScene_.cameraIdx < (uint32_t)cameras.size())) ? true : false;
272 
273         ProcessSlotSubmeshes(*dataStoreCamera, *dataStoreMaterial);
274         const bool hasSubmeshes = (!sortedSlotSubmeshes_.empty());
275         if (hasShaders && hasCamera && hasSubmeshes) {
276             UpdatePostProcessConfiguration();
277             RenderSubmeshes(cmdList, *dataStoreMaterial, *dataStoreCamera);
278         }
279     }
280 
281     cmdList.EndRenderPass();
282 }
283 
RenderSubmeshes(IRenderCommandList & cmdList,const IRenderDataStoreDefaultMaterial & dataStoreMaterial,const IRenderDataStoreDefaultCamera & dataStoreCamera)284 void RenderNodeDefaultMaterialRenderSlot::RenderSubmeshes(IRenderCommandList& cmdList,
285     const IRenderDataStoreDefaultMaterial& dataStoreMaterial, const IRenderDataStoreDefaultCamera& dataStoreCamera)
286 {
287     // re-fetch global descriptor sets every frame
288     const FrameGlobalDescriptorSets fgds = GetFrameGlobalDescriptorSets(renderNodeContextMgr_, stores_, cameraName_);
289     if (!fgds.valid) {
290         return; // cannot continue
291     }
292 
293     // dynamic state
294     cmdList.SetDynamicStateViewport(currentScene_.viewportDesc);
295     cmdList.SetDynamicStateScissor(currentScene_.scissorDesc);
296     if (fsrEnabled_) {
297         cmdList.SetDynamicStateFragmentShadingRate(
298             { 1u, 1u }, FragmentShadingRateCombinerOps { CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE,
299                             CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE });
300     }
301 
302     // first two sets are only bound for the first submesh (inside for loop)
303     // no bindless, we need to update images per object
304     PipelineInfo pipelineInfo;
305     uint32_t currMaterialIndex = ~0u;
306     bool initialBindDone = false; // cannot be checked from the idx
307 
308     const auto& submeshMaterialFlags = dataStoreMaterial.GetSubmeshMaterialFlags();
309     const auto& submeshes = dataStoreMaterial.GetSubmeshes();
310     const auto& customResourceHandles = dataStoreMaterial.GetCustomResourceHandles();
311     const uint64_t camLayerMask = currentScene_.camera.layerMask;
312 
313     for (const auto& ssp : sortedSlotSubmeshes_) {
314         const uint32_t submeshIndex = ssp.submeshIndex;
315         const auto& currSubmesh = submeshes[submeshIndex];
316         // sorted slot submeshes should already have removed layers if default sorting was used
317         if (((camLayerMask & currSubmesh.layers.layerMask) == 0U) ||
318             ((jsonInputs_.nodeFlags & RENDER_SCENE_DISCARD_MATERIAL_BIT) &&
319                 (submeshMaterialFlags[submeshIndex].extraMaterialRenderingFlags &
320                     RenderExtraRenderingFlagBits::RENDER_EXTRA_RENDERING_DISCARD_BIT))) {
321             continue;
322         }
323         const auto materialSubmeshFlags = GetSubmeshMaterialFlags(submeshMaterialFlags[submeshIndex], dataStoreMaterial,
324             (currSubmesh.drawCommand.instanceCount > 1U), currentScene_.hasShadow);
325         const RenderSubmeshFlags submeshFlags = currSubmesh.submeshFlags | jsonInputs_.nodeSubmeshExtraFlags;
326 
327         BindPipeline(cmdList, ssp, materialSubmeshFlags, submeshFlags, currSubmesh.buffers.inputAssembly, pipelineInfo);
328 
329         // bind first set only the first time
330         if (!initialBindDone) {
331             cmdList.BindDescriptorSet(0, fgds.set0);
332         }
333 
334         currMaterialIndex = BindSet1And2(cmdList, currSubmesh, submeshFlags, initialBindDone, fgds, currMaterialIndex);
335         initialBindDone = true;
336 
337         // custom set 3 resources
338         if (pipelineInfo.boundCustomSetNeed) {
339             // if we do not have custom resources, and if we have binding issues we skip
340             if ((currSubmesh.indices.materialIndex >= static_cast<uint32_t>(customResourceHandles.size())) ||
341                 (customResourceHandles[currSubmesh.indices.materialIndex].resourceHandleCount == 0U) ||
342                 !UpdateAndBindSet3(cmdList, customResourceHandles[currSubmesh.indices.materialIndex])) {
343 #if (CORE3D_VALIDATION_ENABLED == 1)
344                 CORE_LOG_ONCE_W("material_render_slot_custom_set3_issue",
345                     "invalid bindings with custom shader descriptor set 3 (render node: %s)",
346                     renderNodeContextMgr_->GetName().data());
347 #endif
348                 continue; // we prevent drawing
349             }
350         }
351 
352         BindVertextBufferAndDraw(cmdList, currSubmesh);
353     }
354 }
355 
BindPipeline(IRenderCommandList & cmdList,const SlotSubmeshIndex & ssp,const RenderDataDefaultMaterial::SubmeshMaterialFlags & renderSubmeshMaterialFlags,const RenderSubmeshFlags submeshFlags,const GraphicsState::InputAssembly & inputAssembly,PipelineInfo & pipelineInfo)356 void RenderNodeDefaultMaterialRenderSlot::BindPipeline(IRenderCommandList& cmdList, const SlotSubmeshIndex& ssp,
357     const RenderDataDefaultMaterial::SubmeshMaterialFlags& renderSubmeshMaterialFlags,
358     const RenderSubmeshFlags submeshFlags, const GraphicsState::InputAssembly& inputAssembly,
359     PipelineInfo& pipelineInfo)
360 {
361     ShaderStateData ssd { ssp.shaderHandle, ssp.gfxStateHandle, 0 };
362     ssd.hash = (ssd.shader.id << 32U) | (ssd.gfxState.id & 0xFFFFffff);
363     // current shader state is fetched for build-in and custom shaders (decision is made later)
364     ssd.hash = HashShaderDataAndSubmesh(ssd.hash, renderSubmeshMaterialFlags.renderHash, currentScene_.lightingFlags,
365         currentScene_.cameraShaderFlags, currentRenderPPConfiguration_.flags.x, inputAssembly);
366     if (ssd.hash != pipelineInfo.boundShaderHash) {
367         const PsoAndInfo psoAndInfo = GetSubmeshPso(ssd, inputAssembly, renderSubmeshMaterialFlags, submeshFlags,
368             currentScene_.lightingFlags, currentScene_.cameraShaderFlags);
369         if (psoAndInfo.pso != pipelineInfo.boundPsoHandle) {
370             pipelineInfo.boundShaderHash = ssd.hash;
371             pipelineInfo.boundPsoHandle = psoAndInfo.pso;
372             cmdList.BindPipeline(pipelineInfo.boundPsoHandle);
373             pipelineInfo.boundCustomSetNeed = psoAndInfo.set3;
374         }
375     }
376 }
377 
BindSet1And2(IRenderCommandList & cmdList,const RenderSubmesh & currSubmesh,const RenderSubmeshFlags submeshFlags,const bool initialBindDone,const FrameGlobalDescriptorSets & fgds,uint32_t currMaterialIndex)378 uint32_t RenderNodeDefaultMaterialRenderSlot::BindSet1And2(IRenderCommandList& cmdList,
379     const RenderSubmesh& currSubmesh, const RenderSubmeshFlags submeshFlags, const bool initialBindDone,
380     const FrameGlobalDescriptorSets& fgds, uint32_t currMaterialIndex)
381 
382 {
383     // set 1 (mesh matrix, skin matrices, material, material user data)
384     const uint32_t currMatOffset = currSubmesh.indices.materialFrameOffset * UBO_BIND_OFFSET_ALIGNMENT;
385     const uint32_t dynamicOffsets[] = { currSubmesh.indices.meshIndex * UBO_BIND_OFFSET_ALIGNMENT,
386         (submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT)
387             ? currSubmesh.indices.skinJointIndex * static_cast<uint32_t>(sizeof(DefaultMaterialSkinStruct))
388             : 0U,
389         currMatOffset, currMatOffset, currMatOffset };
390     // set to bind, handle to resource, offsets for dynamic descs
391     IRenderCommandList::BindDescriptorSetData bindSets[2U] {};
392     uint32_t bindSetCount = 0U;
393     bindSets[bindSetCount++] = { fgds.set1, dynamicOffsets };
394 
395     // update material descriptor set
396     if ((!initialBindDone) || (currMaterialIndex != currSubmesh.indices.materialIndex)) {
397         currMaterialIndex = currSubmesh.indices.materialIndex;
398         // safety check for global material sets
399         const RenderHandle set2Handle =
400             (currMaterialIndex < fgds.set2.size()) ? fgds.set2[currMaterialIndex] : fgds.set2Default;
401         bindSets[bindSetCount++] = { set2Handle, {} };
402     }
403 
404     // bind sets 1 and possibly 2
405     cmdList.BindDescriptorSets(1U, { bindSets, bindSetCount });
406     return currMaterialIndex;
407 }
408 
UpdateAndBindSet3(IRenderCommandList & cmdList,const RenderDataDefaultMaterial::CustomResourceData & customResourceData)409 bool RenderNodeDefaultMaterialRenderSlot::UpdateAndBindSet3(
410     IRenderCommandList& cmdList, const RenderDataDefaultMaterial::CustomResourceData& customResourceData)
411 {
412     IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
413     INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
414     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
415 
416     // with default pipeline layout with default bindings
417     RenderHandle currPlHandle = allShaderData_.defaultPlSet3
418                                     ? allShaderData_.defaultPlHandle
419                                     : shaderMgr.GetPipelineLayoutHandleByShaderHandle(customResourceData.shaderHandle);
420     if (!RenderHandleUtil::IsValid(currPlHandle)) {
421         currPlHandle = shaderMgr.GetReflectionPipelineLayoutHandle(customResourceData.shaderHandle);
422     }
423     const PipelineLayout& plRef = shaderMgr.GetPipelineLayout(currPlHandle);
424     if (plRef.descriptorSetLayouts[FIXED_CUSTOM_SET3].bindings.empty()) {
425         return false; // early out
426     }
427     static_assert(FIXED_CUSTOM_SET3 <
428                   BASE_NS::extent_v<decltype(BASE_NS::remove_reference_t<decltype(plRef)>::descriptorSetLayouts)>);
429     const auto& descBindings = plRef.descriptorSetLayouts[FIXED_CUSTOM_SET3].bindings;
430     const RenderHandle descSetHandle = descriptorSetMgr.CreateOneFrameDescriptorSet(descBindings);
431     if (!RenderHandleUtil::IsValid(descSetHandle) || (descBindings.size() != customResourceData.resourceHandleCount)) {
432         return false;
433     }
434     IDescriptorSetBinder::Ptr binderPtr = descriptorSetMgr.CreateDescriptorSetBinder(descSetHandle, descBindings);
435     if (!binderPtr) {
436         return false;
437     }
438     auto& binder = *binderPtr;
439     for (uint32_t idx = 0; idx < customResourceData.resourceHandleCount; ++idx) {
440         CORE_ASSERT(idx < descBindings.size());
441         const RenderHandle& currRes = customResourceData.resourceHandles[idx];
442         if (gpuResourceMgr.IsGpuBuffer(currRes)) {
443             binder.BindBuffer(idx, currRes, 0);
444         } else if (gpuResourceMgr.IsGpuImage(currRes)) {
445             if (descBindings[idx].descriptorType == DescriptorType::CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
446                 binder.BindImage(idx, currRes, defaultSamplers_.linearMipHandle);
447             } else {
448                 binder.BindImage(idx, currRes);
449             }
450         } else if (gpuResourceMgr.IsGpuSampler(currRes)) {
451             binder.BindSampler(idx, currRes);
452         }
453     }
454 
455     // user generated setup, we check for validity of all bindings in the descriptor set
456     if (!binder.GetDescriptorSetLayoutBindingValidity()) {
457         return false;
458     }
459     cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
460     cmdList.BindDescriptorSet(FIXED_CUSTOM_SET3, binder.GetDescriptorSetHandle());
461     return true;
462 }
463 
GetSubmeshPso(const ShaderStateData & ssd,const GraphicsState::InputAssembly & ia,const RenderDataDefaultMaterial::SubmeshMaterialFlags & submeshMaterialFlags,const RenderSubmeshFlags submeshFlags,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags cameraShaderFlags)464 RenderNodeDefaultMaterialRenderSlot::PsoAndInfo RenderNodeDefaultMaterialRenderSlot::GetSubmeshPso(
465     const ShaderStateData& ssd, const GraphicsState::InputAssembly& ia,
466     const RenderDataDefaultMaterial::SubmeshMaterialFlags& submeshMaterialFlags, const RenderSubmeshFlags submeshFlags,
467     const IRenderDataStoreDefaultLight::LightingFlags lightingFlags, const RenderCamera::ShaderFlags cameraShaderFlags)
468 {
469     if (const auto dataIter = allShaderData_.shaderIdToData.find(ssd.hash);
470         dataIter != allShaderData_.shaderIdToData.cend()) {
471         const auto& ref = allShaderData_.perShaderData[dataIter->second];
472         return { ref.psoHandle, ref.needsCustomSetBindings };
473     }
474 
475     return CreateNewPso(ssd, ia, submeshMaterialFlags, submeshFlags, lightingFlags, cameraShaderFlags);
476 }
477 
UpdatePostProcessConfiguration()478 void RenderNodeDefaultMaterialRenderSlot::UpdatePostProcessConfiguration()
479 {
480     if (jsonInputs_.nodeFlags & RenderSceneFlagBits::RENDER_SCENE_DIRECT_POST_PROCESS_BIT) {
481         if (!jsonInputs_.renderDataStore.dataStoreName.empty()) {
482             auto const& dsMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
483             if (const IRenderDataStore* ds = dsMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName); ds) {
484                 if (jsonInputs_.renderDataStore.typeName == POST_PROCESS_DATA_STORE_TYPE_NAME) {
485                     auto const dataStore = static_cast<const IRenderDataStorePod*>(ds);
486                     auto const dataView = dataStore->Get(jsonInputs_.renderDataStore.configurationName);
487                     if (dataView.data() && (dataView.size_bytes() == sizeof(PostProcessConfiguration))) {
488                         const PostProcessConfiguration* data = (const PostProcessConfiguration*)dataView.data();
489                         currentRenderPPConfiguration_ =
490                             renderNodeContextMgr_->GetRenderNodeUtil().GetRenderPostProcessConfiguration(*data);
491                         currentRenderPPConfiguration_.flags.x =
492                             (currentRenderPPConfiguration_.flags.x & POST_PROCESS_IMPORTANT_FLAGS_MASK);
493                     }
494                 }
495             }
496         }
497     }
498 }
499 
UpdateCurrentScene(const IRenderDataStoreDefaultScene & dataStoreScene,const IRenderDataStoreDefaultCamera & dataStoreCamera,const IRenderDataStoreDefaultLight & dataStoreLight)500 void RenderNodeDefaultMaterialRenderSlot::UpdateCurrentScene(const IRenderDataStoreDefaultScene& dataStoreScene,
501     const IRenderDataStoreDefaultCamera& dataStoreCamera, const IRenderDataStoreDefaultLight& dataStoreLight)
502 {
503     if (jsonInputs_.hasChangeableRenderPassHandles) {
504         const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
505         inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
506         rngRenderPass_ = renderNodeContextMgr_->GetRenderNodeUtil().CreateRenderPass(inputRenderPass_);
507     }
508     // get default RNG based render pass setup
509     renderPass_ = rngRenderPass_;
510 
511     const auto scene = dataStoreScene.GetScene();
512     bool hasCustomCamera = false;
513     bool isNamedCamera = false; // NOTE: legacy support will be removed
514     uint32_t cameraIdx = scene.cameraIndex;
515     if (jsonInputs_.customCameraId != INVALID_CAM_ID) {
516         cameraIdx = dataStoreCamera.GetCameraIndex(jsonInputs_.customCameraId);
517         hasCustomCamera = true;
518     } else if (!(jsonInputs_.customCameraName.empty())) {
519         cameraIdx = dataStoreCamera.GetCameraIndex(jsonInputs_.customCameraName);
520         hasCustomCamera = true;
521         isNamedCamera = true;
522     }
523 
524     if (const auto cameras = dataStoreCamera.GetCameras(); cameraIdx < (uint32_t)cameras.size()) {
525         // store current frame camera
526         currentScene_.camera = cameras[cameraIdx];
527     }
528 
529     const auto camHandles = RenderNodeSceneUtil::GetSceneCameraImageHandles(
530         *renderNodeContextMgr_, stores_.dataStoreNameScene, currentScene_.camera.name, currentScene_.camera);
531     currentScene_.cameraEnvRadianceHandle = camHandles.radianceCubemap;
532 
533     if (!currentScene_.camera.prePassColorTargetName.empty()) {
534         currentScene_.prePassColorTarget =
535             renderNodeContextMgr_->GetGpuResourceManager().GetImageHandle(currentScene_.camera.prePassColorTargetName);
536     }
537 
538     // renderpass needs to be valid (created in init)
539     if (hasCustomCamera) {
540         // uses camera based loadOp clear override if given
541         RenderNodeSceneUtil::UpdateRenderPassFromCustomCamera(currentScene_.camera, isNamedCamera, renderPass_);
542     } else {
543         RenderNodeSceneUtil::UpdateRenderPassFromCamera(currentScene_.camera, renderPass_);
544     }
545     currentScene_.viewportDesc = RenderNodeSceneUtil::CreateViewportFromCamera(currentScene_.camera);
546     currentScene_.scissorDesc = RenderNodeSceneUtil::CreateScissorFromCamera(currentScene_.camera);
547 
548     const IRenderDataStoreDefaultLight::LightCounts lightCounts = dataStoreLight.GetLightCounts();
549     currentScene_.hasShadow = (lightCounts.shadowCount > 0) ? true : false;
550     currentScene_.cameraIdx = cameraIdx;
551     currentScene_.shadowTypes = dataStoreLight.GetShadowTypes();
552     currentScene_.lightingFlags = dataStoreLight.GetLightingFlags();
553     currentScene_.cameraShaderFlags = currentScene_.camera.shaderFlags;
554     // remove fog explicitly if render node graph input and/or default render slot usage states so
555     if (jsonInputs_.nodeFlags & RenderSceneFlagBits::RENDER_SCENE_DISABLE_FOG_BIT) {
556         currentScene_.cameraShaderFlags &= (~RenderCamera::ShaderFlagBits::CAMERA_SHADER_FOG_BIT);
557     }
558     GetMultiViewCameraIndices(dataStoreCamera, currentScene_.camera, currentScene_.mvCameraIndices);
559     // add multi-view flags if needed
560     if (renderPass_.subpassDesc.viewMask > 1U) {
561         ResetRenderSlotData(jsonInputs_.shaderRenderSlotMultiviewId, true);
562     } else {
563         ResetRenderSlotData(jsonInputs_.shaderRenderSlotBaseId, false);
564     }
565 }
566 
CreateDefaultShaderData()567 void RenderNodeDefaultMaterialRenderSlot::CreateDefaultShaderData()
568 {
569     allShaderData_ = {};
570 
571     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
572 
573     // get the default material shader and default shader state
574     const IShaderManager::RenderSlotData shaderRsd = shaderMgr.GetRenderSlotData(jsonInputs_.shaderRenderSlotId);
575     allShaderData_.defaultShaderHandle = shaderRsd.shader.GetHandle();
576     allShaderData_.defaultStateHandle = shaderRsd.graphicsState.GetHandle();
577     // get the pl and vid defaults
578     allShaderData_.defaultPlHandle =
579         (shaderRsd.pipelineLayout)
580             ? shaderRsd.pipelineLayout.GetHandle()
581             : shaderMgr.GetPipelineLayoutHandle(DefaultMaterialShaderConstants::PIPELINE_LAYOUT_FORWARD);
582     allShaderData_.defaultPipelineLayout = shaderMgr.GetPipelineLayout(allShaderData_.defaultPlHandle);
583     allShaderData_.defaultTmpPipelineLayout = allShaderData_.defaultPipelineLayout;
584     allShaderData_.defaultVidHandle = (shaderRsd.vertexInputDeclaration)
585                                           ? shaderRsd.vertexInputDeclaration.GetHandle()
586                                           : shaderMgr.GetVertexInputDeclarationHandle(
587                                               DefaultMaterialShaderConstants::VERTEX_INPUT_DECLARATION_FORWARD);
588     if (!allShaderData_.defaultPipelineLayout.descriptorSetLayouts[FIXED_CUSTOM_SET3].bindings.empty()) {
589         allShaderData_.defaultPlSet3 = true;
590     }
591 
592     if (shaderMgr.IsShader(allShaderData_.defaultShaderHandle)) {
593         allShaderData_.slotHasShaders = true;
594         const ShaderSpecializationConstantView& sscv =
595             shaderMgr.GetReflectionSpecialization(allShaderData_.defaultShaderHandle);
596         allShaderData_.defaultSpecilizationConstants.resize(sscv.constants.size());
597         for (uint32_t idx = 0; idx < (uint32_t)allShaderData_.defaultSpecilizationConstants.size(); ++idx) {
598             allShaderData_.defaultSpecilizationConstants[idx] = sscv.constants[idx];
599         }
600         specializationData_.maxSpecializationCount =
601             Math::min(static_cast<uint32_t>(allShaderData_.defaultSpecilizationConstants.size()),
602                 SpecializationData::MAX_FLAG_COUNT);
603     } else {
604         CORE_LOG_I("RenderNode: %s, no default shaders for render slot id %u", renderNodeContextMgr_->GetName().data(),
605             jsonInputs_.shaderRenderSlotId);
606     }
607     if (jsonInputs_.shaderRenderSlotId != jsonInputs_.stateRenderSlotId) {
608         const IShaderManager::RenderSlotData stateRsd = shaderMgr.GetRenderSlotData(jsonInputs_.stateRenderSlotId);
609         if (stateRsd.graphicsState) {
610             allShaderData_.defaultStateHandle = stateRsd.graphicsState.GetHandle();
611         } else {
612             CORE_LOG_I("RenderNode: %s, no default state for render slot id %u",
613                 renderNodeContextMgr_->GetName().data(), jsonInputs_.stateRenderSlotId);
614         }
615     }
616 }
617 
618 namespace {
619 // updates graphics state based on params
GetNewGraphicsState(const IRenderNodeShaderManager & shaderMgr,const RenderHandle & handle,const bool inverseWinding,const bool customInputAssembly,const GraphicsState::InputAssembly & ia)620 inline GraphicsState GetNewGraphicsState(const IRenderNodeShaderManager& shaderMgr, const RenderHandle& handle,
621     const bool inverseWinding, const bool customInputAssembly, const GraphicsState::InputAssembly& ia)
622 {
623     // we create a new graphics state based on current
624     GraphicsState gfxState = shaderMgr.GetGraphicsState(handle);
625     // update state
626     if (inverseWinding) {
627         gfxState.rasterizationState.frontFace = FrontFace::CORE_FRONT_FACE_CLOCKWISE;
628     }
629     if (customInputAssembly) {
630         gfxState.inputAssembly = ia;
631     }
632     return gfxState;
633 }
634 } // namespace
635 
CreateNewPso(const ShaderStateData & ssd,const GraphicsState::InputAssembly & ia,const RenderDataDefaultMaterial::SubmeshMaterialFlags & submeshMatFlags,const RenderSubmeshFlags submeshFlags,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags camShaderFlags)636 RenderNodeDefaultMaterialRenderSlot::PsoAndInfo RenderNodeDefaultMaterialRenderSlot::CreateNewPso(
637     const ShaderStateData& ssd, const GraphicsState::InputAssembly& ia,
638     const RenderDataDefaultMaterial::SubmeshMaterialFlags& submeshMatFlags, const RenderSubmeshFlags submeshFlags,
639     const IRenderDataStoreDefaultLight::LightingFlags lightingFlags, const RenderCamera::ShaderFlags camShaderFlags)
640 {
641     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
642     // NOTE: The easiest route would be to input shader and graphics state to material component
643     RenderHandle currShader;
644     RenderHandle currVid;
645     RenderHandle currState;
646     // first try to find matching shader
647     if (RenderHandleUtil::GetHandleType(ssd.shader) == RenderHandleType::SHADER_STATE_OBJECT) {
648         // we force the given shader if explicit shader render slot is not given
649         if (!jsonInputs_.explicitShader) {
650             currShader = ssd.shader;
651         }
652         const RenderHandle slotShader = shaderMgr.GetShaderHandle(ssd.shader, jsonInputs_.shaderRenderSlotId);
653         if (RenderHandleUtil::IsValid(slotShader)) {
654             currShader = slotShader; // override with render slot variant
655         }
656         // if not explicit gfx state given, check if shader has graphics state for this slot
657         if (!RenderHandleUtil::IsValid(ssd.gfxState)) {
658             const auto gfxStateHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(currShader);
659             if (shaderMgr.GetRenderSlotId(gfxStateHandle) == jsonInputs_.stateRenderSlotId) {
660                 currState = gfxStateHandle;
661             }
662         }
663         currVid = shaderMgr.GetVertexInputDeclarationHandleByShaderHandle(currShader);
664     }
665     if (RenderHandleUtil::GetHandleType(ssd.gfxState) == RenderHandleType::GRAPHICS_STATE) {
666         const RenderHandle slotState = shaderMgr.GetGraphicsStateHandle(ssd.gfxState, jsonInputs_.stateRenderSlotId);
667         if (RenderHandleUtil::IsValid(slotState)) {
668             currState = slotState;
669         }
670     }
671 
672     bool needsCustomSet = false;
673     const PipelineLayout& pl = GetEvaluatedPipelineLayout(currShader, needsCustomSet);
674 
675     // fallback to defaults if needed
676     currShader = RenderHandleUtil::IsValid(currShader) ? currShader : allShaderData_.defaultShaderHandle;
677     currVid = RenderHandleUtil::IsValid(currVid) ? currVid : allShaderData_.defaultVidHandle;
678     currState = RenderHandleUtil::IsValid(currState) ? currState : allShaderData_.defaultStateHandle;
679 
680     auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
681     RenderHandle psoHandle;
682     const bool inverseWinding = IsInverseWinding(submeshFlags, jsonInputs_.nodeFlags, currentScene_.camera.flags);
683     const bool customIa = (ia.primitiveTopology != CORE_PRIMITIVE_TOPOLOGY_MAX_ENUM) || (ia.enablePrimitiveRestart);
684     const VertexInputDeclarationView vid = shaderMgr.GetVertexInputDeclarationView(currVid);
685     if (inverseWinding || customIa) {
686         const GraphicsState state = GetNewGraphicsState(shaderMgr, currState, inverseWinding, customIa, ia);
687         const auto spec = GetShaderSpecView(state, submeshMatFlags, submeshFlags, lightingFlags, camShaderFlags);
688         psoHandle = psoMgr.GetGraphicsPsoHandle(currShader, state, pl, vid, spec, GetDynamicStates());
689     } else {
690         // graphics state in default mode
691         const GraphicsState& state = shaderMgr.GetGraphicsState(currState);
692         const auto spec = GetShaderSpecView(state, submeshMatFlags, submeshFlags, lightingFlags, camShaderFlags);
693         psoHandle = psoMgr.GetGraphicsPsoHandle(currShader, state, pl, vid, spec, GetDynamicStates());
694     }
695 
696     allShaderData_.perShaderData.push_back(PerShaderData { currShader, psoHandle, currState, needsCustomSet });
697     allShaderData_.shaderIdToData[ssd.hash] = (uint32_t)allShaderData_.perShaderData.size() - 1;
698     return { psoHandle, needsCustomSet };
699 }
700 
GetShaderSpecView(const RENDER_NS::GraphicsState & gfxState,const RenderDataDefaultMaterial::SubmeshMaterialFlags & submeshMatFlags,const RenderSubmeshFlags submeshFlags,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags camShaderFlags)701 ShaderSpecializationConstantDataView RenderNodeDefaultMaterialRenderSlot::GetShaderSpecView(
702     const RENDER_NS::GraphicsState& gfxState, const RenderDataDefaultMaterial::SubmeshMaterialFlags& submeshMatFlags,
703     const RenderSubmeshFlags submeshFlags, const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,
704     const RenderCamera::ShaderFlags camShaderFlags)
705 {
706     RenderMaterialFlags combinedMaterialFlags = submeshMatFlags.renderMaterialFlags;
707     if (gfxState.colorBlendState.colorAttachmentCount > 0) {
708         // enable opaque flag if blending is not enabled with the first color attachment
709         combinedMaterialFlags |= (gfxState.colorBlendState.colorAttachments[0].enableBlend)
710                                      ? 0u
711                                      : RenderMaterialFlagBits::RENDER_MATERIAL_OPAQUE_BIT;
712     }
713     for (uint32_t idx = 0; idx < specializationData_.maxSpecializationCount; ++idx) {
714         const auto& ref = allShaderData_.defaultSpecilizationConstants[idx];
715         const uint32_t constantId = ref.offset / sizeof(uint32_t);
716 
717         // NOTE: vertex and fragment have different specializations for the zero index
718         if (ref.shaderStage == ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT) {
719             if (ref.id == CORE_DM_CONSTANT_ID_SUBMESH_FLAGS) {
720                 specializationData_.flags[constantId] = submeshFlags;
721             } else if (ref.id == CORE_DM_CONSTANT_ID_MATERIAL_FLAGS) {
722                 specializationData_.flags[constantId] = combinedMaterialFlags;
723             }
724         } else if (ref.shaderStage == ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT) {
725             if (ref.id == CORE_DM_CONSTANT_ID_MATERIAL_TYPE) {
726                 specializationData_.flags[constantId] = static_cast<uint32_t>(submeshMatFlags.materialType);
727             } else if (ref.id == CORE_DM_CONSTANT_ID_MATERIAL_FLAGS) {
728                 specializationData_.flags[constantId] = combinedMaterialFlags;
729             } else if (ref.id == CORE_DM_CONSTANT_ID_LIGHTING_FLAGS) {
730                 specializationData_.flags[constantId] = lightingFlags;
731             } else if (ref.id == CORE_DM_CONSTANT_ID_POST_PROCESS_FLAGS) {
732                 specializationData_.flags[constantId] = currentRenderPPConfiguration_.flags.x;
733             } else if (ref.id == CORE_DM_CONSTANT_ID_CAMERA_FLAGS) {
734                 specializationData_.flags[constantId] = camShaderFlags;
735             }
736         }
737     }
738 
739     return { { allShaderData_.defaultSpecilizationConstants.data(), specializationData_.maxSpecializationCount },
740         { specializationData_.flags, specializationData_.maxSpecializationCount } };
741 }
742 
ProcessSlotSubmeshes(const IRenderDataStoreDefaultCamera & dataStoreCamera,const IRenderDataStoreDefaultMaterial & dataStoreMaterial)743 void RenderNodeDefaultMaterialRenderSlot::ProcessSlotSubmeshes(
744     const IRenderDataStoreDefaultCamera& dataStoreCamera, const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
745 {
746     // currentScene has been updated prior, has the correct camera (scene camera or custom camera)
747     const IRenderNodeSceneUtil::RenderSlotInfo rsi { jsonInputs_.renderSlotId, jsonInputs_.sortType,
748         jsonInputs_.cullType, jsonInputs_.nodeMaterialDiscardFlags };
749 
750     RenderNodeSceneUtil::GetRenderSlotSubmeshes(dataStoreCamera, dataStoreMaterial, currentScene_.cameraIdx,
751         currentScene_.mvCameraIndices, rsi, sortedSlotSubmeshes_);
752 }
753 
GetDynamicStates() const754 array_view<const DynamicStateEnum> RenderNodeDefaultMaterialRenderSlot::GetDynamicStates() const
755 {
756     if (fsrEnabled_) {
757         return { DYNAMIC_STATES_FSR, countof(DYNAMIC_STATES_FSR) };
758     } else {
759         return { DYNAMIC_STATES, countof(DYNAMIC_STATES) };
760     }
761 }
762 
ParseRenderNodeInputs()763 void RenderNodeDefaultMaterialRenderSlot::ParseRenderNodeInputs()
764 {
765     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
766     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
767     jsonInputs_.renderPass = parserUtil.GetInputRenderPass(jsonVal, "renderPass");
768     jsonInputs_.customCameraName = parserUtil.GetStringValue(jsonVal, "customCameraName");
769     jsonInputs_.customCameraId = parserUtil.GetUintValue(jsonVal, "customCameraId");
770     jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
771 
772     jsonInputs_.sortType = parserUtil.GetRenderSlotSortType(jsonVal, "renderSlotSortType");
773     jsonInputs_.cullType = parserUtil.GetRenderSlotCullType(jsonVal, "renderSlotCullType");
774     jsonInputs_.nodeFlags = static_cast<uint32_t>(parserUtil.GetUintValue(jsonVal, "nodeFlags"));
775     if (jsonInputs_.nodeFlags == ~0u) {
776         jsonInputs_.nodeFlags = 0;
777     }
778     jsonInputs_.nodeMaterialDiscardFlags =
779         static_cast<uint32_t>(parserUtil.GetUintValue(jsonVal, "nodeMaterialDiscardFlags"));
780     if (jsonInputs_.nodeMaterialDiscardFlags == ~0u) {
781         jsonInputs_.nodeMaterialDiscardFlags = 0;
782     }
783     // automatic default material velocity named target based parsing to add velocity calculations bit
784     for (const auto& ref : jsonInputs_.renderPass.attachments) {
785         if (ref.name == DefaultMaterialRenderNodeConstants::CORE_DM_CAMERA_VELOCITY_NORMAL) {
786             jsonInputs_.nodeSubmeshExtraFlags |= RenderSubmeshFlagBits::RENDER_SUBMESH_VELOCITY_BIT;
787         }
788     }
789 
790     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
791     jsonInputs_.renderSlotName = parserUtil.GetStringValue(jsonVal, "renderSlot");
792     jsonInputs_.renderSlotId = shaderMgr.GetRenderSlotId(jsonInputs_.renderSlotName);
793     jsonInputs_.shaderRenderSlotId = jsonInputs_.renderSlotId;
794     jsonInputs_.stateRenderSlotId = jsonInputs_.renderSlotId;
795     const string shaderRenderSlot = parserUtil.GetStringValue(jsonVal, "shaderRenderSlot");
796     if (!shaderRenderSlot.empty()) {
797         const uint32_t renderSlotId = shaderMgr.GetRenderSlotId(shaderRenderSlot);
798         if (renderSlotId != ~0U) {
799             jsonInputs_.shaderRenderSlotId = renderSlotId;
800             jsonInputs_.initialExplicitShader = true;
801             jsonInputs_.explicitShader = true;
802         }
803     }
804     jsonInputs_.shaderRenderSlotBaseId = jsonInputs_.shaderRenderSlotId;
805     const string stateRenderSlot = parserUtil.GetStringValue(jsonVal, "stateRenderSlot");
806     if (!stateRenderSlot.empty()) {
807         const uint32_t renderSlotId = shaderMgr.GetRenderSlotId(stateRenderSlot);
808         jsonInputs_.stateRenderSlotId = (renderSlotId != ~0U) ? renderSlotId : jsonInputs_.renderSlotId;
809     }
810     const string shaderMultiviewRenderSlot = parserUtil.GetStringValue(jsonVal, "shaderMultiviewRenderSlot");
811     if (!shaderMultiviewRenderSlot.empty()) {
812         jsonInputs_.shaderRenderSlotMultiviewId = shaderMgr.GetRenderSlotId(shaderMultiviewRenderSlot);
813     }
814 
815     EvaluateFogBits();
816 
817     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
818     inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
819     if ((inputRenderPass_.fragmentShadingRateAttachmentIndex < inputRenderPass_.attachments.size()) &&
820         RenderHandleUtil::IsValid(
821             inputRenderPass_.attachments[inputRenderPass_.fragmentShadingRateAttachmentIndex].handle)) {
822         fsrEnabled_ = true;
823     }
824     jsonInputs_.hasChangeableRenderPassHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.renderPass);
825 
826     if (jsonInputs_.customCameraId != INVALID_CAM_ID) {
827         cameraName_ = to_string(jsonInputs_.customCameraId);
828     } else if (!(jsonInputs_.customCameraName.empty())) {
829         cameraName_ = jsonInputs_.customCameraName;
830     }
831 }
832 
ResetRenderSlotData(const uint32_t shaderRenderSlotId,const bool multiView)833 void RenderNodeDefaultMaterialRenderSlot::ResetRenderSlotData(const uint32_t shaderRenderSlotId, const bool multiView)
834 {
835     // can be reset to multi-view usage or reset back to default usage
836     if (shaderRenderSlotId != jsonInputs_.shaderRenderSlotId) {
837         jsonInputs_.shaderRenderSlotId = shaderRenderSlotId;
838         jsonInputs_.explicitShader = jsonInputs_.initialExplicitShader || multiView;
839         // reset
840         CreateDefaultShaderData();
841     }
842 }
843 
EvaluateFogBits()844 void RenderNodeDefaultMaterialRenderSlot::EvaluateFogBits()
845 {
846     // if no explicit bits set we check default render slot usages
847     if ((jsonInputs_.nodeFlags & (RENDER_SCENE_ENABLE_FOG_BIT | RENDER_SCENE_DISABLE_FOG_BIT)) == 0) {
848         // check default render slots
849         const uint32_t opaqueSlotId = renderNodeContextMgr_->GetShaderManager().GetRenderSlotId(
850             DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE);
851         const uint32_t translucentSlotId = renderNodeContextMgr_->GetShaderManager().GetRenderSlotId(
852             DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT);
853         if ((jsonInputs_.renderSlotId == opaqueSlotId) || (jsonInputs_.renderSlotId == translucentSlotId)) {
854             jsonInputs_.nodeFlags |= RenderSceneFlagBits::RENDER_SCENE_ENABLE_FOG_BIT;
855         }
856     }
857 }
858 
GetEvaluatedPipelineLayout(const RenderHandle & currShader,bool & needsCustomSet)859 const PipelineLayout& RenderNodeDefaultMaterialRenderSlot::GetEvaluatedPipelineLayout(
860     const RenderHandle& currShader, bool& needsCustomSet)
861 {
862     // the inputs need to be in certain "state"
863     // currShader is valid if there's custom shader
864 
865     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
866     // clear custom tmp pipeline layouts
867     auto& tmpPl = allShaderData_.defaultTmpPipelineLayout;
868 
869     auto UpdateCustomPl = [](const DescriptorSetLayout& dsl, PipelineLayout& tmpPl) {
870         if (!dsl.bindings.empty()) {
871             tmpPl.descriptorSetLayouts[FIXED_CUSTOM_SET3] = dsl;
872             tmpPl.descriptorSetCount = CUSTOM_SET_DESCRIPTOR_SET_COUNT;
873             return true;
874         } else {
875             return false;
876         }
877     };
878 
879     const bool def3NoShader = ((!RenderHandleUtil::IsValid(currShader)) && (allShaderData_.defaultPlSet3));
880     if (RenderHandleUtil::IsValid(currShader) || def3NoShader) {
881         const RenderHandle shader = def3NoShader ? allShaderData_.defaultShaderHandle : currShader;
882         RenderHandle reflPl;
883         RenderHandle currPl = shaderMgr.GetPipelineLayoutHandleByShaderHandle(shader);
884         if (RenderHandleUtil::IsValid(currPl)) {
885             const auto& plSet = shaderMgr.GetPipelineLayout(currPl).descriptorSetLayouts[FIXED_CUSTOM_SET3];
886             needsCustomSet = UpdateCustomPl(plSet, tmpPl);
887         }
888         if ((!needsCustomSet) && (!RenderHandleUtil::IsValid(currPl))) {
889             reflPl = shaderMgr.GetReflectionPipelineLayoutHandle(shader);
890             const auto& plSet = shaderMgr.GetPipelineLayout(reflPl).descriptorSetLayouts[FIXED_CUSTOM_SET3];
891             needsCustomSet = UpdateCustomPl(plSet, tmpPl);
892         }
893 #if (CORE3D_VALIDATION_ENABLED == 1)
894         {
895             if (!RenderHandleUtil::IsValid(reflPl)) {
896                 reflPl = shaderMgr.GetReflectionPipelineLayoutHandle(shader);
897             }
898             const IShaderManager::CompatibilityFlags flags =
899                 shaderMgr.GetCompatibilityFlags(allShaderData_.defaultPlHandle, reflPl);
900             if (flags == 0) {
901                 const auto idDesc = shaderMgr.GetIdDesc(shader);
902                 CORE_LOG_W("Compatibility issue with 3D default material shaders (name: %s, path: %s)",
903                     idDesc.displayName.c_str(), idDesc.path.c_str());
904             }
905         }
906 #endif
907     }
908 
909     // return modified custom pipeline layout or the default
910     if (needsCustomSet) {
911         return allShaderData_.defaultTmpPipelineLayout;
912     } else {
913         return allShaderData_.defaultPipelineLayout;
914     }
915 }
916 
917 // for plugin / factory interface
Create()918 RENDER_NS::IRenderNode* RenderNodeDefaultMaterialRenderSlot::Create()
919 {
920     return new RenderNodeDefaultMaterialRenderSlot();
921 }
922 
Destroy(IRenderNode * instance)923 void RenderNodeDefaultMaterialRenderSlot::Destroy(IRenderNode* instance)
924 {
925     delete static_cast<RenderNodeDefaultMaterialRenderSlot*>(instance);
926 }
927 CORE3D_END_NAMESPACE()
928