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