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