2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <dali-test-suite-utils.h>
19 #include <dali/public-api/dali-core.h>
21 using namespace std::chrono_literals;
24 #include <mesh-builder.h>
27 struct VertexBufferUpdater
32 void* lastPtr{nullptr};
34 size_t lastReturned{0};
37 VertexBufferUpdater() = default;
39 uint32_t UpdateVertices(void* ptr, size_t size)
41 diagnostics.lastPtr = ptr;
42 diagnostics.lastSize = size;
43 diagnostics.lastReturned = returnSize;
44 diagnostics.counter++;
46 promise.set_value(diagnostics);
50 void SetCallbackReturnValue(size_t size)
57 promise = std::promise<Diagnostics>();
60 std::unique_ptr<VertexBufferUpdateCallback> CreateCallback()
62 return VertexBufferUpdateCallback::New(this, &VertexBufferUpdater::UpdateVertices);
65 Diagnostics GetValue()
67 auto value = promise.get_future().get();
69 // reset promise automatically
76 // fake-wait for two frames
77 auto status = promise.get_future().wait_for(32ms);
78 return status == std::future_status::ready;
81 Diagnostics diagnostics;
82 size_t returnSize{0u};
83 std::promise<Diagnostics> promise;
86 void vertexBuffer_test_startup(void)
88 test_return_value = TET_UNDEF;
91 void vertexBuffer_test_cleanup(void)
93 test_return_value = TET_PASS;
96 int UtcDaliVertexBufferNew01(void)
98 TestApplication application;
100 Property::Map texturedQuadVertexFormat;
101 texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
102 texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
104 VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
106 DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
110 int UtcDaliVertexBufferNew02(void)
112 TestApplication application;
113 VertexBuffer vertexBuffer;
114 DALI_TEST_EQUALS((bool)vertexBuffer, false, TEST_LOCATION);
118 int UtcDaliVertexBufferDownCast01(void)
120 TestApplication application;
122 Property::Map texturedQuadVertexFormat;
123 texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
124 texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
126 VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
128 BaseHandle handle(vertexBuffer);
129 VertexBuffer vertexBuffer2 = VertexBuffer::DownCast(handle);
130 DALI_TEST_EQUALS((bool)vertexBuffer2, true, TEST_LOCATION);
134 int UtcDaliVertexBufferDownCast02(void)
136 TestApplication application;
138 Handle handle = Handle::New(); // Create a custom object
139 VertexBuffer vertexBuffer = VertexBuffer::DownCast(handle);
140 DALI_TEST_EQUALS((bool)vertexBuffer, false, TEST_LOCATION);
144 int UtcDaliVertexBufferCopyConstructor(void)
146 TestApplication application;
148 VertexBuffer vertexBuffer = CreateVertexBuffer();
150 VertexBuffer vertexBufferCopy(vertexBuffer);
152 DALI_TEST_EQUALS((bool)vertexBufferCopy, true, TEST_LOCATION);
153 DALI_TEST_EQUALS(vertexBufferCopy.GetSize(), 0u, TEST_LOCATION);
158 int UtcDaliVertexBufferAssignmentOperator(void)
160 TestApplication application;
162 VertexBuffer vertexBuffer = CreateVertexBuffer();
164 VertexBuffer vertexBuffer2;
165 DALI_TEST_EQUALS((bool)vertexBuffer2, false, TEST_LOCATION);
167 vertexBuffer2 = vertexBuffer;
168 DALI_TEST_EQUALS((bool)vertexBuffer2, true, TEST_LOCATION);
169 DALI_TEST_EQUALS(vertexBuffer2.GetSize(), 0u, TEST_LOCATION);
174 int UtcDaliVertexBufferMoveConstructor(void)
176 TestApplication application;
178 VertexBuffer vertexBuffer = CreateVertexBuffer();
179 DALI_TEST_CHECK(vertexBuffer);
180 DALI_TEST_EQUALS(1, vertexBuffer.GetBaseObject().ReferenceCount(), TEST_LOCATION);
181 DALI_TEST_EQUALS(0u, vertexBuffer.GetSize(), TEST_LOCATION);
183 VertexBuffer move = std::move(vertexBuffer);
184 DALI_TEST_CHECK(move);
185 DALI_TEST_EQUALS(1, move.GetBaseObject().ReferenceCount(), TEST_LOCATION);
186 DALI_TEST_EQUALS(0u, move.GetSize(), TEST_LOCATION);
187 DALI_TEST_CHECK(!vertexBuffer);
192 int UtcDaliVertexBufferMoveAssignment(void)
194 TestApplication application;
196 VertexBuffer vertexBuffer = CreateVertexBuffer();
197 DALI_TEST_CHECK(vertexBuffer);
198 DALI_TEST_EQUALS(1, vertexBuffer.GetBaseObject().ReferenceCount(), TEST_LOCATION);
199 DALI_TEST_EQUALS(0u, vertexBuffer.GetSize(), TEST_LOCATION);
202 move = std::move(vertexBuffer);
203 DALI_TEST_CHECK(move);
204 DALI_TEST_EQUALS(1, move.GetBaseObject().ReferenceCount(), TEST_LOCATION);
205 DALI_TEST_EQUALS(0u, move.GetSize(), TEST_LOCATION);
206 DALI_TEST_CHECK(!vertexBuffer);
211 int UtcDaliVertexBufferSetData01(void)
213 TestApplication application;
215 Property::Map texturedQuadVertexFormat;
216 texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
217 texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
220 VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
221 DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
223 const float halfQuadSize = .5f;
224 struct TexturedQuadVertex
227 Vector2 textureCoordinates;
229 TexturedQuadVertex texturedQuadVertexData[4] = {
230 {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
231 {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
232 {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
233 {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
235 vertexBuffer.SetData(texturedQuadVertexData, 4);
237 Geometry geometry = Geometry::New();
238 geometry.AddVertexBuffer(vertexBuffer);
240 Shader shader = CreateShader();
241 Renderer renderer = Renderer::New(geometry, shader);
242 Actor actor = Actor::New();
243 actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
244 actor.AddRenderer(renderer);
245 application.GetScene().Add(actor);
247 auto& drawTrace = application.GetGlAbstraction().GetDrawTrace();
248 drawTrace.Enable(true);
250 application.SendNotification();
251 application.Render(0);
252 application.Render();
253 application.SendNotification();
255 const TestGlAbstraction::BufferDataCalls& bufferDataCalls =
256 application.GetGlAbstraction().GetBufferDataCalls();
258 DALI_TEST_CHECK(drawTrace.FindMethod("DrawArrays"));
260 DALI_TEST_EQUALS(bufferDataCalls.size(), 3u, TEST_LOCATION);
262 DALI_TEST_EQUALS(bufferDataCalls[0], sizeof(texturedQuadVertexData), TEST_LOCATION);
264 // end of scope to let the buffer and geometry die; do another notification and render to get the deletion processed
265 application.SendNotification();
266 application.Render(0);
271 int UtcDaliVertexBufferSetData02(void)
273 TestApplication application;
275 Property::Map texturedQuadVertexFormat;
276 texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
277 texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
279 VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
280 DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
282 const float halfQuadSize = .5f;
283 struct TexturedQuadVertex
286 Vector2 textureCoordinates;
288 TexturedQuadVertex texturedQuadVertexData[4] = {
289 {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
290 {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
291 {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
292 {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
294 vertexBuffer.SetData(texturedQuadVertexData, 4);
296 Geometry geometry = Geometry::New();
297 geometry.AddVertexBuffer(vertexBuffer);
299 Shader shader = CreateShader();
300 Renderer renderer = Renderer::New(geometry, shader);
301 Actor actor = Actor::New();
302 actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
303 actor.AddRenderer(renderer);
304 application.GetScene().Add(actor);
306 application.SendNotification();
307 application.Render();
310 const TestGlAbstraction::BufferSubDataCalls& bufferSubDataCalls =
311 application.GetGlAbstraction().GetBufferSubDataCalls();
313 const TestGlAbstraction::BufferDataCalls& bufferDataCalls =
314 application.GetGlAbstraction().GetBufferDataCalls();
316 // Should be 1 (Flush standalone uniform buffer per each RenderScene)
317 DALI_TEST_EQUALS(bufferSubDataCalls.size(), 1u, TEST_LOCATION);
318 DALI_TEST_EQUALS(bufferDataCalls.size(), 2u, TEST_LOCATION);
320 DALI_TEST_EQUALS(bufferDataCalls[0], sizeof(texturedQuadVertexData), TEST_LOCATION);
323 // Re-upload the data on the vertexBuffer
324 vertexBuffer.SetData(texturedQuadVertexData, 4);
326 application.SendNotification();
327 application.Render(0);
332 int UtcDaliVertexBufferMapInitializerList(void)
334 TestApplication application;
336 Property::Map texturedQuadVertexFormat = Property::Map{{"aPosition", Property::VECTOR2},
337 {"aTexCoord", Property::VECTOR2},
338 {"aColor", Property::VECTOR4}};
342 VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
343 tet_result(TET_PASS);
345 catch(Dali::DaliException& e)
347 // Shouldn't assert any more
348 tet_result(TET_FAIL);
353 int UtcDaliVertexBufferInvalidTypeN01(void)
355 TestApplication application;
357 Property::Map texturedQuadVertexFormat;
358 texturedQuadVertexFormat["aPosition"] = Property::MAP;
359 texturedQuadVertexFormat["aVertexCoord"] = Property::STRING;
363 VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
364 tet_result(TET_FAIL);
366 catch(Dali::DaliException& e)
368 DALI_TEST_ASSERT(e, "Property::Type not supported in VertexBuffer", TEST_LOCATION);
373 int UtcDaliVertexBufferInvalidTypeN02(void)
375 TestApplication application;
377 Property::Map texturedQuadVertexFormat = Property::Map{{"aPosition", Property::MAP},
378 {"aTexCoord", Property::STRING},
379 {"aColor", Property::VECTOR4}};
383 VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
384 tet_result(TET_FAIL);
386 catch(Dali::DaliException& e)
388 DALI_TEST_ASSERT(e, "Property::Type not supported in VertexBuffer", TEST_LOCATION);
393 int UtcDaliVertexBufferSetDataNegative(void)
395 TestApplication application;
396 Dali::VertexBuffer instance;
400 unsigned long arg2(0u);
401 instance.SetData(arg1, arg2);
402 DALI_TEST_CHECK(false); // Should not get here
406 DALI_TEST_CHECK(true); // We expect an assert
411 int UtcDaliVertexBufferGetSizeNegative(void)
413 TestApplication application;
414 Dali::VertexBuffer instance;
418 DALI_TEST_CHECK(false); // Should not get here
422 DALI_TEST_CHECK(true); // We expect an assert
427 int UtcDaliVertexBufferSetDivisor(void)
429 TestApplication application;
431 Property::Map texturedQuadVertexFormat;
432 texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
433 texturedQuadVertexFormat["aTexCoord"] = Property::VECTOR2;
435 Property::Map instanceFormat{{"aTranslate", Property::VECTOR2}, {"aColor", Property::VECTOR4}};
437 VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
438 DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
440 DALI_TEST_EQUALS(0, vertexBuffer.GetDivisor(), TEST_LOCATION);
442 VertexBuffer instanceBuffer = VertexBuffer::New(instanceFormat);
443 DALI_TEST_EQUALS((bool)instanceBuffer, true, TEST_LOCATION);
445 const float halfQuadSize = .5f;
446 struct TexturedQuadVertex
449 Vector2 textureCoordinates;
451 TexturedQuadVertex texturedQuadVertexData[4] = {
452 {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
453 {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
454 {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
455 {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
457 vertexBuffer.SetData(texturedQuadVertexData, 4);
465 InstanceData instanceData[] = {{Vector2(12, 33), Color::WHITE},
466 {Vector2(-2000, 43), Color::BLUE},
467 {Vector2(200, 43), Color::GREEN},
468 {Vector2(-243, 43), Color::TURQUOISE},
469 {Vector2(192, 43), Color::CYAN},
470 {Vector2(-2000, 43), Color::MAGENTA},
471 {Vector2(-292, 393), Color::BLUE},
472 {Vector2(-499, 128), Color::BLUE},
473 {Vector2(328, 43), Color::BLUE},
474 {Vector2(726, 43), Color::BLUE}};
475 instanceBuffer.SetData(instanceData, sizeof(instanceData) / sizeof(InstanceData));
476 instanceBuffer.SetDivisor(1);
477 DALI_TEST_EQUALS(1, instanceBuffer.GetDivisor(), TEST_LOCATION);
479 Geometry geometry = Geometry::New();
480 geometry.AddVertexBuffer(vertexBuffer);
481 geometry.AddVertexBuffer(instanceBuffer);
483 Shader shader = CreateShader();
484 Renderer renderer = Renderer::New(geometry, shader);
485 Actor actor = Actor::New();
486 actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
487 actor.AddRenderer(renderer);
488 application.GetScene().Add(actor);
490 TestGlAbstraction& gl = application.GetGlAbstraction();
491 auto& bufferTrace = gl.GetBufferTrace();
492 auto& drawTrace = gl.GetDrawTrace();
493 bufferTrace.Enable(true);
494 drawTrace.Enable(true);
496 application.SendNotification();
497 application.Render();
499 TraceCallStack::NamedParams params;
500 params["divisor"] << "1";
501 DALI_TEST_CHECK(bufferTrace.FindMethodAndParams("VertexAttribDivisor", params));
503 TraceCallStack::NamedParams params2;
504 DALI_TEST_CHECK(drawTrace.FindMethodAndGetParameters("DrawArraysInstanced", params2));
505 std::ostringstream oss;
506 oss << sizeof(instanceData) / sizeof(InstanceData);
507 DALI_TEST_EQUALS(params2["instanceCount"].str(), oss.str(), TEST_LOCATION);
511 int UtcDaliVertexBufferUpdateCallback(void)
513 TestApplication application;
515 // Create vertex buffer
516 VertexBuffer vertexBuffer = VertexBuffer::New(Property::Map() = {
517 {"aPosition", Property::Type::VECTOR2},
518 {"aTexCoord", Property::Type::VECTOR2}});
521 auto callback = std::make_unique<VertexBufferUpdater>();
522 vertexBuffer.SetVertexBufferUpdateCallback(callback->CreateCallback());
530 std::vector<Vertex> vertices;
532 vertexBuffer.SetData(vertices.data(), 16);
534 Geometry geometry = Geometry::New();
535 geometry.AddVertexBuffer(vertexBuffer);
536 Shader shader = CreateShader();
537 Renderer renderer = Renderer::New(geometry, shader);
538 Actor actor = Actor::New();
539 actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
540 actor.AddRenderer(renderer);
541 application.GetScene().Add(actor);
543 auto& gl = application.GetGlAbstraction();
544 auto& trace = gl.GetDrawTrace();
546 trace.EnableLogging(true);
548 callback->SetCallbackReturnValue(16 * sizeof(Vertex));
550 application.SendNotification();
551 application.Render();
553 auto value = callback->GetValue();
555 // Test whether callback ran
556 DALI_TEST_EQUALS(value.counter, 1, TEST_LOCATION);
557 DALI_TEST_EQUALS(value.lastSize, 16 * sizeof(Vertex), TEST_LOCATION);
558 DALI_TEST_EQUALS(value.lastReturned, 16 * sizeof(Vertex), TEST_LOCATION);
559 DALI_TEST_NOT_EQUALS(value.lastPtr, (void*)nullptr, 0, TEST_LOCATION);
561 // test whether draw call has been issued (return value indicates end of array to be drawn)
562 auto result = trace.FindMethod("DrawArrays");
563 DALI_TEST_EQUALS(result, true, TEST_LOCATION);
564 result = trace.FindMethodAndParams("DrawArrays", "4, 0, 16");
565 DALI_TEST_EQUALS(result, true, TEST_LOCATION);
567 // Test 2. Update and render only half of vertex buffer
568 callback->SetCallbackReturnValue(8 * sizeof(Vertex));
571 application.SendNotification();
572 application.Render();
574 value = callback->GetValue();
575 // Test whether callback ran
576 DALI_TEST_EQUALS(value.counter, 2, TEST_LOCATION);
577 DALI_TEST_EQUALS(value.lastSize, 16 * sizeof(Vertex), TEST_LOCATION);
578 DALI_TEST_EQUALS(value.lastReturned, 8 * sizeof(Vertex), TEST_LOCATION);
579 DALI_TEST_NOT_EQUALS(value.lastPtr, (void*)nullptr, 0, TEST_LOCATION);
580 result = trace.FindMethod("DrawArrays");
581 DALI_TEST_EQUALS(result, true, TEST_LOCATION);
582 result = trace.FindMethodAndParams("DrawArrays", "4, 0, 8");
583 DALI_TEST_EQUALS(result, true, TEST_LOCATION);
585 // Test 3. callback returns 0 elements to render, the draw call shouldn't happen.
586 callback->SetCallbackReturnValue(0);
589 application.SendNotification();
590 application.Render();
592 value = callback->GetValue();
593 // Test whether callback ran
594 DALI_TEST_EQUALS(value.counter, 3, TEST_LOCATION);
595 DALI_TEST_EQUALS(value.lastSize, 16 * sizeof(Vertex), TEST_LOCATION);
596 DALI_TEST_EQUALS(value.lastReturned, 0, TEST_LOCATION);
597 DALI_TEST_NOT_EQUALS(value.lastPtr, (void*)nullptr, 0, TEST_LOCATION);
598 result = trace.FindMethod("DrawArrays");
599 DALI_TEST_EQUALS(result, false, TEST_LOCATION);
601 // Test 4. removing callback, original behaviour should kick in
602 vertexBuffer.SetVertexBufferUpdateCallback(nullptr);
606 application.SendNotification();
607 application.Render();
609 auto valueReady = callback->IsValueReady();
610 DALI_TEST_EQUALS(valueReady, false, TEST_LOCATION);
611 DALI_TEST_EQUALS(callback->diagnostics.counter, 3, TEST_LOCATION);
612 result = trace.FindMethod("DrawArrays");
613 DALI_TEST_EQUALS(result, true, TEST_LOCATION);
614 result = trace.FindMethodAndParams("DrawArrays", "4, 0, 16");
615 DALI_TEST_EQUALS(result, true, TEST_LOCATION);