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