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