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/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>
38 #if defined(DEBUG_ENABLED)
41 Debug::Filter* gLogRender = Debug::Filter::New(Debug::Concise, false, "LOG_RENDER_TASK");
51 namespace // For internal properties
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 )
65 const char* const SIGNAL_FINISHED = "finished";
67 TypeRegistration mType( typeid( Dali::RenderTask ), typeid( Dali::BaseHandle ), NULL );
69 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &RenderTask::DoConnectSignal );
71 } // Unnamed namespace
73 RenderTask* RenderTask::New( bool isSystemLevel )
75 RenderTask* task( new RenderTask( isSystemLevel ) );
80 void RenderTask::SetSourceActor( Actor* actor )
82 const Stage* stage = Stage::GetCurrent();
85 stage->GetRenderTaskList().SetExclusive( this, mExclusive );
87 mSourceConnector.SetActor( actor );
90 Actor* RenderTask::GetSourceActor() const
92 return mSourceConnector.mActor;
95 void RenderTask::SetExclusive( bool exclusive )
97 if ( mExclusive != exclusive )
99 mExclusive = exclusive;
101 const Stage* stage = Stage::GetCurrent();
104 stage->GetRenderTaskList().SetExclusive( this, exclusive );
109 // mSceneObject is being used in a separate thread; queue a message to set the value
110 SetExclusiveMessage( GetEventThreadServices(), *mSceneObject, mExclusive );
115 bool RenderTask::IsExclusive() const
120 void RenderTask::SetInputEnabled( bool enabled )
122 mInputEnabled = enabled;
125 bool RenderTask::GetInputEnabled() const
127 return mInputEnabled;
130 void RenderTask::SetCameraActor( CameraActor* cameraActor )
132 mCameraConnector.SetActor( cameraActor );
135 CameraActor* RenderTask::GetCameraActor() const
137 // camera connector can only point to camera actor
138 return static_cast< CameraActor* >( mCameraConnector.mActor );
141 void RenderTask::SetTargetFrameBuffer( Dali::FrameBufferImage image )
143 if ( mFrameBufferImage != image )
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
148 if(mFrameBufferImage)
150 GetImplementation(mFrameBufferImage).Disconnect();
153 // update target frame buffer
154 mFrameBufferImage = image;
156 unsigned int resourceId = 0;
157 bool isNativeFBO = false;
158 if( mFrameBufferImage )
160 Dali::Internal::FrameBufferImage& impl = GetImplementation( mFrameBufferImage );
162 resourceId = impl.GetResourceId();
163 isNativeFBO = impl.IsNativeFbo();
166 // mSceneObject is being used in a separate thread; queue a message to set the value
167 SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId, isNativeFBO );
171 // update target frame buffer
172 mFrameBufferImage = image;
177 Dali::FrameBufferImage RenderTask::GetTargetFrameBuffer() const
179 return mFrameBufferImage;
182 void RenderTask::SetScreenToFrameBufferFunction( ScreenToFrameBufferFunction conversionFunction )
184 mScreenToFrameBufferFunction = conversionFunction;
187 RenderTask::ScreenToFrameBufferFunction RenderTask::GetScreenToFrameBufferFunction() const
189 return mScreenToFrameBufferFunction;
192 void RenderTask::SetScreenToFrameBufferMappingActor( Actor* mappingActor )
194 mMappingConnector.SetActor( mappingActor );
197 Actor* RenderTask::GetScreenToFrameBufferMappingActor() const
199 return mMappingConnector.mActor;
202 void RenderTask::SetViewportPosition(const Vector2& value)
204 BakeViewportPositionMessage( GetEventThreadServices(), *mSceneObject, value );
207 Vector2 RenderTask::GetCurrentViewportPosition() const
209 return mSceneObject->GetViewportPosition( GetEventThreadServices().GetEventBufferIndex() );
212 void RenderTask::SetViewportSize(const Vector2& value)
214 BakeViewportSizeMessage( GetEventThreadServices(), *mSceneObject, value );
217 Vector2 RenderTask::GetCurrentViewportSize() const
219 return mSceneObject->GetViewportSize( GetEventThreadServices().GetEventBufferIndex() );
222 void RenderTask::SetViewport( const Viewport& viewport )
224 SetViewportPosition(Vector2(viewport.x, viewport.y));
225 SetViewportSize(Vector2(viewport.width, viewport.height));
228 void RenderTask::GetViewport( Viewport& viewPort ) const
230 BufferIndex bufferIndex = GetEventThreadServices().GetEventBufferIndex();
232 if(!mSceneObject->GetViewportEnabled( bufferIndex ))
234 if ( mFrameBufferImage )
236 viewPort.x = viewPort.y = 0;
237 viewPort.width = mFrameBufferImage.GetWidth();
238 viewPort.height = mFrameBufferImage.GetHeight();
242 Internal::Stage* stage = Internal::Stage::GetCurrent();
245 Vector2 size( stage->GetSize() );
246 viewPort.x = viewPort.y = 0;
247 viewPort.width = size.width;
248 viewPort.height = size.height;
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;
263 void RenderTask::SetClearColor( const Vector4& color )
265 if ( mClearColor != color )
271 // mSceneObject is being used in a separate thread; queue a message to set the value
272 BakeClearColorMessage( GetEventThreadServices(), *mSceneObject, color );
277 const Vector4& RenderTask::GetClearColor() const
279 return mSceneObject->GetClearColor( GetEventThreadServices().GetEventBufferIndex() );
282 void RenderTask::SetClearEnabled( bool enabled )
284 if ( mClearEnabled != enabled )
286 mClearEnabled = enabled;
290 // mSceneObject is being used in a separate thread; queue a message to set the value
291 SetClearEnabledMessage( GetEventThreadServices(), *mSceneObject, mClearEnabled );
296 bool RenderTask::GetClearEnabled() const
298 return mClearEnabled;
301 void RenderTask::SetCullMode( bool mode )
303 if ( mCullMode != mode )
309 // mSceneObject is being used in a separate thread; queue a message to set the value
310 SetCullModeMessage( GetEventThreadServices(), *mSceneObject, mCullMode );
315 bool RenderTask::GetCullMode() const
320 void RenderTask::SetRefreshRate( unsigned int refreshRate )
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);
325 mRefreshRate = refreshRate; // cached for GetRefreshRate()
327 // Note - even when refreshRate is the same as mRefreshRate, a message should be sent
331 // mSceneObject is being used in a separate thread; queue a message to set the value
332 SetRefreshRateMessage( GetEventThreadServices(), *mSceneObject, refreshRate );
336 unsigned int RenderTask::GetRefreshRate() const
341 bool RenderTask::IsHittable( Vector2& screenCoords ) const
343 // True when input is enabled, source & camera actor are valid
344 bool inputEnabled( false );
346 Actor* sourceActor = GetSourceActor();
347 CameraActor* cameraActor = GetCameraActor();
349 if ( mInputEnabled &&
350 NULL != sourceActor &&
351 sourceActor->OnStage() &&
352 NULL != cameraActor &&
353 cameraActor->OnStage() )
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 ) )
359 // This is a suitable render-task for input handling
367 bool RenderTask::TranslateCoordinates( Vector2& screenCoords ) const
369 // return true for on-screen tasks
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 )
375 CameraActor* localCamera = GetCameraActor();
376 StagePtr stage = Stage::GetCurrent();
379 CameraActor& defaultCamera = stage->GetDefaultCameraActor();
383 Vector2 size( stage->GetSize() );
384 viewport.x = viewport.y = 0;
385 viewport.width = size.width;
386 viewport.height = size.height;
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)
393 screenCoords.x = localX;
394 screenCoords.y = localY;
407 else if ( mFrameBufferImage && mScreenToFrameBufferFunction )
409 inside = mScreenToFrameBufferFunction( screenCoords );
414 bool RenderTask::IsSystemLevel() const
416 return mIsSystemLevel;
419 bool RenderTask::WorldToViewport(const Vector3 &position, float& viewportX, float& viewportY) const
421 CameraActor* cam = GetCameraActor();
423 Vector4 pos(position);
426 Vector4 viewportPosition;
429 GetViewport( viewport );
431 bool ok = ProjectFull(pos,
432 cam->GetViewMatrix(),
433 cam->GetProjectionMatrix(),
441 viewportX = viewportPosition.x;
442 viewportY = viewportPosition.y;
448 bool RenderTask::ViewportToLocal(Actor* actor, float viewportX, float viewportY, float &localX, float &localY) const
450 return actor->ScreenToLocal( *this, localX, localY, viewportX, viewportY );
453 SceneGraph::RenderTask* RenderTask::CreateSceneObject()
455 // This should only be called once, with no existing scene-object
456 DALI_ASSERT_DEBUG( NULL == mSceneObject );
458 // Keep the raw-pointer until DiscardSceneObject is called
459 mSceneObject = SceneGraph::RenderTask::New();
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 )
466 Dali::Internal::FrameBufferImage& impl = GetImplementation( mFrameBufferImage );
468 resourceId = impl.GetResourceId();
469 isNativeFBO = impl.IsNativeFbo();
472 // mSceneObject is being used in a separate thread; queue a message to set the value
473 SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId, isNativeFBO );
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 );
482 // Caller takes ownership
486 SceneGraph::RenderTask* RenderTask::GetRenderTaskSceneObject()
491 void RenderTask::DiscardSceneObject()
493 // mSceneObject is not owned; throw away the raw-pointer
496 // if we have a frame buffer we need to track connection status
497 if(mFrameBufferImage)
499 GetImplementation(mFrameBufferImage).Disconnect();
503 /********************************************************************************
504 ******************************** PROPERTY METHODS **************************
505 ********************************************************************************/
507 unsigned int RenderTask::GetDefaultPropertyCount() const
509 return DEFAULT_PROPERTY_COUNT;
512 void RenderTask::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
514 indices.Reserve( DEFAULT_PROPERTY_COUNT );
516 for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
518 indices.PushBack( i );
522 const char* RenderTask::GetDefaultPropertyName( Property::Index index ) const
524 if( index < DEFAULT_PROPERTY_COUNT )
526 return DEFAULT_PROPERTY_DETAILS[index].name;
534 Property::Index RenderTask::GetDefaultPropertyIndex(const std::string& name) const
536 Property::Index index = Property::INVALID_INDEX;
538 // Look for name in default properties
539 for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
541 if( 0 == strcmp( name.c_str(), DEFAULT_PROPERTY_DETAILS[i].name ) ) // dont want to convert rhs to string
551 bool RenderTask::IsDefaultPropertyWritable(Property::Index index) const
553 return DEFAULT_PROPERTY_DETAILS[ index ].writable;
556 bool RenderTask::IsDefaultPropertyAnimatable(Property::Index index) const
558 return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
561 bool RenderTask::IsDefaultPropertyAConstraintInput( Property::Index index ) const
563 return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
566 Property::Type RenderTask::GetDefaultPropertyType(Property::Index index) const
568 if( index < DEFAULT_PROPERTY_COUNT )
570 return DEFAULT_PROPERTY_DETAILS[index].type;
573 // index out of range...return Property::NONE
574 return Property::NONE;
577 void RenderTask::SetDefaultProperty( Property::Index index, const Property::Value& property )
581 case Dali::RenderTask::Property::VIEWPORT_POSITION:
583 SetViewportPosition( property.Get<Vector2>() );
586 case Dali::RenderTask::Property::VIEWPORT_SIZE:
588 SetViewportSize( property.Get<Vector2>() );
591 case Dali::RenderTask::Property::CLEAR_COLOR:
593 SetClearColor( property.Get<Vector4>() );
604 Property::Value RenderTask::GetDefaultProperty(Property::Index index) const
606 Property::Value value;
611 case Dali::RenderTask::Property::VIEWPORT_POSITION:
613 value = GetCurrentViewportPosition();
616 case Dali::RenderTask::Property::VIEWPORT_SIZE:
618 value = GetCurrentViewportSize();
621 case Dali::RenderTask::Property::CLEAR_COLOR:
623 value = GetClearColor();
629 DALI_ASSERT_ALWAYS(false && "RenderTask property index out of range"); // should not come here
637 const SceneGraph::PropertyOwner* RenderTask::GetSceneObject() const
642 const SceneGraph::PropertyBase* RenderTask::GetSceneObjectAnimatableProperty( Property::Index index ) const
644 DALI_ASSERT_ALWAYS( IsPropertyAnimatable(index) && "Property is not animatable" );
646 const SceneGraph::PropertyBase* property( NULL );
648 // This method should only return a property which is part of the scene-graph
649 if( mSceneObject != NULL )
653 case Dali::RenderTask::Property::VIEWPORT_POSITION:
654 property = &mSceneObject->mViewportPosition;
657 case Dali::RenderTask::Property::VIEWPORT_SIZE:
658 property = &mSceneObject->mViewportSize;
661 case Dali::RenderTask::Property::CLEAR_COLOR:
662 property = &mSceneObject->mClearColor;
673 const PropertyInputImpl* RenderTask::GetSceneObjectInputProperty( Property::Index index ) const
675 const PropertyInputImpl* property( NULL );
676 if( mSceneObject != NULL )
680 case Dali::RenderTask::Property::VIEWPORT_POSITION:
681 property = &mSceneObject->mViewportPosition;
684 case Dali::RenderTask::Property::VIEWPORT_SIZE:
685 property = &mSceneObject->mViewportSize;
688 case Dali::RenderTask::Property::CLEAR_COLOR:
689 property = &mSceneObject->mViewportSize;
700 bool RenderTask::HasFinished()
702 bool finished = false;
703 const unsigned int counter = mSceneObject->GetRenderedOnceCounter();
705 if( mRefreshOnceCounter < counter )
708 mRefreshOnceCounter = counter;
711 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::HasFinished()=%s SCRT:%p SC\n", finished?"T":"F", mSceneObject);
716 void RenderTask::EmitSignalFinish()
718 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::EmitSignalFinish(this:%p)\n", this);
720 if( !mSignalFinished.Empty() )
722 Dali::RenderTask handle( this );
723 mSignalFinished.Emit(handle );
727 Dali::RenderTask::RenderTaskSignalType& RenderTask::FinishedSignal()
729 return mSignalFinished;
732 bool RenderTask::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
734 bool connected( true );
735 RenderTask* renderTask = dynamic_cast<RenderTask*>(object);
737 if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
739 renderTask->FinishedSignal().Connect( tracker, functor );
743 // signalName does not match any signal
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 )
765 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::RenderTask(this:%p)\n", this);
768 RenderTask::~RenderTask()
770 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::~RenderTask(this:%p)\n", this);
773 // Helper class for connecting Nodes to the scene-graph RenderTask
775 RenderTask::Connector::Connector( Type type, RenderTask& renderTask )
777 mRenderTask( renderTask ),
782 RenderTask::Connector::~Connector()
787 void RenderTask::Connector::SetActor( Actor* actor )
789 if ( mActor != actor )
793 mActor->RemoveObserver( *this );
800 mActor->AddObserver( *this );
807 void RenderTask::Connector::SceneObjectAdded( Object& object )
812 void RenderTask::Connector::SceneObjectRemoved( Object& object )
817 void RenderTask::Connector::ObjectDestroyed( Object& object )
819 if ( SOURCE_CONNECTOR == mType )
821 const Stage* stage = Stage::GetCurrent();
824 stage->GetRenderTaskList().SetExclusive( &mRenderTask, false );
833 void RenderTask::Connector::UpdateRenderTask()
835 // Guard to allow handle destruction after Core has been destroyed
836 if( Internal::Stage::IsInstalled() &&
837 mRenderTask.mSceneObject )
839 const SceneGraph::Node* node( NULL );
841 // Check whether a Node exists in the scene-graph
842 if ( NULL != mActor )
844 const SceneGraph::PropertyOwner* object = mActor->GetSceneObject();
845 if ( NULL != object )
847 // actors only point to nodes as their scene objects
848 node = static_cast< const SceneGraph::Node* >( object );
852 //the mapping node is not used in the scene graph
853 if ( SOURCE_CONNECTOR == mType )
855 SetSourceNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
857 else if( CAMERA_CONNECTOR == mType )
859 SetCameraNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
864 } // namespace Internal