VertexBuffer instancing
[platform/core/uifw/dali-core.git] / automated-tests / src / dali / utc-Dali-VertexBuffer.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 #include <dali-test-suite-utils.h>
19 #include <dali/public-api/dali-core.h>
20
21 using namespace Dali;
22
23 #include <mesh-builder.h>
24
25 void vertexBuffer_test_startup(void)
26 {
27   test_return_value = TET_UNDEF;
28 }
29
30 void vertexBuffer_test_cleanup(void)
31 {
32   test_return_value = TET_PASS;
33 }
34
35 int UtcDaliVertexBufferNew01(void)
36 {
37   TestApplication application;
38
39   Property::Map texturedQuadVertexFormat;
40   texturedQuadVertexFormat["aPosition"]    = Property::VECTOR2;
41   texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
42
43   VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
44
45   DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
46   END_TEST;
47 }
48
49 int UtcDaliVertexBufferNew02(void)
50 {
51   TestApplication application;
52   VertexBuffer    vertexBuffer;
53   DALI_TEST_EQUALS((bool)vertexBuffer, false, TEST_LOCATION);
54   END_TEST;
55 }
56
57 int UtcDaliVertexBufferDownCast01(void)
58 {
59   TestApplication application;
60
61   Property::Map texturedQuadVertexFormat;
62   texturedQuadVertexFormat["aPosition"]    = Property::VECTOR2;
63   texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
64
65   VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
66
67   BaseHandle   handle(vertexBuffer);
68   VertexBuffer vertexBuffer2 = VertexBuffer::DownCast(handle);
69   DALI_TEST_EQUALS((bool)vertexBuffer2, true, TEST_LOCATION);
70   END_TEST;
71 }
72
73 int UtcDaliVertexBufferDownCast02(void)
74 {
75   TestApplication application;
76
77   Handle       handle       = Handle::New(); // Create a custom object
78   VertexBuffer vertexBuffer = VertexBuffer::DownCast(handle);
79   DALI_TEST_EQUALS((bool)vertexBuffer, false, TEST_LOCATION);
80   END_TEST;
81 }
82
83 int UtcDaliVertexBufferCopyConstructor(void)
84 {
85   TestApplication application;
86
87   VertexBuffer vertexBuffer = CreateVertexBuffer();
88
89   VertexBuffer vertexBufferCopy(vertexBuffer);
90
91   DALI_TEST_EQUALS((bool)vertexBufferCopy, true, TEST_LOCATION);
92   DALI_TEST_EQUALS(vertexBufferCopy.GetSize(), 0u, TEST_LOCATION);
93
94   END_TEST;
95 }
96
97 int UtcDaliVertexBufferAssignmentOperator(void)
98 {
99   TestApplication application;
100
101   VertexBuffer vertexBuffer = CreateVertexBuffer();
102
103   VertexBuffer vertexBuffer2;
104   DALI_TEST_EQUALS((bool)vertexBuffer2, false, TEST_LOCATION);
105
106   vertexBuffer2 = vertexBuffer;
107   DALI_TEST_EQUALS((bool)vertexBuffer2, true, TEST_LOCATION);
108   DALI_TEST_EQUALS(vertexBuffer2.GetSize(), 0u, TEST_LOCATION);
109
110   END_TEST;
111 }
112
113 int UtcDaliVertexBufferMoveConstructor(void)
114 {
115   TestApplication application;
116
117   VertexBuffer vertexBuffer = CreateVertexBuffer();
118   DALI_TEST_CHECK(vertexBuffer);
119   DALI_TEST_EQUALS(1, vertexBuffer.GetBaseObject().ReferenceCount(), TEST_LOCATION);
120   DALI_TEST_EQUALS(0u, vertexBuffer.GetSize(), TEST_LOCATION);
121
122   VertexBuffer move = std::move(vertexBuffer);
123   DALI_TEST_CHECK(move);
124   DALI_TEST_EQUALS(1, move.GetBaseObject().ReferenceCount(), TEST_LOCATION);
125   DALI_TEST_EQUALS(0u, move.GetSize(), TEST_LOCATION);
126   DALI_TEST_CHECK(!vertexBuffer);
127
128   END_TEST;
129 }
130
131 int UtcDaliVertexBufferMoveAssignment(void)
132 {
133   TestApplication application;
134
135   VertexBuffer vertexBuffer = CreateVertexBuffer();
136   DALI_TEST_CHECK(vertexBuffer);
137   DALI_TEST_EQUALS(1, vertexBuffer.GetBaseObject().ReferenceCount(), TEST_LOCATION);
138   DALI_TEST_EQUALS(0u, vertexBuffer.GetSize(), TEST_LOCATION);
139
140   VertexBuffer move;
141   move = std::move(vertexBuffer);
142   DALI_TEST_CHECK(move);
143   DALI_TEST_EQUALS(1, move.GetBaseObject().ReferenceCount(), TEST_LOCATION);
144   DALI_TEST_EQUALS(0u, move.GetSize(), TEST_LOCATION);
145   DALI_TEST_CHECK(!vertexBuffer);
146
147   END_TEST;
148 }
149
150 int UtcDaliVertexBufferSetData01(void)
151 {
152   TestApplication application;
153
154   Property::Map texturedQuadVertexFormat;
155   texturedQuadVertexFormat["aPosition"]    = Property::VECTOR2;
156   texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
157
158   {
159     VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
160     DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
161
162     const float halfQuadSize = .5f;
163     struct TexturedQuadVertex
164     {
165       Vector2 position;
166       Vector2 textureCoordinates;
167     };
168     TexturedQuadVertex texturedQuadVertexData[4] = {
169       {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
170       {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
171       {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
172       {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
173
174     vertexBuffer.SetData(texturedQuadVertexData, 4);
175
176     Geometry geometry = Geometry::New();
177     geometry.AddVertexBuffer(vertexBuffer);
178
179     Shader   shader   = CreateShader();
180     Renderer renderer = Renderer::New(geometry, shader);
181     Actor    actor    = Actor::New();
182     actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
183     actor.AddRenderer(renderer);
184     application.GetScene().Add(actor);
185
186     auto& drawTrace = application.GetGlAbstraction().GetDrawTrace();
187     drawTrace.Enable(true);
188
189     application.SendNotification();
190     application.Render(0);
191     application.Render();
192     application.SendNotification();
193
194     const TestGlAbstraction::BufferDataCalls& bufferDataCalls =
195       application.GetGlAbstraction().GetBufferDataCalls();
196
197     DALI_TEST_CHECK(drawTrace.FindMethod("DrawArrays"));
198
199     DALI_TEST_EQUALS(bufferDataCalls.size(), 3u, TEST_LOCATION);
200
201     DALI_TEST_EQUALS(bufferDataCalls[0], sizeof(texturedQuadVertexData), TEST_LOCATION);
202   }
203   // end of scope to let the buffer and geometry die; do another notification and render to get the deletion processed
204   application.SendNotification();
205   application.Render(0);
206
207   END_TEST;
208 }
209
210 int UtcDaliVertexBufferSetData02(void)
211 {
212   TestApplication application;
213
214   Property::Map texturedQuadVertexFormat;
215   texturedQuadVertexFormat["aPosition"]    = Property::VECTOR2;
216   texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
217
218   VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
219   DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
220
221   const float halfQuadSize = .5f;
222   struct TexturedQuadVertex
223   {
224     Vector2 position;
225     Vector2 textureCoordinates;
226   };
227   TexturedQuadVertex texturedQuadVertexData[4] = {
228     {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
229     {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
230     {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
231     {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
232
233   vertexBuffer.SetData(texturedQuadVertexData, 4);
234
235   Geometry geometry = Geometry::New();
236   geometry.AddVertexBuffer(vertexBuffer);
237
238   Shader   shader   = CreateShader();
239   Renderer renderer = Renderer::New(geometry, shader);
240   Actor    actor    = Actor::New();
241   actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
242   actor.AddRenderer(renderer);
243   application.GetScene().Add(actor);
244
245   application.SendNotification();
246   application.Render();
247
248   {
249     const TestGlAbstraction::BufferSubDataCalls& bufferSubDataCalls =
250       application.GetGlAbstraction().GetBufferSubDataCalls();
251
252     const TestGlAbstraction::BufferDataCalls& bufferDataCalls =
253       application.GetGlAbstraction().GetBufferDataCalls();
254
255     // Should be 1 (Flush standalone uniform buffer per each RenderScene)
256     DALI_TEST_EQUALS(bufferSubDataCalls.size(), 1u, TEST_LOCATION);
257     DALI_TEST_EQUALS(bufferDataCalls.size(), 2u, TEST_LOCATION);
258
259     DALI_TEST_EQUALS(bufferDataCalls[0], sizeof(texturedQuadVertexData), TEST_LOCATION);
260   }
261
262   // Re-upload the data on the vertexBuffer
263   vertexBuffer.SetData(texturedQuadVertexData, 4);
264
265   application.SendNotification();
266   application.Render(0);
267
268   END_TEST;
269 }
270
271 int UtcDaliVertexBufferMapInitializerList(void)
272 {
273   TestApplication application;
274
275   Property::Map texturedQuadVertexFormat = Property::Map{{"aPosition", Property::VECTOR2},
276                                                          {"aTexCoord", Property::VECTOR2},
277                                                          {"aColor", Property::VECTOR4}};
278
279   try
280   {
281     VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
282     tet_result(TET_PASS);
283   }
284   catch(Dali::DaliException& e)
285   {
286     // Shouldn't assert any more
287     tet_result(TET_FAIL);
288   }
289   END_TEST;
290 }
291
292 int UtcDaliVertexBufferInvalidTypeN01(void)
293 {
294   TestApplication application;
295
296   Property::Map texturedQuadVertexFormat;
297   texturedQuadVertexFormat["aPosition"]    = Property::MAP;
298   texturedQuadVertexFormat["aVertexCoord"] = Property::STRING;
299
300   try
301   {
302     VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
303     tet_result(TET_FAIL);
304   }
305   catch(Dali::DaliException& e)
306   {
307     DALI_TEST_ASSERT(e, "Property::Type not supported in VertexBuffer", TEST_LOCATION);
308   }
309   END_TEST;
310 }
311
312 int UtcDaliVertexBufferInvalidTypeN02(void)
313 {
314   TestApplication application;
315
316   Property::Map texturedQuadVertexFormat = Property::Map{{"aPosition", Property::MAP},
317                                                          {"aTexCoord", Property::STRING},
318                                                          {"aColor", Property::VECTOR4}};
319
320   try
321   {
322     VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
323     tet_result(TET_FAIL);
324   }
325   catch(Dali::DaliException& e)
326   {
327     DALI_TEST_ASSERT(e, "Property::Type not supported in VertexBuffer", TEST_LOCATION);
328   }
329   END_TEST;
330 }
331
332 int UtcDaliVertexBufferSetDataNegative(void)
333 {
334   TestApplication    application;
335   Dali::VertexBuffer instance;
336   try
337   {
338     void*         arg1(nullptr);
339     unsigned long arg2(0u);
340     instance.SetData(arg1, arg2);
341     DALI_TEST_CHECK(false); // Should not get here
342   }
343   catch(...)
344   {
345     DALI_TEST_CHECK(true); // We expect an assert
346   }
347   END_TEST;
348 }
349
350 int UtcDaliVertexBufferGetSizeNegative(void)
351 {
352   TestApplication    application;
353   Dali::VertexBuffer instance;
354   try
355   {
356     instance.GetSize();
357     DALI_TEST_CHECK(false); // Should not get here
358   }
359   catch(...)
360   {
361     DALI_TEST_CHECK(true); // We expect an assert
362   }
363   END_TEST;
364 }
365
366 int UtcDaliVertexBufferSetDivisor(void)
367 {
368   TestApplication application;
369
370   Property::Map texturedQuadVertexFormat;
371   texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
372   texturedQuadVertexFormat["aTexCoord"] = Property::VECTOR2;
373
374   Property::Map instanceFormat{{"aTranslate", Property::VECTOR2}, {"aColor", Property::VECTOR4}};
375
376   VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
377   DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
378
379   DALI_TEST_EQUALS(0, vertexBuffer.GetDivisor(), TEST_LOCATION);
380
381   VertexBuffer instanceBuffer = VertexBuffer::New(instanceFormat);
382   DALI_TEST_EQUALS((bool)instanceBuffer, true, TEST_LOCATION);
383
384   const float halfQuadSize = .5f;
385   struct TexturedQuadVertex
386   {
387     Vector2 position;
388     Vector2 textureCoordinates;
389   };
390   TexturedQuadVertex texturedQuadVertexData[4] = {
391     {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
392     {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
393     {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
394     {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
395
396   vertexBuffer.SetData(texturedQuadVertexData, 4);
397
398   struct InstanceData
399   {
400     Vector2 translate;
401     Vector4 color;
402   };
403
404   InstanceData instanceData[] = {{Vector2(12, 33), Color::WHITE},
405                                  {Vector2(-2000, 43), Color::BLUE},
406                                  {Vector2(200, 43), Color::GREEN},
407                                  {Vector2(-243, 43), Color::TURQUOISE},
408                                  {Vector2(192, 43), Color::CYAN},
409                                  {Vector2(-2000, 43), Color::MAGENTA},
410                                  {Vector2(-292, 393), Color::BLUE},
411                                  {Vector2(-499, 128), Color::BLUE},
412                                  {Vector2(328, 43), Color::BLUE},
413                                  {Vector2(726, 43), Color::BLUE}};
414   instanceBuffer.SetData(instanceData, sizeof(instanceData) / sizeof(InstanceData));
415   instanceBuffer.SetDivisor(1);
416   DALI_TEST_EQUALS(1, instanceBuffer.GetDivisor(), TEST_LOCATION);
417
418   Geometry geometry = Geometry::New();
419   geometry.AddVertexBuffer(vertexBuffer);
420   geometry.AddVertexBuffer(instanceBuffer);
421
422   Shader   shader   = CreateShader();
423   Renderer renderer = Renderer::New(geometry, shader);
424   Actor    actor    = Actor::New();
425   actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
426   actor.AddRenderer(renderer);
427   application.GetScene().Add(actor);
428
429   TestGlAbstraction& gl          = application.GetGlAbstraction();
430   auto&              bufferTrace = gl.GetBufferTrace();
431   auto&              drawTrace   = gl.GetDrawTrace();
432   bufferTrace.Enable(true);
433   drawTrace.Enable(true);
434
435   application.SendNotification();
436   application.Render();
437
438   TraceCallStack::NamedParams params;
439   params["divisor"] << "1";
440   DALI_TEST_CHECK(bufferTrace.FindMethodAndParams("VertexAttribDivisor", params));
441
442   TraceCallStack::NamedParams params2;
443   DALI_TEST_CHECK(drawTrace.FindMethodAndGetParameters("DrawArraysInstanced", params2));
444   std::ostringstream oss;
445   oss << sizeof(instanceData) / sizeof(InstanceData);
446   DALI_TEST_EQUALS(params2["instanceCount"].str(), oss.str(), TEST_LOCATION);
447   END_TEST;
448 }