Merge "Change using flag timeToSleepUntil to mForceClear to show swapbuffer logs...
[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   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 ///////////////////////////////////////////////////////////////////////////////////////////////////
385 // EVENT THREAD
386 ///////////////////////////////////////////////////////////////////////////////////////////////////
387
388 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode )
389 {
390   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
391   mUpdateRenderRunCount = numberOfCycles;
392   mUpdateRenderThreadCanSleep = FALSE;
393   mUseElapsedTimeAfterWait = ( animationProgression == AnimationProgression::USE_ELAPSED_TIME );
394   mUploadWithoutRendering = ( updateMode == UpdateMode::SKIP_RENDER );
395   LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
396   mUpdateRenderThreadWaitCondition.Notify( lock );
397 }
398
399 void CombinedUpdateRenderController::PauseUpdateRenderThread()
400 {
401   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
402   mUpdateRenderRunCount = 0;
403 }
404
405 void CombinedUpdateRenderController::StopUpdateRenderThread()
406 {
407   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
408   mDestroyUpdateRenderThread = TRUE;
409   mUpdateRenderThreadWaitCondition.Notify( lock );
410 }
411
412 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
413 {
414   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
415   return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
416          mUpdateRenderThreadCanSleep;               // Report paused if sleeping
417 }
418
419 void CombinedUpdateRenderController::ProcessSleepRequest()
420 {
421   LOG_EVENT_TRACE;
422
423   // Decrement Update request count
424   if( mUpdateRequestCount > 0 )
425   {
426     --mUpdateRequestCount;
427   }
428
429   // Can sleep if our update-request count is 0
430   // Update/Render thread can choose to carry on updating if it determines more update/renders are required
431   if( mUpdateRequestCount == 0 )
432   {
433     LOG_EVENT( "Going to sleep" );
434
435     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
436     mUpdateRenderThreadCanSleep = TRUE;
437   }
438 }
439
440 ///////////////////////////////////////////////////////////////////////////////////////////////////
441 // UPDATE/RENDER THREAD
442 ///////////////////////////////////////////////////////////////////////////////////////////////////
443
444 void CombinedUpdateRenderController::UpdateRenderThread()
445 {
446   SetThreadName("RenderThread\0");
447
448   // Install a function for logging
449   mEnvironmentOptions.InstallLogFunction();
450
451   // Install a function for tracing
452   mEnvironmentOptions.InstallTraceFunction();
453
454   LOG_UPDATE_RENDER( "THREAD CREATED" );
455
456   // Initialize EGL & OpenGL
457   Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
458   displayConnection.Initialize();
459
460   RenderSurfaceInterface* currentSurface = nullptr;
461
462   GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
463   EglGraphics* eglGraphics = static_cast<EglGraphics *>(&graphics);
464
465   // This will only be created once
466   EglInterface* eglInterface = &eglGraphics->GetEglInterface();
467
468   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( *eglInterface );
469
470   // Try to use OpenGL es 3.0
471   // ChooseConfig returns false here when the device only support gles 2.0.
472   // Because eglChooseConfig with gles 3.0 setting fails when the device only support gles 2.0 and Our default setting is gles 3.0.
473   if( !eglImpl.ChooseConfig( true, COLOR_DEPTH_32 ) )
474   {
475     // Retry to use OpenGL es 2.0
476     eglGraphics->SetGlesVersion( 20 );
477     eglImpl.ChooseConfig( true, COLOR_DEPTH_32 );
478   }
479
480   // Check whether surfaceless context is supported
481   bool isSurfacelessContextSupported = eglImpl.IsSurfacelessContextSupported();
482   eglGraphics->SetIsSurfacelessContextSupported( isSurfacelessContextSupported );
483
484   if ( isSurfacelessContextSupported )
485   {
486     // Create a surfaceless OpenGL context for shared resources
487     eglImpl.CreateContext();
488     eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
489   }
490   else
491   {
492     currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
493     if( currentSurface )
494     {
495       currentSurface->InitializeGraphics();
496       currentSurface->MakeContextCurrent();
497     }
498   }
499
500   eglGraphics->GetGlesInterface().ContextCreated();
501
502   // Tell core it has a context
503   mCore.ContextCreated();
504
505   NotifyThreadInitialised();
506
507   // Update time
508   uint64_t lastFrameTime;
509   TimeService::GetNanoseconds( lastFrameTime );
510
511   LOG_UPDATE_RENDER( "THREAD INITIALISED" );
512
513   bool useElapsedTime = true;
514   bool updateRequired = true;
515   uint64_t timeToSleepUntil = 0;
516   int extraFramesDropped = 0;
517
518   const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
519   const bool renderToFboEnabled = 0u != renderToFboInterval;
520   unsigned int frameCount = 0u;
521
522   while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
523   {
524     LOG_UPDATE_RENDER_TRACE;
525
526     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
527     AddPerformanceMarker( PerformanceInterface::VSYNC );
528
529     uint64_t currentFrameStartTime = 0;
530     TimeService::GetNanoseconds( currentFrameStartTime );
531
532     const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
533
534     // Optional FPS Tracking when continuously rendering
535     if( useElapsedTime && mFpsTracker.Enabled() )
536     {
537       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
538       mFpsTracker.Track( absoluteTimeSinceLastRender );
539     }
540
541     lastFrameTime = currentFrameStartTime; // Store frame start time
542
543     //////////////////////////////
544     // REPLACE SURFACE
545     //////////////////////////////
546
547     Integration::RenderSurface* newSurface = ShouldSurfaceBeReplaced();
548     if( DALI_UNLIKELY( newSurface ) )
549     {
550       LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
551
552       // This is designed for replacing pixmap surfaces, but should work for window as well
553       // we need to delete the surface and renderable (pixmap / window)
554       // Then create a new pixmap/window and new surface
555       // If the new surface has a different display connection, then the context will be lost
556
557       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
558       newSurface->InitializeGraphics();
559       newSurface->ReplaceGraphicsSurface();
560       SurfaceReplaced();
561     }
562
563     const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
564     ++frameCount;
565
566     //////////////////////////////
567     // UPDATE
568     //////////////////////////////
569
570     const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
571     const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
572
573     uint64_t noOfFramesSinceLastUpdate = 1;
574     float frameDelta = 0.0f;
575     if( useElapsedTime )
576     {
577       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
578       noOfFramesSinceLastUpdate += extraFramesDropped;
579
580       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
581     }
582     LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
583
584     Integration::UpdateStatus updateStatus;
585
586     AddPerformanceMarker( PerformanceInterface::UPDATE_START );
587     mCore.Update( frameDelta,
588                   currentTime,
589                   nextFrameTime,
590                   updateStatus,
591                   renderToFboEnabled,
592                   isRenderingToFbo );
593     AddPerformanceMarker( PerformanceInterface::UPDATE_END );
594
595     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
596
597     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
598     if( updateStatus.NeedsNotification() )
599     {
600       mNotificationTrigger.Trigger();
601       LOG_UPDATE_RENDER( "Notification Triggered" );
602     }
603
604     // Check resize
605     bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
606     if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
607     {
608       if( updateStatus.SurfaceRectChanged() )
609       {
610         LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
611         SurfaceResized();
612       }
613     }
614
615     // Optional logging of update/render status
616     mUpdateStatusLogger.Log( keepUpdatingStatus );
617
618     //////////////////////////////
619     // RENDER
620     //////////////////////////////
621
622     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
623
624     if( mPreRenderCallback != NULL )
625     {
626       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
627       if( ! keepCallback )
628       {
629         delete mPreRenderCallback;
630         mPreRenderCallback = NULL;
631       }
632     }
633
634     if( eglImpl.IsSurfacelessContextSupported() )
635     {
636       // Make the shared surfaceless context as current before rendering
637       eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
638     }
639
640     if( mFirstFrameAfterResume )
641     {
642       // mFirstFrameAfterResume is set to true when the thread is resumed
643       // Let eglImplementation know the first frame after thread initialized or resumed.
644       eglImpl.SetFirstFrameAfterResume();
645       mFirstFrameAfterResume = FALSE;
646     }
647
648     Integration::RenderStatus renderStatus;
649
650     AddPerformanceMarker( PerformanceInterface::RENDER_START );
651     mCore.Render( renderStatus, mForceClear, mUploadWithoutRendering );
652
653     //////////////////////////////
654     // DELETE SURFACE
655     //////////////////////////////
656
657     Integration::RenderSurface* deletedSurface = ShouldSurfaceBeDeleted();
658     if( DALI_UNLIKELY( deletedSurface ) )
659     {
660       LOG_UPDATE_RENDER_TRACE_FMT( "Deleting Surface" );
661
662       mCore.SurfaceDeleted( deletedSurface );
663
664       SurfaceDeleted();
665     }
666
667     AddPerformanceMarker( PerformanceInterface::RENDER_END );
668
669     mForceClear = false;
670
671     // Trigger event thread to request Update/Render thread to sleep if update not required
672     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
673     {
674       mSleepTrigger->Trigger();
675       updateRequired = false;
676       LOG_UPDATE_RENDER( "Sleep Triggered" );
677     }
678     else
679     {
680       updateRequired = true;
681     }
682
683     //////////////////////////////
684     // FRAME TIME
685     //////////////////////////////
686
687     extraFramesDropped = 0;
688
689     if (timeToSleepUntil == 0)
690     {
691       // If this is the first frame after the thread is initialized or resumed, we
692       // use the actual time the current frame starts from to calculate the time to
693       // sleep until the next frame.
694       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
695     }
696     else
697     {
698       // Otherwise, always use the sleep-until time calculated in the last frame to
699       // calculate the time to sleep until the next frame. In this way, if there is
700       // any time gap between the current frame and the next frame, or if update or
701       // rendering in the current frame takes too much time so that the specified
702       // sleep-until time has already passed, it will try to keep the frames syncing
703       // by shortening the duration of the next frame.
704       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
705
706       // Check the current time at the end of the frame
707       uint64_t currentFrameEndTime = 0;
708       TimeService::GetNanoseconds( currentFrameEndTime );
709       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
710       {
711          // We are more than one frame behind already, so just drop the next frames
712          // until the sleep-until time is later than the current time so that we can
713          // catch up.
714          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
715          extraFramesDropped++;
716       }
717     }
718
719     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
720     if( 0u == renderToFboInterval )
721     {
722       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
723       TimeService::SleepUntil( timeToSleepUntil );
724     }
725   }
726
727   // Inform core of context destruction & shutdown EGL
728   mCore.ContextDestroyed();
729   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
730   if( currentSurface )
731   {
732     currentSurface->DestroySurface();
733     currentSurface = nullptr;
734   }
735
736   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
737
738   // Uninstall the logging function
739   mEnvironmentOptions.UnInstallLogFunction();
740 }
741
742 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
743 {
744   useElapsedTime = true;
745
746   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
747   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
748            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
749          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
750          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
751          ! mDeletedSurface && // Ensure we don't wait if we need to delete the surface
752          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
753   {
754     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
755     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
756     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
757     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
758     LOG_UPDATE_RENDER( "      mDeletedSurface:             %d", mDeletedSurface );
759     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
760
761     // Reset the time when the thread is waiting, so the sleep-until time for
762     // the first frame after resuming should be based on the actual start time
763     // of the first frame.
764     timeToSleepUntil = 0;
765
766     mUpdateRenderThreadWaitCondition.Wait( updateLock );
767
768     if( ! mUseElapsedTimeAfterWait )
769     {
770       useElapsedTime = false;
771     }
772   }
773
774   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
775   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
776   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
777   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
778   LOG_COUNTER_UPDATE_RENDER( "mDeletedSurface:             %d", mDeletedSurface );
779   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
780
781   mUseElapsedTimeAfterWait = FALSE;
782   mUpdateRenderThreadCanSleep = FALSE;
783   mPendingRequestUpdate = FALSE;
784
785   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
786   // requested number of cycles
787   if( mUpdateRenderRunCount > 0 )
788   {
789     --mUpdateRenderRunCount;
790   }
791
792   // Keep the update-render thread alive if this thread is NOT to be destroyed
793   return ! mDestroyUpdateRenderThread;
794 }
795
796 Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
797 {
798   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
799
800   Integration::RenderSurface* newSurface = mNewSurface;
801   mNewSurface = NULL;
802
803   return newSurface;
804 }
805
806 void CombinedUpdateRenderController::SurfaceReplaced()
807 {
808   // Just increment the semaphore
809   sem_post( &mEventThreadSemaphore );
810 }
811
812 Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
813 {
814   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
815
816   Integration::RenderSurface* deletedSurface = mDeletedSurface;
817   mDeletedSurface = NULL;
818
819   return deletedSurface;
820 }
821
822 void CombinedUpdateRenderController::SurfaceDeleted()
823 {
824   // Just increment the semaphore
825   sem_post( &mEventThreadSemaphore );
826 }
827
828 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
829 {
830   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
831   return mSurfaceResized;
832 }
833
834 void CombinedUpdateRenderController::SurfaceResized()
835 {
836   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
837   mSurfaceResized = FALSE;
838 }
839
840 ///////////////////////////////////////////////////////////////////////////////////////////////////
841 // ALL THREADS
842 ///////////////////////////////////////////////////////////////////////////////////////////////////
843
844 void CombinedUpdateRenderController::NotifyThreadInitialised()
845 {
846   // Just increment the semaphore
847   sem_post( &mEventThreadSemaphore );
848 }
849
850 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
851 {
852   if( mPerformanceInterface )
853   {
854     mPerformanceInterface->AddMarker( type );
855   }
856 }
857
858 /////////////////////////////////////////////////////////////////////////////////////////////////
859 // POST RENDERING: EVENT THREAD
860 /////////////////////////////////////////////////////////////////////////////////////////////////
861
862 void CombinedUpdateRenderController::PostRenderComplete()
863 {
864   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
865   mPostRendering = FALSE;
866   mUpdateRenderThreadWaitCondition.Notify( lock );
867 }
868
869 ///////////////////////////////////////////////////////////////////////////////////////////////////
870 // POST RENDERING: RENDER THREAD
871 ///////////////////////////////////////////////////////////////////////////////////////////////////
872
873 void CombinedUpdateRenderController::PostRenderStarted()
874 {
875   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
876   mPostRendering = TRUE;
877 }
878
879 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
880 {
881   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
882   while( mPostRendering &&
883          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
884          ! mDeletedSurface &&            // We should NOT wait if we're deleting the surface
885          ! mSurfaceResized &&            // We should NOT wait if we're resizing the surface
886          ! mDestroyUpdateRenderThread )
887   {
888     mUpdateRenderThreadWaitCondition.Wait( lock );
889   }
890 }
891
892 } // namespace Adaptor
893
894 } // namespace Internal
895
896 } // namespace Dali