[Tizen] Add check code with orientation in creating egl window.
[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
798   mCore.ContextDestroyed();
799   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
800   if( currentSurface )
801   {
802     currentSurface->DestroySurface();
803     currentSurface = nullptr;
804   }
805
806   // Shutdown EGL
807   eglInterface->TerminateGles();
808
809   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
810
811   // Uninstall the logging function
812   mEnvironmentOptions.UnInstallLogFunction();
813 }
814
815 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
816 {
817   useElapsedTime = true;
818
819   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
820   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
821            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
822          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
823          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
824          ! mDeletedSurface && // Ensure we don't wait if we need to delete the surface
825          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
826   {
827     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
828     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
829     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
830     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
831     LOG_UPDATE_RENDER( "      mDeletedSurface:             %d", mDeletedSurface );
832     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
833
834     // Reset the time when the thread is waiting, so the sleep-until time for
835     // the first frame after resuming should be based on the actual start time
836     // of the first frame.
837     timeToSleepUntil = 0;
838
839     mUpdateRenderThreadWaitCondition.Wait( updateLock );
840
841     if( ! mUseElapsedTimeAfterWait )
842     {
843       useElapsedTime = false;
844     }
845   }
846
847   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
848   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
849   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
850   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
851   LOG_COUNTER_UPDATE_RENDER( "mDeletedSurface:             %d", mDeletedSurface );
852   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
853
854   mUseElapsedTimeAfterWait = FALSE;
855   mUpdateRenderThreadCanSleep = FALSE;
856   mPendingRequestUpdate = FALSE;
857
858   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
859   // requested number of cycles
860   if( mUpdateRenderRunCount > 0 )
861   {
862     --mUpdateRenderRunCount;
863   }
864
865   // Keep the update-render thread alive if this thread is NOT to be destroyed
866   return ! mDestroyUpdateRenderThread;
867 }
868
869 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
870 {
871   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
872
873   Dali::RenderSurfaceInterface* newSurface = mNewSurface;
874   mNewSurface = NULL;
875
876   return newSurface;
877 }
878
879 void CombinedUpdateRenderController::SurfaceReplaced()
880 {
881   // Just increment the semaphore
882   sem_post( &mEventThreadSemaphore );
883 }
884
885 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
886 {
887   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
888
889   Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
890   mDeletedSurface = NULL;
891
892   return deletedSurface;
893 }
894
895 void CombinedUpdateRenderController::SurfaceDeleted()
896 {
897   // Just increment the semaphore
898   sem_post( &mEventThreadSemaphore );
899 }
900
901 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
902 {
903   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
904   return mSurfaceResized;
905 }
906
907 void CombinedUpdateRenderController::SurfaceResized()
908 {
909   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
910   mSurfaceResized = FALSE;
911 }
912
913 ///////////////////////////////////////////////////////////////////////////////////////////////////
914 // ALL THREADS
915 ///////////////////////////////////////////////////////////////////////////////////////////////////
916
917 void CombinedUpdateRenderController::NotifyThreadInitialised()
918 {
919   // Just increment the semaphore
920   sem_post( &mEventThreadSemaphore );
921 }
922
923 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
924 {
925   sem_post( &mGraphicsInitializeSemaphore );
926 }
927
928 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
929 {
930   if( mPerformanceInterface )
931   {
932     mPerformanceInterface->AddMarker( type );
933   }
934 }
935
936 /////////////////////////////////////////////////////////////////////////////////////////////////
937 // POST RENDERING: EVENT THREAD
938 /////////////////////////////////////////////////////////////////////////////////////////////////
939
940 void CombinedUpdateRenderController::PostRenderComplete()
941 {
942   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
943   mPostRendering = FALSE;
944   mUpdateRenderThreadWaitCondition.Notify( lock );
945 }
946
947 ///////////////////////////////////////////////////////////////////////////////////////////////////
948 // POST RENDERING: RENDER THREAD
949 ///////////////////////////////////////////////////////////////////////////////////////////////////
950
951 void CombinedUpdateRenderController::PostRenderStarted()
952 {
953   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
954   mPostRendering = TRUE;
955 }
956
957 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
958 {
959   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
960   while( mPostRendering &&
961          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
962          ! mDeletedSurface &&            // We should NOT wait if we're deleting the surface
963          ! mDestroyUpdateRenderThread )
964   {
965     mUpdateRenderThreadWaitCondition.Wait( lock );
966   }
967 }
968
969 } // namespace Adaptor
970
971 } // namespace Internal
972
973 } // namespace Dali