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