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