8be71f8d4c592455322ea39ee3c67747f4649a44
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / common / combined-update-render-controller.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/adaptor/common/combined-update-render-controller.h>
20
21 // EXTERNAL INCLUDES
22 #include <errno.h>
23 #include <dali/integration-api/platform-abstraction.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
27 #include <dali/devel-api/adaptor-framework/thread-settings.h>
28 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
29 #include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
30 #include <dali/internal/graphics/gles/egl-graphics.h>
31 #include <dali/internal/graphics/gles/egl-implementation.h>
32 #include <dali/internal/graphics/common/graphics-interface.h>
33 #include <dali/internal/system/common/environment-options.h>
34 #include <dali/internal/system/common/time-service.h>
35
36 namespace Dali
37 {
38
39 namespace Internal
40 {
41
42 namespace Adaptor
43 {
44
45 namespace
46 {
47
48 const unsigned int CREATED_THREAD_COUNT = 1u;
49
50 const int CONTINUOUS = -1;
51 const int ONCE = 1;
52
53 const unsigned int TRUE = 1u;
54 const unsigned int FALSE = 0u;
55
56 const unsigned int MILLISECONDS_PER_SECOND( 1e+3 );
57 const float        NANOSECONDS_TO_SECOND( 1e-9f );
58 const unsigned int NANOSECONDS_PER_SECOND( 1e+9 );
59 const unsigned int NANOSECONDS_PER_MILLISECOND( 1e+6 );
60
61 // The following values will get calculated at compile time
62 const float        DEFAULT_FRAME_DURATION_IN_SECONDS( 1.0f / 60.0f );
63 const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * MILLISECONDS_PER_SECOND );
64 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * NANOSECONDS_PER_SECOND );
65
66 /**
67  * Handles the use case when an update-request is received JUST before we process a sleep-request. If we did not have an update-request count then
68  * there is a danger that, on the event-thread we could have:
69  *  1) An update-request where we do nothing as Update/Render thread still running.
70  *  2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
71  *
72  * Using a counter means we increment the counter on an update-request, and decrement it on a sleep-request. This handles the above scenario because:
73  *  1) MAIN THREAD:           Update Request: COUNTER = 1
74  *  2) UPDATE/RENDER THREAD:  Do Update/Render, then no Updates required -> Sleep Trigger
75  *  3) MAIN THREAD:           Update Request: COUNTER = 2
76  *  4) MAIN THREAD:           Sleep Request:  COUNTER = 1 -> We do not sleep just yet
77  *
78  * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
79  *  1) MAIN THREAD:           Update Request: COUNTER = 1
80  *  2) UPDATE/RENDER THREAD:  Do Update/Render, then no Updates required -> Sleep Trigger
81  *  3) MAIN THREAD:           Sleep Request:  COUNTER = 0 -> Go to sleep
82  */
83 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
84 } // unnamed namespace
85
86 ///////////////////////////////////////////////////////////////////////////////////////////////////
87 // EVENT THREAD
88 ///////////////////////////////////////////////////////////////////////////////////////////////////
89
90 CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
91 : mFpsTracker( environmentOptions ),
92   mUpdateStatusLogger( environmentOptions ),
93   mEventThreadSemaphore(),
94   mGraphicsInitializeSemaphore(),
95   mUpdateRenderThreadWaitCondition(),
96   mAdaptorInterfaces( adaptorInterfaces ),
97   mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
98   mCore( adaptorInterfaces.GetCore() ),
99   mEnvironmentOptions( environmentOptions ),
100   mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
101   mSleepTrigger( NULL ),
102   mPreRenderCallback( NULL ),
103   mUpdateRenderThread( NULL ),
104   mDefaultFrameDelta( 0.0f ),
105   mDefaultFrameDurationMilliseconds( 0u ),
106   mDefaultFrameDurationNanoseconds( 0u ),
107   mDefaultHalfFrameNanoseconds( 0u ),
108   mUpdateRequestCount( 0u ),
109   mRunning( FALSE ),
110   mUpdateRenderRunCount( 0 ),
111   mDestroyUpdateRenderThread( FALSE ),
112   mUpdateRenderThreadCanSleep( FALSE ),
113   mPendingRequestUpdate( FALSE ),
114   mUseElapsedTimeAfterWait( FALSE ),
115   mNewSurface( NULL ),
116   mDeletedSurface( nullptr ),
117   mPostRendering( FALSE ),
118   mSurfaceResized( FALSE ),
119   mForceClear( FALSE ),
120   mUploadWithoutRendering( FALSE ),
121   mFirstFrameAfterResume( FALSE )
122 {
123   LOG_EVENT_TRACE;
124
125   // Initialise frame delta/duration variables first
126   SetRenderRefreshRate( environmentOptions.GetRenderRefreshRate() );
127
128   // Set the thread-synchronization interface on the render-surface
129   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
130   if( currentSurface )
131   {
132     currentSurface->SetThreadSynchronization( *this );
133   }
134
135   TriggerEventFactoryInterface& triggerFactory = mAdaptorInterfaces.GetTriggerEventFactoryInterface();
136   mSleepTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
137
138   // Initialize to 0 so that it just waits if sem_post has not been called
139   sem_init( &mEventThreadSemaphore, 0, 0 );
140   sem_init( &mGraphicsInitializeSemaphore, 0, 0 );
141 }
142
143 CombinedUpdateRenderController::~CombinedUpdateRenderController()
144 {
145   LOG_EVENT_TRACE;
146
147   Stop();
148
149   delete mPreRenderCallback;
150   delete mSleepTrigger;
151 }
152
153 void CombinedUpdateRenderController::Initialize()
154 {
155   LOG_EVENT_TRACE;
156
157   // Ensure Update/Render Thread not already created
158   DALI_ASSERT_ALWAYS( ! mUpdateRenderThread );
159
160   // Create Update/Render Thread
161   mUpdateRenderThread = new pthread_t();
162   int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this );
163   DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" );
164
165   // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called
166   // When this function returns, the application initialisation on the event thread should occur
167 }
168
169 void CombinedUpdateRenderController::Start()
170 {
171   LOG_EVENT_TRACE;
172
173   DALI_ASSERT_ALWAYS( !mRunning && mUpdateRenderThread );
174
175   // Wait until all threads created in Initialise are up and running
176   for( unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i )
177   {
178     sem_wait( &mEventThreadSemaphore );
179   }
180
181   Integration::RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
182   if( currentSurface )
183   {
184     currentSurface->StartRender();
185   }
186
187   mRunning = TRUE;
188
189   LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
190
191   RunUpdateRenderThread( CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL );
192
193   DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Start\n" );
194 }
195
196 void CombinedUpdateRenderController::Pause()
197 {
198   LOG_EVENT_TRACE;
199
200   mRunning = FALSE;
201
202   PauseUpdateRenderThread();
203
204   AddPerformanceMarker( PerformanceInterface::PAUSED );
205
206   DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Pause\n" );
207 }
208
209 void CombinedUpdateRenderController::Resume()
210 {
211   LOG_EVENT_TRACE;
212
213   if( !mRunning && IsUpdateRenderThreadPaused() )
214   {
215     LOG_EVENT( "Resuming" );
216
217     RunUpdateRenderThread( CONTINUOUS, AnimationProgression::USE_ELAPSED_TIME, UpdateMode::NORMAL );
218
219     AddPerformanceMarker( PerformanceInterface::RESUME );
220
221     mRunning = TRUE;
222     mForceClear = TRUE;
223     mFirstFrameAfterResume = TRUE;
224
225     DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Resume\n" );
226   }
227   else
228   {
229     DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Resume: Already resumed [%d, %d, %d]\n", mRunning, mUpdateRenderRunCount, mUpdateRenderThreadCanSleep );
230   }
231 }
232
233 void CombinedUpdateRenderController::Stop()
234 {
235   LOG_EVENT_TRACE;
236
237   // Stop Rendering and the Update/Render Thread
238   Integration::RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
239   if( currentSurface )
240   {
241     currentSurface->StopRender();
242   }
243
244   StopUpdateRenderThread();
245
246   if( mUpdateRenderThread )
247   {
248     LOG_EVENT( "Destroying UpdateRenderThread" );
249
250     // wait for the thread to finish
251     pthread_join( *mUpdateRenderThread, NULL );
252
253     delete mUpdateRenderThread;
254     mUpdateRenderThread = NULL;
255   }
256
257   mRunning = FALSE;
258
259   DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Stop\n" );
260 }
261
262 void CombinedUpdateRenderController::RequestUpdate()
263 {
264   LOG_EVENT_TRACE;
265
266   // Increment the update-request count to the maximum
267   if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
268   {
269     ++mUpdateRequestCount;
270   }
271
272   if( mRunning && IsUpdateRenderThreadPaused() )
273   {
274     LOG_EVENT( "Processing" );
275
276     RunUpdateRenderThread( CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL );
277   }
278
279   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
280   mPendingRequestUpdate = TRUE;
281 }
282
283 void CombinedUpdateRenderController::RequestUpdateOnce( UpdateMode updateMode )
284 {
285   // Increment the update-request count to the maximum
286   if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
287   {
288     ++mUpdateRequestCount;
289   }
290
291   if( IsUpdateRenderThreadPaused() )
292   {
293     LOG_EVENT_TRACE;
294
295     // Run Update/Render once
296     RunUpdateRenderThread( ONCE, AnimationProgression::NONE, updateMode );
297   }
298 }
299
300 void CombinedUpdateRenderController::ReplaceSurface( Dali::RenderSurfaceInterface* newSurface )
301 {
302   LOG_EVENT_TRACE;
303
304   if( mUpdateRenderThread )
305   {
306     // Set the ThreadSyncronizationInterface on the new surface
307     newSurface->SetThreadSynchronization( *this );
308
309     LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
310
311     // Start replacing the surface.
312     {
313       ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
314       mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
315       mNewSurface = newSurface;
316       mUpdateRenderThreadWaitCondition.Notify( lock );
317     }
318
319     // Wait until the surface has been replaced
320     sem_wait( &mEventThreadSemaphore );
321
322     LOG_EVENT( "Surface replaced, event-thread continuing" );
323   }
324 }
325
326 void CombinedUpdateRenderController::DeleteSurface( Dali::RenderSurfaceInterface* surface )
327 {
328   LOG_EVENT_TRACE;
329
330   if( mUpdateRenderThread )
331   {
332     LOG_EVENT( "Starting to delete the surface, event-thread blocked" );
333
334     // Start replacing the surface.
335     {
336       ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
337       mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will delete the surface now
338       mDeletedSurface = surface;
339       mUpdateRenderThreadWaitCondition.Notify( lock );
340     }
341
342     // Wait until the surface has been deleted
343     sem_wait( &mEventThreadSemaphore );
344
345     LOG_EVENT( "Surface deleted, event-thread continuing" );
346   }
347 }
348
349 void CombinedUpdateRenderController::WaitForGraphicsInitialization()
350 {
351   LOG_EVENT_TRACE;
352
353   if( mUpdateRenderThread )
354   {
355     LOG_EVENT( "Waiting for graphics initialisation, event-thread blocked" );
356
357     // Wait until the graphics has been initialised
358     sem_wait( &mGraphicsInitializeSemaphore );
359
360     LOG_EVENT( "graphics initialised, event-thread continuing" );
361   }
362 }
363
364 void CombinedUpdateRenderController::ResizeSurface()
365 {
366   LOG_EVENT_TRACE;
367
368   LOG_EVENT( "Resize the surface" );
369
370   {
371     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
372     mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
373     mSurfaceResized = TRUE;
374     mUpdateRenderThreadWaitCondition.Notify( lock );
375   }
376 }
377
378 void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOfFramesPerRender )
379 {
380   // Not protected by lock, but written to rarely so not worth adding a lock when reading
381   mDefaultFrameDelta                  = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
382   mDefaultFrameDurationMilliseconds   = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
383   mDefaultFrameDurationNanoseconds    = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
384   mDefaultHalfFrameNanoseconds        = mDefaultFrameDurationNanoseconds / 2u;
385
386   LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds );
387 }
388
389 void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callback )
390 {
391   LOG_EVENT_TRACE;
392   LOG_EVENT( "Set PreRender Callback" );
393
394   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
395   if( mPreRenderCallback )
396   {
397     delete mPreRenderCallback;
398   }
399   mPreRenderCallback = callback;
400 }
401
402 ///////////////////////////////////////////////////////////////////////////////////////////////////
403 // EVENT THREAD
404 ///////////////////////////////////////////////////////////////////////////////////////////////////
405
406 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode )
407 {
408   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
409   mUpdateRenderRunCount = numberOfCycles;
410   mUpdateRenderThreadCanSleep = FALSE;
411   mUseElapsedTimeAfterWait = ( animationProgression == AnimationProgression::USE_ELAPSED_TIME );
412   mUploadWithoutRendering = ( updateMode == UpdateMode::SKIP_RENDER );
413   LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
414   mUpdateRenderThreadWaitCondition.Notify( lock );
415 }
416
417 void CombinedUpdateRenderController::PauseUpdateRenderThread()
418 {
419   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
420   mUpdateRenderRunCount = 0;
421 }
422
423 void CombinedUpdateRenderController::StopUpdateRenderThread()
424 {
425   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
426   mDestroyUpdateRenderThread = TRUE;
427   mUpdateRenderThreadWaitCondition.Notify( lock );
428 }
429
430 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
431 {
432   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
433   return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
434          mUpdateRenderThreadCanSleep;               // Report paused if sleeping
435 }
436
437 void CombinedUpdateRenderController::ProcessSleepRequest()
438 {
439   LOG_EVENT_TRACE;
440
441   // Decrement Update request count
442   if( mUpdateRequestCount > 0 )
443   {
444     --mUpdateRequestCount;
445   }
446
447   // Can sleep if our update-request count is 0
448   // Update/Render thread can choose to carry on updating if it determines more update/renders are required
449   if( mUpdateRequestCount == 0 )
450   {
451     LOG_EVENT( "Going to sleep" );
452
453     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
454     mUpdateRenderThreadCanSleep = TRUE;
455   }
456 }
457
458 ///////////////////////////////////////////////////////////////////////////////////////////////////
459 // UPDATE/RENDER THREAD
460 ///////////////////////////////////////////////////////////////////////////////////////////////////
461
462 void CombinedUpdateRenderController::UpdateRenderThread()
463 {
464   SetThreadName("RenderThread\0");
465
466   // Install a function for logging
467   mEnvironmentOptions.InstallLogFunction();
468
469   // Install a function for tracing
470   mEnvironmentOptions.InstallTraceFunction();
471
472   LOG_UPDATE_RENDER( "THREAD CREATED" );
473
474   // Initialize EGL & OpenGL
475   Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
476   displayConnection.Initialize();
477
478   // EGL has been initialised at this point
479   NotifyGraphicsInitialised();
480
481   RenderSurfaceInterface* currentSurface = nullptr;
482
483   GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
484   EglGraphics* eglGraphics = static_cast<EglGraphics *>(&graphics);
485
486   // This will only be created once
487   EglInterface* eglInterface = &eglGraphics->GetEglInterface();
488
489   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( *eglInterface );
490
491   // Try to use OpenGL es 3.0
492   // ChooseConfig returns false here when the device only support gles 2.0.
493   // Because eglChooseConfig with gles 3.0 setting fails when the device only support gles 2.0 and Our default setting is gles 3.0.
494   if( !eglImpl.ChooseConfig( true, COLOR_DEPTH_32 ) )
495   {
496     // Retry to use OpenGL es 2.0
497     eglGraphics->SetGlesVersion( 20 );
498     eglImpl.ChooseConfig( true, COLOR_DEPTH_32 );
499   }
500
501   // Check whether surfaceless context is supported
502   bool isSurfacelessContextSupported = eglImpl.IsSurfacelessContextSupported();
503   eglGraphics->SetIsSurfacelessContextSupported( isSurfacelessContextSupported );
504
505   if ( isSurfacelessContextSupported )
506   {
507     // Create a surfaceless OpenGL context for shared resources
508     eglImpl.CreateContext();
509     eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
510   }
511   else
512   {
513     currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
514     if( currentSurface )
515     {
516       currentSurface->InitializeGraphics();
517       currentSurface->MakeContextCurrent();
518     }
519   }
520
521   eglGraphics->GetGlesInterface().ContextCreated();
522
523   // Tell core it has a context
524   mCore.ContextCreated();
525
526   NotifyThreadInitialised();
527
528   // Update time
529   uint64_t lastFrameTime;
530   TimeService::GetNanoseconds( lastFrameTime );
531
532   LOG_UPDATE_RENDER( "THREAD INITIALISED" );
533
534   bool useElapsedTime = true;
535   bool updateRequired = true;
536   uint64_t timeToSleepUntil = 0;
537   int extraFramesDropped = 0;
538
539   const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
540   const bool renderToFboEnabled = 0u != renderToFboInterval;
541   unsigned int frameCount = 0u;
542
543   while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
544   {
545     LOG_UPDATE_RENDER_TRACE;
546
547     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
548     AddPerformanceMarker( PerformanceInterface::VSYNC );
549
550     uint64_t currentFrameStartTime = 0;
551     TimeService::GetNanoseconds( currentFrameStartTime );
552
553     const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
554
555     // Optional FPS Tracking when continuously rendering
556     if( useElapsedTime && mFpsTracker.Enabled() )
557     {
558       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
559       mFpsTracker.Track( absoluteTimeSinceLastRender );
560     }
561
562     lastFrameTime = currentFrameStartTime; // Store frame start time
563
564     //////////////////////////////
565     // REPLACE SURFACE
566     //////////////////////////////
567
568     Integration::RenderSurface* newSurface = ShouldSurfaceBeReplaced();
569     if( DALI_UNLIKELY( newSurface ) )
570     {
571       LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
572       // This is designed for replacing pixmap surfaces, but should work for window as well
573       // we need to delete the surface and renderable (pixmap / window)
574       // Then create a new pixmap/window and new surface
575       // If the new surface has a different display connection, then the context will be lost
576       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
577       newSurface->InitializeGraphics();
578       newSurface->MakeContextCurrent();
579       // TODO: ReplaceGraphicsSurface doesn't work, InitializeGraphics()
580       // already creates new surface window, the surface and the context.
581       // We probably don't need ReplaceGraphicsSurface at all.
582       // newSurface->ReplaceGraphicsSurface();
583       SurfaceReplaced();
584     }
585
586     const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
587     ++frameCount;
588
589     //////////////////////////////
590     // UPDATE
591     //////////////////////////////
592
593     const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
594     const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
595
596     uint64_t noOfFramesSinceLastUpdate = 1;
597     float frameDelta = 0.0f;
598     if( useElapsedTime )
599     {
600       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
601       noOfFramesSinceLastUpdate += extraFramesDropped;
602
603       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
604     }
605     LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
606
607     Integration::UpdateStatus updateStatus;
608
609     AddPerformanceMarker( PerformanceInterface::UPDATE_START );
610     mCore.Update( frameDelta,
611                   currentTime,
612                   nextFrameTime,
613                   updateStatus,
614                   renderToFboEnabled,
615                   isRenderingToFbo );
616     AddPerformanceMarker( PerformanceInterface::UPDATE_END );
617
618     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
619
620     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
621     if( updateStatus.NeedsNotification() )
622     {
623       mNotificationTrigger.Trigger();
624       LOG_UPDATE_RENDER( "Notification Triggered" );
625     }
626
627     // Check resize
628     bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
629     if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
630     {
631       if( updateStatus.SurfaceRectChanged() )
632       {
633         LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
634         SurfaceResized();
635       }
636     }
637
638     // Optional logging of update/render status
639     mUpdateStatusLogger.Log( keepUpdatingStatus );
640
641     //////////////////////////////
642     // RENDER
643     //////////////////////////////
644
645     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
646
647     if( mPreRenderCallback != NULL )
648     {
649       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
650       if( ! keepCallback )
651       {
652         delete mPreRenderCallback;
653         mPreRenderCallback = NULL;
654       }
655     }
656
657     if( eglImpl.IsSurfacelessContextSupported() )
658     {
659       // Make the shared surfaceless context as current before rendering
660       eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
661     }
662
663     if( mFirstFrameAfterResume )
664     {
665       // mFirstFrameAfterResume is set to true when the thread is resumed
666       // Let eglImplementation know the first frame after thread initialized or resumed.
667       eglImpl.SetFirstFrameAfterResume();
668       mFirstFrameAfterResume = FALSE;
669     }
670
671     Integration::RenderStatus renderStatus;
672
673     AddPerformanceMarker( PerformanceInterface::RENDER_START );
674     mCore.Render( renderStatus, mForceClear, mUploadWithoutRendering );
675
676     //////////////////////////////
677     // DELETE SURFACE
678     //////////////////////////////
679
680     Integration::RenderSurface* deletedSurface = ShouldSurfaceBeDeleted();
681     if( DALI_UNLIKELY( deletedSurface ) )
682     {
683       LOG_UPDATE_RENDER_TRACE_FMT( "Deleting Surface" );
684
685       mCore.SurfaceDeleted( deletedSurface );
686
687       SurfaceDeleted();
688     }
689
690     AddPerformanceMarker( PerformanceInterface::RENDER_END );
691
692     mForceClear = false;
693
694     // Trigger event thread to request Update/Render thread to sleep if update not required
695     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
696     {
697       mSleepTrigger->Trigger();
698       updateRequired = false;
699       LOG_UPDATE_RENDER( "Sleep Triggered" );
700     }
701     else
702     {
703       updateRequired = true;
704     }
705
706     //////////////////////////////
707     // FRAME TIME
708     //////////////////////////////
709
710     extraFramesDropped = 0;
711
712     if (timeToSleepUntil == 0)
713     {
714       // If this is the first frame after the thread is initialized or resumed, we
715       // use the actual time the current frame starts from to calculate the time to
716       // sleep until the next frame.
717       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
718     }
719     else
720     {
721       // Otherwise, always use the sleep-until time calculated in the last frame to
722       // calculate the time to sleep until the next frame. In this way, if there is
723       // any time gap between the current frame and the next frame, or if update or
724       // rendering in the current frame takes too much time so that the specified
725       // sleep-until time has already passed, it will try to keep the frames syncing
726       // by shortening the duration of the next frame.
727       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
728
729       // Check the current time at the end of the frame
730       uint64_t currentFrameEndTime = 0;
731       TimeService::GetNanoseconds( currentFrameEndTime );
732       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
733       {
734          // We are more than one frame behind already, so just drop the next frames
735          // until the sleep-until time is later than the current time so that we can
736          // catch up.
737          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
738          extraFramesDropped++;
739       }
740     }
741
742     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
743     if( 0u == renderToFboInterval )
744     {
745       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
746       TimeService::SleepUntil( timeToSleepUntil );
747     }
748   }
749
750   // Inform core of context destruction & shutdown EGL
751   mCore.ContextDestroyed();
752   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
753   if( currentSurface )
754   {
755     currentSurface->DestroySurface();
756     currentSurface = nullptr;
757   }
758
759   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
760
761   // Uninstall the logging function
762   mEnvironmentOptions.UnInstallLogFunction();
763 }
764
765 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
766 {
767   useElapsedTime = true;
768
769   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
770   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
771            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
772          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
773          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
774          ! mDeletedSurface && // Ensure we don't wait if we need to delete the surface
775          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
776   {
777     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
778     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
779     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
780     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
781     LOG_UPDATE_RENDER( "      mDeletedSurface:             %d", mDeletedSurface );
782     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
783
784     // Reset the time when the thread is waiting, so the sleep-until time for
785     // the first frame after resuming should be based on the actual start time
786     // of the first frame.
787     timeToSleepUntil = 0;
788
789     mUpdateRenderThreadWaitCondition.Wait( updateLock );
790
791     if( ! mUseElapsedTimeAfterWait )
792     {
793       useElapsedTime = false;
794     }
795   }
796
797   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
798   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
799   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
800   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
801   LOG_COUNTER_UPDATE_RENDER( "mDeletedSurface:             %d", mDeletedSurface );
802   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
803
804   mUseElapsedTimeAfterWait = FALSE;
805   mUpdateRenderThreadCanSleep = FALSE;
806   mPendingRequestUpdate = FALSE;
807
808   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
809   // requested number of cycles
810   if( mUpdateRenderRunCount > 0 )
811   {
812     --mUpdateRenderRunCount;
813   }
814
815   // Keep the update-render thread alive if this thread is NOT to be destroyed
816   return ! mDestroyUpdateRenderThread;
817 }
818
819 Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
820 {
821   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
822
823   Integration::RenderSurface* newSurface = mNewSurface;
824   mNewSurface = NULL;
825
826   return newSurface;
827 }
828
829 void CombinedUpdateRenderController::SurfaceReplaced()
830 {
831   // Just increment the semaphore
832   sem_post( &mEventThreadSemaphore );
833 }
834
835 Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
836 {
837   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
838
839   Integration::RenderSurface* deletedSurface = mDeletedSurface;
840   mDeletedSurface = NULL;
841
842   return deletedSurface;
843 }
844
845 void CombinedUpdateRenderController::SurfaceDeleted()
846 {
847   // Just increment the semaphore
848   sem_post( &mEventThreadSemaphore );
849 }
850
851 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
852 {
853   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
854   return mSurfaceResized;
855 }
856
857 void CombinedUpdateRenderController::SurfaceResized()
858 {
859   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
860   mSurfaceResized = FALSE;
861 }
862
863 ///////////////////////////////////////////////////////////////////////////////////////////////////
864 // ALL THREADS
865 ///////////////////////////////////////////////////////////////////////////////////////////////////
866
867 void CombinedUpdateRenderController::NotifyThreadInitialised()
868 {
869   // Just increment the semaphore
870   sem_post( &mEventThreadSemaphore );
871 }
872
873 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
874 {
875   sem_post( &mGraphicsInitializeSemaphore );
876 }
877
878 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
879 {
880   if( mPerformanceInterface )
881   {
882     mPerformanceInterface->AddMarker( type );
883   }
884 }
885
886 /////////////////////////////////////////////////////////////////////////////////////////////////
887 // POST RENDERING: EVENT THREAD
888 /////////////////////////////////////////////////////////////////////////////////////////////////
889
890 void CombinedUpdateRenderController::PostRenderComplete()
891 {
892   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
893   mPostRendering = FALSE;
894   mUpdateRenderThreadWaitCondition.Notify( lock );
895 }
896
897 ///////////////////////////////////////////////////////////////////////////////////////////////////
898 // POST RENDERING: RENDER THREAD
899 ///////////////////////////////////////////////////////////////////////////////////////////////////
900
901 void CombinedUpdateRenderController::PostRenderStarted()
902 {
903   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
904   mPostRendering = TRUE;
905 }
906
907 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
908 {
909   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
910   while( mPostRendering &&
911          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
912          ! mDeletedSurface &&            // We should NOT wait if we're deleting the surface
913          ! mSurfaceResized &&            // We should NOT wait if we're resizing the surface
914          ! mDestroyUpdateRenderThread )
915   {
916     mUpdateRenderThreadWaitCondition.Wait( lock );
917   }
918 }
919
920 } // namespace Adaptor
921
922 } // namespace Internal
923
924 } // namespace Dali