[dali_1.9.29] Merge branch 'devel/master'
[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           // Collect damage rects
752           mCore.PreRender( scene, mDamagedRects );
753
754           // Render off-screen frame buffers first if any
755           mCore.RenderScene( windowRenderStatus, scene, true );
756
757           Rect<int> clippingRect; // Empty for fbo rendering
758
759           // Switch to the EGL context of the surface, merge damaged areas for previous frames
760           windowSurface->PreRender( surfaceResized, mDamagedRects, clippingRect ); // Switch GL context
761
762           if (clippingRect.IsEmpty())
763           {
764             mDamagedRects.clear();
765           }
766
767           // Render the surface
768           mCore.RenderScene( windowRenderStatus, scene, false, clippingRect );
769
770           if( windowRenderStatus.NeedsPostRender() )
771           {
772             windowSurface->PostRender( false, false, surfaceResized, mDamagedRects ); // Swap Buffer with damage
773           }
774         }
775       }
776     }
777
778     mCore.PostRender( mUploadWithoutRendering );
779
780     //////////////////////////////
781     // DELETE SURFACE
782     //////////////////////////////
783
784     Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
785     if( DALI_UNLIKELY( deletedSurface ) )
786     {
787       LOG_UPDATE_RENDER_TRACE_FMT( "Deleting Surface" );
788
789       deletedSurface->DestroySurface();
790
791       SurfaceDeleted();
792     }
793
794     AddPerformanceMarker( PerformanceInterface::RENDER_END );
795
796     mForceClear = false;
797
798     // Trigger event thread to request Update/Render thread to sleep if update not required
799     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
800     {
801       mSleepTrigger->Trigger();
802       updateRequired = false;
803       LOG_UPDATE_RENDER( "Sleep Triggered" );
804     }
805     else
806     {
807       updateRequired = true;
808     }
809
810     //////////////////////////////
811     // FRAME TIME
812     //////////////////////////////
813
814     extraFramesDropped = 0;
815
816     if (timeToSleepUntil == 0)
817     {
818       // If this is the first frame after the thread is initialized or resumed, we
819       // use the actual time the current frame starts from to calculate the time to
820       // sleep until the next frame.
821       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
822     }
823     else
824     {
825       // Otherwise, always use the sleep-until time calculated in the last frame to
826       // calculate the time to sleep until the next frame. In this way, if there is
827       // any time gap between the current frame and the next frame, or if update or
828       // rendering in the current frame takes too much time so that the specified
829       // sleep-until time has already passed, it will try to keep the frames syncing
830       // by shortening the duration of the next frame.
831       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
832
833       // Check the current time at the end of the frame
834       uint64_t currentFrameEndTime = 0;
835       TimeService::GetNanoseconds( currentFrameEndTime );
836       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
837       {
838          // We are more than one frame behind already, so just drop the next frames
839          // until the sleep-until time is later than the current time so that we can
840          // catch up.
841          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
842          extraFramesDropped++;
843       }
844     }
845
846     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
847     if( 0u == renderToFboInterval )
848     {
849       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
850       TimeService::SleepUntil( timeToSleepUntil );
851     }
852   }
853
854   // Inform core of context destruction
855   mCore.ContextDestroyed();
856
857   WindowContainer windows;
858   mAdaptorInterfaces.GetWindowContainerInterface( windows );
859
860   // Destroy surfaces
861   for( auto&& window : windows )
862   {
863     Dali::RenderSurfaceInterface* surface = window->GetSurface();
864     surface->DestroySurface();
865   }
866
867   // Shutdown EGL
868   eglInterface->TerminateGles();
869
870   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
871
872   // Uninstall the logging function
873   mEnvironmentOptions.UnInstallLogFunction();
874 }
875
876 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
877 {
878   useElapsedTime = true;
879
880   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
881   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
882            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
883          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
884          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
885          ! mDeletedSurface && // Ensure we don't wait if we need to delete the surface
886          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
887   {
888     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
889     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
890     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
891     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
892     LOG_UPDATE_RENDER( "      mDeletedSurface:             %d", mDeletedSurface );
893     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
894
895     // Reset the time when the thread is waiting, so the sleep-until time for
896     // the first frame after resuming should be based on the actual start time
897     // of the first frame.
898     timeToSleepUntil = 0;
899
900     mUpdateRenderThreadWaitCondition.Wait( updateLock );
901
902     if( ! mUseElapsedTimeAfterWait )
903     {
904       useElapsedTime = false;
905     }
906   }
907
908   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
909   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
910   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
911   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
912   LOG_COUNTER_UPDATE_RENDER( "mDeletedSurface:             %d", mDeletedSurface );
913   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
914
915   mUseElapsedTimeAfterWait = FALSE;
916   mUpdateRenderThreadCanSleep = FALSE;
917   mPendingRequestUpdate = FALSE;
918
919   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
920   // requested number of cycles
921   if( mUpdateRenderRunCount > 0 )
922   {
923     --mUpdateRenderRunCount;
924   }
925
926   // Keep the update-render thread alive if this thread is NOT to be destroyed
927   return ! mDestroyUpdateRenderThread;
928 }
929
930 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
931 {
932   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
933
934   Dali::RenderSurfaceInterface* newSurface = mNewSurface;
935   mNewSurface = NULL;
936
937   return newSurface;
938 }
939
940 void CombinedUpdateRenderController::SurfaceReplaced()
941 {
942   // Just increment the semaphore
943   sem_post( &mEventThreadSemaphore );
944 }
945
946 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
947 {
948   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
949
950   Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
951   mDeletedSurface = NULL;
952
953   return deletedSurface;
954 }
955
956 void CombinedUpdateRenderController::SurfaceDeleted()
957 {
958   // Just increment the semaphore
959   sem_post( &mEventThreadSemaphore );
960 }
961
962 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
963 {
964   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
965   return mSurfaceResized;
966 }
967
968 void CombinedUpdateRenderController::SurfaceResized()
969 {
970   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
971   mSurfaceResized = FALSE;
972 }
973
974 ///////////////////////////////////////////////////////////////////////////////////////////////////
975 // ALL THREADS
976 ///////////////////////////////////////////////////////////////////////////////////////////////////
977
978 void CombinedUpdateRenderController::NotifyThreadInitialised()
979 {
980   // Just increment the semaphore
981   sem_post( &mEventThreadSemaphore );
982 }
983
984 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
985 {
986   sem_post( &mGraphicsInitializeSemaphore );
987 }
988
989 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
990 {
991   if( mPerformanceInterface )
992   {
993     mPerformanceInterface->AddMarker( type );
994   }
995 }
996
997 /////////////////////////////////////////////////////////////////////////////////////////////////
998 // POST RENDERING: EVENT THREAD
999 /////////////////////////////////////////////////////////////////////////////////////////////////
1000
1001 void CombinedUpdateRenderController::PostRenderComplete()
1002 {
1003   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
1004   mPostRendering = FALSE;
1005   mUpdateRenderThreadWaitCondition.Notify( lock );
1006 }
1007
1008 ///////////////////////////////////////////////////////////////////////////////////////////////////
1009 // POST RENDERING: RENDER THREAD
1010 ///////////////////////////////////////////////////////////////////////////////////////////////////
1011
1012 void CombinedUpdateRenderController::PostRenderStarted()
1013 {
1014   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
1015   mPostRendering = TRUE;
1016 }
1017
1018 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
1019 {
1020   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
1021   while( mPostRendering &&
1022          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
1023          ! mDeletedSurface &&            // We should NOT wait if we're deleting the surface
1024          ! mDestroyUpdateRenderThread )
1025   {
1026     mUpdateRenderThreadWaitCondition.Wait( lock );
1027   }
1028 }
1029
1030 } // namespace Adaptor
1031
1032 } // namespace Internal
1033
1034 } // namespace Dali