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