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