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