[Tizen] Use OpenGL es 2.0 if eglCreateContext is fail, Prevent glFinish without makeC...
[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   else
449   {
450     if( !eglImpl.CreateContext() )
451     {
452       // Retry to use OpenGL es 2.0
453       eglGraphics->SetGlesVersion( 20 );
454       eglImpl.ChooseConfig( true, COLOR_DEPTH_32 );
455     }
456   }
457
458   // Check whether surfaceless context is supported
459   bool isSurfacelessContextSupported = eglImpl.IsSurfacelessContextSupported();
460   eglGraphics->SetIsSurfacelessContextSupported( isSurfacelessContextSupported );
461
462   if ( isSurfacelessContextSupported )
463   {
464     // Create a surfaceless OpenGL context for shared resources
465     if( eglImpl.GetContext() == 0 )
466     {
467       eglImpl.CreateContext();
468     }
469     eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
470   }
471   else
472   {
473     currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
474     if( currentSurface )
475     {
476       currentSurface->InitializeGraphics();
477       currentSurface->MakeContextCurrent();
478     }
479   }
480
481   // Tell core it has a context
482   mCore.ContextCreated();
483
484   NotifyThreadInitialised();
485
486   // Update time
487   uint64_t lastFrameTime;
488   TimeService::GetNanoseconds( lastFrameTime );
489
490   LOG_UPDATE_RENDER( "THREAD INITIALISED" );
491
492   bool useElapsedTime = true;
493   bool updateRequired = true;
494   uint64_t timeToSleepUntil = 0;
495   int extraFramesDropped = 0;
496
497   const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
498   const bool renderToFboEnabled = 0u != renderToFboInterval;
499   unsigned int frameCount = 0u;
500
501   while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
502   {
503     LOG_UPDATE_RENDER_TRACE;
504
505     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
506     AddPerformanceMarker( PerformanceInterface::VSYNC );
507
508     uint64_t currentFrameStartTime = 0;
509     TimeService::GetNanoseconds( currentFrameStartTime );
510
511     const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
512
513     // Optional FPS Tracking when continuously rendering
514     if( useElapsedTime && mFpsTracker.Enabled() )
515     {
516       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
517       mFpsTracker.Track( absoluteTimeSinceLastRender );
518     }
519
520     lastFrameTime = currentFrameStartTime; // Store frame start time
521
522     //////////////////////////////
523     // REPLACE SURFACE
524     //////////////////////////////
525
526     Integration::RenderSurface* newSurface = ShouldSurfaceBeReplaced();
527     if( DALI_UNLIKELY( newSurface ) )
528     {
529       LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
530
531       // This is designed for replacing pixmap surfaces, but should work for window as well
532       // we need to delete the surface and renderable (pixmap / window)
533       // Then create a new pixmap/window and new surface
534       // If the new surface has a different display connection, then the context will be lost
535
536       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
537       newSurface->InitializeGraphics();
538       newSurface->ReplaceGraphicsSurface();
539       SurfaceReplaced();
540     }
541
542     const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
543     ++frameCount;
544
545     //////////////////////////////
546     // UPDATE
547     //////////////////////////////
548
549     const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
550     const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
551
552     uint64_t noOfFramesSinceLastUpdate = 1;
553     float frameDelta = 0.0f;
554     if( useElapsedTime )
555     {
556       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
557       noOfFramesSinceLastUpdate += extraFramesDropped;
558
559       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
560     }
561     LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
562
563     Integration::UpdateStatus updateStatus;
564
565     AddPerformanceMarker( PerformanceInterface::UPDATE_START );
566     mCore.Update( frameDelta,
567                   currentTime,
568                   nextFrameTime,
569                   updateStatus,
570                   renderToFboEnabled,
571                   isRenderingToFbo );
572     AddPerformanceMarker( PerformanceInterface::UPDATE_END );
573
574     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
575
576     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
577     if( updateStatus.NeedsNotification() )
578     {
579       mNotificationTrigger.Trigger();
580       LOG_UPDATE_RENDER( "Notification Triggered" );
581     }
582
583     // Check resize
584     bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
585     if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
586     {
587       if( updateStatus.SurfaceRectChanged() )
588       {
589         LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
590         SurfaceResized();
591       }
592     }
593
594     // Optional logging of update/render status
595     mUpdateStatusLogger.Log( keepUpdatingStatus );
596
597     //////////////////////////////
598     // RENDER
599     //////////////////////////////
600
601     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
602
603     if( mPreRenderCallback != NULL )
604     {
605       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
606       if( ! keepCallback )
607       {
608         delete mPreRenderCallback;
609         mPreRenderCallback = NULL;
610       }
611     }
612
613     if( eglImpl.IsSurfacelessContextSupported() )
614     {
615       // Make the shared surfaceless context as current before rendering
616       eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
617     }
618
619     Integration::RenderStatus renderStatus;
620
621     AddPerformanceMarker( PerformanceInterface::RENDER_START );
622     mCore.Render( renderStatus, mForceClear );
623     AddPerformanceMarker( PerformanceInterface::RENDER_END );
624
625     mForceClear = false;
626
627     // Trigger event thread to request Update/Render thread to sleep if update not required
628     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
629     {
630       mSleepTrigger->Trigger();
631       updateRequired = false;
632       LOG_UPDATE_RENDER( "Sleep Triggered" );
633     }
634     else
635     {
636       updateRequired = true;
637     }
638
639     //////////////////////////////
640     // FRAME TIME
641     //////////////////////////////
642
643     extraFramesDropped = 0;
644
645     if (timeToSleepUntil == 0)
646     {
647       // If this is the first frame after the thread is initialized or resumed, we
648       // use the actual time the current frame starts from to calculate the time to
649       // sleep until the next frame.
650       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
651     }
652     else
653     {
654       // Otherwise, always use the sleep-until time calculated in the last frame to
655       // calculate the time to sleep until the next frame. In this way, if there is
656       // any time gap between the current frame and the next frame, or if update or
657       // rendering in the current frame takes too much time so that the specified
658       // sleep-until time has already passed, it will try to keep the frames syncing
659       // by shortening the duration of the next frame.
660       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
661
662       // Check the current time at the end of the frame
663       uint64_t currentFrameEndTime = 0;
664       TimeService::GetNanoseconds( currentFrameEndTime );
665       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
666       {
667          // We are more than one frame behind already, so just drop the next frames
668          // until the sleep-until time is later than the current time so that we can
669          // catch up.
670          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
671          extraFramesDropped++;
672       }
673     }
674
675     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
676     if( 0u == renderToFboInterval )
677     {
678       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
679       TimeService::SleepUntil( timeToSleepUntil );
680     }
681   }
682
683   // Inform core of context destruction & shutdown EGL
684   mCore.ContextDestroyed();
685   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
686   if( currentSurface )
687   {
688     currentSurface->DestroySurface();
689     currentSurface = nullptr;
690   }
691
692   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
693
694   // Uninstall the logging function
695   mEnvironmentOptions.UnInstallLogFunction();
696 }
697
698 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
699 {
700   useElapsedTime = true;
701
702   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
703   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
704            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
705          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
706          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
707          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
708   {
709     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
710     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
711     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
712     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
713     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
714
715     // Reset the time when the thread is waiting, so the sleep-until time for
716     // the first frame after resuming should be based on the actual start time
717     // of the first frame.
718     timeToSleepUntil = 0;
719
720     mUpdateRenderThreadWaitCondition.Wait( updateLock );
721
722     if( ! mUseElapsedTimeAfterWait )
723     {
724       useElapsedTime = false;
725     }
726   }
727
728   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
729   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
730   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
731   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
732   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
733
734   mUseElapsedTimeAfterWait = FALSE;
735   mUpdateRenderThreadCanSleep = FALSE;
736   mPendingRequestUpdate = FALSE;
737
738   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
739   // requested number of cycles
740   if( mUpdateRenderRunCount > 0 )
741   {
742     --mUpdateRenderRunCount;
743   }
744
745   // Keep the update-render thread alive if this thread is NOT to be destroyed
746   return ! mDestroyUpdateRenderThread;
747 }
748
749 Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
750 {
751   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
752
753   Integration::RenderSurface* newSurface = mNewSurface;
754   mNewSurface = NULL;
755
756   return newSurface;
757 }
758
759 void CombinedUpdateRenderController::SurfaceReplaced()
760 {
761   // Just increment the semaphore
762   sem_post( &mEventThreadSemaphore );
763 }
764
765 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
766 {
767   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
768   return mSurfaceResized;
769 }
770
771 void CombinedUpdateRenderController::SurfaceResized()
772 {
773   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
774   mSurfaceResized = FALSE;
775 }
776
777 ///////////////////////////////////////////////////////////////////////////////////////////////////
778 // ALL THREADS
779 ///////////////////////////////////////////////////////////////////////////////////////////////////
780
781 void CombinedUpdateRenderController::NotifyThreadInitialised()
782 {
783   // Just increment the semaphore
784   sem_post( &mEventThreadSemaphore );
785 }
786
787 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
788 {
789   if( mPerformanceInterface )
790   {
791     mPerformanceInterface->AddMarker( type );
792   }
793 }
794
795 /////////////////////////////////////////////////////////////////////////////////////////////////
796 // POST RENDERING: EVENT THREAD
797 /////////////////////////////////////////////////////////////////////////////////////////////////
798
799 void CombinedUpdateRenderController::PostRenderComplete()
800 {
801   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
802   mPostRendering = FALSE;
803   mUpdateRenderThreadWaitCondition.Notify( lock );
804 }
805
806 ///////////////////////////////////////////////////////////////////////////////////////////////////
807 // POST RENDERING: RENDER THREAD
808 ///////////////////////////////////////////////////////////////////////////////////////////////////
809
810 void CombinedUpdateRenderController::PostRenderStarted()
811 {
812   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
813   mPostRendering = TRUE;
814 }
815
816 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
817 {
818   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
819   while( mPostRendering &&
820          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
821          ! mSurfaceResized &&            // We should NOT wait if we're resizing the surface
822          ! mDestroyUpdateRenderThread )
823   {
824     mUpdateRenderThreadWaitCondition.Wait( lock );
825   }
826 }
827
828 } // namespace Adaptor
829
830 } // namespace Internal
831
832 } // namespace Dali