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