2 * Copyright (c) 2014 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 if(mFrameBufferImage)
159 GetImplementation(mFrameBufferImage).Connect();
161 resourceId = GetImplementation( mFrameBufferImage ).GetResourceId();
164 // mSceneObject is being used in a separate thread; queue a message to set the value
165 SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId );
169 // update target frame buffer
170 mFrameBufferImage = image;
175 Dali::FrameBufferImage RenderTask::GetTargetFrameBuffer() const
177 return mFrameBufferImage;
180 void RenderTask::SetScreenToFrameBufferFunction( ScreenToFrameBufferFunction conversionFunction )
182 mScreenToFrameBufferFunction = conversionFunction;
185 RenderTask::ScreenToFrameBufferFunction RenderTask::GetScreenToFrameBufferFunction() const
187 return mScreenToFrameBufferFunction;
190 void RenderTask::SetScreenToFrameBufferMappingActor( Actor* mappingActor )
192 mMappingConnector.SetActor( mappingActor );
195 Actor* RenderTask::GetScreenToFrameBufferMappingActor() const
197 return mMappingConnector.mActor;
200 void RenderTask::SetViewportPosition(const Vector2& value)
202 BakeViewportPositionMessage( GetEventThreadServices(), *mSceneObject, value );
205 Vector2 RenderTask::GetCurrentViewportPosition() const
207 return mSceneObject->GetViewportPosition( GetEventThreadServices().GetEventBufferIndex() );
210 void RenderTask::SetViewportSize(const Vector2& value)
212 BakeViewportSizeMessage( GetEventThreadServices(), *mSceneObject, value );
215 Vector2 RenderTask::GetCurrentViewportSize() const
217 return mSceneObject->GetViewportSize( GetEventThreadServices().GetEventBufferIndex() );
220 void RenderTask::SetViewport( const Viewport& viewport )
222 SetViewportPosition(Vector2(viewport.x, viewport.y));
223 SetViewportSize(Vector2(viewport.width, viewport.height));
226 void RenderTask::GetViewport( Viewport& viewPort ) const
228 BufferIndex bufferIndex = GetEventThreadServices().GetEventBufferIndex();
230 if(!mSceneObject->GetViewportEnabled( bufferIndex ))
232 if ( mFrameBufferImage )
234 viewPort.x = viewPort.y = 0;
235 viewPort.width = mFrameBufferImage.GetWidth();
236 viewPort.height = mFrameBufferImage.GetHeight();
240 Internal::Stage* stage = Internal::Stage::GetCurrent();
243 Vector2 size( stage->GetSize() );
244 viewPort.x = viewPort.y = 0;
245 viewPort.width = size.width;
246 viewPort.height = size.height;
252 const Vector2& position = mSceneObject->GetViewportPosition(bufferIndex);
253 const Vector2& size = mSceneObject->GetViewportSize(bufferIndex);
254 viewPort.x = position.x;
255 viewPort.y = position.y;
256 viewPort.width = size.width;
257 viewPort.height = size.height;
261 void RenderTask::SetClearColor( const Vector4& color )
263 if ( mClearColor != color )
269 // mSceneObject is being used in a separate thread; queue a message to set the value
270 BakeClearColorMessage( GetEventThreadServices(), *mSceneObject, color );
275 const Vector4& RenderTask::GetClearColor() const
277 return mSceneObject->GetClearColor( GetEventThreadServices().GetEventBufferIndex() );
280 void RenderTask::SetClearEnabled( bool enabled )
282 if ( mClearEnabled != enabled )
284 mClearEnabled = enabled;
288 // mSceneObject is being used in a separate thread; queue a message to set the value
289 SetClearEnabledMessage( GetEventThreadServices(), *mSceneObject, mClearEnabled );
294 bool RenderTask::GetClearEnabled() const
296 return mClearEnabled;
299 void RenderTask::SetCullMode( bool mode )
301 if ( mCullMode != mode )
307 // mSceneObject is being used in a separate thread; queue a message to set the value
308 SetCullModeMessage( GetEventThreadServices(), *mSceneObject, mCullMode );
313 bool RenderTask::GetCullMode() const
318 void RenderTask::SetRefreshRate( unsigned int refreshRate )
320 DALI_LOG_TRACE_METHOD_FMT(gLogRender, "this:%p rate:%d\n", this, refreshRate);
321 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::SetRefreshRate(this:%p, %d)\n", this, refreshRate);
323 mRefreshRate = refreshRate; // cached for GetRefreshRate()
325 // Note - even when refreshRate is the same as mRefreshRate, a message should be sent
329 // mSceneObject is being used in a separate thread; queue a message to set the value
330 SetRefreshRateMessage( GetEventThreadServices(), *mSceneObject, refreshRate );
334 unsigned int RenderTask::GetRefreshRate() const
339 bool RenderTask::IsHittable( Vector2& screenCoords ) const
341 // True when input is enabled, source & camera actor are valid
342 bool inputEnabled( false );
344 Actor* sourceActor = GetSourceActor();
345 CameraActor* cameraActor = GetCameraActor();
347 if ( mInputEnabled &&
348 NULL != sourceActor &&
349 sourceActor->OnStage() &&
350 NULL != cameraActor &&
351 cameraActor->OnStage() )
353 // If the actors are rendered off-screen, then the screen coordinates must be converted
354 // and the conversion function will tell us if they are inside or outside
355 if ( TranslateCoordinates( screenCoords ) )
357 // This is a suitable render-task for input handling
365 bool RenderTask::TranslateCoordinates( Vector2& screenCoords ) const
367 // return true for on-screen tasks
369 // If the actors are rendered off-screen, then the screen coordinates must be converted
370 // the function should only be called for offscreen tasks
371 if( mFrameBufferImage && mMappingConnector.mActor )
373 CameraActor* localCamera = GetCameraActor();
374 StagePtr stage = Stage::GetCurrent();
377 CameraActor& defaultCamera = stage->GetDefaultCameraActor();
381 Vector2 size( stage->GetSize() );
382 viewport.x = viewport.y = 0;
383 viewport.width = size.width;
384 viewport.height = size.height;
386 float localX, localY;
387 inside = mMappingConnector.mActor->ScreenToLocal(defaultCamera.GetViewMatrix(), defaultCamera.GetProjectionMatrix(), viewport, localX, localY, screenCoords.x, screenCoords.y);
388 Vector3 actorSize = mMappingConnector.mActor->GetCurrentSize();
389 if( inside && localX >= 0.f && localX <= actorSize.x && localY >= 0.f && localY <= actorSize.y)
391 screenCoords.x = localX;
392 screenCoords.y = localY;
405 else if ( mFrameBufferImage && mScreenToFrameBufferFunction )
407 inside = mScreenToFrameBufferFunction( screenCoords );
412 bool RenderTask::IsSystemLevel() const
414 return mIsSystemLevel;
417 bool RenderTask::WorldToViewport(const Vector3 &position, float& viewportX, float& viewportY) const
419 CameraActor* cam = GetCameraActor();
421 Vector4 pos(position);
424 Vector4 viewportPosition;
427 GetViewport( viewport );
429 bool ok = ProjectFull(pos,
430 cam->GetViewMatrix(),
431 cam->GetProjectionMatrix(),
439 viewportX = viewportPosition.x;
440 viewportY = viewportPosition.y;
446 bool RenderTask::ViewportToLocal(Actor* actor, float viewportX, float viewportY, float &localX, float &localY) const
448 return actor->ScreenToLocal( *this, localX, localY, viewportX, viewportY );
451 SceneGraph::RenderTask* RenderTask::CreateSceneObject()
453 // This should only be called once, with no existing scene-object
454 DALI_ASSERT_DEBUG( NULL == mSceneObject );
456 // Keep the raw-pointer until DiscardSceneObject is called
457 mSceneObject = SceneGraph::RenderTask::New();
459 // 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
460 unsigned int resourceId = 0;
461 if(mFrameBufferImage)
463 GetImplementation(mFrameBufferImage).Connect();
465 resourceId = GetImplementation( mFrameBufferImage ).GetResourceId();
468 // mSceneObject is being used in a separate thread; queue a message to set the value
469 SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId );
471 // Send messages to set other properties that may have changed since last time we were on stage
472 SetExclusiveMessage( GetEventThreadServices(), *mSceneObject, mExclusive );
473 SetClearColorMessage( GetEventThreadServices(), *mSceneObject, mClearColor );
474 SetClearEnabledMessage( GetEventThreadServices(), *mSceneObject, mClearEnabled );
475 SetCullModeMessage( GetEventThreadServices(), *mSceneObject, mCullMode );
476 SetRefreshRateMessage( GetEventThreadServices(), *mSceneObject, mRefreshRate );
478 // Caller takes ownership
482 SceneGraph::RenderTask* RenderTask::GetRenderTaskSceneObject()
487 void RenderTask::DiscardSceneObject()
489 // mSceneObject is not owned; throw away the raw-pointer
492 // if we have a frame buffer we need to track connection status
493 if(mFrameBufferImage)
495 GetImplementation(mFrameBufferImage).Disconnect();
499 /********************************************************************************
500 ******************************** PROPERTY METHODS **************************
501 ********************************************************************************/
503 unsigned int RenderTask::GetDefaultPropertyCount() const
505 return DEFAULT_PROPERTY_COUNT;
508 void RenderTask::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
510 indices.Reserve( DEFAULT_PROPERTY_COUNT );
512 for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
514 indices.PushBack( i );
518 const char* RenderTask::GetDefaultPropertyName( Property::Index index ) const
520 if( index < DEFAULT_PROPERTY_COUNT )
522 return DEFAULT_PROPERTY_DETAILS[index].name;
530 Property::Index RenderTask::GetDefaultPropertyIndex(const std::string& name) const
532 Property::Index index = Property::INVALID_INDEX;
534 // Look for name in default properties
535 for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
537 if( 0 == strcmp( name.c_str(), DEFAULT_PROPERTY_DETAILS[i].name ) ) // dont want to convert rhs to string
547 bool RenderTask::IsDefaultPropertyWritable(Property::Index index) const
549 return DEFAULT_PROPERTY_DETAILS[ index ].writable;
552 bool RenderTask::IsDefaultPropertyAnimatable(Property::Index index) const
554 return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
557 bool RenderTask::IsDefaultPropertyAConstraintInput( Property::Index index ) const
559 return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
562 Property::Type RenderTask::GetDefaultPropertyType(Property::Index index) const
564 if( index < DEFAULT_PROPERTY_COUNT )
566 return DEFAULT_PROPERTY_DETAILS[index].type;
569 // index out of range...return Property::NONE
570 return Property::NONE;
573 void RenderTask::SetDefaultProperty( Property::Index index, const Property::Value& property )
577 case Dali::RenderTask::Property::VIEWPORT_POSITION:
579 SetViewportPosition( property.Get<Vector2>() );
582 case Dali::RenderTask::Property::VIEWPORT_SIZE:
584 SetViewportSize( property.Get<Vector2>() );
587 case Dali::RenderTask::Property::CLEAR_COLOR:
589 SetClearColor( property.Get<Vector4>() );
600 Property::Value RenderTask::GetDefaultProperty(Property::Index index) const
602 Property::Value value;
607 case Dali::RenderTask::Property::VIEWPORT_POSITION:
609 value = GetCurrentViewportPosition();
612 case Dali::RenderTask::Property::VIEWPORT_SIZE:
614 value = GetCurrentViewportSize();
617 case Dali::RenderTask::Property::CLEAR_COLOR:
619 value = GetClearColor();
625 DALI_ASSERT_ALWAYS(false && "RenderTask property index out of range"); // should not come here
633 const SceneGraph::PropertyOwner* RenderTask::GetSceneObject() const
638 const SceneGraph::PropertyBase* RenderTask::GetSceneObjectAnimatableProperty( Property::Index index ) const
640 DALI_ASSERT_ALWAYS( IsPropertyAnimatable(index) && "Property is not animatable" );
642 const SceneGraph::PropertyBase* property( NULL );
644 // This method should only return a property which is part of the scene-graph
645 if( mSceneObject != NULL )
649 case Dali::RenderTask::Property::VIEWPORT_POSITION:
650 property = &mSceneObject->mViewportPosition;
653 case Dali::RenderTask::Property::VIEWPORT_SIZE:
654 property = &mSceneObject->mViewportSize;
657 case Dali::RenderTask::Property::CLEAR_COLOR:
658 property = &mSceneObject->mClearColor;
669 const PropertyInputImpl* RenderTask::GetSceneObjectInputProperty( Property::Index index ) const
671 const PropertyInputImpl* property( NULL );
672 if( mSceneObject != NULL )
676 case Dali::RenderTask::Property::VIEWPORT_POSITION:
677 property = &mSceneObject->mViewportPosition;
680 case Dali::RenderTask::Property::VIEWPORT_SIZE:
681 property = &mSceneObject->mViewportSize;
684 case Dali::RenderTask::Property::CLEAR_COLOR:
685 property = &mSceneObject->mViewportSize;
696 bool RenderTask::HasFinished()
698 bool finished = false;
699 const unsigned int counter = mSceneObject->GetRenderedOnceCounter();
701 if( mRefreshOnceCounter < counter )
704 mRefreshOnceCounter = counter;
707 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::HasFinished()=%s SCRT:%p SC\n", finished?"T":"F", mSceneObject);
712 void RenderTask::EmitSignalFinish()
714 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::EmitSignalFinish(this:%p)\n", this);
716 if( !mSignalFinished.Empty() )
718 Dali::RenderTask handle( this );
719 mSignalFinished.Emit(handle );
723 Dali::RenderTask::RenderTaskSignalType& RenderTask::FinishedSignal()
725 return mSignalFinished;
728 bool RenderTask::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
730 bool connected( true );
731 RenderTask* renderTask = dynamic_cast<RenderTask*>(object);
733 if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
735 renderTask->FinishedSignal().Connect( tracker, functor );
739 // signalName does not match any signal
746 RenderTask::RenderTask( bool isSystemLevel )
747 : mSceneObject( NULL ),
748 mSourceConnector( Connector::SOURCE_CONNECTOR, *this ),
749 mCameraConnector( Connector::CAMERA_CONNECTOR, *this ),
750 mMappingConnector( Connector::MAPPING_CONNECTOR, *this ),
751 mClearColor( Dali::RenderTask::DEFAULT_CLEAR_COLOR ),
752 mRefreshRate( Dali::RenderTask::DEFAULT_REFRESH_RATE ),
753 mRefreshOnceCounter( 0u ),
754 mScreenToFrameBufferFunction( Dali::RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION ),
755 mExclusive( Dali::RenderTask::DEFAULT_EXCLUSIVE ),
756 mInputEnabled( Dali::RenderTask::DEFAULT_INPUT_ENABLED ),
757 mClearEnabled( Dali::RenderTask::DEFAULT_CLEAR_ENABLED ),
758 mCullMode( Dali::RenderTask::DEFAULT_CULL_MODE ),
759 mIsSystemLevel( isSystemLevel )
761 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::RenderTask(this:%p)\n", this);
764 RenderTask::~RenderTask()
766 DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::~RenderTask(this:%p)\n", this);
769 // Helper class for connecting Nodes to the scene-graph RenderTask
771 RenderTask::Connector::Connector( Type type, RenderTask& renderTask )
773 mRenderTask( renderTask ),
778 RenderTask::Connector::~Connector()
783 void RenderTask::Connector::SetActor( Actor* actor )
785 if ( mActor != actor )
789 mActor->RemoveObserver( *this );
796 mActor->AddObserver( *this );
803 void RenderTask::Connector::SceneObjectAdded( Object& object )
808 void RenderTask::Connector::SceneObjectRemoved( Object& object )
813 void RenderTask::Connector::ObjectDestroyed( Object& object )
815 if ( SOURCE_CONNECTOR == mType )
817 const Stage* stage = Stage::GetCurrent();
820 stage->GetRenderTaskList().SetExclusive( &mRenderTask, false );
829 void RenderTask::Connector::UpdateRenderTask()
831 // Guard to allow handle destruction after Core has been destroyed
832 if( Internal::Stage::IsInstalled() &&
833 mRenderTask.mSceneObject )
835 const SceneGraph::Node* node( NULL );
837 // Check whether a Node exists in the scene-graph
838 if ( NULL != mActor )
840 const SceneGraph::PropertyOwner* object = mActor->GetSceneObject();
841 if ( NULL != object )
843 // actors only point to nodes as their scene objects
844 node = static_cast< const SceneGraph::Node* >( object );
848 //the mapping node is not used in the scene graph
849 if ( SOURCE_CONNECTOR == mType )
851 SetSourceNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
853 else if( CAMERA_CONNECTOR == mType )
855 SetCameraNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
860 } // namespace Internal