2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/render-tasks/render-task-impl.h>
22 #include <cstring> // for strcmp
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/images/frame-buffer-image-impl.h>
33 #include <dali/internal/update/nodes/node.h>
34 #include <dali/internal/event/render-tasks/render-task-list-impl.h>
35 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
37 #if defined(DEBUG_ENABLED)
40 Debug::Filter* gLogRender = Debug::Filter::New(Debug::Concise, false, "LOG_RENDER_TASK");
50 namespace // For internal properties
55 // Name Type writable animatable constraint-input enum for index-checking
56 DALI_PROPERTY_TABLE_BEGIN
57 DALI_PROPERTY( "viewportPosition", VECTOR2, true, true, true, Dali::RenderTask::Property::VIEWPORT_POSITION )
58 DALI_PROPERTY( "viewportSize", VECTOR2, true, true, true, Dali::RenderTask::Property::VIEWPORT_SIZE )
59 DALI_PROPERTY( "clearColor", VECTOR4, true, true, true, Dali::RenderTask::Property::CLEAR_COLOR )
60 DALI_PROPERTY_TABLE_END( DEFAULT_OBJECT_PROPERTY_START_INDEX )
64 const char* const SIGNAL_FINISHED = "finished";
66 TypeRegistration mType( typeid( Dali::RenderTask ), typeid( Dali::BaseHandle ), NULL );
68 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &RenderTask::DoConnectSignal );
70 } // Unnamed namespace
72 RenderTask* RenderTask::New( bool isSystemLevel )
74 RenderTask* task( new RenderTask( isSystemLevel ) );
79 void RenderTask::SetSourceActor( Actor* actor )
81 const Stage* stage = Stage::GetCurrent();
84 stage->GetRenderTaskList().SetExclusive( this, mExclusive );
86 mSourceConnector.SetActor( actor );
89 Actor* RenderTask::GetSourceActor() const
91 return mSourceConnector.mActor;
94 void RenderTask::SetExclusive( bool exclusive )
96 if ( mExclusive != exclusive )
98 mExclusive = exclusive;
100 const Stage* stage = Stage::GetCurrent();
103 stage->GetRenderTaskList().SetExclusive( this, exclusive );
108 // mSceneObject is being used in a separate thread; queue a message to set the value
109 SetExclusiveMessage( GetEventThreadServices(), *mSceneObject, mExclusive );
114 bool RenderTask::IsExclusive() const
119 void RenderTask::SetInputEnabled( bool enabled )
121 mInputEnabled = enabled;
124 bool RenderTask::GetInputEnabled() const
126 return mInputEnabled;
129 void RenderTask::SetCameraActor( CameraActor* cameraActor )
131 mCameraConnector.SetActor( cameraActor );
134 CameraActor* RenderTask::GetCameraActor() const
136 // camera connector can only point to camera actor
137 return static_cast< CameraActor* >( mCameraConnector.mActor );
140 void RenderTask::SetTargetFrameBuffer( Dali::FrameBufferImage image )
142 if ( mFrameBufferImage != image )
144 // if we have a scene object we need to track connection status and set frame buffer id as well as updating target frame buffer
147 if(mFrameBufferImage)
149 GetImplementation(mFrameBufferImage).Disconnect();
152 // update target frame buffer
153 mFrameBufferImage = image;
155 unsigned int resourceId = 0;
156 bool isNativeFBO = false;
157 if( mFrameBufferImage )
159 Dali::Internal::FrameBufferImage& impl = GetImplementation( mFrameBufferImage );
161 resourceId = impl.GetResourceId();
162 isNativeFBO = impl.IsNativeFbo();
165 // mSceneObject is being used in a separate thread; queue a message to set the value
166 SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId, isNativeFBO );
170 // update target frame buffer
171 mFrameBufferImage = image;
176 Dali::FrameBufferImage RenderTask::GetTargetFrameBuffer() const
178 return mFrameBufferImage;
181 void RenderTask::SetScreenToFrameBufferFunction( ScreenToFrameBufferFunction conversionFunction )
183 mScreenToFrameBufferFunction = conversionFunction;
186 RenderTask::ScreenToFrameBufferFunction RenderTask::GetScreenToFrameBufferFunction() const
188 return mScreenToFrameBufferFunction;
191 void RenderTask::SetScreenToFrameBufferMappingActor( Actor* mappingActor )
193 mMappingConnector.SetActor( mappingActor );
196 Actor* RenderTask::GetScreenToFrameBufferMappingActor() const
198 return mMappingConnector.mActor;
201 void RenderTask::SetViewportPosition(const Vector2& value)
203 BakeViewportPositionMessage( GetEventThreadServices(), *mSceneObject, value );
206 Vector2 RenderTask::GetCurrentViewportPosition() const
208 return mSceneObject->GetViewportPosition( GetEventThreadServices().GetEventBufferIndex() );
211 void RenderTask::SetViewportSize(const Vector2& value)
213 BakeViewportSizeMessage( GetEventThreadServices(), *mSceneObject, value );
216 Vector2 RenderTask::GetCurrentViewportSize() const
218 return mSceneObject->GetViewportSize( GetEventThreadServices().GetEventBufferIndex() );
221 void RenderTask::SetViewport( const Viewport& viewport )
223 SetViewportPosition(Vector2(viewport.x, viewport.y));
224 SetViewportSize(Vector2(viewport.width, viewport.height));
227 void RenderTask::GetViewport( Viewport& viewPort ) const
229 BufferIndex bufferIndex = GetEventThreadServices().GetEventBufferIndex();
231 if(!mSceneObject->GetViewportEnabled( bufferIndex ))
233 if ( mFrameBufferImage )
235 viewPort.x = viewPort.y = 0;
236 viewPort.width = mFrameBufferImage.GetWidth();
237 viewPort.height = mFrameBufferImage.GetHeight();
241 Internal::Stage* stage = Internal::Stage::GetCurrent();
244 Vector2 size( stage->GetSize() );
245 viewPort.x = viewPort.y = 0;
246 viewPort.width = size.width;
247 viewPort.height = size.height;
253 const Vector2& position = mSceneObject->GetViewportPosition(bufferIndex);
254 const Vector2& size = mSceneObject->GetViewportSize(bufferIndex);
255 viewPort.x = position.x;
256 viewPort.y = position.y;
257 viewPort.width = size.width;
258 viewPort.height = size.height;
262 void RenderTask::SetClearColor( const Vector4& color )
264 if ( mClearColor != color )
270 // mSceneObject is being used in a separate thread; queue a message to set the value
271 BakeClearColorMessage( GetEventThreadServices(), *mSceneObject, color );
276 const Vector4& RenderTask::GetClearColor() const
278 return mSceneObject->GetClearColor( GetEventThreadServices().GetEventBufferIndex() );
281 void RenderTask::SetClearEnabled( bool enabled )
283 if ( mClearEnabled != enabled )
285 mClearEnabled = enabled;
289 // mSceneObject is being used in a separate thread; queue a message to set the value
290 SetClearEnabledMessage( GetEventThreadServices(), *mSceneObject, mClearEnabled );
295 bool RenderTask::GetClearEnabled() const
297 return mClearEnabled;
300 void RenderTask::SetCullMode( bool mode )
302 if ( mCullMode != mode )
308 // mSceneObject is being used in a separate thread; queue a message to set the value
309 SetCullModeMessage( GetEventThreadServices(), *mSceneObject, mCullMode );
314 bool RenderTask::GetCullMode() const
319 void RenderTask::SetRefreshRate( unsigned int refreshRate )
321 DALI_LOG_TRACE_METHOD_FMT(gLogRender, "this:%p rate:%d\n", this, refreshRate);
322 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::SetRefreshRate(this:%p, %d)\n", this, refreshRate);
324 mRefreshRate = refreshRate; // cached for GetRefreshRate()
326 // Note - even when refreshRate is the same as mRefreshRate, a message should be sent
330 // mSceneObject is being used in a separate thread; queue a message to set the value
331 SetRefreshRateMessage( GetEventThreadServices(), *mSceneObject, refreshRate );
335 unsigned int RenderTask::GetRefreshRate() const
340 bool RenderTask::IsHittable( Vector2& screenCoords ) const
342 // True when input is enabled, source & camera actor are valid
343 bool inputEnabled( false );
345 Actor* sourceActor = GetSourceActor();
346 CameraActor* cameraActor = GetCameraActor();
348 if ( mInputEnabled &&
349 NULL != sourceActor &&
350 sourceActor->OnStage() &&
351 NULL != cameraActor &&
352 cameraActor->OnStage() )
354 // If the actors are rendered off-screen, then the screen coordinates must be converted
355 // and the conversion function will tell us if they are inside or outside
356 if ( TranslateCoordinates( screenCoords ) )
358 // This is a suitable render-task for input handling
366 bool RenderTask::TranslateCoordinates( Vector2& screenCoords ) const
368 // return true for on-screen tasks
370 // If the actors are rendered off-screen, then the screen coordinates must be converted
371 // the function should only be called for offscreen tasks
372 if( mFrameBufferImage && mMappingConnector.mActor )
374 CameraActor* localCamera = GetCameraActor();
375 StagePtr stage = Stage::GetCurrent();
378 CameraActor& defaultCamera = stage->GetDefaultCameraActor();
382 Vector2 size( stage->GetSize() );
383 viewport.x = viewport.y = 0;
384 viewport.width = size.width;
385 viewport.height = size.height;
387 float localX, localY;
388 inside = mMappingConnector.mActor->ScreenToLocal(defaultCamera.GetViewMatrix(), defaultCamera.GetProjectionMatrix(), viewport, localX, localY, screenCoords.x, screenCoords.y);
389 Vector3 actorSize = mMappingConnector.mActor->GetCurrentSize();
390 if( inside && localX >= 0.f && localX <= actorSize.x && localY >= 0.f && localY <= actorSize.y)
392 screenCoords.x = localX;
393 screenCoords.y = localY;
406 else if ( mFrameBufferImage && mScreenToFrameBufferFunction )
408 inside = mScreenToFrameBufferFunction( screenCoords );
413 bool RenderTask::IsSystemLevel() const
415 return mIsSystemLevel;
418 SceneGraph::RenderTask* RenderTask::CreateSceneObject()
420 // This should only be called once, with no existing scene-object
421 DALI_ASSERT_DEBUG( NULL == mSceneObject );
423 // Keep the raw-pointer until DiscardSceneObject is called
424 mSceneObject = SceneGraph::RenderTask::New();
426 // 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
427 unsigned int resourceId = 0;
428 bool isNativeFBO = false;
429 if( mFrameBufferImage )
431 Dali::Internal::FrameBufferImage& impl = GetImplementation( mFrameBufferImage );
433 resourceId = impl.GetResourceId();
434 isNativeFBO = impl.IsNativeFbo();
437 // mSceneObject is being used in a separate thread; queue a message to set the value
438 SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId, isNativeFBO );
440 // Send messages to set other properties that may have changed since last time we were on stage
441 SetExclusiveMessage( GetEventThreadServices(), *mSceneObject, mExclusive );
442 SetClearColorMessage( GetEventThreadServices(), *mSceneObject, mClearColor );
443 SetClearEnabledMessage( GetEventThreadServices(), *mSceneObject, mClearEnabled );
444 SetCullModeMessage( GetEventThreadServices(), *mSceneObject, mCullMode );
445 SetRefreshRateMessage( GetEventThreadServices(), *mSceneObject, mRefreshRate );
447 // Caller takes ownership
451 SceneGraph::RenderTask* RenderTask::GetRenderTaskSceneObject()
456 void RenderTask::DiscardSceneObject()
458 // mSceneObject is not owned; throw away the raw-pointer
461 // if we have a frame buffer we need to track connection status
462 if(mFrameBufferImage)
464 GetImplementation(mFrameBufferImage).Disconnect();
468 /********************************************************************************
469 ******************************** PROPERTY METHODS **************************
470 ********************************************************************************/
472 unsigned int RenderTask::GetDefaultPropertyCount() const
474 return DEFAULT_PROPERTY_COUNT;
477 void RenderTask::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
479 indices.Reserve( DEFAULT_PROPERTY_COUNT );
481 for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
483 indices.PushBack( i );
487 const char* RenderTask::GetDefaultPropertyName( Property::Index index ) const
489 if( index < DEFAULT_PROPERTY_COUNT )
491 return DEFAULT_PROPERTY_DETAILS[index].name;
499 Property::Index RenderTask::GetDefaultPropertyIndex(const std::string& name) const
501 Property::Index index = Property::INVALID_INDEX;
503 // Look for name in default properties
504 for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
506 if( 0 == strcmp( name.c_str(), DEFAULT_PROPERTY_DETAILS[i].name ) ) // dont want to convert rhs to string
516 bool RenderTask::IsDefaultPropertyWritable(Property::Index index) const
518 return DEFAULT_PROPERTY_DETAILS[ index ].writable;
521 bool RenderTask::IsDefaultPropertyAnimatable(Property::Index index) const
523 return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
526 bool RenderTask::IsDefaultPropertyAConstraintInput( Property::Index index ) const
528 return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
531 Property::Type RenderTask::GetDefaultPropertyType(Property::Index index) const
533 if( index < DEFAULT_PROPERTY_COUNT )
535 return DEFAULT_PROPERTY_DETAILS[index].type;
538 // index out of range...return Property::NONE
539 return Property::NONE;
542 void RenderTask::SetDefaultProperty( Property::Index index, const Property::Value& property )
546 case Dali::RenderTask::Property::VIEWPORT_POSITION:
548 SetViewportPosition( property.Get<Vector2>() );
551 case Dali::RenderTask::Property::VIEWPORT_SIZE:
553 SetViewportSize( property.Get<Vector2>() );
556 case Dali::RenderTask::Property::CLEAR_COLOR:
558 SetClearColor( property.Get<Vector4>() );
569 Property::Value RenderTask::GetDefaultProperty(Property::Index index) const
571 Property::Value value;
576 case Dali::RenderTask::Property::VIEWPORT_POSITION:
578 value = GetCurrentViewportPosition();
581 case Dali::RenderTask::Property::VIEWPORT_SIZE:
583 value = GetCurrentViewportSize();
586 case Dali::RenderTask::Property::CLEAR_COLOR:
588 value = GetClearColor();
594 DALI_ASSERT_ALWAYS(false && "RenderTask property index out of range"); // should not come here
602 const SceneGraph::PropertyOwner* RenderTask::GetSceneObject() const
607 const SceneGraph::PropertyBase* RenderTask::GetSceneObjectAnimatableProperty( Property::Index index ) const
609 DALI_ASSERT_ALWAYS( IsPropertyAnimatable(index) && "Property is not animatable" );
611 const SceneGraph::PropertyBase* property( NULL );
613 // This method should only return a property which is part of the scene-graph
614 if( mSceneObject != NULL )
618 case Dali::RenderTask::Property::VIEWPORT_POSITION:
619 property = &mSceneObject->mViewportPosition;
622 case Dali::RenderTask::Property::VIEWPORT_SIZE:
623 property = &mSceneObject->mViewportSize;
626 case Dali::RenderTask::Property::CLEAR_COLOR:
627 property = &mSceneObject->mClearColor;
638 const PropertyInputImpl* RenderTask::GetSceneObjectInputProperty( Property::Index index ) const
640 const PropertyInputImpl* property( NULL );
641 if( mSceneObject != NULL )
645 case Dali::RenderTask::Property::VIEWPORT_POSITION:
646 property = &mSceneObject->mViewportPosition;
649 case Dali::RenderTask::Property::VIEWPORT_SIZE:
650 property = &mSceneObject->mViewportSize;
653 case Dali::RenderTask::Property::CLEAR_COLOR:
654 property = &mSceneObject->mViewportSize;
665 bool RenderTask::HasFinished()
667 bool finished = false;
668 const unsigned int counter = mSceneObject->GetRenderedOnceCounter();
670 if( mRefreshOnceCounter < counter )
673 mRefreshOnceCounter = counter;
676 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::HasFinished()=%s SCRT:%p SC\n", finished?"T":"F", mSceneObject);
681 void RenderTask::EmitSignalFinish()
683 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::EmitSignalFinish(this:%p)\n", this);
685 if( !mSignalFinished.Empty() )
687 Dali::RenderTask handle( this );
688 mSignalFinished.Emit(handle );
692 Dali::RenderTask::RenderTaskSignalType& RenderTask::FinishedSignal()
694 return mSignalFinished;
697 bool RenderTask::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
699 bool connected( true );
700 RenderTask* renderTask = dynamic_cast<RenderTask*>(object);
702 if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
704 renderTask->FinishedSignal().Connect( tracker, functor );
708 // signalName does not match any signal
715 RenderTask::RenderTask( bool isSystemLevel )
716 : mSceneObject( NULL ),
717 mSourceConnector( Connector::SOURCE_CONNECTOR, *this ),
718 mCameraConnector( Connector::CAMERA_CONNECTOR, *this ),
719 mMappingConnector( Connector::MAPPING_CONNECTOR, *this ),
720 mClearColor( Dali::RenderTask::DEFAULT_CLEAR_COLOR ),
721 mRefreshRate( Dali::RenderTask::DEFAULT_REFRESH_RATE ),
722 mRefreshOnceCounter( 0u ),
723 mScreenToFrameBufferFunction( Dali::RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION ),
724 mExclusive( Dali::RenderTask::DEFAULT_EXCLUSIVE ),
725 mInputEnabled( Dali::RenderTask::DEFAULT_INPUT_ENABLED ),
726 mClearEnabled( Dali::RenderTask::DEFAULT_CLEAR_ENABLED ),
727 mCullMode( Dali::RenderTask::DEFAULT_CULL_MODE ),
728 mIsSystemLevel( isSystemLevel )
730 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::RenderTask(this:%p)\n", this);
733 RenderTask::~RenderTask()
735 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::~RenderTask(this:%p)\n", this);
738 // Helper class for connecting Nodes to the scene-graph RenderTask
740 RenderTask::Connector::Connector( Type type, RenderTask& renderTask )
742 mRenderTask( renderTask ),
747 RenderTask::Connector::~Connector()
752 void RenderTask::Connector::SetActor( Actor* actor )
754 if ( mActor != actor )
758 mActor->RemoveObserver( *this );
765 mActor->AddObserver( *this );
772 void RenderTask::Connector::SceneObjectAdded( Object& object )
777 void RenderTask::Connector::SceneObjectRemoved( Object& object )
782 void RenderTask::Connector::ObjectDestroyed( Object& object )
784 if ( SOURCE_CONNECTOR == mType )
786 const Stage* stage = Stage::GetCurrent();
789 stage->GetRenderTaskList().SetExclusive( &mRenderTask, false );
798 void RenderTask::Connector::UpdateRenderTask()
800 // Guard to allow handle destruction after Core has been destroyed
801 if( Internal::Stage::IsInstalled() &&
802 mRenderTask.mSceneObject )
804 const SceneGraph::Node* node( NULL );
806 // Check whether a Node exists in the scene-graph
807 if ( NULL != mActor )
809 const SceneGraph::PropertyOwner* object = mActor->GetSceneObject();
810 if ( NULL != object )
812 // actors only point to nodes as their scene objects
813 node = static_cast< const SceneGraph::Node* >( object );
817 //the mapping node is not used in the scene graph
818 if ( SOURCE_CONNECTOR == mType )
820 SetSourceNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
822 else if( CAMERA_CONNECTOR == mType )
824 SetCameraNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
829 } // namespace Internal