1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "render_system.h"
17 
18 #include <algorithm>
19 
20 #if (CORE3D_VALIDATION_ENABLED == 1)
21 #include <cinttypes>
22 #include <string>
23 #endif
24 
25 #include <PropertyTools/property_api_impl.inl>
26 #include <PropertyTools/property_macros.h>
27 
28 #include <3d/ecs/components/camera_component.h>
29 #include <3d/ecs/components/environment_component.h>
30 #include <3d/ecs/components/fog_component.h>
31 #include <3d/ecs/components/joint_matrices_component.h>
32 #include <3d/ecs/components/layer_component.h>
33 #include <3d/ecs/components/light_component.h>
34 #include <3d/ecs/components/material_component.h>
35 #include <3d/ecs/components/material_extension_component.h>
36 #include <3d/ecs/components/mesh_component.h>
37 #include <3d/ecs/components/name_component.h>
38 #include <3d/ecs/components/node_component.h>
39 #include <3d/ecs/components/planar_reflection_component.h>
40 #include <3d/ecs/components/post_process_component.h>
41 #include <3d/ecs/components/post_process_configuration_component.h>
42 #include <3d/ecs/components/render_configuration_component.h>
43 #include <3d/ecs/components/render_handle_component.h>
44 #include <3d/ecs/components/render_mesh_batch_component.h>
45 #include <3d/ecs/components/render_mesh_component.h>
46 #include <3d/ecs/components/skin_component.h>
47 #include <3d/ecs/components/skin_joints_component.h>
48 #include <3d/ecs/components/uri_component.h>
49 #include <3d/ecs/components/world_matrix_component.h>
50 #include <3d/ecs/systems/intf_node_system.h>
51 #include <3d/ecs/systems/intf_render_preprocessor_system.h>
52 #include <3d/ecs/systems/intf_skinning_system.h>
53 #include <3d/implementation_uids.h>
54 #include <3d/intf_graphics_context.h>
55 #include <3d/render/intf_render_data_store_default_camera.h>
56 #include <3d/render/intf_render_data_store_default_light.h>
57 #include <3d/render/intf_render_data_store_default_material.h>
58 #include <3d/render/intf_render_data_store_default_scene.h>
59 #include <3d/util/intf_mesh_util.h>
60 #include <3d/util/intf_picking.h>
61 #include <3d/util/intf_render_util.h>
62 #include <base/containers/string.h>
63 #include <base/math/float_packer.h>
64 #include <base/math/matrix_util.h>
65 #include <base/math/quaternion_util.h>
66 #include <base/math/vector.h>
67 #include <base/math/vector_util.h>
68 #include <core/ecs/intf_ecs.h>
69 #include <core/ecs/intf_entity_manager.h>
70 #include <core/implementation_uids.h>
71 #include <core/intf_engine.h>
72 #include <core/log.h>
73 #include <core/namespace.h>
74 #include <core/perf/cpu_perf_scope.h>
75 #include <core/perf/intf_performance_data_manager.h>
76 #include <core/plugin/intf_plugin_register.h>
77 #include <core/util/intf_frustum_util.h>
78 #include <render/datastore/intf_render_data_store_manager.h>
79 #include <render/datastore/intf_render_data_store_pod.h>
80 #include <render/datastore/intf_render_data_store_post_process.h>
81 #include <render/datastore/render_data_store_render_pods.h>
82 #include <render/device/intf_gpu_resource_manager.h>
83 #include <render/device/intf_shader_manager.h>
84 #include <render/device/pipeline_state_desc.h>
85 #include <render/implementation_uids.h>
86 #include <render/intf_render_context.h>
87 #include <render/nodecontext/intf_render_node_graph_manager.h>
88 #include <render/resource_handle.h>
89 
90 #include "ecs/components/previous_joint_matrices_component.h"
91 #include "ecs/components/previous_world_matrix_component.h"
92 #include "ecs/systems/render_preprocessor_system.h"
93 #include "util/component_util_functions.h"
94 #include "util/mesh_util.h"
95 #include "util/scene_util.h"
96 #include "util/uri_lookup.h"
97 
98 CORE_BEGIN_NAMESPACE()
99 DECLARE_PROPERTY_TYPE(RENDER_NS::IRenderDataStoreManager*);
100 CORE_END_NAMESPACE()
101 
102 CORE3D_BEGIN_NAMESPACE()
103 using namespace RENDER_NS;
104 using namespace BASE_NS;
105 using namespace CORE_NS;
106 
107 namespace {
108 static const RenderSubmesh INIT {};
109 static const RenderDataDefaultMaterial::MaterialHandles DEF_MATERIAL_HANDLES {};
110 static const MaterialComponent DEF_MATERIAL_COMPONENT {};
111 static constexpr uint32_t NEEDS_COLOR_PRE_PASS { 1u << 0u };
112 static constexpr uint64_t PREPASS_CAMERA_START_UNIQUE_ID { 1 };
113 static constexpr uint64_t SHADOW_CAMERA_START_UNIQUE_ID { 100 };
114 #if (CORE3D_VALIDATION_ENABLED == 1)
115 static constexpr uint32_t MAX_BATCH_SUBMESH_COUNT { 64u };
116 #endif
117 
118 static constexpr uint32_t MAX_BATCH_OBJECT_COUNT { PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE /
119                                                    PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE };
120 
121 // typename for POD data. (e.g. "PostProcess") (core/render/intf_render_data_store_pod.h)
122 static constexpr string_view POST_PROCESS_NAME { "PostProcess" };
123 static constexpr string_view POD_DATA_STORE_NAME { "RenderDataStorePod" };
124 static constexpr string_view PP_DATA_STORE_NAME { "RenderDataStorePostProcess" };
125 
126 // In addition to the base our renderableQuery has two required components and three optional components:
127 // (0) RenderMeshComponent
128 // (1) WorldMatrixComponent
129 // (2) PreviousWorldMatrixComponent
130 // (3) LayerComponent (optional)
131 // (4) JointMatrixComponent (optional)
132 // (5) PreviousJointMatrixComponent (optional)
133 static constexpr const auto RQ_RMC = 0U;
134 static constexpr const auto RQ_WM = 1U;
135 static constexpr const auto RQ_PWM = 2U;
136 static constexpr const auto RQ_L = 3U;
137 static constexpr const auto RQ_JM = 4U;
138 static constexpr const auto RQ_PJM = 5U;
139 
FillShaderData(IEntityManager & em,IUriComponentManager & uriManager,IRenderHandleComponentManager & renderHandleMgr,const IShaderManager & shaderMgr,const string_view renderSlot,RenderSystem::DefaultMaterialShaderData::SingleShaderData & shaderData)140 void FillShaderData(IEntityManager& em, IUriComponentManager& uriManager,
141     IRenderHandleComponentManager& renderHandleMgr, const IShaderManager& shaderMgr, const string_view renderSlot,
142     RenderSystem::DefaultMaterialShaderData::SingleShaderData& shaderData)
143 {
144     const uint32_t renderSlotId = shaderMgr.GetRenderSlotId(renderSlot);
145     const IShaderManager::RenderSlotData rsd = shaderMgr.GetRenderSlotData(renderSlotId);
146 
147     auto uri = "3dshaders://" + renderSlot;
148     auto resourceEntity = LookupResourceByUri(uri, uriManager, renderHandleMgr);
149     if (!EntityUtil::IsValid(resourceEntity)) {
150         resourceEntity = em.Create();
151         renderHandleMgr.Create(resourceEntity);
152         renderHandleMgr.Write(resourceEntity)->reference = rsd.shader;
153         uriManager.Create(resourceEntity);
154         uriManager.Write(resourceEntity)->uri = uri;
155     }
156     shaderData.shader = em.GetReferenceCounted(resourceEntity);
157 
158     uri = "3dshaderstates://";
159     uri += renderSlot;
160     resourceEntity = LookupResourceByUri(uri, uriManager, renderHandleMgr);
161     if (!EntityUtil::IsValid(resourceEntity)) {
162         resourceEntity = em.Create();
163         renderHandleMgr.Create(resourceEntity);
164         renderHandleMgr.Write(resourceEntity)->reference = rsd.graphicsState;
165         uriManager.Create(resourceEntity);
166         uriManager.Write(resourceEntity)->uri = uri;
167     }
168     shaderData.gfxState = em.GetReferenceCounted(resourceEntity);
169 
170     uri += "_DBL";
171     resourceEntity = LookupResourceByUri(uri, uriManager, renderHandleMgr);
172     if (!EntityUtil::IsValid(resourceEntity)) {
173         // fetch double sided mode (no culling gfx state) (NOTE: could be fetched with name)
174         if (rsd.graphicsState) {
175             GraphicsState gfxState = shaderMgr.GetGraphicsState(rsd.graphicsState);
176             gfxState.rasterizationState.cullModeFlags = CullModeFlagBits::CORE_CULL_MODE_NONE;
177             const uint64_t gfxStateHash = shaderMgr.HashGraphicsState(gfxState);
178             auto handlDbl = shaderMgr.GetGraphicsStateHandleByHash(gfxStateHash);
179             if (handlDbl) {
180                 resourceEntity = em.Create();
181                 renderHandleMgr.Create(resourceEntity);
182                 renderHandleMgr.Write(resourceEntity)->reference = handlDbl;
183                 uriManager.Create(resourceEntity);
184                 uriManager.Write(resourceEntity)->uri = uri;
185             }
186         }
187     }
188     shaderData.gfxStateDoubleSided = em.GetReferenceCounted(resourceEntity);
189 }
190 
CreateReflectionPlaneGpuImageDesc(bool depthImage)191 constexpr GpuImageDesc CreateReflectionPlaneGpuImageDesc(bool depthImage)
192 {
193     GpuImageDesc desc;
194     desc.depth = 1;
195     desc.format = depthImage ? Format::BASE_FORMAT_D16_UNORM : Format::BASE_FORMAT_B10G11R11_UFLOAT_PACK32;
196     desc.memoryPropertyFlags =
197         depthImage ? MemoryPropertyFlags(MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
198                                          MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
199                    : MemoryPropertyFlags(MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
200     desc.usageFlags = depthImage ? ImageUsageFlags(ImageUsageFlagBits::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
201                                                    ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT)
202                                  : ImageUsageFlags(ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
203                                                    ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT);
204     desc.imageType = ImageType::CORE_IMAGE_TYPE_2D;
205     desc.imageTiling = ImageTiling::CORE_IMAGE_TILING_OPTIMAL;
206     desc.imageViewType = ImageViewType::CORE_IMAGE_VIEW_TYPE_2D;
207     desc.engineCreationFlags = EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS;
208     return desc;
209 }
210 
GetRenderCameraFlagsFromComponentFlags(const uint32_t pipelineFlags)211 constexpr uint32_t GetRenderCameraFlagsFromComponentFlags(const uint32_t pipelineFlags)
212 {
213     uint32_t flags = 0;
214     if (pipelineFlags & CameraComponent::PipelineFlagBits::MSAA_BIT) {
215         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_MSAA_BIT;
216     }
217     if (pipelineFlags & CameraComponent::PipelineFlagBits::CLEAR_DEPTH_BIT) {
218         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_CLEAR_DEPTH_BIT;
219     }
220     if (pipelineFlags & CameraComponent::PipelineFlagBits::CLEAR_COLOR_BIT) {
221         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_CLEAR_COLOR_BIT;
222     }
223     if (pipelineFlags & CameraComponent::PipelineFlagBits::HISTORY_BIT) {
224         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_HISTORY_BIT;
225     }
226     if (pipelineFlags & CameraComponent::PipelineFlagBits::JITTER_BIT) {
227         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_JITTER_BIT;
228     }
229     if (pipelineFlags & CameraComponent::PipelineFlagBits::VELOCITY_OUTPUT_BIT) {
230         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_OUTPUT_VELOCITY_NORMAL_BIT;
231     }
232     if (pipelineFlags & CameraComponent::PipelineFlagBits::DEPTH_OUTPUT_BIT) {
233         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_OUTPUT_DEPTH_BIT;
234     }
235     if (pipelineFlags & CameraComponent::PipelineFlagBits::MULTI_VIEW_ONLY_BIT) {
236         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_MULTI_VIEW_ONLY_BIT;
237     }
238     if (pipelineFlags & CameraComponent::PipelineFlagBits::DYNAMIC_CUBEMAP_BIT) {
239         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_DYNAMIC_CUBEMAP_BIT;
240     }
241     if ((pipelineFlags & CameraComponent::PipelineFlagBits::DISALLOW_REFLECTION_BIT) == 0U) {
242         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_ALLOW_REFLECTION_BIT;
243     }
244     // NOTE: color pre pass bit is not currently enabled from here
245     return flags;
246 }
247 
GetRenderCameraCullTypeFromComponent(const CameraComponent::Culling cameraCullType)248 constexpr inline RenderCamera::CameraCullType GetRenderCameraCullTypeFromComponent(
249     const CameraComponent::Culling cameraCullType)
250 {
251     RenderCamera::CameraCullType cullType(RenderCamera::CameraCullType::CAMERA_CULL_NONE);
252     if (cameraCullType == CameraComponent::Culling::VIEW_FRUSTUM) {
253         cullType = RenderCamera::CameraCullType::CAMERA_CULL_VIEW_FRUSTUM;
254     }
255     return cullType;
256 }
257 
GetRenderCameraRenderPipelineTypeFromComponent(const CameraComponent::RenderingPipeline cameraRenderPipelineType)258 constexpr inline RenderCamera::RenderPipelineType GetRenderCameraRenderPipelineTypeFromComponent(
259     const CameraComponent::RenderingPipeline cameraRenderPipelineType)
260 {
261     RenderCamera::RenderPipelineType pipelineType(RenderCamera::RenderPipelineType::FORWARD);
262     if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::LIGHT_FORWARD) {
263         pipelineType = RenderCamera::RenderPipelineType::LIGHT_FORWARD;
264     } else if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::FORWARD) {
265         pipelineType = RenderCamera::RenderPipelineType::FORWARD;
266     } else if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::DEFERRED) {
267         pipelineType = RenderCamera::RenderPipelineType::DEFERRED;
268     } else if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::CUSTOM) {
269         pipelineType = RenderCamera::RenderPipelineType::CUSTOM;
270     }
271     return pipelineType;
272 }
273 
ValidateRenderCamera(RenderCamera & camera)274 void ValidateRenderCamera(RenderCamera& camera)
275 {
276     if (camera.renderPipelineType == RenderCamera::RenderPipelineType::DEFERRED) {
277         if (camera.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_MSAA_BIT) {
278             camera.flags = camera.flags & (~RenderCamera::CameraFlagBits::CAMERA_FLAG_MSAA_BIT);
279 #if (CORE3D_VALIDATION_ENABLED == 1)
280             CORE_LOG_ONCE_I("valid_r_c" + to_string(camera.id),
281                 "MSAA flag with deferred pipeline dropped (cam id %" PRIu64 ")", camera.id);
282 #endif
283         }
284     }
285 }
286 
GetPostProcessName(const IPostProcessComponentManager * postProcessMgr,const IPostProcessConfigurationComponentManager * postProcessConfigMgr,const INameComponentManager * nameMgr,const string_view sceneName,const Entity & entity)287 fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> GetPostProcessName(
288     const IPostProcessComponentManager* postProcessMgr,
289     const IPostProcessConfigurationComponentManager* postProcessConfigMgr, const INameComponentManager* nameMgr,
290     const string_view sceneName, const Entity& entity)
291 {
292     if (postProcessMgr && postProcessConfigMgr && nameMgr) {
293         if (postProcessMgr->HasComponent(entity) || postProcessConfigMgr->HasComponent(entity)) {
294             if (ScopedHandle<const NameComponent> nameHandle = nameMgr->Read(entity);
295                 nameHandle && (!nameHandle->name.empty())) {
296                 return fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> { nameHandle->name };
297             } else {
298                 // checks if any of the post process mgrs has valid entity for camera
299                 fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> ret =
300                     DefaultMaterialCameraConstants::CAMERA_POST_PROCESS_PREFIX_NAME;
301                 ret.append(sceneName);
302                 ret.append(to_hex(entity.id));
303                 return ret;
304             }
305         }
306     }
307     return (DefaultMaterialCameraConstants::CAMERA_POST_PROCESS_PREFIX_NAME);
308 }
309 
GetPostProcessRenderNodeGraph(const IPostProcessConfigurationComponentManager * postProcessConfigMgr,const Entity & entity)310 string GetPostProcessRenderNodeGraph(
311     const IPostProcessConfigurationComponentManager* postProcessConfigMgr, const Entity& entity)
312 {
313     if (postProcessConfigMgr) {
314         if (const auto handle = postProcessConfigMgr->Read(entity); handle) {
315             return handle->customRenderNodeGraphFile;
316         }
317     }
318     return {};
319 }
320 
GetCameraName(INameComponentManager & nameMgr,const Entity & entity)321 inline fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> GetCameraName(
322     INameComponentManager& nameMgr, const Entity& entity)
323 {
324     fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> ret;
325     if (ScopedHandle<const NameComponent> nameHandle = nameMgr.Read(entity);
326         nameHandle && (!nameHandle->name.empty())) {
327         ret.append(nameHandle->name);
328     } else {
329         ret.append(to_hex(entity.id));
330     }
331     return ret;
332 }
333 
334 // does not update all the variables
FillRenderCameraBaseFromCameraComponent(const IRenderHandleComponentManager & renderHandleMgr,const CameraComponent & cc,RenderCamera & renderCamera,const bool checkCustomTargets)335 void FillRenderCameraBaseFromCameraComponent(const IRenderHandleComponentManager& renderHandleMgr,
336     const CameraComponent& cc, RenderCamera& renderCamera, const bool checkCustomTargets)
337 {
338     renderCamera.layerMask = cc.layerMask;
339     renderCamera.viewport = { cc.viewport[0u], cc.viewport[1u], cc.viewport[2u], cc.viewport[3u] };
340     renderCamera.scissor = { cc.scissor[0u], cc.scissor[1u], cc.scissor[2u], cc.scissor[3u] };
341     renderCamera.renderResolution = { cc.renderResolution[0u], cc.renderResolution[1u] };
342     renderCamera.zNear = cc.zNear;
343     renderCamera.zFar = cc.zFar;
344     renderCamera.flags = GetRenderCameraFlagsFromComponentFlags(cc.pipelineFlags);
345     renderCamera.clearDepthStencil = { cc.clearDepthValue, 0u };
346     renderCamera.clearColorValues = { cc.clearColorValue.x, cc.clearColorValue.y, cc.clearColorValue.z,
347         cc.clearColorValue.w };
348     renderCamera.cullType = GetRenderCameraCullTypeFromComponent(cc.culling);
349     renderCamera.renderPipelineType = GetRenderCameraRenderPipelineTypeFromComponent(cc.renderingPipeline);
350     if (cc.customRenderNodeGraph) {
351         renderCamera.customRenderNodeGraph = renderHandleMgr.GetRenderHandleReference(cc.customRenderNodeGraph);
352     }
353     renderCamera.customRenderNodeGraphFile = cc.customRenderNodeGraphFile;
354     const uint32_t maxCount = BASE_NS::Math::min(static_cast<uint32_t>(cc.colorTargetCustomization.size()),
355         RenderSceneDataConstants::MAX_CAMERA_COLOR_TARGET_COUNT);
356     for (uint32_t idx = 0; idx < maxCount; ++idx) {
357         renderCamera.colorTargetCustomization[idx].format = cc.colorTargetCustomization[idx].format;
358         renderCamera.colorTargetCustomization[idx].usageFlags = cc.colorTargetCustomization[idx].usageFlags;
359     }
360     renderCamera.depthTargetCustomization.format = cc.depthTargetCustomization.format;
361     renderCamera.depthTargetCustomization.usageFlags = cc.depthTargetCustomization.usageFlags;
362 
363     if (checkCustomTargets && (cc.customColorTargets.size() > 0 || cc.customDepthTarget)) {
364         renderCamera.flags |= RenderCamera::CAMERA_FLAG_CUSTOM_TARGETS_BIT;
365         RenderHandleReference customColorTarget;
366         if (cc.customColorTargets.size() > 0) {
367             customColorTarget = renderHandleMgr.GetRenderHandleReference(cc.customColorTargets[0]);
368         }
369         RenderHandleReference customDepthTarget = renderHandleMgr.GetRenderHandleReference(cc.customDepthTarget);
370         if (customColorTarget.GetHandleType() != RenderHandleType::GPU_IMAGE) {
371             CORE_LOG_E("invalid custom render target(s) for camera (%s)", renderCamera.name.c_str());
372         }
373         renderCamera.depthTarget = move(customDepthTarget);
374         renderCamera.colorTargets[0u] = move(customColorTarget);
375     }
376 
377     const uint32_t maxMvCount = Math::min(
378         RenderSceneDataConstants::MAX_MULTI_VIEW_LAYER_CAMERA_COUNT, static_cast<uint32_t>(cc.multiViewCameras.size()));
379     for (uint32_t idx = 0; idx < maxMvCount; ++idx) {
380         const auto& mvRef = cc.multiViewCameras[idx];
381         if (EntityUtil::IsValid(mvRef)) {
382             renderCamera.multiViewCameraIds[renderCamera.multiViewCameraCount++] = mvRef.id;
383         }
384     }
385     if (renderCamera.multiViewCameraCount > 0U) {
386         if (renderCamera.renderPipelineType == RenderCamera::RenderPipelineType::LIGHT_FORWARD) {
387 #if (CORE3D_VALIDATION_ENABLED == 1)
388             CORE_LOG_ONCE_W(to_string(renderCamera.id) + "camera_pipeline_mv",
389                 "Camera rendering pipeline cannot be LIGHT_FORWARD for multi-view.");
390 #endif
391             renderCamera.renderPipelineType = RenderCamera::RenderPipelineType::FORWARD;
392         }
393     }
394 
395     ValidateRenderCamera(renderCamera);
396 }
397 
CreateColorPrePassRenderCamera(const IRenderHandleComponentManager & renderHandleMgr,const ICameraComponentManager & cameraMgr,const RenderCamera & baseCamera,const Entity & prePassEntity,const uint64_t uniqueId)398 RenderCamera CreateColorPrePassRenderCamera(const IRenderHandleComponentManager& renderHandleMgr,
399     const ICameraComponentManager& cameraMgr, const RenderCamera& baseCamera, const Entity& prePassEntity,
400     const uint64_t uniqueId)
401 {
402     RenderCamera rc = baseCamera;
403     rc.mainCameraId = baseCamera.id; // main camera for pre-pass
404     // reset targets, pre-pass does not support custom targets nor uses main camera targets
405     rc.depthTarget = {};
406     for (uint32_t idx = 0; idx < countof(rc.colorTargets); ++idx) {
407         rc.colorTargets[idx] = {};
408     }
409     // NOTE: LIGHT_FORWARD prevents additional HDR target creation
410     rc.renderPipelineType = RenderCamera::RenderPipelineType::LIGHT_FORWARD;
411     // by default these cannot be resolved for the pre-pass camera
412     // FillRenderCameraBaseFromCameraComponent handles these for actual pre-pass cameras
413     rc.customRenderNodeGraphFile.clear();
414     rc.customRenderNodeGraph = {};
415     if (const auto prePassCameraHandle = cameraMgr.Read(prePassEntity); prePassCameraHandle) {
416         FillRenderCameraBaseFromCameraComponent(renderHandleMgr, *prePassCameraHandle, rc, false);
417         rc.flags |= RenderCamera::CAMERA_FLAG_COLOR_PRE_PASS_BIT | RenderCamera::CAMERA_FLAG_OPAQUE_BIT |
418                     RenderCamera::CAMERA_FLAG_CLEAR_DEPTH_BIT | RenderCamera::CAMERA_FLAG_CLEAR_COLOR_BIT;
419         // NOTE: does not evaluate custom targets for pre-pass camera
420     } else {
421         // automatic reduction to half res.
422         rc.renderResolution = { static_cast<uint32_t>(static_cast<float>(rc.renderResolution[0]) * 0.5f),
423             static_cast<uint32_t>(static_cast<float>(rc.renderResolution[1]) * 0.5f) };
424         // NOTE: should better evaluate all the flags from the main camera
425         rc.flags = RenderCamera::CAMERA_FLAG_COLOR_PRE_PASS_BIT | RenderCamera::CAMERA_FLAG_OPAQUE_BIT |
426                    RenderCamera::CAMERA_FLAG_CLEAR_DEPTH_BIT | RenderCamera::CAMERA_FLAG_CLEAR_COLOR_BIT;
427     }
428     rc.name = to_string(uniqueId);
429     rc.id = uniqueId; // unique id for main pre-pass
430     rc.prePassColorTargetName = {};
431     rc.postProcessName = DefaultMaterialCameraConstants::CAMERA_PRE_PASS_POST_PROCESS_PREFIX_NAME;
432     return rc;
433 }
434 
FillRenderEnvironment(const IRenderHandleComponentManager & renderHandleMgr,const uint64_t & nodeLayerMask,const Entity & entity,const EnvironmentComponent & component,RenderCamera::Environment & renderEnv)435 void FillRenderEnvironment(const IRenderHandleComponentManager& renderHandleMgr, const uint64_t& nodeLayerMask,
436     const Entity& entity, const EnvironmentComponent& component, RenderCamera::Environment& renderEnv)
437 {
438     renderEnv.id = entity.id;
439     renderEnv.layerMask = nodeLayerMask;
440     renderEnv.shader = renderHandleMgr.GetRenderHandleReference(component.shader);
441     if (component.background == EnvironmentComponent::Background::NONE) {
442         renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_NONE;
443     } else if (component.background == EnvironmentComponent::Background::IMAGE) {
444         renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_IMAGE;
445     } else if (component.background == EnvironmentComponent::Background::CUBEMAP) {
446         renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_CUBEMAP;
447     } else if (component.background == EnvironmentComponent::Background::EQUIRECTANGULAR) {
448         renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_EQUIRECTANGULAR;
449     }
450     renderEnv.radianceCubemap = renderHandleMgr.GetRenderHandleReference(component.radianceCubemap);
451     renderEnv.radianceCubemapMipCount = component.radianceCubemapMipCount;
452     renderEnv.envMap = renderHandleMgr.GetRenderHandleReference(component.envMap);
453     renderEnv.envMapLodLevel = component.envMapLodLevel;
454     const size_t shCount =
455         std::min(countof(component.irradianceCoefficients), countof(renderEnv.shIndirectCoefficients));
456     for (size_t idx = 0; idx < shCount; ++idx) {
457         renderEnv.shIndirectCoefficients[idx] = Math::Vec4(component.irradianceCoefficients[idx], 1.0f);
458     }
459     renderEnv.indirectDiffuseFactor = component.indirectDiffuseFactor;
460     renderEnv.indirectSpecularFactor = component.indirectSpecularFactor;
461     renderEnv.envMapFactor = component.envMapFactor;
462     renderEnv.blendFactor = component.blendFactor;
463     renderEnv.rotation = component.environmentRotation;
464 }
465 
LerpVec4(const Math::Vec4 & vec0,const Math::Vec4 & vec1,const Math::Vec4 & blend)466 inline constexpr Math::Vec4 LerpVec4(const Math::Vec4& vec0, const Math::Vec4& vec1, const Math::Vec4& blend)
467 {
468     return Math::Vec4(Math::lerp(vec0.x, vec1.x, blend.x), Math::lerp(vec0.y, vec1.y, blend.y),
469         Math::lerp(vec0.z, vec1.z, blend.z), Math::lerp(vec0.w, vec1.w, blend.w));
470 }
471 
FillCameraRenderEnvironment(IRenderDataStoreDefaultCamera * dsCamera,const CameraComponent & component,RenderCamera & camera)472 void FillCameraRenderEnvironment(
473     IRenderDataStoreDefaultCamera* dsCamera, const CameraComponent& component, RenderCamera& camera)
474 {
475     camera.environmentCount = 0U;
476 
477     // if dynamic cubemap is used, we create a new environment for camera id with default coefficients
478     if (component.pipelineFlags & CameraComponent::DYNAMIC_CUBEMAP_BIT) {
479         // copy base
480         camera.environment = dsCamera->GetEnvironment(camera.environmentIds[0U]);
481         // replace the main environment id
482         camera.environment.id = camera.id;
483         camera.environmentIds[camera.environmentCount] = camera.environment.id;
484         camera.environmentCount += 1U;
485         camera.environment.backgroundType = RenderCamera::Environment::BG_TYPE_CUBEMAP;
486     }
487     // if environments are empty, we use default
488     if (component.environments.empty()) {
489         const uint64_t id = (component.environment.id == Entity {}.id) ? RenderSceneDataConstants::INVALID_ID
490                                                                        : component.environment.id;
491         camera.environmentIds[camera.environmentCount++] = id;
492     } else {
493         const uint32_t maxCount = Math::min(static_cast<uint32_t>(component.environments.size()),
494             DefaultMaterialCameraConstants::MAX_ENVIRONMENT_COUNT - camera.environmentCount);
495         for (uint32_t idx = 0; idx < maxCount; ++idx) {
496             camera.environmentIds[camera.environmentCount++] = component.environments[idx].id;
497         }
498     }
499 
500     // fetch the main environment for camera for fast and easy access
501     if (camera.environment.id == RenderSceneDataConstants::INVALID_ID) {
502         camera.environment = dsCamera->GetEnvironment(camera.environmentIds[0U]);
503     }
504 
505     if (component.pipelineFlags & CameraComponent::DYNAMIC_CUBEMAP_BIT) {
506         // replace base environment values -> combine indirect diffuse values
507         auto& dynamicEnv = camera.environment;
508         dynamicEnv.indirectDiffuseFactor = Math::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
509         for (size_t idx = 0; idx < countof(dynamicEnv.shIndirectCoefficients); ++idx) {
510             dynamicEnv.shIndirectCoefficients[idx] = Math::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
511         }
512         Math::Vec4 blendFactor = Math::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
513         for (uint32_t envIdx = 1U; envIdx < camera.environmentCount; ++envIdx) {
514             const auto env = dsCamera->GetEnvironment(camera.environmentIds[envIdx]);
515             dynamicEnv.indirectDiffuseFactor =
516                 LerpVec4(dynamicEnv.indirectDiffuseFactor, env.indirectDiffuseFactor, blendFactor);
517             for (size_t idx = 0; idx < countof(dynamicEnv.shIndirectCoefficients); ++idx) {
518                 dynamicEnv.shIndirectCoefficients[idx] =
519                     LerpVec4(dynamicEnv.shIndirectCoefficients[idx], env.shIndirectCoefficients[idx], blendFactor);
520             }
521             blendFactor = env.blendFactor;
522         }
523 
524         // add the dynamic environment which has the indirect diffuse values blended (somewhat)
525         dsCamera->AddEnvironment(camera.environment);
526     }
527 }
528 
GetRenderCameraFogFromComponent(const ILayerComponentManager * layerMgr,const IFogComponentManager * fogMgr,const RenderConfigurationComponent & renderConfigurationComponent,const CameraComponent & cameraComponent)529 RenderCamera::Fog GetRenderCameraFogFromComponent(const ILayerComponentManager* layerMgr,
530     const IFogComponentManager* fogMgr, const RenderConfigurationComponent& renderConfigurationComponent,
531     const CameraComponent& cameraComponent)
532 {
533     RenderCamera::Fog renderFog;
534     if (!(layerMgr && fogMgr)) {
535         return renderFog;
536     }
537 
538     auto fillRenderFog = [](const uint64_t& nodeLayerMask, const Entity& entity, const FogComponent& component,
539                              RenderCamera::Fog& renderFog) {
540         renderFog.id = entity.id;
541         renderFog.layerMask = nodeLayerMask;
542 
543         renderFog.firstLayer = { component.density, component.heightFalloff, component.heightFogOffset, 0.0f };
544         renderFog.secondLayer = { component.layerDensity, component.layerHeightFalloff, component.layerHeightFogOffset,
545             0.0f };
546         renderFog.baseFactors = { component.startDistance, component.cuttoffDistance, component.maxOpacity, 0.0f };
547         renderFog.inscatteringColor = component.inscatteringColor;
548         renderFog.envMapFactor = component.envMapFactor;
549         renderFog.additionalFactor = component.additionalFactor;
550     };
551 
552     const Entity cameraFogEntity = cameraComponent.fog;
553     // Check if camera has a valid fog
554     Entity fogEntity = cameraFogEntity;
555     auto fogId = fogMgr->GetComponentId(fogEntity);
556     if (fogId == IComponentManager::INVALID_COMPONENT_ID) {
557         // Next try if the scene has a valid fog
558         fogEntity = renderConfigurationComponent.fog;
559         fogId = fogMgr->GetComponentId(fogEntity);
560     }
561     if (fogId != IComponentManager::INVALID_COMPONENT_ID) {
562         if (auto fogDataHandle = fogMgr->Read(fogId); fogDataHandle) {
563             const FogComponent& fogComponent = *fogDataHandle;
564             uint64_t layerMask = LayerConstants::DEFAULT_LAYER_MASK;
565             if (auto layerHandle = layerMgr->Read(fogEntity); layerHandle) {
566                 layerMask = layerHandle->layerMask;
567             }
568 
569             fillRenderFog(layerMask, fogEntity, fogComponent, renderFog);
570         }
571     }
572 
573     return renderFog;
574 }
575 
GetRenderShadowTypes(const RenderConfigurationComponent & renderConfigurationComponent)576 constexpr IRenderDataStoreDefaultLight::ShadowTypes GetRenderShadowTypes(
577     const RenderConfigurationComponent& renderConfigurationComponent)
578 {
579     IRenderDataStoreDefaultLight::ShadowTypes st { IRenderDataStoreDefaultLight::ShadowType::PCF,
580         IRenderDataStoreDefaultLight::ShadowQuality::NORMAL, IRenderDataStoreDefaultLight::ShadowSmoothness::NORMAL };
581     st.shadowType = (renderConfigurationComponent.shadowType == RenderConfigurationComponent::SceneShadowType::VSM)
582                         ? IRenderDataStoreDefaultLight::ShadowType::VSM
583                         : IRenderDataStoreDefaultLight::ShadowType::PCF;
584     if (renderConfigurationComponent.shadowQuality == RenderConfigurationComponent::SceneShadowQuality::LOW) {
585         st.shadowQuality = IRenderDataStoreDefaultLight::ShadowQuality::LOW;
586     } else if (renderConfigurationComponent.shadowQuality == RenderConfigurationComponent::SceneShadowQuality::HIGH) {
587         st.shadowQuality = IRenderDataStoreDefaultLight::ShadowQuality::HIGH;
588     } else if (renderConfigurationComponent.shadowQuality == RenderConfigurationComponent::SceneShadowQuality::ULTRA) {
589         st.shadowQuality = IRenderDataStoreDefaultLight::ShadowQuality::ULTRA;
590     }
591     if (renderConfigurationComponent.shadowSmoothness == RenderConfigurationComponent::SceneShadowSmoothness::HARD) {
592         st.shadowSmoothness = IRenderDataStoreDefaultLight::ShadowSmoothness::HARD;
593     } else if (renderConfigurationComponent.shadowSmoothness ==
594                RenderConfigurationComponent::SceneShadowSmoothness::SOFT) {
595         st.shadowSmoothness = IRenderDataStoreDefaultLight::ShadowSmoothness::SOFT;
596     }
597     return st;
598 }
599 
MaterialHandles(const MaterialComponent & materialDesc,const IRenderHandleComponentManager & gpuManager)600 RenderDataDefaultMaterial::MaterialHandles MaterialHandles(
601     const MaterialComponent& materialDesc, const IRenderHandleComponentManager& gpuManager)
602 {
603     RenderDataDefaultMaterial::MaterialHandles materialHandles;
604     auto imageIt = std::begin(materialHandles.images);
605     auto samplerIt = std::begin(materialHandles.samplers);
606     for (const MaterialComponent::TextureInfo& info : materialDesc.textures) {
607         *imageIt++ = gpuManager.GetRenderHandleReference(info.image);
608         *samplerIt++ = gpuManager.GetRenderHandleReference(info.sampler);
609     }
610     return materialHandles;
611 }
612 
RenderMaterialLightingFlagsFromMaterialFlags(const MaterialComponent::LightingFlags materialFlags)613 constexpr uint32_t RenderMaterialLightingFlagsFromMaterialFlags(const MaterialComponent::LightingFlags materialFlags)
614 {
615     uint32_t rmf = 0;
616     if (materialFlags & MaterialComponent::LightingFlagBits::SHADOW_RECEIVER_BIT) {
617         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_SHADOW_RECEIVER_BIT;
618     }
619     if (materialFlags & MaterialComponent::LightingFlagBits::SHADOW_CASTER_BIT) {
620         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_SHADOW_CASTER_BIT;
621     }
622     if (materialFlags & MaterialComponent::LightingFlagBits::PUNCTUAL_LIGHT_RECEIVER_BIT) {
623         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_PUNCTUAL_LIGHT_RECEIVER_BIT;
624     }
625     if (materialFlags & MaterialComponent::LightingFlagBits::INDIRECT_LIGHT_RECEIVER_BIT) {
626         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_INDIRECT_LIGHT_RECEIVER_BIT;
627     }
628     return rmf;
629 }
630 
RenderSubmeshFlagsFromMeshFlags(const MeshComponent::Submesh::Flags flags)631 constexpr uint32_t RenderSubmeshFlagsFromMeshFlags(const MeshComponent::Submesh::Flags flags)
632 {
633     uint32_t rmf = 0;
634     if (flags & MeshComponent::Submesh::FlagBits::TANGENTS_BIT) {
635         rmf |= RenderSubmeshFlagBits::RENDER_SUBMESH_TANGENTS_BIT;
636     }
637     if (flags & MeshComponent::Submesh::FlagBits::VERTEX_COLORS_BIT) {
638         rmf |= RenderSubmeshFlagBits::RENDER_SUBMESH_VERTEX_COLORS_BIT;
639     }
640     if (flags & MeshComponent::Submesh::FlagBits::SKIN_BIT) {
641         rmf |= RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT;
642     }
643     if (flags & MeshComponent::Submesh::FlagBits::SECOND_TEXCOORD_BIT) {
644         rmf |= RenderSubmeshFlagBits::RENDER_SUBMESH_SECOND_TEXCOORD_BIT;
645     }
646     return rmf;
647 }
648 
RenderMaterialFlagsFromMaterialValues(const MaterialComponent & matComp,const RenderDataDefaultMaterial::MaterialHandles & handles,const uint32_t hasTransformBit,const bool enableGpuInstancing)649 uint32_t RenderMaterialFlagsFromMaterialValues(const MaterialComponent& matComp,
650     const RenderDataDefaultMaterial::MaterialHandles& handles, const uint32_t hasTransformBit,
651     const bool enableGpuInstancing)
652 {
653     uint32_t rmf = 0;
654     // enable built-in specialization for default materials
655     CORE_ASSERT(matComp.type <= MaterialComponent::Type::CUSTOM_COMPLEX);
656     if (matComp.type < MaterialComponent::Type::CUSTOM) {
657         if (handles.images[MaterialComponent::TextureIndex::NORMAL] ||
658             handles.images[MaterialComponent::TextureIndex::CLEARCOAT_NORMAL]) {
659             // need to check for tangents as well with submesh
660             rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_NORMAL_MAP_BIT;
661         }
662         if (matComp.textures[MaterialComponent::TextureIndex::CLEARCOAT].factor.x > 0.0f) {
663             rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_CLEAR_COAT_BIT;
664         }
665         if ((matComp.textures[MaterialComponent::TextureIndex::SHEEN].factor.x > 0.0f) ||
666             (matComp.textures[MaterialComponent::TextureIndex::SHEEN].factor.y > 0.0f) ||
667             (matComp.textures[MaterialComponent::TextureIndex::SHEEN].factor.z > 0.0f)) {
668             rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_SHEEN_BIT;
669         }
670         if (matComp.textures[MaterialComponent::TextureIndex::SPECULAR].factor != Math::Vec4(1.f, 1.f, 1.f, 1.f) ||
671             handles.images[MaterialComponent::TextureIndex::SPECULAR]) {
672             rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_SPECULAR_BIT;
673         }
674         if (matComp.textures[MaterialComponent::TextureIndex::TRANSMISSION].factor.x > 0.0f) {
675             rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_TRANSMISSION_BIT;
676         }
677     }
678     rmf |= (hasTransformBit > 0U) ? RenderMaterialFlagBits::RENDER_MATERIAL_TEXTURE_TRANSFORM_BIT : 0U;
679     // NOTE: built-in shaders write 1.0 to alpha always when discard is enabled
680     rmf |= (matComp.alphaCutoff < 1.0f) ? RenderMaterialFlagBits::RENDER_MATERIAL_SHADER_DISCARD_BIT : 0U;
681     // enables instacing and specializes the shader
682     rmf |= (enableGpuInstancing) ? RenderMaterialFlagBits::RENDER_MATERIAL_GPU_INSTANCING_BIT : 0U;
683     // NOTE: earlier version had MASK here for opaque bit as well
684     return rmf;
685 }
686 
FillPostProcessConfigurationVars(const PostProcessConfigurationComponent::PostProcessEffect & pp)687 IRenderDataStorePostProcess::PostProcess::Variables FillPostProcessConfigurationVars(
688     const PostProcessConfigurationComponent::PostProcessEffect& pp)
689 {
690     IRenderDataStorePostProcess::PostProcess::Variables vars;
691     vars.userFactorIndex = pp.globalUserFactorIndex;
692     // NOTE: shader cannot be changed here
693     vars.factor = pp.factor;
694     vars.enabled = pp.enabled;
695     vars.flags = pp.flags;
696     if (pp.customProperties) {
697         array_view<const uint8_t> customData =
698             array_view(static_cast<const uint8_t*>(pp.customProperties->RLock()), pp.customProperties->Size());
699         const size_t copyByteSize = Math::min(countof(vars.customPropertyData), customData.size_bytes());
700         CloneData(vars.customPropertyData, countof(vars.customPropertyData), customData.data(), copyByteSize);
701         pp.customProperties->RUnlock();
702     }
703     return vars;
704 }
705 
706 #if (CORE3D_VALIDATION_ENABLED == 1)
ValidateInputColor(const Entity material,const MaterialComponent & matComp)707 void ValidateInputColor(const Entity material, const MaterialComponent& matComp)
708 {
709     if (matComp.type < MaterialComponent::Type::CUSTOM) {
710         const auto& base = matComp.textures[MaterialComponent::TextureIndex::BASE_COLOR];
711         if ((base.factor.x > 1.0f) || (base.factor.y > 1.0f) || (base.factor.z > 1.0f) || (base.factor.w > 1.0f)) {
712             CORE_LOG_ONCE_W(to_string(material.id) + "_base_fac",
713                 "CORE3D_VALIDATION: Non custom material type expects base color factor to be <= 1.0f.");
714         }
715         const auto& mat = matComp.textures[MaterialComponent::TextureIndex::MATERIAL];
716         if ((mat.factor.y > 1.0f) || (mat.factor.z > 1.0f)) {
717             CORE_LOG_ONCE_W(to_string(material.id) + "_mat_fac",
718                 "CORE3D_VALIDATION: Non custom material type expects roughness and metallic to be <= 1.0f.");
719         }
720     }
721 }
722 #endif
723 
InputMaterialUniformsFromMaterialComponent(const Entity material,const MaterialComponent & matDesc)724 RenderDataDefaultMaterial::InputMaterialUniforms InputMaterialUniformsFromMaterialComponent(
725     const Entity material, const MaterialComponent& matDesc)
726 {
727     static constexpr const RenderDataDefaultMaterial::InputMaterialUniforms defaultInput {};
728     RenderDataDefaultMaterial::InputMaterialUniforms mu = defaultInput;
729 
730 #if (CORE3D_VALIDATION_ENABLED == 1)
731     ValidateInputColor(material, matDesc);
732 #endif
733 
734     uint32_t transformBits = 0u;
735     static constexpr const uint32_t texCount =
736         Math::min(static_cast<uint32_t>(MaterialComponent::TextureIndex::TEXTURE_COUNT),
737             RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT);
738     for (uint32_t idx = 0u; idx < texCount; ++idx) {
739         const auto& tex = matDesc.textures[idx];
740         auto& texRef = mu.textureData[idx];
741         texRef.factor = tex.factor;
742         texRef.translation = tex.transform.translation;
743         texRef.rotation = tex.transform.rotation;
744         texRef.scale = tex.transform.scale;
745         const bool hasTransform = (texRef.translation.x != 0.0f) || (texRef.translation.y != 0.0f) ||
746                                   (texRef.rotation != 0.0f) || (texRef.scale.x != 1.0f) || (texRef.scale.y != 1.0f);
747         transformBits |= static_cast<uint32_t>(hasTransform) << idx;
748     }
749     {
750         // NOTE: premultiplied alpha, applied here and therefore the baseColor factor is special
751         const auto& tex = matDesc.textures[MaterialComponent::TextureIndex::BASE_COLOR];
752         const float alpha = tex.factor.w;
753         const Math::Vec4 baseColor = {
754             tex.factor.x * alpha,
755             tex.factor.y * alpha,
756             tex.factor.z * alpha,
757             alpha,
758         };
759 
760         constexpr uint32_t index = 0u;
761         mu.textureData[index].factor = baseColor;
762     }
763     mu.alphaCutoff = matDesc.alphaCutoff;
764     mu.texCoordSetBits = matDesc.useTexcoordSetBit;
765     mu.texTransformSetBits = transformBits;
766     mu.id = material.id;
767     return mu;
768 }
769 
770 BEGIN_PROPERTY(IRenderSystem::Properties, ComponentMetadata)
771     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreMaterial, "dataStoreMaterial", 0)
772     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreCamera, "dataStoreCamera", 0)
773     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreLight, "dataStoreLight", 0)
774     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreScene, "dataStoreScene", 0)
775     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreMorph, "dataStoreMorph", 0)
776     DECL_PROPERTY2(IRenderSystem::Properties, dataStorePrefix, "", 0)
777 END_PROPERTY();
778 
SetupSubmeshBuffers(const IRenderHandleComponentManager & renderHandleManager,const MeshComponent & desc,const MeshComponent::Submesh & submesh,RenderSubmesh & renderSubmesh)779 void SetupSubmeshBuffers(const IRenderHandleComponentManager& renderHandleManager, const MeshComponent& desc,
780     const MeshComponent::Submesh& submesh, RenderSubmesh& renderSubmesh)
781 {
782     CORE_STATIC_ASSERT(
783         MeshComponent::Submesh::BUFFER_COUNT <= RENDER_NS::PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT);
784     // calculate real vertex buffer count and fill "safety" handles for default material
785     // no default shader variants without joints etc.
786     // NOTE:
787     // optimize for minimal GetRenderHandleReference calls
788     // often the same vertex buffer is used.
789     Entity prevEntity = {};
790     for (size_t idx = 0; idx < countof(submesh.bufferAccess); ++idx) {
791         const auto& acc = submesh.bufferAccess[idx];
792         auto& vb = renderSubmesh.vertexBuffers[idx];
793         if (EntityUtil::IsValid(prevEntity) && (prevEntity == acc.buffer)) {
794             vb.bufferHandle = renderSubmesh.vertexBuffers[idx - 1].bufferHandle;
795             vb.bufferOffset = acc.offset;
796             vb.byteSize = acc.byteSize;
797         } else if (acc.buffer) {
798             vb.bufferHandle = renderHandleManager.GetRenderHandleReference(acc.buffer);
799             vb.bufferOffset = acc.offset;
800             vb.byteSize = acc.byteSize;
801 
802             // store the previous entity
803             prevEntity = acc.buffer;
804         } else {
805             vb.bufferHandle = renderSubmesh.vertexBuffers[0].bufferHandle; // expecting safety binding
806             vb.bufferOffset = 0;
807             vb.byteSize = 0;
808         }
809     }
810 
811     // NOTE: we will get max amount of vertex buffers if there is at least one
812     renderSubmesh.vertexBufferCount =
813         submesh.bufferAccess[0U].buffer ? static_cast<uint32_t>(countof(submesh.bufferAccess)) : 0U;
814 
815     if (submesh.indexBuffer.buffer) {
816         renderSubmesh.indexBuffer.bufferHandle =
817             renderHandleManager.GetRenderHandleReference(submesh.indexBuffer.buffer);
818         renderSubmesh.indexBuffer.bufferOffset = submesh.indexBuffer.offset;
819         renderSubmesh.indexBuffer.byteSize = submesh.indexBuffer.byteSize;
820         renderSubmesh.indexBuffer.indexType = submesh.indexBuffer.indexType;
821     }
822     if (submesh.indirectArgsBuffer.buffer) {
823         renderSubmesh.indirectArgsBuffer.bufferHandle =
824             renderHandleManager.GetRenderHandleReference(submesh.indirectArgsBuffer.buffer);
825         renderSubmesh.indirectArgsBuffer.bufferOffset = submesh.indirectArgsBuffer.offset;
826         renderSubmesh.indirectArgsBuffer.byteSize = submesh.indirectArgsBuffer.byteSize;
827     }
828 
829     // Set submesh flags.
830     renderSubmesh.submeshFlags = RenderSubmeshFlagsFromMeshFlags(submesh.flags);
831 }
832 
GetRenderHandleReferences(const IRenderHandleComponentManager & renderHandleMgr,const array_view<const EntityReference> inputs,array_view<RenderHandleReference> & outputs)833 void GetRenderHandleReferences(const IRenderHandleComponentManager& renderHandleMgr,
834     const array_view<const EntityReference> inputs, array_view<RenderHandleReference>& outputs)
835 {
836     for (size_t idx = 0; idx < outputs.size(); ++idx) {
837         outputs[idx] = renderHandleMgr.GetRenderHandleReference(inputs[idx]);
838     }
839 }
840 
841 struct RenderMaterialIndices {
842     uint32_t materialIndex { ~0u };
843     uint32_t materialCustomResourceIndex { ~0u };
844 };
AddSingleMaterial(const IMaterialComponentManager & materialMgr,const IMaterialExtensionComponentManager & materialExtMgr,const IRenderHandleComponentManager & renderHandleMgr,IRenderDataStoreDefaultMaterial & dataStoreMaterial,const Entity & material,const bool fetchMaterialHandles,const bool checkExtMaterial,const uint32_t materialIndex,const uint32_t matInstanceIndex,const uint32_t matInstanceCount,const bool enableGpuInstancing)845 RenderMaterialIndices AddSingleMaterial(const IMaterialComponentManager& materialMgr,
846     const IMaterialExtensionComponentManager& materialExtMgr, const IRenderHandleComponentManager& renderHandleMgr,
847     IRenderDataStoreDefaultMaterial& dataStoreMaterial, const Entity& material, const bool fetchMaterialHandles,
848     const bool checkExtMaterial, const uint32_t materialIndex, const uint32_t matInstanceIndex,
849     const uint32_t matInstanceCount, const bool enableGpuInstancing)
850 {
851     RenderMaterialIndices rmi { materialIndex, ~0u };
852     // scoped
853     auto matData = materialMgr.Read(material);
854     const MaterialComponent& materialComp = (matData) ? *matData : DEF_MATERIAL_COMPONENT;
855     RenderDataDefaultMaterial::InputMaterialUniforms materialUniforms =
856         InputMaterialUniformsFromMaterialComponent(material, materialComp);
857 
858     array_view<const uint8_t> customData;
859     if (materialComp.customProperties) {
860         const auto buffer = static_cast<const uint8_t*>(materialComp.customProperties->RLock());
861         // NOTE: set and binding are currently not supported, we only support built-in mapping
862         // the data goes to a predefined set and binding
863         customData = array_view(buffer, materialComp.customProperties->Size());
864         materialComp.customProperties->RUnlock();
865     }
866     // material extensions
867     if (checkExtMaterial) {
868         // first check the preferred vector version
869         if (!materialComp.customResources.empty()) {
870             RenderHandleReference handleReferences[MaterialExtensionComponent::ResourceIndex::RESOURCE_COUNT];
871             const size_t maxCount = Math::min(static_cast<size_t>(materialComp.customResources.size()),
872                 static_cast<size_t>(MaterialExtensionComponent::ResourceIndex::RESOURCE_COUNT));
873             array_view<RenderHandleReference> handles = { handleReferences, maxCount };
874             GetRenderHandleReferences(renderHandleMgr, materialComp.customResources, handles);
875             rmi.materialCustomResourceIndex = dataStoreMaterial.AddMaterialCustomResources(material.id, handles);
876         } else if (const auto matExtHandle = materialExtMgr.Read(material); matExtHandle) {
877             RenderHandleReference handleReferences[MaterialExtensionComponent::ResourceIndex::RESOURCE_COUNT];
878             const MaterialExtensionComponent& matExtComp = *matExtHandle;
879             std::transform(std::begin(matExtComp.resources), std::end(matExtComp.resources),
880                 std::begin(handleReferences), [&renderHandleMgr](const EntityReference& matEntity) {
881                     return renderHandleMgr.GetRenderHandleReference(matEntity);
882                 });
883             // bind all handles, invalid handles are just ignored
884             rmi.materialCustomResourceIndex =
885                 dataStoreMaterial.AddMaterialCustomResources(material.id, handleReferences);
886         }
887     }
888     // optimization for e.g. with batch GPU instancing (we do not care about material handles)
889     if (fetchMaterialHandles) {
890         const RenderDataDefaultMaterial::MaterialHandles materialHandles =
891             MaterialHandles(materialComp, renderHandleMgr);
892         const uint32_t transformBits = materialUniforms.texTransformSetBits;
893 
894         const RenderMaterialFlags rmfFromBits =
895             RenderMaterialLightingFlagsFromMaterialFlags(materialComp.materialLightingFlags);
896         const RenderMaterialFlags rmfFromValues =
897             RenderMaterialFlagsFromMaterialValues(materialComp, materialHandles, transformBits, enableGpuInstancing);
898         const RenderMaterialFlags rmf = rmfFromBits | rmfFromValues;
899         const RenderDataDefaultMaterial::MaterialData data {
900             RenderMaterialType(materialComp.type),
901             materialComp.extraRenderingFlags,
902             rmf,
903             materialComp.customRenderSlotId,
904             { renderHandleMgr.GetRenderHandleReference(materialComp.materialShader.shader),
905                 renderHandleMgr.GetRenderHandleReference(materialComp.materialShader.graphicsState) },
906             { renderHandleMgr.GetRenderHandleReference(materialComp.depthShader.shader),
907                 renderHandleMgr.GetRenderHandleReference(materialComp.depthShader.graphicsState) },
908         };
909 
910         dataStoreMaterial.AddInstanceMaterialData(
911             materialIndex, matInstanceIndex, matInstanceCount, materialUniforms, materialHandles, data, customData);
912     } else {
913         dataStoreMaterial.AddInstanceMaterialData(
914             materialIndex, matInstanceIndex, matInstanceCount, materialUniforms, customData);
915     }
916     return rmi;
917 }
918 
AddRenderMaterial(IMaterialComponentManager & materialMgr,IMaterialExtensionComponentManager & materialExtMgr,IRenderHandleComponentManager & renderHandleMgr,IRenderDataStoreDefaultMaterial & dataStoreMaterial,const Entity & material,const uint32_t instanceCount,const bool duplicateMaterialInstances)919 RenderMaterialIndices AddRenderMaterial(IMaterialComponentManager& materialMgr,
920     IMaterialExtensionComponentManager& materialExtMgr, IRenderHandleComponentManager& renderHandleMgr,
921     IRenderDataStoreDefaultMaterial& dataStoreMaterial, const Entity& material, const uint32_t instanceCount,
922     const bool duplicateMaterialInstances)
923 {
924     const uint32_t materialDuplicateInstanceCount = duplicateMaterialInstances ? instanceCount : 0u;
925     const auto matIndices = dataStoreMaterial.GetMaterialIndices(material.id, instanceCount);
926     RenderMaterialIndices indices = { matIndices.materialIndex, matIndices.materialCustomResourceIndex };
927     if (indices.materialIndex == RenderSceneDataConstants::INVALID_INDEX) {
928         indices.materialIndex = dataStoreMaterial.AllocateMaterials(material.id, instanceCount);
929         const bool enableGpuInstancing = (instanceCount > 1U);
930         // indices, might add extension index
931         // material extensions are checked only when material entity is valid i.e. not default material.
932         indices = AddSingleMaterial(materialMgr, materialExtMgr, renderHandleMgr, dataStoreMaterial, material, true,
933             EntityUtil::IsValid(material), indices.materialIndex, 0U, materialDuplicateInstanceCount,
934             enableGpuInstancing);
935     }
936     return indices;
937 }
938 
939 // Extended sign: returns -1, 0 or 1 based on sign of a
Sgn(float a)940 float Sgn(float a)
941 {
942     if (a > 0.0f) {
943         return 1.0f;
944     }
945 
946     if (a < 0.0f) {
947         return -1.0f;
948     }
949 
950     return 0.0f;
951 }
952 
953 struct ReflectionPlaneTargetUpdate {
954     bool recreated { false };
955     uint32_t mipCount { 1u };
956 };
957 
UpdateReflectionPlaneMaterial(IRenderMeshComponentManager & renderMeshMgr,IMeshComponentManager & meshMgr,IMaterialComponentManager & materialMgr,const Entity & entity,const PlanarReflectionComponent & reflComponent,const ReflectionPlaneTargetUpdate & rptu)958 void UpdateReflectionPlaneMaterial(IRenderMeshComponentManager& renderMeshMgr, IMeshComponentManager& meshMgr,
959     IMaterialComponentManager& materialMgr, const Entity& entity, const PlanarReflectionComponent& reflComponent,
960     const ReflectionPlaneTargetUpdate& rptu)
961 {
962     // update material
963     if (const auto rmcHandle = renderMeshMgr.Read(entity); rmcHandle) {
964         const RenderMeshComponent& rmc = *rmcHandle;
965         if (const auto meshHandle = meshMgr.Read(rmc.mesh); meshHandle) {
966             const MeshComponent& meshComponent = *meshHandle;
967             if (!meshComponent.submeshes.empty()) {
968                 if (auto matHandle = materialMgr.Write(meshComponent.submeshes[0].material); matHandle) {
969                     MaterialComponent& matComponent = *matHandle;
970                     // NOTE: CLEARCOAT_ROUGHNESS cannot be used due to material flags bit is enabled for lighting
971                     matComponent.textures[MaterialComponent::TextureIndex::CLEARCOAT_ROUGHNESS].factor = {
972                         static_cast<float>(rptu.mipCount),
973                         reflComponent.screenPercentage,
974                         static_cast<float>(reflComponent.renderTargetResolution[0u]),
975                         static_cast<float>(reflComponent.renderTargetResolution[1u]),
976                     };
977                 }
978             }
979         }
980     }
981 }
982 
UpdatePlaneReflectionTargetResolution(IGpuResourceManager & gpuResourceMgr,IRenderHandleComponentManager & gpuHandleMgr,IPlanarReflectionComponentManager & planarReflMgr,const RenderCamera & sceneCamera,const Entity & entity,PlanarReflectionComponent & reflComp)983 ReflectionPlaneTargetUpdate UpdatePlaneReflectionTargetResolution(IGpuResourceManager& gpuResourceMgr,
984     IRenderHandleComponentManager& gpuHandleMgr, IPlanarReflectionComponentManager& planarReflMgr,
985     const RenderCamera& sceneCamera, const Entity& entity, PlanarReflectionComponent& reflComp)
986 {
987     // NOTE: if the resource is not yet created one should attach it to material as well
988     // these resources should be un-named
989     const uint32_t newWidth =
990         std::max(static_cast<uint32_t>(static_cast<float>(sceneCamera.renderResolution.x) * reflComp.screenPercentage),
991             reflComp.renderTargetResolution[0]);
992     const uint32_t newHeight =
993         std::max(static_cast<uint32_t>(static_cast<float>(sceneCamera.renderResolution.y) * reflComp.screenPercentage),
994             reflComp.renderTargetResolution[1]);
995 
996     ReflectionPlaneTargetUpdate rptu;
997 
998     const RenderHandle colorRenderTarget = gpuHandleMgr.GetRenderHandle(reflComp.colorRenderTarget);
999     const RenderHandle depthRenderTarget = gpuHandleMgr.GetRenderHandle(reflComp.depthRenderTarget);
1000     // get current mip count
1001     rptu.mipCount = RenderHandleUtil::IsValid(colorRenderTarget)
1002                         ? gpuResourceMgr.GetImageDescriptor(gpuResourceMgr.Get(colorRenderTarget)).mipCount
1003                         : 1u;
1004     if ((!RenderHandleUtil::IsValid(colorRenderTarget)) || (!RenderHandleUtil::IsValid(depthRenderTarget)) ||
1005         (newWidth > reflComp.renderTargetResolution[0]) || (newHeight > reflComp.renderTargetResolution[1])) {
1006         auto reCreateGpuImage = [](IGpuResourceManager& gpuResourceMgr, uint64_t id, RenderHandle handle,
1007                                     uint32_t newWidth, uint32_t newHeight, uint baseMipCount, bool depthImage) {
1008             GpuImageDesc desc = RenderHandleUtil::IsValid(handle)
1009                                     ? gpuResourceMgr.GetImageDescriptor(gpuResourceMgr.Get(handle))
1010                                     : CreateReflectionPlaneGpuImageDesc(depthImage);
1011             desc.mipCount = baseMipCount;
1012             desc.width = newWidth;
1013             desc.height = newHeight;
1014             if (RenderHandleUtil::IsValid(handle)) {
1015                 return gpuResourceMgr.Create(gpuResourceMgr.Get(handle), desc);
1016             } else {
1017                 return gpuResourceMgr.Create(desc);
1018             }
1019         };
1020         if (!EntityUtil::IsValid(reflComp.colorRenderTarget)) {
1021             reflComp.colorRenderTarget = gpuHandleMgr.GetEcs().GetEntityManager().CreateReferenceCounted();
1022             gpuHandleMgr.Create(reflComp.colorRenderTarget);
1023         }
1024         rptu.mipCount = Math::min(Math::max(DefaultMaterialCameraConstants::REFLECTION_PLANE_MIP_COUNT, rptu.mipCount),
1025             static_cast<uint32_t>(std::log2f(static_cast<float>(std::max(newWidth, newHeight)))) + 1u);
1026         gpuHandleMgr.Write(reflComp.colorRenderTarget)->reference =
1027             reCreateGpuImage(gpuResourceMgr, entity.id, colorRenderTarget, newWidth, newHeight, rptu.mipCount, false);
1028 
1029         if (!EntityUtil::IsValid(reflComp.depthRenderTarget)) {
1030             reflComp.depthRenderTarget = gpuHandleMgr.GetEcs().GetEntityManager().CreateReferenceCounted();
1031             gpuHandleMgr.Create(reflComp.depthRenderTarget);
1032         }
1033         gpuHandleMgr.Write(reflComp.depthRenderTarget)->reference =
1034             reCreateGpuImage(gpuResourceMgr, entity.id, depthRenderTarget, newWidth, newHeight, 1u, true);
1035 
1036         reflComp.renderTargetResolution[0] = newWidth;
1037         reflComp.renderTargetResolution[1] = newHeight;
1038         rptu.recreated = true;
1039         planarReflMgr.Set(entity, reflComp);
1040     }
1041 
1042     return rptu;
1043 }
1044 
1045 // Given position and normal of the plane, calculates plane in camera space.
CalculateCameraSpaceClipPlane(const Math::Mat4X4 & view,Math::Vec3 pos,Math::Vec3 normal,float sideSign,float clipPlaneOffset)1046 inline Math::Vec4 CalculateCameraSpaceClipPlane(
1047     const Math::Mat4X4& view, Math::Vec3 pos, Math::Vec3 normal, float sideSign, float clipPlaneOffset)
1048 {
1049     const Math::Vec3 offsetPos = pos + normal * clipPlaneOffset;
1050     const Math::Vec3 cpos = Math::MultiplyPoint3X4(view, offsetPos);
1051     const Math::Vec3 cnormal = Math::Normalize(Math::MultiplyVector(view, normal)) * sideSign;
1052     return Math::Vec4(cnormal.x, cnormal.y, cnormal.z, -Math::Dot(cpos, cnormal));
1053 }
1054 
1055 // See http://aras-p.info/texts/obliqueortho.html
CalculateObliqueProjectionMatrix(Math::Mat4X4 & projection,const Math::Vec4 & plane)1056 inline void CalculateObliqueProjectionMatrix(Math::Mat4X4& projection, const Math::Vec4& plane)
1057 {
1058     const Math::Mat4X4 inverseProjection = Inverse(projection);
1059 
1060     const Math::Vec4 q = inverseProjection * Math::Vec4(Sgn(plane.x), Sgn(plane.y), 1.0f, 1.0f);
1061     const Math::Vec4 c = plane * (2.0f / Math::Dot(plane, q));
1062 
1063     projection.data[2u] = c.x;
1064     projection.data[6u] = c.y;
1065     projection.data[10u] = c.z;
1066     projection.data[14u] = c.w;
1067 }
1068 
1069 // Calculate reflection matrix from given matrix.
CalculateReflectionMatrix(const Math::Vec4 & plane)1070 Math::Mat4X4 CalculateReflectionMatrix(const Math::Vec4& plane)
1071 {
1072     Math::Mat4X4 result(1.0f);
1073 
1074     result.data[0u] = (1.0f - 2.0f * plane[0u] * plane[0u]);
1075     result.data[4u] = (-2.0f * plane[0u] * plane[1u]);
1076     result.data[8u] = (-2.0f * plane[0u] * plane[2u]);
1077     result.data[12u] = (-2.0f * plane[3u] * plane[0u]);
1078 
1079     result.data[1u] = (-2.0f * plane[1u] * plane[0u]);
1080     result.data[5u] = (1.0f - 2.0f * plane[1u] * plane[1u]);
1081     result.data[9u] = (-2.0f * plane[1u] * plane[2u]);
1082     result.data[13u] = (-2.0f * plane[3u] * plane[1u]);
1083 
1084     result.data[2u] = (-2.0f * plane[2u] * plane[0u]);
1085     result.data[6u] = (-2.0f * plane[2u] * plane[1u]);
1086     result.data[10u] = (1.0f - 2.0f * plane[2u] * plane[2u]);
1087     result.data[14u] = (-2.0f * plane[3u] * plane[2u]);
1088 
1089     result.data[3u] = 0.0f;
1090     result.data[7u] = 0.0f;
1091     result.data[11u] = 0.0f;
1092     result.data[15u] = 1.0f;
1093 
1094     return result;
1095 }
1096 
LogBatchValidation(const MeshComponent & mesh)1097 inline void LogBatchValidation(const MeshComponent& mesh)
1098 {
1099 #if (CORE3D_VALIDATION_ENABLED == 1)
1100     if (mesh.submeshes.size() > MAX_BATCH_SUBMESH_COUNT) {
1101         CORE_LOG_ONCE_E("submesh_counts_batch",
1102             "CORE3D_VALIDATION: GPU instancing batches not supported for submeshes with count %u > %u ",
1103             static_cast<uint32_t>(mesh.submeshes.size()), MAX_BATCH_SUBMESH_COUNT);
1104     }
1105 #endif
1106 }
1107 
DestroyBatchData(BASE_NS::unordered_map<CORE_NS::Entity,RenderSystem::BatchDataVector> & batches)1108 inline void DestroyBatchData(BASE_NS::unordered_map<CORE_NS::Entity, RenderSystem::BatchDataVector>& batches)
1109 {
1110     // NOTE: we destroy batch entity if its elements were not used in this frame
1111     for (auto iter = batches.begin(); iter != batches.end();) {
1112         if (iter->second.empty()) {
1113             iter = batches.erase(iter);
1114         } else {
1115             iter->second.clear();
1116             ++iter;
1117         }
1118     }
1119 }
1120 
GetMeshMinAndMax(const IRenderPreprocessorSystem & renderPreprocessorSystem,const Entity renderMeshEntity,array_view<const Entity> nextRenderMeshEntities)1121 MinAndMax GetMeshMinAndMax(const IRenderPreprocessorSystem& renderPreprocessorSystem, const Entity renderMeshEntity,
1122     array_view<const Entity> nextRenderMeshEntities)
1123 {
1124     const auto meshAabb =
1125         static_cast<const RenderPreprocessorSystem&>(renderPreprocessorSystem).GetRenderMeshAabb(renderMeshEntity);
1126     MinAndMax mam { meshAabb.min, meshAabb.max };
1127     for (const auto& nextRenderMeshEntity : nextRenderMeshEntities) {
1128         const auto nextMeshAabb = static_cast<const RenderPreprocessorSystem&>(renderPreprocessorSystem)
1129                                       .GetRenderMeshAabb(nextRenderMeshEntity);
1130         mam.minAABB = Math::min(mam.minAABB, nextMeshAabb.min);
1131         mam.maxAABB = Math::max(mam.maxAABB, nextMeshAabb.max);
1132     }
1133     return mam;
1134 }
1135 
ProcessCameraAddMultiViewHash(const RenderCamera & cam,unordered_map<uint64_t,uint64_t> & childToParent)1136 inline void ProcessCameraAddMultiViewHash(const RenderCamera& cam, unordered_map<uint64_t, uint64_t>& childToParent)
1137 {
1138     for (uint32_t idx = 0; idx < cam.multiViewCameraCount; ++idx) {
1139         childToParent.insert_or_assign(cam.multiViewCameraIds[idx], cam.id);
1140     }
1141 }
1142 } // namespace
1143 
RenderSystem(IEcs & ecs)1144 RenderSystem::RenderSystem(IEcs& ecs)
1145     : ecs_(ecs), nodeMgr_(GetManager<INodeComponentManager>(ecs)),
1146       renderMeshBatchMgr_(GetManager<IRenderMeshBatchComponentManager>(ecs)),
1147       renderMeshMgr_(GetManager<IRenderMeshComponentManager>(ecs)),
1148       worldMatrixMgr_(GetManager<IWorldMatrixComponentManager>(ecs)),
1149       prevWorldMatrixMgr_(GetManager<IPreviousWorldMatrixComponentManager>(ecs)),
1150       renderConfigMgr_(GetManager<IRenderConfigurationComponentManager>(ecs)),
1151       cameraMgr_(GetManager<ICameraComponentManager>(ecs)), lightMgr_(GetManager<ILightComponentManager>(ecs)),
1152       planarReflectionMgr_(GetManager<IPlanarReflectionComponentManager>(ecs)),
1153       materialExtensionMgr_(GetManager<IMaterialExtensionComponentManager>(ecs)),
1154       materialMgr_(GetManager<IMaterialComponentManager>(ecs)), meshMgr_(GetManager<IMeshComponentManager>(ecs)),
1155       uriMgr_(GetManager<IUriComponentManager>(ecs)), nameMgr_(GetManager<INameComponentManager>(ecs)),
1156       environmentMgr_(GetManager<IEnvironmentComponentManager>(ecs)), fogMgr_(GetManager<IFogComponentManager>(ecs)),
1157       gpuHandleMgr_(GetManager<IRenderHandleComponentManager>(ecs)), layerMgr_(GetManager<ILayerComponentManager>(ecs)),
1158       jointMatricesMgr_(GetManager<IJointMatricesComponentManager>(ecs)),
1159       prevJointMatricesMgr_(GetManager<IPreviousJointMatricesComponentManager>(ecs)),
1160       postProcessMgr_(GetManager<IPostProcessComponentManager>(ecs)),
1161       postProcessConfigMgr_(GetManager<IPostProcessConfigurationComponentManager>(ecs)),
1162       RENDER_SYSTEM_PROPERTIES(&properties_, array_view(ComponentMetadata))
1163 {
1164     if (IEngine* engine = ecs_.GetClassFactory().GetInterface<IEngine>(); engine) {
1165         frustumUtil_ = GetInstance<IFrustumUtil>(UID_FRUSTUM_UTIL);
1166         renderContext_ = GetInstance<IRenderContext>(*engine->GetInterface<IClassRegister>(), UID_RENDER_CONTEXT);
1167         if (renderContext_) {
1168             picking_ = GetInstance<IPicking>(*renderContext_->GetInterface<IClassRegister>(), UID_PICKING);
1169             graphicsContext_ =
1170                 GetInstance<IGraphicsContext>(*renderContext_->GetInterface<IClassRegister>(), UID_GRAPHICS_CONTEXT);
1171             if (graphicsContext_) {
1172                 renderUtil_ = &graphicsContext_->GetRenderUtil();
1173             }
1174             shaderMgr_ = &renderContext_->GetDevice().GetShaderManager();
1175             gpuResourceMgr_ = &renderContext_->GetDevice().GetGpuResourceManager();
1176         }
1177     }
1178 }
1179 
~RenderSystem()1180 RenderSystem::~RenderSystem()
1181 {
1182     DestroyRenderDataStores();
1183 }
1184 
SetActive(bool state)1185 void RenderSystem::SetActive(bool state)
1186 {
1187     active_ = state;
1188 }
1189 
IsActive() const1190 bool RenderSystem::IsActive() const
1191 {
1192     return active_;
1193 }
1194 
GetName() const1195 string_view RenderSystem::GetName() const
1196 {
1197     return CORE3D_NS::GetName(this);
1198 }
1199 
GetUid() const1200 Uid RenderSystem::GetUid() const
1201 {
1202     return UID;
1203 }
1204 
GetProperties()1205 IPropertyHandle* RenderSystem::GetProperties()
1206 {
1207     return RENDER_SYSTEM_PROPERTIES.GetData();
1208 }
1209 
GetProperties() const1210 const IPropertyHandle* RenderSystem::GetProperties() const
1211 {
1212     return RENDER_SYSTEM_PROPERTIES.GetData();
1213 }
1214 
SetProperties(const IPropertyHandle & data)1215 void RenderSystem::SetProperties(const IPropertyHandle& data)
1216 {
1217     if (data.Owner() != &RENDER_SYSTEM_PROPERTIES) {
1218         return;
1219     }
1220     if (const auto in = ScopedHandle<const IRenderSystem::Properties>(&data); in) {
1221         properties_.dataStoreScene = in->dataStoreScene;
1222         properties_.dataStoreCamera = in->dataStoreCamera;
1223         properties_.dataStoreLight = in->dataStoreLight;
1224         properties_.dataStoreMaterial = in->dataStoreMaterial;
1225         properties_.dataStoreMorph = in->dataStoreMorph;
1226         properties_.dataStorePrefix = in->dataStorePrefix;
1227         if (renderContext_) {
1228             SetDataStorePointers(renderContext_->GetRenderDataStoreManager());
1229         }
1230     }
1231 }
1232 
SetDataStorePointers(IRenderDataStoreManager & manager)1233 void RenderSystem::SetDataStorePointers(IRenderDataStoreManager& manager)
1234 {
1235     // get data stores
1236     dsScene_ =
1237         static_cast<IRenderDataStoreDefaultScene*>(manager.GetRenderDataStore(properties_.dataStoreScene.data()));
1238     dsCamera_ =
1239         static_cast<IRenderDataStoreDefaultCamera*>(manager.GetRenderDataStore(properties_.dataStoreCamera.data()));
1240     dsLight_ =
1241         static_cast<IRenderDataStoreDefaultLight*>(manager.GetRenderDataStore(properties_.dataStoreLight.data()));
1242     dsMaterial_ =
1243         static_cast<IRenderDataStoreDefaultMaterial*>(manager.GetRenderDataStore(properties_.dataStoreMaterial.data()));
1244 }
1245 
GetECS() const1246 const IEcs& RenderSystem::GetECS() const
1247 {
1248     return ecs_;
1249 }
1250 
Initialize()1251 void RenderSystem::Initialize()
1252 {
1253     if (graphicsContext_ && renderContext_) {
1254         renderPreprocessorSystem_ = GetSystem<IRenderPreprocessorSystem>(ecs_);
1255         if (renderPreprocessorSystem_) {
1256             const auto in =
1257                 ScopedHandle<IRenderPreprocessorSystem::Properties>(renderPreprocessorSystem_->GetProperties());
1258             properties_.dataStoreScene = in->dataStoreScene;
1259             properties_.dataStoreCamera = in->dataStoreCamera;
1260             properties_.dataStoreLight = in->dataStoreLight;
1261             properties_.dataStoreMaterial = in->dataStoreMaterial;
1262             properties_.dataStoreMorph = in->dataStoreMorph;
1263             properties_.dataStorePrefix = in->dataStorePrefix;
1264         } else {
1265             CORE_LOG_E("DEPRECATED USAGE: RenderPreprocessorSystem not found. Add system to system graph.");
1266         }
1267 
1268         SetDataStorePointers(renderContext_->GetRenderDataStoreManager());
1269     }
1270     if (renderContext_ && uriMgr_ && gpuHandleMgr_) {
1271         // fetch default shaders and graphics states
1272         const IShaderManager& shaderMgr = renderContext_->GetDevice().GetShaderManager();
1273         auto& entityMgr = ecs_.GetEntityManager();
1274         FillShaderData(entityMgr, *uriMgr_, *gpuHandleMgr_, shaderMgr,
1275             DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE, dmShaderData_.opaque);
1276         FillShaderData(entityMgr, *uriMgr_, *gpuHandleMgr_, shaderMgr,
1277             DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT, dmShaderData_.blend);
1278         FillShaderData(entityMgr, *uriMgr_, *gpuHandleMgr_, shaderMgr,
1279             DefaultMaterialShaderConstants::RENDER_SLOT_DEPTH, dmShaderData_.depth);
1280     }
1281 
1282     {
1283         const ComponentQuery::Operation operations[] = {
1284             { *nodeMgr_, ComponentQuery::Operation::REQUIRE },
1285             { *worldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1286             { *layerMgr_, ComponentQuery::Operation::OPTIONAL },
1287         };
1288         lightQuery_.SetEcsListenersEnabled(true);
1289         lightQuery_.SetupQuery(*lightMgr_, operations);
1290     }
1291     {
1292         const ComponentQuery::Operation operations[] = {
1293             { *worldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1294             { *prevWorldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1295             { *layerMgr_, ComponentQuery::Operation::OPTIONAL },
1296             { *jointMatricesMgr_, ComponentQuery::Operation::OPTIONAL },
1297             { *prevJointMatricesMgr_, ComponentQuery::Operation::OPTIONAL },
1298         };
1299         renderableQuery_.SetEcsListenersEnabled(true);
1300         renderableQuery_.SetupQuery(*renderMeshMgr_, operations, true);
1301     }
1302     {
1303         const ComponentQuery::Operation operations[] = {
1304             { *worldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1305             { *nodeMgr_, ComponentQuery::Operation::REQUIRE },
1306             { *renderMeshMgr_, ComponentQuery::Operation::REQUIRE },
1307         };
1308         reflectionsQuery_.SetEcsListenersEnabled(true);
1309         reflectionsQuery_.SetupQuery(*planarReflectionMgr_, operations);
1310     }
1311 }
1312 
Update(bool frameRenderingQueued,uint64_t totalTime,uint64_t deltaTime)1313 bool RenderSystem::Update(bool frameRenderingQueued, uint64_t totalTime, uint64_t deltaTime)
1314 {
1315     renderProcessing_.frameProcessed = false;
1316     if (!active_) {
1317         return false;
1318     }
1319 
1320     const auto renderConfigurationGen = renderConfigMgr_->GetGenerationCounter();
1321     const auto cameraGen = cameraMgr_->GetGenerationCounter();
1322     const auto lightGen = lightMgr_->GetGenerationCounter();
1323     const auto planarReflectionGen = planarReflectionMgr_->GetGenerationCounter();
1324     const auto materialExtensionGen = materialExtensionMgr_->GetGenerationCounter();
1325     const auto environmentGen = environmentMgr_->GetGenerationCounter();
1326     const auto fogGen = fogMgr_->GetGenerationCounter();
1327     const auto postprocessGen = postProcessMgr_->GetGenerationCounter();
1328     const auto postprocessConfigurationGen = postProcessConfigMgr_->GetGenerationCounter();
1329     if (!frameRenderingQueued && (renderConfigurationGeneration_ == renderConfigurationGen) &&
1330         (cameraGeneration_ == cameraGen) && (lightGeneration_ == lightGen) &&
1331         (planarReflectionGeneration_ == planarReflectionGen) &&
1332         (materialExtensionGeneration_ == materialExtensionGen) && (environmentGeneration_ == environmentGen) &&
1333         (fogGeneration_ == fogGen) && (postprocessGeneration_ == postprocessGen) &&
1334         (postprocessConfigurationGeneration_ == postprocessConfigurationGen)) {
1335         return false;
1336     }
1337 
1338     renderConfigurationGeneration_ = renderConfigurationGen;
1339     cameraGeneration_ = cameraGen;
1340     lightGeneration_ = lightGen;
1341     planarReflectionGeneration_ = planarReflectionGen;
1342     materialExtensionGeneration_ = materialExtensionGen;
1343     environmentGeneration_ = environmentGen;
1344     fogGeneration_ = fogGen;
1345     postprocessGeneration_ = postprocessGen;
1346     postprocessConfigurationGeneration_ = postprocessConfigurationGen;
1347 
1348     totalTime_ = totalTime;
1349     deltaTime_ = deltaTime;
1350 
1351     if (dsMaterial_ && dsCamera_ && dsLight_ && dsScene_) {
1352         dsMaterial_->Clear();
1353         dsCamera_->Clear();
1354         dsLight_->Clear();
1355         dsScene_->Clear();
1356         FetchFullScene();
1357     } else {
1358 #if (CORE3D_VALIDATION_ENABLED == 1)
1359         CORE_LOG_ONCE_W("rs_data_stores_not_found", "CORE3D_VALIDATION: render system render data stores not found");
1360 #endif
1361     }
1362     frameIndex_++;
1363 
1364     renderProcessing_.frameProcessed = true;
1365     return true;
1366 }
1367 
Uninitialize()1368 void RenderSystem::Uninitialize()
1369 {
1370     lightQuery_.SetEcsListenersEnabled(false);
1371     renderableQuery_.SetEcsListenersEnabled(false);
1372     reflectionsQuery_.SetEcsListenersEnabled(false);
1373 }
1374 
GetRenderConfigurationComponent()1375 RenderConfigurationComponent RenderSystem::GetRenderConfigurationComponent()
1376 {
1377     for (IComponentManager::ComponentId i = 0; i < renderConfigMgr_->GetComponentCount(); i++) {
1378         const Entity id = renderConfigMgr_->GetEntity(i);
1379         if (nodeMgr_->Get(id).effectivelyEnabled) {
1380             return renderConfigMgr_->Get(i);
1381         }
1382     }
1383     return {};
1384 }
1385 
ProcessScene(const RenderConfigurationComponent & sc)1386 Entity RenderSystem::ProcessScene(const RenderConfigurationComponent& sc)
1387 {
1388     Entity cameraEntity { INVALID_ENTITY };
1389     // Grab active camera.
1390     const auto cameraCount = cameraMgr_->GetComponentCount();
1391     for (IComponentManager::ComponentId id = 0; id < cameraCount; ++id) {
1392         if (auto handle = cameraMgr_->Read(id); handle) {
1393             if (handle->sceneFlags & CameraComponent::SceneFlagBits::MAIN_CAMERA_BIT) {
1394                 cameraEntity = cameraMgr_->GetEntity(id);
1395                 break;
1396             }
1397         }
1398     }
1399     dsLight_->SetShadowTypes(GetRenderShadowTypes(sc), 0u);
1400 
1401     // NOTE: removed code for "No main camera set, grab 1st one (if any)."
1402 
1403     return cameraEntity;
1404 }
1405 
EvaluateMaterialModifications(const MaterialComponent & matComp)1406 void RenderSystem::EvaluateMaterialModifications(const MaterialComponent& matComp)
1407 {
1408     // update built-in pipeline modifications for default materials
1409     CORE_ASSERT(matComp.type <= MaterialComponent::Type::CUSTOM_COMPLEX);
1410     if (matComp.type < MaterialComponent::Type::CUSTOM) {
1411         if (matComp.textures[MaterialComponent::TextureIndex::TRANSMISSION].factor.x > 0.0f) {
1412             // NOTE: should be alpha blend and not double sided, should be set by material author
1413             // automatically done by e.g. gltf2 importer
1414             renderProcessing_.frameFlags |= NEEDS_COLOR_PRE_PASS; // when allowing prepass on demand
1415         }
1416     }
1417 }
1418 
ProcessSubmesh(const MeshProcessData & mpd,const MeshComponent::Submesh & submesh,const uint32_t meshIndex,const uint32_t subMeshIndex,const uint32_t skinJointIndex,const MinAndMax & mam,const bool isNegative)1419 uint32_t RenderSystem::ProcessSubmesh(const MeshProcessData& mpd, const MeshComponent::Submesh& submesh,
1420     const uint32_t meshIndex, const uint32_t subMeshIndex, const uint32_t skinJointIndex, const MinAndMax& mam,
1421     const bool isNegative)
1422 {
1423     uint32_t materialIndex = RenderSceneDataConstants::INVALID_INDEX;
1424     // The cost of constructing RenderSubmesh is suprisingly high. alternatives are copy-construction from a constant
1425     // or perhaps directly assinging the final values.
1426     RenderSubmesh renderSubmesh { INIT };
1427     renderSubmesh.id = mpd.renderMeshEntity.id;
1428     renderSubmesh.meshId = mpd.meshEntity.id;
1429     renderSubmesh.subMeshIndex = subMeshIndex;
1430     renderSubmesh.layerMask = mpd.layerMask; // pass node layer mask for render submesh
1431     renderSubmesh.renderSortLayer = submesh.renderSortLayer;
1432     renderSubmesh.renderSortLayerOrder = submesh.renderSortLayerOrder;
1433     renderSubmesh.meshIndex = meshIndex;
1434     renderSubmesh.skinJointIndex = skinJointIndex;
1435     renderSubmesh.worldCenter = (mam.minAABB + mam.maxAABB) * 0.5f;
1436     renderSubmesh.worldRadius = Math::sqrt(Math::max(Math::Distance2(renderSubmesh.worldCenter, mam.minAABB),
1437         Math::Distance2(renderSubmesh.worldCenter, mam.maxAABB)));
1438 
1439     SetupSubmeshBuffers(*gpuHandleMgr_, mpd.meshComponent, submesh, renderSubmesh);
1440 
1441     // Clear skinning bit if joint matrices were not given.
1442     if (skinJointIndex == RenderSceneDataConstants::INVALID_INDEX) {
1443         renderSubmesh.submeshFlags &= ~RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT;
1444     }
1445     if (isNegative) {
1446         renderSubmesh.submeshFlags |= RenderSubmeshFlagBits::RENDER_SUBMESH_INVERSE_WINDING_BIT;
1447     }
1448 
1449     renderSubmesh.drawCommand.vertexCount = submesh.vertexCount;
1450     renderSubmesh.drawCommand.indexCount = submesh.indexCount;
1451     // NOTE: batch instance count
1452     renderSubmesh.drawCommand.instanceCount = submesh.instanceCount + mpd.batchInstanceCount;
1453 
1454     // overwrites the render submesh for every new material
1455     auto addMaterial = [&](Entity materialEntity) {
1456         if (EntityUtil::IsValid(materialEntity)) {
1457             if (auto materialData = materialMgr_->Read(materialEntity); materialData) {
1458                 if (materialData->extraRenderingFlags & MaterialComponent::DISABLE_BIT) {
1459                     return; // early out from lambda with disabled material
1460                 }
1461                 EvaluateMaterialModifications(*materialData);
1462             }
1463         }
1464         RenderMaterialIndices matIndices = AddRenderMaterial(*materialMgr_, *materialExtensionMgr_, *gpuHandleMgr_,
1465             *dsMaterial_, materialEntity, renderSubmesh.drawCommand.instanceCount, mpd.duplicateMaterialInstances);
1466         renderSubmesh.materialIndex = matIndices.materialIndex;
1467         renderSubmesh.customResourcesIndex = matIndices.materialCustomResourceIndex;
1468         dsMaterial_->AddSubmesh(renderSubmesh);
1469     };
1470     addMaterial(submesh.material);
1471     materialIndex = renderSubmesh.materialIndex;
1472 
1473     // updates only the material related indices in renderSubmesh for additional materials
1474     // NOTE: there will be as many RenderSubmeshes as materials
1475     for (const auto& matRef : submesh.additionalMaterials) {
1476         addMaterial(matRef);
1477     }
1478     return materialIndex;
1479 }
1480 
ProcessMesh(const MeshProcessData & mpd,const MinAndMax & batchMam,const SkinProcessData & spd,vector<uint32_t> * submeshMaterials)1481 void RenderSystem::ProcessMesh(const MeshProcessData& mpd, const MinAndMax& batchMam, const SkinProcessData& spd,
1482     vector<uint32_t>* submeshMaterials)
1483 {
1484     CORE_STATIC_ASSERT(sizeof(RenderMeshComponent::customData) == sizeof(RenderMeshData::customData));
1485     RenderMeshData rmd { mpd.world, mpd.world, mpd.prevWorld, mpd.renderMeshEntity.id, mpd.meshEntity.id,
1486         mpd.layerMask };
1487     std::copy(std::begin(mpd.renderMeshComponent.customData), std::end(mpd.renderMeshComponent.customData),
1488         std::begin(rmd.customData));
1489     const uint32_t meshIndex = dsMaterial_->AddMeshData(rmd);
1490     uint32_t skinIndex = RenderSceneDataConstants::INVALID_INDEX;
1491     const bool useJoints = spd.jointMatricesComponent && (spd.jointMatricesComponent->count > 0);
1492     if (useJoints) {
1493         CORE_ASSERT(spd.prevJointMatricesComponent);
1494         const auto jm = array_view<Math::Mat4X4 const>(
1495             spd.jointMatricesComponent->jointMatrices, spd.jointMatricesComponent->count);
1496         const auto pjm = array_view<Math::Mat4X4 const>(
1497             spd.prevJointMatricesComponent->jointMatrices, spd.prevJointMatricesComponent->count);
1498         skinIndex = dsMaterial_->AddSkinJointMatrices(jm, pjm);
1499     }
1500 
1501     const bool isMeshNegative = Math::Determinant(mpd.world) < 0.0f;
1502     // NOTE: When object is skinned we use the mesh bounding box for all the submeshes because currently
1503     // there is no way to know here which joints affect one specific renderSubmesh.
1504     MinAndMax skinnedMeshBounds;
1505     if (useJoints) {
1506         skinnedMeshBounds.minAABB = spd.jointMatricesComponent->jointsAabbMin;
1507         skinnedMeshBounds.maxAABB = spd.jointMatricesComponent->jointsAabbMax;
1508     }
1509     const auto aabbs =
1510         static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetRenderMeshAabbs(mpd.renderMeshEntity);
1511     CORE_ASSERT(picking_);
1512     for (uint32_t subMeshIdx = 0; subMeshIdx < mpd.meshComponent.submeshes.size(); ++subMeshIdx) {
1513         const auto& submesh = mpd.meshComponent.submeshes[subMeshIdx];
1514 
1515         MinAndMax mam = [&]() {
1516             if (useJoints) {
1517                 return skinnedMeshBounds;
1518             }
1519             if (subMeshIdx < aabbs.size()) {
1520                 return MinAndMax { aabbs[subMeshIdx].min, aabbs[subMeshIdx].max };
1521             } else if (!aabbs.empty()) {
1522                 return MinAndMax { aabbs[0U].min, aabbs[0U].max };
1523             }
1524             return MinAndMax {};
1525         }();
1526         if (mpd.batchInstanceCount > 0) {
1527             mam.minAABB = Math::min(mam.minAABB, batchMam.minAABB);
1528             mam.maxAABB = Math::max(mam.maxAABB, batchMam.maxAABB);
1529         }
1530         auto materialIndex = ProcessSubmesh(mpd, submesh, meshIndex, subMeshIdx, skinIndex, mam, isMeshNegative);
1531         if (submeshMaterials) {
1532             submeshMaterials->push_back(materialIndex);
1533         }
1534     }
1535 }
1536 
ProcessRenderMeshBatch(const Entity renderMeshBatch,const ComponentQuery::ResultRow * row)1537 void RenderSystem::ProcessRenderMeshBatch(const Entity renderMeshBatch, const ComponentQuery::ResultRow* row)
1538 {
1539     const RenderMeshComponent renderMeshComponent = renderMeshMgr_->Get(row->components[RQ_RMC]);
1540     const Math::Mat4X4& world = worldMatrixMgr_->Read(row->components[RQ_WM])->matrix;
1541     const Math::Mat4X4& prevWorld = prevWorldMatrixMgr_->Read(row->components[RQ_PWM])->matrix;
1542     const uint64_t layerMask = !row->IsValidComponentId(RQ_L) ? LayerConstants::DEFAULT_LAYER_MASK
1543                                                               : layerMgr_->Get(row->components[RQ_L]).layerMask;
1544     // NOTE: direct component id for skins added to batch processing
1545     batches_[renderMeshBatch].push_back({ row->entity, renderMeshComponent.mesh, layerMask, row->components[RQ_JM],
1546         row->components[RQ_PJM], world, prevWorld });
1547 }
1548 
ProcessRenderMeshBatch(array_view<const Entity> renderMeshComponents)1549 void RenderSystem::ProcessRenderMeshBatch(array_view<const Entity> renderMeshComponents)
1550 {
1551     uint32_t batchIndex = 0;
1552     uint32_t batchedCount = 0;
1553     auto& materialIndices = materialIndices_;
1554     ScopedHandle<const MeshComponent> meshHandle;
1555     const uint32_t batchInstCount = static_cast<uint32_t>(renderMeshComponents.size());
1556     for (const auto& entity : renderMeshComponents) {
1557         if (const auto row = renderableQuery_.FindResultRow(entity); row) {
1558             const RenderMeshComponent rmc = renderMeshMgr_->Get(row->components[RQ_RMC]);
1559             if (!meshHandle) {
1560                 meshHandle = meshMgr_->Read(rmc.mesh);
1561             }
1562             if (meshHandle) {
1563                 const Math::Mat4X4& world = worldMatrixMgr_->Read(row->components[RQ_WM])->matrix;
1564                 const Math::Mat4X4& prevWorld = prevWorldMatrixMgr_->Read(row->components[RQ_PWM])->matrix;
1565                 const uint64_t layerMask = !row->IsValidComponentId(RQ_L)
1566                                                ? LayerConstants::DEFAULT_LAYER_MASK
1567                                                : layerMgr_->Read(row->components[RQ_L])->layerMask;
1568                 if (batchIndex == 0) {
1569                     LogBatchValidation(*meshHandle);
1570                     materialIndices.clear();
1571                     materialIndices.reserve(meshHandle->submeshes.size());
1572                     const uint32_t currBatchCount = Math::min(batchInstCount - batchedCount, MAX_BATCH_OBJECT_COUNT);
1573                     // process AABBs for all instances, the same mesh is used for all instances with their own
1574                     // transform
1575                     const auto mam = GetMeshMinAndMax(*renderPreprocessorSystem_, entity,
1576                         array_view(renderMeshComponents.data() + batchedCount, currBatchCount));
1577 
1578                     batchedCount += currBatchCount;
1579                     MeshProcessData mpd { layerMask, currBatchCount - 1u, true, entity, rmc.mesh, *meshHandle, rmc,
1580                         world, prevWorld };
1581                     // Optional skin, cannot change based on submesh)
1582                     if (row->IsValidComponentId(RQ_JM) && row->IsValidComponentId(RQ_PJM)) {
1583                         auto const jointMatricesData = jointMatricesMgr_->Read(row->components[RQ_JM]);
1584                         auto const prevJointMatricesData = prevJointMatricesMgr_->Read(row->components[RQ_PJM]);
1585                         const SkinProcessData spd { &(*jointMatricesData), &(*prevJointMatricesData) };
1586                         ProcessMesh(mpd, mam, spd, &materialIndices);
1587                     } else {
1588                         ProcessMesh(mpd, mam, {}, &materialIndices);
1589                     }
1590                 } else {
1591                     // NOTE: normal matrix is missing
1592                     RenderMeshData rmd { world, world, prevWorld, entity.id, rmc.mesh.id, layerMask };
1593                     std::copy(std::begin(rmc.customData), std::end(rmc.customData), std::begin(rmd.customData));
1594                     dsMaterial_->AddMeshData(rmd);
1595                     // NOTE: materials have been automatically duplicated for all instance
1596                 }
1597                 if (++batchIndex == MAX_BATCH_OBJECT_COUNT) {
1598                     batchIndex = 0;
1599                 }
1600             }
1601         }
1602     }
1603 }
1604 
ProcessSingleRenderMesh(Entity renderMeshComponent)1605 void RenderSystem::ProcessSingleRenderMesh(Entity renderMeshComponent)
1606 {
1607     // add a single mesh
1608     if (const auto row = renderableQuery_.FindResultRow(renderMeshComponent); row) {
1609         const RenderMeshComponent rms = renderMeshMgr_->Get(row->components[RQ_RMC]);
1610         if (const auto meshData = meshMgr_->Read(rms.mesh); meshData) {
1611             const WorldMatrixComponent world = worldMatrixMgr_->Get(row->components[RQ_WM]);
1612             const PreviousWorldMatrixComponent prevWorld = prevWorldMatrixMgr_->Get(row->components[RQ_PWM]);
1613             const uint64_t layerMask = !row->IsValidComponentId(RQ_L) ? LayerConstants::DEFAULT_LAYER_MASK
1614                                                                       : layerMgr_->Get(row->components[RQ_L]).layerMask;
1615             const MeshProcessData mpd { layerMask, 0, false, row->entity, rms.mesh, *meshData, rms, world.matrix,
1616                 prevWorld.matrix };
1617             // (4, 5) JointMatrixComponents are optional.
1618             if (row->IsValidComponentId(RQ_JM) && row->IsValidComponentId(RQ_PJM)) {
1619                 auto const jointMatricesData = jointMatricesMgr_->Read(row->components[RQ_JM]);
1620                 auto const prevJointMatricesData = prevJointMatricesMgr_->Read(row->components[RQ_PJM]);
1621                 CORE_ASSERT(jointMatricesData);
1622                 CORE_ASSERT(prevJointMatricesData);
1623                 const SkinProcessData spd { &(*jointMatricesData), &(*prevJointMatricesData) };
1624                 ProcessMesh(mpd, {}, spd, nullptr);
1625             } else {
1626                 ProcessMesh(mpd, {}, {}, nullptr);
1627             }
1628         }
1629     }
1630 }
1631 
ProcessRenderables()1632 void RenderSystem::ProcessRenderables()
1633 {
1634     renderableQuery_.Execute();
1635     {
1636         const auto renderBatchEntities =
1637             static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetRenderBatchMeshEntities();
1638         for (const auto& rmc : renderBatchEntities) {
1639             if (const auto row = renderableQuery_.FindResultRow(rmc); row) {
1640                 const RenderMeshComponent renderMeshComponent = renderMeshMgr_->Get(row->components[RQ_RMC]);
1641                 // batched render mesh components not processed linearly
1642                 ProcessRenderMeshBatch(renderMeshComponent.renderMeshBatch, row);
1643             }
1644         }
1645     }
1646 
1647     {
1648         auto currentIndex = 0U;
1649         auto batchStartIndex = 0U;
1650         Entity currentMesh;
1651         const auto instancingAllowedEntities =
1652             static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetInstancingAllowedEntities();
1653         for (const auto& rmc : instancingAllowedEntities) {
1654             if (const auto row = renderableQuery_.FindResultRow(rmc); row) {
1655                 const RenderMeshComponent renderMeshComponent = renderMeshMgr_->Get(row->components[RQ_RMC]);
1656                 if (currentMesh != renderMeshComponent.mesh) {
1657                     // create batch when the mesh changes [batchStartIndex..currentIndex)
1658                     if (const auto batchSize = currentIndex - batchStartIndex; batchSize) {
1659                         ProcessRenderMeshBatch({ instancingAllowedEntities.data() + batchStartIndex, batchSize });
1660                     }
1661 
1662                     batchStartIndex = currentIndex;
1663                     currentMesh = renderMeshComponent.mesh;
1664                 }
1665             }
1666             ++currentIndex;
1667         }
1668 
1669         // handle the tail
1670         if (const auto batchSize = currentIndex - batchStartIndex; batchSize) {
1671             ProcessRenderMeshBatch({ instancingAllowedEntities.data() + batchStartIndex, batchSize });
1672         }
1673     }
1674 
1675     {
1676         const auto instancingDisabledEntities =
1677             static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetInstancingDisabledEntities();
1678         for (const auto& rmc : instancingDisabledEntities) {
1679             ProcessSingleRenderMesh(rmc);
1680         }
1681     }
1682 
1683     ProcessBatchRenderables();
1684 }
1685 
ProcessBatchRenderables()1686 void RenderSystem::ProcessBatchRenderables()
1687 {
1688     auto& materialIndices = materialIndices_;
1689     for (const auto& batchRef : batches_) {
1690         uint32_t batchIndex = 0;
1691         uint32_t batchedCount = 0;
1692         const uint32_t batchInstCount = static_cast<uint32_t>(batchRef.second.size());
1693         for (uint32_t entIdx = 0; entIdx < batchInstCount; ++entIdx) {
1694             const auto& inst = batchRef.second[entIdx];
1695             const Entity& entRef = inst.entity;
1696             const Entity& meshEntRef = inst.mesh;
1697             if (const auto meshData = meshMgr_->Read(meshEntRef); meshData) {
1698                 const auto& mesh = *meshData;
1699                 const RenderMeshComponent rmc = renderMeshMgr_->Get(entRef);
1700                 // process the first fully
1701                 if (batchIndex == 0) {
1702                     LogBatchValidation(mesh);
1703 
1704                     materialIndices.clear();
1705                     materialIndices.reserve(meshData->submeshes.size());
1706                     const uint32_t currPatchCount = Math::min(batchInstCount - batchedCount, MAX_BATCH_OBJECT_COUNT);
1707                     // process AABBs for all instances, the same mesh is used for all instances with their own
1708                     // transform
1709                     MinAndMax mam;
1710                     const BatchIndices batchIndices { ~0u, entIdx + 1, entIdx + currPatchCount };
1711                     CombineBatchWorldMinAndMax(batchRef.second, batchIndices, mesh, mam);
1712                     batchedCount += currPatchCount;
1713                     MeshProcessData mpd { inst.layerMask, currPatchCount - 1u, false, entRef, meshEntRef, mesh, rmc,
1714                         inst.mtx, inst.prevWorld };
1715                     // Optional skin, cannot change based on submesh)
1716                     if (inst.jointId != IComponentManager::INVALID_COMPONENT_ID) {
1717                         auto const jointMatricesData = jointMatricesMgr_->Read(inst.jointId);
1718                         auto const prevJointMatricesData = prevJointMatricesMgr_->Read(inst.prevJointId);
1719                         const SkinProcessData spd { &(*jointMatricesData), &(*prevJointMatricesData) };
1720                         ProcessMesh(mpd, mam, spd, &materialIndices);
1721                     } else {
1722                         ProcessMesh(mpd, mam, {}, &materialIndices);
1723                     }
1724                 } else {
1725                     // NOTE: normal matrix is missing
1726                     RenderMeshData rmd { inst.mtx, inst.mtx, inst.prevWorld, entRef.id, meshEntRef.id, inst.layerMask };
1727                     std::copy(std::begin(rmc.customData), std::end(rmc.customData), std::begin(rmd.customData));
1728                     dsMaterial_->AddMeshData(rmd);
1729                     // NOTE: we force add a new material for every instance object, but we do not fetch texture
1730                     // handles
1731 
1732                     for (size_t i = 0U, count = meshData->submeshes.size(); i < count; ++i) {
1733                         AddSingleMaterial(*materialMgr_, *materialExtensionMgr_, *gpuHandleMgr_, *dsMaterial_,
1734                             meshData->submeshes[i].material, false, false, materialIndices[i], batchIndex, 1U, false);
1735                     }
1736                 }
1737                 if (++batchIndex == MAX_BATCH_OBJECT_COUNT) {
1738                     batchIndex = 0;
1739                 }
1740             }
1741         }
1742     }
1743     // NOTE: we destroy batch entity if its elements were not used in this frame
1744     DestroyBatchData(batches_);
1745 }
1746 
CombineBatchWorldMinAndMax(const BatchDataVector & batchVec,const BatchIndices & batchIndices,const MeshComponent & mesh,MinAndMax & mam) const1747 void RenderSystem::CombineBatchWorldMinAndMax(
1748     const BatchDataVector& batchVec, const BatchIndices& batchIndices, const MeshComponent& mesh, MinAndMax& mam) const
1749 {
1750     CORE_ASSERT(picking_);
1751     CORE_ASSERT(batchIndices.batchEndCount <= static_cast<uint32_t>(batchVec.size()));
1752     const int32_t batchCount =
1753         static_cast<int32_t>(batchIndices.batchEndCount) - static_cast<int32_t>(batchIndices.batchStartIndex);
1754     if (batchCount <= 1) {
1755         return;
1756     }
1757     if (batchIndices.submeshIndex == ~0u) {
1758         for (uint32_t bIdx = batchIndices.batchStartIndex; bIdx < batchIndices.batchEndCount; ++bIdx) {
1759             const BatchData& bData = batchVec[bIdx];
1760             const auto meshAabb =
1761                 static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetRenderMeshAabb(bData.entity);
1762             mam.minAABB = Math::min(mam.minAABB, meshAabb.min);
1763             mam.maxAABB = Math::max(mam.maxAABB, meshAabb.max);
1764         }
1765     } else if (batchIndices.submeshIndex < mesh.submeshes.size()) {
1766         for (uint32_t bIdx = batchIndices.batchStartIndex; bIdx < batchIndices.batchEndCount; ++bIdx) {
1767             const BatchData& bData = batchVec[bIdx];
1768             const auto submeshAabbs =
1769                 static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetRenderMeshAabbs(bData.entity);
1770             if (batchIndices.submeshIndex < submeshAabbs.size()) {
1771                 mam.minAABB = Math::min(mam.minAABB, submeshAabbs[batchIndices.submeshIndex].min);
1772                 mam.maxAABB = Math::max(mam.maxAABB, submeshAabbs[batchIndices.submeshIndex].min);
1773             }
1774         }
1775     }
1776 }
1777 
ProcessEnvironments(const RenderConfigurationComponent & renderConfig)1778 void RenderSystem::ProcessEnvironments(const RenderConfigurationComponent& renderConfig)
1779 {
1780     if (!(environmentMgr_ && materialExtensionMgr_ && layerMgr_ && gpuHandleMgr_)) {
1781         return;
1782     }
1783 
1784     // default environment
1785     RenderCamera::Environment defaultEnv {};
1786 
1787     const auto envCount = environmentMgr_->GetComponentCount();
1788     for (IComponentManager::ComponentId id = 0; id < envCount; ++id) {
1789         ScopedHandle<const EnvironmentComponent> handle = environmentMgr_->Read(id);
1790         const EnvironmentComponent& component = *handle;
1791 
1792         const Entity envEntity = environmentMgr_->GetEntity(id);
1793         uint64_t layerMask = LayerConstants::DEFAULT_LAYER_MASK;
1794         if (auto layerHandle = layerMgr_->Read(envEntity); layerHandle) {
1795             layerMask = layerHandle->layerMask;
1796         }
1797 
1798         RenderCamera::Environment renderEnv;
1799         FillRenderEnvironment(*gpuHandleMgr_, layerMask, envEntity, component, renderEnv);
1800         // material custom resources (first check preferred custom resources)
1801         if (!component.customResources.empty()) {
1802             const size_t maxCustomCount = Math::min(
1803                 component.customResources.size(), static_cast<size_t>(MaterialExtensionComponent::RESOURCE_COUNT));
1804             for (size_t idx = 0; idx < maxCustomCount; ++idx) {
1805                 renderEnv.customResourceHandles[idx] =
1806                     gpuHandleMgr_->GetRenderHandleReference(component.customResources[idx]);
1807             }
1808         } else if (const auto matExtHandle = materialExtensionMgr_->Read(envEntity); matExtHandle) {
1809             const MaterialExtensionComponent& matExtComp = *matExtHandle;
1810             constexpr size_t maxCount = Math::min(static_cast<size_t>(MaterialExtensionComponent::RESOURCE_COUNT),
1811                 static_cast<size_t>(RenderSceneDataConstants::MAX_ENV_CUSTOM_RESOURCE_COUNT));
1812             for (size_t idx = 0; idx < maxCount; ++idx) {
1813                 renderEnv.customResourceHandles[idx] =
1814                     gpuHandleMgr_->GetRenderHandleReference(matExtComp.resources[idx]);
1815             }
1816         }
1817         dsCamera_->AddEnvironment(renderEnv);
1818         if (renderEnv.id == renderConfig.environment.id) {
1819             defaultEnv = renderEnv;
1820         }
1821     }
1822     // add default env with default data or render config data
1823     defaultEnv.id = RenderSceneDataConstants::INVALID_ID;
1824     dsCamera_->AddEnvironment(defaultEnv);
1825 }
1826 
ProcessCameras(const RenderConfigurationComponent & renderConfig,const Entity & mainCameraEntity,RenderScene & renderScene)1827 void RenderSystem::ProcessCameras(
1828     const RenderConfigurationComponent& renderConfig, const Entity& mainCameraEntity, RenderScene& renderScene)
1829 {
1830     // The scene camera and active render cameras are added here. ProcessReflections reflection cameras.
1831     // This is temporary when moving towards camera based rendering in 3D context.
1832     const uint32_t mainCameraId = cameraMgr_->GetComponentId(mainCameraEntity);
1833     const auto cameraCount = cameraMgr_->GetComponentCount();
1834     vector<RenderCamera> tmpCameras;
1835     tmpCameras.reserve(cameraCount);
1836     unordered_map<uint64_t, uint64_t> mvChildToParent; // multi-view child to parent
1837     for (IComponentManager::ComponentId id = 0; id < cameraCount; ++id) {
1838         ScopedHandle<const CameraComponent> handle = cameraMgr_->Read(id);
1839         const CameraComponent& component = *handle;
1840         if ((mainCameraId != id) && ((component.sceneFlags & CameraComponent::SceneFlagBits::ACTIVE_RENDER_BIT) == 0)) {
1841             continue;
1842         }
1843         const Entity cameraEntity = cameraMgr_->GetEntity(id);
1844         const auto worldMatrixComponentId = worldMatrixMgr_->GetComponentId(cameraEntity);
1845         // Make sure we have render matrix.
1846         if (worldMatrixComponentId != IComponentManager::INVALID_COMPONENT_ID) {
1847             const WorldMatrixComponent renderMatrixComponent = worldMatrixMgr_->Get(worldMatrixComponentId);
1848 
1849             float determinant = 0.0f;
1850             const Math::Mat4X4 view = Math::Inverse(Math::Mat4X4(renderMatrixComponent.matrix.data), determinant);
1851 
1852             RenderCamera::Flags rcFlags = 0;
1853             bool createPrePassCam = false;
1854             if (mainCameraId == id) {
1855                 renderScene.cameraIndex = static_cast<uint32_t>(tmpCameras.size());
1856                 rcFlags = RenderCamera::CAMERA_FLAG_MAIN_BIT;
1857                 createPrePassCam = (component.pipelineFlags & CameraComponent::FORCE_COLOR_PRE_PASS_BIT) ||
1858                                    (component.pipelineFlags & CameraComponent::ALLOW_COLOR_PRE_PASS_BIT);
1859                 renderProcessing_.frameFlags |=
1860                     (component.pipelineFlags & CameraComponent::FORCE_COLOR_PRE_PASS_BIT) ? NEEDS_COLOR_PRE_PASS : 0;
1861             }
1862 
1863             bool isCameraNegative = determinant < 0.0f;
1864             const auto proj = CameraMatrixUtil::CalculateProjectionMatrix(component, isCameraNegative);
1865 
1866             RenderCamera camera;
1867             FillRenderCameraBaseFromCameraComponent(*gpuHandleMgr_, component, camera, true);
1868             // we add entity id as camera name if there isn't name (we need this for render node graphs)
1869             camera.id = cameraEntity.id;
1870             camera.name = GetCameraName(*nameMgr_, cameraEntity);
1871             camera.matrices.view = view;
1872             camera.matrices.proj = proj;
1873             const CameraData prevFrameCamData = UpdateAndGetPreviousFrameCameraData(cameraEntity, view, proj);
1874             camera.matrices.viewPrevFrame = prevFrameCamData.view;
1875             camera.matrices.projPrevFrame = prevFrameCamData.proj;
1876             camera.flags |= (rcFlags | ((isCameraNegative) ? RenderCamera::CAMERA_FLAG_INVERSE_WINDING_BIT : 0));
1877             FillCameraRenderEnvironment(dsCamera_, component, camera);
1878             camera.fog = GetRenderCameraFogFromComponent(layerMgr_, fogMgr_, renderConfig, component);
1879             camera.shaderFlags |=
1880                 (camera.fog.id != RenderSceneDataConstants::INVALID_ID) ? RenderCamera::CAMERA_SHADER_FOG_BIT : 0U;
1881             camera.postProcessName = GetPostProcessName(
1882                 postProcessMgr_, postProcessConfigMgr_, nameMgr_, properties_.dataStoreScene, component.postProcess);
1883             camera.customPostProcessRenderNodeGraphFile =
1884                 GetPostProcessRenderNodeGraph(postProcessConfigMgr_, component.postProcess);
1885 
1886             // NOTE: setting up the color pre pass with a target name is a temporary solution
1887             if (createPrePassCam) {
1888                 camera.prePassColorTargetName = renderScene.name +
1889                                                 DefaultMaterialCameraConstants::CAMERA_COLOR_PREFIX_NAME +
1890                                                 to_hex(PREPASS_CAMERA_START_UNIQUE_ID);
1891             }
1892             tmpCameras.push_back(camera);
1893             ProcessCameraAddMultiViewHash(camera, mvChildToParent);
1894             // The order of setting cameras matter (main camera index is set already)
1895             if (createPrePassCam) {
1896                 tmpCameras.push_back(CreateColorPrePassRenderCamera(
1897                     *gpuHandleMgr_, *cameraMgr_, camera, component.prePassCamera, PREPASS_CAMERA_START_UNIQUE_ID));
1898             }
1899         }
1900     }
1901     // add cameras to data store
1902     for (auto& cam : tmpCameras) {
1903         // fill multi-view info
1904         if (cam.flags & RenderCamera::CAMERA_FLAG_MULTI_VIEW_ONLY_BIT) {
1905             if (const auto iter = mvChildToParent.find(cam.id); iter != mvChildToParent.cend()) {
1906                 cam.multiViewParentCameraId = iter->second;
1907             }
1908         }
1909         dsCamera_->AddCamera(cam);
1910     }
1911 }
1912 
ProcessReflection(const ComponentQuery::ResultRow & row,const RenderCamera & camera)1913 void RenderSystem::ProcessReflection(const ComponentQuery::ResultRow& row, const RenderCamera& camera)
1914 {
1915     // ReflectionsQuery has three required components:
1916     // (0) PlanarReflectionComponent
1917     // (1) WorldMatrixComponent
1918     // (2) NodeComponent
1919     // (3) RenderMeshComponent
1920     // Skip if this node is disabled.
1921     const NodeComponent nodeComponent = nodeMgr_->Get(row.components[2u]);
1922     if (!nodeComponent.effectivelyEnabled) {
1923         return;
1924     }
1925     PlanarReflectionComponent reflComponent = planarReflectionMgr_->Get(row.components[0u]);
1926     if ((reflComponent.additionalFlags & PlanarReflectionComponent::FlagBits::ACTIVE_RENDER_BIT) == 0) {
1927         return;
1928     }
1929 
1930     const WorldMatrixComponent reflectionPlaneMatrix = worldMatrixMgr_->Get(row.components[1u]);
1931 
1932     // cull plane (sphere) from camera
1933     bool insideFrustum = true;
1934     if (frustumUtil_ && picking_) {
1935         const RenderMeshComponent rmc = renderMeshMgr_->Get(row.components[3U]);
1936         if (const auto meshHandle = meshMgr_->Read(rmc.mesh); meshHandle) {
1937             // frustum planes created without jitter
1938             const Frustum frustum = frustumUtil_->CreateFrustum(camera.matrices.proj * camera.matrices.view);
1939             const auto mam =
1940                 picking_->GetWorldAABB(reflectionPlaneMatrix.matrix, meshHandle->aabbMin, meshHandle->aabbMax);
1941             const float radius = Math::Magnitude(mam.maxAABB - mam.minAABB) * 0.5f;
1942             const Math::Vec3 pos = Math::Vec3(reflectionPlaneMatrix.matrix[3U]);
1943             insideFrustum = frustumUtil_->SphereFrustumCollision(frustum, pos, radius);
1944             // NOTE: add normal check for camera (cull based on normal and camera view)
1945         }
1946     }
1947     if (!insideFrustum) {
1948         return; // early out
1949     }
1950 
1951     // Calculate reflected view matrix from camera matrix.
1952     // Reflection plane.
1953     const Math::Vec3 translation = reflectionPlaneMatrix.matrix.w;
1954     const Math::Vec3 normal = Math::Normalize(Math::GetColumn(reflectionPlaneMatrix.matrix, 1));
1955     const float distance = -Math::Dot(normal, translation) - reflComponent.clipOffset;
1956     const Math::Vec4 plane { normal.x, normal.y, normal.z, distance };
1957 
1958     // Calculate mirror matrix from plane.
1959     const Math::Mat4X4 reflection = CalculateReflectionMatrix(plane);
1960     const Math::Mat4X4 reflectedView = camera.matrices.view * reflection;
1961 
1962     Math::Mat4X4 reflectedProjection = camera.matrices.proj;
1963 
1964     // NOTE: Should modify near plane of projection matrix to clip in to reflection plane.
1965     // This effectively optimizes away the un-wanted objects that are behind the plane
1966     // and otherwise would be visible in the reflection.
1967     // e.g.
1968     // CalculateCameraSpaceClipPlane()
1969     // calculate camera-space projection matrix that has clip plane as near plane.
1970     // CalculateObliqueProjectionMatrix()
1971 
1972     const ReflectionPlaneTargetUpdate rptu = UpdatePlaneReflectionTargetResolution(
1973         *gpuResourceMgr_, *gpuHandleMgr_, *planarReflectionMgr_, camera, row.entity, reflComponent);
1974     if (rptu.recreated) {
1975         UpdateReflectionPlaneMaterial(*renderMeshMgr_, *meshMgr_, *materialMgr_, row.entity, reflComponent, rptu);
1976     }
1977 
1978     RenderCamera reflCam;
1979     const uint64_t reflCamId = Hash(row.entity.id, camera.id);
1980     reflCam.id = reflCamId;
1981     reflCam.mainCameraId = camera.id; // link to main camera
1982     reflCam.layerMask = reflComponent.layerMask;
1983     reflCam.matrices.view = reflectedView;
1984     reflCam.matrices.proj = reflectedProjection;
1985     const CameraData prevFrameCamData =
1986         UpdateAndGetPreviousFrameCameraData({ reflCamId }, reflCam.matrices.view, reflCam.matrices.proj);
1987     reflCam.matrices.viewPrevFrame = prevFrameCamData.view;
1988     reflCam.matrices.projPrevFrame = prevFrameCamData.proj;
1989     const auto xFactor = (static_cast<float>(camera.renderResolution[0]) * reflComponent.screenPercentage) /
1990                          static_cast<float>(reflComponent.renderTargetResolution[0]);
1991     const auto yFactor = (static_cast<float>(camera.renderResolution[1]) * reflComponent.screenPercentage) /
1992                          static_cast<float>(reflComponent.renderTargetResolution[1]);
1993     reflCam.viewport = { camera.viewport[0u] * xFactor, camera.viewport[1u] * yFactor, camera.viewport[2u] * xFactor,
1994         camera.viewport[3u] * yFactor };
1995     reflCam.depthTarget = gpuHandleMgr_->GetRenderHandleReference(reflComponent.depthRenderTarget);
1996     reflCam.colorTargets[0u] = gpuHandleMgr_->GetRenderHandleReference(reflComponent.colorRenderTarget);
1997 
1998     reflCam.renderResolution = { reflComponent.renderTargetResolution[0], reflComponent.renderTargetResolution[1] };
1999     reflCam.zNear = camera.zNear;
2000     reflCam.zFar = camera.zFar;
2001     reflCam.flags = (reflComponent.additionalFlags & PlanarReflectionComponent::FlagBits::MSAA_BIT)
2002                         ? RenderCamera::CAMERA_FLAG_MSAA_BIT
2003                         : 0U;
2004     reflCam.flags |= (RenderCamera::CAMERA_FLAG_REFLECTION_BIT | RenderCamera::CAMERA_FLAG_INVERSE_WINDING_BIT);
2005     reflCam.flags |= (RenderCamera::CAMERA_FLAG_CUSTOM_TARGETS_BIT);
2006     reflCam.renderPipelineType = RenderCamera::RenderPipelineType::LIGHT_FORWARD;
2007     reflCam.clearDepthStencil = camera.clearDepthStencil;
2008     reflCam.clearColorValues = camera.clearColorValues;
2009     reflCam.cullType = RenderCamera::CameraCullType::CAMERA_CULL_VIEW_FRUSTUM;
2010     reflCam.environment = camera.environment;
2011     reflCam.environmentCount =
2012         Math::min(camera.environmentCount, DefaultMaterialCameraConstants::MAX_ENVIRONMENT_COUNT);
2013     CloneData(reflCam.environmentIds, sizeof(reflCam.environmentIds), camera.environmentIds,
2014         sizeof(camera.environmentIds[0U]) * reflCam.environmentCount);
2015     reflCam.postProcessName = DefaultMaterialCameraConstants::CAMERA_REFLECTION_POST_PROCESS_PREFIX_NAME;
2016     dsCamera_->AddCamera(reflCam);
2017 }
2018 
ProcessReflections(const RenderScene & renderScene)2019 void RenderSystem::ProcessReflections(const RenderScene& renderScene)
2020 {
2021     const size_t cameraCount = dsCamera_->GetCameraCount();
2022     if (cameraCount == 0) {
2023         return; // early out
2024     }
2025 
2026     reflectionsQuery_.Execute();
2027     const auto queryResults = reflectionsQuery_.GetResults();
2028     if (queryResults.empty()) {
2029         return; // early out
2030     }
2031 
2032     constexpr RenderCamera::Flags disableFlags { RenderCamera::CAMERA_FLAG_REFLECTION_BIT |
2033                                                  RenderCamera::CAMERA_FLAG_SHADOW_BIT |
2034                                                  RenderCamera::CAMERA_FLAG_OPAQUE_BIT };
2035     constexpr RenderCamera::Flags enableFlags { RenderCamera::CAMERA_FLAG_ALLOW_REFLECTION_BIT };
2036     for (const auto& row : queryResults) {
2037         for (size_t camIdx = 0; camIdx < cameraCount; ++camIdx) {
2038             const auto& cameras = dsCamera_->GetCameras();
2039             if (camIdx < cameras.size()) {
2040                 const auto& cam = cameras[camIdx];
2041                 if (((cam.flags & disableFlags) == 0) && ((cam.flags & enableFlags) != 0)) {
2042                     ProcessReflection(row, cam);
2043                 }
2044             }
2045         }
2046     }
2047 }
2048 
ProcessLight(const LightProcessData & lpd)2049 void RenderSystem::ProcessLight(const LightProcessData& lpd)
2050 {
2051     const auto& lightComponent = lpd.lightComponent;
2052     RenderLight light { lpd.entity.id, lightComponent.lightLayerMask,
2053         { lpd.world[3u], 1.0f }, // the last column (3) of the world matrix contains the world position.
2054         { Math::Normalize(lpd.world * Math::Vec4(0.0f, 0.0f, -1.0f, 0.0f)), 0.0f },
2055         { lightComponent.color, lightComponent.intensity } };
2056 
2057     // See:
2058     // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
2059     const float outer = Math::clamp(lightComponent.spotOuterAngle, lightComponent.spotInnerAngle, Math::PI / 2.0f);
2060     const float inner = Math::clamp(lightComponent.spotInnerAngle, 0.0f, outer);
2061 
2062     if (lightComponent.type == LightComponent::Type::DIRECTIONAL) {
2063         light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT;
2064     } else if (lightComponent.type == LightComponent::Type::POINT) {
2065         light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_POINT_LIGHT_BIT;
2066     } else if (lightComponent.type == LightComponent::Type::SPOT) {
2067         light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_SPOT_LIGHT_BIT;
2068 
2069         const float cosInnerConeAngle = cosf(inner);
2070         const float cosOuterConeAngle = cosf(outer);
2071 
2072         const float lightAngleScale = 1.0f / Math::max(0.001f, cosInnerConeAngle - cosOuterConeAngle);
2073         const float lightAngleOffset = -cosOuterConeAngle * lightAngleScale;
2074 
2075         light.spotLightParams = { lightAngleScale, lightAngleOffset, inner, outer };
2076     }
2077     light.range = ComponentUtilFunctions::CalculateSafeLightRange(lightComponent.range, lightComponent.intensity);
2078 
2079     if (lightComponent.shadowEnabled) {
2080         light.shadowFactors = { Math::clamp01(lightComponent.shadowStrength), lightComponent.shadowDepthBias,
2081             lightComponent.shadowNormalBias, 0.0f };
2082         ProcessShadowCamera(lpd, light);
2083     }
2084 
2085     dsLight_->AddLight(light);
2086 }
2087 
ProcessShadowCamera(const LightProcessData lpd,RenderLight & light)2088 void RenderSystem::ProcessShadowCamera(const LightProcessData lpd, RenderLight& light)
2089 {
2090     if ((light.lightUsageFlags &
2091             (RenderLight::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT | RenderLight::LIGHT_USAGE_SPOT_LIGHT_BIT)) == 0) {
2092         return;
2093     }
2094     light.shadowCameraIndex = static_cast<uint32_t>(dsCamera_->GetCameraCount());
2095     if (light.shadowCameraIndex >= DefaultMaterialCameraConstants::MAX_CAMERA_COUNT) {
2096         light.shadowCameraIndex = ~0u;
2097         light.lightUsageFlags &= (~RenderLight::LightUsageFlagBits::LIGHT_USAGE_SHADOW_LIGHT_BIT);
2098 #if (CORE3D_VALIDATION_ENABLED == 1)
2099         const string onceName = string(to_string(light.id) + "_too_many_cam");
2100         CORE_LOG_ONCE_W(onceName, "CORE3D_VALIDATION: shadow camera dropped, too many cameras in scene");
2101 #endif
2102         return; // early out
2103     }
2104     light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_SHADOW_LIGHT_BIT;
2105 
2106     float zNear = 0.0f;
2107     float zFar = 0.0f;
2108     RenderCamera camera;
2109     camera.id = SHADOW_CAMERA_START_UNIQUE_ID + light.shadowCameraIndex; // id used for easier uniqueness
2110     camera.shadowId = lpd.entity.id;
2111     camera.layerMask = lpd.lightComponent.shadowLayerMask; // we respect light shadow rendering mask
2112     if (light.lightUsageFlags & RenderLight::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT) {
2113         // NOTE: modifies the light camera to follow center of scene
2114         // Add slight bias offset to radius.
2115 #if (CORE3D_VALIDATION_ENABLED == 1)
2116         if (std::isinf(lpd.renderScene.worldSceneBoundingSphereRadius)) {
2117             CORE_LOG_ONCE_W("inf_scene", "Infinite world bounding sphere, shadows won't be visible.");
2118         }
2119 #endif
2120         const float nonZeroRadius = Math::max(lpd.renderScene.worldSceneBoundingSphereRadius, Math::EPSILON);
2121         const float radius = nonZeroRadius + nonZeroRadius * 0.05f;
2122         const Math::Vec3 lightPos =
2123             lpd.renderScene.worldSceneCenter - Math::Vec3(light.dir.x, light.dir.y, light.dir.z) * radius;
2124         camera.matrices.view = Math::LookAtRh(lightPos, lpd.renderScene.worldSceneCenter, { 0.0f, 1.0f, 0.0f });
2125         camera.matrices.proj = Math::OrthoRhZo(-radius, radius, -radius, radius, 0.001f, radius * 2.0f);
2126         zNear = 0.0f;
2127         zFar = 6.0f;
2128     } else if (light.lightUsageFlags & RenderLight::LIGHT_USAGE_SPOT_LIGHT_BIT) {
2129         float determinant = 0.0f;
2130         camera.matrices.view = Math::Inverse(lpd.world, determinant);
2131         const float yFov = Math::clamp(light.spotLightParams.w * 2.0f, 0.0f, Math::PI);
2132         zFar = light.range; // use light range for z far
2133         zNear = Math::max(0.1f, lpd.lightComponent.nearPlane);
2134         camera.matrices.proj = Math::PerspectiveRhZo(yFov, 1.0f, zNear, zFar);
2135     }
2136 
2137     camera.matrices.proj[1][1] *= -1.0f; // left-hand NDC while Vulkan right-handed -> flip y
2138 
2139     const CameraData prevFrameCamData =
2140         UpdateAndGetPreviousFrameCameraData(lpd.entity, camera.matrices.viewPrevFrame, camera.matrices.projPrevFrame);
2141     camera.matrices.viewPrevFrame = prevFrameCamData.view;
2142     camera.matrices.projPrevFrame = prevFrameCamData.proj;
2143     camera.viewport = { 0.0f, 0.0f, 1.0f, 1.0f };
2144     // get current default resolution
2145     camera.renderResolution = dsLight_->GetShadowQualityResolution();
2146     // NOTE: custom shadow camera targets not yet supported
2147     camera.zNear = zNear;
2148     camera.zFar = zFar;
2149     camera.flags = RenderCamera::CAMERA_FLAG_SHADOW_BIT;
2150     camera.cullType = RenderCamera::CameraCullType::CAMERA_CULL_VIEW_FRUSTUM;
2151 
2152     dsCamera_->AddCamera(camera);
2153 }
2154 
ProcessLights(RenderScene & renderScene)2155 void RenderSystem::ProcessLights(RenderScene& renderScene)
2156 {
2157     lightQuery_.Execute();
2158 
2159     uint32_t spotLightIndex = 0;
2160     for (const auto& row : lightQuery_.GetResults()) {
2161         // In addition to the base our lightQuery has two required components and two optional components:
2162         // (0) LightComponent
2163         // (1) NodeComponent
2164         // (2) WorldMatrixComponent
2165         const LightComponent lightComponent = lightMgr_->Get(row.components[0u]);
2166         const NodeComponent nodeComponent = nodeMgr_->Get(row.components[1u]);
2167         const WorldMatrixComponent renderMatrixComponent = worldMatrixMgr_->Get(row.components[2u]);
2168         const uint64_t layerMask = !row.IsValidComponentId(3u) ? LayerConstants::DEFAULT_LAYER_MASK
2169                                                                : layerMgr_->Get(row.components[3u]).layerMask;
2170         if (nodeComponent.effectivelyEnabled) {
2171             const Math::Mat4X4 world(renderMatrixComponent.matrix.data);
2172             const LightProcessData lpd { layerMask, row.entity, lightComponent, world, renderScene, spotLightIndex };
2173             ProcessLight(lpd);
2174         }
2175     }
2176 }
2177 
ProcessPostProcesses()2178 void RenderSystem::ProcessPostProcesses()
2179 {
2180     if (renderContext_ && postProcessMgr_ && postProcessConfigMgr_) {
2181         IRenderDataStoreManager& rdsMgr = renderContext_->GetRenderDataStoreManager();
2182         auto* dsPod = static_cast<IRenderDataStorePod*>(rdsMgr.GetRenderDataStore(POD_DATA_STORE_NAME));
2183         auto* dsPp = static_cast<IRenderDataStorePostProcess*>(rdsMgr.GetRenderDataStore(PP_DATA_STORE_NAME));
2184         if ((!dsPod) || (!dsPp)) {
2185             return;
2186         }
2187 
2188         const auto postProcessCount = postProcessMgr_->GetComponentCount();
2189         for (IComponentManager::ComponentId id = 0; id < postProcessCount; ++id) {
2190             if (const auto handle = postProcessMgr_->Read(id); handle) {
2191                 const auto& pp = *handle;
2192 
2193                 // just copy values (no support for fog control)
2194                 PostProcessConfiguration ppConfig;
2195                 ppConfig.enableFlags = pp.enableFlags;
2196                 ppConfig.bloomConfiguration = pp.bloomConfiguration;
2197                 ppConfig.vignetteConfiguration = pp.vignetteConfiguration;
2198                 ppConfig.colorFringeConfiguration = pp.colorFringeConfiguration;
2199                 ppConfig.ditherConfiguration = pp.ditherConfiguration;
2200                 ppConfig.blurConfiguration = pp.blurConfiguration;
2201                 ppConfig.colorConversionConfiguration = pp.colorConversionConfiguration;
2202                 ppConfig.tonemapConfiguration = pp.tonemapConfiguration;
2203                 ppConfig.fxaaConfiguration = pp.fxaaConfiguration;
2204                 ppConfig.taaConfiguration = pp.taaConfiguration;
2205                 ppConfig.dofConfiguration = pp.dofConfiguration;
2206                 ppConfig.motionBlurConfiguration = pp.motionBlurConfiguration;
2207 
2208                 const Entity ppEntity = postProcessMgr_->GetEntity(id);
2209                 const auto ppName = GetPostProcessName(
2210                     postProcessMgr_, postProcessConfigMgr_, nameMgr_, properties_.dataStoreScene, ppEntity);
2211                 auto const dataView = dsPod->Get(ppName);
2212                 if (dataView.data() && (dataView.size_bytes() == sizeof(PostProcessConfiguration))) {
2213                     dsPod->Set(ppName, arrayviewU8(ppConfig));
2214                 } else {
2215                     renderProcessing_.postProcessPods.emplace_back(ppName);
2216                     dsPod->CreatePod(POST_PROCESS_NAME, ppName, arrayviewU8(ppConfig));
2217                 }
2218             }
2219         }
2220         const auto postProcessConfigCount = postProcessConfigMgr_->GetComponentCount();
2221         for (IComponentManager::ComponentId id = 0; id < postProcessConfigCount; ++id) {
2222             // NOTE: should check if nothing has changed and not copy data if it has not changed
2223             if (const auto handle = postProcessConfigMgr_->Read(id); handle) {
2224                 const auto& pp = *handle;
2225                 const Entity ppEntity = postProcessConfigMgr_->GetEntity(id);
2226                 const auto ppName = GetPostProcessName(
2227                     postProcessMgr_, postProcessConfigMgr_, nameMgr_, properties_.dataStoreScene, ppEntity);
2228                 if (!dsPp->Contains(ppName)) {
2229                     renderProcessing_.postProcessConfigs.emplace_back(ppName);
2230                     dsPp->Create(ppName);
2231                 }
2232                 for (const auto& ref : pp.postProcesses) {
2233                     const IRenderDataStorePostProcess::PostProcess::Variables vars =
2234                         FillPostProcessConfigurationVars(ref);
2235                     if (dsPp->Contains(ppName, ref.name)) {
2236                         dsPp->Set(ppName, ref.name, vars);
2237                     } else {
2238                         RenderHandleReference shader = gpuHandleMgr_->GetRenderHandleReference(ref.shader);
2239                         dsPp->Create(ppName, ref.name, move(shader));
2240                         dsPp->Set(ppName, ref.name, vars);
2241                     }
2242                 }
2243             }
2244         }
2245     }
2246 }
2247 
DestroyRenderDataStores()2248 void RenderSystem::DestroyRenderDataStores()
2249 {
2250     if (IEngine* engine = ecs_.GetClassFactory().GetInterface<IEngine>(); engine) {
2251         // check that render context is still alive
2252         if (auto renderContext =
2253                 GetInstance<IRenderContext>(*engine->GetInterface<IClassRegister>(), UID_RENDER_CONTEXT);
2254             renderContext) {
2255             IRenderDataStoreManager& rdsMgr = renderContext_->GetRenderDataStoreManager();
2256             if (auto* dataStore = static_cast<IRenderDataStorePod*>(rdsMgr.GetRenderDataStore(POD_DATA_STORE_NAME));
2257                 dataStore) {
2258                 for (const auto& ref : renderProcessing_.postProcessPods) {
2259                     dataStore->DestroyPod(POST_PROCESS_NAME, ref.c_str());
2260                 }
2261             }
2262             if (auto* dataStore =
2263                     static_cast<IRenderDataStorePostProcess*>(rdsMgr.GetRenderDataStore(PP_DATA_STORE_NAME));
2264                 dataStore) {
2265                 for (const auto& ref : renderProcessing_.postProcessConfigs) {
2266                     dataStore->Destroy(ref.c_str());
2267                 }
2268             }
2269         }
2270     }
2271 }
2272 
FetchFullScene()2273 void RenderSystem::FetchFullScene()
2274 {
2275     if (!active_) {
2276         return;
2277     }
2278 
2279 #if (CORE3D_DEV_ENABLED == 1)
2280     CORE_CPU_PERF_BEGIN(graphCpuTimer, "ECS", "RenderSystem", "FetchRenderables_Cpu");
2281 #endif
2282 
2283     // Process scene settings (if present), look up first active scene.
2284     const RenderConfigurationComponent renderConfig = GetRenderConfigurationComponent();
2285     const Entity cameraEntity = ProcessScene(renderConfig);
2286 
2287     RenderScene renderDataScene;
2288     renderDataScene.customRenderNodeGraphFile = renderConfig.customRenderNodeGraphFile;
2289     renderDataScene.customPostSceneRenderNodeGraphFile = renderConfig.customPostSceneRenderNodeGraphFile;
2290     renderDataScene.name = properties_.dataStoreScene;
2291     renderDataScene.dataStoreNamePrefix = properties_.dataStorePrefix;
2292     renderDataScene.dataStoreNameCamera = properties_.dataStoreCamera;
2293     renderDataScene.dataStoreNameLight = properties_.dataStoreLight;
2294     renderDataScene.dataStoreNameMaterial = properties_.dataStoreMaterial;
2295     renderDataScene.dataStoreNameMorph = properties_.dataStoreMorph;
2296     constexpr double uToMsDiv = 1000.0;
2297     constexpr double uToSDiv = 1000000.0;
2298     renderDataScene.sceneDeltaTime =
2299         static_cast<float>(static_cast<double>(deltaTime_) / uToMsDiv); // real delta time used for scene as well
2300     renderDataScene.totalTime = static_cast<float>(static_cast<double>(totalTime_) / uToSDiv);
2301     renderDataScene.deltaTime = renderDataScene.sceneDeltaTime;
2302     renderDataScene.frameIndex = static_cast<uint32_t>((frameIndex_ % std::numeric_limits<uint32_t>::max()));
2303     renderProcessing_.frameFlags = 0; // zero frame flags for camera processing
2304 
2305     ProcessEnvironments(renderConfig);
2306     ProcessCameras(renderConfig, cameraEntity, renderDataScene);
2307     ProcessReflections(renderDataScene);
2308     ProcessPostProcesses();
2309 
2310     // Process all render components.
2311     ProcessRenderables();
2312 
2313     // Process render node graphs automatically based on camera if needed bits set for properties
2314     // Some materials might request color pre-pass etc. (needs to be done after renderables are processed)
2315     ProcessRenderNodeGraphs(renderConfig, renderDataScene);
2316 
2317     // NOTE: move world sphere calculation to own system
2318     const auto boundingSphere = static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetBoundingSphere();
2319     sceneBoundingSpherePosition_ = boundingSphere.center;
2320     sceneBoundingSphereRadius_ = boundingSphere.radius;
2321 
2322     renderDataScene.worldSceneCenter = sceneBoundingSpherePosition_;
2323     renderDataScene.worldSceneBoundingSphereRadius = sceneBoundingSphereRadius_;
2324 
2325     // Process lights.
2326     ProcessLights(renderDataScene);
2327 
2328     dsScene_->SetScene(renderDataScene);
2329 
2330     // Remove prev frame data from not used cameras
2331     for (auto iter = cameraData_.begin(); iter != cameraData_.end();) {
2332         if (iter->second.lastFrameIndex != frameIndex_) {
2333             iter = cameraData_.erase(iter);
2334         } else {
2335             ++iter;
2336         }
2337     }
2338 
2339 #if (CORE3D_DEV_ENABLED == 1)
2340     CORE_CPU_PERF_END(graphCpuTimer);
2341 #endif
2342 }
2343 
ProcessRenderNodeGraphs(const RenderConfigurationComponent & renderConfig,const RenderScene & renderScene)2344 void RenderSystem::ProcessRenderNodeGraphs(
2345     const RenderConfigurationComponent& renderConfig, const RenderScene& renderScene)
2346 {
2347     auto& orderedRngs = renderProcessing_.orderedRenderNodeGraphs;
2348     orderedRngs.clear();
2349     const bool createRngs =
2350         (renderConfig.renderingFlags & RenderConfigurationComponent::SceneRenderingFlagBits::CREATE_RNGS_BIT);
2351     if (createRngs && graphicsContext_ && renderUtil_) {
2352         struct CameraOrdering {
2353             uint64_t id { RenderSceneDataConstants::INVALID_ID };
2354             uint64_t mainId { RenderSceneDataConstants::INVALID_ID };
2355             size_t renderCameraIdx { 0 };
2356         };
2357         const auto& renderCameras = dsCamera_->GetCameras();
2358         vector<CameraOrdering> baseCameras;
2359         vector<CameraOrdering> depCameras;
2360         baseCameras.reserve(renderCameras.size());
2361         depCameras.reserve(renderCameras.size());
2362         size_t mainCamIdx = size_t(~0);
2363         // ignore shadow and multi-view only cameras
2364         constexpr uint32_t ignoreFlags { RenderCamera::CAMERA_FLAG_SHADOW_BIT |
2365                                          RenderCamera::CAMERA_FLAG_MULTI_VIEW_ONLY_BIT };
2366         for (size_t camIdx = 0; camIdx < renderCameras.size(); ++camIdx) {
2367             const auto& cam = renderCameras[camIdx];
2368             if ((cam.flags & ignoreFlags) == 0) {
2369                 if (cam.flags & RenderCamera::CAMERA_FLAG_MAIN_BIT) {
2370                     mainCamIdx = camIdx;
2371                 } else {
2372                     if (cam.mainCameraId == RenderSceneDataConstants::INVALID_ID) {
2373                         baseCameras.push_back({ cam.id, cam.mainCameraId, camIdx });
2374                     } else {
2375                         // do not add pre-pass camera if render processing does not need it
2376                         if (cam.flags & RenderCamera::CAMERA_FLAG_COLOR_PRE_PASS_BIT) {
2377                             if (renderProcessing_.frameFlags & NEEDS_COLOR_PRE_PASS) {
2378                                 depCameras.push_back({ cam.id, cam.mainCameraId, camIdx });
2379                             }
2380                         } else {
2381                             depCameras.push_back({ cam.id, cam.mainCameraId, camIdx });
2382                         }
2383                     }
2384                 }
2385             }
2386         }
2387         // main camera needs to be the last
2388         if (mainCamIdx < renderCameras.size()) {
2389             const auto& cam = renderCameras[mainCamIdx];
2390             baseCameras.push_back({ cam.id, cam.mainCameraId, mainCamIdx });
2391         }
2392         // insert dependency cameras to correct positions
2393         for (const auto& depCam : depCameras) {
2394             for (size_t idx = 0; idx < baseCameras.size(); ++idx) {
2395                 if (depCam.mainId == baseCameras[idx].id) {
2396                     baseCameras.insert(baseCameras.begin() + int64_t(idx), depCam);
2397                     break;
2398                 }
2399             }
2400         }
2401         // now cameras are in correct order if the dependencied were correct in RenderCameras
2402 
2403         // first create scene render node graph if needed
2404         // we need to have scene render node graph as a separate
2405         orderedRngs.push_back(GetSceneRenderNodeGraph(renderScene));
2406 
2407         // then, add valid camera render node graphs
2408         for (const auto& cam : baseCameras) {
2409             CORE_ASSERT(cam.renderCameraIdx < renderCameras.size());
2410             const auto& camRef = renderCameras[cam.renderCameraIdx];
2411             CORE_ASSERT(camRef.id != 0xFFFFFFFFffffffff); // there must be an id for uniqueness
2412             CameraRngsOutput camRngs = GetCameraRenderNodeGraphs(renderScene, camRef);
2413             if (camRngs.rngs.rngHandle) {
2414                 orderedRngs.push_back(move(camRngs.rngs.rngHandle));
2415                 if (camRngs.rngs.ppRngHandle) {
2416                     orderedRngs.push_back(move(camRngs.rngs.ppRngHandle));
2417                 }
2418                 for (uint32_t mvIdx = 0U; mvIdx < RenderSceneDataConstants::MAX_MULTI_VIEW_LAYER_CAMERA_COUNT;
2419                      ++mvIdx) {
2420                     if (camRngs.multiviewPpHandles[mvIdx]) {
2421                         orderedRngs.push_back(move(camRngs.multiviewPpHandles[mvIdx]));
2422                     }
2423                 }
2424             }
2425         }
2426         // then possible post scene custom render node graph
2427         if (renderProcessing_.sceneRngs.customPostRng) {
2428             orderedRngs.push_back(renderProcessing_.sceneRngs.customPostRng);
2429         }
2430         // destroy unused after two frames
2431         const uint64_t ageLimit = (frameIndex_ < 2) ? 0 : (frameIndex_ - 2);
2432         for (auto iter = renderProcessing_.camIdToRng.begin(); iter != renderProcessing_.camIdToRng.end();) {
2433             if (iter->second.enableAutoDestroy && iter->second.lastFrameIndex < ageLimit) {
2434                 iter = renderProcessing_.camIdToRng.erase(iter);
2435             } else {
2436                 ++iter;
2437             }
2438         }
2439     }
2440 }
2441 
GetCameraRenderNodeGraphs(const RenderScene & renderScene,const RenderCamera & renderCamera)2442 RenderSystem::CameraRngsOutput RenderSystem::GetCameraRenderNodeGraphs(
2443     const RenderScene& renderScene, const RenderCamera& renderCamera)
2444 {
2445     constexpr uint32_t rngChangeFlags =
2446         RenderCamera::CAMERA_FLAG_MSAA_BIT | RenderCamera::CAMERA_FLAG_CUSTOM_TARGETS_BIT;
2447     auto createNewRngs = [](auto& rngm, const auto& rnUtil, const auto& scene, const auto& obj, const auto& mvCams) {
2448         const auto descs = rnUtil->GetRenderNodeGraphDescs(scene, obj, 0, mvCams);
2449         CameraRngsOutput rngs;
2450         rngs.rngs.rngHandle = rngm.Create(
2451             IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, descs.camera, {}, scene.name);
2452         if (!descs.postProcess.nodes.empty()) {
2453             rngs.rngs.ppRngHandle =
2454                 rngm.Create(IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC,
2455                     descs.postProcess, {}, scene.name);
2456         }
2457         for (size_t mvIdx = 0; mvIdx < mvCams.size(); ++mvIdx) {
2458             rngs.multiviewPpHandles[mvIdx] =
2459                 rngm.Create(IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC,
2460                     descs.multiViewCameraPostProcesses[mvIdx], {}, scene.name);
2461         }
2462         return rngs;
2463     };
2464 
2465     IRenderNodeGraphManager& rngm = renderContext_->GetRenderNodeGraphManager();
2466     CameraRngsOutput rngs;
2467     rngs.rngs.rngHandle = renderCamera.customRenderNodeGraph;
2468     if (!rngs.rngs.rngHandle) {
2469         if (auto iter = renderProcessing_.camIdToRng.find(renderCamera.id);
2470             iter != renderProcessing_.camIdToRng.cend()) {
2471             // NOTE: not optimal, currently re-creates a render node graph if:
2472             // * msaa flags have changed
2473             // * post process name / component has changed
2474             // * pipeline has changed
2475             // * rng files have changed
2476             // * multi-view count has changed
2477             const bool reCreate =
2478                 ((iter->second.flags & rngChangeFlags) != (renderCamera.flags & rngChangeFlags)) ||
2479                 (iter->second.postProcessName != renderCamera.postProcessName) ||
2480                 (iter->second.renderPipelineType != renderCamera.renderPipelineType) ||
2481                 (iter->second.customRngFile != renderCamera.customRenderNodeGraphFile) ||
2482                 (iter->second.customPostProcessRngFile != renderCamera.customPostProcessRenderNodeGraphFile) ||
2483                 (iter->second.multiViewCameraCount != renderCamera.multiViewCameraCount);
2484             if (reCreate) {
2485                 iter->second.rngs = {};
2486                 const vector<RenderCamera> multiviewCameras = GetMultiviewCameras(renderCamera);
2487                 auto newRngs = createNewRngs(rngm, renderUtil_, renderScene, renderCamera, multiviewCameras);
2488                 // copy
2489                 rngs = newRngs;
2490                 iter->second.rngs = move(newRngs.rngs);
2491                 // update multiview post process
2492                 for (size_t mvIdx = 0; mvIdx < multiviewCameras.size(); ++mvIdx) {
2493                     const auto& mvCamera = multiviewCameras[mvIdx];
2494                     auto& mvData = renderProcessing_.camIdToRng[mvCamera.id];
2495                     mvData.rngs.ppRngHandle = move(newRngs.multiviewPpHandles[mvIdx]);
2496                     mvData.lastFrameIndex = frameIndex_;
2497                 }
2498             } else {
2499                 // found and copy the handles
2500                 rngs.rngs = iter->second.rngs;
2501                 // multiview post processes
2502                 for (uint32_t mvIdx = 0; mvIdx < renderCamera.multiViewCameraCount; ++mvIdx) {
2503                     auto& mvData = renderProcessing_.camIdToRng[renderCamera.multiViewCameraIds[mvIdx]];
2504                     rngs.multiviewPpHandles[mvIdx] = mvData.rngs.ppRngHandle;
2505                     mvData.lastFrameIndex = frameIndex_;
2506                 }
2507             }
2508             iter->second.lastFrameIndex = frameIndex_;
2509             iter->second.flags = renderCamera.flags;
2510             iter->second.renderPipelineType = renderCamera.renderPipelineType;
2511             iter->second.postProcessName = renderCamera.postProcessName;
2512             iter->second.customRngFile = renderCamera.customRenderNodeGraphFile;
2513             iter->second.customPostProcessRngFile = renderCamera.customPostProcessRenderNodeGraphFile;
2514             iter->second.multiViewCameraCount = renderCamera.multiViewCameraCount;
2515         } else {
2516             const vector<RenderCamera> multiviewCameras = GetMultiviewCameras(renderCamera);
2517             auto newRngs = createNewRngs(rngm, renderUtil_, renderScene, renderCamera, multiviewCameras);
2518             rngs = newRngs;
2519             renderProcessing_.camIdToRng[renderCamera.id] = { move(newRngs.rngs), renderCamera.flags,
2520                 renderCamera.renderPipelineType, frameIndex_, true, renderCamera.postProcessName,
2521                 renderCamera.customRenderNodeGraphFile, renderCamera.customPostProcessRenderNodeGraphFile,
2522                 renderCamera.multiViewCameraCount };
2523             // update multiview post process
2524             for (size_t mvIdx = 0; mvIdx < multiviewCameras.size(); ++mvIdx) {
2525                 const auto& mvCamera = multiviewCameras[mvIdx];
2526                 auto& mvData = renderProcessing_.camIdToRng[mvCamera.id];
2527                 mvData.rngs.ppRngHandle = move(newRngs.multiviewPpHandles[mvIdx]);
2528                 mvData.lastFrameIndex = frameIndex_;
2529             }
2530         }
2531     }
2532     return rngs;
2533 }
2534 
GetSceneRenderNodeGraph(const RenderScene & renderScene)2535 RenderHandleReference RenderSystem::GetSceneRenderNodeGraph(const RenderScene& renderScene)
2536 {
2537     IRenderNodeGraphManager& rngm = renderContext_->GetRenderNodeGraphManager();
2538     auto createNewRng = [](auto& rngm, const auto& rnUtil, const auto& scene) {
2539         const RenderNodeGraphDesc desc = rnUtil->GetRenderNodeGraphDesc(scene, 0);
2540         return rngm.Create(
2541             IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, desc, {}, scene.name);
2542     };
2543     auto createNewCustomRng = [](auto& rngm, const auto& rnUtil, const auto& scene, const auto& rngFile) {
2544         const RenderNodeGraphDesc desc = rnUtil->GetRenderNodeGraphDesc(scene, rngFile, 0);
2545         return rngm.Create(
2546             IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, desc, {}, scene.name);
2547     };
2548 
2549     // first check if there's custom render node graph file
2550     // if not, use the default
2551     RenderHandleReference handle;
2552     if (!renderScene.customRenderNodeGraphFile.empty()) {
2553         const bool reCreate = (renderProcessing_.sceneRngs.customRngFile != renderScene.customRenderNodeGraphFile);
2554         if (reCreate) {
2555             renderProcessing_.sceneRngs.customRng = createNewRng(rngm, renderUtil_, renderScene);
2556         }
2557         handle = renderProcessing_.sceneRngs.customRng;
2558         renderProcessing_.sceneRngs.customRngFile = renderScene.customRenderNodeGraphFile;
2559     } else {
2560         // clear
2561         renderProcessing_.sceneRngs.customRng = {};
2562         renderProcessing_.sceneRngs.customRngFile.clear();
2563     }
2564     if (!handle) {
2565         if (!renderProcessing_.sceneRngs.rng) {
2566             renderProcessing_.sceneRngs.rng = createNewRng(rngm, renderUtil_, renderScene);
2567         }
2568         handle = renderProcessing_.sceneRngs.rng;
2569     }
2570 
2571     // process custom post scene render node graph
2572     // NOTE: it is not returned by the method
2573     if (!renderScene.customPostSceneRenderNodeGraphFile.empty()) {
2574         const bool reCreate =
2575             (renderProcessing_.sceneRngs.customPostSceneRngFile != renderScene.customPostSceneRenderNodeGraphFile);
2576         if (reCreate) {
2577             renderProcessing_.sceneRngs.customPostRng =
2578                 createNewCustomRng(rngm, renderUtil_, renderScene, renderScene.customPostSceneRenderNodeGraphFile);
2579         }
2580         renderProcessing_.sceneRngs.customPostSceneRngFile = renderScene.customPostSceneRenderNodeGraphFile;
2581     } else {
2582         // clear
2583         renderProcessing_.sceneRngs.customPostRng = {};
2584         renderProcessing_.sceneRngs.customPostSceneRngFile.clear();
2585     }
2586 
2587     return handle;
2588 }
2589 
GetRenderNodeGraphs() const2590 array_view<const RenderHandleReference> RenderSystem::GetRenderNodeGraphs() const
2591 {
2592     if (renderProcessing_.frameProcessed) {
2593         return renderProcessing_.orderedRenderNodeGraphs;
2594     } else {
2595         return {};
2596     }
2597 }
2598 
UpdateAndGetPreviousFrameCameraData(const Entity & entity,const Math::Mat4X4 & view,const Math::Mat4X4 & proj)2599 RenderSystem::CameraData RenderSystem::UpdateAndGetPreviousFrameCameraData(
2600     const Entity& entity, const Math::Mat4X4& view, const Math::Mat4X4& proj)
2601 {
2602     CameraData currData = { view, proj, frameIndex_ };
2603     if (auto iter = cameraData_.find(entity); iter != cameraData_.end()) {
2604         const CameraData prevData = iter->second;
2605         iter->second = currData;
2606         return prevData; // correct previous frame matrices
2607     } else {
2608         cameraData_.insert_or_assign(entity, currData);
2609         return currData; // current frame returned because of no prev frame matrices
2610     }
2611 }
2612 
GetMultiviewCameras(const RenderCamera & renderCamera)2613 vector<RenderCamera> RenderSystem::GetMultiviewCameras(const RenderCamera& renderCamera)
2614 {
2615     vector<RenderCamera> mvCameras;
2616     if (renderCamera.multiViewCameraCount > 0U) {
2617         const auto& cameras = dsCamera_->GetCameras();
2618         for (uint32_t camIdx = 0; camIdx < renderCamera.multiViewCameraCount; ++camIdx) {
2619             const uint32_t ci = dsCamera_->GetCameraIndex(renderCamera.multiViewCameraIds[camIdx]);
2620             if (ci < cameras.size()) {
2621                 mvCameras.push_back(cameras[ci]);
2622             }
2623         }
2624     }
2625     return mvCameras;
2626 }
2627 
IRenderSystemInstance(IEcs & ecs)2628 ISystem* IRenderSystemInstance(IEcs& ecs)
2629 {
2630     return new RenderSystem(ecs);
2631 }
2632 
IRenderSystemDestroy(ISystem * instance)2633 void IRenderSystemDestroy(ISystem* instance)
2634 {
2635     delete static_cast<RenderSystem*>(instance);
2636 }
2637 CORE3D_END_NAMESPACE()
2638