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