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