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