462fc9cb72530bcd1f2997a66d642c648555847d
[platform/core/uifw/dali-core.git] / vertex-buffer-impl.cpp
1 /*
2  * Copyright (c) 2021 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 // CLASS HEADER
19 #include <dali/internal/event/rendering/vertex-buffer-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/update/manager/update-manager.h>
23 #include <dali/public-api/rendering/vertex-buffer.h>
24
25 #if defined(ANDROID) || defined(WIN32) || defined(__APPLE__)
26 namespace std
27 {
28 uint64_t _Hash_bytes(const void* bytes, uint64_t size, uint64_t seed)
29 {
30   for(uint64_t i = 0; i < size; i++)
31   {
32     seed = seed * 31 + reinterpret_cast<const unsigned char*>(bytes)[i];
33   }
34
35   return seed;
36 }
37 } // namespace std
38 #endif
39
40 namespace Dali
41 {
42 namespace Internal
43 {
44 namespace
45 {
46 /**
47  * Calculate the alignment requirements of a type
48  *
49  * This is used to calculate the memory alignment requirements of a type
50  * It creates a structure with a dummy char and a member of the type we want to check
51  * this will cause the second member to be aligned by it's alignment requirement.
52  */
53 template<Property::Type type>
54 struct PropertyImplementationTypeAlignment
55 {
56   // Create a structure that forces alignment of the data type
57   struct TestStructure
58   {
59     char                                            oneChar; ///< Member with sizeof() == 1
60     typename PropertyImplementationType<type>::Type data;
61   };
62   enum
63   {
64     VALUE = offsetof(TestStructure, data)
65   };
66 };
67
68 uint32_t GetPropertyImplementationAlignment(Property::Type& propertyType)
69 {
70   uint32_t alignment = 0u;
71
72   switch(propertyType)
73   {
74     case Property::BOOLEAN:
75     {
76       alignment = PropertyImplementationTypeAlignment<Property::BOOLEAN>::VALUE;
77       break;
78     }
79     case Property::INTEGER:
80     {
81       alignment = PropertyImplementationTypeAlignment<Property::INTEGER>::VALUE;
82       break;
83     }
84     case Property::FLOAT:
85     {
86       alignment = PropertyImplementationTypeAlignment<Property::FLOAT>::VALUE;
87       break;
88     }
89     case Property::VECTOR2:
90     {
91       alignment = PropertyImplementationTypeAlignment<Property::VECTOR2>::VALUE;
92       break;
93     }
94     case Property::VECTOR3:
95     {
96       alignment = PropertyImplementationTypeAlignment<Property::VECTOR3>::VALUE;
97       break;
98     }
99     case Property::VECTOR4:
100     {
101       alignment = PropertyImplementationTypeAlignment<Property::VECTOR4>::VALUE;
102       break;
103     }
104     case Property::MATRIX3:
105     {
106       alignment = PropertyImplementationTypeAlignment<Property::MATRIX3>::VALUE;
107       break;
108     }
109     case Property::MATRIX:
110     {
111       alignment = PropertyImplementationTypeAlignment<Property::MATRIX>::VALUE;
112       break;
113     }
114     case Property::RECTANGLE:
115     {
116       alignment = PropertyImplementationTypeAlignment<Property::RECTANGLE>::VALUE;
117       break;
118     }
119     case Property::ROTATION:
120     {
121       alignment = PropertyImplementationTypeAlignment<Property::ROTATION>::VALUE;
122       break;
123     }
124     case Property::NONE:
125     case Property::STRING:
126     case Property::ARRAY:
127     case Property::MAP:
128     case Property::EXTENTS:
129     {
130       // already handled by higher level code
131     }
132   }
133
134   return alignment;
135 }
136
137 } // unnamed namespace
138
139 VertexBufferPtr VertexBuffer::New(Dali::Property::Map& format)
140 {
141   DALI_ASSERT_ALWAYS(format.Count() && "Format cannot be empty.");
142
143   VertexBufferPtr vertexBuffer(new VertexBuffer());
144   vertexBuffer->Initialize(format);
145
146   return vertexBuffer;
147 }
148
149 void VertexBuffer::SetData(const void* data, uint32_t size)
150 {
151   mSize = size; // size is the number of elements
152
153   uint32_t bufferSize = mBufferFormatSize * mSize;
154
155   // create a new DALi vector to store the buffer data
156   // the heap allocated vector will end up being owned by Render::VertexBuffer
157   OwnerPointer<Vector<uint8_t> > bufferCopy = new Dali::Vector<uint8_t>();
158   bufferCopy->Resize(bufferSize);
159
160   // copy the data
161   const uint8_t* source      = static_cast<const uint8_t*>(data);
162   uint8_t*       destination = &((*bufferCopy)[0]);
163   std::copy(source, source + bufferSize, destination);
164
165   // Ownership of the bufferCopy is passed to the message ( uses an owner pointer )
166   SceneGraph::SetVertexBufferData(mEventThreadServices.GetUpdateManager(), *mRenderObject, bufferCopy, mSize);
167 }
168
169 uint32_t VertexBuffer::GetSize() const
170 {
171   return mSize;
172 }
173
174 const Render::VertexBuffer* VertexBuffer::GetRenderObject() const
175 {
176   return mRenderObject;
177 }
178
179 VertexBuffer::~VertexBuffer()
180 {
181   if(EventThreadServices::IsCoreRunning() && mRenderObject)
182   {
183     SceneGraph::RemoveVertexBuffer(mEventThreadServices.GetUpdateManager(), *mRenderObject);
184   }
185 }
186
187 VertexBuffer::VertexBuffer()
188 : mEventThreadServices(EventThreadServices::Get()),
189   mRenderObject(nullptr),
190   mBufferFormatSize(0),
191   mSize(0)
192 {
193 }
194
195 void VertexBuffer::Initialize(Dali::Property::Map& formatMap)
196 {
197   mRenderObject = new Render::VertexBuffer();
198   OwnerPointer<Render::VertexBuffer> transferOwnership(mRenderObject);
199   SceneGraph::AddVertexBuffer(mEventThreadServices.GetUpdateManager(), transferOwnership);
200
201   uint32_t numComponents = static_cast<uint32_t>(formatMap.Count());
202
203   // Create the format
204   OwnerPointer<Render::VertexBuffer::Format> format = new Render::VertexBuffer::Format();
205   format->components.resize(numComponents);
206
207   uint32_t currentAlignment     = 0u;
208   uint32_t maxAlignmentRequired = 0u;
209
210   for(uint32_t i = 0u; i < numComponents; ++i)
211   {
212     KeyValuePair component = formatMap.GetKeyValue(i);
213
214     // Get the name
215     if(component.first.type == Property::Key::INDEX)
216     {
217       continue;
218     }
219     format->components[i].name = ConstString(component.first.stringKey);
220
221     // enums are stored in the map as int
222     Property::Type type = Property::Type(component.second.Get<int>());
223
224     // Get the size and alignment
225     if((type == Property::NONE) ||
226        (type == Property::STRING) ||
227        (type == Property::ARRAY) ||
228        (type == Property::MAP))
229     {
230       DALI_ABORT("Property::Type not supported in VertexBuffer");
231     }
232     uint32_t elementSize      = GetPropertyImplementationSize(type);
233     uint32_t elementAlignment = GetPropertyImplementationAlignment(type);
234
235     // check if current alignment is compatible with new member
236     if(uint32_t offset = currentAlignment % elementAlignment)
237     {
238       // Not compatible, realign
239       currentAlignment = currentAlignment + elementSize - offset;
240     }
241
242     // write to the format
243     format->components[i].size   = elementSize;
244     format->components[i].offset = currentAlignment;
245     format->components[i].type   = type;
246
247     // update offset
248     currentAlignment += elementSize;
249
250     // update max alignment requirement
251     if(elementAlignment > maxAlignmentRequired)
252     {
253       maxAlignmentRequired = elementAlignment;
254     }
255   }
256
257   // Check the alignment for the maxAlignment required to calculate the size of the format
258   if(maxAlignmentRequired != 0)
259   {
260     if(uint32_t offset = currentAlignment % maxAlignmentRequired)
261     {
262       // Not compatible, realign
263       currentAlignment = currentAlignment + maxAlignmentRequired - offset;
264     }
265   }
266
267   // Set the format size
268   format->size = currentAlignment;
269
270   mBufferFormatSize = format->size;
271
272   SceneGraph::SetVertexBufferFormat(mEventThreadServices.GetUpdateManager(), *mRenderObject, format);
273 }
274
275 uint32_t GetPropertyImplementationSize(Property::Type& propertyType)
276 {
277   uint32_t size = 0u;
278
279   switch(propertyType)
280   {
281     case Property::BOOLEAN:
282     {
283       size = sizeof(PropertyImplementationType<Property::BOOLEAN>::Type);
284       break;
285     }
286     case Property::INTEGER:
287     {
288       size = sizeof(PropertyImplementationType<Property::INTEGER>::Type);
289       break;
290     }
291     case Property::FLOAT:
292     {
293       size = sizeof(PropertyImplementationType<Property::FLOAT>::Type);
294       break;
295     }
296     case Property::VECTOR2:
297     {
298       size = sizeof(PropertyImplementationType<Property::VECTOR2>::Type);
299       break;
300     }
301     case Property::VECTOR3:
302     {
303       size = sizeof(PropertyImplementationType<Property::VECTOR3>::Type);
304       break;
305     }
306     case Property::VECTOR4:
307     {
308       size = sizeof(PropertyImplementationType<Property::VECTOR4>::Type);
309       break;
310     }
311     case Property::MATRIX3:
312     {
313       size = sizeof(PropertyImplementationType<Property::MATRIX3>::Type);
314       break;
315     }
316     case Property::MATRIX:
317     {
318       size = sizeof(PropertyImplementationType<Property::MATRIX>::Type);
319       break;
320     }
321     case Property::RECTANGLE:
322     {
323       size = sizeof(PropertyImplementationType<Property::RECTANGLE>::Type);
324       break;
325     }
326     case Property::ROTATION:
327     {
328       size = sizeof(PropertyImplementationType<Property::ROTATION>::Type);
329       break;
330     }
331     case Property::NONE:
332     case Property::STRING:
333     case Property::ARRAY:
334     case Property::MAP:
335     case Property::EXTENTS:
336     {
337       // already handled by higher level code
338     }
339   }
340
341   return size;
342 }
343
344 } // namespace Internal
345 } // namespace Dali