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