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