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