2 * Copyright (c) 2016 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( "requiresSync", BOOLEAN, true, false, false, Dali::RenderTask::Property::REQUIRES_SYNC )
62 DALI_PROPERTY_TABLE_END( DEFAULT_OBJECT_PROPERTY_START_INDEX )
66 const char* const SIGNAL_FINISHED = "finished";
68 TypeRegistration mType( typeid( Dali::RenderTask ), typeid( Dali::BaseHandle ), NULL );
70 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &RenderTask::DoConnectSignal );
72 } // Unnamed namespace
74 RenderTask* RenderTask::New( bool isSystemLevel )
76 RenderTask* task( new RenderTask( isSystemLevel ) );
81 void RenderTask::SetSourceActor( Actor* actor )
83 const Stage* stage = Stage::GetCurrent();
86 stage->GetRenderTaskList().SetExclusive( this, mExclusive );
88 mSourceConnector.SetActor( actor );
91 Actor* RenderTask::GetSourceActor() const
93 return mSourceConnector.mActor;
96 void RenderTask::SetExclusive( bool exclusive )
98 if ( mExclusive != exclusive )
100 mExclusive = exclusive;
102 const Stage* stage = Stage::GetCurrent();
105 stage->GetRenderTaskList().SetExclusive( this, exclusive );
110 // mSceneObject is being used in a separate thread; queue a message to set the value
111 SetExclusiveMessage( GetEventThreadServices(), *mSceneObject, mExclusive );
116 bool RenderTask::IsExclusive() const
121 void RenderTask::SetInputEnabled( bool enabled )
123 mInputEnabled = enabled;
126 bool RenderTask::GetInputEnabled() const
128 return mInputEnabled;
131 void RenderTask::SetCameraActor( CameraActor* cameraActor )
135 mCameraConnector.mCamera = cameraActor->GetCamera();
139 mCameraConnector.mCamera = NULL;
141 mCameraConnector.SetActor( cameraActor );
144 CameraActor* RenderTask::GetCameraActor() const
146 // camera connector can only point to camera actor
147 return static_cast< CameraActor* >( mCameraConnector.mActor );
150 void RenderTask::SetTargetFrameBuffer( Dali::FrameBufferImage image )
152 if ( mFrameBufferImage != image )
154 // if we have a scene object we need to track connection status and set frame buffer id as well as updating target frame buffer
157 if(mFrameBufferImage)
159 GetImplementation(mFrameBufferImage).Disconnect();
162 // update target frame buffer
163 mFrameBufferImage = image;
165 unsigned int resourceId = 0;
166 bool isNativeFBO = false;
167 if( mFrameBufferImage )
169 Dali::Internal::FrameBufferImage& impl = GetImplementation( mFrameBufferImage );
171 resourceId = impl.GetResourceId();
172 isNativeFBO = impl.IsNativeFbo();
175 // mSceneObject is being used in a separate thread; queue a message to set the value
176 SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId, isNativeFBO );
180 // update target frame buffer
181 mFrameBufferImage = image;
186 void RenderTask::SetFrameBuffer( Dali::FrameBuffer frameBuffer )
190 mFrameBuffer = Internal::FrameBufferPtr( &GetImplementation( frameBuffer ) );
191 SetFrameBufferMessage( GetEventThreadServices(), *mSceneObject, mFrameBuffer->GetRenderObject() );
195 mFrameBuffer.Reset();
196 SetFrameBufferMessage( GetEventThreadServices(), *mSceneObject, NULL );
200 FrameBuffer* RenderTask::GetFrameBuffer() const
202 return mFrameBuffer.Get();
205 Dali::FrameBufferImage RenderTask::GetTargetFrameBuffer() const
207 return mFrameBufferImage;
210 void RenderTask::SetScreenToFrameBufferFunction( ScreenToFrameBufferFunction conversionFunction )
212 mScreenToFrameBufferFunction = conversionFunction;
215 RenderTask::ScreenToFrameBufferFunction RenderTask::GetScreenToFrameBufferFunction() const
217 return mScreenToFrameBufferFunction;
220 void RenderTask::SetScreenToFrameBufferMappingActor( Actor* mappingActor )
222 mMappingConnector.SetActor( mappingActor );
225 Actor* RenderTask::GetScreenToFrameBufferMappingActor() const
227 return mMappingConnector.mActor;
230 void RenderTask::SetViewportPosition(const Vector2& value)
232 BakeViewportPositionMessage( GetEventThreadServices(), *mSceneObject, value );
235 Vector2 RenderTask::GetCurrentViewportPosition() const
237 return mSceneObject->GetViewportPosition( GetEventThreadServices().GetEventBufferIndex() );
240 void RenderTask::SetViewportSize(const Vector2& value)
242 BakeViewportSizeMessage( GetEventThreadServices(), *mSceneObject, value );
245 Vector2 RenderTask::GetCurrentViewportSize() const
247 return mSceneObject->GetViewportSize( GetEventThreadServices().GetEventBufferIndex() );
250 void RenderTask::SetViewport( const Viewport& viewport )
252 SetViewportPosition(Vector2(viewport.x, viewport.y));
253 SetViewportSize(Vector2(viewport.width, viewport.height));
256 void RenderTask::GetViewport( Viewport& viewPort ) const
258 BufferIndex bufferIndex = GetEventThreadServices().GetEventBufferIndex();
260 if(!mSceneObject->GetViewportEnabled( bufferIndex ))
262 if ( mFrameBufferImage )
264 viewPort.x = viewPort.y = 0;
265 viewPort.width = mFrameBufferImage.GetWidth();
266 viewPort.height = mFrameBufferImage.GetHeight();
270 Internal::Stage* stage = Internal::Stage::GetCurrent();
273 Vector2 size( stage->GetSize() );
274 viewPort.x = viewPort.y = 0;
275 viewPort.width = size.width;
276 viewPort.height = size.height;
282 const Vector2& position = mSceneObject->GetViewportPosition(bufferIndex);
283 const Vector2& size = mSceneObject->GetViewportSize(bufferIndex);
284 viewPort.x = position.x;
285 viewPort.y = position.y;
286 viewPort.width = size.width;
287 viewPort.height = size.height;
291 void RenderTask::SetClearColor( const Vector4& color )
293 if ( mClearColor != color )
299 // mSceneObject is being used in a separate thread; queue a message to set the value
300 BakeClearColorMessage( GetEventThreadServices(), *mSceneObject, color );
305 const Vector4& RenderTask::GetClearColor() const
307 return mSceneObject->GetClearColor( GetEventThreadServices().GetEventBufferIndex() );
310 void RenderTask::SetSyncRequired( bool requiresSync )
312 if( mRequiresSync != requiresSync )
314 mRequiresSync = requiresSync;
318 // mSceneObject is being used in a separate thread; queue a message to set the value
319 SetSyncRequiredMessage( GetEventThreadServices(), *mSceneObject, requiresSync );
324 bool RenderTask::IsSyncRequired() const
326 return mRequiresSync;
329 void RenderTask::SetClearEnabled( bool enabled )
331 if ( mClearEnabled != enabled )
333 mClearEnabled = enabled;
337 // mSceneObject is being used in a separate thread; queue a message to set the value
338 SetClearEnabledMessage( GetEventThreadServices(), *mSceneObject, mClearEnabled );
343 bool RenderTask::GetClearEnabled() const
345 return mClearEnabled;
348 void RenderTask::SetCullMode( bool mode )
350 if ( mCullMode != mode )
356 // mSceneObject is being used in a separate thread; queue a message to set the value
357 SetCullModeMessage( GetEventThreadServices(), *mSceneObject, mCullMode );
362 bool RenderTask::GetCullMode() const
367 void RenderTask::SetRefreshRate( unsigned int refreshRate )
369 DALI_LOG_TRACE_METHOD_FMT(gLogRender, "this:%p rate:%d\n", this, refreshRate);
370 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::SetRefreshRate(this:%p, %d)\n", this, refreshRate);
372 mRefreshRate = refreshRate; // cached for GetRefreshRate()
374 // Note - even when refreshRate is the same as mRefreshRate, a message should be sent
378 // mSceneObject is being used in a separate thread; queue a message to set the value
379 SetRefreshRateMessage( GetEventThreadServices(), *mSceneObject, refreshRate );
383 unsigned int RenderTask::GetRefreshRate() const
388 bool RenderTask::IsHittable( Vector2& screenCoords ) const
390 // True when input is enabled, source & camera actor are valid
391 bool inputEnabled( false );
393 Actor* sourceActor = GetSourceActor();
394 CameraActor* cameraActor = GetCameraActor();
396 if ( mInputEnabled &&
397 NULL != sourceActor &&
398 sourceActor->OnStage() &&
399 NULL != cameraActor &&
400 cameraActor->OnStage() )
402 // If the actors are rendered off-screen, then the screen coordinates must be converted
403 // and the conversion function will tell us if they are inside or outside
404 if ( TranslateCoordinates( screenCoords ) )
406 // This is a suitable render-task for input handling
414 bool RenderTask::TranslateCoordinates( Vector2& screenCoords ) const
416 // return true for on-screen tasks
418 // If the actors are rendered off-screen, then the screen coordinates must be converted
419 // the function should only be called for offscreen tasks
420 if( mFrameBufferImage && mMappingConnector.mActor )
422 CameraActor* localCamera = GetCameraActor();
423 StagePtr stage = Stage::GetCurrent();
426 CameraActor& defaultCamera = stage->GetDefaultCameraActor();
430 Vector2 size( stage->GetSize() );
431 viewport.x = viewport.y = 0;
432 viewport.width = size.width;
433 viewport.height = size.height;
435 float localX, localY;
436 inside = mMappingConnector.mActor->ScreenToLocal(defaultCamera.GetViewMatrix(), defaultCamera.GetProjectionMatrix(), viewport, localX, localY, screenCoords.x, screenCoords.y);
437 Vector3 actorSize = mMappingConnector.mActor->GetCurrentSize();
438 if( inside && localX >= 0.f && localX <= actorSize.x && localY >= 0.f && localY <= actorSize.y)
440 screenCoords.x = localX;
441 screenCoords.y = localY;
454 else if ( mFrameBufferImage && mScreenToFrameBufferFunction )
456 inside = mScreenToFrameBufferFunction( screenCoords );
461 bool RenderTask::IsSystemLevel() const
463 return mIsSystemLevel;
466 bool RenderTask::WorldToViewport(const Vector3 &position, float& viewportX, float& viewportY) const
468 CameraActor* cam = GetCameraActor();
470 Vector4 pos(position);
473 Vector4 viewportPosition;
476 GetViewport( viewport );
478 bool ok = ProjectFull(pos,
479 cam->GetViewMatrix(),
480 cam->GetProjectionMatrix(),
488 viewportX = viewportPosition.x;
489 viewportY = viewportPosition.y;
495 bool RenderTask::ViewportToLocal(Actor* actor, float viewportX, float viewportY, float &localX, float &localY) const
497 return actor->ScreenToLocal( *this, localX, localY, viewportX, viewportY );
500 SceneGraph::RenderTask* RenderTask::CreateSceneObject()
502 // This should only be called once, with no existing scene-object
503 DALI_ASSERT_DEBUG( NULL == mSceneObject );
505 // Keep the raw-pointer until DiscardSceneObject is called
506 mSceneObject = SceneGraph::RenderTask::New();
508 // 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
509 unsigned int resourceId = 0;
510 bool isNativeFBO = false;
511 if( mFrameBufferImage )
513 Dali::Internal::FrameBufferImage& impl = GetImplementation( mFrameBufferImage );
515 resourceId = impl.GetResourceId();
516 isNativeFBO = impl.IsNativeFbo();
519 // mSceneObject is being used in a separate thread; queue a message to set the value
520 SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId, isNativeFBO );
522 // Send messages to set other properties that may have changed since last time we were on stage
523 SetExclusiveMessage( GetEventThreadServices(), *mSceneObject, mExclusive );
524 SetClearColorMessage( GetEventThreadServices(), *mSceneObject, mClearColor );
525 SetClearEnabledMessage( GetEventThreadServices(), *mSceneObject, mClearEnabled );
526 SetCullModeMessage( GetEventThreadServices(), *mSceneObject, mCullMode );
527 SetRefreshRateMessage( GetEventThreadServices(), *mSceneObject, mRefreshRate );
529 // Caller takes ownership
533 SceneGraph::RenderTask* RenderTask::GetRenderTaskSceneObject()
538 void RenderTask::DiscardSceneObject()
540 // mSceneObject is not owned; throw away the raw-pointer
543 // if we have a frame buffer we need to track connection status
544 if(mFrameBufferImage)
546 GetImplementation(mFrameBufferImage).Disconnect();
550 /********************************************************************************
551 ******************************** PROPERTY METHODS **************************
552 ********************************************************************************/
554 unsigned int RenderTask::GetDefaultPropertyCount() const
556 return DEFAULT_PROPERTY_COUNT;
559 void RenderTask::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
561 indices.Reserve( DEFAULT_PROPERTY_COUNT );
563 for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
565 indices.PushBack( i );
569 const char* RenderTask::GetDefaultPropertyName( Property::Index index ) const
571 if( index < DEFAULT_PROPERTY_COUNT )
573 return DEFAULT_PROPERTY_DETAILS[index].name;
581 Property::Index RenderTask::GetDefaultPropertyIndex(const std::string& name) const
583 Property::Index index = Property::INVALID_INDEX;
585 // Look for name in default properties
586 for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
588 if( 0 == strcmp( name.c_str(), DEFAULT_PROPERTY_DETAILS[i].name ) ) // dont want to convert rhs to string
598 bool RenderTask::IsDefaultPropertyWritable(Property::Index index) const
600 return DEFAULT_PROPERTY_DETAILS[ index ].writable;
603 bool RenderTask::IsDefaultPropertyAnimatable(Property::Index index) const
605 return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
608 bool RenderTask::IsDefaultPropertyAConstraintInput( Property::Index index ) const
610 return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
613 Property::Type RenderTask::GetDefaultPropertyType(Property::Index index) const
615 if( index < DEFAULT_PROPERTY_COUNT )
617 return DEFAULT_PROPERTY_DETAILS[index].type;
620 // index out of range...return Property::NONE
621 return Property::NONE;
624 void RenderTask::SetDefaultProperty( Property::Index index, const Property::Value& property )
628 case Dali::RenderTask::Property::VIEWPORT_POSITION:
630 SetViewportPosition( property.Get<Vector2>() );
633 case Dali::RenderTask::Property::VIEWPORT_SIZE:
635 SetViewportSize( property.Get<Vector2>() );
638 case Dali::RenderTask::Property::CLEAR_COLOR:
640 SetClearColor( property.Get<Vector4>() );
643 case Dali::RenderTask::Property::REQUIRES_SYNC:
645 SetSyncRequired( property.Get<bool>() );
656 Property::Value RenderTask::GetDefaultProperty(Property::Index index) const
658 Property::Value value;
663 case Dali::RenderTask::Property::VIEWPORT_POSITION:
665 value = GetCurrentViewportPosition();
668 case Dali::RenderTask::Property::VIEWPORT_SIZE:
670 value = GetCurrentViewportSize();
673 case Dali::RenderTask::Property::CLEAR_COLOR:
675 value = GetClearColor();
678 case Dali::RenderTask::Property::REQUIRES_SYNC:
680 value = IsSyncRequired();
686 DALI_ASSERT_ALWAYS(false && "RenderTask property index out of range"); // should not come here
694 const SceneGraph::PropertyOwner* RenderTask::GetSceneObject() const
699 const SceneGraph::PropertyBase* RenderTask::GetSceneObjectAnimatableProperty( Property::Index index ) const
701 DALI_ASSERT_ALWAYS( IsPropertyAnimatable(index) && "Property is not animatable" );
703 const SceneGraph::PropertyBase* property( NULL );
705 // This method should only return a property which is part of the scene-graph
706 if( mSceneObject != NULL )
710 case Dali::RenderTask::Property::VIEWPORT_POSITION:
711 property = &mSceneObject->mViewportPosition;
714 case Dali::RenderTask::Property::VIEWPORT_SIZE:
715 property = &mSceneObject->mViewportSize;
718 case Dali::RenderTask::Property::CLEAR_COLOR:
719 property = &mSceneObject->mClearColor;
730 const PropertyInputImpl* RenderTask::GetSceneObjectInputProperty( Property::Index index ) const
732 const PropertyInputImpl* property( NULL );
733 if( mSceneObject != NULL )
737 case Dali::RenderTask::Property::VIEWPORT_POSITION:
738 property = &mSceneObject->mViewportPosition;
741 case Dali::RenderTask::Property::VIEWPORT_SIZE:
742 property = &mSceneObject->mViewportSize;
745 case Dali::RenderTask::Property::CLEAR_COLOR:
746 property = &mSceneObject->mClearColor;
757 bool RenderTask::HasFinished()
759 bool finished = false;
760 const unsigned int counter = mSceneObject->GetRenderedOnceCounter();
762 if( mRefreshOnceCounter < counter )
765 mRefreshOnceCounter = counter;
768 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::HasFinished()=%s SCRT:%p SC\n", finished?"T":"F", mSceneObject);
773 void RenderTask::EmitSignalFinish()
775 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::EmitSignalFinish(this:%p)\n", this);
777 if( !mSignalFinished.Empty() )
779 Dali::RenderTask handle( this );
780 mSignalFinished.Emit(handle );
784 Dali::RenderTask::RenderTaskSignalType& RenderTask::FinishedSignal()
786 return mSignalFinished;
789 bool RenderTask::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
791 bool connected( true );
792 RenderTask* renderTask = dynamic_cast<RenderTask*>(object);
794 if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
796 renderTask->FinishedSignal().Connect( tracker, functor );
800 // signalName does not match any signal
807 RenderTask::RenderTask( bool isSystemLevel )
808 : mSceneObject( NULL ),
809 mSourceConnector( Connector::SOURCE_CONNECTOR, *this ),
810 mCameraConnector( Connector::CAMERA_CONNECTOR, *this ),
811 mMappingConnector( Connector::MAPPING_CONNECTOR, *this ),
812 mClearColor( Dali::RenderTask::DEFAULT_CLEAR_COLOR ),
813 mRefreshRate( Dali::RenderTask::DEFAULT_REFRESH_RATE ),
814 mRefreshOnceCounter( 0u ),
815 mScreenToFrameBufferFunction( Dali::RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION ),
816 mExclusive( Dali::RenderTask::DEFAULT_EXCLUSIVE ),
817 mInputEnabled( Dali::RenderTask::DEFAULT_INPUT_ENABLED ),
818 mClearEnabled( Dali::RenderTask::DEFAULT_CLEAR_ENABLED ),
819 mCullMode( Dali::RenderTask::DEFAULT_CULL_MODE ),
820 mIsSystemLevel( isSystemLevel ),
821 mRequiresSync( false )
823 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::RenderTask(this:%p)\n", this);
826 RenderTask::~RenderTask()
828 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::~RenderTask(this:%p)\n", this);
831 // Helper class for connecting Nodes to the scene-graph RenderTask
833 RenderTask::Connector::Connector( Type type, RenderTask& renderTask )
835 mRenderTask( renderTask ),
841 RenderTask::Connector::~Connector()
846 void RenderTask::Connector::SetActor( Actor* actor )
848 if ( mActor != actor )
852 mActor->RemoveObserver( *this );
859 mActor->AddObserver( *this );
866 void RenderTask::Connector::SceneObjectAdded( Object& object )
871 void RenderTask::Connector::SceneObjectRemoved( Object& object )
876 void RenderTask::Connector::ObjectDestroyed( Object& object )
878 if ( SOURCE_CONNECTOR == mType )
880 const Stage* stage = Stage::GetCurrent();
883 stage->GetRenderTaskList().SetExclusive( &mRenderTask, false );
888 mCamera = NULL; // only meaningful for the camera connector but no simple way to distinguish
893 void RenderTask::Connector::UpdateRenderTask()
895 // Guard to allow handle destruction after Core has been destroyed
896 if( Internal::Stage::IsInstalled() &&
897 mRenderTask.mSceneObject )
899 const SceneGraph::Node* node( NULL );
901 // Check whether a Node exists in the scene-graph
902 if ( NULL != mActor )
904 const SceneGraph::PropertyOwner* object = mActor->GetSceneObject();
905 if ( NULL != object )
907 // actors only point to nodes as their scene objects
908 node = static_cast< const SceneGraph::Node* >( object );
912 //the mapping node is not used in the scene graph
913 if ( SOURCE_CONNECTOR == mType )
915 SetSourceNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
917 else if( CAMERA_CONNECTOR == mType )
919 SetCameraMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node, mCamera );
924 } // namespace Internal