94693d2056cb1d6c58469dbec3286d648b358333
[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     Integration::RenderStatus renderStatus;
637
638     AddPerformanceMarker( PerformanceInterface::RENDER_START );
639     mCore.Render( renderStatus, mForceClear );
640
641     //////////////////////////////
642     // DELETE SURFACE
643     //////////////////////////////
644
645     Integration::RenderSurface* deletedSurface = ShouldSurfaceBeDeleted();
646     if( DALI_UNLIKELY( deletedSurface ) )
647     {
648       LOG_UPDATE_RENDER_TRACE_FMT( "Deleting Surface" );
649
650       mCore.SurfaceDeleted( deletedSurface );
651
652       SurfaceDeleted();
653     }
654
655     AddPerformanceMarker( PerformanceInterface::RENDER_END );
656
657     mForceClear = false;
658
659     // Trigger event thread to request Update/Render thread to sleep if update not required
660     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
661     {
662       mSleepTrigger->Trigger();
663       updateRequired = false;
664       LOG_UPDATE_RENDER( "Sleep Triggered" );
665     }
666     else
667     {
668       updateRequired = true;
669     }
670
671     //////////////////////////////
672     // FRAME TIME
673     //////////////////////////////
674
675     extraFramesDropped = 0;
676
677     if (timeToSleepUntil == 0)
678     {
679       // If this is the first frame after the thread is initialized or resumed, we
680       // use the actual time the current frame starts from to calculate the time to
681       // sleep until the next frame.
682       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
683     }
684     else
685     {
686       // Otherwise, always use the sleep-until time calculated in the last frame to
687       // calculate the time to sleep until the next frame. In this way, if there is
688       // any time gap between the current frame and the next frame, or if update or
689       // rendering in the current frame takes too much time so that the specified
690       // sleep-until time has already passed, it will try to keep the frames syncing
691       // by shortening the duration of the next frame.
692       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
693
694       // Check the current time at the end of the frame
695       uint64_t currentFrameEndTime = 0;
696       TimeService::GetNanoseconds( currentFrameEndTime );
697       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
698       {
699          // We are more than one frame behind already, so just drop the next frames
700          // until the sleep-until time is later than the current time so that we can
701          // catch up.
702          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
703          extraFramesDropped++;
704       }
705     }
706
707     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
708     if( 0u == renderToFboInterval )
709     {
710       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
711       TimeService::SleepUntil( timeToSleepUntil );
712     }
713   }
714
715   // Inform core of context destruction & shutdown EGL
716   mCore.ContextDestroyed();
717   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
718   if( currentSurface )
719   {
720     currentSurface->DestroySurface();
721     currentSurface = nullptr;
722   }
723
724   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
725
726   // Uninstall the logging function
727   mEnvironmentOptions.UnInstallLogFunction();
728 }
729
730 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
731 {
732   useElapsedTime = true;
733
734   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
735   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
736            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
737          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
738          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
739          ! mDeletedSurface && // Ensure we don't wait if we need to delete the surface
740          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
741   {
742     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
743     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
744     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
745     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
746     LOG_UPDATE_RENDER( "      mDeletedSurface:             %d", mDeletedSurface );
747     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
748
749     // Reset the time when the thread is waiting, so the sleep-until time for
750     // the first frame after resuming should be based on the actual start time
751     // of the first frame.
752     timeToSleepUntil = 0;
753
754     mUpdateRenderThreadWaitCondition.Wait( updateLock );
755
756     if( ! mUseElapsedTimeAfterWait )
757     {
758       useElapsedTime = false;
759     }
760   }
761
762   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
763   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
764   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
765   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
766   LOG_COUNTER_UPDATE_RENDER( "mDeletedSurface:             %d", mDeletedSurface );
767   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
768
769   mUseElapsedTimeAfterWait = FALSE;
770   mUpdateRenderThreadCanSleep = FALSE;
771   mPendingRequestUpdate = FALSE;
772
773   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
774   // requested number of cycles
775   if( mUpdateRenderRunCount > 0 )
776   {
777     --mUpdateRenderRunCount;
778   }
779
780   // Keep the update-render thread alive if this thread is NOT to be destroyed
781   return ! mDestroyUpdateRenderThread;
782 }
783
784 Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
785 {
786   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
787
788   Integration::RenderSurface* newSurface = mNewSurface;
789   mNewSurface = NULL;
790
791   return newSurface;
792 }
793
794 void CombinedUpdateRenderController::SurfaceReplaced()
795 {
796   // Just increment the semaphore
797   sem_post( &mEventThreadSemaphore );
798 }
799
800 Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
801 {
802   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
803
804   Integration::RenderSurface* deletedSurface = mDeletedSurface;
805   mDeletedSurface = NULL;
806
807   return deletedSurface;
808 }
809
810 void CombinedUpdateRenderController::SurfaceDeleted()
811 {
812   // Just increment the semaphore
813   sem_post( &mEventThreadSemaphore );
814 }
815
816 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
817 {
818   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
819   return mSurfaceResized;
820 }
821
822 void CombinedUpdateRenderController::SurfaceResized()
823 {
824   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
825   mSurfaceResized = FALSE;
826 }
827
828 ///////////////////////////////////////////////////////////////////////////////////////////////////
829 // ALL THREADS
830 ///////////////////////////////////////////////////////////////////////////////////////////////////
831
832 void CombinedUpdateRenderController::NotifyThreadInitialised()
833 {
834   // Just increment the semaphore
835   sem_post( &mEventThreadSemaphore );
836 }
837
838 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
839 {
840   if( mPerformanceInterface )
841   {
842     mPerformanceInterface->AddMarker( type );
843   }
844 }
845
846 /////////////////////////////////////////////////////////////////////////////////////////////////
847 // POST RENDERING: EVENT THREAD
848 /////////////////////////////////////////////////////////////////////////////////////////////////
849
850 void CombinedUpdateRenderController::PostRenderComplete()
851 {
852   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
853   mPostRendering = FALSE;
854   mUpdateRenderThreadWaitCondition.Notify( lock );
855 }
856
857 ///////////////////////////////////////////////////////////////////////////////////////////////////
858 // POST RENDERING: RENDER THREAD
859 ///////////////////////////////////////////////////////////////////////////////////////////////////
860
861 void CombinedUpdateRenderController::PostRenderStarted()
862 {
863   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
864   mPostRendering = TRUE;
865 }
866
867 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
868 {
869   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
870   while( mPostRendering &&
871          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
872          ! mDeletedSurface &&            // We should NOT wait if we're deleting the surface
873          ! mSurfaceResized &&            // We should NOT wait if we're resizing the surface
874          ! mDestroyUpdateRenderThread )
875   {
876     mUpdateRenderThreadWaitCondition.Wait( lock );
877   }
878 }
879
880 } // namespace Adaptor
881
882 } // namespace Internal
883
884 } // namespace Dali