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