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