• 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_data_store_default_material.h"
17 
18 #include <algorithm>
19 #include <cstdint>
20 
21 #include <3d/implementation_uids.h>
22 #include <3d/intf_graphics_context.h>
23 #include <3d/render/intf_render_data_store_default_material.h>
24 #include <base/containers/array_view.h>
25 #include <base/math/float_packer.h>
26 #include <base/math/matrix_util.h>
27 #include <core/log.h>
28 #include <render/datastore/intf_render_data_store_default_acceleration_structure_staging.h>
29 #include <render/datastore/intf_render_data_store_manager.h>
30 #include <render/device/intf_gpu_resource_manager.h>
31 #include <render/device/intf_shader_manager.h>
32 #include <render/intf_render_context.h>
33 #include <render/resource_handle.h>
34 
35 #include "render_data_store_default_material.h"
36 
37 CORE3D_BEGIN_NAMESPACE()
38 using namespace BASE_NS;
39 using namespace RENDER_NS;
40 
41 using RENDER_NS::IShaderManager;
42 using RENDER_NS::RenderHandleReference;
43 
44 namespace {
45 // for packing defines
46 #include <3d/shaders/common/3d_dm_structures_common.h>
47 } // namespace
48 namespace {
49 constexpr size_t MEMORY_ALIGNMENT { 64 };
50 constexpr bool ENABLE_RT { true };
51 
52 static constexpr uint32_t MATERIAL_TYPE_SHIFT { 28u };
53 static constexpr uint32_t MATERIAL_TYPE_MASK { 0xF0000000u };
54 static constexpr uint32_t MATERIAL_FLAGS_SHIFT { 8u };
55 static constexpr uint32_t MATERIAL_FLAGS_MASK { 0x0FFFff00u };
56 static constexpr uint32_t SUBMESH_FLAGS_MASK { 0x00000ffu };
57 
58 static constexpr uint32_t COMBINED_GPU_INSTANCING_REMOVAL { ~(
59     RenderMaterialFlagBits::RENDER_MATERIAL_GPU_INSTANCING_BIT |
60     RenderMaterialFlagBits::RENDER_MATERIAL_GPU_INSTANCING_MATERIAL_BIT) };
61 
62 static constexpr RenderDataDefaultMaterial::AllMaterialUniforms INIT_ALL_MATERIAL_UNIFORMS {};
63 
64 static constexpr float FMAX_VAL_AABB { std::numeric_limits<float>::max() };
65 
66 static constexpr string_view DS_ACCELERATION_STRUCTURE { "RenderDataStoreDefaultAccelerationStructureStaging" };
67 
68 struct MinAndMax {
69     BASE_NS::Math::Vec3 minAABB { FMAX_VAL_AABB, FMAX_VAL_AABB, FMAX_VAL_AABB };
70     BASE_NS::Math::Vec3 maxAABB { -FMAX_VAL_AABB, -FMAX_VAL_AABB, -FMAX_VAL_AABB };
71 };
72 
73 static constexpr RenderMeshBatchData DEFAULT_RENDER_MESH_BATCH_DATA {};
74 
HashCombine32Bit(uint32_t & seed,const uint32_t v)75 inline void HashCombine32Bit(uint32_t& seed, const uint32_t v)
76 {
77     constexpr const uint32_t goldenRatio = 0x9e3779b9;
78     constexpr const uint32_t rotl = 6U;
79     constexpr const uint32_t rotr = 2U;
80     seed ^= hash(v) + goldenRatio + (seed << rotl) + (seed >> rotr);
81 }
82 
ConvertMaterialHandleReferences(const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference & inputHandles,vector<RenderHandleReference> & references)83 inline constexpr RenderDataDefaultMaterial::MaterialHandles ConvertMaterialHandleReferences(
84     const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference& inputHandles,
85     vector<RenderHandleReference>& references)
86 {
87     RenderDataDefaultMaterial::MaterialHandles mh;
88     for (uint32_t idx = 0; idx < RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT; ++idx) {
89         if (inputHandles.images[idx]) {
90             mh.images[idx] = inputHandles.images[idx].GetHandle();
91             references.push_back(inputHandles.images[idx]);
92         }
93         if (inputHandles.samplers[idx]) {
94             mh.samplers[idx] = inputHandles.samplers[idx].GetHandle();
95             references.push_back(inputHandles.samplers[idx]);
96         }
97     }
98     return mh;
99 }
100 
GetRenderSortLayerHash(const RenderSubmesh & submesh)101 inline constexpr uint16_t GetRenderSortLayerHash(const RenderSubmesh& submesh)
102 {
103     // if submesh layers are defaults -> use material sort values (the defaults are the same)
104     if ((submesh.layers.meshRenderSortLayer == RenderSceneDataConstants::DEFAULT_RENDER_SORT_LAYER_ID) &&
105         (submesh.layers.meshRenderSortLayerOrder == 0)) {
106         return (static_cast<uint16_t>(submesh.layers.materialRenderSortLayer) << 8u) |
107                (static_cast<uint16_t>(submesh.layers.materialRenderSortLayerOrder) & 0xffu);
108     } else {
109         return (static_cast<uint16_t>(submesh.layers.meshRenderSortLayer) << 8u) |
110                (static_cast<uint16_t>(submesh.layers.meshRenderSortLayerOrder) & 0xffu);
111     }
112 }
113 
ConvertRenderSubmeshBuffers(const RenderSubmeshBuffersWithHandleReference & buffers,vector<RenderHandleReference> & handleReferences)114 RenderSubmeshBuffers ConvertRenderSubmeshBuffers(
115     const RenderSubmeshBuffersWithHandleReference& buffers, vector<RenderHandleReference>& handleReferences)
116 {
117     // convert and add references
118     RenderSubmeshBuffers rsb;
119     const auto& ib = buffers.indexBuffer;
120     if (ib.bufferHandle) {
121         handleReferences.push_back(ib.bufferHandle);
122         rsb.indexBuffer = { ib.bufferHandle.GetHandle(), ib.bufferOffset, ib.byteSize, ib.indexType };
123     }
124     const auto& iargs = buffers.indirectArgsBuffer;
125     if (iargs.bufferHandle) {
126         handleReferences.push_back(iargs.bufferHandle);
127         rsb.indirectArgsBuffer = { iargs.bufferHandle.GetHandle(), iargs.bufferOffset, iargs.byteSize };
128     }
129     const RenderHandle safetyBuffer = buffers.vertexBuffers[0U].bufferHandle.GetHandle();
130     RenderHandle prevHandle {};
131     for (uint32_t idx = 0; idx < RENDER_NS::PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT; ++idx) {
132         const auto& vb = buffers.vertexBuffers[idx];
133         // add safety handles to invalid buffers
134         if (vb.bufferHandle) {
135             const RenderHandle currHandle = vb.bufferHandle.GetHandle();
136             if (currHandle != prevHandle) {
137                 handleReferences.push_back(vb.bufferHandle);
138             }
139             rsb.vertexBuffers[idx] = { currHandle, vb.bufferOffset, vb.byteSize };
140         } else {
141             rsb.vertexBuffers[idx] = { safetyBuffer, 0U, 0U };
142         }
143         prevHandle = rsb.vertexBuffers[idx].bufferHandle;
144     }
145     // NOTE: we will get max amount of vertex buffers if there is at least one
146     rsb.vertexBufferCount = RenderHandleUtil::IsValid(rsb.vertexBuffers[0U].bufferHandle)
147                                 ? RENDER_NS::PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT
148                                 : 0U;
149     rsb.inputAssembly = buffers.inputAssembly;
150     return rsb;
151 }
152 
ConvertRenderSubmeshInput(const RenderSubmeshWithHandleReference & input,vector<RenderHandleReference> & references)153 RenderSubmesh ConvertRenderSubmeshInput(
154     const RenderSubmeshWithHandleReference& input, vector<RenderHandleReference>& references)
155 {
156     RenderSubmeshBuffers rsb;
157     const auto& ib = input.buffers.indexBuffer;
158     if (ib.bufferHandle) {
159         references.push_back(ib.bufferHandle);
160         rsb.indexBuffer = { ib.bufferHandle.GetHandle(), ib.bufferOffset, ib.byteSize, ib.indexType };
161     }
162     const auto& iargs = input.buffers.indirectArgsBuffer;
163     if (iargs.bufferHandle) {
164         references.push_back(iargs.bufferHandle);
165         rsb.indirectArgsBuffer = { iargs.bufferHandle.GetHandle(), iargs.bufferOffset, iargs.byteSize };
166     }
167     const RenderHandle safetyBuffer = input.buffers.vertexBuffers[0U].bufferHandle.GetHandle();
168     RenderHandle prevHandle {};
169     for (uint32_t idx = 0; idx < RENDER_NS::PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT; ++idx) {
170         const auto& vb = input.buffers.vertexBuffers[idx];
171         // add safety handles to invalid buffers
172         if (vb.bufferHandle) {
173             rsb.vertexBuffers[idx] = { vb.bufferHandle.GetHandle(), vb.bufferOffset, vb.byteSize };
174             // often we have the same buffer (GPU resource)
175             if (rsb.vertexBuffers[idx].bufferHandle != prevHandle) {
176                 references.push_back(vb.bufferHandle);
177             }
178         } else {
179             rsb.vertexBuffers[idx] = { safetyBuffer, 0U, 0U };
180         }
181         prevHandle = rsb.vertexBuffers[idx].bufferHandle;
182     }
183     // NOTE: we will get max amount of vertex buffers if there is at least one
184     rsb.vertexBufferCount = RenderHandleUtil::IsValid(rsb.vertexBuffers[0U].bufferHandle)
185                                 ? RENDER_NS::PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT
186                                 : 0U;
187     rsb.inputAssembly = input.buffers.inputAssembly;
188 
189     return RenderSubmesh { input.submeshFlags, input.renderSubmeshMaterialFlags, input.indices, input.layers,
190         input.bounds, input.drawCommand, move(rsb) };
191 }
192 
193 #if (CORE3D_VALIDATION_ENABLED == 1)
ValidateSubmesh(const RenderSubmeshWithHandleReference & submesh)194 void ValidateSubmesh(const RenderSubmeshWithHandleReference& submesh)
195 {
196     if (((submesh.submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT) == 0) &&
197         submesh.indices.skinJointIndex != RenderSceneDataConstants::INVALID_INDEX) {
198         CORE_LOG_W("CORE3D_VALIDATION: skin bit is not set for submesh flags");
199     }
200 }
201 #endif
202 
PackMaterialUVec(const Math::Vec4 & up0,const Math::Vec4 & up1)203 inline Math::UVec4 PackMaterialUVec(const Math::Vec4& up0, const Math::Vec4& up1)
204 {
205     return Math::UVec4 {
206         Math::PackHalf2X16({ up0.x, up0.y }),
207         Math::PackHalf2X16({ up0.z, up0.w }),
208         Math::PackHalf2X16({ up1.x, up1.y }),
209         Math::PackHalf2X16({ up1.z, up1.w }),
210     };
211 }
212 
ExtentRenderMaterialFlagsFromSubmeshValues(const RenderSubmeshFlags & submeshFlags,RenderMaterialFlags & rmf)213 inline void ExtentRenderMaterialFlagsFromSubmeshValues(const RenderSubmeshFlags& submeshFlags, RenderMaterialFlags& rmf)
214 {
215     // if there are normal maps and there are tangets, we allow the normal map flag
216     if ((rmf & RenderMaterialFlagBits::RENDER_MATERIAL_NORMAL_MAP_BIT) &&
217         (submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_TANGENTS_BIT)) {
218         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_NORMAL_MAP_BIT;
219     } else {
220         // remove flag if there were only normal maps but no tangents
221         rmf &= (~RenderMaterialFlagBits::RENDER_MATERIAL_NORMAL_MAP_BIT);
222     }
223 }
224 
ExtentRenderMaterialFlagsForComplexity(const RenderMaterialType materialType,RenderMaterialFlags & rmf)225 void ExtentRenderMaterialFlagsForComplexity(const RenderMaterialType materialType, RenderMaterialFlags& rmf)
226 {
227     constexpr RenderMaterialFlags complexMask { RENDER_MATERIAL_CLEAR_COAT_BIT | RENDER_MATERIAL_TRANSMISSION_BIT |
228                                                 RENDER_MATERIAL_SHEEN_BIT | RENDER_MATERIAL_SPECULAR_BIT };
229     if ((materialType == RenderMaterialType::CUSTOM) || (materialType == RenderMaterialType::CUSTOM_COMPLEX)) {
230         rmf |= (materialType == RenderMaterialType::CUSTOM_COMPLEX) ? RENDER_MATERIAL_COMPLEX_BIT
231                                                                     : RENDER_MATERIAL_BASIC_BIT;
232         if (materialType < RenderMaterialType::CUSTOM) {
233             rmf |= ((rmf & complexMask) || (materialType == RenderMaterialType::SPECULAR_GLOSSINESS))
234                        ? RENDER_MATERIAL_COMPLEX_BIT
235                        : RENDER_MATERIAL_BASIC_BIT;
236         }
237     } else {
238         rmf |= ((rmf & complexMask) > 0) ? RENDER_MATERIAL_COMPLEX_BIT : RENDER_MATERIAL_BASIC_BIT;
239     }
240 }
241 
HashSubmeshMaterials(const RenderMaterialType materialType,const RenderMaterialFlags materialFlags,const RenderSubmeshFlags submeshFlags)242 inline constexpr uint32_t HashSubmeshMaterials(const RenderMaterialType materialType,
243     const RenderMaterialFlags materialFlags, const RenderSubmeshFlags submeshFlags)
244 {
245     return (((uint32_t)materialType << MATERIAL_TYPE_SHIFT) & MATERIAL_TYPE_MASK) |
246            ((materialFlags << MATERIAL_FLAGS_SHIFT) & MATERIAL_FLAGS_MASK) | (submeshFlags & SUBMESH_FLAGS_MASK);
247 }
248 
PatchRenderMaterialSortLayers(const RenderDataDefaultMaterial::MaterialData & matData,RenderSubmeshLayers & layers)249 inline constexpr void PatchRenderMaterialSortLayers(
250     const RenderDataDefaultMaterial::MaterialData& matData, RenderSubmeshLayers& layers)
251 {
252     // batch render material sort layers if default
253     if (layers.materialRenderSortLayer == RenderSceneDataConstants::DEFAULT_RENDER_SORT_LAYER_ID) {
254         layers.materialRenderSortLayer = matData.renderSortLayer;
255     }
256     if (layers.materialRenderSortLayerOrder == 0U) {
257         layers.materialRenderSortLayerOrder = matData.renderSortLayerOrder;
258     }
259 }
260 
HashMaterialId(const uint64_t id,const uint32_t instanceCount)261 inline uint64_t HashMaterialId(const uint64_t id, const uint32_t instanceCount)
262 {
263     return Hash(id, static_cast<uint64_t>(instanceCount));
264 }
265 
AllocateMatrixMemory(RenderDataStoreDefaultMaterial::LinearAllocatorStruct & allocator,const size_t byteSize)266 void* AllocateMatrixMemory(RenderDataStoreDefaultMaterial::LinearAllocatorStruct& allocator, const size_t byteSize)
267 {
268     void* data = nullptr;
269     if (!allocator.allocators.empty()) {
270         data = allocator.allocators[allocator.currentIndex]->Allocate(byteSize);
271     }
272 
273     if (data) {
274         return data;
275     } else { // current allocator is out of memory
276         allocator.allocators.push_back(make_unique<LinearAllocator>(byteSize, MEMORY_ALIGNMENT));
277         allocator.currentIndex = (uint32_t)(allocator.allocators.size() - 1);
278         data = allocator.allocators[allocator.currentIndex]->Allocate(byteSize);
279         CORE_ASSERT_MSG(data, "render data store default material allocation : out of memory");
280         return data;
281     }
282 }
283 
AllocateMatrices(RenderDataStoreDefaultMaterial::LinearAllocatorStruct & allocator,const size_t count)284 Math::Mat4X4* AllocateMatrices(RenderDataStoreDefaultMaterial::LinearAllocatorStruct& allocator, const size_t count)
285 {
286     const size_t byteSize = count * sizeof(Math::Mat4X4);
287     return static_cast<Math::Mat4X4*>(AllocateMatrixMemory(allocator, byteSize));
288 }
289 
MaterialUniformsPackedFromInput(const RenderDataDefaultMaterial::InputMaterialUniforms & input)290 RenderDataDefaultMaterial::AllMaterialUniforms MaterialUniformsPackedFromInput(
291     const RenderDataDefaultMaterial::InputMaterialUniforms& input)
292 {
293     RenderDataDefaultMaterial::AllMaterialUniforms amu = INIT_ALL_MATERIAL_UNIFORMS;
294     // premultiplication needs to be handled already with some factors like baseColor
295     for (uint32_t idx = 0; idx < RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT; ++idx) {
296         amu.factors.factors[idx] = input.textureData[idx].factor;
297     }
298     uint32_t transformBits = 0;
299     {
300         constexpr auto supportedMaterials = RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT;
301         for (uint32_t i = 0; i < supportedMaterials; ++i) {
302             const auto& tex = input.textureData[i];
303 
304             /* TRS matrix for 2D transformations:
305              * { scaleX * cos(rot),  scaleY * sin(rot), transX }
306              * { scaleX * -sin(rot), scaleY * cos(rot), transY }
307              * { 0,                  0,                 1      }
308              */
309             const Math::Vec4 rotateScale =
310                 [](const RenderDataDefaultMaterial::InputMaterialUniforms::TextureData& data) {
311                     if (data.rotation == 0.f) {
312                         return Math::Vec4 { data.scale.x, 0.f, 0.f, data.scale.y };
313                     }
314                     const float sinR = Math::sin(data.rotation);
315                     const float cosR = Math::cos(data.rotation);
316                     return Math::Vec4 { data.scale.x * cosR, data.scale.y * sinR, data.scale.x * -sinR,
317                         data.scale.y * cosR };
318                 }(tex);
319 
320             // set transform bit for texture index
321             static constexpr const auto identityRs = Math::Vec4(1.f, 0.f, 0.f, 1.f);
322             const bool hasTransform =
323                 (tex.translation.x != 0.f) || (tex.translation.y != 0.f) || (rotateScale != identityRs);
324             if (!hasTransform) {
325                 // this matches packing identityRs.xy, identityRs.zw, translation.xy, and 0,0
326                 static constexpr const auto identity = Math::UVec4(0x3c000000, 0x00003c00, 0x0, 0x0);
327                 amu.transforms.packed[CORE_MATERIAL_PACK_TEX_BASE_COLOR_UV_IDX + i] = identity;
328             } else {
329                 // using PackMaterialUVec costs packing the last unused zeros
330                 amu.transforms.packed[CORE_MATERIAL_PACK_TEX_BASE_COLOR_UV_IDX + i] =
331                     Math::UVec4 { Math::PackHalf2X16({ rotateScale.x, rotateScale.y }),
332                         Math::PackHalf2X16({ rotateScale.z, rotateScale.w }),
333                         Math::PackHalf2X16({ tex.translation.x, tex.translation.y }), 0 };
334                 transformBits |= static_cast<uint32_t>(hasTransform) << i;
335             }
336         }
337     }
338     const uint32_t transformInfoBits = (input.texCoordSetBits << 16u) | transformBits; // 16: left remove 16 bits
339     const Math::UVec4 indices = { uint32_t(input.id >> 32u), uint32_t(input.id & 0xFFFFffff), 0u, 0u };
340 
341     // finalize factors
342     amu.factors.factors[RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT] = { input.alphaCutoff,
343         *reinterpret_cast<const float*>(&transformInfoBits), 0.0f, 0.0f };
344     amu.factors.indices = indices;
345     // finalize transforms
346     amu.transforms.packed[CORE_MATERIAL_PACK_ADDITIONAL_IDX] = { Math::PackHalf2X16({ input.alphaCutoff, 0.f }),
347         transformInfoBits, 0, 0 };
348     amu.transforms.indices = indices;
349     return amu;
350 }
351 
GetSubmeshBounds(const RenderMeshAabbData renderMeshAabbData,const RenderMeshSkinData & meshSkinData,const RenderMeshBatchData renderMeshBatchData,const uint32_t submeshIdx,const bool useJoints,const uint32_t batchCount)352 RenderSubmeshBounds GetSubmeshBounds(const RenderMeshAabbData renderMeshAabbData,
353     const RenderMeshSkinData& meshSkinData, const RenderMeshBatchData renderMeshBatchData, const uint32_t submeshIdx,
354     const bool useJoints, const uint32_t batchCount)
355 {
356     RenderMinAndMax mam = [&]() {
357         if (useJoints) {
358             return meshSkinData.aabb;
359         } else if (submeshIdx < renderMeshAabbData.submeshAabb.size()) {
360             return renderMeshAabbData.submeshAabb[submeshIdx];
361         } else {
362             // NOTE: there should always be data
363             return renderMeshAabbData.aabb;
364         }
365     }();
366     if (batchCount > 0) {
367         mam.minAabb = Math::min(mam.minAabb, renderMeshBatchData.aabb.minAabb);
368         mam.maxAabb = Math::max(mam.maxAabb, renderMeshBatchData.aabb.maxAabb);
369     }
370     RenderSubmeshBounds bounds;
371     bounds.worldCenter = (mam.minAabb + mam.maxAabb) * 0.5f;
372     bounds.worldRadius = Math::sqrt(
373         Math::max(Math::Distance2(bounds.worldCenter, mam.minAabb), Math::Distance2(bounds.worldCenter, mam.maxAabb)));
374     return bounds;
375 }
376 
DestroyMaterialByIndex(const uint32_t index,RenderDataStoreDefaultMaterial::AllMaterialData & matData)377 void DestroyMaterialByIndex(const uint32_t index, RenderDataStoreDefaultMaterial::AllMaterialData& matData)
378 {
379     if (index < matData.data.size()) {
380         matData.data[index] = {};
381         matData.allUniforms[index] = {};
382         matData.handles[index] = {};
383         matData.customPropertyData[index] = {};
384         matData.customResourceData[index] = {};
385         matData.renderSlotData[index] = {};
386 
387         // add for re-use
388         matData.availableIndices.push_back(index);
389     }
390 }
391 
DestroyMeshByIndex(const uint32_t index,RenderDataStoreDefaultMaterial::AllMeshData & meshData)392 inline void DestroyMeshByIndex(const uint32_t index, RenderDataStoreDefaultMaterial::AllMeshData& meshData)
393 {
394     if (index < meshData.data.size()) {
395         meshData.data[index] = {};
396 
397         // add for re-use
398         meshData.availableIndices.push_back(index);
399     }
400 }
401 
GetCertainMaterialIndex(const uint32_t index,const RenderDataStoreDefaultMaterial::AllMaterialData & matData)402 uint32_t GetCertainMaterialIndex(const uint32_t index, const RenderDataStoreDefaultMaterial::AllMaterialData& matData)
403 {
404     if (index >= static_cast<uint32_t>(matData.data.size())) {
405         // built-in material in 0
406         CORE_ASSERT(!matData.data.empty());
407         if (!matData.data.empty()) {
408             return 0;
409         }
410     }
411     return index;
412 }
413 
GetCertainMaterialIndices(const RenderFrameMaterialIndices & indices,const RenderDataStoreDefaultMaterial::AllMaterialData & matData)414 RenderFrameMaterialIndices GetCertainMaterialIndices(
415     const RenderFrameMaterialIndices& indices, const RenderDataStoreDefaultMaterial::AllMaterialData& matData)
416 {
417     if (indices.index >= static_cast<uint32_t>(matData.data.size())) {
418         // built-in material in 0
419         CORE_ASSERT(!matData.data.empty());
420         if (!matData.data.empty()) {
421             return { 0, 0 };
422         }
423     }
424     return indices;
425 }
426 
GetDefaultInputMaterialUniforms()427 constexpr RenderDataDefaultMaterial::InputMaterialUniforms GetDefaultInputMaterialUniforms()
428 {
429     CORE_STATIC_ASSERT(RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT == 11U);
430 
431     // needs to match material component for default data
432     RenderDataDefaultMaterial::InputMaterialUniforms imu;
433     imu.textureData[0U].factor = { 1.f, 1.f, 1.f, 1.f };   // base color opaque white
434     imu.textureData[1U].factor = { 1.f, 0.f, 0.f, 0.f };   // normal scale 1
435     imu.textureData[2U].factor = { 0.f, 1.f, 1.f, 0.04f }; // material (empty, roughness, metallic, reflectance)
436     imu.textureData[3U].factor = { 0.f, 0.f, 0.f, 1.f };   // emissive 0
437     imu.textureData[4U].factor = { 1.f, 0.f, 0.f, 0.f };   // ambient occlusion 1
438     imu.textureData[5U].factor = { 0.f, 0.f, 0.f, 0.f };   // clearcoat intensity 0
439     imu.textureData[6U].factor = { 0.f, 0.f, 0.f, 0.f };   // clearcoat roughness 0
440     imu.textureData[7U].factor = { 1.f, 0.f, 0.f, 0.f };   // clearcoat normal scale 1
441     imu.textureData[8U].factor = { 0.f, 0.f, 0.f, 0.f };   // sheen color black, roughness 0
442     imu.textureData[9U].factor = { 0.f, 0.f, 0.f, 0.f };   // transmission 0
443     imu.textureData[10U].factor = { 1.f, 1.f, 1.f, 1.f };  // specular white
444 
445     imu.id = 0xFFFFffffU;
446 
447     return imu;
448 }
449 
FillMaterialDefaultRenderSlotData(const IShaderManager & shaderMgr,const RenderDataStoreDefaultMaterial::MaterialRenderSlots & materialRenderSlots,const RenderDataDefaultMaterial::MaterialData & matData,RenderDataStoreDefaultMaterial::MaterialDefaultRenderSlotData & renderSlotData)450 void FillMaterialDefaultRenderSlotData(const IShaderManager& shaderMgr,
451     const RenderDataStoreDefaultMaterial::MaterialRenderSlots& materialRenderSlots,
452     const RenderDataDefaultMaterial::MaterialData& matData,
453     RenderDataStoreDefaultMaterial::MaterialDefaultRenderSlotData& renderSlotData)
454 {
455     renderSlotData.count = 0U;
456     // default support for 2 render slots
457     renderSlotData.data[0U].shader = matData.materialShader.shader;
458     renderSlotData.data[0U].graphicsState = matData.materialShader.graphicsState;
459     constexpr uint32_t INVALID_RENDER_SLOT_ID = ~0u;
460     uint32_t renderSlotId = matData.customRenderSlotId;
461     if ((renderSlotId == INVALID_RENDER_SLOT_ID) && renderSlotData.data[0U].graphicsState) {
462         renderSlotId = shaderMgr.GetRenderSlotId(renderSlotData.data[0U].graphicsState);
463     }
464     if ((renderSlotId == INVALID_RENDER_SLOT_ID) && renderSlotData.data[0U].shader) {
465         renderSlotId = shaderMgr.GetRenderSlotId(renderSlotData.data[0U].shader);
466     }
467     // if all fails, render as opaque
468     if (renderSlotId == INVALID_RENDER_SLOT_ID) {
469         renderSlotId = materialRenderSlots.defaultOpaqueRenderSlot;
470     }
471     renderSlotData.data[renderSlotData.count].renderSlotId = renderSlotId;
472     renderSlotData.count++;
473 
474     if (matData.renderMaterialFlags & RenderMaterialFlagBits::RENDER_MATERIAL_SHADOW_CASTER_BIT) {
475         renderSlotData.data[renderSlotData.count].renderSlotId = materialRenderSlots.defaultDepthRenderSlot;
476         renderSlotData.data[renderSlotData.count].shader = matData.depthShader.shader;
477         renderSlotData.data[renderSlotData.count].graphicsState = matData.depthShader.graphicsState;
478         renderSlotData.count++;
479     }
480     CORE_ASSERT(renderSlotData.count <= RenderDataStoreDefaultMaterial::SHADER_DEFAULT_RENDER_SLOT_COUNT);
481 }
482 } // namespace
483 
RenderDataStoreDefaultMaterial(RENDER_NS::IRenderContext & renderContext,const string_view name)484 RenderDataStoreDefaultMaterial::RenderDataStoreDefaultMaterial(
485     RENDER_NS::IRenderContext& renderContext, const string_view name)
486     : name_(name), renderContext_(renderContext), gpuResourceMgr_(renderContext.GetDevice().GetGpuResourceManager()),
487       shaderMgr_(renderContext.GetDevice().GetShaderManager())
488 {
489     GetDefaultRenderSlots();
490 
491     // add default materials (~0U and max ~0ULL)
492     const uint32_t materialIndex = AddMaterialDataImpl(~0U, GetDefaultInputMaterialUniforms(), {}, {}, {}, {});
493     CORE_ASSERT(materialIndex == 0);
494     matData_.materialIdToIndex.insert_or_assign(0xFFFFffff, materialIndex);
495     matData_.materialIdToIndex.insert_or_assign(0xFFFFFFFFffffffff, materialIndex);
496 
497     // get flags for rt
498     if constexpr (ENABLE_RT) {
499         CORE_NS::IClassRegister *cr = renderContext.GetInterface<CORE_NS::IClassRegister>();
500         if (cr) {
501             IGraphicsContext* graphicsContext = CORE_NS::GetInstance<IGraphicsContext>(
502                 *cr, UID_GRAPHICS_CONTEXT);
503             if (graphicsContext) {
504                 const IGraphicsContext::CreateInfo ci = graphicsContext->GetCreateInfo();
505                 if (ci.createFlags & IGraphicsContext::CreateInfo::ENABLE_ACCELERATION_STRUCTURES_BIT) {
506                     rtEnabled_ = true;
507                 }
508             }
509         } else {
510             CORE_LOG_E("get null ClassRegister");
511         }
512     }
513 }
514 
PostRender()515 void RenderDataStoreDefaultMaterial::PostRender()
516 {
517     Clear();
518 }
519 
Clear()520 void RenderDataStoreDefaultMaterial::Clear()
521 {
522     // NOTE: clear is at the moment called typically two times
523     // this could be further optimized to know if clear has already been called
524 
525     renderFrameObjectInfo_ = {};
526 
527     // release references
528     handleReferences_.clear();
529 
530     meshData_.frameMeshData.clear();
531     meshData_.frameSubmeshes.clear();
532     meshData_.frameJointMatrixIndices.clear();
533     meshData_.frameSubmeshMaterialFlags.clear();
534     meshData_.frameMeshBlasInstanceData.clear();
535     for (auto& meshRef : meshData_.data) {
536         meshRef.frameReferenced = false; // clear for this frame processing
537     }
538 
539     // NOTE: material data is not cleared automatically anymore
540     // we keep the data but update the resource references if data is used
541     // separate destroy
542     {
543         matData_.frameIndices.clear();
544         matData_.idHashToFrameIndex.clear();
545 
546 #if (CORE3D_VALIDATION_ENABLED == 1)
547         vector<uint32_t> noIdRemoval;
548 #endif
549         // check that we have id of material (if not, then it's a single frame (usually) debug material
550         for (size_t idx = 0; idx < matData_.data.size(); ++idx) {
551             auto& matRef = matData_.data[idx];
552             matRef.frameReferenced = false;
553             if (matRef.noId) {
554                 DestroyMaterialByIndex(static_cast<uint32_t>(idx), matData_);
555 #if (CORE3D_VALIDATION_ENABLED == 1)
556                 // should not have an id
557                 noIdRemoval.push_back(static_cast<uint32_t>(idx));
558 #endif
559             }
560         }
561 #if (CORE3D_VALIDATION_ENABLED == 1)
562         for (const auto& ref : matData_.materialIdToIndex) {
563             for (const auto& noIdRef : noIdRemoval) {
564                 if (ref.second == noIdRef) {
565                     CORE_LOG_E("CORE3D_VALIDATION: Material removal issue");
566                 }
567             }
568         }
569         noIdRemoval.clear();
570 #endif
571     }
572 
573     for (auto& slotRef : slotToSubmeshIndices_) { // does not remove slots from use
574         slotRef.second.indices.clear();
575         slotRef.second.materialData.clear();
576         slotRef.second.objectCounts = {};
577     }
578 
579     if (!meshJointMatricesAllocator_.allocators.empty()) {
580         meshJointMatricesAllocator_.currentIndex = 0;
581         if (meshJointMatricesAllocator_.allocators.size() == 1) { // size is good for this frame
582             meshJointMatricesAllocator_.allocators[meshJointMatricesAllocator_.currentIndex]->Reset();
583         } else if (meshJointMatricesAllocator_.allocators.size() > 1) {
584             size_t fullByteSize = 0;
585             for (auto& ref : meshJointMatricesAllocator_.allocators) {
586                 fullByteSize += ref->GetCurrentByteSize();
587                 ref.reset();
588             }
589             meshJointMatricesAllocator_.allocators.clear();
590             // create new single allocation for combined previous size and some extra bytes
591             meshJointMatricesAllocator_.allocators.push_back(
592                 make_unique<LinearAllocator>(fullByteSize, MEMORY_ALIGNMENT));
593         }
594     }
595 
596     // NOTE: re-fetch if default slots are invalid
597     if (materialRenderSlots_.opaqueMask != 0) {
598         GetDefaultRenderSlots();
599     }
600 }
601 
Ref()602 void RenderDataStoreDefaultMaterial::Ref()
603 {
604     refcnt_.fetch_add(1, std::memory_order_relaxed);
605 }
606 
Unref()607 void RenderDataStoreDefaultMaterial::Unref()
608 {
609     if (std::atomic_fetch_sub_explicit(&refcnt_, 1, std::memory_order_release) == 1) {
610         std::atomic_thread_fence(std::memory_order_acquire);
611         delete this;
612     }
613 }
614 
GetRefCount()615 int32_t RenderDataStoreDefaultMaterial::GetRefCount()
616 {
617     return refcnt_;
618 }
619 
DestroyMaterialData(const uint64_t id)620 void RenderDataStoreDefaultMaterial::DestroyMaterialData(const uint64_t id)
621 {
622     // explicit material destruction
623     // NOTE: does not clear resource handle references for this frame
624 
625     CORE_ASSERT(matData_.allUniforms.size() == matData_.data.size());
626     if (auto iter = matData_.materialIdToIndex.find(id); iter != matData_.materialIdToIndex.cend()) {
627         CORE_ASSERT(iter->second < matData_.allUniforms.size());
628         DestroyMaterialByIndex(iter->second, matData_);
629 
630         // destroy from material map
631         matData_.materialIdToIndex.erase(iter);
632     }
633 }
634 
DestroyMaterialData(const BASE_NS::array_view<uint64_t> ids)635 void RenderDataStoreDefaultMaterial::DestroyMaterialData(const BASE_NS::array_view<uint64_t> ids)
636 {
637     for (const auto& idRef : ids) {
638         DestroyMaterialData(idRef);
639     }
640 }
641 
DestroyMeshData(const uint64_t id)642 void RenderDataStoreDefaultMaterial::DestroyMeshData(const uint64_t id)
643 {
644     if (auto iter = meshData_.meshIdToIndex.find(id); iter != meshData_.meshIdToIndex.cend()) {
645         CORE_ASSERT(iter->second < meshData_.data.size());
646         DestroyMeshByIndex(iter->second, meshData_);
647 
648         // destroy from mesh map
649         meshData_.meshIdToIndex.erase(iter);
650     }
651 }
652 
GetDefaultRenderSlots()653 void RenderDataStoreDefaultMaterial::GetDefaultRenderSlots()
654 {
655     materialRenderSlots_.defaultOpaqueRenderSlot =
656         shaderMgr_.GetRenderSlotId(DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE);
657     materialRenderSlots_.opaqueMask = (1ull << uint64_t(materialRenderSlots_.defaultOpaqueRenderSlot));
658     materialRenderSlots_.opaqueMask |=
659         (1ull << uint64_t(shaderMgr_.GetRenderSlotId(DefaultMaterialShaderConstants::RENDER_SLOT_DEFERRED_OPAQUE)));
660 
661     materialRenderSlots_.defaultTranslucentRenderSlot =
662         shaderMgr_.GetRenderSlotId(DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT);
663     materialRenderSlots_.translucentMask = (1ull << uint64_t(materialRenderSlots_.defaultTranslucentRenderSlot));
664 
665     materialRenderSlots_.defaultDepthRenderSlot =
666         shaderMgr_.GetRenderSlotId(DefaultMaterialShaderConstants::RENDER_SLOT_DEPTH);
667     materialRenderSlots_.depthMask = (1ull << uint64_t(materialRenderSlots_.defaultDepthRenderSlot));
668     materialRenderSlots_.depthMask |=
669         (1ull << uint64_t(shaderMgr_.GetRenderSlotId(DefaultMaterialShaderConstants::RENDER_SLOT_DEPTH_VSM)));
670 }
671 
AddMaterialDataImpl(const uint32_t matIndex,const RenderDataDefaultMaterial::InputMaterialUniforms & materialUniforms,const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference & materialHandles,const RenderDataDefaultMaterial::MaterialData & materialData,const array_view<const uint8_t> customData,const array_view<const RenderHandleReference> customResourceData)672 uint32_t RenderDataStoreDefaultMaterial::AddMaterialDataImpl(const uint32_t matIndex,
673     const RenderDataDefaultMaterial::InputMaterialUniforms& materialUniforms,
674     const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference& materialHandles,
675     const RenderDataDefaultMaterial::MaterialData& materialData, const array_view<const uint8_t> customData,
676     const array_view<const RenderHandleReference> customResourceData)
677 {
678     uint32_t materialIndex = matIndex;
679     // matData_.frameIndices can have higher counts)
680     CORE_ASSERT(matData_.allUniforms.size() == matData_.data.size());
681     CORE_ASSERT(matData_.handles.size() == matData_.customPropertyData.size());
682     CORE_ASSERT(matData_.renderSlotData.size() == matData_.customPropertyData.size());
683     if ((materialIndex == ~0U) && (matData_.availableIndices.empty())) {
684         // totally new indices and material
685         materialIndex = static_cast<uint32_t>(matData_.allUniforms.size());
686         matData_.handles.push_back(ConvertMaterialHandleReferences(materialHandles, handleReferences_));
687         matData_.allUniforms.push_back(MaterialUniformsPackedFromInput(materialUniforms));
688         matData_.customPropertyData.push_back({});
689         matData_.customResourceData.push_back({});
690         matData_.data.push_back({});
691         matData_.renderSlotData.push_back({});
692     } else {
693         if ((materialIndex == ~0U) && (!matData_.availableIndices.empty())) {
694             materialIndex = matData_.availableIndices.back();
695             matData_.availableIndices.pop_back();
696         }
697         if (materialIndex >= matData_.allUniforms.size()) {
698             CORE_ASSERT(true);
699             return ~0U;
700         }
701         matData_.handles[materialIndex] = ConvertMaterialHandleReferences(materialHandles, handleReferences_);
702         matData_.allUniforms[materialIndex] = MaterialUniformsPackedFromInput(materialUniforms);
703         matData_.customPropertyData[materialIndex].data.clear();
704         matData_.customResourceData[materialIndex] = {};
705     }
706 
707     // NOTE: when material is added/updated, we need to keep the handle reference
708     // the user might not have local references
709 
710     // not referenced yet this frame for rendering (false)
711     matData_.data[materialIndex].frameReferenced = false;
712     matData_.data[materialIndex].noId = false;
713     auto& currMaterialData = matData_.data[materialIndex].md;
714     currMaterialData = materialData;
715     auto& currRenderSlotData = matData_.renderSlotData[materialIndex];
716     ExtentRenderMaterialFlagsForComplexity(currMaterialData.materialType, currMaterialData.renderMaterialFlags);
717     FillMaterialDefaultRenderSlotData(shaderMgr_, materialRenderSlots_, currMaterialData, currRenderSlotData);
718 
719     if (!customData.empty()) {
720         const auto maxByteSize = Math::min(static_cast<uint32_t>(customData.size_bytes()),
721             RenderDataDefaultMaterial::MAX_MATERIAL_CUSTOM_PROPERTY_BYTE_SIZE);
722         auto& cpdRef = matData_.customPropertyData[materialIndex];
723         cpdRef.data.resize(maxByteSize);
724         CloneData(cpdRef.data.data(), maxByteSize, customData.data(), maxByteSize);
725     }
726 
727     if (!customResourceData.empty()) {
728         auto& dataRef = matData_.customResourceData[materialIndex];
729         dataRef.resourceHandleCount = 0U;
730         dataRef.shaderHandle = materialData.materialShader.shader.GetHandle();
731         const uint32_t maxCount = Math::min(static_cast<uint32_t>(customResourceData.size()),
732             RenderDataDefaultMaterial::MAX_MATERIAL_CUSTOM_RESOURCE_COUNT);
733         for (uint32_t idx = 0; idx < maxCount; ++idx) {
734             if (customResourceData[idx]) {
735                 // NOTE: when material is added/updated, we need to keep the handle reference
736                 // the user might not have local references
737                 handleReferences_.push_back(customResourceData[idx]);
738                 dataRef.resourceHandles[dataRef.resourceHandleCount++] = customResourceData[idx].GetHandle();
739             }
740         }
741     }
742 
743     return materialIndex;
744 }
745 
UpdateMaterialData(const uint64_t id,const RenderDataDefaultMaterial::InputMaterialUniforms & materialUniforms,const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference & materialHandles,const RenderDataDefaultMaterial::MaterialData & materialData,const array_view<const uint8_t> customData,const array_view<const RenderHandleReference> customBindings)746 uint32_t RenderDataStoreDefaultMaterial::UpdateMaterialData(const uint64_t id,
747     const RenderDataDefaultMaterial::InputMaterialUniforms& materialUniforms,
748     const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference& materialHandles,
749     const RenderDataDefaultMaterial::MaterialData& materialData, const array_view<const uint8_t> customData,
750     const array_view<const RenderHandleReference> customBindings)
751 {
752     CORE_STATIC_ASSERT(RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT == MaterialComponent::TEXTURE_COUNT);
753 
754     CORE_ASSERT(matData_.allUniforms.size() == matData_.data.size());
755     if (const auto iter = matData_.materialIdToIndex.find(id); iter != matData_.materialIdToIndex.cend()) {
756         CORE_ASSERT(iter->second < matData_.allUniforms.size());
757         const uint32_t materialIndex = AddMaterialDataImpl(
758             iter->second, materialUniforms, materialHandles, materialData, customData, customBindings);
759         CORE_UNUSED(materialIndex);
760         CORE_ASSERT(materialIndex == iter->second);
761         return iter->second;
762     } else {
763         // create new
764         const uint32_t materialIndex =
765             AddMaterialDataImpl(~0U, materialUniforms, materialHandles, materialData, customData, customBindings);
766         matData_.materialIdToIndex.insert_or_assign(id, materialIndex);
767         return materialIndex;
768     }
769 }
770 
UpdateMaterialData(const uint64_t id,const RenderDataDefaultMaterial::InputMaterialUniforms & materialUniforms,const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference & materialHandles,const RenderDataDefaultMaterial::MaterialData & materialData,const array_view<const uint8_t> customData)771 uint32_t RenderDataStoreDefaultMaterial::UpdateMaterialData(const uint64_t id,
772     const RenderDataDefaultMaterial::InputMaterialUniforms& materialUniforms,
773     const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference& materialHandles,
774     const RenderDataDefaultMaterial::MaterialData& materialData, const array_view<const uint8_t> customData)
775 {
776     return UpdateMaterialData(id, materialUniforms, materialHandles, materialData, customData, {});
777 }
778 
UpdateMaterialData(const uint64_t id,const RenderDataDefaultMaterial::InputMaterialUniforms & materialUniforms,const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference & materialHandles,const RenderDataDefaultMaterial::MaterialData & materialData)779 uint32_t RenderDataStoreDefaultMaterial::UpdateMaterialData(const uint64_t id,
780     const RenderDataDefaultMaterial::InputMaterialUniforms& materialUniforms,
781     const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference& materialHandles,
782     const RenderDataDefaultMaterial::MaterialData& materialData)
783 {
784     return UpdateMaterialData(id, materialUniforms, materialHandles, materialData, {}, {});
785 }
786 
AddFrameMaterialData(const uint64_t id,const uint32_t instanceCount)787 RenderFrameMaterialIndices RenderDataStoreDefaultMaterial::AddFrameMaterialData(
788     const uint64_t id, const uint32_t instanceCount)
789 {
790     // we expect the material to be in data
791 #if (CORE3D_VALIDATION_ENABLED == 1)
792     if (const auto iter = matData_.materialIdToIndex.find(id); iter == matData_.materialIdToIndex.cend()) {
793         const string name = string("AddFrameMaterialData" + BASE_NS::to_hex(id));
794         CORE_LOG_ONCE_W(name, "AddFrameMaterialData id not updated prior add");
795     }
796 #endif
797     // NOTE: we need to update the reference counts for rendering time
798     // material resource references are not kept alive when just updating the materials
799     // with this approach the resources can be destroyed during the application time
800 
801     const uint64_t searchId = HashMaterialId(id, static_cast<uint32_t>(instanceCount));
802     if (const auto iter = matData_.idHashToFrameIndex.find(searchId); iter != matData_.idHashToFrameIndex.cend()) {
803         if (iter->second < static_cast<uint32_t>(matData_.frameIndices.size())) {
804             // these have been already updated with reference counts, just return the indices
805             return { matData_.frameIndices[iter->second], iter->second };
806         }
807     } else if (const auto matIter = matData_.materialIdToIndex.find(id); matIter != matData_.materialIdToIndex.cend()) {
808         // append instance count amount
809         const uint32_t frameMaterialOffset = static_cast<uint32_t>(matData_.frameIndices.size());
810         matData_.idHashToFrameIndex.insert_or_assign(searchId, frameMaterialOffset);
811         RenderFrameMaterialIndices rfmi { matIter->second, frameMaterialOffset };
812         matData_.frameIndices.append(instanceCount, matIter->second); // add material index
813 
814         // update reference counts for this frame if needed
815         UpdateFrameMaterialResourceReferences(matIter->second);
816 
817         return rfmi;
818     }
819     return {};
820 }
821 
AddFrameMaterialData(const uint64_t id)822 RenderFrameMaterialIndices RenderDataStoreDefaultMaterial::AddFrameMaterialData(const uint64_t id)
823 {
824     return AddFrameMaterialData(id, 1U);
825 }
826 
AddFrameMaterialData(const BASE_NS::array_view<const uint64_t> ids)827 RenderFrameMaterialIndices RenderDataStoreDefaultMaterial::AddFrameMaterialData(
828     const BASE_NS::array_view<const uint64_t> ids)
829 {
830     if (!ids.empty()) {
831         RenderFrameMaterialIndices rfmi = AddFrameMaterialData(ids[0U], 1U);
832         for (size_t idx = 1; idx < ids.size(); ++idx) {
833             AddFrameMaterialData(ids[idx], 1U);
834         }
835         return rfmi;
836     } else {
837         return {};
838     }
839 }
840 
AddFrameMaterialData(const RenderDataDefaultMaterial::InputMaterialUniforms & materialUniforms,const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference & materialHandles,const RenderDataDefaultMaterial::MaterialData & materialData,const BASE_NS::array_view<const uint8_t> customPropertyData,const BASE_NS::array_view<const RENDER_NS::RenderHandleReference> customBindings)841 RenderFrameMaterialIndices RenderDataStoreDefaultMaterial::AddFrameMaterialData(
842     const RenderDataDefaultMaterial::InputMaterialUniforms& materialUniforms,
843     const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference& materialHandles,
844     const RenderDataDefaultMaterial::MaterialData& materialData,
845     const BASE_NS::array_view<const uint8_t> customPropertyData,
846     const BASE_NS::array_view<const RENDER_NS::RenderHandleReference> customBindings)
847 {
848     // NOTE: this data is added as is
849     // cannot be retrieved with id or anything
850     // mostly used for some debug meshes etc.
851     const uint32_t materialIndex =
852         AddMaterialDataImpl(~0U, materialUniforms, materialHandles, materialData, customPropertyData, customBindings);
853     // add for automatic destruction after rendering
854     if (materialIndex < matData_.data.size()) {
855         matData_.data[materialIndex].noId = true;
856     }
857 
858     const uint32_t materialOffset = static_cast<uint32_t>(matData_.frameIndices.size());
859     matData_.frameIndices.push_back(materialIndex); // material index
860     return { materialIndex, materialOffset };
861 }
862 
AddFrameMaterialInstanceData(uint32_t materialIndex,uint32_t frameOffset,uint32_t instanceIndex)863 RenderFrameMaterialIndices RenderDataStoreDefaultMaterial::AddFrameMaterialInstanceData(
864     uint32_t materialIndex, uint32_t frameOffset, uint32_t instanceIndex)
865 {
866     const uint32_t frameFullOffset = frameOffset + instanceIndex;
867     if (frameFullOffset < static_cast<uint32_t>(matData_.frameIndices.size())) {
868         matData_.frameIndices[frameFullOffset] = materialIndex;
869         return { materialIndex, frameFullOffset };
870     }
871     return {};
872 }
873 
UpdateFrameMaterialResourceReferences(const uint32_t materialIndex)874 void RenderDataStoreDefaultMaterial::UpdateFrameMaterialResourceReferences(const uint32_t materialIndex)
875 {
876     CORE_ASSERT(matData_.data.size() == matData_.handles.size());
877     CORE_ASSERT(matData_.data.size() == matData_.customResourceData.size());
878     if (materialIndex < static_cast<uint32_t>(matData_.handles.size())) {
879         auto& matDataRef = matData_.data[materialIndex];
880         if (!matDataRef.frameReferenced) {
881             // add references
882             matDataRef.frameReferenced = true;
883             const auto& handles = matData_.handles[materialIndex];
884             // NOTE: access to GPU resource manager is locking behaviour
885             // this can be evaluated further and possibly add array_view for get to get all with a one lock
886             for (uint32_t idx = 0; idx < RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT; ++idx) {
887                 if (RenderHandleUtil::IsValid(handles.images[idx])) {
888                     handleReferences_.push_back(gpuResourceMgr_.Get(handles.images[idx]));
889                 }
890                 if (RenderHandleUtil::IsValid(handles.samplers[idx])) {
891                     handleReferences_.push_back(gpuResourceMgr_.Get(handles.samplers[idx]));
892                 }
893             }
894             const auto& customHandles = matData_.customResourceData[materialIndex];
895             for (uint32_t idx = 0; idx < RenderDataDefaultMaterial::MAX_MATERIAL_CUSTOM_RESOURCE_COUNT; ++idx) {
896                 if (RenderHandleUtil::IsValid(customHandles.resourceHandles[idx])) {
897                     handleReferences_.push_back(gpuResourceMgr_.Get(customHandles.resourceHandles[idx]));
898                 }
899             }
900             // update render frame object info
901             renderFrameObjectInfo_.renderMaterialFlags |= matDataRef.md.renderMaterialFlags;
902         }
903     }
904 }
905 
AddMeshData(const RenderMeshData & meshData)906 uint32_t RenderDataStoreDefaultMaterial::AddMeshData(const RenderMeshData& meshData)
907 {
908     // DEPRECATED support
909     const uint32_t renderMeshIdx = static_cast<uint32_t>(meshData_.frameMeshData.size());
910     meshData_.frameMeshData.push_back(meshData);
911     return renderMeshIdx;
912 }
913 
AddFrameRenderMeshDataAdditionalMaterial(const uint64_t matId,const uint32_t submeshFrameIndex,RenderSubmesh & renderSubmesh)914 void RenderDataStoreDefaultMaterial::AddFrameRenderMeshDataAdditionalMaterial(
915     const uint64_t matId, const uint32_t submeshFrameIndex, RenderSubmesh& renderSubmesh)
916 {
917     RenderFrameMaterialIndices matIndices = GetCertainMaterialIndices(AddFrameMaterialData(matId, 1U), matData_);
918     renderSubmesh.indices.materialIndex = matIndices.index;
919     renderSubmesh.indices.materialFrameOffset = matIndices.frameOffset;
920     const auto& matData = matData_.data[matIndices.index].md;
921     PatchRenderMaterialSortLayers(matData, renderSubmesh.layers);
922 
923     const auto& matRenderSlotData = matData_.renderSlotData[matIndices.index];
924     FillSubmeshImpl({ matRenderSlotData.data, matRenderSlotData.count }, submeshFrameIndex, renderSubmesh);
925 }
926 
AddFrameRenderMeshDataImpl(const RenderMeshData & meshData,const RenderMeshAabbData & meshAabbData,const RenderMeshSkinData & meshSkinData,const RenderMeshBatchData & batchData,const uint32_t batchCount)927 void RenderDataStoreDefaultMaterial::AddFrameRenderMeshDataImpl(const RenderMeshData& meshData,
928     const RenderMeshAabbData& meshAabbData, const RenderMeshSkinData& meshSkinData,
929     const RenderMeshBatchData& batchData, const uint32_t batchCount)
930 {
931     // full render mesh process data
932     if (auto iter = meshData_.meshIdToIndex.find(meshData.meshId); iter != meshData_.meshIdToIndex.end()) {
933         CORE_ASSERT(iter->second < meshData_.data.size());
934         if (iter->second < meshData_.data.size()) {
935             auto& mesh = meshData_.data[iter->second];
936 
937             if constexpr (ENABLE_RT) {
938                 if (rtEnabled_) {
939                     // update for tlas update
940                     UpdateFrameMeshBlasInstanceData(mesh, meshData.world);
941                 }
942             }
943 
944             const bool frameReferenced = mesh.frameReferenced;
945             mesh.frameReferenced = true; // mark for referenced this frame
946 
947             const uint32_t skinJointIndex =
948                 AddFrameSkinJointMatricesImpl(meshSkinData.skinJointMatrices, meshSkinData.prevSkinJointMatrices);
949             const bool useJoints = (skinJointIndex != RenderSceneDataConstants::INVALID_INDEX);
950             const RenderSubmeshFlags rsAndFlags =
951                 useJoints ? 0xFFFFffff : (~RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT);
952             const RenderSubmeshFlags rsOrFlags = (Math::Determinant(meshData.world) < 0.0f)
953                                                      ? RenderSubmeshFlagBits::RENDER_SUBMESH_INVERSE_WINDING_BIT
954                                                      : 0U;
955 
956             // NOTE: When object is skinned we use the mesh bounding box for all the submeshes because currently
957             // there is no way to know here which joints affect one specific renderSubmesh.
958 
959             const uint32_t renderMeshIdx = static_cast<uint32_t>(meshData_.frameMeshData.size());
960             meshData_.frameMeshData.push_back(meshData);
961             // process submeshes for rendering
962             for (uint32_t submeshIdx = 0; submeshIdx < mesh.submeshes.size(); ++submeshIdx) {
963                 CORE_ASSERT(meshData_.frameSubmeshes.size() == meshData_.frameSubmeshMaterialFlags.size());
964 
965                 const uint32_t submeshFrameIndex = static_cast<uint32_t>(meshData_.frameSubmeshes.size());
966                 meshData_.frameSubmeshes.push_back({});
967                 auto& rs = meshData_.frameSubmeshes.back();
968 
969                 auto& submesh = mesh.submeshes[submeshIdx];
970                 submesh.frameReferenced = frameReferenced; // process if needed
971                 UpdateFrameMeshResourceReferences(submesh);
972 
973                 rs.bounds = GetSubmeshBounds(meshAabbData, meshSkinData, batchData, submeshIdx, useJoints, batchCount);
974                 rs.buffers = submesh.sd.buffers;
975                 rs.drawCommand = submesh.sd.drawCommand;
976                 rs.submeshFlags = (submesh.sd.submeshFlags & rsAndFlags) | rsOrFlags;
977 
978                 rs.layers.layerMask = meshData.layerMask;
979                 rs.layers.sceneId = static_cast<uint32_t>(meshData.sceneId); // ID is originally 32 bit.
980                 rs.layers.meshRenderSortLayer = submesh.sd.meshRenderSortLayer;
981                 rs.layers.meshRenderSortLayerOrder = submesh.sd.meshRenderSortLayerOrder;
982 
983                 const uint32_t matInstanceCount = (batchCount > 0) ? rs.drawCommand.instanceCount : 1U;
984                 RenderFrameMaterialIndices matIndices =
985                     GetCertainMaterialIndices(AddFrameMaterialData(submesh.sd.material, matInstanceCount), matData_);
986                 rs.indices = { meshData.id, mesh.md.meshId, submeshFrameIndex, renderMeshIdx, skinJointIndex,
987                     matIndices.index, matIndices.frameOffset };
988 
989                 rs.renderSubmeshMaterialFlags = (submesh.sd.renderSubmeshMaterialFlags | batchData.materialFlags);
990                 const auto& matData = matData_.data[matIndices.index].md;
991                 PatchRenderMaterialSortLayers(matData, rs.layers);
992 
993                 const auto& matRenderSlotData = matData_.renderSlotData[matIndices.index];
994                 FillSubmeshImpl({ matRenderSlotData.data, matRenderSlotData.count }, submeshFrameIndex, rs);
995 
996                 // add additional materials
997                 for (uint32_t mIdx = submesh.sd.additionalMaterialOffset; mIdx < submesh.sd.additionalMaterialCount;
998                      ++mIdx) {
999                     if (mIdx < mesh.submeshAdditionalMaterials.size()) {
1000                         const uint32_t addSubmeshFrameIndex = static_cast<uint32_t>(meshData_.frameSubmeshes.size());
1001                         meshData_.frameSubmeshes.push_back(rs); // start with the current setup
1002                         auto& addRs = meshData_.frameSubmeshes.back();
1003                         AddFrameRenderMeshDataAdditionalMaterial(
1004                             mesh.submeshAdditionalMaterials[mIdx], addSubmeshFrameIndex, addRs);
1005                     }
1006                 }
1007             }
1008         }
1009     }
1010 #if (CORE3D_VALIDATION_ENABLED == 1)
1011     if (!meshData_.meshIdToIndex.contains(meshData.meshId)) {
1012         const string str = string("AddFrameRenderMeshDataImpl_") + to_string(meshData.meshId);
1013         CORE_LOG_ONCE_W(str, "CORE3D_VALIDATION: Mesh id not found for render mesh");
1014     }
1015 #endif
1016 }
1017 
AddFrameRenderMeshData(const array_view<const RenderMeshData> meshData,const RenderMeshAabbData & meshAabbData,const RenderMeshSkinData & meshSkinData,const RenderMeshBatchData & batchData)1018 void RenderDataStoreDefaultMaterial::AddFrameRenderMeshData(const array_view<const RenderMeshData> meshData,
1019     const RenderMeshAabbData& meshAabbData, const RenderMeshSkinData& meshSkinData,
1020     const RenderMeshBatchData& batchData)
1021 {
1022     bool initialProcess = true;
1023     uint32_t batchIndex = 0;
1024     const uint32_t batchCount = (static_cast<uint32_t>(meshData.size()) - 1);
1025     for (const auto& meshDataRef : meshData) {
1026         if (auto iter = meshData_.meshIdToIndex.find(meshDataRef.meshId); iter != meshData_.meshIdToIndex.end()) {
1027             CORE_ASSERT(iter->second < meshData_.data.size());
1028             if (iter->second < meshData_.data.size()) {
1029                 auto& mesh = meshData_.data[iter->second];
1030 
1031                 if constexpr (ENABLE_RT) {
1032                     if (rtEnabled_) {
1033                         // update for tlas update
1034                         UpdateFrameMeshBlasInstanceData(mesh, meshDataRef.world);
1035                     }
1036                 }
1037                 const bool frameReferenced = mesh.frameReferenced;
1038                 mesh.frameReferenced = true; // mark for referenced this frame
1039                 uint32_t skinJointIndex = ~0U;
1040                 RenderSubmeshFlags rsAndFlags = 0U;
1041                 RenderSubmeshFlags rsOrFlags = 0U;
1042                 bool useJoints = false;
1043                 if (initialProcess) {
1044                     materialFrameOffsets_.clear();
1045                     materialFrameOffsets_.reserve(mesh.submeshes.size());
1046                     skinJointIndex = AddFrameSkinJointMatricesImpl(
1047                         meshSkinData.skinJointMatrices, meshSkinData.prevSkinJointMatrices);
1048                     useJoints = (skinJointIndex != RenderSceneDataConstants::INVALID_INDEX);
1049                     rsAndFlags = useJoints ? 0xFFFFffff : (~RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT);
1050                     rsOrFlags = (Math::Determinant(meshDataRef.world) < 0.0f)
1051                                     ? RenderSubmeshFlagBits::RENDER_SUBMESH_INVERSE_WINDING_BIT
1052                                     : 0U;
1053                 }
1054                 // NOTE: When object is skinned we use the mesh bounding box for all the submeshes because currently
1055                 // there is no way to know here which joints affect one specific renderSubmesh.
1056 
1057                 const uint32_t renderMeshIdx = static_cast<uint32_t>(meshData_.frameMeshData.size());
1058                 meshData_.frameMeshData.push_back(meshDataRef);
1059                 for (uint32_t submeshIdx = 0; submeshIdx < mesh.submeshes.size(); ++submeshIdx) {
1060                     CORE_ASSERT(meshData_.frameSubmeshes.size() == meshData_.frameSubmeshMaterialFlags.size());
1061                     auto& submesh = mesh.submeshes[submeshIdx];
1062                     submesh.frameReferenced = frameReferenced; // process if needed
1063                     UpdateFrameMeshResourceReferences(submesh);
1064 
1065                     if (initialProcess) {
1066                         const uint32_t submeshFrameIndex = static_cast<uint32_t>(meshData_.frameSubmeshes.size());
1067                         meshData_.frameSubmeshes.push_back({});
1068                         auto& rs = meshData_.frameSubmeshes.back();
1069 
1070                         rs.bounds =
1071                             GetSubmeshBounds(meshAabbData, meshSkinData, batchData, submeshIdx, useJoints, batchCount);
1072                         rs.buffers = submesh.sd.buffers;
1073                         rs.drawCommand = submesh.sd.drawCommand;
1074                         // additional batch instance counts
1075                         rs.drawCommand.instanceCount += batchCount;
1076                         rs.submeshFlags = (submesh.sd.submeshFlags & rsAndFlags) | rsOrFlags;
1077                         rs.renderSubmeshMaterialFlags =
1078                             (submesh.sd.renderSubmeshMaterialFlags | batchData.materialFlags);
1079 
1080                         rs.layers.layerMask = meshDataRef.layerMask;
1081                         rs.layers.sceneId = static_cast<uint32_t>(meshDataRef.sceneId); // ID is originally 32 bit.
1082                         rs.layers.meshRenderSortLayer = submesh.sd.meshRenderSortLayer;
1083                         rs.layers.meshRenderSortLayerOrder = submesh.sd.meshRenderSortLayerOrder;
1084 
1085                         const uint32_t matInstanceCount = (batchCount > 0) ? rs.drawCommand.instanceCount : 1U;
1086                         RenderFrameMaterialIndices matIndices = GetCertainMaterialIndices(
1087                             AddFrameMaterialData(submesh.sd.material, matInstanceCount), matData_);
1088                         // add for the batch materials
1089                         materialFrameOffsets_.push_back(matIndices.frameOffset);
1090                         rs.indices = { meshDataRef.id, mesh.md.meshId, submeshFrameIndex, renderMeshIdx, skinJointIndex,
1091                             matIndices.index, matIndices.frameOffset };
1092 
1093                         const auto& matData = matData_.data[matIndices.index].md;
1094                         PatchRenderMaterialSortLayers(matData, rs.layers);
1095 
1096                         const auto& matRenderSlotData = matData_.renderSlotData[matIndices.index];
1097                         FillSubmeshImpl({ matRenderSlotData.data, matRenderSlotData.count }, submeshFrameIndex, rs);
1098 
1099                         // add additional materials
1100                         for (uint32_t mIdx = submesh.sd.additionalMaterialOffset;
1101                              mIdx < submesh.sd.additionalMaterialCount; ++mIdx) {
1102                             if (mIdx < mesh.submeshAdditionalMaterials.size()) {
1103                                 const uint32_t addSubmeshFrameIndex =
1104                                     static_cast<uint32_t>(meshData_.frameSubmeshes.size());
1105                                 meshData_.frameSubmeshes.push_back(rs); // start with the current setup
1106                                 auto& addRs = meshData_.frameSubmeshes.back();
1107                                 AddFrameRenderMeshDataAdditionalMaterial(
1108                                     mesh.submeshAdditionalMaterials[mIdx], addSubmeshFrameIndex, addRs);
1109                             }
1110                         }
1111                     } else {
1112                         // material offset for submesh
1113                         const uint32_t baseFrameOffset =
1114                             (submeshIdx < static_cast<uint32_t>(materialFrameOffsets_.size()))
1115                                 ? materialFrameOffsets_[submeshIdx]
1116                                 : 0U;
1117                         const uint32_t matIndex = GetMaterialIndex(submesh.sd.material);
1118                         AddFrameMaterialInstanceData(matIndex, baseFrameOffset, batchIndex);
1119                     }
1120                 }
1121             }
1122         }
1123         // next batch index for submesh for offsets etc.
1124         batchIndex++;
1125         initialProcess = false;
1126     }
1127 }
1128 
AddFrameRenderMeshData(const RenderMeshData & meshData,const RenderMeshAabbData & meshAabbData,const RenderMeshSkinData & meshSkinData)1129 void RenderDataStoreDefaultMaterial::AddFrameRenderMeshData(
1130     const RenderMeshData& meshData, const RenderMeshAabbData& meshAabbData, const RenderMeshSkinData& meshSkinData)
1131 {
1132     AddFrameRenderMeshDataImpl(meshData, meshAabbData, meshSkinData, DEFAULT_RENDER_MESH_BATCH_DATA, 0U);
1133 }
1134 
UpdateFrameMeshResourceReferences(SubmeshDataContainer & submeshDataRef)1135 void RenderDataStoreDefaultMaterial::UpdateFrameMeshResourceReferences(SubmeshDataContainer& submeshDataRef)
1136 {
1137     if (!submeshDataRef.frameReferenced) {
1138         // add references
1139         submeshDataRef.frameReferenced = true;
1140         // NOTE: access to GPU resource manager is locking behaviour
1141         // this can be evaluated further and possibly add array_view for get to get all with a one lock
1142         auto AddValidReference = [&](const RenderHandle& handle) {
1143             if (RenderHandleUtil::IsValid(handle)) {
1144                 handleReferences_.push_back(gpuResourceMgr_.Get(handle));
1145             }
1146         };
1147         AddValidReference(submeshDataRef.sd.buffers.indexBuffer.bufferHandle);
1148         AddValidReference(submeshDataRef.sd.buffers.indirectArgsBuffer.bufferHandle);
1149         const uint32_t vertexBufferCount = Math::min(
1150             submeshDataRef.sd.buffers.vertexBufferCount, RENDER_NS::PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT);
1151         for (uint32_t idx = 0; idx < vertexBufferCount; ++idx) {
1152             AddValidReference(submeshDataRef.sd.buffers.vertexBuffers[idx].bufferHandle);
1153         }
1154     }
1155 }
1156 
UpdateMeshData(const uint64_t id,const MeshDataWithHandleReference & meshData)1157 void RenderDataStoreDefaultMaterial::UpdateMeshData(const uint64_t id, const MeshDataWithHandleReference& meshData)
1158 {
1159     auto& md = meshData_;
1160     uint32_t index = ~0U;
1161 
1162     if (const auto iter = md.meshIdToIndex.find(id); iter != md.meshIdToIndex.cend()) {
1163         CORE_ASSERT(iter->second < md.data.size());
1164         index = iter->second;
1165     } else {
1166         // create new
1167         if (md.availableIndices.empty()) {
1168             index = static_cast<uint32_t>(md.data.size());
1169             md.data.push_back({});
1170         } else {
1171             // use available index
1172             index = md.availableIndices.back();
1173             md.availableIndices.pop_back();
1174         }
1175     }
1176 
1177     if (index < md.data.size()) {
1178         md.meshIdToIndex.insert_or_assign(id, index);
1179 
1180         auto& data = md.data[index];
1181         // clear
1182         const size_t baseAdditionalMaterialCount = data.submeshAdditionalMaterials.size();
1183         data.submeshAdditionalMaterials.clear();
1184         data.submeshes.clear();
1185 
1186         data.frameReferenced = true; // submeshes referenced for this frame below
1187 
1188         data.md.meshId = meshData.meshId;
1189         // NOTE: no aabb data
1190         data.submeshes.resize(meshData.submeshes.size());
1191         data.submeshAdditionalMaterials.reserve(baseAdditionalMaterialCount);
1192         for (size_t smIdx = 0; smIdx < data.submeshes.size(); ++smIdx) {
1193             const auto& readRef = meshData.submeshes[smIdx];
1194             auto& writeRef = data.submeshes[smIdx];
1195             // NOTE: no AABB
1196             writeRef.sd.submeshFlags = readRef.submeshFlags;
1197             writeRef.sd.renderSubmeshMaterialFlags = 0U;
1198             writeRef.sd.drawCommand = readRef.drawCommand;
1199 
1200             // adds references for this frame
1201             writeRef.sd.buffers = ConvertRenderSubmeshBuffers(readRef.buffers, handleReferences_);
1202             writeRef.frameReferenced = true;
1203 
1204             writeRef.sd.material = readRef.materialId;
1205             writeRef.sd.meshRenderSortLayer = readRef.meshRenderSortLayer;
1206             writeRef.sd.meshRenderSortLayerOrder = readRef.meshRenderSortLayerOrder;
1207 
1208             if (!readRef.additionalMaterials.empty()) {
1209                 writeRef.sd.additionalMaterialOffset = static_cast<uint32_t>(data.submeshAdditionalMaterials.size());
1210                 data.submeshAdditionalMaterials.resize(
1211                     data.submeshAdditionalMaterials.size() + readRef.additionalMaterials.size());
1212                 writeRef.sd.additionalMaterialCount = static_cast<uint32_t>(data.submeshAdditionalMaterials.size()) -
1213                                                       writeRef.sd.additionalMaterialOffset;
1214             }
1215         }
1216 
1217         if constexpr (ENABLE_RT) {
1218             if (rtEnabled_) {
1219                 UpdateMeshBlasData(data);
1220             }
1221         }
1222     }
1223 }
1224 
UpdateMeshBlasData(MeshDataContainer & meshData)1225 void RenderDataStoreDefaultMaterial::UpdateMeshBlasData(MeshDataContainer& meshData)
1226 {
1227     CORE_ASSERT(rtEnabled_);
1228     if (!dsAcceleration_) {
1229         dsAcceleration_ = refcnt_ptr<IRenderDataStoreDefaultAccelerationStructureStaging>(
1230             renderContext_.GetRenderDataStoreManager().GetRenderDataStore(DS_ACCELERATION_STRUCTURE));
1231     }
1232     if (dsAcceleration_) {
1233         // create blas and instance reference
1234         vector<AsGeometryTrianglesDataWithHandleReference> trianglesData;
1235         vector<AsGeometryTrianglesInfo> trianglesInfo;
1236         trianglesData.reserve(meshData.submeshes.size());
1237         trianglesInfo.reserve(meshData.submeshes.size());
1238         for (const auto& submesh : meshData.submeshes) {
1239             AsGeometryTrianglesDataWithHandleReference data;
1240             data.info.geometryFlags = GeometryFlagBits::GEOMETRY_OPAQUE_BIT;
1241             data.info.vertexFormat = BASE_NS::Format::BASE_FORMAT_R32G32B32_SFLOAT;
1242             data.info.vertexStride = sizeof(float) * 3U; // NOTE: hard coded
1243             data.info.indexType = submesh.sd.buffers.indexBuffer.indexType;
1244             data.info.maxVertex = submesh.sd.buffers.vertexBuffers[0].byteSize / data.info.vertexStride;
1245             data.info.indexCount =
1246                 submesh.sd.buffers.indexBuffer.byteSize /
1247                 ((data.info.indexType == IndexType::CORE_INDEX_TYPE_UINT32) ? sizeof(uint32_t) : sizeof(uint16_t));
1248             data.vertexData = { gpuResourceMgr_.Get(submesh.sd.buffers.vertexBuffers[0].bufferHandle),
1249                 submesh.sd.buffers.vertexBuffers[0].bufferOffset };
1250             data.indexData = { gpuResourceMgr_.Get(submesh.sd.buffers.indexBuffer.bufferHandle),
1251                 submesh.sd.buffers.indexBuffer.bufferOffset };
1252             trianglesData.push_back(data);
1253             trianglesInfo.push_back(data.info);
1254         }
1255         // create buffer for bottom level structures
1256         {
1257             AsBuildGeometryInfo geometryInfo;
1258             geometryInfo.type = AccelerationStructureType::CORE_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;
1259             geometryInfo.flags =
1260                 BuildAccelerationStructureFlagBits::CORE_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT;
1261             AsBuildSizes asbs =
1262                 renderContext_.GetDevice().GetAccelerationStructureBuildSizes(geometryInfo, trianglesInfo, {}, {});
1263             if (asbs.accelerationStructureSize) {
1264                 const GpuAccelerationStructureDesc desc {
1265                     AccelerationStructureType::CORE_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL,
1266                     GpuBufferDesc {
1267                         CORE_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT,
1268                         CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1269                         CORE_ENGINE_BUFFER_CREATION_DYNAMIC_BARRIERS,
1270                         asbs.accelerationStructureSize,
1271                     }
1272                 };
1273                 meshData.blas.blas = gpuResourceMgr_.Create(desc);
1274             }
1275         }
1276         // send for build to bottom level acceleration structure staging
1277         {
1278             AsBuildGeometryDataWithHandleReference geometryData;
1279             geometryData.info.type = AccelerationStructureType::CORE_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;
1280             geometryData.dstAccelerationStructure = meshData.blas.blas;
1281             dsAcceleration_->BuildAccelerationStructure(geometryData, trianglesData);
1282         }
1283         // instance reference which will be pushes to TLAS later
1284         meshData.blas.instance = { Math::IDENTITY_4X3, 0U, 0xFF, 0U,
1285             GeometryInstanceFlagBits::CORE_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT |
1286                 GeometryInstanceFlagBits::CORE_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT,
1287             meshData.blas.blas };
1288     }
1289 }
1290 
UpdateFrameMeshBlasInstanceData(const MeshDataContainer & meshData,const Math::Mat4X4 & transform)1291 void RenderDataStoreDefaultMaterial::UpdateFrameMeshBlasInstanceData(
1292     const MeshDataContainer& meshData, const Math::Mat4X4& transform)
1293 {
1294     CORE_ASSERT(rtEnabled_);
1295     const auto& instRef = meshData.blas.instance;
1296 
1297     AsInstance asInstance {};
1298     asInstance.transform.x = transform.x;
1299     asInstance.transform.y = transform.y;
1300     asInstance.transform.z = transform.z;
1301     asInstance.transform.w = transform.w;
1302     asInstance.accelerationStructure = instRef.accelerationStructure.GetHandle();
1303     asInstance.flags = instRef.flags;
1304     asInstance.instanceCustomIndex = instRef.instanceCustomIndex;
1305     asInstance.mask = instRef.mask;
1306     asInstance.shaderBindingTableOffset = instRef.shaderBindingTableOffset;
1307     meshData_.frameMeshBlasInstanceData.push_back(asInstance);
1308 }
1309 
AddFrameSkinJointMatricesImpl(const array_view<const Math::Mat4X4> skinJointMatrices,const array_view<const Math::Mat4X4> prevSkinJointMatrices)1310 uint32_t RenderDataStoreDefaultMaterial::AddFrameSkinJointMatricesImpl(
1311     const array_view<const Math::Mat4X4> skinJointMatrices, const array_view<const Math::Mat4X4> prevSkinJointMatrices)
1312 {
1313     // check max supported joint count
1314     const uint32_t jointCount =
1315         std::min(RenderDataDefaultMaterial::MAX_SKIN_MATRIX_COUNT, static_cast<uint32_t>(skinJointMatrices.size()));
1316     uint32_t skinJointIndex = RenderSceneDataConstants::INVALID_INDEX;
1317     if (jointCount > 0) {
1318         const uint32_t byteSize = sizeof(Math::Mat4X4) * jointCount;
1319         const uint32_t fullJointCount = jointCount * 2u;
1320         Math::Mat4X4* jointMatrixData = AllocateMatrices(meshJointMatricesAllocator_, fullJointCount);
1321         if (jointMatrixData) {
1322             CloneData(jointMatrixData, byteSize, skinJointMatrices.data(), byteSize);
1323             if (skinJointMatrices.size() == prevSkinJointMatrices.size()) {
1324                 CloneData(jointMatrixData + jointCount, byteSize, prevSkinJointMatrices.data(), byteSize);
1325             } else {
1326                 // copy current to previous if given prevSkinJointMatrices is not valid
1327                 CloneData(jointMatrixData + jointCount, byteSize, skinJointMatrices.data(), byteSize);
1328             }
1329         }
1330         skinJointIndex = static_cast<uint32_t>(meshData_.frameJointMatrixIndices.size());
1331         meshData_.frameJointMatrixIndices.push_back(
1332             RenderDataDefaultMaterial::JointMatrixData { jointMatrixData, fullJointCount });
1333     }
1334     return skinJointIndex;
1335 }
1336 
AddSubmesh(const RenderSubmeshWithHandleReference & submesh)1337 void RenderDataStoreDefaultMaterial::AddSubmesh(const RenderSubmeshWithHandleReference& submesh)
1338 {
1339     const uint32_t materialIndex = GetCertainMaterialIndex(submesh.indices.materialIndex, matData_);
1340     if (materialIndex < static_cast<uint32_t>(matData_.data.size())) {
1341         CORE_ASSERT(matData_.data.size() == matData_.renderSlotData.size());
1342         const auto& rsData = matData_.renderSlotData[materialIndex];
1343         AddSubmesh(submesh, { rsData.data, rsData.count });
1344     }
1345 }
1346 
AddSubmesh(const RenderSubmeshWithHandleReference & submesh,const array_view<const IShaderManager::RenderSlotData> renderSlotAndShaders)1347 void RenderDataStoreDefaultMaterial::AddSubmesh(const RenderSubmeshWithHandleReference& submesh,
1348     const array_view<const IShaderManager::RenderSlotData> renderSlotAndShaders)
1349 {
1350     // DEPRECATED support
1351 #if (CORE3D_VALIDATION_ENABLED == 1)
1352     ValidateSubmesh(submesh);
1353 #endif
1354     const uint32_t submeshIndex = static_cast<uint32_t>(meshData_.frameSubmeshes.size());
1355     meshData_.frameSubmeshes.push_back(ConvertRenderSubmeshInput(submesh, handleReferences_));
1356     auto& currSubmesh = meshData_.frameSubmeshes.back();
1357 
1358     FillSubmeshImpl(renderSlotAndShaders, submeshIndex, currSubmesh);
1359 }
1360 
FillSubmeshImpl(const array_view<const IShaderManager::RenderSlotData> renderSlotAndShaders,const uint32_t submeshIndex,RenderSubmesh & submesh)1361 void RenderDataStoreDefaultMaterial::FillSubmeshImpl(
1362     const array_view<const IShaderManager::RenderSlotData> renderSlotAndShaders, const uint32_t submeshIndex,
1363     RenderSubmesh& submesh)
1364 {
1365     const uint32_t materialIndex = GetCertainMaterialIndex(submesh.indices.materialIndex, matData_);
1366     submesh.indices.materialIndex = materialIndex; // if invalid -> store the default material
1367     if (submesh.indices.meshIndex >= static_cast<uint32_t>(meshData_.frameMeshData.size())) {
1368         CORE_LOG_W("invalid mesh index (%u) given", submesh.indices.meshIndex);
1369         submesh.indices.meshIndex = 0;
1370     }
1371     if ((submesh.submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT) &&
1372         (submesh.indices.skinJointIndex >= static_cast<uint32_t>(meshData_.frameJointMatrixIndices.size()))) {
1373         CORE_LOG_W("invalid skin joint index (%u) given", submesh.indices.skinJointIndex);
1374         submesh.indices.skinJointIndex = RenderSceneDataConstants::INVALID_INDEX;
1375     }
1376 
1377     if (submesh.indices.materialIndex >= static_cast<uint32_t>(matData_.allUniforms.size())) {
1378         // NOTE: shouldn't come here with basic usage
1379         RenderFrameMaterialIndices rfmi = AddFrameMaterialData({}, {}, {}, {}, {});
1380         submesh.indices.materialIndex = rfmi.index;
1381         submesh.indices.materialFrameOffset = rfmi.frameOffset;
1382     } else {
1383         CORE_ASSERT(matData_.data.size() == matData_.allUniforms.size());
1384     }
1385     const RenderDataDefaultMaterial::MaterialData& perMatData = matData_.data[submesh.indices.materialIndex].md;
1386     // batch render material sort layers if default values
1387     PatchRenderMaterialSortLayers(perMatData, submesh.layers);
1388 
1389     // combine with submesh specific flags
1390     RenderMaterialFlags submeshRenderMaterialFlags =
1391         perMatData.renderMaterialFlags | submesh.renderSubmeshMaterialFlags;
1392     // remove instancing related things if not available
1393     if (submesh.drawCommand.instanceCount > 1U) {
1394         submeshRenderMaterialFlags |= RenderMaterialFlagBits::RENDER_MATERIAL_GPU_INSTANCING_BIT;
1395     } else {
1396         submeshRenderMaterialFlags &= COMBINED_GPU_INSTANCING_REMOVAL;
1397     }
1398     ExtentRenderMaterialFlagsFromSubmeshValues(submesh.submeshFlags, submeshRenderMaterialFlags);
1399 
1400     const uint32_t renderHash =
1401         HashSubmeshMaterials(perMatData.materialType, submeshRenderMaterialFlags, submesh.submeshFlags);
1402     // depth optimized flags
1403     const uint32_t renderDepthHash = HashSubmeshMaterials(perMatData.materialType,
1404         submeshRenderMaterialFlags & RenderDataDefaultMaterial::RENDER_MATERIAL_DEPTH_FLAGS,
1405         submesh.submeshFlags & RenderDataDefaultMaterial::RENDER_SUBMESH_DEPTH_FLAGS);
1406     meshData_.frameSubmeshMaterialFlags.push_back(
1407         RenderDataDefaultMaterial::SubmeshMaterialFlags { perMatData.materialType, submesh.submeshFlags,
1408             perMatData.extraMaterialRenderingFlags, submeshRenderMaterialFlags, renderHash, renderDepthHash });
1409 
1410     const uint16_t renderSortLayerHash = GetRenderSortLayerHash(submesh);
1411     // add submeshs to slots
1412     for (const auto& slotRef : renderSlotAndShaders) {
1413         SlotSubmeshData& dataRef = slotToSubmeshIndices_[slotRef.renderSlotId];
1414         dataRef.indices.push_back(submeshIndex);
1415         // hash for sorting (material index is certain for the same material)
1416         // shader and gfx state is not needed, because it's already in the material, or they are defaults
1417         // inverse winding can affect the final graphics state but it's in renderHash
1418         // we hash with material index, and render hash
1419         // id generation does not matter to us, because this is per frame
1420         uint32_t renderSortHash = submesh.indices.materialIndex;
1421         HashCombine32Bit(renderSortHash, renderHash);
1422         // custom camera id for camera material effect
1423         const uint32_t cameraId = perMatData.customCameraId;
1424         dataRef.materialData.push_back({ slotRef.shader.GetHandle(), slotRef.graphicsState.GetHandle(),
1425             submeshRenderMaterialFlags, cameraId, renderSortHash, renderSortLayerHash });
1426 
1427         dataRef.objectCounts.submeshCount++;
1428         if (submesh.indices.skinJointIndex != RenderSceneDataConstants::INVALID_INDEX) {
1429             dataRef.objectCounts.skinCount++;
1430         }
1431     }
1432 }
1433 
SetRenderSlots(const RenderDataDefaultMaterial::MaterialSlotType materialSlotType,const BASE_NS::array_view<const uint32_t> renderSlotIds)1434 void RenderDataStoreDefaultMaterial::SetRenderSlots(const RenderDataDefaultMaterial::MaterialSlotType materialSlotType,
1435     const BASE_NS::array_view<const uint32_t> renderSlotIds)
1436 {
1437     uint64_t mask = 0;
1438     for (const auto renderSlotId : renderSlotIds) {
1439         mask |= 1ULL << uint64_t(renderSlotId);
1440     }
1441     if (materialSlotType == RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_OPAQUE) {
1442         materialRenderSlots_.opaqueMask = mask;
1443     } else if (materialSlotType == RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_TRANSLUCENT) {
1444         materialRenderSlots_.translucentMask = mask;
1445     } else if (materialSlotType == RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_DEPTH) {
1446         materialRenderSlots_.depthMask = mask;
1447     }
1448 }
1449 
GetRenderSlotMask(const RenderDataDefaultMaterial::MaterialSlotType materialSlotType) const1450 uint64_t RenderDataStoreDefaultMaterial::GetRenderSlotMask(
1451     const RenderDataDefaultMaterial::MaterialSlotType materialSlotType) const
1452 {
1453     uint64_t mask = 0;
1454     if (materialSlotType == RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_OPAQUE) {
1455         mask = materialRenderSlots_.opaqueMask;
1456     } else if (materialSlotType == RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_TRANSLUCENT) {
1457         mask = materialRenderSlots_.translucentMask;
1458     } else if (materialSlotType == RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_DEPTH) {
1459         mask = materialRenderSlots_.depthMask;
1460     }
1461     return mask;
1462 }
1463 
GetRenderSlotIdFromMasks(const uint32_t renderSlotId) const1464 uint32_t RenderDataStoreDefaultMaterial::GetRenderSlotIdFromMasks(const uint32_t renderSlotId) const
1465 {
1466     // compare to masks
1467     const uint64_t renderSlotMask = 1ULL << uint64_t(renderSlotId & 0x3F); // 63
1468     uint32_t newRenderSlotId = renderSlotId;
1469     if (renderSlotMask & materialRenderSlots_.opaqueMask) {
1470         newRenderSlotId = materialRenderSlots_.defaultOpaqueRenderSlot;
1471     } else if (renderSlotMask & materialRenderSlots_.translucentMask) {
1472         newRenderSlotId = materialRenderSlots_.defaultTranslucentRenderSlot;
1473     } else if (renderSlotMask & materialRenderSlots_.depthMask) {
1474         newRenderSlotId = materialRenderSlots_.defaultDepthRenderSlot;
1475     }
1476     return newRenderSlotId;
1477 }
1478 
GetSlotSubmeshIndices(const uint32_t renderSlotId) const1479 array_view<const uint32_t> RenderDataStoreDefaultMaterial::GetSlotSubmeshIndices(const uint32_t renderSlotId) const
1480 {
1481     const uint32_t rsId = GetRenderSlotIdFromMasks(renderSlotId);
1482     if (const auto iter = slotToSubmeshIndices_.find(rsId); iter != slotToSubmeshIndices_.cend()) {
1483         const auto& slotRef = iter->second;
1484         return slotRef.indices;
1485     } else {
1486         return {};
1487     }
1488 }
1489 
1490 array_view<const RenderDataDefaultMaterial::SlotMaterialData>
GetSlotSubmeshMaterialData(const uint32_t renderSlotId) const1491 RenderDataStoreDefaultMaterial::GetSlotSubmeshMaterialData(const uint32_t renderSlotId) const
1492 {
1493     const uint32_t rsId = GetRenderSlotIdFromMasks(renderSlotId);
1494     if (const auto iter = slotToSubmeshIndices_.find(rsId); iter != slotToSubmeshIndices_.cend()) {
1495         const auto& slotRef = iter->second;
1496         return slotRef.materialData;
1497     } else {
1498         return {};
1499     }
1500 }
1501 
GetSlotObjectCounts(const uint32_t renderSlotId) const1502 RenderDataDefaultMaterial::ObjectCounts RenderDataStoreDefaultMaterial::GetSlotObjectCounts(
1503     const uint32_t renderSlotId) const
1504 {
1505     const uint32_t rsId = GetRenderSlotIdFromMasks(renderSlotId);
1506     if (const auto iter = slotToSubmeshIndices_.find(rsId); iter != slotToSubmeshIndices_.cend()) {
1507         return RenderDataDefaultMaterial::ObjectCounts {
1508             static_cast<uint32_t>(meshData_.frameMeshData.size()),
1509             iter->second.objectCounts.submeshCount,
1510             iter->second.objectCounts.skinCount,
1511             static_cast<uint32_t>(matData_.frameIndices.size()),
1512             static_cast<uint32_t>(matData_.allUniforms.size()),
1513         };
1514     } else {
1515         return {};
1516     }
1517 }
1518 
GetObjectCounts() const1519 RenderDataDefaultMaterial::ObjectCounts RenderDataStoreDefaultMaterial::GetObjectCounts() const
1520 {
1521     return RenderDataDefaultMaterial::ObjectCounts {
1522         static_cast<uint32_t>(meshData_.frameMeshData.size()),
1523         static_cast<uint32_t>(meshData_.frameSubmeshes.size()),
1524         static_cast<uint32_t>(meshData_.frameJointMatrixIndices.size()),
1525         static_cast<uint32_t>(matData_.frameIndices.size()),
1526         static_cast<uint32_t>(matData_.allUniforms.size()),
1527     };
1528 }
1529 
GetSubmeshes() const1530 array_view<const RenderSubmesh> RenderDataStoreDefaultMaterial::GetSubmeshes() const
1531 {
1532     return meshData_.frameSubmeshes;
1533 }
1534 
GetMeshData() const1535 array_view<const RenderMeshData> RenderDataStoreDefaultMaterial::GetMeshData() const
1536 {
1537     return meshData_.frameMeshData;
1538 }
1539 
1540 array_view<const RenderDataDefaultMaterial::JointMatrixData>
GetMeshJointMatrices() const1541 RenderDataStoreDefaultMaterial::GetMeshJointMatrices() const
1542 {
1543     return meshData_.frameJointMatrixIndices;
1544 }
1545 
GetSubmeshJointMatrixData(const uint32_t skinJointIndex) const1546 array_view<const Math::Mat4X4> RenderDataStoreDefaultMaterial::GetSubmeshJointMatrixData(
1547     const uint32_t skinJointIndex) const
1548 {
1549     if (skinJointIndex < static_cast<uint32_t>(meshData_.frameJointMatrixIndices.size())) {
1550         const RenderDataDefaultMaterial::JointMatrixData& jm = meshData_.frameJointMatrixIndices[skinJointIndex];
1551         return array_view<const Math::Mat4X4>(jm.data, static_cast<size_t>(jm.count));
1552     } else {
1553         return {};
1554     }
1555 }
1556 
1557 array_view<const RenderDataDefaultMaterial::AllMaterialUniforms>
GetMaterialUniforms() const1558 RenderDataStoreDefaultMaterial::GetMaterialUniforms() const
1559 {
1560     return matData_.allUniforms;
1561 }
1562 
GetMaterialFrameIndices() const1563 array_view<const uint32_t> RenderDataStoreDefaultMaterial::GetMaterialFrameIndices() const
1564 {
1565     return matData_.frameIndices;
1566 }
1567 
GetMaterialHandles() const1568 array_view<const RenderDataDefaultMaterial::MaterialHandles> RenderDataStoreDefaultMaterial::GetMaterialHandles() const
1569 {
1570     return matData_.handles;
1571 }
1572 
GetMaterialCustomPropertyData(const uint32_t materialIndex) const1573 array_view<const uint8_t> RenderDataStoreDefaultMaterial::GetMaterialCustomPropertyData(
1574     const uint32_t materialIndex) const
1575 {
1576     if (materialIndex < static_cast<uint32_t>(matData_.customPropertyData.size())) {
1577         return matData_.customPropertyData[materialIndex].data;
1578     } else {
1579         return {};
1580     }
1581 }
1582 
1583 array_view<const RenderDataDefaultMaterial::SubmeshMaterialFlags>
GetSubmeshMaterialFlags() const1584 RenderDataStoreDefaultMaterial::GetSubmeshMaterialFlags() const
1585 {
1586     return meshData_.frameSubmeshMaterialFlags;
1587 }
1588 
1589 array_view<const RenderDataDefaultMaterial::CustomResourceData>
GetCustomResourceHandles() const1590 RenderDataStoreDefaultMaterial::GetCustomResourceHandles() const
1591 {
1592     return matData_.customResourceData;
1593 }
1594 
GetRenderFrameObjectInfo() const1595 RenderFrameObjectInfo RenderDataStoreDefaultMaterial::GetRenderFrameObjectInfo() const
1596 {
1597     return renderFrameObjectInfo_;
1598 }
1599 
GenerateRenderHash(const RenderDataDefaultMaterial::SubmeshMaterialFlags & flags) const1600 uint32_t RenderDataStoreDefaultMaterial::GenerateRenderHash(
1601     const RenderDataDefaultMaterial::SubmeshMaterialFlags& flags) const
1602 {
1603     return HashSubmeshMaterials(flags.materialType, flags.renderMaterialFlags, flags.submeshFlags);
1604 }
1605 
GetMaterialIndex(const uint64_t id) const1606 uint32_t RenderDataStoreDefaultMaterial::GetMaterialIndex(const uint64_t id) const
1607 {
1608     if (const auto iter = matData_.materialIdToIndex.find(id); iter != matData_.materialIdToIndex.cend()) {
1609         return iter->second;
1610     } else {
1611         return RenderSceneDataConstants::INVALID_INDEX;
1612     }
1613 }
1614 
AddRenderSlotSubmeshesFrameMaterialData(const uint32_t toSlotId,const array_view<const uint32_t> fromSlotIds,const RenderDataDefaultMaterial::InputMaterialUniforms & materialUniforms,const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference & materialHandles,const RenderDataDefaultMaterial::MaterialData & materialData,const array_view<const uint8_t> customPropertyData,const array_view<const RenderHandleReference> customBindings)1615 RenderFrameMaterialIndices RenderDataStoreDefaultMaterial::AddRenderSlotSubmeshesFrameMaterialData(
1616     const uint32_t toSlotId, const array_view<const uint32_t> fromSlotIds,
1617     const RenderDataDefaultMaterial::InputMaterialUniforms& materialUniforms,
1618     const RenderDataDefaultMaterial::MaterialHandlesWithHandleReference& materialHandles,
1619     const RenderDataDefaultMaterial::MaterialData& materialData, const array_view<const uint8_t> customPropertyData,
1620     const array_view<const RenderHandleReference> customBindings)
1621 {
1622     const RenderFrameMaterialIndices rfmi =
1623         AddFrameMaterialData(materialUniforms, materialHandles, materialData, customPropertyData, customBindings);
1624 
1625     const IShaderManager::RenderSlotData rds { toSlotId, {}, {}, {}, {} };
1626     const array_view<const IShaderManager::RenderSlotData> rdsView = { &rds, 1U };
1627     for (uint32_t slotIdx = 0U; slotIdx < fromSlotIds.size(); ++slotIdx) {
1628         const uint32_t currSlotIdx = fromSlotIds[slotIdx];
1629         const auto slotSubmeshIndices = GetSlotSubmeshIndices(currSlotIdx);
1630         meshData_.frameSubmeshes.reserve(meshData_.frameSubmeshes.size() + slotSubmeshIndices.size());
1631         for (uint32_t ssIdx = 0U; ssIdx < static_cast<uint32_t>(slotSubmeshIndices.size()); ++ssIdx) {
1632             const uint32_t currSubmeshIdx = slotSubmeshIndices[ssIdx];
1633             if (currSubmeshIdx < static_cast<uint32_t>(meshData_.frameSubmeshes.size())) {
1634                 // duplicate
1635                 RenderSubmesh newSubmesh = meshData_.frameSubmeshes[currSubmeshIdx];
1636                 newSubmesh.indices.materialIndex = rfmi.index;
1637                 newSubmesh.indices.materialFrameOffset = rfmi.frameOffset;
1638 
1639                 const uint32_t submeshIndex = static_cast<uint32_t>(meshData_.frameSubmeshes.size());
1640                 meshData_.frameSubmeshes.push_back(newSubmesh);
1641 
1642                 auto& currSubmesh = meshData_.frameSubmeshes.back();
1643                 FillSubmeshImpl(rdsView, submeshIndex, currSubmesh);
1644             }
1645         }
1646     }
1647     return rfmi;
1648 }
1649 
GetMeshBlasData() const1650 array_view<const AsInstance> RenderDataStoreDefaultMaterial::GetMeshBlasData() const
1651 {
1652     return meshData_.frameMeshBlasInstanceData;
1653 }
1654 
1655 // for plugin / factory interface
Create(RENDER_NS::IRenderContext & renderContext,char const * name)1656 refcnt_ptr<IRenderDataStore> RenderDataStoreDefaultMaterial::Create(
1657     RENDER_NS::IRenderContext& renderContext, char const* name)
1658 {
1659     return refcnt_ptr<IRenderDataStore>(new RenderDataStoreDefaultMaterial(renderContext, name));
1660 }
1661 CORE3D_END_NAMESPACE()
1662