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