Revert "[Tizen] Revert "Support multiple window rendering""
[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 #if DALI_GLES_VERSION >= 30
428
429   GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
430   EglGraphics* eglGraphics = static_cast<EglGraphics *>(&graphics);
431
432   // This will only be created once
433   EglInterface* eglInterface = &eglGraphics->GetEglInterface();
434
435   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( *eglInterface );
436   eglImpl.ChooseConfig( true, COLOR_DEPTH_32 ); // Always use this for shared context???
437
438   // Create a surfaceless OpenGL context for shared resources
439   eglImpl.CreateContext();
440   eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
441
442 #else // DALI_GLES_VERSION >= 30
443
444   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
445   if( currentSurface )
446   {
447     currentSurface->InitializeGraphics();
448     currentSurface->MakeContextCurrent();
449   }
450
451 #endif
452
453   // Tell core it has a context
454   mCore.ContextCreated();
455
456   NotifyThreadInitialised();
457
458   // Update time
459   uint64_t lastFrameTime;
460   TimeService::GetNanoseconds( lastFrameTime );
461
462   LOG_UPDATE_RENDER( "THREAD INITIALISED" );
463
464   bool useElapsedTime = true;
465   bool updateRequired = true;
466   uint64_t timeToSleepUntil = 0;
467   int extraFramesDropped = 0;
468
469   const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
470   const bool renderToFboEnabled = 0u != renderToFboInterval;
471   unsigned int frameCount = 0u;
472
473   while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
474   {
475     LOG_UPDATE_RENDER_TRACE;
476
477     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
478     AddPerformanceMarker( PerformanceInterface::VSYNC );
479
480     uint64_t currentFrameStartTime = 0;
481     TimeService::GetNanoseconds( currentFrameStartTime );
482
483     const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
484
485     // Optional FPS Tracking when continuously rendering
486     if( useElapsedTime && mFpsTracker.Enabled() )
487     {
488       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
489       mFpsTracker.Track( absoluteTimeSinceLastRender );
490     }
491
492     lastFrameTime = currentFrameStartTime; // Store frame start time
493
494     //////////////////////////////
495     // REPLACE SURFACE
496     //////////////////////////////
497
498     Integration::RenderSurface* newSurface = ShouldSurfaceBeReplaced();
499     if( DALI_UNLIKELY( newSurface ) )
500     {
501       LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
502
503       // This is designed for replacing pixmap surfaces, but should work for window as well
504       // we need to delete the surface and renderable (pixmap / window)
505       // Then create a new pixmap/window and new surface
506       // If the new surface has a different display connection, then the context will be lost
507
508       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
509       newSurface->InitializeGraphics();
510       newSurface->ReplaceGraphicsSurface();
511       SurfaceReplaced();
512     }
513
514     const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
515     ++frameCount;
516
517     //////////////////////////////
518     // UPDATE
519     //////////////////////////////
520
521     const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
522     const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
523
524     uint64_t noOfFramesSinceLastUpdate = 1;
525     float frameDelta = 0.0f;
526     if( useElapsedTime )
527     {
528       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
529       noOfFramesSinceLastUpdate += extraFramesDropped;
530
531       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
532     }
533     LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
534
535     Integration::UpdateStatus updateStatus;
536
537     AddPerformanceMarker( PerformanceInterface::UPDATE_START );
538     mCore.Update( frameDelta,
539                   currentTime,
540                   nextFrameTime,
541                   updateStatus,
542                   renderToFboEnabled,
543                   isRenderingToFbo );
544     AddPerformanceMarker( PerformanceInterface::UPDATE_END );
545
546     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
547
548     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
549     if( updateStatus.NeedsNotification() )
550     {
551       mNotificationTrigger.Trigger();
552       LOG_UPDATE_RENDER( "Notification Triggered" );
553     }
554
555     // Check resize
556     bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
557     if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
558     {
559       if( updateStatus.SurfaceRectChanged() )
560       {
561         LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
562         SurfaceResized();
563       }
564     }
565
566     // Optional logging of update/render status
567     mUpdateStatusLogger.Log( keepUpdatingStatus );
568
569     //////////////////////////////
570     // RENDER
571     //////////////////////////////
572
573     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
574
575     if( mPreRenderCallback != NULL )
576     {
577       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
578       if( ! keepCallback )
579       {
580         delete mPreRenderCallback;
581         mPreRenderCallback = NULL;
582       }
583     }
584
585 #if DALI_GLES_VERSION >= 30
586     // Make the shared surfaceless context as current before rendering
587     eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
588 #endif
589
590     Integration::RenderStatus renderStatus;
591
592     AddPerformanceMarker( PerformanceInterface::RENDER_START );
593     mCore.Render( renderStatus, mForceClear );
594     AddPerformanceMarker( PerformanceInterface::RENDER_END );
595
596     mForceClear = false;
597
598     // Trigger event thread to request Update/Render thread to sleep if update not required
599     if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
600     {
601       mSleepTrigger->Trigger();
602       updateRequired = false;
603       LOG_UPDATE_RENDER( "Sleep Triggered" );
604     }
605     else
606     {
607       updateRequired = true;
608     }
609
610     //////////////////////////////
611     // FRAME TIME
612     //////////////////////////////
613
614     extraFramesDropped = 0;
615
616     if (timeToSleepUntil == 0)
617     {
618       // If this is the first frame after the thread is initialized or resumed, we
619       // use the actual time the current frame starts from to calculate the time to
620       // sleep until the next frame.
621       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
622     }
623     else
624     {
625       // Otherwise, always use the sleep-until time calculated in the last frame to
626       // calculate the time to sleep until the next frame. In this way, if there is
627       // any time gap between the current frame and the next frame, or if update or
628       // rendering in the current frame takes too much time so that the specified
629       // sleep-until time has already passed, it will try to keep the frames syncing
630       // by shortening the duration of the next frame.
631       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
632
633       // Check the current time at the end of the frame
634       uint64_t currentFrameEndTime = 0;
635       TimeService::GetNanoseconds( currentFrameEndTime );
636       while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
637       {
638          // We are more than one frame behind already, so just drop the next frames
639          // until the sleep-until time is later than the current time so that we can
640          // catch up.
641          timeToSleepUntil += mDefaultFrameDurationNanoseconds;
642          extraFramesDropped++;
643       }
644     }
645
646     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
647     if( 0u == renderToFboInterval )
648     {
649       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
650       TimeService::SleepUntil( timeToSleepUntil );
651     }
652   }
653
654   // Inform core of context destruction & shutdown EGL
655   mCore.ContextDestroyed();
656   currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
657   if( currentSurface )
658   {
659     currentSurface->DestroySurface();
660     currentSurface = nullptr;
661   }
662
663   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
664
665   // Uninstall the logging function
666   mEnvironmentOptions.UnInstallLogFunction();
667 }
668
669 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
670 {
671   useElapsedTime = true;
672
673   ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
674   while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
675            ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
676          ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
677          ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
678          ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
679   {
680     LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
681     LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
682     LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
683     LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
684     LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
685
686     // Reset the time when the thread is waiting, so the sleep-until time for
687     // the first frame after resuming should be based on the actual start time
688     // of the first frame.
689     timeToSleepUntil = 0;
690
691     mUpdateRenderThreadWaitCondition.Wait( updateLock );
692
693     if( ! mUseElapsedTimeAfterWait )
694     {
695       useElapsedTime = false;
696     }
697   }
698
699   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
700   LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
701   LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
702   LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
703   LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
704
705   mUseElapsedTimeAfterWait = FALSE;
706   mUpdateRenderThreadCanSleep = FALSE;
707   mPendingRequestUpdate = FALSE;
708
709   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
710   // requested number of cycles
711   if( mUpdateRenderRunCount > 0 )
712   {
713     --mUpdateRenderRunCount;
714   }
715
716   // Keep the update-render thread alive if this thread is NOT to be destroyed
717   return ! mDestroyUpdateRenderThread;
718 }
719
720 Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
721 {
722   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
723
724   Integration::RenderSurface* newSurface = mNewSurface;
725   mNewSurface = NULL;
726
727   return newSurface;
728 }
729
730 void CombinedUpdateRenderController::SurfaceReplaced()
731 {
732   // Just increment the semaphore
733   sem_post( &mEventThreadSemaphore );
734 }
735
736 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
737 {
738   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
739   return mSurfaceResized;
740 }
741
742 void CombinedUpdateRenderController::SurfaceResized()
743 {
744   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
745   mSurfaceResized = FALSE;
746 }
747
748 ///////////////////////////////////////////////////////////////////////////////////////////////////
749 // ALL THREADS
750 ///////////////////////////////////////////////////////////////////////////////////////////////////
751
752 void CombinedUpdateRenderController::NotifyThreadInitialised()
753 {
754   // Just increment the semaphore
755   sem_post( &mEventThreadSemaphore );
756 }
757
758 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
759 {
760   if( mPerformanceInterface )
761   {
762     mPerformanceInterface->AddMarker( type );
763   }
764 }
765
766 /////////////////////////////////////////////////////////////////////////////////////////////////
767 // POST RENDERING: EVENT THREAD
768 /////////////////////////////////////////////////////////////////////////////////////////////////
769
770 void CombinedUpdateRenderController::PostRenderComplete()
771 {
772   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
773   mPostRendering = FALSE;
774   mUpdateRenderThreadWaitCondition.Notify( lock );
775 }
776
777 ///////////////////////////////////////////////////////////////////////////////////////////////////
778 // POST RENDERING: RENDER THREAD
779 ///////////////////////////////////////////////////////////////////////////////////////////////////
780
781 void CombinedUpdateRenderController::PostRenderStarted()
782 {
783   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
784   mPostRendering = TRUE;
785 }
786
787 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
788 {
789   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
790   while( mPostRendering &&
791          ! mNewSurface &&                // We should NOT wait if we're replacing the surface
792          ! mSurfaceResized &&            // We should NOT wait if we're resizing the surface
793          ! mDestroyUpdateRenderThread )
794   {
795     mUpdateRenderThreadWaitCondition.Wait( lock );
796   }
797 }
798
799 } // namespace Adaptor
800
801 } // namespace Internal
802
803 } // namespace Dali