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