• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "util/render_util.h"
17 
18 #include <algorithm>
19 
20 #include <3d/intf_graphics_context.h>
21 #include <3d/render/intf_render_data_store_default_camera.h>
22 #include <core/intf_engine.h>
23 #include <core/json/json.h>
24 #include <core/namespace.h>
25 #include <render/device/intf_device.h>
26 #include <render/device/intf_gpu_resource_manager.h>
27 #include <render/intf_plugin.h>
28 #include <render/intf_render_context.h>
29 #include <render/render_data_structures.h>
30 
31 CORE3D_BEGIN_NAMESPACE()
32 using namespace BASE_NS;
33 using namespace CORE_NS;
34 using namespace RENDER_NS;
35 
36 namespace {
37 constexpr const string_view SCENE_STR = "3drendernodegraphs://core3d_rng_scene.rng";
38 constexpr const string_view CAM_SCENE_LWRP_STR = "3drendernodegraphs://core3d_rng_cam_scene_lwrp.rng";
39 constexpr const string_view CAM_SCENE_LWRP_MSAA_STR = "3drendernodegraphs://core3d_rng_cam_scene_lwrp_msaa.rng";
40 constexpr const string_view CAM_SCENE_LWRP_MSAA_DEPTH_STR =
41     "3drendernodegraphs://core3d_rng_cam_scene_lwrp_msaa_depth.rng";
42 constexpr const string_view CAM_SCENE_LWRP_MSAA_GLES_STR =
43     "3drendernodegraphs://core3d_rng_cam_scene_lwrp_msaa_gles.rng";
44 constexpr const string_view CAM_SCENE_HDRP_STR = "3drendernodegraphs://core3d_rng_cam_scene_hdrp.rng";
45 constexpr const string_view CAM_SCENE_HDRP_MSAA_STR = "3drendernodegraphs://core3d_rng_cam_scene_hdrp_msaa.rng";
46 constexpr const string_view CAM_SCENE_HDRP_MSAA_DEPTH_STR =
47     "3drendernodegraphs://core3d_rng_cam_scene_hdrp_msaa_depth.rng";
48 constexpr const string_view CAM_SCENE_REFLECTION_STR = "3drendernodegraphs://core3d_rng_reflection_cam_scene.rng";
49 constexpr const string_view CAM_SCENE_REFLECTION_MSAA_STR =
50     "3drendernodegraphs://core3d_rng_reflection_cam_scene_msaa.rng";
51 constexpr const string_view CAM_SCENE_PRE_PASS_STR = "3drendernodegraphs://core3d_rng_cam_scene_pre_pass.rng";
52 constexpr const string_view CAM_SCENE_DEFERRED_STR = "3drendernodegraphs://core3d_rng_cam_scene_deferred.rng";
53 constexpr const string_view CAM_SCENE_POST_PROCESS_STR = "3drendernodegraphs://core3d_rng_cam_scene_post_process.rng";
54 
55 constexpr const string_view RENDER_NODE_DEFAULT_CAMERA_CONTROLLER_STR = "RenderNodeDefaultCameraController";
56 constexpr const string_view RENDER_NODE_DEFAULT_MATERIAL_RENDER_SLOT_STR = "RenderNodeDefaultMaterialRenderSlot";
57 constexpr const string_view RENDER_NODE_CAMERA_WEATHER_STR = "RenderNodeCameraWeather";
58 
59 constexpr bool ENABLE_WEATHER_INJECT { true };
60 
LoadRenderNodeGraph(IRenderNodeGraphLoader & rngLoader,const string_view rng)61 RenderNodeGraphDesc LoadRenderNodeGraph(IRenderNodeGraphLoader& rngLoader, const string_view rng)
62 {
63     IRenderNodeGraphLoader::LoadResult lr = rngLoader.Load(rng);
64     if (!lr.success) {
65         CORE_LOG_E("error loading render node graph: %s - error: %s", rng.data(), lr.error.data());
66     }
67     return lr.desc;
68 }
69 
GetDefaultCameraControllerNode()70 inline RenderNodeDesc GetDefaultCameraControllerNode()
71 {
72     RenderNodeDesc rnd;
73     rnd.typeName = RENDER_NODE_DEFAULT_CAMERA_CONTROLLER_STR;
74     rnd.nodeName = "CORE3D_RN_CAM_CTRL";
75     rnd.nodeJson = "{\"typeName\" : \"RenderNodeDefaultCameraController\",\"nodeName\" : \"CORE3D_RN_CAM_CTRL\"}";
76     return rnd;
77 }
78 
GetDefaultCameraCloudsNode()79 inline RenderNodeDesc GetDefaultCameraCloudsNode()
80 {
81     RenderNodeDesc rnd;
82     rnd.typeName = RENDER_NODE_CAMERA_WEATHER_STR;
83     rnd.nodeName = "CORE3D_RN_CAM_WEATHER";
84     rnd.nodeJson = "{\"typeName\" : \"RenderNodeCameraWeather\",\"nodeName\" : \"CORE3D_RN_CAM_WEATHER\"}";
85     return rnd;
86 }
87 
GetPodPostProcess(const string_view name)88 inline json::standalone_value GetPodPostProcess(const string_view name)
89 {
90     auto renderDataStore = json::standalone_value { json::standalone_value::object {} };
91     renderDataStore["dataStoreName"] = "RenderDataStorePod";
92     renderDataStore["typeName"] = "RenderDataStorePod"; // This is render data store TYPE_NAME
93     renderDataStore["configurationName"] = string(name);
94     return renderDataStore;
95 }
96 
GetPostProcess(const string_view name)97 inline json::standalone_value GetPostProcess(const string_view name)
98 {
99     auto renderDataStore = json::standalone_value { json::standalone_value::object {} };
100     renderDataStore["dataStoreName"] = "RenderDataStorePostProcess";
101     renderDataStore["typeName"] = "RenderDataStorePostProcess"; // This is render data store TYPE_NAME
102     renderDataStore["configurationName"] = string(name);
103     return renderDataStore;
104 }
105 
HasRenderDataStorePostProcess(const json::standalone_value & dataStore)106 inline bool HasRenderDataStorePostProcess(const json::standalone_value& dataStore)
107 {
108     if (const auto typeName = dataStore.find("typeName"); typeName) {
109         if (typeName->is_string() && (typeName->string_ == "RenderDataStorePostProcess")) {
110             return true;
111         }
112     }
113     return false;
114 }
115 
GetCameraName(const RenderCamera & camera)116 inline string GetCameraName(const RenderCamera& camera)
117 {
118     return camera.name.empty() ? string(to_hex(camera.id)) : string(camera.name);
119 }
120 
GetSceneName(const RenderScene & scene)121 inline string GetSceneName(const RenderScene& scene)
122 {
123     return scene.name.empty() ? string(to_hex(scene.id)) : string(scene.name);
124 }
125 
GetRenderNodesWithDependencies()126 vector<const RENDER_NS::RenderNodeTypeInfo*> GetRenderNodesWithDependencies()
127 {
128     // Gather RenderNodeTypeInfo which have after of before dependencies.
129     vector<const RENDER_NS::RenderNodeTypeInfo*> renderNodesWithDependencies;
130     auto typeInfos = CORE_NS::GetPluginRegister().GetTypeInfos(RENDER_NS::RenderNodeTypeInfo::UID);
131     for (auto* info : typeInfos) {
132         if (info && (info->typeUid == RenderNodeTypeInfo::UID)) {
133             auto* renderNodeTypeInfo = static_cast<const RenderNodeTypeInfo*>(info);
134             if ((renderNodeTypeInfo->afterNode != Uid {}) || (renderNodeTypeInfo->beforeNode != Uid {})) {
135                 renderNodesWithDependencies.push_back(renderNodeTypeInfo);
136             }
137         }
138     }
139     return renderNodesWithDependencies;
140 }
141 
InjectRenderNodes(RenderNodeGraphDesc & desc)142 void InjectRenderNodes(RenderNodeGraphDesc& desc)
143 {
144     const auto typeInfos = CORE_NS::GetPluginRegister().GetTypeInfos(RENDER_NS::RenderNodeTypeInfo::UID);
145     const auto renderNodeTypeInfos =
146         array_view(reinterpret_cast<const RenderNodeTypeInfo* const*>(typeInfos.data()), typeInfos.size());
147     const auto renderNodesWithDependencies = GetRenderNodesWithDependencies();
148     for (const auto* depending : renderNodesWithDependencies) {
149         // Try adding only if node isn't already there.
150         if (std::any_of(desc.nodes.cbegin(), desc.nodes.cend(),
151                 [typeName = depending->typeName](const RenderNodeDesc& desc) { return desc.typeName == typeName; })) {
152             continue;
153         }
154 
155         ptrdiff_t index = -1;
156 
157         // Find the insertion index based on afterNode
158         if (depending->afterNode != Uid {}) {
159             // Find the typeinfo of the dependency UID
160             auto info = std::find_if(renderNodeTypeInfos.cbegin(), renderNodeTypeInfos.cend(),
161                 [uid = depending->afterNode](const RenderNodeTypeInfo* info) { return info->uid == uid; });
162             if (info != renderNodeTypeInfos.cend()) {
163                 // Find the last instance matching dependency typeName
164                 auto graphIt = std::find_if(desc.nodes.crbegin(), desc.nodes.crend(),
165                     [typeName = (*info)->typeName](const RenderNodeDesc& desc) { return desc.typeName == typeName; });
166                 if (graphIt != desc.nodes.crend()) {
167                     index = graphIt.base() - desc.nodes.cbegin();
168                 }
169             }
170         }
171 
172         // Find the insertion index based on beforeNode
173         if (depending->beforeNode != Uid {}) {
174             // Find the typeinfo of the dependency UID
175             auto info = std::find_if(renderNodeTypeInfos.cbegin(), renderNodeTypeInfos.cend(),
176                 [uid = depending->beforeNode](const RenderNodeTypeInfo* info) { return info->uid == uid; });
177             if (info != renderNodeTypeInfos.cend()) {
178                 // Find the last instance matching dependency typeName
179                 auto graphIt = std::find_if(desc.nodes.crbegin(), desc.nodes.crend(),
180                     [typeName = (*info)->typeName](const RenderNodeDesc& desc) { return desc.typeName == typeName; });
181                 if (graphIt != desc.nodes.crend()) {
182                     index = graphIt.base() - desc.nodes.cbegin();
183                 }
184             }
185         }
186 
187         // If no valid index found, continue to the next node
188         if (index < 0 || size_t(index) > desc.nodes.size()) {
189             continue;
190         }
191 
192         // Create the new render node descriptor
193         json::standalone_value jsonVal(json::standalone_value::object {});
194         jsonVal["typeName"] = depending->typeName;
195         auto nodeName = RenderDataConstants::RenderDataFixedString("CORE3D_RN_SCENE_") + depending->typeName;
196         jsonVal["nodeName"] = nodeName.data();
197         desc.nodes.insert(
198             desc.nodes.cbegin() + index, RenderNodeDesc { depending->typeName, nodeName, {}, to_string(jsonVal) });
199     }
200 }
201 
FillCameraDescsData(const RenderCamera & renderCamera,const string & customCameraName,RenderNodeGraphDesc & desc)202 void FillCameraDescsData(const RenderCamera& renderCamera, const string& customCameraName, RenderNodeGraphDesc& desc)
203 {
204     // check for render compatibility for render node graph RenderNodeDefaultCameraController
205     if (!renderCamera.customRenderNodeGraphFile.empty()) {
206         bool forceInject = true;
207         for (const auto& rnRef : desc.nodes) {
208             if (rnRef.typeName == RENDER_NODE_DEFAULT_CAMERA_CONTROLLER_STR) {
209                 forceInject = false;
210                 break;
211             }
212         }
213         if (forceInject) {
214             for (size_t nodeIdx = 0; nodeIdx < desc.nodes.size(); ++nodeIdx) {
215                 if (desc.nodes[nodeIdx].typeName == RENDER_NODE_DEFAULT_MATERIAL_RENDER_SLOT_STR) {
216                     desc.nodes.insert(desc.nodes.begin() + int64_t(nodeIdx), GetDefaultCameraControllerNode());
217 #if (CORE3D_DEV_ENABLED == 1)
218                     CORE_LOG_W("Injecting camera RenderNodeDefaultCameraController render node for compatibility");
219 #endif
220                     break;
221                 }
222             }
223         }
224     }
225 
226     // inject camera weather effect render node (for e.g. clouds) after camera controller
227     if constexpr (ENABLE_WEATHER_INJECT) {
228         if (renderCamera.environment.flags & RenderCamera::Environment::ENVIRONMENT_FLAG_CAMERA_WEATHER_BIT) {
229             for (size_t nodeIdx = 0; nodeIdx < desc.nodes.size(); ++nodeIdx) {
230                 if (desc.nodes[nodeIdx].typeName == RENDER_NODE_DEFAULT_CAMERA_CONTROLLER_STR) {
231                     desc.nodes.insert(desc.nodes.begin() + int64_t(nodeIdx + 1), GetDefaultCameraCloudsNode());
232 #if (CORE3D_DEV_ENABLED == 1)
233                     CORE_LOG_I("Injecting camera RenderNodeCameraWeather render node");
234 #endif
235                     break;
236                 }
237             }
238         }
239     }
240     InjectRenderNodes(desc);
241 
242     for (auto& rnRef : desc.nodes) {
243         json::standalone_value jsonVal = CORE_NS::json::parse(rnRef.nodeJson.data());
244         jsonVal["customCameraId"] = renderCamera.id; // cam id
245         jsonVal["customCameraName"] = customCameraName;
246         if (renderCamera.flags & RenderCamera::CAMERA_FLAG_REFLECTION_BIT) {
247             jsonVal["nodeFlags"] = 7u; // NOTE: hard coded
248         }
249         if (auto dataStore = jsonVal.find("renderDataStore"); dataStore) {
250             if (auto config = dataStore->find("configurationName"); config) {
251                 if (!config->string_.empty()) {
252                     const bool rpp = HasRenderDataStorePostProcess(*dataStore);
253                     auto renderDataStore = rpp ? GetPostProcess(renderCamera.postProcessName)
254                                                : GetPodPostProcess(renderCamera.postProcessName);
255                     jsonVal["renderDataStore"] = move(renderDataStore);
256                 }
257             }
258         }
259         rnRef.nodeJson = to_string(jsonVal);
260     }
261 }
262 
FillCameraPostProcessDescsData(const RenderCamera & renderCamera,const uint64_t baseCameraId,const string & customCameraName,const bool customPostProcess,RenderNodeGraphDesc & desc)263 void FillCameraPostProcessDescsData(const RenderCamera& renderCamera, const uint64_t baseCameraId,
264     const string& customCameraName, const bool customPostProcess, RenderNodeGraphDesc& desc)
265 {
266     InjectRenderNodes(desc);
267 
268     for (auto& rnRef : desc.nodes) {
269         json::standalone_value jsonVal = CORE_NS::json::parse(rnRef.nodeJson.data());
270         // add camera info as well
271         jsonVal["customCameraId"] = renderCamera.id; // cam id
272         jsonVal["customCameraName"] = customCameraName;
273         jsonVal["multiviewBaseCameraId"] = baseCameraId;
274         if (auto dataStore = jsonVal.find("renderDataStore"); dataStore) {
275             if (auto config = dataStore->find("configurationName"); config) {
276                 if (config->is_string() && (!config->string_.empty())) {
277                     const bool rpp = customPostProcess || HasRenderDataStorePostProcess(*dataStore);
278                     auto renderDataStore = rpp ? GetPostProcess(renderCamera.postProcessName)
279                                                : GetPodPostProcess(renderCamera.postProcessName);
280                     jsonVal["renderDataStore"] = move(renderDataStore);
281                 }
282             }
283         }
284         rnRef.nodeJson = to_string(jsonVal);
285     }
286 }
287 } // namespace
288 
RenderUtil(IGraphicsContext & graphicsContext)289 RenderUtil::RenderUtil(IGraphicsContext& graphicsContext)
290     : context_(graphicsContext.GetRenderContext()), backendType_(context_.GetDevice().GetBackendType())
291 {
292     InitRenderNodeGraphs();
293 }
294 
InitRenderNodeGraphs()295 void RenderUtil::InitRenderNodeGraphs()
296 {
297     IRenderNodeGraphManager& rngm = context_.GetRenderNodeGraphManager();
298     IRenderNodeGraphLoader& rngl = rngm.GetRenderNodeGraphLoader();
299 
300     rngdScene_ = LoadRenderNodeGraph(rngl, SCENE_STR);
301     rngdCamLwrp_ = LoadRenderNodeGraph(rngl, CAM_SCENE_LWRP_STR);
302     rngdCamLwrpMsaa_ = LoadRenderNodeGraph(rngl, CAM_SCENE_LWRP_MSAA_STR);
303     rngdCamLwrpMsaaDepth_ = LoadRenderNodeGraph(rngl, CAM_SCENE_LWRP_MSAA_DEPTH_STR);
304     rngdCamLwrpMsaaGles_ = LoadRenderNodeGraph(rngl, CAM_SCENE_LWRP_MSAA_GLES_STR);
305     rngdCamHdr_ = LoadRenderNodeGraph(rngl, CAM_SCENE_HDRP_STR);
306     rngdCamHdrMsaa_ = LoadRenderNodeGraph(rngl, CAM_SCENE_HDRP_MSAA_STR);
307     rngdCamHdrMsaaDepth_ = LoadRenderNodeGraph(rngl, CAM_SCENE_HDRP_MSAA_DEPTH_STR);
308     rngdReflCam_ = LoadRenderNodeGraph(rngl, CAM_SCENE_REFLECTION_STR);
309     rngdReflCamMsaa_ = LoadRenderNodeGraph(rngl, CAM_SCENE_REFLECTION_MSAA_STR);
310     rngdCamPrePass_ = LoadRenderNodeGraph(rngl, CAM_SCENE_PRE_PASS_STR);
311 
312     rngdDeferred_ = LoadRenderNodeGraph(rngl, CAM_SCENE_DEFERRED_STR);
313 
314     rngdPostProcess_ = LoadRenderNodeGraph(rngl, CAM_SCENE_POST_PROCESS_STR);
315 }
316 
SelectBaseDesc(const RenderCamera & renderCamera) const317 RenderNodeGraphDesc RenderUtil::SelectBaseDesc(const RenderCamera& renderCamera) const
318 {
319     if (!renderCamera.customRenderNodeGraphFile.empty()) {
320         // custom render node graph file given which is patched
321         IRenderNodeGraphLoader& rngl = context_.GetRenderNodeGraphManager().GetRenderNodeGraphLoader();
322         return LoadRenderNodeGraph(rngl, renderCamera.customRenderNodeGraphFile);
323     }
324 
325     if (renderCamera.flags & RenderCamera::CAMERA_FLAG_REFLECTION_BIT) {
326         // check for msaa
327         return (renderCamera.flags & RenderCamera::CAMERA_FLAG_MSAA_BIT) ? rngdReflCamMsaa_ : rngdReflCam_;
328     }
329     if (renderCamera.flags & RenderCamera::CAMERA_FLAG_OPAQUE_BIT) {
330         return rngdCamPrePass_;
331     }
332     if (renderCamera.renderPipelineType == RenderCamera::RenderPipelineType::DEFERRED) {
333         return rngdDeferred_;
334     }
335     if (renderCamera.flags & RenderCamera::CAMERA_FLAG_MSAA_BIT) {
336         // NOTE: check for optimal GL(ES) render node graph if backbuffer is multisampled
337         const bool depthOutput =
338             ((renderCamera.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_OUTPUT_DEPTH_BIT) != 0U);
339         if (renderCamera.renderPipelineType != RenderCamera::RenderPipelineType::LIGHT_FORWARD) {
340             return depthOutput ? rngdCamHdrMsaaDepth_ : rngdCamHdrMsaa_;
341         }
342 
343         if ((backendType_ == DeviceBackendType::VULKAN) ||
344             (renderCamera.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_CUSTOM_TARGETS_BIT)) {
345             return depthOutput ? rngdCamLwrpMsaaDepth_ : rngdCamLwrpMsaa_;
346         }
347         const auto& gpuResourceMgr = context_.GetDevice().GetGpuResourceManager();
348         // NOTE: special handling on msaa swapchain with GLES
349         // creates issues with multi-ECS cases and might need to be dropped
350         // Prefer assigning swapchain image to camera in this case
351         const RenderHandleReference imageHandle = gpuResourceMgr.GetImageHandle("CORE_DEFAULT_BACKBUFFER");
352         const GpuImageDesc imageDesc = gpuResourceMgr.GetImageDescriptor(imageHandle);
353         if ((renderCamera.flags & RenderCamera::CAMERA_FLAG_MAIN_BIT) && (imageDesc.sampleCountFlags > 1) &&
354             (!depthOutput)) {
355 #if (CORE3D_VALIDATION_ENABLED == 1)
356             CORE_LOG_ONCE_I("3d_util_depth_gles_mixing" + to_string(renderCamera.id),
357                 "CORE3D_VALIDATION: GL(ES) Camera MSAA flags checked from CORE_DEFAULT_BACKBUFFER. "
358                 "Prefer assigning swapchain handle to camera.");
359 #endif
360             return rngdCamLwrpMsaaGles_;
361         }
362         return depthOutput ? rngdCamLwrpMsaaDepth_ : rngdCamLwrpMsaa_;
363     }
364     if (renderCamera.renderPipelineType != RenderCamera::RenderPipelineType::LIGHT_FORWARD) {
365         return rngdCamHdr_;
366     }
367     return rngdCamLwrp_;
368 }
369 
GetBasePostProcessDesc(const RenderCamera & renderCamera) const370 RenderNodeGraphDesc RenderUtil::GetBasePostProcessDesc(const RenderCamera& renderCamera) const
371 {
372     // light forward and opaque / pre-pass camera does not have separate post processes
373     if ((renderCamera.renderPipelineType != RenderCamera::RenderPipelineType::LIGHT_FORWARD) &&
374         ((renderCamera.flags & RenderCamera::CAMERA_FLAG_OPAQUE_BIT) == 0)) {
375         return rngdPostProcess_;
376     } else {
377         return {};
378     }
379 }
380 
GetRenderNodeGraphDesc(const RenderScene & renderScene,const RenderCamera & renderCamera,const uint32_t flags) const381 RenderNodeGraphDesc RenderUtil::GetRenderNodeGraphDesc(
382     const RenderScene& renderScene, const RenderCamera& renderCamera, const uint32_t flags) const
383 {
384     const string customCameraName = GetCameraName(renderCamera);
385     RenderNodeGraphDesc desc = SelectBaseDesc(renderCamera);
386     // process
387     desc.renderNodeGraphName = renderScene.name + to_hex(renderCamera.id);
388     FillCameraDescsData(renderCamera, customCameraName, desc);
389     return desc;
390 }
391 
GetRenderNodeGraphDescs(const RenderScene & renderScene,const RenderCamera & renderCamera,const uint32_t flags,const array_view<const RenderCamera> multiviewCameras) const392 IRenderUtil::CameraRenderNodeGraphDescs RenderUtil::GetRenderNodeGraphDescs(const RenderScene& renderScene,
393     const RenderCamera& renderCamera, const uint32_t flags, const array_view<const RenderCamera> multiviewCameras) const
394 {
395     // Gets RenderNodeGraphDescs for camera and patches
396     // 1. With built-in RNGs
397     //  * Select RNG for camera
398     //  * Select RNG for camera post process (if not LIGHT_FORWARD)
399     // 2. With built-in RNG for camera and custom for post process
400     //  * Select RNG for camera
401     //  * Load RNG for camera post process
402     // 3. With custom RNG for camera
403     //  * Load RNG for camera
404     //  * Load RNG for camera post process, only if custom given
405     // NOTE: special opaque / pre-pass camera (transmission) has built-in post process in RNG
406 
407     const string customCameraName = GetCameraName(renderCamera);
408     IRenderUtil::CameraRenderNodeGraphDescs descs;
409     // process camera
410     {
411         auto& desc = descs.camera;
412         desc = SelectBaseDesc(renderCamera);
413         desc.renderNodeGraphName = renderScene.name + to_hex(renderCamera.id);
414         FillCameraDescsData(renderCamera, customCameraName, desc);
415     }
416     // process post process
417     // NOTE: we do not add base post process render node graph to custom camera render node graphs
418     {
419         // NOTE: currently there are separate paths for new post process configurations and old
420         auto& desc = descs.postProcess;
421         const bool customPostProcess = !renderCamera.customPostProcessRenderNodeGraphFile.empty();
422         if (customPostProcess) {
423             IRenderNodeGraphLoader& rngl = context_.GetRenderNodeGraphManager().GetRenderNodeGraphLoader();
424             desc = LoadRenderNodeGraph(rngl, renderCamera.customPostProcessRenderNodeGraphFile);
425         } else if (renderCamera.customRenderNodeGraphFile.empty()) {
426             // only fetched when using built-in camera RNGs
427             desc = GetBasePostProcessDesc(renderCamera);
428         }
429         if (!desc.nodes.empty()) {
430             desc.renderNodeGraphName = renderScene.name + to_hex(renderCamera.id);
431             FillCameraPostProcessDescsData(
432                 renderCamera, RenderSceneDataConstants::INVALID_ID, customCameraName, customPostProcess, desc);
433         }
434 #if (CORE3D_VALIDATION_ENABLED == 1)
435         if (renderCamera.multiViewCameraCount != static_cast<uint32_t>(multiviewCameras.size())) {
436             CORE_LOG_W("CORE3D_VALIDATION: Multi-view camera count mismatch in render node graph creation.");
437         }
438 #endif
439         // multi-view camera post processes
440         if (renderCamera.multiViewCameraCount == static_cast<uint32_t>(multiviewCameras.size())) {
441 #if (CORE3D_VALIDATION_ENABLED == 1)
442             if (!renderCamera.customPostProcessRenderNodeGraphFile.empty()) {
443                 CORE_LOG_W("CORE3D_VALIDATION: Multi-view camera custom post process render node graph not supported.");
444             }
445 #endif
446             CORE_ASSERT(descs.multiViewCameraCount <= countof(descs.multiViewCameraPostProcesses));
447             descs.multiViewCameraCount = renderCamera.multiViewCameraCount;
448             for (size_t mvIdx = 0; mvIdx < descs.multiViewCameraCount; ++mvIdx) {
449                 const auto& mvCameraRef = multiviewCameras[mvIdx];
450                 auto& ppDesc = descs.multiViewCameraPostProcesses[mvIdx];
451                 ppDesc = GetBasePostProcessDesc(mvCameraRef);
452                 if (!ppDesc.nodes.empty()) {
453                     const string ppCustomCameraName = GetCameraName(mvCameraRef);
454                     ppDesc.renderNodeGraphName = renderScene.name + to_hex(mvCameraRef.id);
455                     FillCameraPostProcessDescsData(mvCameraRef, renderCamera.id, ppCustomCameraName, false, ppDesc);
456                 }
457             }
458         }
459     }
460 
461     return descs;
462 }
463 
GetRenderNodeGraphDescs(const RenderScene & renderScene,const RenderCamera & renderCamera,const uint32_t flags) const464 IRenderUtil::CameraRenderNodeGraphDescs RenderUtil::GetRenderNodeGraphDescs(
465     const RenderScene& renderScene, const RenderCamera& renderCamera, const uint32_t flags) const
466 {
467     return GetRenderNodeGraphDescs(renderScene, renderCamera, flags, {});
468 }
469 
GetRenderNodeGraphDesc(const RenderScene & renderScene,const uint32_t flags) const470 RenderNodeGraphDesc RenderUtil::GetRenderNodeGraphDesc(const RenderScene& renderScene, const uint32_t flags) const
471 {
472     RenderNodeGraphDesc desc;
473     if (!renderScene.customRenderNodeGraphFile.empty()) {
474         // custom render node graph file given which is patched
475         IRenderNodeGraphLoader& rngl = context_.GetRenderNodeGraphManager().GetRenderNodeGraphLoader();
476         desc = LoadRenderNodeGraph(rngl, renderScene.customRenderNodeGraphFile);
477     } else {
478         desc = rngdScene_;
479     }
480 
481     InjectRenderNodes(desc);
482 
483     const string customSceneName = GetSceneName(renderScene);
484     const auto sceneIdStr = to_hex(renderScene.id);
485     const auto combinedStr = renderScene.name + sceneIdStr;
486     desc.renderNodeGraphName = combinedStr;
487     for (auto& rnRef : desc.nodes) {
488         json::standalone_value jsonVal = CORE_NS::json::parse(rnRef.nodeJson.data());
489         jsonVal[string_view("customId")] = renderScene.id; // cam id
490         jsonVal[string_view("customName")] = customSceneName;
491         rnRef.nodeJson = to_string(jsonVal);
492     }
493     return desc;
494 }
495 
GetRenderNodeGraphDesc(const RenderScene & renderScene,const string & rngFile,const uint32_t flags) const496 RenderNodeGraphDesc RenderUtil::GetRenderNodeGraphDesc(
497     const RenderScene& renderScene, const string& rngFile, const uint32_t flags) const
498 {
499     RenderNodeGraphDesc desc;
500     if (!rngFile.empty()) {
501         // custom render node graph file given which is patched
502         IRenderNodeGraphLoader& rngl = context_.GetRenderNodeGraphManager().GetRenderNodeGraphLoader();
503         desc = LoadRenderNodeGraph(rngl, rngFile);
504     } else {
505         desc = rngdScene_;
506     }
507 
508     InjectRenderNodes(desc);
509 
510     const string customSceneName = GetSceneName(renderScene);
511     const auto sceneIdStr = to_hex(renderScene.id);
512     const auto combinedStr = renderScene.name + sceneIdStr;
513     desc.renderNodeGraphName = combinedStr;
514     for (auto& rnRef : desc.nodes) {
515         json::standalone_value jsonVal = CORE_NS::json::parse(rnRef.nodeJson.data());
516         jsonVal[string_view("customId")] = renderScene.id;
517         jsonVal[string_view("customName")] = customSceneName;
518         rnRef.nodeJson = to_string(jsonVal);
519     }
520     return desc;
521 }
522 CORE3D_END_NAMESPACE()
523