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