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