• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/implementation_uids.h>
19 #include <3d/intf_graphics_context.h>
20 #include <3d/render/default_material_constants.h>
21 #include <3d/render/intf_render_data_store_default_material.h>
22 #include <base/containers/allocator.h>
23 #include <base/containers/type_traits.h>
24 #include <base/math/matrix.h>
25 #include <base/math/vector.h>
26 #include <core/log.h>
27 #include <core/namespace.h>
28 #include <core/plugin/intf_class_register.h>
29 #include <render/datastore/intf_render_data_store.h>
30 #include <render/datastore/intf_render_data_store_manager.h>
31 #include <render/device/intf_gpu_resource_manager.h>
32 #include <render/device/pipeline_layout_desc.h>
33 #include <render/intf_render_context.h>
34 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
35 #include <render/nodecontext/intf_render_command_list.h>
36 #include <render/nodecontext/intf_render_node_context_manager.h>
37 #include <render/resource_handle.h>
38 
39 #include "render/datastore/render_data_store_default_material.h"
40 
41 namespace {
42 #include <3d/shaders/common/3d_dm_structures_common.h>
43 } // namespace
44 
45 CORE3D_BEGIN_NAMESPACE()
46 using namespace BASE_NS;
47 using namespace RENDER_NS;
48 
49 namespace {
50 constexpr bool ENABLE_RT { true };
51 
52 constexpr uint32_t UBO_BIND_OFFSET_ALIGNMENT { PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE };
53 constexpr uint32_t MIN_UBO_OBJECT_COUNT { CORE_UNIFORM_BUFFER_MAX_BIND_SIZE / UBO_BIND_OFFSET_ALIGNMENT };
54 constexpr uint32_t MIN_MATERIAL_DESC_SET_COUNT { 64U };
55 
56 constexpr GpuBufferDesc UBO_DESC { CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
57     (CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT),
58     CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER, 0U };
59 
Align(size_t value,size_t align)60 constexpr size_t Align(size_t value, size_t align)
61 {
62     if (value == 0) {
63         return 0;
64     }
65     return ((value + align) / align) * align;
66 }
67 
GetDefaultMaterialGpuResources(const IRenderNodeGpuResourceManager & gpuResourceMgr,RenderNodeDefaultMaterialObjects::MaterialHandleStruct & defaultMat)68 void GetDefaultMaterialGpuResources(const IRenderNodeGpuResourceManager& gpuResourceMgr,
69     RenderNodeDefaultMaterialObjects::MaterialHandleStruct& defaultMat)
70 {
71     defaultMat.resources[MaterialComponent::TextureIndex::BASE_COLOR].handle =
72         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_BASE_COLOR);
73     defaultMat.resources[MaterialComponent::TextureIndex::NORMAL].handle =
74         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_NORMAL);
75     defaultMat.resources[MaterialComponent::TextureIndex::MATERIAL].handle =
76         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_MATERIAL);
77     defaultMat.resources[MaterialComponent::TextureIndex::EMISSIVE].handle =
78         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_EMISSIVE);
79     defaultMat.resources[MaterialComponent::TextureIndex::AO].handle =
80         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_AO);
81 
82     defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT].handle =
83         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT);
84     defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT_ROUGHNESS].handle =
85         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT_ROUGHNESS);
86     defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT_NORMAL].handle =
87         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT_NORMAL);
88 
89     defaultMat.resources[MaterialComponent::TextureIndex::SHEEN].handle =
90         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_SHEEN);
91 
92     defaultMat.resources[MaterialComponent::TextureIndex::TRANSMISSION].handle =
93         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_TRANSMISSION);
94 
95     defaultMat.resources[MaterialComponent::TextureIndex::SPECULAR].handle =
96         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_SPECULAR);
97 
98     const RenderHandle samplerHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_REPEAT");
99     for (uint32_t idx = 0; idx < countof(defaultMat.resources); ++idx) {
100         defaultMat.resources[idx].samplerHandle = samplerHandle;
101     }
102 }
103 
104 // 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)105 bool UpdateCurrentMaterialHandles(IRenderNodeGpuResourceManager& gpuResourceMgr, const bool forceUpdate,
106     const RenderNodeDefaultMaterialObjects::MaterialHandleStruct& defaultMat,
107     const RenderDataDefaultMaterial::MaterialHandles& matHandles,
108     RenderNodeDefaultMaterialObjects::MaterialHandleStruct& storedMaterialHandles)
109 {
110     RenderNodeDefaultMaterialObjects::MaterialHandleStruct currMaterialHandles;
111     bool hasChanges = false;
112     for (uint32_t idx = 0; idx < countof(matHandles.images); ++idx) {
113         const auto& defaultRes = defaultMat.resources[idx];
114         const auto& srcImage = matHandles.images[idx];
115         const auto& srcSampler = matHandles.samplers[idx];
116         auto& dst = currMaterialHandles.resources[idx];
117 
118         // fetch updated with generation counter raw handles
119         if (RenderHandleUtil::IsValid(srcImage)) {
120             dst.handle = gpuResourceMgr.GetRawHandle(srcImage);
121         } else {
122             dst.handle = defaultRes.handle;
123         }
124         if (RenderHandleUtil::IsValid(srcSampler)) {
125             dst.samplerHandle = gpuResourceMgr.GetRawHandle(srcSampler);
126         } else {
127             dst.samplerHandle = defaultRes.samplerHandle;
128         }
129 
130         // check if there are changes
131         auto& stored = storedMaterialHandles.resources[idx];
132         if ((stored.handle != dst.handle) || (stored.samplerHandle != dst.samplerHandle) ||
133             (dst.handle.id & RenderHandleUtil::RENDER_HANDLE_NEEDS_UPDATE_MASK)) {
134             hasChanges = true;
135             stored.handle = dst.handle;
136             stored.samplerHandle = dst.samplerHandle;
137         }
138     }
139     return hasChanges;
140 }
141 } // namespace
142 
InitNode(IRenderNodeContextManager & renderNodeContextMgr)143 void RenderNodeDefaultMaterialObjects::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
144 {
145     renderNodeContextMgr_ = &renderNodeContextMgr;
146 
147     // get flags for rt
148     if constexpr (ENABLE_RT) {
149         rtEnabled_ = false;
150         IRenderContext &renderContext = renderNodeContextMgr_->GetRenderContext();
151         CORE_NS::IClassRegister *cr = renderContext.GetInterface<CORE_NS::IClassRegister>();
152         if (cr != nullptr) {
153             IGraphicsContext *graphicsContext = CORE_NS::GetInstance<IGraphicsContext>(*cr, UID_GRAPHICS_CONTEXT);
154             if (graphicsContext) {
155                 const IGraphicsContext::CreateInfo ci = graphicsContext->GetCreateInfo();
156                 if (ci.createFlags & IGraphicsContext::CreateInfo::ENABLE_ACCELERATION_STRUCTURES_BIT) {
157                     rtEnabled_ = true;
158                 }
159             }
160         } else {
161             CORE_LOG_E("get null ClassRegister");
162         }
163     }
164 
165     globalDescs_ = {};
166 
167     const auto& renderNodeGraphData = renderNodeContextMgr_->GetRenderNodeGraphData();
168     stores_ = RenderNodeSceneUtil::GetSceneRenderDataStores(
169         renderNodeContextMgr, renderNodeGraphData.renderNodeGraphDataStoreName);
170 
171     const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
172     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
173     const IShaderManager::RenderSlotData shaderRsd = shaderMgr.GetRenderSlotData(
174         shaderMgr.GetRenderSlotId(DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE));
175 #if (CORE3D_VALIDATION_ENABLED == 1)
176     if (!shaderRsd.pipelineLayout) {
177         CORE_LOG_W("CORE3D_VALIDATION: Missing default material pipeline layout");
178     }
179 #endif
180     defaultMaterialPipelineLayout_ = shaderMgr.GetPipelineLayout(shaderRsd.pipelineLayout.GetHandle());
181     GetDefaultMaterialGpuResources(gpuResourceMgr, defaultMaterialStruct_);
182 
183     ProcessBuffers({ 1u, 1u, 1u, 1u, 1u });
184 }
185 
PreExecuteFrame()186 void RenderNodeDefaultMaterialObjects::PreExecuteFrame()
187 {
188     // NOTE: global binders and buffers needs to processed in PreExecuteFrame
189     // that other render nodes have access to those
190     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
191     // we need to have all buffers created (reason to have at least 1u)
192     if (const IRenderDataStoreDefaultMaterial* dataStoreMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(
193             renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameMaterial));
194         dataStoreMaterial) {
195         const auto dsOc = dataStoreMaterial->GetObjectCounts();
196         const ObjectCounts oc {
197             Math::max(dsOc.meshCount, 1u),
198             Math::max(dsOc.submeshCount, 1u),
199             Math::max(dsOc.skinCount, 1u),
200             Math::max(dsOc.materialCount, 1u),
201             Math::max(dsOc.uniqueMaterialCount, 1u),
202         };
203         ProcessBuffers(oc);
204     } else {
205         ProcessBuffers({ 1u, 1u, 1u, 1u, 1u });
206     }
207 }
208 
ExecuteFrame(IRenderCommandList & cmdList)209 void RenderNodeDefaultMaterialObjects::ExecuteFrame(IRenderCommandList& cmdList)
210 {
211     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
212     const auto* dataStoreMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(
213         renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameMaterial));
214 
215     if (dataStoreMaterial) {
216         UpdateMeshBuffer(*dataStoreMaterial);
217         UpdateSkinBuffer(*dataStoreMaterial);
218         UpdateMaterialBuffers(*dataStoreMaterial);
219         UpdateTlasBuffers(cmdList, *dataStoreMaterial);
220 
221         UpdateDescriptorSets(cmdList, *dataStoreMaterial);
222     } else {
223         CORE_LOG_E("invalid render data store in RenderNodeDefaultMaterialObjects");
224     }
225 }
226 
UpdateMeshBuffer(const IRenderDataStoreDefaultMaterial & dataStoreMaterial)227 void RenderNodeDefaultMaterialObjects::UpdateMeshBuffer(const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
228 {
229     IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
230     // mesh data is copied to single buffer with UBO_BIND_OFFSET_ALIGNMENT alignments
231     if (auto meshDataPtr = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.mesh.GetHandle())); meshDataPtr) {
232         constexpr uint32_t meshByteSize = sizeof(DefaultMaterialSingleMeshStruct);
233         CORE_STATIC_ASSERT(meshByteSize >= UBO_BIND_OFFSET_ALIGNMENT);
234         CORE_STATIC_ASSERT(sizeof(RenderMeshData) == sizeof(DefaultMaterialSingleMeshStruct));
235         const auto* meshDataPtrEnd = meshDataPtr + meshByteSize * objectCounts_.maxMeshCount;
236         if (const auto meshData = dataStoreMaterial.GetMeshData(); !meshData.empty()) {
237             // clone all at once, they are in order
238             const size_t cloneByteSize = meshData.size_bytes();
239             if (!CloneData(meshDataPtr, size_t(meshDataPtrEnd - meshDataPtr), meshData.data(), cloneByteSize)) {
240                 CORE_LOG_I("meshData ubo copying failed");
241             }
242         }
243 
244         gpuResourceMgr.UnmapBuffer(ubos_.mesh.GetHandle());
245     }
246 }
247 
UpdateSkinBuffer(const IRenderDataStoreDefaultMaterial & dataStoreMaterial)248 void RenderNodeDefaultMaterialObjects::UpdateSkinBuffer(const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
249 {
250     IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
251     // skindata is copied to a single buffer with sizeof(DefaultMaterialSkinStruct) offset
252     // skin offset for submesh is calculated submesh.skinIndex * sizeof(DefaultMaterialSkinStruct)
253     // NOTE: the size could be optimized, but render data store should calculate correct size with alignment
254     if (auto skinData = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.submeshSkin.GetHandle())); skinData) {
255         CORE_STATIC_ASSERT(
256             RenderDataDefaultMaterial::MAX_SKIN_MATRIX_COUNT * 2u == CORE_DEFAULT_MATERIAL_MAX_JOINT_COUNT);
257         const auto* skinDataEnd = skinData + sizeof(DefaultMaterialSkinStruct) * objectCounts_.maxSkinCount;
258         const auto meshJointMatrices = dataStoreMaterial.GetMeshJointMatrices();
259         for (const auto& jointRef : meshJointMatrices) {
260             // we copy first current frame matrices, then previous frame
261             const size_t copyCount = static_cast<size_t>(jointRef.count / 2u);
262             const size_t copySize = copyCount * sizeof(Math::Mat4X4);
263             const size_t ptrOffset = CORE_DEFAULT_MATERIAL_PREV_JOINT_OFFSET * sizeof(Math::Mat4X4);
264             if (!CloneData(skinData, size_t(skinDataEnd - skinData), jointRef.data, copySize)) {
265                 CORE_LOG_I("skinData ubo copying failed");
266             }
267             if (!CloneData(skinData + ptrOffset, size_t(skinDataEnd - (skinData + ptrOffset)),
268                     jointRef.data + copyCount, copySize)) {
269                 CORE_LOG_I("skinData ubo copying failed");
270             }
271             skinData = skinData + sizeof(DefaultMaterialSkinStruct);
272         }
273 
274         gpuResourceMgr.UnmapBuffer(ubos_.submeshSkin.GetHandle());
275     }
276 }
277 
UpdateMaterialBuffers(const IRenderDataStoreDefaultMaterial & dataStoreMaterial)278 void RenderNodeDefaultMaterialObjects::UpdateMaterialBuffers(const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
279 {
280     IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
281     // material data is copied to single buffer with UBO_BIND_OFFSET_ALIGNMENT alignment
282     auto matFactorData = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.mat.GetHandle()));
283     auto matTransformData = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.matTransform.GetHandle()));
284     auto userMaterialData = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.userMat.GetHandle()));
285     if (!matFactorData || !matTransformData || !userMaterialData) {
286         return;
287     }
288     const auto* matFactorDataEnd = matFactorData + UBO_BIND_OFFSET_ALIGNMENT * objectCounts_.maxMaterialCount;
289     const auto* matTransformDataEnd = matTransformData + UBO_BIND_OFFSET_ALIGNMENT * objectCounts_.maxMaterialCount;
290     const auto* userMaterialDataEnd = userMaterialData + UBO_BIND_OFFSET_ALIGNMENT * objectCounts_.maxMaterialCount;
291     const auto materialUniforms = dataStoreMaterial.GetMaterialUniforms();
292     const auto materialFrameIndices = dataStoreMaterial.GetMaterialFrameIndices();
293     for (uint32_t matOff = 0; matOff < materialFrameIndices.size(); ++matOff) {
294         const uint32_t matIdx = materialFrameIndices[matOff];
295         if (matIdx >= materialUniforms.size()) {
296             continue;
297         }
298 
299         const RenderDataDefaultMaterial::AllMaterialUniforms& uniforms = materialUniforms[matIdx];
300         if (!CloneData(matFactorData, size_t(matFactorDataEnd - matFactorData), &uniforms.factors,
301                 sizeof(RenderDataDefaultMaterial::MaterialUniforms))) {
302             CORE_LOG_I("materialFactorData ubo copying failed");
303         }
304         if (!CloneData(matTransformData, size_t(matTransformDataEnd - matTransformData), &uniforms.transforms,
305                 sizeof(RenderDataDefaultMaterial::MaterialPackedUniforms))) {
306             CORE_LOG_I("materialTransformData ubo copying failed");
307         }
308         const auto materialCustomProperties = dataStoreMaterial.GetMaterialCustomPropertyData(matIdx);
309         if (!materialCustomProperties.empty()) {
310             CORE_ASSERT(materialCustomProperties.size_bytes() <= UBO_BIND_OFFSET_ALIGNMENT);
311             if (!CloneData(userMaterialData, size_t(userMaterialDataEnd - userMaterialData),
312                     materialCustomProperties.data(), materialCustomProperties.size_bytes())) {
313                 CORE_LOG_I("userMaterialData ubo copying failed");
314             }
315         }
316         matFactorData = matFactorData + UBO_BIND_OFFSET_ALIGNMENT;
317         matTransformData = matTransformData + UBO_BIND_OFFSET_ALIGNMENT;
318         userMaterialData = userMaterialData + UBO_BIND_OFFSET_ALIGNMENT;
319     }
320 
321     gpuResourceMgr.UnmapBuffer(ubos_.mat.GetHandle());
322     gpuResourceMgr.UnmapBuffer(ubos_.matTransform.GetHandle());
323     gpuResourceMgr.UnmapBuffer(ubos_.userMat.GetHandle());
324 }
325 
UpdateDescriptorSets(IRenderCommandList & cmdList,const IRenderDataStoreDefaultMaterial & dataStoreMaterial)326 void RenderNodeDefaultMaterialObjects::UpdateDescriptorSets(
327     IRenderCommandList& cmdList, const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
328 {
329     // loop through all materials at the moment
330     {
331         const auto& materialHandles = dataStoreMaterial.GetMaterialHandles();
332 #if (CORE3D_VALIDATION_ENABLED == 1)
333         if (globalDescs_.descriptorSets.size() != globalDescs_.materials.size()) {
334             const string tmpStr =
335                 renderNodeContextMgr_->GetName() + "RenderNodeDefaultMaterialObjects::UpdateDescriptorSets";
336             CORE_LOG_ONCE_W(tmpStr, "CORE3D_VALIDATION: Invalid default material descriptor set setup");
337         }
338 #endif
339         IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
340         for (size_t idx = 0; idx < materialHandles.size(); ++idx) {
341             if (idx >= globalDescs_.descriptorSets.size()) {
342                 break; // prevent possible issues
343             }
344             auto* binder = globalDescs_.descriptorSets[idx].get();
345             if (binder && (idx < materialHandles.size())) {
346                 const auto& matHandles = materialHandles[idx];
347                 MaterialHandleStruct& storedMatHandles = globalDescs_.materials[idx];
348                 const bool updateDescSet = UpdateCurrentMaterialHandles(
349                     gpuResourceMgr, globalDescs_.forceUpdate, defaultMaterialStruct_, matHandles, storedMatHandles);
350 
351                 if (globalDescs_.forceUpdate || updateDescSet) {
352                     uint32_t bindingIdx = 0u;
353                     // base color is bound separately to support automatic hwbuffer/OES shader modification
354                     binder->BindImage(
355                         bindingIdx++, storedMatHandles.resources[MaterialComponent::TextureIndex::BASE_COLOR]);
356 
357                     CORE_STATIC_ASSERT(MaterialComponent::TextureIndex::BASE_COLOR == 0);
358                     // skip baseColor as it's bound already
359                     constexpr size_t theCount = RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT - 1;
360                     binder->BindImages(bindingIdx++, array_view(storedMatHandles.resources + 1, theCount));
361 
362                     cmdList.UpdateDescriptorSet(
363                         binder->GetDescriptorSetHandle(), binder->GetDescriptorSetLayoutBindingResources());
364                 }
365             }
366         }
367         globalDescs_.forceUpdate = false;
368     }
369     if (auto* binder = globalDescs_.dmSet1Binder.get(); binder) {
370         // NOTE: should be PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE or current size
371         constexpr uint32_t skinSize = sizeof(DefaultMaterialSkinStruct);
372         uint32_t bindingIdx = 0u;
373         binder->BindBuffer(bindingIdx++, ubos_.mesh.GetHandle(), 0U, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
374         binder->BindBuffer(bindingIdx++, ubos_.submeshSkin.GetHandle(), 0U, skinSize);
375         binder->BindBuffer(bindingIdx++, ubos_.mat.GetHandle(), 0U, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
376         binder->BindBuffer(
377             bindingIdx++, ubos_.matTransform.GetHandle(), 0U, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
378         binder->BindBuffer(
379             bindingIdx++, ubos_.userMat.GetHandle(), 0U, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
380         cmdList.UpdateDescriptorSet(binder->GetDescriptorSetHandle(), binder->GetDescriptorSetLayoutBindingResources());
381     }
382     // update only once
383     if (!globalDescs_.dmSet2Ready) {
384         if (auto* binder = globalDescs_.dmSet2Binder.get(); binder) {
385             uint32_t bindingIdx = 0u;
386             // base color is bound separately to support automatic hwbuffer/OES shader modification
387             binder->BindImage(
388                 bindingIdx++, defaultMaterialStruct_.resources[MaterialComponent::TextureIndex::BASE_COLOR]);
389 
390             CORE_STATIC_ASSERT(MaterialComponent::TextureIndex::BASE_COLOR == 0);
391             // skip baseColor as it's bound already
392             constexpr size_t theCount = RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT - 1;
393             binder->BindImages(bindingIdx++, array_view(defaultMaterialStruct_.resources + 1, theCount));
394 
395             cmdList.UpdateDescriptorSet(
396                 binder->GetDescriptorSetHandle(), binder->GetDescriptorSetLayoutBindingResources());
397             globalDescs_.dmSet2Ready = true;
398         }
399     }
400 }
401 
ProcessBuffers(const ObjectCounts & objectCounts)402 void RenderNodeDefaultMaterialObjects::ProcessBuffers(const ObjectCounts& objectCounts)
403 {
404     auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
405     constexpr uint32_t overEstimate { 16u };
406     constexpr uint32_t baseStructSize = CORE_UNIFORM_BUFFER_MAX_BIND_SIZE;
407     constexpr uint32_t singleComponentStructSize = UBO_BIND_OFFSET_ALIGNMENT;
408     const string_view us = stores_.dataStoreNameScene;
409     GpuBufferDesc bDesc = UBO_DESC;
410     // instancing utilization for mesh and materials
411     if (objectCounts_.maxMeshCount < objectCounts.maxMeshCount) {
412         // mesh matrix uses max ubo bind size to utilize gpu instancing
413         CORE_STATIC_ASSERT(sizeof(DefaultMaterialMeshStruct) <= PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
414         objectCounts_.maxMeshCount =
415             objectCounts.maxMeshCount + (objectCounts.maxMeshCount / overEstimate) + MIN_UBO_OBJECT_COUNT;
416 
417         const uint32_t byteSize =
418             static_cast<uint32_t>(Align(objectCounts_.maxMeshCount * singleComponentStructSize, baseStructSize));
419         objectCounts_.maxMeshCount = (byteSize / singleComponentStructSize) - MIN_UBO_OBJECT_COUNT;
420         CORE_ASSERT((int32_t(byteSize / singleComponentStructSize) - int32_t(MIN_UBO_OBJECT_COUNT)) > 0);
421 
422         bDesc.byteSize = byteSize;
423         ubos_.mesh = gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::MESH_DATA_BUFFER_NAME, bDesc);
424 
425         // rt
426         if constexpr (ENABLE_RT) {
427             if (rtEnabled_) {
428                 ProcessTlasBuffers();
429             }
430         }
431     }
432     if (objectCounts_.maxSkinCount < objectCounts.maxSkinCount) {
433         objectCounts_.maxSkinCount = objectCounts.maxSkinCount + (objectCounts.maxSkinCount / overEstimate);
434 
435         bDesc.byteSize = static_cast<uint32_t>(sizeof(DefaultMaterialSkinStruct)) * objectCounts_.maxSkinCount;
436         ubos_.submeshSkin = gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::SKIN_DATA_BUFFER_NAME, bDesc);
437     }
438     if (objectCounts_.maxMaterialCount < objectCounts.maxMaterialCount) {
439         CORE_STATIC_ASSERT(sizeof(RenderDataDefaultMaterial::MaterialUniforms) <= UBO_BIND_OFFSET_ALIGNMENT);
440         objectCounts_.maxMaterialCount =
441             objectCounts.maxMaterialCount + (objectCounts.maxMaterialCount / overEstimate) + MIN_UBO_OBJECT_COUNT;
442 
443         const uint32_t byteSize =
444             static_cast<uint32_t>(Align(objectCounts_.maxMaterialCount * singleComponentStructSize, baseStructSize));
445         objectCounts_.maxMaterialCount = (byteSize / singleComponentStructSize) - MIN_UBO_OBJECT_COUNT;
446         CORE_ASSERT((int32_t(byteSize / singleComponentStructSize) - int32_t(MIN_UBO_OBJECT_COUNT)) > 0);
447 
448         bDesc.byteSize = byteSize;
449         ubos_.mat = gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::MATERIAL_DATA_BUFFER_NAME, bDesc);
450         ubos_.matTransform =
451             gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::MATERIAL_TRANSFORM_DATA_BUFFER_NAME, bDesc);
452         ubos_.userMat =
453             gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::MATERIAL_USER_DATA_BUFFER_NAME, bDesc);
454     }
455     if (objectCounts_.maxUniqueMaterialCount < objectCounts.maxUniqueMaterialCount) {
456         CORE_STATIC_ASSERT(sizeof(RenderDataDefaultMaterial::MaterialUniforms) <= UBO_BIND_OFFSET_ALIGNMENT);
457         objectCounts_.maxUniqueMaterialCount = objectCounts.maxUniqueMaterialCount +
458                                                (objectCounts.maxUniqueMaterialCount / overEstimate) +
459                                                MIN_MATERIAL_DESC_SET_COUNT;
460         objectCounts_.maxUniqueMaterialCount =
461             static_cast<uint32_t>(Align(objectCounts_.maxUniqueMaterialCount, MIN_MATERIAL_DESC_SET_COUNT));
462         // global descriptor sets
463         INodeContextDescriptorSetManager& dsMgr = renderNodeContextMgr_->GetDescriptorSetManager();
464         constexpr uint32_t set = 2U;
465         globalDescs_.handles.clear();
466         globalDescs_.descriptorSets.clear();
467         globalDescs_.forceUpdate = true;
468         const auto& bindings = defaultMaterialPipelineLayout_.descriptorSetLayouts[set].bindings;
469 #if (CORE3D_VALIDATION_ENABLED == 1)
470         if (bindings.empty()) {
471             CORE_LOG_W("CORE3D_VALIDATION: Zero bindings in default material pipeline layout set 2");
472         }
473 #endif
474         globalDescs_.handles = dsMgr.CreateGlobalDescriptorSets(
475             us + DefaultMaterialMaterialConstants::MATERIAL_RESOURCES_GLOBAL_DESCRIPTOR_SET_NAME, bindings,
476             objectCounts_.maxUniqueMaterialCount);
477         globalDescs_.descriptorSets.resize(globalDescs_.handles.size());
478         globalDescs_.materials.resize(globalDescs_.handles.size());
479         for (size_t idx = 0; idx < globalDescs_.handles.size(); ++idx) {
480             globalDescs_.descriptorSets[idx] =
481                 dsMgr.CreateDescriptorSetBinder(globalDescs_.handles[idx].GetHandle(), bindings);
482         }
483     }
484     ProcessGlobalBinders();
485 }
486 
ProcessGlobalBinders()487 void RenderNodeDefaultMaterialObjects::ProcessGlobalBinders()
488 {
489     if (!globalDescs_.dmSet1Binder) {
490         const string_view us = stores_.dataStoreNameScene;
491         INodeContextDescriptorSetManager& dsMgr = renderNodeContextMgr_->GetDescriptorSetManager();
492         globalDescs_.dmSet1 = {};
493         globalDescs_.dmSet1Binder = {};
494         constexpr uint32_t set = 1U;
495         const auto& bindings = defaultMaterialPipelineLayout_.descriptorSetLayouts[set].bindings;
496         globalDescs_.dmSet1 = dsMgr.CreateGlobalDescriptorSet(
497             us + DefaultMaterialMaterialConstants::MATERIAL_SET1_GLOBAL_DESCRIPTOR_SET_NAME, bindings);
498         globalDescs_.dmSet1Binder = dsMgr.CreateDescriptorSetBinder(globalDescs_.dmSet1.GetHandle(), bindings);
499     }
500     if (!globalDescs_.dmSet2Binder) {
501         const string_view us = stores_.dataStoreNameScene;
502         INodeContextDescriptorSetManager& dsMgr = renderNodeContextMgr_->GetDescriptorSetManager();
503         globalDescs_.dmSet2 = {};
504         globalDescs_.dmSet2Binder = {};
505         constexpr uint32_t set = 2U;
506         const auto& bindings = defaultMaterialPipelineLayout_.descriptorSetLayouts[set].bindings;
507         globalDescs_.dmSet2 = dsMgr.CreateGlobalDescriptorSet(
508             us + DefaultMaterialMaterialConstants::MATERIAL_DEFAULT_RESOURCE_GLOBAL_DESCRIPTOR_SET_NAME, bindings);
509         globalDescs_.dmSet2Binder = dsMgr.CreateDescriptorSetBinder(globalDescs_.dmSet2.GetHandle(), bindings);
510     }
511 }
512 
ProcessTlasBuffers()513 void RenderNodeDefaultMaterialObjects::ProcessTlasBuffers()
514 {
515     CORE_ASSERT(rtEnabled_);
516     // NOTE: does not overestimate
517     // re-allocates every time
518     auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
519     const string_view us = stores_.dataStoreNameScene;
520 
521     IDevice& device = renderNodeContextMgr_->GetRenderContext().GetDevice();
522     {
523         AsGeometryInstancesInfo asInstances { false, 0U, objectCounts_.maxMeshCount };
524 
525         AsBuildGeometryInfo geometryInfo;
526         geometryInfo.type = AccelerationStructureType::CORE_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL;
527         // build
528         geometryInfo.mode = BuildAccelerationStructureMode::CORE_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD;
529         geometryInfo.flags = BuildAccelerationStructureFlagBits::CORE_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT;
530         tlas_.asBuildSizes = device.GetAccelerationStructureBuildSizes(geometryInfo, {}, {}, { &asInstances, 1U });
531         const GpuAccelerationStructureDesc desc { AccelerationStructureType::CORE_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL,
532             GpuBufferDesc {
533                 CORE_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT,
534                 CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
535                 CORE_ENGINE_BUFFER_CREATION_DYNAMIC_BARRIERS,
536                 tlas_.asBuildSizes.accelerationStructureSize,
537             } };
538         tlas_.as = gpuResourceMgr.Create(us + DefaultMaterialMaterialConstants::MATERIAL_TLAS_PREFIX_NAME, desc);
539         tlas_.createNewBuffer = true;
540     }
541     // GPU buffer is made during ExecuteFrame
542 }
543 
UpdateTlasBuffers(IRenderCommandList & cmdList,const IRenderDataStoreDefaultMaterial & dataStoreMaterial)544 void RenderNodeDefaultMaterialObjects::UpdateTlasBuffers(
545     IRenderCommandList& cmdList, const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
546 {
547     if constexpr (ENABLE_RT) {
548         if (rtEnabled_) {
549             if (tlas_.createNewBuffer) {
550                 tlas_.createNewBuffer = false;
551 
552                 auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
553                 const uint32_t byteSize =
554                     PipelineStateConstants::ACCELERATION_STRUCTURE_INSTANCE_SIZE * objectCounts_.maxMeshCount;
555                 const GpuBufferDesc desc {
556                     BufferUsageFlagBits::CORE_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
557                         BufferUsageFlagBits::
558                             CORE_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT, // usageFlags
559                     MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
560                         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT, // memoryPropertyFlags
561                     CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER,                    // engineCreationFlags
562                     byteSize,                                                           // byteSize
563                     BASE_NS::Format::BASE_FORMAT_UNDEFINED,                             // format
564                 };
565                 // name not needed, only access here
566                 tlas_.asInstanceBuffer = gpuResourceMgr.Create(tlas_.asInstanceBuffer, desc);
567 
568                 // allocate scratch
569                 const GpuBufferDesc scratchDesc {
570                     BufferUsageFlagBits::CORE_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
571                         BufferUsageFlagBits::CORE_BUFFER_USAGE_STORAGE_BUFFER_BIT, // usageFlags
572                     CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,                         // memoryPropertyFlags
573                     0U,                                                            // engineCreationFlags
574                     tlas_.asBuildSizes.buildScratchSize,                           // byteSize
575                     BASE_NS::Format::BASE_FORMAT_UNDEFINED,                        // format
576                 };
577                 tlas_.scratch = gpuResourceMgr.Create(tlas_.scratch, scratchDesc);
578             }
579 
580             const RenderDataStoreDefaultMaterial& dsMat = (const RenderDataStoreDefaultMaterial&)dataStoreMaterial;
581             const auto blasData = dsMat.GetMeshBlasData();
582             if (!blasData.empty()) {
583                 cmdList.CopyAccelerationStructureInstances({ tlas_.asInstanceBuffer.GetHandle(), 0U }, blasData);
584 
585                 const uint32_t blasCount = static_cast<uint32_t>(blasData.size());
586                 AsGeometryInstancesData asInstances;
587                 asInstances.info = { false, 0U, blasCount };
588                 asInstances.data = { tlas_.asInstanceBuffer.GetHandle(), 0U };
589 
590                 AsBuildGeometryData geometry;
591                 geometry.dstAccelerationStructure = tlas_.as.GetHandle();
592                 geometry.scratchBuffer = { tlas_.scratch.GetHandle(), 0U };
593                 geometry.srcAccelerationStructure = {};
594                 geometry.info.type = AccelerationStructureType::CORE_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL;
595                 geometry.info.mode = BuildAccelerationStructureMode::CORE_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD;
596                 geometry.info.flags =
597                     BuildAccelerationStructureFlagBits::CORE_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT;
598                 cmdList.BuildAccelerationStructures(geometry, {}, {}, { &asInstances, 1U });
599             }
600         }
601     }
602 }
603 
604 // for plugin / factory interface
Create()605 RENDER_NS::IRenderNode* RenderNodeDefaultMaterialObjects::Create()
606 {
607     return new RenderNodeDefaultMaterialObjects();
608 }
609 
Destroy(IRenderNode * instance)610 void RenderNodeDefaultMaterialObjects::Destroy(IRenderNode* instance)
611 {
612     delete static_cast<RenderNodeDefaultMaterialObjects*>(instance);
613 }
614 CORE3D_END_NAMESPACE()
615