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