2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include "adaptor-impl.h"
21 #include <boost/thread/tss.hpp>
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/integration-api/core.h>
25 #include <dali/integration-api/events/touch-event-integ.h>
26 #include <dali/integration-api/events/notification-event.h>
29 #include <base/update-render-controller.h>
30 #include <base/environment-variables.h>
31 #include <base/performance-logging/performance-interface-factory.h>
32 #include <base/lifecycle-observer.h>
34 #include <internal/common/callback-manager.h>
35 #include <internal/common/trigger-event.h>
36 #include <internal/common/render-surface-impl.h>
37 #include <internal/common/tts-player-impl.h>
38 #include <internal/common/accessibility-manager-impl.h>
39 #include <internal/common/timer-impl.h>
40 #include <internal/common/events/gesture-manager.h>
41 #include <internal/common/events/event-handler.h>
42 #include <internal/common/feedback/feedback-controller.h>
43 #include <internal/common/feedback/feedback-plugin-proxy.h>
44 #include <internal/common/gl/gl-implementation.h>
45 #include <internal/common/gl/egl-sync-implementation.h>
46 #include <internal/common/gl/egl-image-extensions.h>
47 #include <internal/common/gl/egl-factory.h>
48 #include <internal/common/imf-manager-impl.h>
49 #include <internal/common/clipboard-impl.h>
50 #include <internal/common/vsync-monitor.h>
52 #include <slp-logging.h>
67 boost::thread_specific_ptr<Adaptor> gThreadLocalAdaptor;
69 unsigned int GetIntegerEnvironmentVariable( const char* variable, unsigned int defaultValue )
71 const char* variableParameter = std::getenv(variable);
73 // if the parameter exists convert it to an integer, else return the default value
74 unsigned int intValue = variableParameter ? atoi(variableParameter) : defaultValue;
78 } // unnamed namespace
80 Dali::Adaptor* Adaptor::New( RenderSurface *surface, const DeviceLayout& baseLayout )
82 DALI_ASSERT_ALWAYS( surface->GetType() != Dali::RenderSurface::NO_SURFACE && "No surface for adaptor" );
84 Dali::Adaptor* adaptor = new Dali::Adaptor;
85 Adaptor* impl = new Adaptor( *adaptor, surface, baseLayout );
86 adaptor->mImpl = impl;
93 void Adaptor::ParseLogOptions()
95 const char* resourceLogOption = std::getenv(DALI_ENV_ENABLE_LOG);
96 unsigned int logOpts = Integration::Log::ParseLogOptions(resourceLogOption);
98 // get logging options
99 unsigned int logFrameRateFrequency = GetIntegerEnvironmentVariable( DALI_ENV_FPS_TRACKING, 0 ); ;
100 unsigned int logupdateStatusFrequency = GetIntegerEnvironmentVariable( DALI_ENV_UPDATE_STATUS_INTERVAL, 0 );
101 unsigned int logPerformanceLevel = GetIntegerEnvironmentVariable( DALI_ENV_LOG_PERFORMANCE, 0 );
103 Dali::Integration::Log::LogFunction logFunction(Dali::SlpPlatform::LogMessage);
105 mLogOptions.SetOptions( logFunction, logOpts, logFrameRateFrequency, logupdateStatusFrequency, logPerformanceLevel );
107 // all threads here (event, update, and render) will send their logs to SLP Platform's LogMessage handler.
108 // Dali::Integration::Log::LogFunction logFunction(Dali::SlpPlatform::LogMessage);
109 if( mLogOptions.IsFilterEnabled( Debug::LogEventThread ))
111 mLogOptions.InstallLogFunction();
115 void Adaptor::Initialize()
119 mPlatformAbstraction = new SlpPlatform::SlpPlatformAbstraction;
121 if( mLogOptions.GetPerformanceLoggingLevel() > 0 )
123 mPerformanceInterface = PerformanceInterfaceFactory::CreateInterface( *this, mLogOptions );
126 mCallbackManager = CallbackManager::New();
128 PositionSize size = mSurface->GetPositionSize();
130 mGestureManager = new GestureManager(*this, Vector2(size.width, size.height), mCallbackManager);
132 mGLES = new GlImplementation;
134 mEglFactory = new EglFactory();
136 EglSyncImplementation* eglSyncImpl = mEglFactory->GetSyncImplementation();
138 mCore = Integration::Core::New( *this, *mPlatformAbstraction, *mGLES, *eglSyncImpl, *mGestureManager );
140 mNotificationTrigger = new TriggerEvent( boost::bind(&Adaptor::SendNotificationEvent, this) );
142 mVSyncMonitor = new VSyncMonitor;
144 mUpdateRenderController = new UpdateRenderController( *this, mLogOptions );
146 mDaliFeedbackPlugin = new FeedbackPluginProxy( FeedbackPluginProxy::DEFAULT_OBJECT_NAME );
147 DALI_LOG_RESOURCE("[INIT] Resource log start\n");
152 // Ensure stop status
155 // Release first as we do not want any access to Adaptor as it is being destroyed.
156 gThreadLocalAdaptor.release();
158 for ( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
160 (*iter)->OnDestroy();
163 if (mUpdateRenderController)
165 delete mUpdateRenderController;
166 mUpdateRenderController = NULL;
171 delete mVSyncMonitor;
172 mVSyncMonitor = NULL;
177 delete mEventHandler;
178 mEventHandler = NULL;
187 // Delete EGL factory after Core, otherwise we may have a crash from GL resource destructors
194 // Delete feedback controller before feedback plugin & style monitor dependencies
195 delete mFeedbackController;
197 if (mDaliFeedbackPlugin)
199 delete mDaliFeedbackPlugin;
200 mDaliFeedbackPlugin = NULL;
211 delete mGestureManager;
212 mGestureManager = NULL;
215 if (mPlatformAbstraction)
217 delete mPlatformAbstraction;
218 mPlatformAbstraction = NULL;
221 if (mCallbackManager)
223 delete mCallbackManager;
224 mCallbackManager = NULL;
227 if( mPerformanceInterface )
229 delete mPerformanceInterface;
230 mPerformanceInterface = NULL;
233 // uninstall it on this thread (main actor thread)
234 Dali::Integration::Log::UninstallLogFunction();
236 DALI_LOG_RESOURCE("[FIN] Resource log end\n");
239 void Adaptor::Start()
241 // it doesn't support restart after stop at this moment
242 // to support restarting, need more testing
243 if( READY != mState )
248 // Start the callback manager
249 mCallbackManager->Start();
251 // create event handler
252 mEventHandler = new EventHandler( mSurface, *this, *mGestureManager, *this, mDragAndDropDetector );
254 if( mDeferredRotationObserver != NULL )
256 mEventHandler->SetRotationObserver(mDeferredRotationObserver);
257 mDeferredRotationObserver = NULL;
260 // guarantee map the surface before starting render-thread.
263 // NOTE: dpi must be set before starting the render thread
264 // use default or command line settings if not run on device
266 // set the DPI value for font rendering
267 unsigned int dpiHor, dpiVer;
269 mSurface->GetDpi(dpiHor, dpiVer);
271 // tell core about the value
272 mCore->SetDpi(dpiHor, dpiVer);
274 mCore->SetDpi(mHDpi, mVDpi);
277 // Tell the core the size of the surface just before we start the render-thread
278 PositionSize size = mSurface->GetPositionSize();
279 mCore->SurfaceResized( size.width, size.height );
281 // Start the update & render threads
282 mUpdateRenderController->Start();
286 SendNotificationEvent(); // Ensure any startup messages are processed.
288 if ( !mFeedbackController )
290 // Start sound & haptic feedback
291 mFeedbackController = new FeedbackController( *mDaliFeedbackPlugin );
294 for ( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
300 // Dali::Internal::Adaptor::Adaptor::Pause
301 void Adaptor::Pause()
303 // Only pause the adaptor if we're actually running.
304 if( RUNNING == mState )
306 // Inform observers that we are about to be paused.
307 for( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
312 // Reset the event handler when adaptor paused
315 mEventHandler->Reset();
318 mUpdateRenderController->Pause();
324 // Dali::Internal::Adaptor::Adaptor::Resume
325 void Adaptor::Resume()
327 // Only resume the adaptor if we are in the suspended state.
328 if( PAUSED == mState )
331 mUpdateRenderController->Resume();
334 // Reset the event handler when adaptor resumed
337 mEventHandler->Reset();
340 // Inform observers that we have resumed.
341 for( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
346 SendNotificationEvent(); // Ensure any outstanding messages are processed
352 if( RUNNING == mState ||
354 PAUSED_WHILE_HIDDEN == mState )
356 for( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
361 mUpdateRenderController->Stop();
364 // Delete the TTS player
365 for(int i =0; i < Dali::TtsPlayer::MODE_NUM; i++)
369 mTtsPlayers[i].Reset();
373 delete mEventHandler;
374 mEventHandler = NULL;
376 delete mNotificationTrigger;
377 mNotificationTrigger = NULL;
379 mCallbackManager->Stop();
385 void Adaptor::FeedTouchPoint( TouchPoint& point, int timeStamp )
387 mEventHandler->FeedTouchPoint( point, timeStamp );
390 void Adaptor::FeedWheelEvent( MouseWheelEvent& wheelEvent )
392 mEventHandler->FeedWheelEvent( wheelEvent );
395 void Adaptor::FeedKeyEvent( KeyEvent& keyEvent )
397 mEventHandler->FeedKeyEvent( keyEvent );
400 bool Adaptor::MoveResize( const PositionSize& positionSize )
402 PositionSize old = mSurface->GetPositionSize();
404 // just resize the surface. The driver should automatically resize the egl Surface (untested)
405 // EGL Spec says : EGL window surfaces need to be resized when their corresponding native window
406 // is resized. Implementations typically use hooks into the OS and native window
407 // system to perform this resizing on demand, transparently to the client.
408 mSurface->MoveResize( positionSize );
410 if(old.width != positionSize.width || old.height != positionSize.height)
412 SurfaceSizeChanged(positionSize);
418 void Adaptor::SurfaceResized( const PositionSize& positionSize )
420 PositionSize old = mSurface->GetPositionSize();
422 // Called by an application, when it has resized a window outside of Dali.
423 // The EGL driver automatically detects X Window resize calls, and resizes
424 // the EGL surface for us.
425 mSurface->MoveResize( positionSize );
427 if(old.width != positionSize.width || old.height != positionSize.height)
429 SurfaceSizeChanged(positionSize);
433 void Adaptor::ReplaceSurface( Dali::RenderSurface& surface )
435 // adaptor implementation needs the implementation of
436 RenderSurface* internalSurface = dynamic_cast<Internal::Adaptor::RenderSurface*>( &surface );
437 DALI_ASSERT_ALWAYS( internalSurface && "Incorrect surface" );
439 mSurface = internalSurface;
441 SurfaceSizeChanged( internalSurface->GetPositionSize() );
443 // flush the event queue to give update and render threads chance
444 // to start processing messages for new camera setup etc as soon as possible
445 SendNotificationEvent();
447 // this method is synchronous
448 mUpdateRenderController->ReplaceSurface(internalSurface);
451 void Adaptor::RenderSync()
453 mUpdateRenderController->RenderSync();
456 Dali::RenderSurface& Adaptor::GetSurface() const
461 Dali::TtsPlayer Adaptor::GetTtsPlayer(Dali::TtsPlayer::Mode mode)
463 if(!mTtsPlayers[mode])
465 // Create the TTS player when it needed, because it can reduce launching time.
466 mTtsPlayers[mode] = TtsPlayer::New(mode);
469 return mTtsPlayers[mode];
472 bool Adaptor::AddIdle(boost::function<void(void)> callBack)
474 bool idleAdded(false);
476 // Only add an idle if the Adaptor is actually running
477 if( RUNNING == mState )
479 idleAdded = mCallbackManager->AddCallback(callBack, CallbackManager::IDLE_PRIORITY);
485 bool Adaptor::CallFromMainLoop(boost::function<void(void)> callBack)
487 bool callAdded(false);
489 // Only allow the callback if the Adaptor is actually running
490 if ( RUNNING == mState )
492 callAdded = mCallbackManager->AddCallback(callBack, CallbackManager::DEFAULT_PRIORITY);
498 Dali::Adaptor& Adaptor::Get()
500 DALI_ASSERT_ALWAYS( gThreadLocalAdaptor.get() != NULL && "Adaptor not instantiated" );
501 return gThreadLocalAdaptor->mAdaptor;
504 bool Adaptor::IsAvailable()
506 return gThreadLocalAdaptor.get() != NULL;
509 Dali::Integration::Core& Adaptor::GetCore()
514 void Adaptor::DisableVSync()
516 mUpdateRenderController->DisableVSync();
519 void Adaptor::SetDpi(size_t hDpi, size_t vDpi)
525 EglFactory& Adaptor::GetEGLFactory() const
527 DALI_ASSERT_DEBUG( mEglFactory && "EGL Factory not created" );
531 EglFactoryInterface& Adaptor::GetEGLFactoryInterface() const
536 Integration::GlAbstraction& Adaptor::GetGlAbstraction() const
538 DALI_ASSERT_DEBUG( mGLES && "GLImplementation not created" );
542 Dali::Integration::PlatformAbstraction& Adaptor::GetPlatformAbstractionInterface()
544 return *mPlatformAbstraction;
547 Dali::Integration::GlAbstraction& Adaptor::GetGlesInterface()
552 TriggerEventInterface& Adaptor::GetTriggerEventInterface()
554 return *mNotificationTrigger;
556 RenderSurface* Adaptor::GetRenderSurfaceInterface()
560 VSyncMonitorInterface* Adaptor::GetVSyncMonitorInterface()
562 return mVSyncMonitor;
565 KernelTraceInterface& Adaptor::GetKernelTraceInterface()
567 return mKernelTracer;
570 PerformanceInterface* Adaptor::GetPerformanceInterface()
572 return mPerformanceInterface;
575 Integration::PlatformAbstraction& Adaptor::GetPlatformAbstraction() const
577 DALI_ASSERT_DEBUG( mPlatformAbstraction && "PlatformAbstraction not created" );
578 return *mPlatformAbstraction;
581 void Adaptor::SetDragAndDropDetector( DragAndDropDetectorPtr detector )
583 mDragAndDropDetector = detector;
587 mEventHandler->SetDragAndDropDetector( detector );
591 void Adaptor::SetRotationObserver( RotationObserver* observer )
595 mEventHandler->SetRotationObserver( observer );
597 else if( mState == READY )
599 // Set once event handler exists
600 mDeferredRotationObserver = observer;
604 void Adaptor::DestroyTtsPlayer(Dali::TtsPlayer::Mode mode)
606 if(mTtsPlayers[mode])
608 mTtsPlayers[mode].Reset();
612 void Adaptor::AddObserver( LifeCycleObserver& observer )
614 ObserverContainer::iterator match ( find(mObservers.begin(), mObservers.end(), &observer) );
616 if ( match == mObservers.end() )
618 mObservers.push_back( &observer );
622 void Adaptor::RemoveObserver( LifeCycleObserver& observer )
624 ObserverContainer::iterator match ( find(mObservers.begin(), mObservers.end(), &observer) );
626 if ( match != mObservers.end() )
628 mObservers.erase( match );
632 void Adaptor::QueueCoreEvent(const Dali::Integration::Event& event)
636 mCore->QueueEvent(event);
640 void Adaptor::ProcessCoreEvents()
644 if( mPerformanceInterface )
646 mPerformanceInterface->AddMarker( PerformanceMarker::PROCESS_EVENTS_START );
649 mCore->ProcessEvents();
651 if( mPerformanceInterface )
653 mPerformanceInterface->AddMarker( PerformanceMarker::PROCESS_EVENTS_END );
659 void Adaptor::RequestUpdate()
661 // When Dali applications are partially visible behind the lock-screen,
662 // the indicator must be updated (therefore allow updates in the PAUSED state)
663 if ( PAUSED == mState ||
666 mUpdateRenderController->RequestUpdate();
670 void Adaptor::RequestNotificationEventOnIdle()
672 // Only request a notification if the Adaptor is actually running
673 if ( RUNNING == mState )
675 boost::unique_lock<boost::mutex> lock( mIdleInstaller );
677 // check if the idle handle is already installed
678 if( mNotificationOnIdleInstalled )
682 mNotificationOnIdleInstalled = AddIdle( boost::bind( &Adaptor::SendNotificationEventFromIdle, this ) );
686 void Adaptor::OnWindowShown()
688 if ( PAUSED_WHILE_HIDDEN == mState )
690 // Adaptor can now be resumed
695 // Force a render task
700 void Adaptor::OnWindowHidden()
702 if ( STOPPED != mState )
706 // Adaptor cannot be resumed until the window is shown
707 mState = PAUSED_WHILE_HIDDEN;
711 // Dali::Internal::Adaptor::Adaptor::OnDamaged
712 void Adaptor::OnDamaged( const DamageArea& area )
714 // This is needed for the case where Dali window is partially obscured
718 void Adaptor::SurfaceSizeChanged(const PositionSize& positionSize)
720 // let the core know the surface size has changed
721 mCore->SurfaceResized(positionSize.width, positionSize.height);
723 mResizedSignalV2.Emit( mAdaptor );
726 void Adaptor::NotifyLanguageChanged()
728 mLanguageChangedSignalV2.Emit( mAdaptor );
731 void Adaptor::SendNotificationEvent()
733 // Notification events are sent in order to process messages queued (internally) during rendering.
734 Integration::NotificationEvent event;
735 QueueCoreEvent(event);
739 void Adaptor::RequestUpdateOnce()
741 if( PAUSED_WHILE_HIDDEN != mState )
743 if( mUpdateRenderController )
745 mUpdateRenderController->RequestUpdateOnce();
750 void Adaptor::SendNotificationEventFromIdle()
752 SendNotificationEvent();
754 // the idle handle automatically un-installs itself
755 mNotificationOnIdleInstalled = false;
758 void Adaptor::RegisterSingleton(const std::type_info& info, BaseHandle singleton)
762 mSingletonContainer.insert(SingletonPair(info.name(), singleton));
766 BaseHandle Adaptor::GetSingleton(const std::type_info& info) const
768 BaseHandle object = Dali::BaseHandle();
770 SingletonConstIter iter = mSingletonContainer.find(info.name());
771 if(iter != mSingletonContainer.end())
773 object = (*iter).second;
779 Adaptor::Adaptor(Dali::Adaptor& adaptor, RenderSurface* surface, const DeviceLayout& baseLayout)
783 mUpdateRenderController(NULL),
788 mPlatformAbstraction( NULL ),
789 mEventHandler( NULL ),
790 mCallbackManager( NULL ),
791 mNotificationOnIdleInstalled( false ),
792 mNotificationTrigger(NULL),
793 mGestureManager(NULL),
796 mDaliFeedbackPlugin(NULL),
797 mFeedbackController(NULL),
799 mDragAndDropDetector(),
800 mDeferredRotationObserver(NULL),
801 mBaseLayout(baseLayout),
803 mPerformanceInterface(NULL)
805 DALI_ASSERT_ALWAYS( gThreadLocalAdaptor.get() == NULL && "Cannot create more than one Adaptor per thread" );
806 gThreadLocalAdaptor.reset(this);
809 } // namespace Adaptor
811 } // namespace Internal