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 "util/render_util.h"
17 
18 #include <3d/intf_graphics_context.h>
19 #include <3d/render/intf_render_data_store_default_camera.h>
20 #include <core/intf_engine.h>
21 #include <core/json/json.h>
22 #include <core/namespace.h>
23 #include <render/device/intf_device.h>
24 #include <render/device/intf_gpu_resource_manager.h>
25 #include <render/intf_render_context.h>
26 #include <render/render_data_structures.h>
27 
28 CORE3D_BEGIN_NAMESPACE()
29 using namespace BASE_NS;
30 using namespace CORE_NS;
31 using namespace RENDER_NS;
32 
33 namespace {
34 constexpr const string_view SCENE_STR = "3drendernodegraphs://core3d_rng_scene.rng";
35 constexpr const string_view CAM_SCENE_LWRP_STR = "3drendernodegraphs://core3d_rng_cam_scene_lwrp.rng";
36 constexpr const string_view CAM_SCENE_LWRP_MSAA_STR = "3drendernodegraphs://core3d_rng_cam_scene_lwrp_msaa.rng";
37 constexpr const string_view CAM_SCENE_LWRP_MSAA_DEPTH_STR =
38     "3drendernodegraphs://core3d_rng_cam_scene_lwrp_msaa_depth.rng";
39 constexpr const string_view CAM_SCENE_LWRP_MSAA_GLES_STR =
40     "3drendernodegraphs://core3d_rng_cam_scene_lwrp_msaa_gles.rng";
41 constexpr const string_view CAM_SCENE_HDRP_STR = "3drendernodegraphs://core3d_rng_cam_scene_hdrp.rng";
42 constexpr const string_view CAM_SCENE_HDRP_MSAA_STR = "3drendernodegraphs://core3d_rng_cam_scene_hdrp_msaa.rng";
43 constexpr const string_view CAM_SCENE_HDRP_MSAA_DEPTH_STR =
44     "3drendernodegraphs://core3d_rng_cam_scene_hdrp_msaa_depth.rng";
45 constexpr const string_view CAM_SCENE_REFLECTION_STR = "3drendernodegraphs://core3d_rng_reflection_cam_scene.rng";
46 constexpr const string_view CAM_SCENE_REFLECTION_MSAA_STR =
47     "3drendernodegraphs://core3d_rng_reflection_cam_scene_msaa.rng";
48 constexpr const string_view CAM_SCENE_PRE_PASS_STR = "3drendernodegraphs://core3d_rng_cam_scene_pre_pass.rng";
49 constexpr const string_view CAM_SCENE_DEFERRED_STR = "3drendernodegraphs://core3d_rng_cam_scene_deferred.rng";
50 constexpr const string_view CAM_SCENE_POST_PROCESS_STR = "3drendernodegraphs://core3d_rng_cam_scene_post_process.rng";
51 
LoadRenderNodeGraph(IRenderNodeGraphLoader & rngLoader,const string_view rng)52 RenderNodeGraphDesc LoadRenderNodeGraph(IRenderNodeGraphLoader& rngLoader, const string_view rng)
53 {
54     IRenderNodeGraphLoader::LoadResult lr = rngLoader.Load(rng);
55     if (!lr.success) {
56         CORE_LOG_E("error loading render node graph: %s - error: %s", rng.data(), lr.error.data());
57     }
58     return lr.desc;
59 }
60 
GetPodPostProcess(const string_view name)61 json::standalone_value GetPodPostProcess(const string_view name)
62 {
63     auto renderDataStore = json::standalone_value { json::standalone_value::object {} };
64     renderDataStore["dataStoreName"] = "RenderDataStorePod";
65     renderDataStore["typeName"] = "RenderDataStorePod"; // This is render data store TYPE_NAME
66     renderDataStore["configurationName"] = string(name);
67     return renderDataStore;
68 }
69 
GetPostProcess(const string_view name)70 json::standalone_value GetPostProcess(const string_view name)
71 {
72     auto renderDataStore = json::standalone_value { json::standalone_value::object {} };
73     renderDataStore["dataStoreName"] = "RenderDataStorePostProcess";
74     renderDataStore["typeName"] = "RenderDataStorePostProcess"; // This is render data store TYPE_NAME
75     renderDataStore["configurationName"] = string(name);
76     return renderDataStore;
77 }
78 
HasRenderDataStorePostProcess(const json::standalone_value & dataStore)79 inline bool HasRenderDataStorePostProcess(const json::standalone_value& dataStore)
80 {
81     if (const auto typeName = dataStore.find("typeName"); typeName) {
82         if (typeName->is_string() && (typeName->string_ == "RenderDataStorePostProcess")) {
83             return true;
84         }
85     }
86     return false;
87 }
88 
GetCameraName(const RenderCamera & camera)89 inline string GetCameraName(const RenderCamera& camera)
90 {
91     return camera.name.empty() ? string(to_hex(camera.id)) : string(camera.name);
92 }
93 
GetSceneName(const RenderScene & scene)94 inline string GetSceneName(const RenderScene& scene)
95 {
96     return scene.name.empty() ? string(to_hex(scene.id)) : string(scene.name);
97 }
98 
FillCameraDescsData(const RenderCamera & renderCamera,const string & customCameraName,RenderNodeGraphDesc & desc)99 void FillCameraDescsData(const RenderCamera& renderCamera, const string& customCameraName, RenderNodeGraphDesc& desc)
100 {
101     for (auto& rnRef : desc.nodes) {
102         json::standalone_value jsonVal = CORE_NS::json::parse(rnRef.nodeJson.data());
103         jsonVal["customCameraId"] = renderCamera.id; // cam id
104         jsonVal["customCameraName"] = customCameraName;
105         if (renderCamera.flags & RenderCamera::CAMERA_FLAG_REFLECTION_BIT) {
106             jsonVal["nodeFlags"] = 7u; // NOTE: hard coded
107         }
108         if (auto dataStore = jsonVal.find("renderDataStore"); dataStore) {
109             if (auto config = dataStore->find("configurationName"); config) {
110                 if (!config->string_.empty()) {
111                     const bool rpp = HasRenderDataStorePostProcess(*dataStore);
112                     auto renderDataStore = rpp ? GetPostProcess(renderCamera.postProcessName)
113                                                : GetPodPostProcess(renderCamera.postProcessName);
114                     jsonVal["renderDataStore"] = move(renderDataStore);
115                 }
116             }
117         }
118         rnRef.nodeJson = to_string(jsonVal);
119     }
120 }
121 
FillCameraPostProcessDescsData(const RenderCamera & renderCamera,const uint64_t baseCameraId,const string & customCameraName,const bool customPostProcess,RenderNodeGraphDesc & desc)122 void FillCameraPostProcessDescsData(const RenderCamera& renderCamera, const uint64_t baseCameraId,
123     const string& customCameraName, const bool customPostProcess, RenderNodeGraphDesc& desc)
124 {
125     for (auto& rnRef : desc.nodes) {
126         json::standalone_value jsonVal = CORE_NS::json::parse(rnRef.nodeJson.data());
127         // add camera info as well
128         jsonVal["customCameraId"] = renderCamera.id; // cam id
129         jsonVal["customCameraName"] = customCameraName;
130         jsonVal["multiviewBaseCameraId"] = baseCameraId;
131         if (auto dataStore = jsonVal.find("renderDataStore"); dataStore) {
132             if (auto config = dataStore->find("configurationName"); config) {
133                 if (config->is_string() && (!config->string_.empty())) {
134                     const bool rpp = customPostProcess || HasRenderDataStorePostProcess(*dataStore);
135                     auto renderDataStore = rpp ? GetPostProcess(renderCamera.postProcessName)
136                                                : GetPodPostProcess(renderCamera.postProcessName);
137                     jsonVal["renderDataStore"] = move(renderDataStore);
138                 }
139             }
140         }
141         rnRef.nodeJson = to_string(jsonVal);
142     }
143 }
144 } // namespace
145 
RenderUtil(IGraphicsContext & graphicsContext)146 RenderUtil::RenderUtil(IGraphicsContext& graphicsContext)
147     : context_(graphicsContext.GetRenderContext()), backendType_(context_.GetDevice().GetBackendType())
148 {
149     InitRenderNodeGraphs();
150 }
151 
InitRenderNodeGraphs()152 void RenderUtil::InitRenderNodeGraphs()
153 {
154     IRenderNodeGraphManager& rngm = context_.GetRenderNodeGraphManager();
155     IRenderNodeGraphLoader& rngl = rngm.GetRenderNodeGraphLoader();
156 
157     rngdScene_ = LoadRenderNodeGraph(rngl, SCENE_STR);
158     rngdCamLwrp_ = LoadRenderNodeGraph(rngl, CAM_SCENE_LWRP_STR);
159     rngdCamLwrpMsaa_ = LoadRenderNodeGraph(rngl, CAM_SCENE_LWRP_MSAA_STR);
160     rngdCamLwrpMsaaDepth_ = LoadRenderNodeGraph(rngl, CAM_SCENE_LWRP_MSAA_DEPTH_STR);
161     rngdCamLwrpMsaaGles_ = LoadRenderNodeGraph(rngl, CAM_SCENE_LWRP_MSAA_GLES_STR);
162     rngdCamHdr_ = LoadRenderNodeGraph(rngl, CAM_SCENE_HDRP_STR);
163     rngdCamHdrMsaa_ = LoadRenderNodeGraph(rngl, CAM_SCENE_HDRP_MSAA_STR);
164     rngdCamHdrMsaaDepth_ = LoadRenderNodeGraph(rngl, CAM_SCENE_HDRP_MSAA_DEPTH_STR);
165     rngdReflCam_ = LoadRenderNodeGraph(rngl, CAM_SCENE_REFLECTION_STR);
166     rngdReflCamMsaa_ = LoadRenderNodeGraph(rngl, CAM_SCENE_REFLECTION_MSAA_STR);
167     rngdCamPrePass_ = LoadRenderNodeGraph(rngl, CAM_SCENE_PRE_PASS_STR);
168 
169     rngdDeferred_ = LoadRenderNodeGraph(rngl, CAM_SCENE_DEFERRED_STR);
170 
171     rngdPostProcess_ = LoadRenderNodeGraph(rngl, CAM_SCENE_POST_PROCESS_STR);
172 }
173 
SelectBaseDesc(const RenderCamera & renderCamera) const174 RenderNodeGraphDesc RenderUtil::SelectBaseDesc(const RenderCamera& renderCamera) const
175 {
176     RenderNodeGraphDesc desc;
177     if (!renderCamera.customRenderNodeGraphFile.empty()) {
178         // custom render node graph file given which is patched
179         IRenderNodeGraphLoader& rngl = context_.GetRenderNodeGraphManager().GetRenderNodeGraphLoader();
180         desc = LoadRenderNodeGraph(rngl, renderCamera.customRenderNodeGraphFile);
181     } else {
182         if (renderCamera.flags & RenderCamera::CAMERA_FLAG_REFLECTION_BIT) {
183             // check for msaa
184             desc = (renderCamera.flags & RenderCamera::CAMERA_FLAG_MSAA_BIT) ? rngdReflCamMsaa_ : rngdReflCam_;
185         } else if (renderCamera.flags & RenderCamera::CAMERA_FLAG_OPAQUE_BIT) {
186             desc = rngdCamPrePass_;
187         } else {
188             if (renderCamera.renderPipelineType == RenderCamera::RenderPipelineType::DEFERRED) {
189                 desc = rngdDeferred_;
190             } else {
191                 if (renderCamera.flags & RenderCamera::CAMERA_FLAG_MSAA_BIT) {
192                     // NOTE: check for optimal GL(ES) render node graph if backbuffer is multisampled
193                     const bool depthOutput =
194                         ((renderCamera.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_OUTPUT_DEPTH_BIT) != 0U);
195                     if (renderCamera.renderPipelineType != RenderCamera::RenderPipelineType::LIGHT_FORWARD) {
196                         desc = depthOutput ? rngdCamHdrMsaaDepth_ : rngdCamHdrMsaa_;
197                     } else if ((backendType_ == DeviceBackendType::VULKAN) ||
198                                (renderCamera.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_CUSTOM_TARGETS_BIT)) {
199                         desc = depthOutput ? rngdCamLwrpMsaaDepth_ : rngdCamLwrpMsaa_;
200                     } else {
201                         const auto& gpuResourceMgr = context_.GetDevice().GetGpuResourceManager();
202                         // NOTE: special handling on msaa swapchain with GLES
203                         // creates issues with multi-ECS cases and might need to be dropped
204                         // Prefer assigning swapchain image to camera in this case
205                         const RenderHandleReference imageHandle =
206                             gpuResourceMgr.GetImageHandle("CORE_DEFAULT_BACKBUFFER");
207                         const GpuImageDesc imageDesc = gpuResourceMgr.GetImageDescriptor(imageHandle);
208                         if ((renderCamera.flags & RenderCamera::CAMERA_FLAG_MAIN_BIT) &&
209                             (imageDesc.sampleCountFlags > 1) && (!depthOutput)) {
210 #if (CORE3D_VALIDATION_ENABLED == 1)
211                             CORE_LOG_ONCE_I("3d_util_depth_gles_mixing" + to_string(renderCamera.id),
212                                 "CORE3D_VALIDATION: GL(ES) Camera MSAA flags checked from CORE_DEFAULT_BACKBUFFER. "
213                                 "Prefer assigning swapchain handle to camera.");
214 #endif
215                             desc = rngdCamLwrpMsaaGles_;
216                         } else {
217                             desc = depthOutput ? rngdCamLwrpMsaaDepth_ : rngdCamLwrpMsaa_;
218                         }
219                     }
220                 } else if (renderCamera.renderPipelineType != RenderCamera::RenderPipelineType::LIGHT_FORWARD) {
221                     desc = rngdCamHdr_;
222                 } else {
223                     desc = rngdCamLwrp_;
224                 }
225             }
226         }
227     }
228     return desc;
229 }
230 
GetBasePostProcessDesc(const RenderCamera & renderCamera) const231 RenderNodeGraphDesc RenderUtil::GetBasePostProcessDesc(const RenderCamera& renderCamera) const
232 {
233     // light forward and opaque / pre-pass camera does not have separate post processes
234     if ((renderCamera.renderPipelineType != RenderCamera::RenderPipelineType::LIGHT_FORWARD) &&
235         ((renderCamera.flags & RenderCamera::CAMERA_FLAG_OPAQUE_BIT) == 0)) {
236         return rngdPostProcess_;
237     } else {
238         return {};
239     }
240 }
241 
GetRenderNodeGraphDesc(const RenderScene & renderScene,const RenderCamera & renderCamera,const uint32_t flags) const242 RenderNodeGraphDesc RenderUtil::GetRenderNodeGraphDesc(
243     const RenderScene& renderScene, const RenderCamera& renderCamera, const uint32_t flags) const
244 {
245     const string customCameraName = GetCameraName(renderCamera);
246     RenderNodeGraphDesc desc = SelectBaseDesc(renderCamera);
247     // process
248     desc.renderNodeGraphName = renderScene.name + to_hex(renderCamera.id);
249     FillCameraDescsData(renderCamera, customCameraName, desc);
250     return desc;
251 }
252 
GetRenderNodeGraphDescs(const RenderScene & renderScene,const RenderCamera & renderCamera,const uint32_t flags,const array_view<const RenderCamera> multiviewCameras) const253 IRenderUtil::CameraRenderNodeGraphDescs RenderUtil::GetRenderNodeGraphDescs(const RenderScene& renderScene,
254     const RenderCamera& renderCamera, const uint32_t flags, const array_view<const RenderCamera> multiviewCameras) const
255 {
256     // Gets RenderNodeGraphDescs for camera and patches
257     // 1. With built-in RNGs
258     //  * Select RNG for camera
259     //  * Select RNG for camera post process (if not LIGHT_FORWARD)
260     // 2. With built-in RNG for camera and custom for post process
261     //  * Select RNG for camera
262     //  * Load RNG for camera post process
263     // 3. With custom RNG for camera
264     //  * Load RNG for camera
265     //  * Load RNG for camera post process, only if custom given
266     // NOTE: special opaque / pre-pass camera (transmission) has built-in post process in RNG
267 
268     const string customCameraName = GetCameraName(renderCamera);
269     IRenderUtil::CameraRenderNodeGraphDescs descs;
270     // process camera
271     {
272         auto& desc = descs.camera;
273         desc = SelectBaseDesc(renderCamera);
274         desc.renderNodeGraphName = renderScene.name + to_hex(renderCamera.id);
275         FillCameraDescsData(renderCamera, customCameraName, desc);
276     }
277     // process post process
278     // NOTE: we do not add base post process render node graph to custom camera render node graphs
279     {
280         // NOTE: currently there are separate paths for new post process configurations and old
281         auto& desc = descs.postProcess;
282         const bool customPostProcess = !renderCamera.customPostProcessRenderNodeGraphFile.empty();
283         if (customPostProcess) {
284             IRenderNodeGraphLoader& rngl = context_.GetRenderNodeGraphManager().GetRenderNodeGraphLoader();
285             desc = LoadRenderNodeGraph(rngl, renderCamera.customPostProcessRenderNodeGraphFile);
286         } else if (renderCamera.customRenderNodeGraphFile.empty()) {
287             // only fetched when using built-in camera RNGs
288             desc = GetBasePostProcessDesc(renderCamera);
289         }
290         if (!desc.nodes.empty()) {
291             desc.renderNodeGraphName = renderScene.name + to_hex(renderCamera.id);
292             FillCameraPostProcessDescsData(
293                 renderCamera, RenderSceneDataConstants::INVALID_ID, customCameraName, customPostProcess, desc);
294         }
295 #if (CORE3D_VALIDATION_ENABLED == 1)
296         if (renderCamera.multiViewCameraCount != static_cast<uint32_t>(multiviewCameras.size())) {
297             CORE_LOG_W("CORE3D_VALIDATION: Multi-view camera count mismatch in render node graph creation.");
298         }
299 #endif
300         // multi-view camera post processes
301         if (renderCamera.multiViewCameraCount == static_cast<uint32_t>(multiviewCameras.size())) {
302 #if (CORE3D_VALIDATION_ENABLED == 1)
303             if (!renderCamera.customPostProcessRenderNodeGraphFile.empty()) {
304                 CORE_LOG_W("CORE3D_VALIDATION: Multi-view camera custom post process render node graph not supported.");
305             }
306 #endif
307             CORE_ASSERT(descs.multiViewCameraCount <= countof(descs.multiViewCameraPostProcesses));
308             descs.multiViewCameraCount = renderCamera.multiViewCameraCount;
309             for (size_t mvIdx = 0; mvIdx < descs.multiViewCameraCount; ++mvIdx) {
310                 const auto& mvCameraRef = multiviewCameras[mvIdx];
311                 auto& ppDesc = descs.multiViewCameraPostProcesses[mvIdx];
312                 ppDesc = GetBasePostProcessDesc(mvCameraRef);
313                 if (!ppDesc.nodes.empty()) {
314                     const string ppCustomCameraName = GetCameraName(mvCameraRef);
315                     ppDesc.renderNodeGraphName = renderScene.name + to_hex(mvCameraRef.id);
316                     FillCameraPostProcessDescsData(mvCameraRef, renderCamera.id, ppCustomCameraName, false, ppDesc);
317                 }
318             }
319         }
320     }
321 
322     return descs;
323 }
324 
GetRenderNodeGraphDescs(const RenderScene & renderScene,const RenderCamera & renderCamera,const uint32_t flags) const325 IRenderUtil::CameraRenderNodeGraphDescs RenderUtil::GetRenderNodeGraphDescs(
326     const RenderScene& renderScene, const RenderCamera& renderCamera, const uint32_t flags) const
327 {
328     return GetRenderNodeGraphDescs(renderScene, renderCamera, flags, {});
329 }
330 
GetRenderNodeGraphDesc(const RenderScene & renderScene,const uint32_t flags) const331 RenderNodeGraphDesc RenderUtil::GetRenderNodeGraphDesc(const RenderScene& renderScene, const uint32_t flags) const
332 {
333     RenderNodeGraphDesc desc;
334     if (!renderScene.customRenderNodeGraphFile.empty()) {
335         // custom render node graph file given which is patched
336         IRenderNodeGraphLoader& rngl = context_.GetRenderNodeGraphManager().GetRenderNodeGraphLoader();
337         desc = LoadRenderNodeGraph(rngl, renderScene.customRenderNodeGraphFile);
338     } else {
339         desc = rngdScene_;
340     }
341     const string customSceneName = GetSceneName(renderScene);
342     const auto sceneIdStr = to_hex(renderScene.id);
343     const auto combinedStr = renderScene.name + sceneIdStr;
344     desc.renderNodeGraphName = combinedStr;
345     for (auto& rnRef : desc.nodes) {
346         json::standalone_value jsonVal = CORE_NS::json::parse(rnRef.nodeJson.data());
347         jsonVal[string_view("customId")] = renderScene.id; // cam id
348         jsonVal[string_view("customName")] = customSceneName;
349         rnRef.nodeJson = to_string(jsonVal);
350     }
351     return desc;
352 }
353 
GetRenderNodeGraphDesc(const RenderScene & renderScene,const string & rngFile,const uint32_t flags) const354 RenderNodeGraphDesc RenderUtil::GetRenderNodeGraphDesc(
355     const RenderScene& renderScene, const string& rngFile, const uint32_t flags) const
356 {
357     RenderNodeGraphDesc desc;
358     if (!rngFile.empty()) {
359         // custom render node graph file given which is patched
360         IRenderNodeGraphLoader& rngl = context_.GetRenderNodeGraphManager().GetRenderNodeGraphLoader();
361         desc = LoadRenderNodeGraph(rngl, rngFile);
362     } else {
363         desc = rngdScene_;
364     }
365     const string customSceneName = GetSceneName(renderScene);
366     const auto sceneIdStr = to_hex(renderScene.id);
367     const auto combinedStr = renderScene.name + sceneIdStr;
368     desc.renderNodeGraphName = combinedStr;
369     for (auto& rnRef : desc.nodes) {
370         json::standalone_value jsonVal = CORE_NS::json::parse(rnRef.nodeJson.data());
371         jsonVal[string_view("customId")] = renderScene.id;
372         jsonVal[string_view("customName")] = customSceneName;
373         rnRef.nodeJson = to_string(jsonVal);
374     }
375     return desc;
376 }
377 CORE3D_END_NAMESPACE()
378