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