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_node_default_cameras.h"
17 
18 #include <3d/render/default_material_constants.h>
19 #include <3d/render/intf_render_data_store_default_camera.h>
20 #include <3d/render/intf_render_data_store_default_light.h>
21 #include <base/containers/allocator.h>
22 #include <base/math/matrix_util.h>
23 #include <core/log.h>
24 #include <core/namespace.h>
25 #include <core/util/intf_frustum_util.h>
26 #include <render/datastore/intf_render_data_store.h>
27 #include <render/datastore/intf_render_data_store_manager.h>
28 #include <render/device/intf_gpu_resource_manager.h>
29 #include <render/nodecontext/intf_render_node_context_manager.h>
30 #include <render/nodecontext/intf_render_node_graph_share_manager.h>
31 
32 namespace {
33 #include "3d/shaders/common/3d_dm_structures_common.h"
34 } // namespace
35 
36 CORE3D_BEGIN_NAMESPACE()
37 using namespace BASE_NS;
38 using namespace CORE_NS;
39 using namespace RENDER_NS;
40 
41 namespace {
42 constexpr BASE_NS::Math::Mat4X4 ZERO_MATRIX_4X4 = {};
43 constexpr BASE_NS::Math::Mat4X4 SHADOW_BIAS_MATRIX = BASE_NS::Math::Mat4X4 { 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f,
44     0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.0f, 1.0f };
GetShadowBias(const uint32_t shadowIndex,const uint32_t shadowCount)45 constexpr BASE_NS::Math::Mat4X4 GetShadowBias(const uint32_t shadowIndex, const uint32_t shadowCount)
46 {
47     const float theShadowCount = static_cast<float>(Math::max(1u, shadowCount));
48     const float invShadowCount = (1.0f / theShadowCount);
49     const float sc = 0.5f * invShadowCount;
50     const float so = invShadowCount * static_cast<float>(shadowIndex);
51     return BASE_NS::Math::Mat4X4 { sc, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, sc + so, 0.5f,
52         0.0f, 1.0f };
53 }
54 
55 constexpr uint32_t HALTON_SAMPLE_COUNT { 16u };
GetHaltonOffset(const uint32_t haltonIndex)56 Math::Vec2 GetHaltonOffset(const uint32_t haltonIndex)
57 {
58     // positive halton
59     constexpr const Math::Vec2 halton16[] = {
60         { 0.500000f, 0.333333f }, // 00
61         { 0.250000f, 0.666667f }, // 01
62         { 0.750000f, 0.111111f }, // 02
63         { 0.125000f, 0.444444f }, // 03
64         { 0.625000f, 0.777778f }, // 04
65         { 0.375000f, 0.222222f }, // 05
66         { 0.875000f, 0.555556f }, // 06
67         { 0.062500f, 0.888889f }, // 07
68         { 0.562500f, 0.037037f }, // 08
69         { 0.312500f, 0.370370f }, // 09
70         { 0.812500f, 0.703704f }, // 10
71         { 0.187500f, 0.148148f }, // 11
72         { 0.687500f, 0.481481f }, // 12
73         { 0.437500f, 0.814815f }, // 13
74         { 0.937500f, 0.259259f }, // 14
75         { 0.031250f, 0.592593f }, // 15
76     };
77     return halton16[haltonIndex];
78 }
79 
GetPacked64(const uint64_t value)80 inline constexpr Math::UVec2 GetPacked64(const uint64_t value)
81 {
82     return { static_cast<uint32_t>(value >> 32) & 0xFFFFffff, static_cast<uint32_t>(value & 0xFFFFffff) };
83 }
84 
GetMultiViewCameraIndices(const IRenderDataStoreDefaultCamera * rds,const RenderCamera & cam)85 inline constexpr Math::UVec4 GetMultiViewCameraIndices(
86     const IRenderDataStoreDefaultCamera* rds, const RenderCamera& cam)
87 {
88     Math::UVec4 mvIndices { 0U, 0U, 0U, 0U };
89     CORE_STATIC_ASSERT(RenderSceneDataConstants::MAX_MULTI_VIEW_LAYER_CAMERA_COUNT == 3U);
90     const uint32_t inputCount = cam.multiViewCameraCount;
91     for (uint32_t idx = 0U; idx < inputCount; ++idx) {
92         const uint64_t id = cam.multiViewCameraIds[idx];
93         if (id != RenderSceneDataConstants::INVALID_ID) {
94             mvIndices[0U]++; // recalculates the count
95             mvIndices[mvIndices[0U]] = Math::min(rds->GetCameraIndex(id), CORE_DEFAULT_MATERIAL_MAX_CAMERA_COUNT - 1U);
96         }
97     }
98     return mvIndices;
99 }
100 } // namespace
101 
InitNode(IRenderNodeContextManager & renderNodeContextMgr)102 void RenderNodeDefaultCameras::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
103 {
104     renderNodeContextMgr_ = &renderNodeContextMgr;
105 
106     // Get IFrustumUtil from global plugin registry.
107     frustumUtil_ = GetInstance<IFrustumUtil>(UID_FRUSTUM_UTIL);
108 
109     const auto& renderNodeGraphData = renderNodeContextMgr_->GetRenderNodeGraphData();
110     stores_ = RenderNodeSceneUtil::GetSceneRenderDataStores(
111         renderNodeContextMgr, renderNodeGraphData.renderNodeGraphDataStoreName);
112     const string bufferName =
113         stores_.dataStoreNameScene.c_str() + DefaultMaterialCameraConstants::CAMERA_DATA_BUFFER_NAME;
114 
115     CORE_STATIC_ASSERT((sizeof(DefaultCameraMatrixStruct) % CORE_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT) == 0);
116     auto& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
117     resHandle_ = gpuResourceMgr.Create(
118         bufferName, { CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
119                         (CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT),
120                         CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER,
121                         sizeof(DefaultCameraMatrixStruct) * CORE_DEFAULT_MATERIAL_MAX_CAMERA_COUNT });
122     if (resHandle_) {
123         IRenderNodeGraphShareManager& rngShareMgr = renderNodeContextMgr_->GetRenderNodeGraphShareManager();
124         const RenderHandle handle = resHandle_.GetHandle();
125         rngShareMgr.RegisterRenderNodeOutputs({ &handle, 1u });
126     }
127 }
128 
PreExecuteFrame()129 void RenderNodeDefaultCameras::PreExecuteFrame()
130 {
131     if (resHandle_) {
132         IRenderNodeGraphShareManager& rngShareMgr = renderNodeContextMgr_->GetRenderNodeGraphShareManager();
133         const RenderHandle handle = resHandle_.GetHandle();
134         rngShareMgr.RegisterRenderNodeOutputs({ &handle, 1u });
135     }
136 }
137 
ExecuteFrame(IRenderCommandList & cmdList)138 void RenderNodeDefaultCameras::ExecuteFrame(IRenderCommandList& cmdList)
139 {
140     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
141     const IRenderDataStoreDefaultCamera* dsCamera =
142         static_cast<IRenderDataStoreDefaultCamera*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameCamera));
143     const IRenderDataStoreDefaultLight* dsLight =
144         static_cast<IRenderDataStoreDefaultLight*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameLight));
145     if (dsCamera) {
146         const auto& cameras = dsCamera->GetCameras();
147         if (!cameras.empty()) {
148             const auto& gpuResMgr = renderNodeContextMgr_->GetGpuResourceManager();
149             if (uint8_t* data = reinterpret_cast<uint8_t*>(gpuResMgr.MapBuffer(resHandle_.GetHandle())); data) {
150                 const uint32_t cameraCount =
151                     Math::min(CORE_DEFAULT_MATERIAL_MAX_CAMERA_COUNT, static_cast<uint32_t>(cameras.size()));
152 
153                 for (uint32_t idx = 0; idx < cameraCount; ++idx) {
154                     const auto& currCamera = cameras[idx];
155                     const Math::UVec4 mvCameraIndices = GetMultiViewCameraIndices(dsCamera, currCamera);
156                     auto dat =
157                         reinterpret_cast<DefaultCameraMatrixStruct*>(data + sizeof(DefaultCameraMatrixStruct) * idx);
158 
159                     const JitterProjection jp = GetProjectionMatrix(currCamera, false);
160                     const Math::Mat4X4 viewProj = jp.proj * currCamera.matrices.view;
161                     dat->view = currCamera.matrices.view;
162                     dat->proj = jp.proj;
163                     dat->viewProj = viewProj;
164 
165                     dat->viewInv = Math::Inverse(currCamera.matrices.view);
166                     dat->projInv = Math::Inverse(jp.proj);
167                     dat->viewProjInv = Math::Inverse(viewProj);
168 
169                     const JitterProjection jpPrevFrame = GetProjectionMatrix(currCamera, true);
170                     const Math::Mat4X4 viewProjPrevFrame = jpPrevFrame.proj * currCamera.matrices.viewPrevFrame;
171                     dat->viewPrevFrame = currCamera.matrices.viewPrevFrame;
172                     dat->projPrevFrame = jpPrevFrame.proj;
173                     dat->viewProjPrevFrame = viewProjPrevFrame;
174 
175                     // possible shadow matrices
176                     const Math::Mat4X4 shadowBias = GetShadowBiasMatrix(dsLight, currCamera);
177                     const Math::Mat4X4 shadowViewProj = shadowBias * viewProj;
178                     dat->shadowViewProj = shadowViewProj;
179                     dat->shadowViewProjInv = Math::Inverse(shadowViewProj);
180 
181                     // jitter data
182                     dat->jitter = jp.jitter;
183                     dat->jitterPrevFrame = jpPrevFrame.jitter;
184 
185                     const Math::UVec2 packedId = GetPacked64(currCamera.id);
186                     const Math::UVec2 packedLayer = GetPacked64(currCamera.layerMask);
187                     dat->indices = { packedId.x, packedId.y, packedLayer.x, packedLayer.y };
188                     dat->multiViewIndices = mvCameraIndices;
189 
190                     // frustum planes
191                     if (frustumUtil_) {
192                         // frustum planes created without jitter
193                         const Frustum frustum = frustumUtil_->CreateFrustum(jp.baseProj * currCamera.matrices.view);
194                         CloneData(dat->frustumPlanes, CORE_DEFAULT_CAMERA_FRUSTUM_PLANE_COUNT * sizeof(Math::Vec4),
195                             frustum.planes, Frustum::PLANE_COUNT * sizeof(Math::Vec4));
196                     }
197 
198                     // padding
199                     dat->counts = { currCamera.environmentCount, 0U, 0U, 0U };
200                     dat->pad0 = { 0U, 0U, 0U, 0U };
201                     dat->matPad0 = ZERO_MATRIX_4X4;
202                     dat->matPad1 = ZERO_MATRIX_4X4;
203                 }
204 
205                 gpuResMgr.UnmapBuffer(resHandle_.GetHandle());
206             }
207         }
208     }
209 
210     jitterIndex_ = (jitterIndex_ + 1) % HALTON_SAMPLE_COUNT;
211 }
212 
GetProjectionMatrix(const RenderCamera & camera,const bool prevFrame) const213 RenderNodeDefaultCameras::JitterProjection RenderNodeDefaultCameras::GetProjectionMatrix(
214     const RenderCamera& camera, const bool prevFrame) const
215 {
216     JitterProjection jp;
217     jp.baseProj = prevFrame ? camera.matrices.projPrevFrame : camera.matrices.proj;
218     jp.proj = jp.baseProj;
219     if (camera.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_JITTER_BIT) {
220         // NOTE: currently calculates the same jitter for both frames to get zero velocity
221         const uint32_t jitterIndex = jitterIndex_;
222         const Math::Vec2 renderRes = Math::Vec2(static_cast<float>(Math::max(1u, camera.renderResolution.x)),
223             static_cast<float>(Math::max(1u, camera.renderResolution.y)));
224         const Math::Vec2 haltonOffset = GetHaltonOffset(jitterIndex);
225         const Math::Vec2 haltonOffsetRes =
226             Math::Vec2((haltonOffset.x * 2.0f - 1.0f) / renderRes.x, (haltonOffset.y * 2.0f - 1.0f) / renderRes.y);
227 
228         jp.jitter = Math::Vec4(haltonOffset.x, haltonOffset.y, haltonOffsetRes.x, haltonOffsetRes.y);
229         jp.proj[2U][0U] += haltonOffsetRes.x;
230         jp.proj[2U][1U] += haltonOffsetRes.y;
231     }
232     return jp;
233 }
234 
GetShadowBiasMatrix(const IRenderDataStoreDefaultLight * dataStore,const RenderCamera & camera) const235 BASE_NS::Math::Mat4X4 RenderNodeDefaultCameras::GetShadowBiasMatrix(
236     const IRenderDataStoreDefaultLight* dataStore, const RenderCamera& camera) const
237 {
238     if (dataStore) {
239         const auto lightCounts = dataStore->GetLightCounts();
240         const uint32_t shadowCount = lightCounts.shadowCount;
241         const auto lights = dataStore->GetLights();
242         for (const auto& lightRef : lights) {
243             if (lightRef.id == camera.shadowId) {
244                 return GetShadowBias(lightRef.shadowIndex, shadowCount);
245             }
246         }
247     }
248     return SHADOW_BIAS_MATRIX;
249 }
250 
251 // for plugin / factory interface
Create()252 RENDER_NS::IRenderNode* RenderNodeDefaultCameras::Create()
253 {
254     return new RenderNodeDefaultCameras();
255 }
256 
Destroy(IRenderNode * instance)257 void RenderNodeDefaultCameras::Destroy(IRenderNode* instance)
258 {
259     delete static_cast<RenderNodeDefaultCameras*>(instance);
260 }
261 CORE3D_END_NAMESPACE()
262