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