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/render_node_scene_util.h"
45 
46 #if (CORE3D_DEV_ENABLED == 1)
47 #include "render/datastore/render_data_store_default_material.h"
48 #endif
49 
50 namespace {
51 #include <3d/shaders/common/3d_dm_structures_common.h>
52 #include <render/shaders/common/render_post_process_structs_common.h>
53 } // namespace
54 
55 CORE3D_BEGIN_NAMESPACE()
56 using namespace BASE_NS;
57 using namespace RENDER_NS;
58 
59 namespace {
60 constexpr string_view POST_PROCESS_DATA_STORE_TYPE_NAME { "RenderDataStorePod" };
61 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
62 constexpr DynamicStateEnum DYNAMIC_STATES_FSR[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR,
63     CORE_DYNAMIC_STATE_ENUM_FRAGMENT_SHADING_RATE };
64 
65 constexpr uint32_t UBO_BIND_OFFSET_ALIGNMENT { PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE };
66 
67 static constexpr uint64_t LIGHTING_FLAGS_SHIFT { 32u };
68 static constexpr uint64_t LIGHTING_FLAGS_MASK { 0xF00000000u };
69 static constexpr uint64_t POST_PROCESS_FLAGS_SHIFT { 36u };
70 static constexpr uint64_t POST_PROCESS_FLAGS_MASK { 0xF000000000u };
71 static constexpr uint64_t CAMERA_FLAGS_SHIFT { 40u };
72 static constexpr uint64_t CAMERA_FLAGS_MASK { 0xF0000000000u };
73 static constexpr uint64_t RENDER_HASH_FLAGS_MASK { 0xFFFFffffu };
74 
75 // our light weight straight to screen post processes are only interested in these
76 static constexpr uint32_t POST_PROCESS_IMPORTANT_FLAGS_MASK { 0xffu };
77 
78 static constexpr uint32_t FIXED_CUSTOM_SET3 { 3u };
79 static constexpr uint32_t CUSTOM_SET_DESCRIPTOR_SET_COUNT { 4u };
80 
GetDefaultMaterialGpuResources(const IRenderNodeGpuResourceManager & gpuResourceMgr,RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct & defaultMat)81 void GetDefaultMaterialGpuResources(const IRenderNodeGpuResourceManager& gpuResourceMgr,
82     RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct& defaultMat)
83 {
84     defaultMat.resources[MaterialComponent::TextureIndex::BASE_COLOR].handle =
85         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_BASE_COLOR);
86     defaultMat.resources[MaterialComponent::TextureIndex::NORMAL].handle =
87         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_NORMAL);
88     defaultMat.resources[MaterialComponent::TextureIndex::MATERIAL].handle =
89         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_MATERIAL);
90     defaultMat.resources[MaterialComponent::TextureIndex::EMISSIVE].handle =
91         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_EMISSIVE);
92     defaultMat.resources[MaterialComponent::TextureIndex::AO].handle =
93         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_AO);
94 
95     defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT].handle =
96         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT);
97     defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT_ROUGHNESS].handle =
98         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT_ROUGHNESS);
99     defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT_NORMAL].handle =
100         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT_NORMAL);
101 
102     defaultMat.resources[MaterialComponent::TextureIndex::SHEEN].handle =
103         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_SHEEN);
104 
105     defaultMat.resources[MaterialComponent::TextureIndex::TRANSMISSION].handle =
106         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_TRANSMISSION);
107 
108     defaultMat.resources[MaterialComponent::TextureIndex::SPECULAR].handle =
109         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_SPECULAR);
110 
111     const RenderHandle samplerHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_REPEAT");
112     for (uint32_t idx = 0; idx < countof(defaultMat.resources); ++idx) {
113         defaultMat.resources[idx].samplerHandle = samplerHandle;
114     }
115 }
116 
GetShadowBufferNodeData(IRenderNodeGpuResourceManager & gpuResourceMgr,const string_view sceneName)117 RenderNodeDefaultMaterialRenderSlot::ShadowBuffers GetShadowBufferNodeData(
118     IRenderNodeGpuResourceManager& gpuResourceMgr, const string_view sceneName)
119 {
120     RenderNodeDefaultMaterialRenderSlot::ShadowBuffers sb;
121     sb.vsmSamplerHandle =
122         gpuResourceMgr.GetSamplerHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_VSM_SHADOW_SAMPLER);
123     sb.pcfSamplerHandle =
124         gpuResourceMgr.GetSamplerHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_PCF_SHADOW_SAMPLER);
125 
126     sb.depthHandle =
127         gpuResourceMgr.GetImageHandle(sceneName + DefaultMaterialLightingConstants::SHADOW_DEPTH_BUFFER_NAME);
128     sb.vsmColorHandle =
129         gpuResourceMgr.GetImageHandle(sceneName + DefaultMaterialLightingConstants::SHADOW_VSM_COLOR_BUFFER_NAME);
130     if (!RenderHandleUtil::IsValid(sb.depthHandle)) {
131         sb.depthHandle = gpuResourceMgr.GetImageHandle("CORE_DEFAULT_GPU_IMAGE_WHITE");
132     }
133     if (!RenderHandleUtil::IsValid(sb.vsmColorHandle)) {
134         sb.vsmColorHandle = gpuResourceMgr.GetImageHandle("CORE_DEFAULT_GPU_IMAGE");
135     }
136 
137     return sb;
138 }
139 
HashShaderDataAndSubmesh(const uint64_t shaderDataHash,const uint32_t renderHash,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags & cameraShaderFlags,const PostProcessConfiguration::PostProcessEnableFlags postProcessFlags)140 inline uint64_t HashShaderDataAndSubmesh(const uint64_t shaderDataHash, const uint32_t renderHash,
141     const IRenderDataStoreDefaultLight::LightingFlags lightingFlags, const RenderCamera::ShaderFlags& cameraShaderFlags,
142     const PostProcessConfiguration::PostProcessEnableFlags postProcessFlags)
143 {
144     const uint32_t ppEnabled = (postProcessFlags > 0);
145     uint64_t hash = ((uint64_t)renderHash & RENDER_HASH_FLAGS_MASK) |
146                     (((uint64_t)lightingFlags << LIGHTING_FLAGS_SHIFT) & LIGHTING_FLAGS_MASK) |
147                     (((uint64_t)ppEnabled << POST_PROCESS_FLAGS_SHIFT) & POST_PROCESS_FLAGS_MASK) |
148                     (((uint64_t)cameraShaderFlags << CAMERA_FLAGS_SHIFT) & CAMERA_FLAGS_MASK);
149     HashCombine(hash, shaderDataHash);
150     return hash;
151 }
152 
IsInverseWinding(const RenderSubmeshFlags submeshFlags,const RenderSceneFlags sceneRenderingFlags,const RenderCamera::Flags cameraRenderingFlags)153 inline bool IsInverseWinding(const RenderSubmeshFlags submeshFlags, const RenderSceneFlags sceneRenderingFlags,
154     const RenderCamera::Flags cameraRenderingFlags)
155 {
156     const bool flipWinding = (sceneRenderingFlags & RENDER_SCENE_FLIP_WINDING_BIT) |
157                              (cameraRenderingFlags & RenderCamera::CAMERA_FLAG_INVERSE_WINDING_BIT);
158     const bool isNegative = flipWinding
159                                 ? !((submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_INVERSE_WINDING_BIT) > 0)
160                                 : ((submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_INVERSE_WINDING_BIT) > 0);
161     return isNegative;
162 }
163 
UpdateCurrentMaterialHandles(const RenderSubmesh & currSubmesh,const RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct & defaultMat,const RenderDataDefaultMaterial::MaterialHandles & currSubmeshHandles,RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct & currMaterialHandles)164 void UpdateCurrentMaterialHandles(const RenderSubmesh& currSubmesh,
165     const RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct& defaultMat,
166     const RenderDataDefaultMaterial::MaterialHandles& currSubmeshHandles,
167     RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct& currMaterialHandles)
168 {
169     for (uint32_t idx = 0; idx < countof(currSubmeshHandles.images); ++idx) {
170         const auto& defaultRes = defaultMat.resources[idx];
171         const auto& srcImage = currSubmeshHandles.images[idx].GetHandle();
172         const auto& srcSampler = currSubmeshHandles.samplers[idx].GetHandle();
173         auto& dst = currMaterialHandles.resources[idx];
174         dst.handle = RenderHandleUtil::IsValid(srcImage) ? srcImage : defaultRes.handle;
175         dst.samplerHandle = RenderHandleUtil::IsValid(srcSampler) ? srcSampler : defaultRes.samplerHandle;
176     }
177 }
178 } // namespace
179 
InitNode(IRenderNodeContextManager & renderNodeContextMgr)180 void RenderNodeDefaultMaterialRenderSlot::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
181 {
182     renderNodeContextMgr_ = &renderNodeContextMgr;
183     ParseRenderNodeInputs();
184 
185     const auto& renderNodeGraphData = renderNodeContextMgr_->GetRenderNodeGraphData();
186     stores_ = RenderNodeSceneUtil::GetSceneRenderDataStores(
187         renderNodeContextMgr, renderNodeGraphData.renderNodeGraphDataStoreName);
188 
189     // reset
190     currentScene_ = {};
191     allShaderData_ = {};
192     objectCounts_ = {};
193 
194     if ((jsonInputs_.nodeFlags & RenderSceneFlagBits::RENDER_SCENE_DIRECT_POST_PROCESS_BIT) &&
195         jsonInputs_.renderDataStore.dataStoreName.empty()) {
196         CORE_LOG_V("%s: render data store post process configuration not set in render node graph",
197             renderNodeContextMgr_->GetName().data());
198     }
199     rngRenderPass_ = renderNodeContextMgr_->GetRenderNodeUtil().CreateRenderPass(inputRenderPass_);
200     CreateDefaultShaderData();
201 
202     auto& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
203     defaultSamplers_.cubemapHandle =
204         gpuResourceMgr.GetSamplerHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_RADIANCE_CUBEMAP_SAMPLER);
205     defaultSamplers_.linearHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_CLAMP");
206     defaultSamplers_.nearestHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_NEAREST_CLAMP");
207     defaultSamplers_.linearMipHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_CLAMP");
208     defaultColorPrePassHandle_ = gpuResourceMgr.GetImageHandle("CORE_DEFAULT_GPU_IMAGE");
209 
210     GetSceneUniformBuffers(stores_.dataStoreNameScene);
211 
212     shadowBuffers_ = GetShadowBufferNodeData(gpuResourceMgr, stores_.dataStoreNameScene);
213 
214     GetDefaultMaterialGpuResources(gpuResourceMgr, defaultMaterialStruct_);
215 }
216 
PreExecuteFrame()217 void RenderNodeDefaultMaterialRenderSlot::PreExecuteFrame()
218 {
219     // re-create needed gpu resources
220     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
221     const IRenderDataStoreDefaultMaterial* dataStoreMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(
222         renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameMaterial));
223     // we need to have all buffers created (reason to have at least 1u)
224     if (dataStoreMaterial) {
225         const auto dsOc = dataStoreMaterial->GetSlotObjectCounts(jsonInputs_.renderSlotId);
226         const ObjectCounts oc {
227             Math::max(dsOc.meshCount, 1u),
228             Math::max(dsOc.submeshCount, 1u),
229             Math::max(dsOc.skinCount, 1u),
230             Math::max(dsOc.materialCount, 1u),
231         };
232         ProcessBuffersAndDescriptors(oc);
233     } else if (objectCounts_.maxSlotMeshCount == 0) {
234         ProcessBuffersAndDescriptors({ 1u, 1u, 1u, 1u });
235     }
236 }
237 
ExecuteFrame(IRenderCommandList & cmdList)238 void RenderNodeDefaultMaterialRenderSlot::ExecuteFrame(IRenderCommandList& cmdList)
239 {
240     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
241     const auto* dataStoreScene =
242         static_cast<IRenderDataStoreDefaultScene*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameScene));
243     const auto* dataStoreMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(
244         renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameMaterial));
245     const auto* dataStoreCamera =
246         static_cast<IRenderDataStoreDefaultCamera*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameCamera));
247     const auto* dataStoreLight =
248         static_cast<IRenderDataStoreDefaultLight*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameLight));
249 
250     const bool validRenderDataStore = dataStoreScene && dataStoreMaterial && dataStoreCamera && dataStoreLight;
251     if (validRenderDataStore) {
252         UpdateCurrentScene(*dataStoreScene, *dataStoreCamera, *dataStoreLight);
253     } else {
254         CORE_LOG_E("invalid render data stores in RenderNodeDefaultMaterialRenderSlot");
255     }
256 
257     cmdList.BeginRenderPass(renderPass_.renderPassDesc, renderPass_.subpassStartIndex, renderPass_.subpassDesc);
258 
259     if (validRenderDataStore) {
260         const auto cameras = dataStoreCamera->GetCameras();
261         const auto scene = dataStoreScene->GetScene();
262 
263         const bool hasShaders = allShaderData_.slotHasShaders;
264         const bool hasCamera =
265             (!cameras.empty() && (currentScene_.cameraIdx < (uint32_t)cameras.size())) ? true : false;
266 
267         ProcessSlotSubmeshes(*dataStoreCamera, *dataStoreMaterial);
268         const bool hasSubmeshes = (!sortedSlotSubmeshes_.empty());
269         if (hasShaders && hasCamera && hasSubmeshes) {
270             UpdatePostProcessConfiguration();
271             RenderSubmeshes(cmdList, *dataStoreMaterial, *dataStoreCamera);
272         }
273     }
274 
275     cmdList.EndRenderPass();
276 }
277 
RenderSubmeshes(IRenderCommandList & cmdList,const IRenderDataStoreDefaultMaterial & dataStoreMaterial,const IRenderDataStoreDefaultCamera & dataStoreCamera)278 void RenderNodeDefaultMaterialRenderSlot::RenderSubmeshes(IRenderCommandList& cmdList,
279     const IRenderDataStoreDefaultMaterial& dataStoreMaterial, const IRenderDataStoreDefaultCamera& dataStoreCamera)
280 {
281     const size_t submeshCount = sortedSlotSubmeshes_.size();
282     CORE_ASSERT(submeshCount <= objectCounts_.maxSlotSubmeshCount);
283 
284     // dynamic state
285     cmdList.SetDynamicStateViewport(currentScene_.viewportDesc);
286     cmdList.SetDynamicStateScissor(currentScene_.scissorDesc);
287     if (fsrEnabled_) {
288         cmdList.SetDynamicStateFragmentShadingRate(
289             { 1u, 1u }, FragmentShadingRateCombinerOps { CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE,
290                             CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE });
291     }
292 
293     // set 0, update camera, general data, and lighting
294     // set 1, update mesh matrices, material data, and skinning data (uses dynamic offset)
295     UpdateSet01(cmdList);
296 
297     // first two sets are only bound for the first submesh (inside for loop)
298     // no bindless, we need to update images per object
299     RenderHandle boundPsoHandle = {};
300     uint64_t boundShaderHash = 0;
301     uint32_t currMaterialIndex = ~0u;
302     MaterialHandleStruct currentMaterialHandles;
303     bool initialBindDone = false; // cannot be checked from the idx
304     bool boundCustomSetNeed = false;
305 
306     const auto& materialHandles = dataStoreMaterial.GetMaterialHandles();
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     for (size_t idx = 0; idx < submeshCount; ++idx) {
312         const auto& ssp = sortedSlotSubmeshes_[idx];
313         const uint32_t submeshIndex = ssp.submeshIndex;
314         const auto& currSubmesh = submeshes[submeshIndex];
315         const auto& currSubmeshMatHandles = materialHandles[currSubmesh.materialIndex];
316         const RenderSubmeshFlags submeshFlags = currSubmesh.submeshFlags | jsonInputs_.nodeSubmeshExtraFlags;
317         auto currMaterialFlags = submeshMaterialFlags[submeshIndex];
318 
319         // sorted slot submeshes should already have removed layers if default sorting was used
320         if (((camLayerMask & currSubmesh.layerMask) == 0) ||
321             ((jsonInputs_.nodeFlags & RENDER_SCENE_DISCARD_MATERIAL_BIT) &&
322                 (currMaterialFlags.extraMaterialRenderingFlags &
323                     RenderExtraRenderingFlagBits::RENDER_EXTRA_RENDERING_DISCARD_BIT))) {
324             continue;
325         }
326 
327         uint32_t renderHash = currMaterialFlags.renderHash;
328         if (!currentScene_.hasShadow) { // remove shadow if not in scene
329             currMaterialFlags.renderMaterialFlags =
330                 currMaterialFlags.renderMaterialFlags & (~RenderMaterialFlagBits::RENDER_MATERIAL_SHADOW_RECEIVER_BIT);
331             renderHash = dataStoreMaterial.GenerateRenderHash(currMaterialFlags);
332         }
333         // get shader and graphics state and start hashing
334         ShaderStateData ssd { ssp.shaderHandle, ssp.gfxStateHandle, 0 };
335         ssd.hash = (ssd.shader.id << 32U) | (ssd.gfxState.id & 0xFFFFffff);
336         // current shader state is fetched for build-in and custom shaders (decision is made later)
337         ssd.hash = HashShaderDataAndSubmesh(ssd.hash, renderHash, currentScene_.lightingFlags,
338             currentScene_.cameraShaderFlags, currentRenderPPConfiguration_.flags.x);
339         if (ssd.hash != boundShaderHash) {
340             const PsoAndInfo psoAndInfo = GetSubmeshPso(
341                 ssd, currMaterialFlags, submeshFlags, currentScene_.lightingFlags, currentScene_.cameraShaderFlags);
342             if (psoAndInfo.pso.id != boundPsoHandle.id) {
343                 boundShaderHash = ssd.hash;
344                 boundPsoHandle = psoAndInfo.pso;
345                 cmdList.BindPipeline(boundPsoHandle);
346                 boundCustomSetNeed = psoAndInfo.set3;
347             }
348         }
349 
350         // bind first set only the first time
351         if (!initialBindDone) {
352             RenderHandle setResourceHandles[2u] { allDescriptorSets_.set01[0u]->GetDescriptorSetHandle(),
353                 allDescriptorSets_.set01[1u]->GetDescriptorSetHandle() };
354             cmdList.BindDescriptorSets(0, { setResourceHandles, 2u });
355         }
356 
357         // set 1 (mesh matrix, skin matrices, material, material user data)
358         const uint32_t currMeshMatrixOffset = currSubmesh.meshIndex * UBO_BIND_OFFSET_ALIGNMENT;
359         const uint32_t currMaterialOffset = currSubmesh.materialIndex * UBO_BIND_OFFSET_ALIGNMENT;
360         const uint32_t currMaterialTransformOffset = currSubmesh.materialIndex * UBO_BIND_OFFSET_ALIGNMENT;
361         const uint32_t currUserMaterialOffset = currSubmesh.materialIndex * UBO_BIND_OFFSET_ALIGNMENT;
362         uint32_t currJointMatrixOffset = 0u;
363         if (submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT) {
364             currJointMatrixOffset =
365                 currSubmesh.skinJointIndex * static_cast<uint32_t>(sizeof(DefaultMaterialSkinStruct));
366         }
367         const uint32_t dynamicOffsets[] = { currMeshMatrixOffset, currJointMatrixOffset, currMaterialOffset,
368             currMaterialTransformOffset, currUserMaterialOffset };
369         // set to bind, handle to resource, offsets for dynamic descs
370         cmdList.BindDescriptorSet(1u, allDescriptorSets_.set01[1u]->GetDescriptorSetHandle(), dynamicOffsets);
371 
372         // update material descriptor set
373         if ((!initialBindDone) || (currMaterialIndex != currSubmesh.materialIndex)) {
374             // the data changes, when the material changes, so we need to rebind the material data
375             UpdateCurrentMaterialHandles(
376                 currSubmesh, defaultMaterialStruct_, currSubmeshMatHandles, currentMaterialHandles);
377             UpdateAndBindSet2(cmdList, currentMaterialHandles, static_cast<uint32_t>(idx));
378             currMaterialIndex = currSubmesh.materialIndex;
379         }
380 
381         initialBindDone = true;
382 
383         // custom set 3 resources
384         if (boundCustomSetNeed) {
385             // if we do not have custom resources, and if we have binding issues we skip
386             if ((!(currSubmesh.customResourcesIndex < static_cast<uint32_t>(customResourceHandles.size()))) ||
387                 (!UpdateAndBindSet3(cmdList, customResourceHandles[currSubmesh.customResourcesIndex]))) {
388                 continue; // we prevent drawing
389             }
390         }
391 
392         // vertex buffers and draw
393         if (currSubmesh.vertexBufferCount > 0) {
394             VertexBuffer vbs[RENDER_NS::PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT];
395             for (uint32_t vbIdx = 0; vbIdx < currSubmesh.vertexBufferCount; ++vbIdx) {
396                 vbs[vbIdx] = ConvertVertexBuffer(currSubmesh.vertexBuffers[vbIdx]);
397             }
398             cmdList.BindVertexBuffers({ vbs, currSubmesh.vertexBufferCount });
399         }
400         const auto& dc = currSubmesh.drawCommand;
401         const RenderVertexBuffer& iArgs = currSubmesh.indirectArgsBuffer;
402         const bool indirectDraw = iArgs.bufferHandle ? true : false;
403         if (currSubmesh.indexBuffer.byteSize > 0U) {
404             cmdList.BindIndexBuffer(ConvertIndexBuffer(currSubmesh.indexBuffer));
405             if (indirectDraw) {
406                 cmdList.DrawIndexedIndirect(iArgs.bufferHandle.GetHandle(), iArgs.bufferOffset, 1u, 0u);
407             } else {
408                 cmdList.DrawIndexed(dc.indexCount, dc.instanceCount, 0, 0, 0);
409             }
410         } else {
411             if (indirectDraw) {
412                 cmdList.DrawIndirect(iArgs.bufferHandle.GetHandle(), iArgs.bufferOffset, 1u, 0u);
413             } else {
414                 cmdList.Draw(dc.vertexCount, dc.instanceCount, 0, 0);
415             }
416         }
417     }
418 }
419 
UpdateSet01(IRenderCommandList & cmdList)420 void RenderNodeDefaultMaterialRenderSlot::UpdateSet01(IRenderCommandList& cmdList)
421 {
422     auto& binder0 = *allDescriptorSets_.set01[0u];
423     auto& binder1 = *allDescriptorSets_.set01[1u];
424     {
425         auto& binder = binder0;
426         uint32_t bindingIndex = 0;
427         binder.BindBuffer(bindingIndex++, sceneBuffers_.camera, 0u);
428         binder.BindBuffer(bindingIndex++, cameraBuffers_.generalData, 0u);
429 
430         const RenderHandle radianceCubemap = currentScene_.cameraEnvRadianceHandle;
431         const RenderHandle colorPrePass = RenderHandleUtil::IsValid(currentScene_.prePassColorTarget)
432                                               ? currentScene_.prePassColorTarget
433                                               : defaultColorPrePassHandle_;
434 
435         binder.BindBuffer(
436             bindingIndex++, { cameraBuffers_.environment, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
437         binder.BindBuffer(bindingIndex++, { cameraBuffers_.fog, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
438         binder.BindBuffer(bindingIndex++, { cameraBuffers_.light, 0u, PipelineStateConstants ::GPU_BUFFER_WHOLE_SIZE });
439         binder.BindBuffer(
440             bindingIndex++, { cameraBuffers_.postProcess, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
441         binder.BindBuffer(
442             bindingIndex++, { cameraBuffers_.lightCluster, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
443         // use immutable samplers for all set 0 samplers
444         BindableImage bi;
445         bi.handle = colorPrePass;
446         bi.samplerHandle = defaultSamplers_.linearMipHandle;
447         binder.BindImage(bindingIndex++, bi, CORE_ADDITIONAL_DESCRIPTOR_IMMUTABLE_SAMPLER_BIT);
448         bi.handle = shadowBuffers_.vsmColorHandle;
449         bi.samplerHandle = shadowBuffers_.vsmSamplerHandle;
450         binder.BindImage(bindingIndex++, bi, CORE_ADDITIONAL_DESCRIPTOR_IMMUTABLE_SAMPLER_BIT);
451         bi.handle = shadowBuffers_.depthHandle;
452         bi.samplerHandle = shadowBuffers_.pcfSamplerHandle;
453         binder.BindImage(bindingIndex++, bi, CORE_ADDITIONAL_DESCRIPTOR_IMMUTABLE_SAMPLER_BIT);
454         bi.handle = radianceCubemap;
455         bi.samplerHandle = defaultSamplers_.cubemapHandle;
456         binder.BindImage(bindingIndex++, bi, CORE_ADDITIONAL_DESCRIPTOR_IMMUTABLE_SAMPLER_BIT);
457     }
458     {
459         auto& binder = binder1;
460         // NOTE: should be PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE or current size
461         constexpr uint32_t skinSize = sizeof(DefaultMaterialSkinStruct);
462         uint32_t bindingIdx = 0u;
463         binder.BindBuffer(bindingIdx++, sceneBuffers_.mesh, 0u, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
464         binder.BindBuffer(bindingIdx++, sceneBuffers_.skinJoint, 0u, skinSize);
465         binder.BindBuffer(bindingIdx++, sceneBuffers_.material, 0, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
466         binder.BindBuffer(
467             bindingIdx++, sceneBuffers_.materialTransform, 0, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
468         binder.BindBuffer(
469             bindingIdx++, sceneBuffers_.materialCustom, 0, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
470     }
471 
472     const RenderHandle handles[] { binder0.GetDescriptorSetHandle(), binder1.GetDescriptorSetHandle() };
473     const DescriptorSetLayoutBindingResources resources[] { binder0.GetDescriptorSetLayoutBindingResources(),
474         binder1.GetDescriptorSetLayoutBindingResources() };
475     cmdList.UpdateDescriptorSets(handles, resources);
476 }
477 
UpdateAndBindSet2(IRenderCommandList & cmdList,const MaterialHandleStruct & materialHandles,const uint32_t objIdx)478 void RenderNodeDefaultMaterialRenderSlot::UpdateAndBindSet2(
479     IRenderCommandList& cmdList, const MaterialHandleStruct& materialHandles, const uint32_t objIdx)
480 {
481     auto& binder = *allDescriptorSets_.sets2[objIdx];
482     uint32_t bindingIdx = 0u;
483 
484     // base color is bound separately to support e.g. gles automatic OES shader modification
485     binder.BindImage(bindingIdx++, materialHandles.resources[MaterialComponent::TextureIndex::BASE_COLOR]);
486 
487     CORE_STATIC_ASSERT(MaterialComponent::TextureIndex::BASE_COLOR == 0);
488     // skip baseColor as it's bound already
489     constexpr size_t theCount = RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT - 1;
490     binder.BindImages(bindingIdx++, array_view(materialHandles.resources + 1, theCount));
491 
492     cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
493     cmdList.BindDescriptorSet(2u, binder.GetDescriptorSetHandle()); // set to bind
494 }
495 
UpdateAndBindSet3(IRenderCommandList & cmdList,const RenderDataDefaultMaterial::CustomResourceData & customResourceData)496 bool RenderNodeDefaultMaterialRenderSlot::UpdateAndBindSet3(
497     IRenderCommandList& cmdList, const RenderDataDefaultMaterial::CustomResourceData& customResourceData)
498 {
499     IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
500     INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
501     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
502 
503     RenderHandle currPlHandle =
504         shaderMgr.GetPipelineLayoutHandleByShaderHandle(customResourceData.shaderHandle.GetHandle());
505     const PipelineLayout& plRef = shaderMgr.GetPipelineLayout(currPlHandle);
506     if (plRef.descriptorSetCount < CUSTOM_SET_DESCRIPTOR_SET_COUNT) {
507         return false; // early out
508     }
509     const auto& descBindings = plRef.descriptorSetLayouts[FIXED_CUSTOM_SET3].bindings;
510     const RenderHandle descSetHandle = descriptorSetMgr.CreateOneFrameDescriptorSet(descBindings);
511     bool valid = false;
512     if (RenderHandleUtil::IsValid(descSetHandle) && (descBindings.size() == customResourceData.resourceHandleCount)) {
513         IDescriptorSetBinder::Ptr binderPtr = descriptorSetMgr.CreateDescriptorSetBinder(descSetHandle, descBindings);
514         if (binderPtr) {
515             auto& binder = *binderPtr;
516             for (uint32_t idx = 0; idx < customResourceData.resourceHandleCount; ++idx) {
517                 CORE_ASSERT(idx < descBindings.size());
518                 const RenderHandle& currRes = customResourceData.resourceHandles[idx].GetHandle();
519                 if (gpuResourceMgr.IsGpuBuffer(currRes)) {
520                     binder.BindBuffer(idx, currRes, 0);
521                 } else if (gpuResourceMgr.IsGpuImage(currRes)) {
522                     if (descBindings[idx].descriptorType ==
523                         DescriptorType::CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
524                         binder.BindImage(idx, currRes, defaultSamplers_.linearMipHandle);
525                     } else {
526                         binder.BindImage(idx, currRes);
527                     }
528                 } else if (gpuResourceMgr.IsGpuSampler(currRes)) {
529                     binder.BindSampler(idx, currRes);
530                 }
531             }
532 
533             // user generated setup, we check for validity of all bindings in the descriptor set
534             if (binder.GetDescriptorSetLayoutBindingValidity()) {
535                 cmdList.UpdateDescriptorSet(
536                     binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
537                 cmdList.BindDescriptorSet(FIXED_CUSTOM_SET3, binder.GetDescriptorSetHandle());
538                 valid = true;
539             }
540         }
541     }
542     if (!valid) {
543 #if (CORE3D_VALIDATION_ENABLED == 1)
544         CORE_LOG_ONCE_W("material_render_slot_custom_set3_issue",
545             "invalid bindings with custom shader descriptor set 3 (render node: %s)",
546             renderNodeContextMgr_->GetName().data());
547 #endif
548     }
549     return valid;
550 }
551 
GetSubmeshPso(const ShaderStateData & ssd,const RenderDataDefaultMaterial::SubmeshMaterialFlags & submeshMaterialFlags,const RenderSubmeshFlags submeshFlags,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags cameraShaderFlags)552 RenderNodeDefaultMaterialRenderSlot::PsoAndInfo RenderNodeDefaultMaterialRenderSlot::GetSubmeshPso(
553     const ShaderStateData& ssd, const RenderDataDefaultMaterial::SubmeshMaterialFlags& submeshMaterialFlags,
554     const RenderSubmeshFlags submeshFlags, const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,
555     const RenderCamera::ShaderFlags cameraShaderFlags)
556 {
557     if (const auto dataIter = allShaderData_.shaderIdToData.find(ssd.hash);
558         dataIter != allShaderData_.shaderIdToData.cend()) {
559         const auto& ref = allShaderData_.perShaderData[dataIter->second];
560         return { ref.psoHandle, ref.needsCustomSetBindings };
561     }
562 
563     return CreateNewPso(ssd, submeshMaterialFlags, submeshFlags, lightingFlags, cameraShaderFlags);
564 }
565 
UpdatePostProcessConfiguration()566 void RenderNodeDefaultMaterialRenderSlot::UpdatePostProcessConfiguration()
567 {
568     if (jsonInputs_.nodeFlags & RenderSceneFlagBits::RENDER_SCENE_DIRECT_POST_PROCESS_BIT) {
569         if (!jsonInputs_.renderDataStore.dataStoreName.empty()) {
570             auto const& dsMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
571             if (const IRenderDataStore* ds = dsMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName); ds) {
572                 if (jsonInputs_.renderDataStore.typeName == POST_PROCESS_DATA_STORE_TYPE_NAME) {
573                     auto const dataStore = static_cast<IRenderDataStorePod const*>(ds);
574                     auto const dataView = dataStore->Get(jsonInputs_.renderDataStore.configurationName);
575                     if (dataView.data() && (dataView.size_bytes() == sizeof(PostProcessConfiguration))) {
576                         const PostProcessConfiguration* data = (const PostProcessConfiguration*)dataView.data();
577                         currentRenderPPConfiguration_ =
578                             renderNodeContextMgr_->GetRenderNodeUtil().GetRenderPostProcessConfiguration(*data);
579                         currentRenderPPConfiguration_.flags.x =
580                             (currentRenderPPConfiguration_.flags.x & POST_PROCESS_IMPORTANT_FLAGS_MASK);
581                     }
582                 }
583             }
584         }
585     }
586 }
587 
UpdateCurrentScene(const IRenderDataStoreDefaultScene & dataStoreScene,const IRenderDataStoreDefaultCamera & dataStoreCamera,const IRenderDataStoreDefaultLight & dataStoreLight)588 void RenderNodeDefaultMaterialRenderSlot::UpdateCurrentScene(const IRenderDataStoreDefaultScene& dataStoreScene,
589     const IRenderDataStoreDefaultCamera& dataStoreCamera, const IRenderDataStoreDefaultLight& dataStoreLight)
590 {
591     if (jsonInputs_.hasChangeableRenderPassHandles) {
592         const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
593         inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
594         rngRenderPass_ = renderNodeContextMgr_->GetRenderNodeUtil().CreateRenderPass(inputRenderPass_);
595     }
596     // get default RNG based render pass setup
597     renderPass_ = rngRenderPass_;
598 
599     const auto scene = dataStoreScene.GetScene();
600     bool hasCustomCamera = false;
601     bool isNamedCamera = false; // NOTE: legacy support will be removed
602     uint32_t cameraIdx = scene.cameraIndex;
603     if (jsonInputs_.customCameraId != INVALID_CAM_ID) {
604         cameraIdx = dataStoreCamera.GetCameraIndex(jsonInputs_.customCameraId);
605         hasCustomCamera = true;
606     } else if (!(jsonInputs_.customCameraName.empty())) {
607         cameraIdx = dataStoreCamera.GetCameraIndex(jsonInputs_.customCameraName);
608         hasCustomCamera = true;
609         isNamedCamera = true;
610     }
611 
612     if (const auto cameras = dataStoreCamera.GetCameras(); cameraIdx < (uint32_t)cameras.size()) {
613         // store current frame camera
614         currentScene_.camera = cameras[cameraIdx];
615     }
616     const auto camHandles = RenderNodeSceneUtil::GetSceneCameraImageHandles(
617         *renderNodeContextMgr_, stores_.dataStoreNameScene, currentScene_.camera.name, currentScene_.camera);
618     currentScene_.cameraEnvRadianceHandle = camHandles.radianceCubemap;
619 
620     if (!currentScene_.camera.prePassColorTargetName.empty()) {
621         currentScene_.prePassColorTarget =
622             renderNodeContextMgr_->GetGpuResourceManager().GetImageHandle(currentScene_.camera.prePassColorTargetName);
623     }
624 
625     // renderpass needs to be valid (created in init)
626     if (hasCustomCamera) {
627         // uses camera based loadOp clear override if given
628         RenderNodeSceneUtil::UpdateRenderPassFromCustomCamera(currentScene_.camera, isNamedCamera, renderPass_);
629     } else {
630         RenderNodeSceneUtil::UpdateRenderPassFromCamera(currentScene_.camera, renderPass_);
631     }
632     currentScene_.viewportDesc = RenderNodeSceneUtil::CreateViewportFromCamera(currentScene_.camera);
633     currentScene_.scissorDesc = RenderNodeSceneUtil::CreateScissorFromCamera(currentScene_.camera);
634 
635     const IRenderDataStoreDefaultLight::LightCounts lightCounts = dataStoreLight.GetLightCounts();
636     currentScene_.hasShadow = (lightCounts.shadowCount > 0) ? true : false;
637     currentScene_.cameraIdx = cameraIdx;
638     currentScene_.shadowTypes = dataStoreLight.GetShadowTypes();
639     currentScene_.lightingFlags = dataStoreLight.GetLightingFlags();
640     currentScene_.cameraShaderFlags = currentScene_.camera.shaderFlags;
641     // remove fog explicitly if render node graph input and/or default render slot usage states so
642     if (jsonInputs_.nodeFlags & RenderSceneFlagBits::RENDER_SCENE_DISABLE_FOG_BIT) {
643         currentScene_.cameraShaderFlags &= (~RenderCamera::ShaderFlagBits::CAMERA_SHADER_FOG_BIT);
644     }
645     // add multi-view flags if needed
646     if (renderPass_.subpassDesc.viewMask > 1U) {
647         ResetRenderSlotData(jsonInputs_.shaderRenderSlotMultiviewId, true);
648     } else {
649         ResetRenderSlotData(jsonInputs_.shaderRenderSlotBaseId, false);
650     }
651 }
652 
CreateDefaultShaderData()653 void RenderNodeDefaultMaterialRenderSlot::CreateDefaultShaderData()
654 {
655     allShaderData_ = {};
656 
657     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
658     allShaderData_.defaultPlHandle =
659         shaderMgr.GetPipelineLayoutHandle(DefaultMaterialShaderConstants::PIPELINE_LAYOUT_FORWARD);
660     allShaderData_.defaultPipelineLayout = shaderMgr.GetPipelineLayout(allShaderData_.defaultPlHandle);
661     allShaderData_.defaultVidHandle =
662         shaderMgr.GetVertexInputDeclarationHandle(DefaultMaterialShaderConstants::VERTEX_INPUT_DECLARATION_FORWARD);
663 
664     {
665         // get the default material shader and default shader state
666         const IShaderManager::RenderSlotData shaderRsd = shaderMgr.GetRenderSlotData(jsonInputs_.shaderRenderSlotId);
667         allShaderData_.defaultShaderHandle = shaderRsd.shader.GetHandle();
668         allShaderData_.defaultStateHandle = shaderRsd.graphicsState.GetHandle();
669         if (shaderMgr.IsShader(allShaderData_.defaultShaderHandle)) {
670             allShaderData_.slotHasShaders = true;
671             const ShaderSpecializationConstantView& sscv =
672                 shaderMgr.GetReflectionSpecialization(allShaderData_.defaultShaderHandle);
673             allShaderData_.defaultSpecilizationConstants.resize(sscv.constants.size());
674             for (uint32_t idx = 0; idx < (uint32_t)allShaderData_.defaultSpecilizationConstants.size(); ++idx) {
675                 allShaderData_.defaultSpecilizationConstants[idx] = sscv.constants[idx];
676             }
677             specializationData_.maxSpecializationCount =
678                 Math::min(static_cast<uint32_t>(allShaderData_.defaultSpecilizationConstants.size()),
679                     SpecializationData::MAX_FLAG_COUNT);
680         } else {
681             CORE_LOG_I("RenderNode: %s, no default shaders for render slot id %u",
682                 renderNodeContextMgr_->GetName().data(), jsonInputs_.shaderRenderSlotId);
683         }
684         if (jsonInputs_.shaderRenderSlotId != jsonInputs_.stateRenderSlotId) {
685             const IShaderManager::RenderSlotData stateRsd = shaderMgr.GetRenderSlotData(jsonInputs_.stateRenderSlotId);
686             if (stateRsd.graphicsState) {
687                 allShaderData_.defaultStateHandle = stateRsd.graphicsState.GetHandle();
688             } else {
689                 CORE_LOG_I("RenderNode: %s, no default state for render slot id %u",
690                     renderNodeContextMgr_->GetName().data(), jsonInputs_.stateRenderSlotId);
691             }
692         }
693     }
694 }
695 
GetSceneUniformBuffers(const string_view us)696 void RenderNodeDefaultMaterialRenderSlot::GetSceneUniformBuffers(const string_view us)
697 {
698     sceneBuffers_ = RenderNodeSceneUtil::GetSceneBufferHandles(*renderNodeContextMgr_, stores_.dataStoreNameScene);
699 
700     string camName;
701     if (jsonInputs_.customCameraId != INVALID_CAM_ID) {
702         camName = to_string(jsonInputs_.customCameraId);
703     } else if (!(jsonInputs_.customCameraName.empty())) {
704         camName = jsonInputs_.customCameraName;
705     }
706     cameraBuffers_ =
707         RenderNodeSceneUtil::GetSceneCameraBufferHandles(*renderNodeContextMgr_, stores_.dataStoreNameScene, camName);
708 }
709 
CreateNewPso(const ShaderStateData & ssd,const RenderDataDefaultMaterial::SubmeshMaterialFlags & submeshMaterialFlags,const RenderSubmeshFlags submeshFlags,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags cameraShaderFlags)710 RenderNodeDefaultMaterialRenderSlot::PsoAndInfo RenderNodeDefaultMaterialRenderSlot::CreateNewPso(
711     const ShaderStateData& ssd, const RenderDataDefaultMaterial::SubmeshMaterialFlags& submeshMaterialFlags,
712     const RenderSubmeshFlags submeshFlags, const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,
713     const RenderCamera::ShaderFlags cameraShaderFlags)
714 {
715     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
716     // NOTE: The easiest route would be to input shader and graphics state to material component
717     RenderHandle currShader;
718     RenderHandle currPl;
719     RenderHandle currVid;
720     RenderHandle currState;
721     // first try to find matching shader
722     if (RenderHandleUtil::GetHandleType(ssd.shader) == RenderHandleType::SHADER_STATE_OBJECT) {
723         // we force the given shader if explicit shader render slot is not given
724         if (!jsonInputs_.explicitShader) {
725             currShader = ssd.shader;
726         }
727         const RenderHandle slotShader = shaderMgr.GetShaderHandle(ssd.shader, jsonInputs_.shaderRenderSlotId);
728         if (RenderHandleUtil::IsValid(slotShader)) {
729             currShader = slotShader; // override with render slot variant
730         }
731         // if not explicit gfx state given, check if shader has graphics state for this slot
732         if (!RenderHandleUtil::IsValid(ssd.gfxState)) {
733             const auto gfxStateHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(currShader);
734             if (shaderMgr.GetRenderSlotId(gfxStateHandle) == jsonInputs_.stateRenderSlotId) {
735                 currState = gfxStateHandle;
736             }
737         }
738         currVid = shaderMgr.GetVertexInputDeclarationHandleByShaderHandle(currShader);
739         currPl = shaderMgr.GetPipelineLayoutHandleByShaderHandle(currShader);
740     }
741     if (RenderHandleUtil::GetHandleType(ssd.gfxState) == RenderHandleType::GRAPHICS_STATE) {
742         const RenderHandle slotState = shaderMgr.GetGraphicsStateHandle(ssd.gfxState, jsonInputs_.stateRenderSlotId);
743         if (RenderHandleUtil::IsValid(slotState)) {
744             currState = slotState;
745         }
746     }
747 
748     // NOTE: the pipeline layout compatibility should be checked
749 
750     // fallback to defaults if needed
751     currShader = RenderHandleUtil::IsValid(currShader) ? currShader : allShaderData_.defaultShaderHandle;
752     currPl = RenderHandleUtil::IsValid(currPl) ? currPl : allShaderData_.defaultPlHandle;
753     currVid = RenderHandleUtil::IsValid(currVid) ? currVid : allShaderData_.defaultVidHandle;
754     currState = RenderHandleUtil::IsValid(currState) ? currState : allShaderData_.defaultStateHandle;
755 
756     auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
757     RenderHandle psoHandle;
758     if (IsInverseWinding(submeshFlags, jsonInputs_.nodeFlags, currentScene_.camera.flags)) {
759         // we create a new graphics state with inverse winding
760         GraphicsState gfxState = shaderMgr.GetGraphicsState(currState);
761         gfxState.rasterizationState.frontFace = FrontFace::CORE_FRONT_FACE_CLOCKWISE;
762         const auto spec =
763             GetShaderSpecializationView(gfxState, submeshMaterialFlags, submeshFlags, lightingFlags, cameraShaderFlags);
764         psoHandle = psoMgr.GetGraphicsPsoHandle(currShader, gfxState, shaderMgr.GetPipelineLayout(currPl),
765             shaderMgr.GetVertexInputDeclarationView(currVid), spec, GetDynamicStates());
766     } else {
767         const GraphicsState& gfxState = shaderMgr.GetGraphicsState(currState);
768         const auto spec =
769             GetShaderSpecializationView(gfxState, submeshMaterialFlags, submeshFlags, lightingFlags, cameraShaderFlags);
770         psoHandle = psoMgr.GetGraphicsPsoHandle(currShader, currState, currPl, currVid, spec, GetDynamicStates());
771     }
772     const bool needsCustomSet =
773         shaderMgr.GetPipelineLayout(currPl).descriptorSetCount == CUSTOM_SET_DESCRIPTOR_SET_COUNT;
774 
775     allShaderData_.perShaderData.push_back(PerShaderData { currShader, psoHandle, currState, needsCustomSet });
776     allShaderData_.shaderIdToData[ssd.hash] = (uint32_t)allShaderData_.perShaderData.size() - 1;
777     return { psoHandle, needsCustomSet };
778 }
779 
GetShaderSpecializationView(const RENDER_NS::GraphicsState & gfxState,const RenderDataDefaultMaterial::SubmeshMaterialFlags & submeshMaterialFlags,const RenderSubmeshFlags submeshFlags,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags cameraShaderFlags)780 ShaderSpecializationConstantDataView RenderNodeDefaultMaterialRenderSlot::GetShaderSpecializationView(
781     const RENDER_NS::GraphicsState& gfxState,
782     const RenderDataDefaultMaterial::SubmeshMaterialFlags& submeshMaterialFlags, const RenderSubmeshFlags submeshFlags,
783     const IRenderDataStoreDefaultLight::LightingFlags lightingFlags, const RenderCamera::ShaderFlags cameraShaderFlags)
784 {
785     RenderMaterialFlags combinedMaterialFlags = submeshMaterialFlags.renderMaterialFlags;
786     if (gfxState.colorBlendState.colorAttachmentCount > 0) {
787         // enable opaque flag if blending is not enabled with the first color attachment
788         combinedMaterialFlags |= (gfxState.colorBlendState.colorAttachments[0].enableBlend)
789                                      ? 0u
790                                      : RenderMaterialFlagBits::RENDER_MATERIAL_OPAQUE_BIT;
791     }
792     for (uint32_t idx = 0; idx < specializationData_.maxSpecializationCount; ++idx) {
793         const auto& ref = allShaderData_.defaultSpecilizationConstants[idx];
794         const uint32_t constantId = ref.offset / sizeof(uint32_t);
795 
796         // NOTE: vertex and fragment have different specializations for the zero index
797         if (ref.shaderStage == ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT) {
798             if (ref.id == 0u) {
799                 specializationData_.flags[constantId] = submeshFlags;
800             } else if (ref.id == 1u) {
801                 specializationData_.flags[constantId] = combinedMaterialFlags;
802             }
803         } else if (ref.shaderStage == ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT) {
804             if (ref.id == 0u) {
805                 specializationData_.flags[constantId] = static_cast<uint32_t>(submeshMaterialFlags.materialType);
806             } else if (ref.id == 1u) {
807                 specializationData_.flags[constantId] = combinedMaterialFlags;
808             } else if (ref.id == 2u) {
809                 specializationData_.flags[constantId] = lightingFlags;
810             } else if (ref.id == 3u) {
811                 specializationData_.flags[constantId] = currentRenderPPConfiguration_.flags.x;
812             } else if (ref.id == 4u) {
813                 specializationData_.flags[constantId] = cameraShaderFlags;
814             }
815         }
816     }
817 
818     return { { allShaderData_.defaultSpecilizationConstants.data(), specializationData_.maxSpecializationCount },
819         { specializationData_.flags, specializationData_.maxSpecializationCount } };
820 }
821 
ProcessBuffersAndDescriptors(const ObjectCounts & objectCounts)822 void RenderNodeDefaultMaterialRenderSlot::ProcessBuffersAndDescriptors(const ObjectCounts& objectCounts)
823 {
824     constexpr uint32_t overEstimate { 16u };
825     bool updateDescriptorSets = false;
826     if (objectCounts_.maxSlotMeshCount < objectCounts.maxSlotMeshCount) {
827         updateDescriptorSets = true;
828         objectCounts_.maxSlotMeshCount = objectCounts.maxSlotMeshCount + (objectCounts.maxSlotMeshCount / overEstimate);
829     }
830     if (objectCounts_.maxSlotSkinCount < objectCounts.maxSlotSkinCount) {
831         updateDescriptorSets = true;
832         objectCounts_.maxSlotSkinCount = objectCounts.maxSlotSkinCount + (objectCounts.maxSlotSkinCount / overEstimate);
833     }
834     if (objectCounts_.maxSlotSubmeshCount < objectCounts.maxSlotSubmeshCount) {
835         updateDescriptorSets = true;
836         objectCounts_.maxSlotSubmeshCount =
837             objectCounts.maxSlotSubmeshCount + (objectCounts.maxSlotSubmeshCount / overEstimate);
838     }
839 
840     if (updateDescriptorSets) {
841         ResetAndUpdateDescriptorSets();
842     }
843 }
844 
ResetAndUpdateDescriptorSets()845 void RenderNodeDefaultMaterialRenderSlot::ResetAndUpdateDescriptorSets()
846 {
847     INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
848     // known and calculated (could run through descriptorsets and calculate automatically as well)
849     const DescriptorCounts dc { {
850         // camera + general data + post process + 3 light buffers + (mat + mat user data) * objectCount
851         { CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 6u },
852         // light cluster
853         { CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u },
854         // mesh and material data
855         { CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 5u },
856         // set0 (4) + per submesh material images
857         { CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
858             4u + objectCounts_.maxSlotSubmeshCount * RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT },
859     } };
860     descriptorSetMgr.ResetAndReserve(dc);
861 
862     for (uint32_t setIdx = 0; setIdx < AllDescriptorSets::SINGLE_SET_COUNT; ++setIdx) {
863         const RenderHandle descriptorSetHandle =
864             descriptorSetMgr.CreateDescriptorSet(setIdx, allShaderData_.defaultPipelineLayout);
865         allDescriptorSets_.set01[setIdx] = descriptorSetMgr.CreateDescriptorSetBinder(
866             descriptorSetHandle, allShaderData_.defaultPipelineLayout.descriptorSetLayouts[setIdx].bindings);
867     }
868     {
869         const uint32_t set = 2u;
870         allDescriptorSets_.sets2.clear();
871         allDescriptorSets_.sets2.resize(objectCounts_.maxSlotSubmeshCount);
872         for (uint32_t idx = 0; idx < objectCounts_.maxSlotSubmeshCount; ++idx) {
873             const RenderHandle descriptorSetHandle =
874                 descriptorSetMgr.CreateDescriptorSet(set, allShaderData_.defaultPipelineLayout);
875             allDescriptorSets_.sets2[idx] = descriptorSetMgr.CreateDescriptorSetBinder(
876                 descriptorSetHandle, allShaderData_.defaultPipelineLayout.descriptorSetLayouts[set].bindings);
877         }
878     }
879 }
880 
ProcessSlotSubmeshes(const IRenderDataStoreDefaultCamera & dataStoreCamera,const IRenderDataStoreDefaultMaterial & dataStoreMaterial)881 void RenderNodeDefaultMaterialRenderSlot::ProcessSlotSubmeshes(
882     const IRenderDataStoreDefaultCamera& dataStoreCamera, const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
883 {
884     // currentScene has been updated prior, has the correct camera (scene camera or custom camera)
885     const IRenderNodeSceneUtil::RenderSlotInfo rsi { jsonInputs_.renderSlotId, jsonInputs_.sortType,
886         jsonInputs_.cullType, jsonInputs_.nodeMaterialDiscardFlags };
887     RenderNodeSceneUtil::GetRenderSlotSubmeshes(
888         dataStoreCamera, dataStoreMaterial, currentScene_.cameraIdx, rsi, sortedSlotSubmeshes_);
889 }
890 
GetDynamicStates() const891 array_view<const DynamicStateEnum> RenderNodeDefaultMaterialRenderSlot::GetDynamicStates() const
892 {
893     if (fsrEnabled_) {
894         return { DYNAMIC_STATES_FSR, countof(DYNAMIC_STATES_FSR) };
895     } else {
896         return { DYNAMIC_STATES, countof(DYNAMIC_STATES) };
897     }
898 }
899 
ParseRenderNodeInputs()900 void RenderNodeDefaultMaterialRenderSlot::ParseRenderNodeInputs()
901 {
902     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
903     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
904     jsonInputs_.renderPass = parserUtil.GetInputRenderPass(jsonVal, "renderPass");
905     jsonInputs_.customCameraName = parserUtil.GetStringValue(jsonVal, "customCameraName");
906     jsonInputs_.customCameraId = parserUtil.GetUintValue(jsonVal, "customCameraId");
907     jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
908 
909     jsonInputs_.sortType = parserUtil.GetRenderSlotSortType(jsonVal, "renderSlotSortType");
910     jsonInputs_.cullType = parserUtil.GetRenderSlotCullType(jsonVal, "renderSlotCullType");
911     jsonInputs_.nodeFlags = static_cast<uint32_t>(parserUtil.GetUintValue(jsonVal, "nodeFlags"));
912     if (jsonInputs_.nodeFlags == ~0u) {
913         jsonInputs_.nodeFlags = 0;
914     }
915     jsonInputs_.nodeMaterialDiscardFlags =
916         static_cast<uint32_t>(parserUtil.GetUintValue(jsonVal, "nodeMaterialDiscardFlags"));
917     if (jsonInputs_.nodeMaterialDiscardFlags == ~0u) {
918         jsonInputs_.nodeMaterialDiscardFlags = 0;
919     }
920     // automatic default material velocity named target based parsing to add velocity calculations bit
921     for (const auto& ref : jsonInputs_.renderPass.attachments) {
922         if (ref.name == DefaultMaterialRenderNodeConstants::CORE_DM_CAMERA_VELOCITY_NORMAL) {
923             jsonInputs_.nodeSubmeshExtraFlags |= RenderSubmeshFlagBits::RENDER_SUBMESH_VELOCITY_BIT;
924         }
925     }
926 
927     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
928     const string renderSlot = parserUtil.GetStringValue(jsonVal, "renderSlot");
929     jsonInputs_.renderSlotId = shaderMgr.GetRenderSlotId(renderSlot);
930     jsonInputs_.shaderRenderSlotId = jsonInputs_.renderSlotId;
931     jsonInputs_.stateRenderSlotId = jsonInputs_.renderSlotId;
932     const string shaderRenderSlot = parserUtil.GetStringValue(jsonVal, "shaderRenderSlot");
933     if (!shaderRenderSlot.empty()) {
934         const uint32_t renderSlotId = shaderMgr.GetRenderSlotId(shaderRenderSlot);
935         if (renderSlotId != ~0U) {
936             jsonInputs_.shaderRenderSlotId = renderSlotId;
937             jsonInputs_.initialExplicitShader = true;
938             jsonInputs_.explicitShader = true;
939         }
940     }
941     jsonInputs_.shaderRenderSlotBaseId = jsonInputs_.shaderRenderSlotId;
942     const string stateRenderSlot = parserUtil.GetStringValue(jsonVal, "stateRenderSlot");
943     if (!stateRenderSlot.empty()) {
944         const uint32_t renderSlotId = shaderMgr.GetRenderSlotId(stateRenderSlot);
945         jsonInputs_.stateRenderSlotId = (renderSlotId != ~0U) ? renderSlotId : jsonInputs_.renderSlotId;
946     }
947     const string shaderMultiviewRenderSlot = parserUtil.GetStringValue(jsonVal, "shaderMultiviewRenderSlot");
948     if (!shaderMultiviewRenderSlot.empty()) {
949         jsonInputs_.shaderRenderSlotMultiviewId = shaderMgr.GetRenderSlotId(shaderMultiviewRenderSlot);
950     }
951 
952     EvaluateFogBits();
953 
954     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
955     inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
956     if ((inputRenderPass_.fragmentShadingRateAttachmentIndex < inputRenderPass_.attachments.size()) &&
957         RenderHandleUtil::IsValid(
958             inputRenderPass_.attachments[inputRenderPass_.fragmentShadingRateAttachmentIndex].handle)) {
959         fsrEnabled_ = true;
960     }
961     jsonInputs_.hasChangeableRenderPassHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.renderPass);
962 }
963 
ResetRenderSlotData(const uint32_t shaderRenderSlotId,const bool multiView)964 void RenderNodeDefaultMaterialRenderSlot::ResetRenderSlotData(const uint32_t shaderRenderSlotId, const bool multiView)
965 {
966     // can be reset to multi-view usage or reset back to default usage
967     if (shaderRenderSlotId != jsonInputs_.shaderRenderSlotId) {
968         jsonInputs_.shaderRenderSlotId = shaderRenderSlotId;
969         jsonInputs_.explicitShader = jsonInputs_.initialExplicitShader || multiView;
970         // reset
971         CreateDefaultShaderData();
972     }
973 }
974 
EvaluateFogBits()975 void RenderNodeDefaultMaterialRenderSlot::EvaluateFogBits()
976 {
977     // if no explicit bits set we check default render slot usages
978     if ((jsonInputs_.nodeFlags & (RENDER_SCENE_ENABLE_FOG_BIT | RENDER_SCENE_DISABLE_FOG_BIT)) == 0) {
979         // check default render slots
980         const uint32_t opaqueSlotId = renderNodeContextMgr_->GetShaderManager().GetRenderSlotId(
981             DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE);
982         const uint32_t translucentSlotId = renderNodeContextMgr_->GetShaderManager().GetRenderSlotId(
983             DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT);
984         if ((jsonInputs_.renderSlotId == opaqueSlotId) || (jsonInputs_.renderSlotId == translucentSlotId)) {
985             jsonInputs_.nodeFlags |= RenderSceneFlagBits::RENDER_SCENE_ENABLE_FOG_BIT;
986         }
987     }
988 }
989 
990 // for plugin / factory interface
Create()991 RENDER_NS::IRenderNode* RenderNodeDefaultMaterialRenderSlot::Create()
992 {
993     return new RenderNodeDefaultMaterialRenderSlot();
994 }
995 
Destroy(IRenderNode * instance)996 void RenderNodeDefaultMaterialRenderSlot::Destroy(IRenderNode* instance)
997 {
998     delete static_cast<RenderNodeDefaultMaterialRenderSlot*>(instance);
999 }
1000 CORE3D_END_NAMESPACE()
1001