ce43396afc36625737c19ade7ed3fff02c59b3c4
[platform/core/uifw/dali-core.git] / dali / internal / event / render-tasks / render-task-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/render-tasks/render-task-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/common/dali-common.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/internal/event/common/event-thread-services.h>
28 #include <dali/internal/event/actors/actor-impl.h>
29 #include <dali/internal/event/actors/camera-actor-impl.h>
30 #include <dali/internal/event/common/property-helper.h>
31 #include <dali/internal/event/common/stage-impl.h>
32 #include <dali/internal/event/common/projection.h>
33 #include <dali/internal/event/images/frame-buffer-image-impl.h>
34 #include <dali/internal/update/nodes/node.h>
35 #include <dali/internal/event/render-tasks/render-task-list-impl.h>
36 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
37
38 #if defined(DEBUG_ENABLED)
39 namespace
40 {
41 Debug::Filter* gLogRender = Debug::Filter::New(Debug::Concise, false, "LOG_RENDER_TASK");
42 }
43 #endif
44
45 namespace Dali
46 {
47
48 namespace Internal
49 {
50
51 namespace // For internal properties
52 {
53
54 // Properties
55
56 //              Name                 Type     writable animatable constraint-input  enum for index-checking
57 DALI_PROPERTY_TABLE_BEGIN
58 DALI_PROPERTY( "viewportPosition",   VECTOR2,    true,    true,    true,    Dali::RenderTask::Property::VIEWPORT_POSITION )
59 DALI_PROPERTY( "viewportSize",       VECTOR2,    true,    true,    true,    Dali::RenderTask::Property::VIEWPORT_SIZE     )
60 DALI_PROPERTY( "clearColor",         VECTOR4,    true,    true,    true,    Dali::RenderTask::Property::CLEAR_COLOR       )
61 DALI_PROPERTY_TABLE_END( DEFAULT_OBJECT_PROPERTY_START_INDEX )
62
63 // Signals
64
65 const char* const SIGNAL_FINISHED = "finished";
66
67 TypeRegistration mType( typeid( Dali::RenderTask ), typeid( Dali::BaseHandle ), NULL );
68
69 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &RenderTask::DoConnectSignal );
70
71 } // Unnamed namespace
72
73 RenderTask* RenderTask::New( bool isSystemLevel )
74 {
75   RenderTask* task( new RenderTask( isSystemLevel ) );
76
77   return task;
78 }
79
80 void RenderTask::SetSourceActor( Actor* actor )
81 {
82   const Stage* stage = Stage::GetCurrent();
83   if ( stage )
84   {
85     stage->GetRenderTaskList().SetExclusive( this, mExclusive );
86   }
87   mSourceConnector.SetActor( actor );
88 }
89
90 Actor* RenderTask::GetSourceActor() const
91 {
92   return mSourceConnector.mActor;
93 }
94
95 void RenderTask::SetExclusive( bool exclusive )
96 {
97   if ( mExclusive != exclusive )
98   {
99     mExclusive = exclusive;
100
101     const Stage* stage = Stage::GetCurrent();
102     if ( stage )
103     {
104       stage->GetRenderTaskList().SetExclusive( this, exclusive );
105     }
106
107     if ( mSceneObject )
108     {
109       // mSceneObject is being used in a separate thread; queue a message to set the value
110       SetExclusiveMessage( GetEventThreadServices(), *mSceneObject, mExclusive );
111     }
112   }
113 }
114
115 bool RenderTask::IsExclusive() const
116 {
117   return mExclusive;
118 }
119
120 void RenderTask::SetInputEnabled( bool enabled )
121 {
122   mInputEnabled = enabled;
123 }
124
125 bool RenderTask::GetInputEnabled() const
126 {
127   return mInputEnabled;
128 }
129
130 void RenderTask::SetCameraActor( CameraActor* cameraActor )
131 {
132   mCameraConnector.SetActor( cameraActor );
133 }
134
135 CameraActor* RenderTask::GetCameraActor() const
136 {
137   // camera connector can only point to camera actor
138   return static_cast< CameraActor* >( mCameraConnector.mActor );
139 }
140
141 void RenderTask::SetTargetFrameBuffer( Dali::FrameBufferImage image )
142 {
143   if ( mFrameBufferImage != image )
144   {
145     // if we have a scene object we need to track connection status and set frame buffer id as well as updating target frame buffer
146     if ( mSceneObject )
147     {
148       if(mFrameBufferImage)
149       {
150         GetImplementation(mFrameBufferImage).Disconnect();
151       }
152
153       // update target frame buffer
154       mFrameBufferImage = image;
155
156       unsigned int resourceId = 0;
157       bool isNativeFBO = false;
158       if( mFrameBufferImage )
159       {
160         Dali::Internal::FrameBufferImage& impl = GetImplementation( mFrameBufferImage );
161         impl.Connect();
162         resourceId = impl.GetResourceId();
163         isNativeFBO = impl.IsNativeFbo();
164       }
165
166       // mSceneObject is being used in a separate thread; queue a message to set the value
167       SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId, isNativeFBO );
168     }
169     else
170     {
171       // update target frame buffer
172       mFrameBufferImage = image;
173     }
174   }
175 }
176
177 Dali::FrameBufferImage RenderTask::GetTargetFrameBuffer() const
178 {
179   return mFrameBufferImage;
180 }
181
182 void RenderTask::SetScreenToFrameBufferFunction( ScreenToFrameBufferFunction conversionFunction )
183 {
184   mScreenToFrameBufferFunction = conversionFunction;
185 }
186
187 RenderTask::ScreenToFrameBufferFunction RenderTask::GetScreenToFrameBufferFunction() const
188 {
189   return mScreenToFrameBufferFunction;
190 }
191
192 void RenderTask::SetScreenToFrameBufferMappingActor( Actor* mappingActor )
193 {
194   mMappingConnector.SetActor( mappingActor );
195 }
196
197 Actor* RenderTask::GetScreenToFrameBufferMappingActor() const
198 {
199   return mMappingConnector.mActor;
200 }
201
202 void RenderTask::SetViewportPosition(const Vector2& value)
203 {
204   BakeViewportPositionMessage( GetEventThreadServices(), *mSceneObject, value );
205 }
206
207 Vector2 RenderTask::GetCurrentViewportPosition() const
208 {
209   return mSceneObject->GetViewportPosition( GetEventThreadServices().GetEventBufferIndex() );
210 }
211
212 void RenderTask::SetViewportSize(const Vector2& value)
213 {
214   BakeViewportSizeMessage( GetEventThreadServices(), *mSceneObject, value );
215 }
216
217 Vector2 RenderTask::GetCurrentViewportSize() const
218 {
219   return mSceneObject->GetViewportSize( GetEventThreadServices().GetEventBufferIndex() );
220 }
221
222 void RenderTask::SetViewport( const Viewport& viewport )
223 {
224   SetViewportPosition(Vector2(viewport.x, viewport.y));
225   SetViewportSize(Vector2(viewport.width, viewport.height));
226 }
227
228 void RenderTask::GetViewport( Viewport& viewPort ) const
229 {
230   BufferIndex bufferIndex = GetEventThreadServices().GetEventBufferIndex();
231
232   if(!mSceneObject->GetViewportEnabled( bufferIndex ))
233   {
234     if ( mFrameBufferImage )
235     {
236       viewPort.x = viewPort.y = 0;
237       viewPort.width = mFrameBufferImage.GetWidth();
238       viewPort.height = mFrameBufferImage.GetHeight();
239     }
240     else
241     {
242       Internal::Stage* stage = Internal::Stage::GetCurrent();
243       if ( stage )
244       {
245         Vector2 size( stage->GetSize() );
246         viewPort.x = viewPort.y = 0;
247         viewPort.width = size.width;
248         viewPort.height = size.height;
249       }
250     }
251   }
252   else
253   {
254     const Vector2& position = mSceneObject->GetViewportPosition(bufferIndex);
255     const Vector2& size = mSceneObject->GetViewportSize(bufferIndex);
256     viewPort.x = position.x;
257     viewPort.y = position.y;
258     viewPort.width = size.width;
259     viewPort.height = size.height;
260   }
261 }
262
263 void RenderTask::SetClearColor( const Vector4& color )
264 {
265   if ( mClearColor != color )
266   {
267     mClearColor = color;
268
269     if ( mSceneObject )
270     {
271       // mSceneObject is being used in a separate thread; queue a message to set the value
272       BakeClearColorMessage( GetEventThreadServices(), *mSceneObject, color );
273     }
274   }
275 }
276
277 const Vector4& RenderTask::GetClearColor() const
278 {
279   return mSceneObject->GetClearColor( GetEventThreadServices().GetEventBufferIndex() );
280 }
281
282 void RenderTask::SetClearEnabled( bool enabled )
283 {
284   if ( mClearEnabled != enabled )
285   {
286     mClearEnabled = enabled;
287
288     if ( mSceneObject )
289     {
290       // mSceneObject is being used in a separate thread; queue a message to set the value
291       SetClearEnabledMessage( GetEventThreadServices(), *mSceneObject, mClearEnabled );
292     }
293   }
294 }
295
296 bool RenderTask::GetClearEnabled() const
297 {
298   return mClearEnabled;
299 }
300
301 void RenderTask::SetCullMode( bool mode )
302 {
303   if ( mCullMode != mode )
304   {
305     mCullMode = mode;
306
307     if ( mSceneObject )
308     {
309       // mSceneObject is being used in a separate thread; queue a message to set the value
310       SetCullModeMessage( GetEventThreadServices(), *mSceneObject, mCullMode );
311     }
312   }
313 }
314
315 bool RenderTask::GetCullMode() const
316 {
317   return mCullMode;
318 }
319
320 void RenderTask::SetRefreshRate( unsigned int refreshRate )
321 {
322   DALI_LOG_TRACE_METHOD_FMT(gLogRender, "this:%p  rate:%d\n", this, refreshRate);
323   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::SetRefreshRate(this:%p, %d)\n", this, refreshRate);
324
325   mRefreshRate = refreshRate; // cached for GetRefreshRate()
326
327   // Note - even when refreshRate is the same as mRefreshRate, a message should be sent
328
329   if ( mSceneObject )
330   {
331     // mSceneObject is being used in a separate thread; queue a message to set the value
332     SetRefreshRateMessage( GetEventThreadServices(), *mSceneObject, refreshRate );
333   }
334 }
335
336 unsigned int RenderTask::GetRefreshRate() const
337 {
338   return mRefreshRate;
339 }
340
341 bool RenderTask::IsHittable( Vector2& screenCoords ) const
342 {
343   // True when input is enabled, source & camera actor are valid
344   bool inputEnabled( false );
345
346   Actor* sourceActor = GetSourceActor();
347   CameraActor* cameraActor = GetCameraActor();
348
349   if ( mInputEnabled  &&
350        NULL != sourceActor    &&
351        sourceActor->OnStage() &&
352        NULL != cameraActor    &&
353        cameraActor->OnStage() )
354   {
355     // If the actors are rendered off-screen, then the screen coordinates must be converted
356     // and the conversion function will tell us if they are inside or outside
357     if ( TranslateCoordinates( screenCoords ) )
358     {
359       // This is a suitable render-task for input handling
360       inputEnabled = true;
361     }
362   }
363
364   return inputEnabled;
365 }
366
367 bool RenderTask::TranslateCoordinates( Vector2& screenCoords ) const
368 {
369   // return true for on-screen tasks
370   bool inside( true );
371   // If the actors are rendered off-screen, then the screen coordinates must be converted
372   // the function should only be called for offscreen tasks
373   if( mFrameBufferImage && mMappingConnector.mActor )
374   {
375     CameraActor* localCamera = GetCameraActor();
376     StagePtr stage = Stage::GetCurrent();
377     if( stage )
378     {
379       CameraActor& defaultCamera = stage->GetDefaultCameraActor();
380       if( localCamera )
381       {
382         Viewport viewport;
383         Vector2 size( stage->GetSize() );
384         viewport.x = viewport.y = 0;
385         viewport.width = size.width;
386         viewport.height = size.height;
387
388         float localX, localY;
389         inside = mMappingConnector.mActor->ScreenToLocal(defaultCamera.GetViewMatrix(), defaultCamera.GetProjectionMatrix(), viewport, localX, localY, screenCoords.x, screenCoords.y);
390         Vector3 actorSize = mMappingConnector.mActor->GetCurrentSize();
391         if( inside && localX >= 0.f && localX <= actorSize.x && localY >= 0.f && localY <= actorSize.y)
392         {
393           screenCoords.x = localX;
394           screenCoords.y = localY;
395         }
396         else
397         {
398           inside = false;
399         }
400       }
401       else
402       {
403         inside = false;
404       }
405     }
406   }
407   else if ( mFrameBufferImage && mScreenToFrameBufferFunction )
408   {
409     inside = mScreenToFrameBufferFunction( screenCoords );
410   }
411   return inside;
412 }
413
414 bool RenderTask::IsSystemLevel() const
415 {
416   return mIsSystemLevel;
417 }
418
419 bool RenderTask::WorldToViewport(const Vector3 &position, float& viewportX, float& viewportY) const
420 {
421   CameraActor* cam = GetCameraActor();
422
423   Vector4 pos(position);
424   pos.w = 1.0;
425
426   Vector4 viewportPosition;
427
428   Viewport viewport;
429   GetViewport( viewport );
430
431   bool ok = ProjectFull(pos,
432                         cam->GetViewMatrix(),
433                         cam->GetProjectionMatrix(),
434                         viewport.x,
435                         viewport.y,
436                         viewport.width,
437                         viewport.height,
438                         viewportPosition);
439   if(ok)
440   {
441     viewportX = viewportPosition.x;
442     viewportY = viewportPosition.y;
443   }
444
445   return ok;
446 }
447
448 bool RenderTask::ViewportToLocal(Actor* actor, float viewportX, float viewportY, float &localX, float &localY) const
449 {
450   return actor->ScreenToLocal( *this, localX, localY, viewportX, viewportY );
451 }
452
453 SceneGraph::RenderTask* RenderTask::CreateSceneObject()
454 {
455   // This should only be called once, with no existing scene-object
456   DALI_ASSERT_DEBUG( NULL == mSceneObject );
457
458   // Keep the raw-pointer until DiscardSceneObject is called
459   mSceneObject = SceneGraph::RenderTask::New();
460
461   // if we have a frame buffer we need to track connection status then send a message to set the frame buffer id in case it has changed since last time we were on stage
462   unsigned int resourceId = 0;
463   bool isNativeFBO = false;
464   if( mFrameBufferImage )
465   {
466     Dali::Internal::FrameBufferImage& impl = GetImplementation( mFrameBufferImage );
467     impl.Connect();
468     resourceId = impl.GetResourceId();
469     isNativeFBO = impl.IsNativeFbo();
470   }
471
472   // mSceneObject is being used in a separate thread; queue a message to set the value
473   SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId, isNativeFBO );
474
475   // Send messages to set other properties that may have changed since last time we were on stage
476   SetExclusiveMessage( GetEventThreadServices(), *mSceneObject, mExclusive );
477   SetClearColorMessage(  GetEventThreadServices(), *mSceneObject, mClearColor );
478   SetClearEnabledMessage(  GetEventThreadServices(), *mSceneObject, mClearEnabled );
479   SetCullModeMessage(  GetEventThreadServices(), *mSceneObject, mCullMode );
480   SetRefreshRateMessage(  GetEventThreadServices(), *mSceneObject, mRefreshRate );
481
482   // Caller takes ownership
483   return mSceneObject;
484 }
485
486 SceneGraph::RenderTask* RenderTask::GetRenderTaskSceneObject()
487 {
488   return mSceneObject;
489 }
490
491 void RenderTask::DiscardSceneObject()
492 {
493   // mSceneObject is not owned; throw away the raw-pointer
494   mSceneObject = NULL;
495
496   // if we have a frame buffer we need to track connection status
497   if(mFrameBufferImage)
498   {
499     GetImplementation(mFrameBufferImage).Disconnect();
500   }
501 }
502
503 /********************************************************************************
504  ********************************   PROPERTY METHODS   **************************
505  ********************************************************************************/
506
507 unsigned int RenderTask::GetDefaultPropertyCount() const
508 {
509   return DEFAULT_PROPERTY_COUNT;
510 }
511
512 void RenderTask::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
513 {
514   indices.Reserve( DEFAULT_PROPERTY_COUNT );
515
516   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
517   {
518     indices.PushBack( i );
519   }
520 }
521
522 const char* RenderTask::GetDefaultPropertyName( Property::Index index ) const
523 {
524   if( index < DEFAULT_PROPERTY_COUNT )
525   {
526     return DEFAULT_PROPERTY_DETAILS[index].name;
527   }
528   else
529   {
530     return NULL;
531   }
532 }
533
534 Property::Index RenderTask::GetDefaultPropertyIndex(const std::string& name) const
535 {
536   Property::Index index = Property::INVALID_INDEX;
537
538   // Look for name in default properties
539   for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
540   {
541     if( 0 == strcmp( name.c_str(), DEFAULT_PROPERTY_DETAILS[i].name ) ) // dont want to convert rhs to string
542     {
543       index = i;
544       break;
545     }
546   }
547
548   return index;
549 }
550
551 bool RenderTask::IsDefaultPropertyWritable(Property::Index index) const
552 {
553   return DEFAULT_PROPERTY_DETAILS[ index ].writable;
554 }
555
556 bool RenderTask::IsDefaultPropertyAnimatable(Property::Index index) const
557 {
558   return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
559 }
560
561 bool RenderTask::IsDefaultPropertyAConstraintInput( Property::Index index ) const
562 {
563   return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
564 }
565
566 Property::Type RenderTask::GetDefaultPropertyType(Property::Index index) const
567 {
568   if( index < DEFAULT_PROPERTY_COUNT )
569   {
570     return DEFAULT_PROPERTY_DETAILS[index].type;
571   }
572
573   // index out of range...return Property::NONE
574   return Property::NONE;
575 }
576
577 void RenderTask::SetDefaultProperty( Property::Index index, const Property::Value& property )
578 {
579   switch ( index )
580   {
581     case Dali::RenderTask::Property::VIEWPORT_POSITION:
582     {
583       SetViewportPosition( property.Get<Vector2>() );
584       break;
585     }
586     case Dali::RenderTask::Property::VIEWPORT_SIZE:
587     {
588       SetViewportSize( property.Get<Vector2>() );
589       break;
590     }
591     case Dali::RenderTask::Property::CLEAR_COLOR:
592     {
593       SetClearColor( property.Get<Vector4>() );
594       break;
595     }
596     default:
597     {
598       // nothing to do
599       break;
600     }
601   }
602 }
603
604 Property::Value RenderTask::GetDefaultProperty(Property::Index index) const
605 {
606   Property::Value value;
607
608   switch ( index )
609   {
610
611     case Dali::RenderTask::Property::VIEWPORT_POSITION:
612     {
613       value = GetCurrentViewportPosition();
614       break;
615     }
616     case Dali::RenderTask::Property::VIEWPORT_SIZE:
617     {
618       value = GetCurrentViewportSize();
619       break;
620     }
621     case Dali::RenderTask::Property::CLEAR_COLOR:
622     {
623       value = GetClearColor();
624       break;
625     }
626
627     default:
628     {
629       DALI_ASSERT_ALWAYS(false && "RenderTask property index out of range"); // should not come here
630       break;
631     }
632   }
633
634   return value;
635 }
636
637 const SceneGraph::PropertyOwner* RenderTask::GetSceneObject() const
638 {
639   return mSceneObject;
640 }
641
642 const SceneGraph::PropertyBase* RenderTask::GetSceneObjectAnimatableProperty( Property::Index index ) const
643 {
644   DALI_ASSERT_ALWAYS( IsPropertyAnimatable(index) && "Property is not animatable" );
645
646   const SceneGraph::PropertyBase* property( NULL );
647
648   // This method should only return a property which is part of the scene-graph
649   if( mSceneObject != NULL )
650   {
651     switch ( index )
652     {
653       case Dali::RenderTask::Property::VIEWPORT_POSITION:
654         property = &mSceneObject->mViewportPosition;
655         break;
656
657       case Dali::RenderTask::Property::VIEWPORT_SIZE:
658         property = &mSceneObject->mViewportSize;
659         break;
660
661       case Dali::RenderTask::Property::CLEAR_COLOR:
662         property = &mSceneObject->mClearColor;
663         break;
664
665       default:
666         break;
667     }
668   }
669
670   return property;
671 }
672
673 const PropertyInputImpl* RenderTask::GetSceneObjectInputProperty( Property::Index index ) const
674 {
675   const PropertyInputImpl* property( NULL );
676   if( mSceneObject != NULL )
677   {
678     switch ( index )
679     {
680       case Dali::RenderTask::Property::VIEWPORT_POSITION:
681         property = &mSceneObject->mViewportPosition;
682         break;
683
684       case Dali::RenderTask::Property::VIEWPORT_SIZE:
685         property = &mSceneObject->mViewportSize;
686         break;
687
688       case Dali::RenderTask::Property::CLEAR_COLOR:
689         property = &mSceneObject->mViewportSize;
690         break;
691
692       default:
693         break;
694     }
695   }
696
697   return property;
698 }
699
700 bool RenderTask::HasFinished()
701 {
702   bool finished = false;
703   const unsigned int counter = mSceneObject->GetRenderedOnceCounter();
704
705   if( mRefreshOnceCounter < counter )
706   {
707     finished = true;
708     mRefreshOnceCounter = counter;
709   }
710
711   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::HasFinished()=%s SCRT:%p  SC\n", finished?"T":"F", mSceneObject);
712
713   return finished;
714 }
715
716 void RenderTask::EmitSignalFinish()
717 {
718   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::EmitSignalFinish(this:%p)\n", this);
719
720   if( !mSignalFinished.Empty() )
721   {
722     Dali::RenderTask handle( this );
723     mSignalFinished.Emit(handle );
724   }
725 }
726
727 Dali::RenderTask::RenderTaskSignalType& RenderTask::FinishedSignal()
728 {
729   return mSignalFinished;
730 }
731
732 bool RenderTask::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
733 {
734   bool connected( true );
735   RenderTask* renderTask = dynamic_cast<RenderTask*>(object);
736
737   if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
738   {
739     renderTask->FinishedSignal().Connect( tracker, functor );
740   }
741   else
742   {
743     // signalName does not match any signal
744     connected = false;
745   }
746
747   return connected;
748 }
749
750 RenderTask::RenderTask( bool isSystemLevel )
751 : mSceneObject( NULL ),
752   mSourceConnector( Connector::SOURCE_CONNECTOR, *this ),
753   mCameraConnector( Connector::CAMERA_CONNECTOR, *this ),
754   mMappingConnector( Connector::MAPPING_CONNECTOR, *this  ),
755   mClearColor( Dali::RenderTask::DEFAULT_CLEAR_COLOR ),
756   mRefreshRate( Dali::RenderTask::DEFAULT_REFRESH_RATE ),
757   mRefreshOnceCounter( 0u ),
758   mScreenToFrameBufferFunction( Dali::RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION ),
759   mExclusive( Dali::RenderTask::DEFAULT_EXCLUSIVE ),
760   mInputEnabled( Dali::RenderTask::DEFAULT_INPUT_ENABLED ),
761   mClearEnabled( Dali::RenderTask::DEFAULT_CLEAR_ENABLED ),
762   mCullMode( Dali::RenderTask::DEFAULT_CULL_MODE ),
763   mIsSystemLevel( isSystemLevel )
764 {
765   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::RenderTask(this:%p)\n", this);
766 }
767
768 RenderTask::~RenderTask()
769 {
770   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::~RenderTask(this:%p)\n", this);
771 }
772
773 // Helper class for connecting Nodes to the scene-graph RenderTask
774
775 RenderTask::Connector::Connector( Type type, RenderTask& renderTask )
776 : mType( type ),
777   mRenderTask( renderTask ),
778   mActor( NULL )
779 {
780 }
781
782 RenderTask::Connector::~Connector()
783 {
784   SetActor( NULL );
785 }
786
787 void RenderTask::Connector::SetActor( Actor* actor )
788 {
789   if ( mActor != actor )
790   {
791     if ( mActor )
792     {
793       mActor->RemoveObserver( *this );
794     }
795
796     mActor = actor;
797
798     if ( mActor )
799     {
800       mActor->AddObserver( *this );
801     }
802
803     UpdateRenderTask();
804   }
805 }
806
807 void RenderTask::Connector::SceneObjectAdded( Object& object )
808 {
809   UpdateRenderTask();
810 }
811
812 void RenderTask::Connector::SceneObjectRemoved( Object& object )
813 {
814   UpdateRenderTask();
815 }
816
817 void RenderTask::Connector::ObjectDestroyed( Object& object )
818 {
819   if ( SOURCE_CONNECTOR == mType )
820   {
821     const Stage* stage = Stage::GetCurrent();
822     if ( stage )
823     {
824       stage->GetRenderTaskList().SetExclusive( &mRenderTask, false );
825     }
826   }
827
828   mActor = NULL;
829
830   UpdateRenderTask();
831 }
832
833 void RenderTask::Connector::UpdateRenderTask()
834 {
835   // Guard to allow handle destruction after Core has been destroyed
836   if( Internal::Stage::IsInstalled() &&
837       mRenderTask.mSceneObject )
838   {
839     const SceneGraph::Node* node( NULL );
840
841     // Check whether a Node exists in the scene-graph
842     if ( NULL != mActor )
843     {
844       const SceneGraph::PropertyOwner* object = mActor->GetSceneObject();
845       if ( NULL != object )
846       {
847         // actors only point to nodes as their scene objects
848         node = static_cast< const SceneGraph::Node* >( object );
849       }
850     }
851
852     //the mapping node is not used in the scene graph
853     if ( SOURCE_CONNECTOR == mType )
854     {
855       SetSourceNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
856     }
857     else if( CAMERA_CONNECTOR == mType )
858     {
859       SetCameraNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
860     }
861   }
862 }
863
864 } // namespace Internal
865
866 } // namespace Dali