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