• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 <algorithm>
17 
18 #include <gtest/gtest.h>
19 
20 #include <3d/ecs/components/material_component.h>
21 #include <3d/render/intf_render_data_store_default_material.h>
22 #include <base/math/vector_util.h>
23 #include <core/ecs/intf_entity_manager.h>
24 #include <core/intf_engine.h>
25 #include <core/plugin/intf_plugin.h>
26 #include <core/property/intf_property_api.h>
27 #include <core/property/intf_property_handle.h>
28 #include <core/property/property_types.h>
29 #include <render/datastore/intf_render_data_store.h>
30 #include <render/datastore/intf_render_data_store_manager.h>
31 #include <render/intf_renderer.h>
32 
33 #include "TestRunner.h"
34 
35 using namespace BASE_NS;
36 using namespace CORE_NS;
37 using namespace RENDER_NS;
38 using namespace CORE3D_NS;
39 using namespace testing::ext;
40 
41 namespace {
42 struct TestContext {
43     std::shared_ptr<ISceneInit> sceneInit_ = nullptr;
44     CORE_NS::IEcs::Ptr ecs_;
45 };
46 static TestContext g_context;
47 
48 using IntfPtr = BASE_NS::shared_ptr<CORE_NS::IInterface>;
49 using IntfWeakPtr = BASE_NS::weak_ptr<CORE_NS::IInterface>;
50 static constexpr BASE_NS::Uid ENGINE_THREAD{"2070e705-d061-40e4-bfb7-90fad2c280af"};
51 static constexpr BASE_NS::Uid APP_THREAD{"b2e8cef3-453a-4651-b564-5190f8b5190d"};
52 static constexpr BASE_NS::Uid IO_QUEUE{"be88e9a0-9cd8-45ab-be48-937953dc258f"};
53 static constexpr BASE_NS::Uid JS_RELEASE_THREAD{"3784fa96-b25b-4e9c-bbf1-e897d36f73af"};
54 
SceneDispose(TestContext & context)55 bool SceneDispose(TestContext &context)
56 {
57     context.ecs_ = nullptr;
58     context.sceneInit_ = nullptr;
59     return true;
60 }
61 
SceneCreate(TestContext & context)62 bool SceneCreate(TestContext &context)
63 {
64     context.sceneInit_ = CreateTestScene();
65     context.sceneInit_->LoadPluginsAndInit();
66     if (!context.sceneInit_->GetEngineInstance().engine_) {
67         WIDGET_LOGE("fail to get engine");
68         return false;
69     }
70     context.ecs_ = context.sceneInit_->GetEngineInstance().engine_->CreateEcs();
71     if (!context.ecs_) {
72         WIDGET_LOGE("fail to get ecs");
73         return false;
74     }
75     auto factory = GetInstance<Core::ISystemGraphLoaderFactory>(UID_SYSTEM_GRAPH_LOADER);
76     auto systemGraphLoader = factory->Create(context.sceneInit_->GetEngineInstance().engine_->GetFileManager());
77     systemGraphLoader->Load("rofs3D://systemGraph.json", *(context.ecs_));
78     auto& ecs = *(context.ecs_);
79     ecs.Initialize();
80 
81     using namespace SCENE_NS;
82 #if SCENE_META_TEST
83     auto fun = [&context]() {
84         auto &obr = META_NS::GetObjectRegistry();
85 
86         context.params_ = interface_pointer_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
87         if (!context.params_) {
88             CORE_LOG_E("default obj null");
89         }
90         context.scene_ =
91             interface_pointer_cast<SCENE_NS::IScene>(obr.Create(SCENE_NS::ClassId::Scene, context.params_));
92 
93         auto onLoaded = META_NS::MakeCallback<META_NS::IOnChanged>([&context]() {
94             bool complete = false;
95             auto status = context.scene_->Status()->GetValue();
96             if (status == SCENE_NS::IScene::SCENE_STATUS_READY) {
97                 // still in engine thread
98                 complete = true;
99             } else if (status == SCENE_NS::IScene::SCENE_STATUS_LOADING_FAILED) {
100                 // make sure we don't have anything in result if error
101                 complete = true;
102             }
103 
104             if (complete) {
105                 if (context.scene_) {
106                     auto &obr = META_NS::GetObjectRegistry();
107                     // make sure we have renderconfig
108                     auto rc = context.scene_->RenderConfiguration()->GetValue();
109                     if (!rc) {
110                         // Create renderconfig
111                         rc = obr.Create<SCENE_NS::IRenderConfiguration>(SCENE_NS::ClassId::RenderConfiguration);
112                         context.scene_->RenderConfiguration()->SetValue(rc);
113                     }
114 
115                     interface_cast<IEcsScene>(context.scene_)
116                         ->RenderMode()
117                         ->SetValue(IEcsScene::RenderMode::RENDER_ALWAYS);
118                     auto duh = context.params_->GetArrayPropertyByName<IntfWeakPtr>("Scenes");
119                     if (!duh) {
120                         return ;
121                     }
122                     duh->AddValue(interface_pointer_cast<CORE_NS::IInterface>(context.scene_));
123                 }
124             }
125         });
126         context.scene_->Asynchronous()->SetValue(false);
127         context.scene_->Uri()->SetValue("scene://empty");
128         return META_NS::IAny::Ptr{};
129     };
130     // Should it be possible to cancel? (ie. do we need to store the token for something ..)
131     META_NS::GetTaskQueueRegistry()
132         .GetTaskQueue(ENGINE_THREAD)
133         ->AddWaitableTask(META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>(BASE_NS::move(fun)))
134         ->Wait();
135 #endif
136     return true;
137 }
138 } // namespace
139 
140 class RenderDataStoreDefaultMaterialTest : public testing::Test {
141 public:
SetUpTestSuite()142     static void SetUpTestSuite()
143     {
144         SceneCreate(g_context);
145     }
TearDownTestSuite()146     static void TearDownTestSuite()
147     {
148         SceneDispose(g_context);
149     }
SetUp()150     void SetUp() override {}
TearDown()151     void TearDown() override {}
152 };
153 
154 /**
155  * @tc.name: CreateDestroyTest
156  * @tc.desc: test CreateDestroy
157  * @tc.type: FUNC
158  */
159 HWTEST_F(RenderDataStoreDefaultMaterialTest, CreateDestroyTest, TestSize.Level1)
160 {
161     auto engine = g_context.sceneInit_->GetEngineInstance().engine_;
162     auto renderContext = g_context.sceneInit_->GetEngineInstance().renderContext_;
163     auto graphicsContext = g_context.sceneInit_->GetEngineInstance().graphicsContext_;
164     auto ecs = g_context.ecs_;
165 
166     auto& dsManager = renderContext->GetRenderDataStoreManager();
167 
168     constexpr BASE_NS::string_view dataStoreName = "DataStoreDefaultMaterial0";
169     auto dataStoreDefaultMaterial = dsManager.Create(IRenderDataStoreDefaultMaterial::UID, dataStoreName.data());
170     ASSERT_TRUE(dataStoreDefaultMaterial);
171     ASSERT_EQ("RenderDataStoreDefaultMaterial", dataStoreDefaultMaterial->GetTypeName());
172     ASSERT_EQ(dataStoreName, dataStoreDefaultMaterial->GetName());
173     ASSERT_EQ(IRenderDataStoreDefaultMaterial::UID, dataStoreDefaultMaterial->GetUid());
174     ASSERT_EQ(0u, dataStoreDefaultMaterial->GetFlags());
175 
176     EXPECT_TRUE(dsManager.GetRenderDataStore(dataStoreName));
177     // Destruction is deferred
178     dataStoreDefaultMaterial.reset();
179     // Render with no render node graph just to trigger destruction
180     renderContext->GetRenderer().RenderFrame({});
181     EXPECT_FALSE(dsManager.GetRenderDataStore(dataStoreName));
182 }
183 
184 /**
185  * @tc.name: DefaultMaterialTest
186  * @tc.desc: test DefaultMaterial
187  * @tc.type: FUNC
188  */
189 HWTEST_F(RenderDataStoreDefaultMaterialTest, DefaultMaterialTest, TestSize.Level1)
190 {
191     auto engine = g_context.sceneInit_->GetEngineInstance().engine_;
192     auto renderContext = g_context.sceneInit_->GetEngineInstance().renderContext_;
193     auto graphicsContext = g_context.sceneInit_->GetEngineInstance().graphicsContext_;
194     auto ecs = g_context.ecs_;
195 
196     auto& dsManager = renderContext->GetRenderDataStoreManager();
197 
198     constexpr BASE_NS::string_view dataStoreName = "DataStoreDefaultMaterial0";
199     auto dataStoreDefaultMaterial = dsManager.Create(IRenderDataStoreDefaultMaterial::UID, dataStoreName.data());
200     ASSERT_TRUE(dataStoreDefaultMaterial);
201 
202     const uint32_t invalidId = ~0U; // built-in invalid
203     auto ds = static_cast<IRenderDataStoreDefaultMaterial*>(dataStoreDefaultMaterial.get());
204     const uint32_t materialIndex = ds->GetMaterialIndex(invalidId);
205     EXPECT_EQ(0U, materialIndex);
206 
207     const auto& matUniforms = ds->GetMaterialUniforms();
208     EXPECT_EQ(1U, matUniforms.size());
209     if (!matUniforms.empty()) {
210         const MaterialComponent mc;
211         const auto& mat = matUniforms[0U];
212 
213         for (uint32_t idx = 0; idx < MaterialComponent::TextureIndex::TEXTURE_COUNT; ++idx) {
214             EXPECT_EQ(mat.factors.factors[idx], mc.textures[idx].factor);
215         }
216         // alpha cut-off
217         EXPECT_EQ(mat.factors.factors[RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT].x, mc.alphaCutoff);
218 
219         // needs to match
220         const uint32_t mcLightingFlags = mc.materialLightingFlags;
221         constexpr uint32_t expectedDefaultMc = MaterialComponent::LightingFlagBits::SHADOW_RECEIVER_BIT |
222                                                MaterialComponent::LightingFlagBits::SHADOW_CASTER_BIT |
223                                                MaterialComponent::LightingFlagBits::PUNCTUAL_LIGHT_RECEIVER_BIT |
224                                                MaterialComponent::LightingFlagBits::INDIRECT_LIGHT_RECEIVER_BIT;
225         EXPECT_EQ(mcLightingFlags, expectedDefaultMc);
226         // needs to match
227         const RenderDataDefaultMaterial::MaterialData mdDefault;
228         const uint32_t dsLightingFlags = mdDefault.renderMaterialFlags;
229         constexpr uint32_t expectedDefaultDs = RENDER_MATERIAL_SHADOW_RECEIVER_BIT | RENDER_MATERIAL_SHADOW_CASTER_BIT |
230                                                RENDER_MATERIAL_PUNCTUAL_LIGHT_RECEIVER_BIT |
231                                                RENDER_MATERIAL_INDIRECT_LIGHT_RECEIVER_BIT;
232         EXPECT_EQ(dsLightingFlags, expectedDefaultDs);
233     }
234 
235     EXPECT_TRUE(dsManager.GetRenderDataStore(dataStoreName));
236     // Destruction is deferred
237     dataStoreDefaultMaterial.reset();
238     // Render with no render node graph just to trigger destruction
239     renderContext->GetRenderer().RenderFrame({});
240     EXPECT_FALSE(dsManager.GetRenderDataStore(dataStoreName));
241 }
242 
243 /**
244  * @tc.name: UpdateMaterialTest
245  * @tc.desc: test UpdateMaterial
246  * @tc.type: FUNC
247  */
248 HWTEST_F(RenderDataStoreDefaultMaterialTest, UpdateMaterialTest, TestSize.Level1)
249 {
250     auto engine = g_context.sceneInit_->GetEngineInstance().engine_;
251     auto renderContext = g_context.sceneInit_->GetEngineInstance().renderContext_;
252     auto graphicsContext = g_context.sceneInit_->GetEngineInstance().graphicsContext_;
253     auto ecs = g_context.ecs_;
254 
255     auto& dsManager = renderContext->GetRenderDataStoreManager();
256 
257     constexpr BASE_NS::string_view dataStoreName = "DataStoreDefaultMaterial0";
258     auto dataStoreDefaultMaterial = dsManager.Create(IRenderDataStoreDefaultMaterial::UID, dataStoreName.data());
259     ASSERT_TRUE(dataStoreDefaultMaterial);
260 
261     auto ds = static_cast<IRenderDataStoreDefaultMaterial*>(dataStoreDefaultMaterial.get());
262     const uint64_t matId = 4;
263     ds->UpdateMaterialData(matId, {}, {}, {}, {});
264     {
265         const auto& matUniforms = ds->GetMaterialUniforms();
266         EXPECT_EQ(2U, matUniforms.size());
267     }
268 
269     RenderDataDefaultMaterial::InputMaterialUniforms imu;
270     imu.alphaCutoff = 0.25f;
271     imu.texCoordSetBits = 1U;
272     imu.textureData[2U].factor = { 0.25f, 0.25f, 0.25f, 0.25f };
273     const uint32_t matIdx = ds->UpdateMaterialData(matId, imu, {}, {}, {});
274     {
275         const auto& matUniforms = ds->GetMaterialUniforms();
276         EXPECT_EQ(2U, matUniforms.size());
277 
278         for (uint32_t idx = 0; idx < RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT; ++idx) {
279             EXPECT_EQ(imu.textureData[idx].factor, matUniforms[matIdx].factors.factors[idx]);
280         }
281     }
282 
283     EXPECT_TRUE(dsManager.GetRenderDataStore(dataStoreName));
284     // Destruction is deferred
285     dataStoreDefaultMaterial.reset();
286     // Render with no render node graph just to trigger destruction
287     renderContext->GetRenderer().RenderFrame({});
288     EXPECT_FALSE(dsManager.GetRenderDataStore(dataStoreName));
289 }
290 
291 /**
292  * @tc.name: GetSetRenderSlotsTest
293  * @tc.desc: test GetSetRenderSlots
294  * @tc.type: FUNC
295  */
296 HWTEST_F(RenderDataStoreDefaultMaterialTest, GetSetRenderSlotsTest, TestSize.Level1)
297 {
298     auto engine = g_context.sceneInit_->GetEngineInstance().engine_;
299     auto renderContext = g_context.sceneInit_->GetEngineInstance().renderContext_;
300     auto graphicsContext = g_context.sceneInit_->GetEngineInstance().graphicsContext_;
301     auto ecs = g_context.ecs_;
302 
303     auto& dsManager = renderContext->GetRenderDataStoreManager();
304 
305     constexpr BASE_NS::string_view dataStoreName = "DataStoreDefaultMaterial0";
306     auto dataStore = dsManager.Create(IRenderDataStoreDefaultMaterial::UID, dataStoreName.data());
307     ASSERT_TRUE(dataStore);
308 
309     auto dataStoreDefaultMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(dataStore.get());
310 
311     {
312         uint32_t slots[] = { 0u, 3u, 12u };
313         dataStoreDefaultMaterial->SetRenderSlots(
314             RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_OPAQUE, { slots, countof(slots) });
315         auto slotMask =
316             dataStoreDefaultMaterial->GetRenderSlotMask(RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_OPAQUE);
317         for (uint32_t slot : slots) {
318             EXPECT_TRUE((1ULL << uint64_t(slot)) & slotMask);
319         }
320     }
321     {
322         uint32_t slots[] = { 1u, 15u, 2u, 4u };
323         dataStoreDefaultMaterial->SetRenderSlots(
324             RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_DEPTH, { slots, countof(slots) });
325         auto slotMask =
326             dataStoreDefaultMaterial->GetRenderSlotMask(RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_DEPTH);
327         for (uint32_t slot : slots) {
328             EXPECT_TRUE((1ULL << uint64_t(slot)) & slotMask);
329         }
330     }
331     {
332         uint32_t slots[] = { 11u, 10u };
333         dataStoreDefaultMaterial->SetRenderSlots(
334             RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_TRANSLUCENT, { slots, countof(slots) });
335         auto slotMask = dataStoreDefaultMaterial->GetRenderSlotMask(
336             RenderDataDefaultMaterial::MaterialSlotType::SLOT_TYPE_TRANSLUCENT);
337         for (uint32_t slot : slots) {
338             EXPECT_TRUE((1ULL << uint64_t(slot)) & slotMask);
339         }
340     }
341     // Destruction is deferred
342     dataStore.reset();
343     // Render with no render node graph just to trigger destruction
344     renderContext->GetRenderer().RenderFrame({});
345     EXPECT_FALSE(dsManager.GetRenderDataStore(dataStoreName));
346 }
347 
348 /**
349  * @tc.name: AddMaterialDataTest
350  * @tc.desc: test AddMaterialData
351  * @tc.type: FUNC
352  */
353 HWTEST_F(RenderDataStoreDefaultMaterialTest, AddMaterialDataTest, TestSize.Level1)
354 {
355     auto engine = g_context.sceneInit_->GetEngineInstance().engine_;
356     auto renderContext = g_context.sceneInit_->GetEngineInstance().renderContext_;
357     auto graphicsContext = g_context.sceneInit_->GetEngineInstance().graphicsContext_;
358     auto ecs = g_context.ecs_;
359 
360     auto& dsManager = renderContext->GetRenderDataStoreManager();
361 
362     constexpr BASE_NS::string_view dataStoreName = "DataStoreDefaultMaterial0";
363     auto dataStore = dsManager.Create(IRenderDataStoreDefaultMaterial::UID, dataStoreName.data());
364     ASSERT_TRUE(dataStore);
365 
366     auto dataStoreDefaultMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(dataStore.get());
367 
368     {
369         RenderDataDefaultMaterial::InputMaterialUniforms uniforms;
370         RenderDataDefaultMaterial::MaterialHandlesWithHandleReference handles;
371         RenderDataDefaultMaterial::MaterialData data;
372         uint8_t customPropertyData[16];
373         const uint64_t entityIndex = 5ULL;
374         const uint64_t dummyEntityIndex = 6ULL;
375 
376         auto materialIndex = dataStoreDefaultMaterial->UpdateMaterialData(
377             entityIndex, uniforms, handles, data, { customPropertyData, countof(customPropertyData) });
378         materialIndex = dataStoreDefaultMaterial->UpdateMaterialData(
379             entityIndex, uniforms, handles, data, { customPropertyData, countof(customPropertyData) }, {});
380         const auto matIdx = dataStoreDefaultMaterial->GetMaterialIndex(entityIndex);
381         EXPECT_EQ(materialIndex, matIdx);
382         EXPECT_EQ(materialIndex, dataStoreDefaultMaterial->UpdateMaterialData(entityIndex, uniforms, handles, data));
383         EXPECT_EQ(materialIndex, dataStoreDefaultMaterial->GetMaterialIndex(entityIndex));
384         EXPECT_EQ(RenderSceneDataConstants::INVALID_INDEX, dataStoreDefaultMaterial->GetMaterialIndex(100U));
385         EXPECT_EQ(
386             0, dataStoreDefaultMaterial->GetMaterialCustomPropertyData(RenderSceneDataConstants::INVALID_INDEX).size());
387         EXPECT_EQ(RenderSceneDataConstants::INVALID_INDEX,
388             dataStoreDefaultMaterial->AddFrameMaterialData(dummyEntityIndex, 0u).index);
389         const auto batchMaterialIndex = dataStoreDefaultMaterial->AddFrameMaterialData(dummyEntityIndex, 2u);
390         EXPECT_NE(materialIndex, batchMaterialIndex.index);
391         RenderHandleReference rhr[3];
392         auto resIndex = dataStoreDefaultMaterial->UpdateMaterialData(entityIndex, uniforms, handles, data,
393             { customPropertyData, countof(customPropertyData) }, { rhr, countof(rhr) });
394         EXPECT_NE(RenderSceneDataConstants::INVALID_INDEX, resIndex);
395 
396         const auto frameIndices = dataStoreDefaultMaterial->GetMaterialFrameIndices();
397         EXPECT_NE(frameIndices.size(), 2U);
398     }
399 
400     // Destruction is deferred
401     dataStore.reset();
402     // Render with no render node graph just to trigger destruction
403     renderContext->GetRenderer().RenderFrame({});
404     EXPECT_FALSE(dsManager.GetRenderDataStore(dataStoreName));
405 }
406 
407 /**
408  * @tc.name: AddInstanceMaterialDataTest
409  * @tc.desc: test AddInstanceMaterialData
410  * @tc.type: FUNC
411  */
412 HWTEST_F(RenderDataStoreDefaultMaterialTest, AddInstanceMaterialDataTest, TestSize.Level1)
413 {
414     auto engine = g_context.sceneInit_->GetEngineInstance().engine_;
415     auto renderContext = g_context.sceneInit_->GetEngineInstance().renderContext_;
416     auto graphicsContext = g_context.sceneInit_->GetEngineInstance().graphicsContext_;
417     auto ecs = g_context.ecs_;
418 
419     auto& dsManager = renderContext->GetRenderDataStoreManager();
420 
421     constexpr BASE_NS::string_view dataStoreName = "DataStoreDefaultMaterial0";
422     auto dataStore = dsManager.Create(IRenderDataStoreDefaultMaterial::UID, dataStoreName.data());
423     ASSERT_TRUE(dataStore);
424 
425     auto dataStoreDefaultMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(dataStore.get());
426 
427     {
428         RenderDataDefaultMaterial::InputMaterialUniforms uniforms;
429         RenderDataDefaultMaterial::MaterialData data;
430         uint8_t customPropertyData[16];
431         uint64_t entityIndex = 5ULL;
432 
433         const auto materialIndex = dataStoreDefaultMaterial->UpdateMaterialData(
434             entityIndex, uniforms, {}, data, { customPropertyData, countof(customPropertyData) });
435         dataStoreDefaultMaterial->AddFrameMaterialData(entityIndex, 2U);
436         const auto frameIndices = dataStoreDefaultMaterial->GetMaterialFrameIndices();
437         EXPECT_EQ(frameIndices.size(), 2U);
438         EXPECT_EQ(16u, dataStoreDefaultMaterial->GetMaterialCustomPropertyData(materialIndex).size());
439     }
440 
441     // Destruction is deferred
442     dataStore.reset();
443     // Render with no render node graph just to trigger destruction
444     renderContext->GetRenderer().RenderFrame({});
445     EXPECT_FALSE(dsManager.GetRenderDataStore(dataStoreName));
446 }
447 
448 /**
449  * @tc.name: SubmeshJointsTest
450  * @tc.desc: test SubmeshJoints
451  * @tc.type: FUNC
452  */
453 HWTEST_F(RenderDataStoreDefaultMaterialTest, SubmeshJointsTest, TestSize.Level1)
454 {
455     auto engine = g_context.sceneInit_->GetEngineInstance().engine_;
456     auto renderContext = g_context.sceneInit_->GetEngineInstance().renderContext_;
457     auto graphicsContext = g_context.sceneInit_->GetEngineInstance().graphicsContext_;
458     auto ecs = g_context.ecs_;
459 
460     auto& dsManager = renderContext->GetRenderDataStoreManager();
461 
462     constexpr BASE_NS::string_view dataStoreName = "DataStoreDefaultMaterial0";
463     auto dataStore = dsManager.Create(IRenderDataStoreDefaultMaterial::UID, dataStoreName.data());
464     ASSERT_TRUE(dataStore);
465 
466     auto dataStoreDefaultMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(dataStore.get());
467 
468     {
469         RenderSubmeshWithHandleReference submesh;
470         submesh.indices.skinJointIndex = 0u;
471         submesh.indices.materialFrameOffset = 64U;
472         submesh.indices.materialIndex = RenderSceneDataConstants::INVALID_INDEX;
473         dataStoreDefaultMaterial->AddSubmesh(submesh);
474     }
475     {
476         RenderSubmeshWithHandleReference submesh;
477         submesh.indices.skinJointIndex = 0u;
478         submesh.indices.materialFrameOffset = 64U;
479         submesh.indices.meshIndex = 1500u;
480         submesh.indices.materialIndex = 1500u;
481         dataStoreDefaultMaterial->AddSubmesh(submesh, {});
482     }
483     {
484         RenderSubmeshWithHandleReference submesh;
485         submesh.submeshFlags = RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT;
486         submesh.indices.skinJointIndex = 1500u;
487         submesh.indices.materialFrameOffset = 64U;
488         submesh.indices.meshIndex = 1500u;
489         submesh.indices.materialIndex = 1500u;
490         dataStoreDefaultMaterial->AddSubmesh(submesh, {});
491     }
492 
493     dataStoreDefaultMaterial->Clear();
494     EXPECT_EQ(0, dataStoreDefaultMaterial->GetSubmeshJointMatrixData(RenderSceneDataConstants::INVALID_INDEX).size());
495 
496     // Destruction is deferred
497     dataStore.reset();
498     // Render with no render node graph just to trigger destruction
499     renderContext->GetRenderer().RenderFrame({});
500     EXPECT_FALSE(dsManager.GetRenderDataStore(dataStoreName));
501 }
502 
503 /**
504  * @tc.name: RenderSortLayerTest
505  * @tc.desc: test RenderSortLayer
506  * @tc.type: FUNC
507  */
508 HWTEST_F(RenderDataStoreDefaultMaterialTest, RenderSortLayerTest, TestSize.Level1)
509 {
510     auto engine = g_context.sceneInit_->GetEngineInstance().engine_;
511     auto renderContext = g_context.sceneInit_->GetEngineInstance().renderContext_;
512     auto graphicsContext = g_context.sceneInit_->GetEngineInstance().graphicsContext_;
513     auto ecs = g_context.ecs_;
514 
515     auto& dsManager = renderContext->GetRenderDataStoreManager();
516 
517     constexpr BASE_NS::string_view dataStoreName = "DataStoreDefaultMaterial0";
518     auto dataStore = dsManager.Create(IRenderDataStoreDefaultMaterial::UID, dataStoreName.data());
519     ASSERT_TRUE(dataStore);
520 
521     auto dataStoreDefaultMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(dataStore.get());
522 
523     // Non-default values
524     constexpr uint64_t renderSortLayer = 2;
525     constexpr uint64_t renderSortLayerOrder = 53;
526     constexpr uint64_t meshRenderSortLayer = 48;
527     constexpr uint64_t meshRenderSortLayerOrder = 45;
528     constexpr uint64_t entityIndex = 14;
529     RenderFrameMaterialIndices matIndices;
530     {
531         RenderDataDefaultMaterial::InputMaterialUniforms uniforms;
532         RenderDataDefaultMaterial::MaterialData data;
533         data.renderSortLayer = renderSortLayer;
534         data.renderSortLayerOrder = renderSortLayerOrder;
535 
536         const auto materialIndex = dataStoreDefaultMaterial->UpdateMaterialData(entityIndex, uniforms, {}, data);
537         matIndices = dataStoreDefaultMaterial->AddFrameMaterialData(entityIndex, 1U);
538     }
539     {
540         RenderSubmeshWithHandleReference submesh;
541         submesh.indices.materialIndex = matIndices.index;
542         submesh.indices.materialFrameOffset = matIndices.frameOffset;
543         submesh.layers.meshRenderSortLayer = meshRenderSortLayer;
544         submesh.layers.meshRenderSortLayerOrder = meshRenderSortLayerOrder;
545         dataStoreDefaultMaterial->AddSubmesh(submesh);
546 
547         const auto& submeshes = dataStoreDefaultMaterial->GetSubmeshes();
548 
549         EXPECT_EQ(submeshes.size(), size_t(1));
550         if (submeshes.size() >= 1) {
551             EXPECT_EQ(submeshes[0U].layers.materialRenderSortLayer, renderSortLayer);
552             EXPECT_EQ(submeshes[0U].layers.materialRenderSortLayerOrder, renderSortLayerOrder);
553             EXPECT_EQ(submeshes[0U].layers.meshRenderSortLayer, meshRenderSortLayer);
554             EXPECT_EQ(submeshes[0U].layers.meshRenderSortLayerOrder, meshRenderSortLayerOrder);
555         }
556     }
557     {
558         RenderSubmeshWithHandleReference submesh;
559         submesh.indices.materialIndex = matIndices.index;
560         submesh.indices.materialFrameOffset = matIndices.frameOffset;
561         submesh.layers.meshRenderSortLayer = meshRenderSortLayer;
562         submesh.layers.meshRenderSortLayerOrder = meshRenderSortLayerOrder;
563         // non-default values
564         submesh.layers.materialRenderSortLayer = 8U;
565         submesh.layers.materialRenderSortLayerOrder = 9U;
566         dataStoreDefaultMaterial->AddSubmesh(submesh);
567 
568         const auto& submeshes = dataStoreDefaultMaterial->GetSubmeshes();
569 
570         EXPECT_EQ(submeshes.size(), size_t(2));
571         if (submeshes.size() >= 2) {
572             EXPECT_EQ(submeshes[1U].layers.materialRenderSortLayer, 8U);
573             EXPECT_EQ(submeshes[1U].layers.materialRenderSortLayerOrder, 9U);
574             EXPECT_EQ(submeshes[1U].layers.meshRenderSortLayer, meshRenderSortLayer);
575             EXPECT_EQ(submeshes[1U].layers.meshRenderSortLayerOrder, meshRenderSortLayerOrder);
576         }
577     }
578 
579     // Destruction is deferred
580     dataStore.reset();
581     // Render with no render node graph just to trigger destruction
582     renderContext->GetRenderer().RenderFrame({});
583     EXPECT_FALSE(dsManager.GetRenderDataStore(dataStoreName));
584 }
585