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_material_objects.h"
17
18 #include <3d/render/default_material_constants.h>
19 #include <3d/render/intf_render_data_store_default_material.h>
20 #include <base/containers/allocator.h>
21 #include <base/containers/type_traits.h>
22 #include <base/math/matrix.h>
23 #include <base/math/vector.h>
24 #include <core/log.h>
25 #include <core/namespace.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/device/pipeline_layout_desc.h>
30 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
31 #include <render/nodecontext/intf_render_command_list.h>
32 #include <render/nodecontext/intf_render_node_context_manager.h>
33 #include <render/resource_handle.h>
34
35 namespace {
36 #include <3d/shaders/common/3d_dm_structures_common.h>
37 } // namespace
38
39 CORE3D_BEGIN_NAMESPACE()
40 using namespace BASE_NS;
41 using namespace RENDER_NS;
42
43 namespace {
44 constexpr uint32_t UBO_BIND_OFFSET_ALIGNMENT { PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE };
45 constexpr uint32_t MIN_UBO_OBJECT_COUNT { CORE_UNIFORM_BUFFER_MAX_BIND_SIZE / UBO_BIND_OFFSET_ALIGNMENT };
46 constexpr uint32_t MIN_MATERIAL_DESC_SET_COUNT { 64U };
47
48 constexpr GpuBufferDesc UBO_DESC { CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
49 (CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT),
50 CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER, 0U };
51
Align(size_t value,size_t align)52 constexpr size_t Align(size_t value, size_t align)
53 {
54 if (value == 0) {
55 return 0;
56 }
57 return ((value + align) / align) * align;
58 }
59
GetDefaultMaterialGpuResources(const IRenderNodeGpuResourceManager & gpuResourceMgr,RenderNodeDefaultMaterialObjects::MaterialHandleStruct & defaultMat)60 void GetDefaultMaterialGpuResources(const IRenderNodeGpuResourceManager& gpuResourceMgr,
61 RenderNodeDefaultMaterialObjects::MaterialHandleStruct& defaultMat)
62 {
63 defaultMat.resources[MaterialComponent::TextureIndex::BASE_COLOR].handle =
64 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_BASE_COLOR);
65 defaultMat.resources[MaterialComponent::TextureIndex::NORMAL].handle =
66 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_NORMAL);
67 defaultMat.resources[MaterialComponent::TextureIndex::MATERIAL].handle =
68 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_MATERIAL);
69 defaultMat.resources[MaterialComponent::TextureIndex::EMISSIVE].handle =
70 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_EMISSIVE);
71 defaultMat.resources[MaterialComponent::TextureIndex::AO].handle =
72 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_AO);
73
74 defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT].handle =
75 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT);
76 defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT_ROUGHNESS].handle =
77 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT_ROUGHNESS);
78 defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT_NORMAL].handle =
79 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT_NORMAL);
80
81 defaultMat.resources[MaterialComponent::TextureIndex::SHEEN].handle =
82 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_SHEEN);
83
84 defaultMat.resources[MaterialComponent::TextureIndex::TRANSMISSION].handle =
85 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_TRANSMISSION);
86
87 defaultMat.resources[MaterialComponent::TextureIndex::SPECULAR].handle =
88 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_SPECULAR);
89
90 const RenderHandle samplerHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_REPEAT");
91 for (uint32_t idx = 0; idx < countof(defaultMat.resources); ++idx) {
92 defaultMat.resources[idx].samplerHandle = samplerHandle;
93 }
94 }
95
96 // returns if there were changes and needs a descriptor set update
UpdateCurrentMaterialHandles(IRenderNodeGpuResourceManager & gpuResourceMgr,const bool forceUpdate,const RenderNodeDefaultMaterialObjects::MaterialHandleStruct & defaultMat,const RenderDataDefaultMaterial::MaterialHandles & matHandles,RenderNodeDefaultMaterialObjects::MaterialHandleStruct & storedMaterialHandles)97 bool UpdateCurrentMaterialHandles(IRenderNodeGpuResourceManager& gpuResourceMgr, const bool forceUpdate,
98 const RenderNodeDefaultMaterialObjects::MaterialHandleStruct& defaultMat,
99 const RenderDataDefaultMaterial::MaterialHandles& matHandles,
100 RenderNodeDefaultMaterialObjects::MaterialHandleStruct& storedMaterialHandles)
101 {
102 RenderNodeDefaultMaterialObjects::MaterialHandleStruct currMaterialHandles;
103 bool hasChanges = false;
104 for (uint32_t idx = 0; idx < countof(matHandles.images); ++idx) {
105 const auto& defaultRes = defaultMat.resources[idx];
106 const auto& srcImage = matHandles.images[idx];
107 const auto& srcSampler = matHandles.samplers[idx];
108 auto& dst = currMaterialHandles.resources[idx];
109
110 // fetch updated with generation counter raw handles
111 if (RenderHandleUtil::IsValid(srcImage)) {
112 dst.handle = gpuResourceMgr.GetRawHandle(srcImage);
113 } else {
114 dst.handle = defaultRes.handle;
115 }
116 if (RenderHandleUtil::IsValid(srcSampler)) {
117 dst.samplerHandle = gpuResourceMgr.GetRawHandle(srcSampler);
118 } else {
119 dst.samplerHandle = defaultRes.samplerHandle;
120 }
121
122 // check if there are changes
123 auto& stored = storedMaterialHandles.resources[idx];
124 if ((stored.handle != dst.handle) || (stored.samplerHandle != dst.samplerHandle) ||
125 (dst.handle.id & RenderHandleUtil::RENDER_HANDLE_NEEDS_UPDATE_MASK)) {
126 hasChanges = true;
127 stored.handle = dst.handle;
128 stored.samplerHandle = dst.samplerHandle;
129 }
130 }
131 return hasChanges;
132 }
133 } // namespace
134
InitNode(IRenderNodeContextManager & renderNodeContextMgr)135 void RenderNodeDefaultMaterialObjects::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
136 {
137 renderNodeContextMgr_ = &renderNodeContextMgr;
138 globalDescs_ = {};
139
140 const auto& renderNodeGraphData = renderNodeContextMgr_->GetRenderNodeGraphData();
141 stores_ = RenderNodeSceneUtil::GetSceneRenderDataStores(
142 renderNodeContextMgr, renderNodeGraphData.renderNodeGraphDataStoreName);
143
144 const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
145 const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
146 const RenderHandle defaultPlHandle =
147 shaderMgr.GetPipelineLayoutHandle(DefaultMaterialShaderConstants::PIPELINE_LAYOUT_FORWARD);
148 defaultMaterialPipelineLayout_ = shaderMgr.GetPipelineLayout(defaultPlHandle);
149 GetDefaultMaterialGpuResources(gpuResourceMgr, defaultMaterialStruct_);
150
151 ProcessBuffers({ 1u, 1u, 1u, 1u });
152 }
153
PreExecuteFrame()154 void RenderNodeDefaultMaterialObjects::PreExecuteFrame()
155 {
156 // re-create needed gpu resources
157 const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
158 const IRenderDataStoreDefaultMaterial* dataStoreMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(
159 renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameMaterial));
160 // we need to have all buffers created (reason to have at least 1u)
161 if (dataStoreMaterial) {
162 const auto dsOc = dataStoreMaterial->GetObjectCounts();
163 const ObjectCounts oc {
164 Math::max(dsOc.meshCount, 1u),
165 Math::max(dsOc.submeshCount, 1u),
166 Math::max(dsOc.skinCount, 1u),
167 Math::max(dsOc.materialCount, 1u),
168 Math::max(dsOc.uniqueMaterialCount, 1u),
169 };
170 ProcessBuffers(oc);
171 } else {
172 ProcessBuffers({ 1u, 1u, 1u, 1u, 1u });
173 }
174 }
175
ExecuteFrame(IRenderCommandList & cmdList)176 void RenderNodeDefaultMaterialObjects::ExecuteFrame(IRenderCommandList& cmdList)
177 {
178 const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
179 const auto* dataStoreMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(
180 renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameMaterial));
181
182 if (dataStoreMaterial) {
183 UpdateBuffers(*dataStoreMaterial);
184 UpdateDescriptorSets(cmdList, *dataStoreMaterial);
185 } else {
186 CORE_LOG_E("invalid render data store in RenderNodeDefaultMaterialObjects");
187 }
188 }
189
UpdateBuffers(const IRenderDataStoreDefaultMaterial & dataStoreMaterial)190 void RenderNodeDefaultMaterialObjects::UpdateBuffers(const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
191 {
192 UpdateMeshBuffer(dataStoreMaterial);
193 UpdateSkinBuffer(dataStoreMaterial);
194 UpdateMaterialBuffers(dataStoreMaterial);
195 }
196
UpdateMeshBuffer(const IRenderDataStoreDefaultMaterial & dataStoreMaterial)197 void RenderNodeDefaultMaterialObjects::UpdateMeshBuffer(const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
198 {
199 IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
200 // mesh data is copied to single buffer with UBO_BIND_OFFSET_ALIGNMENT alignments
201 if (auto meshDataPtr = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.mesh.GetHandle())); meshDataPtr) {
202 constexpr uint32_t meshByteSize = sizeof(DefaultMaterialSingleMeshStruct);
203 CORE_STATIC_ASSERT(meshByteSize >= UBO_BIND_OFFSET_ALIGNMENT);
204 CORE_STATIC_ASSERT(sizeof(RenderMeshData) == sizeof(DefaultMaterialSingleMeshStruct));
205 const auto* meshDataPtrEnd = meshDataPtr + meshByteSize * objectCounts_.maxMeshCount;
206 if (const auto meshData = dataStoreMaterial.GetMeshData(); !meshData.empty()) {
207 // clone all at once, they are in order
208 const size_t cloneByteSize = meshData.size_bytes();
209 if (!CloneData(meshDataPtr, size_t(meshDataPtrEnd - meshDataPtr), meshData.data(), cloneByteSize)) {
210 CORE_LOG_I("meshData ubo copying failed");
211 }
212 }
213
214 gpuResourceMgr.UnmapBuffer(ubos_.mesh.GetHandle());
215 }
216 }
217
UpdateSkinBuffer(const IRenderDataStoreDefaultMaterial & dataStoreMaterial)218 void RenderNodeDefaultMaterialObjects::UpdateSkinBuffer(const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
219 {
220 IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
221 // skindata is copied to a single buffer with sizeof(DefaultMaterialSkinStruct) offset
222 // skin offset for submesh is calculated submesh.skinIndex * sizeof(DefaultMaterialSkinStruct)
223 // NOTE: the size could be optimized, but render data store should calculate correct size with alignment
224 if (auto skinData = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.submeshSkin.GetHandle())); skinData) {
225 CORE_STATIC_ASSERT(
226 RenderDataDefaultMaterial::MAX_SKIN_MATRIX_COUNT * 2u == CORE_DEFAULT_MATERIAL_MAX_JOINT_COUNT);
227 const auto* skinDataEnd = skinData + sizeof(DefaultMaterialSkinStruct) * objectCounts_.maxSkinCount;
228 const auto meshJointMatrices = dataStoreMaterial.GetMeshJointMatrices();
229 for (const auto& jointRef : meshJointMatrices) {
230 // we copy first current frame matrices, then previous frame
231 const size_t copyCount = static_cast<size_t>(jointRef.count / 2u);
232 const size_t copySize = copyCount * sizeof(Math::Mat4X4);
233 const size_t ptrOffset = CORE_DEFAULT_MATERIAL_PREV_JOINT_OFFSET * sizeof(Math::Mat4X4);
234 if (!CloneData(skinData, size_t(skinDataEnd - skinData), jointRef.data, copySize)) {
235 CORE_LOG_I("skinData ubo copying failed");
236 }
237 if (!CloneData(skinData + ptrOffset, size_t(skinDataEnd - (skinData + ptrOffset)),
238 jointRef.data + copyCount, copySize)) {
239 CORE_LOG_I("skinData ubo copying failed");
240 }
241 skinData = skinData + sizeof(DefaultMaterialSkinStruct);
242 }
243
244 gpuResourceMgr.UnmapBuffer(ubos_.submeshSkin.GetHandle());
245 }
246 }
247
UpdateMaterialBuffers(const IRenderDataStoreDefaultMaterial & dataStoreMaterial)248 void RenderNodeDefaultMaterialObjects::UpdateMaterialBuffers(const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
249 {
250 IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
251 // material data is copied to single buffer with UBO_BIND_OFFSET_ALIGNMENT alignment
252 auto matFactorData = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.mat.GetHandle()));
253 auto matTransformData = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.matTransform.GetHandle()));
254 auto userMaterialData = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.userMat.GetHandle()));
255 if (!matFactorData || !matTransformData || !userMaterialData) {
256 return;
257 }
258 const auto* matFactorDataEnd = matFactorData + UBO_BIND_OFFSET_ALIGNMENT * objectCounts_.maxMaterialCount;
259 const auto* matTransformDataEnd = matTransformData + UBO_BIND_OFFSET_ALIGNMENT * objectCounts_.maxMaterialCount;
260 const auto* userMaterialDataEnd = userMaterialData + UBO_BIND_OFFSET_ALIGNMENT * objectCounts_.maxMaterialCount;
261 const auto materialUniforms = dataStoreMaterial.GetMaterialUniforms();
262 const auto materialFrameIndices = dataStoreMaterial.GetMaterialFrameIndices();
263 for (uint32_t matOff = 0; matOff < materialFrameIndices.size(); ++matOff) {
264 const uint32_t matIdx = materialFrameIndices[matOff];
265 if (matIdx >= materialUniforms.size()) {
266 continue;
267 }
268
269 const RenderDataDefaultMaterial::AllMaterialUniforms& uniforms = materialUniforms[matIdx];
270 if (!CloneData(matFactorData, size_t(matFactorDataEnd - matFactorData), &uniforms.factors,
271 sizeof(RenderDataDefaultMaterial::MaterialUniforms))) {
272 CORE_LOG_I("materialFactorData ubo copying failed");
273 }
274 if (!CloneData(matTransformData, size_t(matTransformDataEnd - matTransformData), &uniforms.transforms,
275 sizeof(RenderDataDefaultMaterial::MaterialPackedUniforms))) {
276 CORE_LOG_I("materialTransformData ubo copying failed");
277 }
278 const auto materialCustomProperties = dataStoreMaterial.GetMaterialCustomPropertyData(matIdx);
279 if (!materialCustomProperties.empty()) {
280 CORE_ASSERT(materialCustomProperties.size_bytes() <= UBO_BIND_OFFSET_ALIGNMENT);
281 if (!CloneData(userMaterialData, size_t(userMaterialDataEnd - userMaterialData),
282 materialCustomProperties.data(), materialCustomProperties.size_bytes())) {
283 CORE_LOG_I("userMaterialData ubo copying failed");
284 }
285 }
286 matFactorData = matFactorData + UBO_BIND_OFFSET_ALIGNMENT;
287 matTransformData = matTransformData + UBO_BIND_OFFSET_ALIGNMENT;
288 userMaterialData = userMaterialData + UBO_BIND_OFFSET_ALIGNMENT;
289 }
290
291 gpuResourceMgr.UnmapBuffer(ubos_.mat.GetHandle());
292 gpuResourceMgr.UnmapBuffer(ubos_.matTransform.GetHandle());
293 gpuResourceMgr.UnmapBuffer(ubos_.userMat.GetHandle());
294 }
295
UpdateDescriptorSets(IRenderCommandList & cmdList,const IRenderDataStoreDefaultMaterial & dataStoreMaterial)296 void RenderNodeDefaultMaterialObjects::UpdateDescriptorSets(
297 IRenderCommandList& cmdList, const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
298 {
299 // loop through all materials at the moment
300 {
301 const auto& materialHandles = dataStoreMaterial.GetMaterialHandles();
302 CORE_ASSERT(materialHandles.size() <= globalDescs_.descriptorSets.size());
303 CORE_ASSERT(globalDescs_.descriptorSets.size() == globalDescs_.materials.size());
304 IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
305 for (size_t idx = 0; idx < materialHandles.size(); ++idx) {
306 auto* binder = globalDescs_.descriptorSets[idx].get();
307 if (binder && (idx < materialHandles.size())) {
308 const auto& matHandles = materialHandles[idx];
309 MaterialHandleStruct& storedMatHandles = globalDescs_.materials[idx];
310 const bool updateDescSet = UpdateCurrentMaterialHandles(
311 gpuResourceMgr, globalDescs_.forceUpdate, defaultMaterialStruct_, matHandles, storedMatHandles);
312 if (globalDescs_.forceUpdate || updateDescSet) {
313 uint32_t bindingIdx = 0u;
314 // base color is bound separately to support automatic hwbuffer/OES shader modification
315 binder->BindImage(
316 bindingIdx++, storedMatHandles.resources[MaterialComponent::TextureIndex::BASE_COLOR]);
317
318 CORE_STATIC_ASSERT(MaterialComponent::TextureIndex::BASE_COLOR == 0);
319 // skip baseColor as it's bound already
320 constexpr size_t theCount = RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT - 1;
321 binder->BindImages(bindingIdx++, array_view(storedMatHandles.resources + 1, theCount));
322
323 cmdList.UpdateDescriptorSet(
324 binder->GetDescriptorSetHandle(), binder->GetDescriptorSetLayoutBindingResources());
325 }
326 }
327 }
328 globalDescs_.forceUpdate = false;
329 }
330 if (auto* binder = globalDescs_.dmSet1Binder.get(); binder) {
331 // NOTE: should be PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE or current size
332 constexpr uint32_t skinSize = sizeof(DefaultMaterialSkinStruct);
333 uint32_t bindingIdx = 0u;
334 binder->BindBuffer(bindingIdx++, ubos_.mesh.GetHandle(), 0U, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
335 binder->BindBuffer(bindingIdx++, ubos_.submeshSkin.GetHandle(), 0U, skinSize);
336 binder->BindBuffer(bindingIdx++, ubos_.mat.GetHandle(), 0U, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
337 binder->BindBuffer(
338 bindingIdx++, ubos_.matTransform.GetHandle(), 0U, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
339 binder->BindBuffer(
340 bindingIdx++, ubos_.userMat.GetHandle(), 0U, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
341 cmdList.UpdateDescriptorSet(binder->GetDescriptorSetHandle(), binder->GetDescriptorSetLayoutBindingResources());
342 }
343 // update only once
344 if (!globalDescs_.dmSet2Ready) {
345 if (auto* binder = globalDescs_.dmSet2Binder.get(); binder) {
346 uint32_t bindingIdx = 0u;
347 // base color is bound separately to support automatic hwbuffer/OES shader modification
348 binder->BindImage(
349 bindingIdx++, defaultMaterialStruct_.resources[MaterialComponent::TextureIndex::BASE_COLOR]);
350
351 CORE_STATIC_ASSERT(MaterialComponent::TextureIndex::BASE_COLOR == 0);
352 // skip baseColor as it's bound already
353 constexpr size_t theCount = RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT - 1;
354 binder->BindImages(bindingIdx++, array_view(defaultMaterialStruct_.resources + 1, theCount));
355
356 cmdList.UpdateDescriptorSet(
357 binder->GetDescriptorSetHandle(), binder->GetDescriptorSetLayoutBindingResources());
358 globalDescs_.dmSet2Ready = true;
359 }
360 }
361 }
362
ProcessBuffers(const ObjectCounts & objectCounts)363 void RenderNodeDefaultMaterialObjects::ProcessBuffers(const ObjectCounts& objectCounts)
364 {
365 auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
366 constexpr uint32_t overEstimate { 16u };
367 constexpr uint32_t baseStructSize = CORE_UNIFORM_BUFFER_MAX_BIND_SIZE;
368 constexpr uint32_t singleComponentStructSize = UBO_BIND_OFFSET_ALIGNMENT;
369 const string_view us = stores_.dataStoreNameScene;
370 GpuBufferDesc bDesc = UBO_DESC;
371 // instancing utilization for mesh and materials
372 if (objectCounts_.maxMeshCount < objectCounts.maxMeshCount) {
373 // mesh matrix uses max ubo bind size to utilize gpu instancing
374 CORE_STATIC_ASSERT(sizeof(DefaultMaterialMeshStruct) <= PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
375 objectCounts_.maxMeshCount =
376 objectCounts.maxMeshCount + (objectCounts.maxMeshCount / overEstimate) + MIN_UBO_OBJECT_COUNT;
377
378 const uint32_t byteSize =
379 static_cast<uint32_t>(Align(objectCounts_.maxMeshCount * singleComponentStructSize, baseStructSize));
380 objectCounts_.maxMeshCount = (byteSize / singleComponentStructSize) - MIN_UBO_OBJECT_COUNT;
381 CORE_ASSERT((int32_t(byteSize / singleComponentStructSize) - int32_t(MIN_UBO_OBJECT_COUNT)) > 0);
382
383 bDesc.byteSize = byteSize;
384 ubos_.mesh = gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::MESH_DATA_BUFFER_NAME, bDesc);
385 }
386 if (objectCounts_.maxSkinCount < objectCounts.maxSkinCount) {
387 objectCounts_.maxSkinCount = objectCounts.maxSkinCount + (objectCounts.maxSkinCount / overEstimate);
388
389 bDesc.byteSize = static_cast<uint32_t>(sizeof(DefaultMaterialSkinStruct)) * objectCounts_.maxSkinCount;
390 ubos_.submeshSkin = gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::SKIN_DATA_BUFFER_NAME, bDesc);
391 }
392 if (objectCounts_.maxMaterialCount < objectCounts.maxMaterialCount) {
393 CORE_STATIC_ASSERT(sizeof(RenderDataDefaultMaterial::MaterialUniforms) <= UBO_BIND_OFFSET_ALIGNMENT);
394 objectCounts_.maxMaterialCount =
395 objectCounts.maxMaterialCount + (objectCounts.maxMaterialCount / overEstimate) + MIN_UBO_OBJECT_COUNT;
396
397 const uint32_t byteSize =
398 static_cast<uint32_t>(Align(objectCounts_.maxMaterialCount * singleComponentStructSize, baseStructSize));
399 objectCounts_.maxMaterialCount = (byteSize / singleComponentStructSize) - MIN_UBO_OBJECT_COUNT;
400 CORE_ASSERT((int32_t(byteSize / singleComponentStructSize) - int32_t(MIN_UBO_OBJECT_COUNT)) > 0);
401
402 bDesc.byteSize = byteSize;
403 ubos_.mat = gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::MATERIAL_DATA_BUFFER_NAME, bDesc);
404 ubos_.matTransform =
405 gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::MATERIAL_TRANSFORM_DATA_BUFFER_NAME, bDesc);
406 ubos_.userMat =
407 gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::MATERIAL_USER_DATA_BUFFER_NAME, bDesc);
408 }
409 if (objectCounts_.maxUniqueMaterialCount < objectCounts.maxUniqueMaterialCount) {
410 CORE_STATIC_ASSERT(sizeof(RenderDataDefaultMaterial::MaterialUniforms) <= UBO_BIND_OFFSET_ALIGNMENT);
411 objectCounts_.maxUniqueMaterialCount = objectCounts.maxUniqueMaterialCount +
412 (objectCounts.maxUniqueMaterialCount / overEstimate) +
413 MIN_MATERIAL_DESC_SET_COUNT;
414 objectCounts_.maxUniqueMaterialCount =
415 static_cast<uint32_t>(Align(objectCounts_.maxUniqueMaterialCount, MIN_MATERIAL_DESC_SET_COUNT));
416 // global descriptor sets
417 INodeContextDescriptorSetManager& dsMgr = renderNodeContextMgr_->GetDescriptorSetManager();
418 constexpr uint32_t set = 2U;
419 globalDescs_.handles.clear();
420 globalDescs_.descriptorSets.clear();
421 globalDescs_.forceUpdate = true;
422 const auto& bindings = defaultMaterialPipelineLayout_.descriptorSetLayouts[set].bindings;
423 globalDescs_.handles = dsMgr.CreateGlobalDescriptorSets(
424 us + DefaultMaterialMaterialConstants::MATERIAL_RESOURCES_GLOBAL_DESCRIPTOR_SET_NAME, bindings,
425 objectCounts_.maxUniqueMaterialCount);
426 globalDescs_.descriptorSets.resize(globalDescs_.handles.size());
427 globalDescs_.materials.resize(globalDescs_.handles.size());
428 for (size_t idx = 0; idx < globalDescs_.handles.size(); ++idx) {
429 globalDescs_.descriptorSets[idx] =
430 dsMgr.CreateDescriptorSetBinder(globalDescs_.handles[idx].GetHandle(), bindings);
431 }
432 }
433 ProcessGlobalBinders();
434 }
435
ProcessGlobalBinders()436 void RenderNodeDefaultMaterialObjects::ProcessGlobalBinders()
437 {
438 if (!globalDescs_.dmSet1Binder) {
439 const string_view us = stores_.dataStoreNameScene;
440 INodeContextDescriptorSetManager& dsMgr = renderNodeContextMgr_->GetDescriptorSetManager();
441 globalDescs_.dmSet1 = {};
442 globalDescs_.dmSet1Binder = {};
443 constexpr uint32_t set = 1U;
444 const auto& bindings = defaultMaterialPipelineLayout_.descriptorSetLayouts[set].bindings;
445 globalDescs_.dmSet1 = dsMgr.CreateGlobalDescriptorSet(
446 us + DefaultMaterialMaterialConstants::MATERIAL_SET1_GLOBAL_DESCRIPTOR_SET_NAME, bindings);
447 globalDescs_.dmSet1Binder = dsMgr.CreateDescriptorSetBinder(globalDescs_.dmSet1.GetHandle(), bindings);
448 }
449 if (!globalDescs_.dmSet2Binder) {
450 const string_view us = stores_.dataStoreNameScene;
451 INodeContextDescriptorSetManager& dsMgr = renderNodeContextMgr_->GetDescriptorSetManager();
452 globalDescs_.dmSet2 = {};
453 globalDescs_.dmSet2Binder = {};
454 constexpr uint32_t set = 2U;
455 const auto& bindings = defaultMaterialPipelineLayout_.descriptorSetLayouts[set].bindings;
456 globalDescs_.dmSet2 = dsMgr.CreateGlobalDescriptorSet(
457 us + DefaultMaterialMaterialConstants::MATERIAL_DEFAULT_RESOURCE_GLOBAL_DESCRIPTOR_SET_NAME, bindings);
458 globalDescs_.dmSet2Binder = dsMgr.CreateDescriptorSetBinder(globalDescs_.dmSet2.GetHandle(), bindings);
459 }
460 }
461
462 // for plugin / factory interface
Create()463 RENDER_NS::IRenderNode* RenderNodeDefaultMaterialObjects::Create()
464 {
465 return new RenderNodeDefaultMaterialObjects();
466 }
467
Destroy(IRenderNode * instance)468 void RenderNodeDefaultMaterialObjects::Destroy(IRenderNode* instance)
469 {
470 delete static_cast<RenderNodeDefaultMaterialObjects*>(instance);
471 }
472 CORE3D_END_NAMESPACE()
473