Support surfaceless context for OpenGL ES 2
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / common / combined-update-render-controller.cpp
1 /*
2  * Copyright (c) 2019 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/trigger-event-factory.h>
27 #include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
28 #include <dali/internal/system/common/environment-options.h>
29 #include <dali/internal/system/common/time-service.h>
30 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
31 #include <dali/devel-api/adaptor-framework/thread-settings.h>
32 #include <dali/internal/graphics/gles/egl-graphics.h>
33 #include <dali/internal/graphics/gles/egl-implementation.h>
34 #include <dali/internal/graphics/common/graphics-interface.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   mUpdateRenderThreadWaitCondition(),
95   mAdaptorInterfaces( adaptorInterfaces ),
96   mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
97   mCore( adaptorInterfaces.GetCore() ),
98   mEnvironmentOptions( environmentOptions ),
99   mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
100   mSleepTrigger( NULL ),
101   mPreRenderCallback( NULL ),
102   mUpdateRenderThread( NULL ),
103   mDefaultFrameDelta( 0.0f ),
104   mDefaultFrameDurationMilliseconds( 0u ),
105   mDefaultFrameDurationNanoseconds( 0u ),
106   mDefaultHalfFrameNanoseconds( 0u ),
107   mUpdateRequestCount( 0u ),
108   mRunning( FALSE ),
109   mUpdateRenderRunCount( 0 ),
110   mDestroyUpdateRenderThread( FALSE ),
111   mUpdateRenderThreadCanSleep( FALSE ),
112   mPendingRequestUpdate( FALSE ),
113   mUseElapsedTimeAfterWait( FALSE ),
114   mNewSurface( NULL ),
115   mPostRendering( FALSE ),
116   mSurfaceResized( FALSE ),
117   mForceClear( FALSE )
118 {
119   LOG_EVENT_TRACE;
120
121   // Initialise frame delta/duration variables first
122   SetRenderRefreshRate( environmentOptions.GetRenderRefreshRate() );
123
124   // Set the thread-synchronization interface on the render-surface
125   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
126   if( currentSurface )
127   {
128     currentSurface->SetThreadSynchronization( *this );
129   }
130
131   TriggerEventFactoryInterface& triggerFactory = mAdaptorInterfaces.GetTriggerEventFactoryInterface();
132   mSleepTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
133
134   sem_init( &mEventThreadSemaphore, 0, 0 ); // Initialize to 0 so that it just waits if sem_post has not been called
135 }
136
137 CombinedUpdateRenderController::~CombinedUpdateRenderController()
138 {
139   LOG_EVENT_TRACE;
140
141   Stop();
142
143   delete mPreRenderCallback;
144   delete mSleepTrigger;
145 }
146
147 void CombinedUpdateRenderController::Initialize()
148 {
149   LOG_EVENT_TRACE;
150
151   // Ensure Update/Render Thread not already created
152   DALI_ASSERT_ALWAYS( ! mUpdateRenderThread );
153
154   // Create Update/Render Thread
155   mUpdateRenderThread = new pthread_t();
156   int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this );
157   DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" );
158
159   // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called
160   // When this function returns, the application initialisation on the event thread should occur
161 }
162
163 void CombinedUpdateRenderController::Start()
164 {
165   LOG_EVENT_TRACE;
166
167   DALI_ASSERT_ALWAYS( !mRunning && mUpdateRenderThread );
168
169   // Wait until all threads created in Initialise are up and running
170   for( unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i )
171   {
172     sem_wait( &mEventThreadSemaphore );
173   }
174
175   Integration::RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
176   if( currentSurface )
177   {
178     currentSurface->StartRender();
179   }
180
181   mRunning = TRUE;
182
183   LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
184
185   RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
186
187   DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Start\n" );
188 }
189
190 void CombinedUpdateRenderController::Pause()
191 {
192   LOG_EVENT_TRACE;
193
194   mRunning = FALSE;
195
196   PauseUpdateRenderThread();
197
198   AddPerformanceMarker( PerformanceInterface::PAUSED );
199
200   DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Pause\n" );
201 }
202
203 void CombinedUpdateRenderController::Resume()
204 {
205   LOG_EVENT_TRACE;
206
207   if( !mRunning && IsUpdateRenderThreadPaused() )
208   {
209     LOG_EVENT( "Resuming" );
210
211     RunUpdateRenderThread( CONTINUOUS, true /* Animation progression required while we were paused */ );
212
213     AddPerformanceMarker( PerformanceInterface::RESUME );
214
215     mRunning = TRUE;
216     mForceClear = TRUE;
217   }
218
219   DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Resume\n" );
220 }
221
222 void CombinedUpdateRenderController::Stop()
223 {
224   LOG_EVENT_TRACE;
225
226   // Stop Rendering and the Update/Render Thread
227   Integration::RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
228   if( currentSurface )
229   {
230     currentSurface->StopRender();
231   }
232
233   StopUpdateRenderThread();
234
235   if( mUpdateRenderThread )
236   {
237     LOG_EVENT( "Destroying UpdateRenderThread" );
238
239     // wait for the thread to finish
240     pthread_join( *mUpdateRenderThread, NULL );
241
242     delete mUpdateRenderThread;
243     mUpdateRenderThread = NULL;
244   }
245
246   mRunning = FALSE;
247
248   DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Stop\n" );
249 }
250
251 void CombinedUpdateRenderController::RequestUpdate()
252 {
253   LOG_EVENT_TRACE;
254
255   // Increment the update-request count to the maximum
256   if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
257   {
258     ++mUpdateRequestCount;
259   }
260
261   if( mRunning && IsUpdateRenderThreadPaused() )
262   {
263     LOG_EVENT( "Processing" );
264
265     RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
266   }
267
268   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
269   mPendingRequestUpdate = TRUE;
270 }
271
272 void CombinedUpdateRenderController::RequestUpdateOnce()
273 {
274   // Increment the update-request count to the maximum
275   if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
276   {
277     ++mUpdateRequestCount;
278   }
279
280   if( IsUpdateRenderThreadPaused() )
281   {
282     LOG_EVENT_TRACE;
283
284     // Run Update/Render once
285     RunUpdateRenderThread( ONCE, false /* No animation progression */ );
286   }
287 }
288
289 void CombinedUpdateRenderController::ReplaceSurface( Dali::RenderSurfaceInterface* newSurface )
290 {
291   LOG_EVENT_TRACE;
292
293   // Set the ThreadSyncronizationInterface on the new surface
294   newSurface->SetThreadSynchronization( *this );
295
296   LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
297
298   // Start replacing the surface.
299   {
300     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
301     mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
302     mNewSurface = newSurface;
303     mUpdateRenderThreadWaitCondition.Notify( lock );
304   }
305
306   // Wait until the surface has been replaced
307   sem_wait( &mEventThreadSemaphore );
308
309   LOG_EVENT( "Surface replaced, event-thread continuing" );
310 }
311
312 void CombinedUpdateRenderController::ResizeSurface()
313 {
314   LOG_EVENT_TRACE;
315
316   LOG_EVENT( "Resize the surface" );
317
318   {
319     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
320     mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
321     mSurfaceResized = TRUE;
322     mUpdateRenderThreadWaitCondition.Notify( lock );
323   }
324 }
325
326 void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOfFramesPerRender )
327 {
328   // Not protected by lock, but written to rarely so not worth adding a lock when reading
329   mDefaultFrameDelta                  = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
330   mDefaultFrameDurationMilliseconds   = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
331   mDefaultFrameDurationNanoseconds    = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
332   mDefaultHalfFrameNanoseconds        = mDefaultFrameDurationNanoseconds / 2u;
333
334   LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds );
335 }
336
337 void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callback )
338 {
339   LOG_EVENT_TRACE;
340   LOG_EVENT( "Set PreRender Callback" );
341
342   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
343   if( mPreRenderCallback )
344   {
345     delete mPreRenderCallback;
346   }
347   mPreRenderCallback = callback;
348 }
349
350 ///////////////////////////////////////////////////////////////////////////////////////////////////
351 // EVENT THREAD
352 ///////////////////////////////////////////////////////////////////////////////////////////////////
353
354 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
355 {
356   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
357   mUpdateRenderRunCount = numberOfCycles;
358   mUpdateRenderThreadCanSleep = FALSE;
359   mUseElapsedTimeAfterWait = useElapsedTime;
360   LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
361   mUpdateRenderThreadWaitCondition.Notify( lock );
362 }
363
364 void CombinedUpdateRenderController::PauseUpdateRenderThread()
365 {
366   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
367   mUpdateRenderRunCount = 0;
368 }
369
370 void CombinedUpdateRenderController::StopUpdateRenderThread()
371 {
372   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
373   mDestroyUpdateRenderThread = TRUE;
374   mUpdateRenderThreadWaitCondition.Notify( lock );
375 }
376
377 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
378 {
379   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
380   return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
381          mUpdateRenderThreadCanSleep;               // Report paused if sleeping
382 }
383
384 void CombinedUpdateRenderController::ProcessSleepRequest()
385 {
386   LOG_EVENT_TRACE;
387
388   // Decrement Update request count
389   if( mUpdateRequestCount > 0 )
390   {
391     --mUpdateRequestCount;
392   }
393
394   // Can sleep if our update-request count is 0
395   // Update/Render thread can choose to carry on updating if it determines more update/renders are required
396   if( mUpdateRequestCount == 0 )
397   {
398     LOG_EVENT( "Going to sleep" );
399
400     ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
401     mUpdateRenderThreadCanSleep = TRUE;
402   }
403 }
404
405 ///////////////////////////////////////////////////////////////////////////////////////////////////
406 // UPDATE/RENDER THREAD
407 ///////////////////////////////////////////////////////////////////////////////////////////////////
408
409 void CombinedUpdateRenderController::UpdateRenderThread()
410 {
411   SetThreadName("RenderThread\0");
412
413   // Install a function for logging
414   mEnvironmentOptions.InstallLogFunction();
415
416   // Install a function for tracing
417   mEnvironmentOptions.InstallTraceFunction();
418
419   LOG_UPDATE_RENDER( "THREAD CREATED" );
420
421   // Initialize EGL & OpenGL
422   Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
423   displayConnection.Initialize();
424
425   RenderSurfaceInterface* currentSurface = nullptr;
426
427   GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
428   EglGraphics* eglGraphics = static_cast<EglGraphics *>(&graphics);
429
430   // This will only be created once
431   EglInterface* eglInterface = &eglGraphics->GetEglInterface();
432
433   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( *eglInterface );
434
435   // Try to use OpenGL es 3.0
436   // ChooseConfig returns false here when the device only support gles 2.0.
437   // Because eglChooseConfig with gles 3.0 setting fails when the device only support gles 2.0 and Our default setting is gles 3.0.
438   if( !eglImpl.ChooseConfig( true, COLOR_DEPTH_32 ) )
439   {
440     // Retry to use OpenGL es 2.0
441     eglGraphics->SetGlesVersion( 20 );
442     eglImpl.ChooseConfig( true, COLOR_DEPTH_32 );
443   }
444
445   // Check whether surfaceless context is supported
446   bool isSurfacelessContextSupported = eglImpl.IsSurfacelessContextSupported();
447   eglGraphics->SetIsSurfacelessContextSupported( isSurfacelessContextSupported );
448
449   if ( isSurfacelessContextSupported )
450   {
451     // Create a surfaceless OpenGL context for shared resources
452     eglImpl.CreateContext();
453     eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
454   }
455   else
456   {
457     currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
458     if( currentSurface )
459     {
460       currentSurface->InitializeGraphics();
461       currentSurface->MakeContextCurrent();
462     }
463   }
464
465   // Tell core it has a context
466   mCore.ContextCreated();
467
468   NotifyThreadInitialised();
469
470   // Update time
471   uint64_t lastFrameTime;
472   TimeService::GetNanoseconds( lastFrameTime );
473
474   LOG_UPDATE_RENDER( "THREAD INITIALISED" );
475
476   bool useElapsedTime = true;
477   bool updateRequired = true;
478   uint64_t timeToSleepUntil = 0;
479   int extraFramesDropped = 0;
480
481   const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
482   const bool renderToFboEnabled = 0u != renderToFboInterval;
483   unsigned int frameCount = 0u;
484
485   while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
486   {
487     LOG_UPDATE_RENDER_TRACE;
488
489     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
490     AddPerformanceMarker( PerformanceInterface::VSYNC );
491
492     uint64_t currentFrameStartTime = 0;
493     TimeService::GetNanoseconds( currentFrameStartTime );
494
495     const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
496
497     // Optional FPS Tracking when continuously rendering
498     if( useElapsedTime && mFpsTracker.Enabled() )
499     {
500       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
501       mFpsTracker.Track( absoluteTimeSinceLastRender );
502     }
503
504     lastFrameTime = currentFrameStartTime; // Store frame start time
505
506     //////////////////////////////
507     // REPLACE SURFACE
508     //////////////////////////////
509
510     Integration::RenderSurface* newSurface = ShouldSurfaceBeReplaced();
511     if( DALI_UNLIKELY( newSurface ) )
512     {
513       LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
514
515       // This is designed for replacing pixmap surfaces, but should work for window as well
516       // we need to delete the surface and renderable (pixmap / window)
517       // Then create a new pixmap/window and new surface
518       // If the new surface has a different display connection, then the context will be lost
519
520       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
521       newSurface->InitializeGraphics();
522       newSurface->ReplaceGraphicsSurface();
523       SurfaceReplaced();
524     }
525
526     const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
527     ++frameCount;
528
529     //////////////////////////////
530     // UPDATE
531     //////////////////////////////
532
533     const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
534     const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
535
536     uint64_t noOfFramesSinceLastUpdate = 1;
537     float frameDelta = 0.0f;
538     if( useElapsedTime )
539     {
540       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
541       noOfFramesSinceLastUpdate += extraFramesDropped;
542
543       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
544     }
545     LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
546
547     Integration::UpdateStatus updateStatus;
548
549     AddPerformanceMarker( PerformanceInterface::UPDATE_START );
550     mCore.Update( frameDelta,
551                   currentTime,
552                   nextFrameTime,
553                   updateStatus,
554                   renderToFboEnabled,
555                   isRenderingToFbo );
556     AddPerformanceMarker( PerformanceInterface::UPDATE_END );
557
558     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
559
560     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
561     if( updateStatus.NeedsNotification() )
562     {
563       mNotificationTrigger.Trigger();
564       LOG_UPDATE_RENDER( "Notification Triggered" );
565     }
566
567     // Check resize
568     bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
569     if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
570     {
571       if( updateStatus.SurfaceRectChanged() )
572       {
573         LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
574         SurfaceResized();
575       }
576     }
577
578     // Optional logging of update/render status
579     mUpdateStatusLogger.Log( keepUpdatingStatus );
580
581     //////////////////////////////
582     // RENDER
583     //////////////////////////////
584
585     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
586
587     if( mPreRenderCallback != NULL )
588     {
589       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
590       if( ! keepCallback )
591       {
592         delete mPreRenderCallback;
593         mPreRenderCallback = NULL;
594       }
595     }
596
597     if( eglImpl.IsSurfacelessContextSupported() )
598     {
599       // Make the shared surfaceless context as current before rendering
600       eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
601     }
602
603     Integration::RenderStatus renderStatus;
604
605     AddPerformanceMarker( PerformanceInterface::RENDER_START );
606     mCore.Render( renderStatus, mForceClear );
607     AddPerformanceMarker( PerformanceInterface::RENDER_END );
608
609     mForceClear = false;
610
611     // Trigger event thread to request Update/Render thread to sleep if update not required
612     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
613     {
614       mSleepTrigger->Trigger();
615       updateRequired = false;
616       LOG_UPDATE_RENDER( "Sleep Triggered" );
617     }
618     else
619     {
620       updateRequired = true;
621     }
622
623     //////////////////////////////
624     // FRAME TIME
625     //////////////////////////////
626
627     extraFramesDropped = 0;
628
629     if (timeToSleepUntil == 0)
630     {
631       // If this is the first frame after the thread is initialized or resumed, we
632       // use the actual time the current frame starts from to calculate the time to
633       // sleep until the next frame.
634       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
635     }
636     else
637     {
638       // Otherwise, always use the sleep-until time calculated in the last frame to
639       // calculate the time to sleep until the next frame. In this way, if there is
640       // any time gap between the current frame and the next frame, or if update or
641       // rendering in the current frame takes too much time so that the specified
642       // sleep-until time has already passed, it will try to keep the frames syncing
643       // by shortening the duration of the next frame.
644       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
645
646       // Check the current time at the end of the frame
647       uint64_t currentFrameEndTime = 0;
648       TimeService::GetNanoseconds( currentFrameEndTime );
649       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
650       {
651          // We are more than one frame behind already, so just drop the next frames
652          // until the sleep-until time is later than the current time so that we can
653          // catch up.
654          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
655          extraFramesDropped++;
656       }
657     }
658
659     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
660     if( 0u == renderToFboInterval )
661     {
662       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
663       TimeService::SleepUntil( timeToSleepUntil );
664     }
665   }
666
667   // Inform core of context destruction & shutdown EGL
668   mCore.ContextDestroyed();
669   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
670   if( currentSurface )
671   {
672     currentSurface->DestroySurface();
673     currentSurface = nullptr;
674   }
675
676   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
677
678   // Uninstall the logging function
679   mEnvironmentOptions.UnInstallLogFunction();
680 }
681
682 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
683 {
684   useElapsedTime = true;
685
686   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
687   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
688            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
689          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
690          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
691          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
692   {
693     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
694     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
695     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
696     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
697     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
698
699     // Reset the time when the thread is waiting, so the sleep-until time for
700     // the first frame after resuming should be based on the actual start time
701     // of the first frame.
702     timeToSleepUntil = 0;
703
704     mUpdateRenderThreadWaitCondition.Wait( updateLock );
705
706     if( ! mUseElapsedTimeAfterWait )
707     {
708       useElapsedTime = false;
709     }
710   }
711
712   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
713   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
714   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
715   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
716   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
717
718   mUseElapsedTimeAfterWait = FALSE;
719   mUpdateRenderThreadCanSleep = FALSE;
720   mPendingRequestUpdate = FALSE;
721
722   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
723   // requested number of cycles
724   if( mUpdateRenderRunCount > 0 )
725   {
726     --mUpdateRenderRunCount;
727   }
728
729   // Keep the update-render thread alive if this thread is NOT to be destroyed
730   return ! mDestroyUpdateRenderThread;
731 }
732
733 Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
734 {
735   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
736
737   Integration::RenderSurface* newSurface = mNewSurface;
738   mNewSurface = NULL;
739
740   return newSurface;
741 }
742
743 void CombinedUpdateRenderController::SurfaceReplaced()
744 {
745   // Just increment the semaphore
746   sem_post( &mEventThreadSemaphore );
747 }
748
749 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
750 {
751   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
752   return mSurfaceResized;
753 }
754
755 void CombinedUpdateRenderController::SurfaceResized()
756 {
757   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
758   mSurfaceResized = FALSE;
759 }
760
761 ///////////////////////////////////////////////////////////////////////////////////////////////////
762 // ALL THREADS
763 ///////////////////////////////////////////////////////////////////////////////////////////////////
764
765 void CombinedUpdateRenderController::NotifyThreadInitialised()
766 {
767   // Just increment the semaphore
768   sem_post( &mEventThreadSemaphore );
769 }
770
771 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
772 {
773   if( mPerformanceInterface )
774   {
775     mPerformanceInterface->AddMarker( type );
776   }
777 }
778
779 /////////////////////////////////////////////////////////////////////////////////////////////////
780 // POST RENDERING: EVENT THREAD
781 /////////////////////////////////////////////////////////////////////////////////////////////////
782
783 void CombinedUpdateRenderController::PostRenderComplete()
784 {
785   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
786   mPostRendering = FALSE;
787   mUpdateRenderThreadWaitCondition.Notify( lock );
788 }
789
790 ///////////////////////////////////////////////////////////////////////////////////////////////////
791 // POST RENDERING: RENDER THREAD
792 ///////////////////////////////////////////////////////////////////////////////////////////////////
793
794 void CombinedUpdateRenderController::PostRenderStarted()
795 {
796   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
797   mPostRendering = TRUE;
798 }
799
800 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
801 {
802   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
803   while( mPostRendering &&
804          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
805          ! mSurfaceResized &&            // We should NOT wait if we're resizing the surface
806          ! mDestroyUpdateRenderThread )
807   {
808     mUpdateRenderThreadWaitCondition.Wait( lock );
809   }
810 }
811
812 } // namespace Adaptor
813
814 } // namespace Internal
815
816 } // namespace Dali