Correctly calculate alignment of members in propertyBuffers.
[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/public-api/object/property-buffer.h> // Dali::Internal::PropertyBuffer
26 #include <dali/internal/event/common/object-impl-helper.h> // Dali::Internal::ObjectHelper
27 #include <dali/internal/event/common/property-helper.h> // DALI_PROPERTY_TABLE_BEGIN, DALI_PROPERTY, DALI_PROPERTY_TABLE_END
28 #include <dali/internal/update/common/scene-graph-property-buffer.h>
29 #include <dali/internal/update/manager/update-manager.h>
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35
36 using SceneGraph::PropertyBufferMetadata::Format;
37 using SceneGraph::PropertyBufferMetadata::Component;
38
39 namespace
40 {
41
42 /**
43  *            |name    |type             |writable|animatable|constraint-input|enum for index-checking|
44  */
45 DALI_PROPERTY_TABLE_BEGIN
46 DALI_PROPERTY( "size",          UNSIGNED_INTEGER, true, false,  true,   Dali::PropertyBuffer::Property::SIZE )
47 DALI_PROPERTY( "buffer-format", MAP,              false, false, false,  Dali::PropertyBuffer::Property::BUFFER_FORMAT )
48 DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX )
49
50 const ObjectImplHelper<DEFAULT_PROPERTY_COUNT> PROPERTY_BUFFER_IMPL = { DEFAULT_PROPERTY_DETAILS };
51
52 unsigned int GetPropertyImplementationSize( Property::Type& propertyType )
53 {
54   unsigned int size = 0u;
55
56   switch( propertyType )
57   {
58     case Property::NONE:
59     case Property::TYPE_COUNT:
60     case Property::STRING:
61     case Property::ARRAY:
62     case Property::MAP:
63     {
64       DALI_ASSERT_ALWAYS( "No size for properties with no type, or dynamic sizes" );
65       break;
66     }
67     case Property::BOOLEAN:
68     {
69       size = sizeof( PropertyImplementationType< Property::BOOLEAN >::Type );
70       break;
71     }
72     case Property::INTEGER:
73     {
74       size = sizeof( PropertyImplementationType< Property::INTEGER >::Type );
75       break;
76     }
77     case Property::UNSIGNED_INTEGER:
78     {
79       size = sizeof( PropertyImplementationType< Property::UNSIGNED_INTEGER >::Type );
80       break;
81     }
82     case Property::FLOAT:
83     {
84       size = sizeof( PropertyImplementationType< Property::FLOAT >::Type );
85       break;
86     }
87     case Property::VECTOR2:
88     {
89       size = sizeof( PropertyImplementationType< Property::VECTOR2 >::Type );
90       break;
91     }
92     case Property::VECTOR3:
93     {
94       size = sizeof( PropertyImplementationType< Property::VECTOR3 >::Type );
95       break;
96     }
97     case Property::VECTOR4:
98     {
99       size = sizeof( PropertyImplementationType< Property::VECTOR4 >::Type );
100       break;
101     }
102     case Property::MATRIX3:
103     {
104       size = sizeof( PropertyImplementationType< Property::MATRIX3 >::Type );
105       break;
106     }
107     case Property::MATRIX:
108     {
109       size = sizeof( PropertyImplementationType< Property::MATRIX >::Type );
110       break;
111     }
112     case Property::RECTANGLE:
113     {
114       size = sizeof( PropertyImplementationType< Property::RECTANGLE >::Type );
115       break;
116     }
117     case Property::ROTATION:
118     {
119       size = sizeof( PropertyImplementationType< Property::ROTATION >::Type );
120       break;
121     }
122   }
123
124   return size;
125 }
126
127 /**
128  * Calculate the alignment requirements of a type
129  *
130  * This is used to calculate the memory alignment requirements of a type
131  * It creates a structure with a dummy char and a member of the type we want to check
132  * this will cause the second member to be aligned by it's alignment requirement.
133  */
134 template<Property::Type type>
135 struct PropertyImplementationTypeAlignment
136 {
137   // Create a structure that forces alignment of the data type
138   struct TestStructure
139   {
140     char oneChar;  ///< Member with sizeof() == 1
141     typename PropertyImplementationType<type>::Type data;
142   };
143   enum { VALUE = offsetof( TestStructure, data ) };
144 };
145
146 unsigned int GetPropertyImplementationAlignment( Property::Type& propertyType )
147 {
148   unsigned int alignment = 0u;
149
150   switch( propertyType )
151   {
152     case Property::NONE:
153     case Property::TYPE_COUNT:
154     case Property::STRING:
155     case Property::ARRAY:
156     case Property::MAP:
157     {
158       DALI_ASSERT_ALWAYS( "No size for properties with no type, or dynamic sizes" );
159       break;
160     }
161     case Property::BOOLEAN:
162     {
163       alignment = sizeof( PropertyImplementationTypeAlignment< Property::BOOLEAN >::VALUE );
164       break;
165     }
166     case Property::INTEGER:
167     {
168       alignment = sizeof( PropertyImplementationTypeAlignment< Property::INTEGER >::VALUE );
169       break;
170     }
171     case Property::UNSIGNED_INTEGER:
172     {
173       alignment = sizeof( PropertyImplementationTypeAlignment< Property::UNSIGNED_INTEGER >::VALUE );
174       break;
175     }
176     case Property::FLOAT:
177     {
178       alignment = sizeof( PropertyImplementationTypeAlignment< Property::FLOAT >::VALUE );
179       break;
180     }
181     case Property::VECTOR2:
182     {
183       alignment = sizeof( PropertyImplementationTypeAlignment< Property::VECTOR2 >::VALUE );
184       break;
185     }
186     case Property::VECTOR3:
187     {
188       alignment = sizeof( PropertyImplementationTypeAlignment< Property::VECTOR3 >::VALUE );
189       break;
190     }
191     case Property::VECTOR4:
192     {
193       alignment = sizeof( PropertyImplementationTypeAlignment< Property::VECTOR4 >::VALUE );
194       break;
195     }
196     case Property::MATRIX3:
197     {
198       alignment = sizeof( PropertyImplementationTypeAlignment< Property::MATRIX3 >::VALUE );
199       break;
200     }
201     case Property::MATRIX:
202     {
203       alignment = sizeof( PropertyImplementationTypeAlignment< Property::MATRIX >::VALUE );
204       break;
205     }
206     case Property::RECTANGLE:
207     {
208       alignment = sizeof( PropertyImplementationTypeAlignment< Property::RECTANGLE >::VALUE );
209       break;
210     }
211     case Property::ROTATION:
212     {
213       alignment = sizeof( PropertyImplementationTypeAlignment< Property::ROTATION >::VALUE );
214       break;
215     }
216   }
217
218   return alignment;
219 }
220
221 } // unnamed namespace
222
223 PropertyBufferPtr PropertyBuffer::New()
224 {
225   PropertyBufferPtr propertyBuffer( new PropertyBuffer() );
226   propertyBuffer->Initialize();
227
228   return propertyBuffer;
229 }
230
231 void PropertyBuffer::SetSize( std::size_t size )
232 {
233   mSize = size;
234
235   SizeChanged();
236
237   SceneGraph::SetSizeMessage( GetEventThreadServices(),
238                               *mSceneObject,
239                               mSize );
240 }
241
242 std::size_t PropertyBuffer::GetSize() const
243 {
244   return mSize;
245 }
246
247 void PropertyBuffer::SetData( const void* data )
248 {
249   DALI_ASSERT_DEBUG( mFormat.Count() && "Format must be set before setting the data." );
250
251   DALI_ASSERT_ALWAYS( mSize && "Size of the buffer must be set before setting the data." );
252
253   const char* source = static_cast<const char*>( data );
254   std::copy( source, source + mBuffer.Size(), &mBuffer[0] );
255
256   SceneGraph::SetDataMessage( GetEventThreadServices(),
257                               *mSceneObject,
258                               new SceneGraph::PropertyBuffer::BufferType( mBuffer ) );
259 }
260
261 Dali::Property::Index PropertyBuffer::GetPropertyIndex( const std::string name, std::size_t index )
262 {
263   //TODO: MESH_REWORK
264   DALI_ASSERT_ALWAYS( false && "MESH_REWORK" );
265   return 0;
266 }
267
268 const SceneGraph::PropertyBuffer* PropertyBuffer::GetPropertyBufferSceneObject() const
269 {
270   return mSceneObject;
271 }
272
273 void PropertyBuffer::SetType( Dali::PropertyBuffer::Type type )
274 {
275   DALI_ASSERT_DEBUG( mType == Dali::PropertyBuffer::TYPE_COUNT && "Type can only be set once." );
276   DALI_ASSERT_DEBUG( type != Dali::PropertyBuffer::TYPE_COUNT && "Type must be set to a valid value." );
277
278   mType = type;
279 }
280
281 void PropertyBuffer::SetFormat( Dali::Property::Map& format )
282 {
283   DALI_ASSERT_ALWAYS( format.Count() && "Format cannot be empty." );
284
285   DALI_ASSERT_DEBUG( 0 == mFormat.Count() && "Format of property buffer can only be set once." );
286
287   mFormat = format;
288
289   FormatChanged();
290 }
291
292 unsigned int PropertyBuffer::GetDefaultPropertyCount() const
293 {
294   return PROPERTY_BUFFER_IMPL.GetDefaultPropertyCount();
295 }
296
297 void PropertyBuffer::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
298 {
299   PROPERTY_BUFFER_IMPL.GetDefaultPropertyIndices( indices );
300 }
301
302 const char* PropertyBuffer::GetDefaultPropertyName(Property::Index index) const
303 {
304   return PROPERTY_BUFFER_IMPL.GetDefaultPropertyName( index );
305 }
306
307 Property::Index PropertyBuffer::GetDefaultPropertyIndex( const std::string& name ) const
308 {
309   return PROPERTY_BUFFER_IMPL.GetDefaultPropertyIndex( name );
310 }
311
312 bool PropertyBuffer::IsDefaultPropertyWritable( Property::Index index ) const
313 {
314   return PROPERTY_BUFFER_IMPL.IsDefaultPropertyWritable( index );
315 }
316
317 bool PropertyBuffer::IsDefaultPropertyAnimatable( Property::Index index ) const
318 {
319   return PROPERTY_BUFFER_IMPL.IsDefaultPropertyAnimatable( index );
320 }
321
322 bool PropertyBuffer::IsDefaultPropertyAConstraintInput( Property::Index index ) const
323 {
324   return PROPERTY_BUFFER_IMPL.IsDefaultPropertyAConstraintInput( index );
325 }
326
327 Property::Type PropertyBuffer::GetDefaultPropertyType( Property::Index index ) const
328 {
329   return PROPERTY_BUFFER_IMPL.GetDefaultPropertyType( index );
330 }
331
332 void PropertyBuffer::SetDefaultProperty( Property::Index index,
333                                          const Property::Value& propertyValue )
334 {
335   switch( index )
336   {
337     case Dali::PropertyBuffer::Property::SIZE:
338     {
339       SetSize( propertyValue.Get<int>() );
340       break;
341     }
342     case Dali::PropertyBuffer::Property::BUFFER_FORMAT:
343     {
344       DALI_ASSERT_ALWAYS( 0 && "MESH_REWORK" );
345       break;
346     }
347   }
348 }
349
350 void PropertyBuffer::SetSceneGraphProperty( Property::Index index,
351                                             const PropertyMetadata& entry,
352                                             const Property::Value& value )
353 {
354   PROPERTY_BUFFER_IMPL.SetSceneGraphProperty( GetEventThreadServices(), this, index, entry, value );
355 }
356
357 Property::Value PropertyBuffer::GetDefaultProperty( Property::Index index ) const
358 {
359   Property::Value value;
360
361   switch( index )
362   {
363     case Dali::PropertyBuffer::Property::SIZE:
364     {
365       value = static_cast<int>( GetSize() ); // @todo MESH_REWORK Add a size_t type to PropertyValue
366       break;
367     }
368     case Dali::PropertyBuffer::Property::BUFFER_FORMAT:
369     {
370       DALI_ASSERT_ALWAYS( 0 && "MESH_REWORK" );
371       break;
372     }
373   }
374   return value;
375 }
376
377 const SceneGraph::PropertyOwner* PropertyBuffer::GetPropertyOwner() const
378 {
379   return mSceneObject;
380 }
381
382 const SceneGraph::PropertyOwner* PropertyBuffer::GetSceneObject() const
383 {
384   return mSceneObject;
385 }
386
387 const SceneGraph::PropertyBase* PropertyBuffer::GetSceneObjectAnimatableProperty( Property::Index index ) const
388 {
389   DALI_ASSERT_ALWAYS( IsPropertyAnimatable(index) && "Property is not animatable" );
390   const SceneGraph::PropertyBase* property = NULL;
391
392   if( OnStage() )
393   {
394     property = PROPERTY_BUFFER_IMPL.GetRegisteredSceneGraphProperty(
395       this,
396       &PropertyBuffer::FindAnimatableProperty,
397       &PropertyBuffer::FindCustomProperty,
398       index );
399
400     if( property == NULL && index < DEFAULT_PROPERTY_MAX_COUNT )
401     {
402       DALI_ASSERT_ALWAYS( 0 && "Property is not animatable" );
403     }
404   }
405
406   return property;
407 }
408
409 const PropertyInputImpl* PropertyBuffer::GetSceneObjectInputProperty( Property::Index index ) const
410 {
411   const PropertyInputImpl* property = NULL;
412
413   if( OnStage() )
414   {
415     const SceneGraph::PropertyBase* baseProperty =
416       PROPERTY_BUFFER_IMPL.GetRegisteredSceneGraphProperty( this,
417                                                             &PropertyBuffer::FindAnimatableProperty,
418                                                             &PropertyBuffer::FindCustomProperty,
419                                                             index );
420     property = static_cast<const PropertyInputImpl*>( baseProperty );
421
422     if( property == NULL && index < DEFAULT_PROPERTY_MAX_COUNT )
423     {
424       if( index == Dali::PropertyBuffer::Property::SIZE )
425       {
426         // @todo MESH_REWORK
427         DALI_ASSERT_ALWAYS( 0 && "MESH_REWORK" );
428       }
429     }
430   }
431
432   return property;
433 }
434
435 int PropertyBuffer::GetPropertyComponentIndex( Property::Index index ) const
436 {
437   return PROPERTY_BUFFER_IMPL.GetPropertyComponentIndex( index );
438 }
439
440 bool PropertyBuffer::OnStage() const
441 {
442   return mOnStage;
443 }
444
445 void PropertyBuffer::Connect()
446 {
447   mOnStage = true;
448 }
449
450 void PropertyBuffer::Disconnect()
451 {
452   mOnStage = false;
453 }
454
455 PropertyBuffer::~PropertyBuffer()
456 {
457 }
458
459 PropertyBuffer::PropertyBuffer()
460 : mSceneObject( NULL ),
461   mBufferFormat( NULL ),
462   mSize( 0 ),
463   mType( Dali::PropertyBuffer::TYPE_COUNT ),
464   mOnStage( false )
465 {
466 }
467
468 void PropertyBuffer::Initialize()
469 {
470   EventThreadServices& eventThreadServices = GetEventThreadServices();
471   SceneGraph::UpdateManager& updateManager = eventThreadServices.GetUpdateManager();
472
473   DALI_ASSERT_ALWAYS( EventThreadServices::IsCoreRunning() && "Core is not running" );
474
475   mSceneObject = new SceneGraph::PropertyBuffer();
476   AddMessage( updateManager, updateManager.GetPropertyBufferOwner(), *mSceneObject );
477 }
478
479 void PropertyBuffer::FormatChanged()
480 {
481   size_t numComponents = mFormat.Count();
482
483   // Create the format
484   DALI_ASSERT_DEBUG( mBufferFormat == NULL && "PropertyFormat should not be set yet" );
485   Format* bufferFormat = new Format();
486   bufferFormat->components.resize( numComponents );
487
488   unsigned int currentAlignment = 0u;
489   unsigned int maxAlignmentRequired = 0u;
490
491   for( size_t i = 0u; i < numComponents; ++i )
492   {
493     StringValuePair component = mFormat.GetPair( i );
494
495     // Get the name
496     bufferFormat->components[i].name = component.first;
497
498     // enums are stored in the map as int
499     Property::Type type = Property::Type( component.second.Get<int>() );
500
501     // Get the size and alignment
502     unsigned int elementSize = GetPropertyImplementationSize( type );
503     unsigned int elementAlignment = GetPropertyImplementationAlignment( type );
504
505     // check if current alignment is compatible with new member
506     if( unsigned int offset = currentAlignment % elementAlignment )
507     {
508       // Not compatible, realign
509       currentAlignment = currentAlignment + elementSize - offset;
510     }
511
512     // write to the format
513     bufferFormat->components[i].size = elementSize;
514     bufferFormat->components[i].offset = currentAlignment;
515
516     // update offset
517     currentAlignment += elementSize;
518
519     // update max alignment requirement
520     if( elementAlignment > maxAlignmentRequired )
521     {
522       maxAlignmentRequired = elementAlignment;
523     }
524
525   }
526
527   // Check the alignment for the maxAlignment required to calculate the size of the format
528   if( unsigned int offset = currentAlignment % maxAlignmentRequired )
529   {
530     // Not compatible, realign
531     currentAlignment = currentAlignment + maxAlignmentRequired - offset;
532   }
533
534   // Set the format size
535   bufferFormat->size = currentAlignment;
536
537   mBufferFormat = bufferFormat;
538
539   SceneGraph::SetFormatMessage( GetEventThreadServices(),
540                                 *mSceneObject,
541                                 bufferFormat );
542
543   if( mSize )
544   {
545     SizeChanged();
546   }
547 }
548
549 void PropertyBuffer::SizeChanged()
550 {
551   // Check if format and size have been set yet
552   if( mBufferFormat != NULL )
553   {
554     unsigned int bufferSize = mBufferFormat->size * mSize;
555     mBuffer.Resize( bufferSize );
556   }
557 }
558
559 } // namespace Internal
560 } // namespace Dali