70a278d28956516e7ebb53b3b2e1b30700a4f068
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / common / combined-update-render-controller.cpp
1 /*
2  * Copyright (c) 2023 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 <dali/integration-api/platform-abstraction.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include "dali/public-api/common/dali-common.h"
26
27 // INTERNAL INCLUDES
28 #include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
29 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
30 #include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
31 #include <dali/internal/graphics/common/graphics-interface.h>
32 #include <dali/internal/graphics/gles/egl-graphics.h>
33 #include <dali/internal/system/common/environment-options.h>
34 #include <dali/internal/system/common/time-service.h>
35 #include <dali/internal/thread/common/thread-settings-impl.h>
36 #include <dali/internal/window-system/common/window-impl.h>
37
38 namespace Dali
39 {
40 namespace Internal
41 {
42 namespace Adaptor
43 {
44 namespace
45 {
46 const unsigned int CREATED_THREAD_COUNT = 1u;
47
48 const int CONTINUOUS = -1;
49 const int ONCE       = 1;
50
51 const unsigned int TRUE  = 1u;
52 const unsigned int FALSE = 0u;
53
54 const unsigned int MILLISECONDS_PER_SECOND(1e+3);
55 const float        NANOSECONDS_TO_SECOND(1e-9f);
56 const unsigned int NANOSECONDS_PER_SECOND(1e+9);
57 const unsigned int NANOSECONDS_PER_MILLISECOND(1e+6);
58
59 // The following values will get calculated at compile time
60 const float    DEFAULT_FRAME_DURATION_IN_SECONDS(1.0f / 60.0f);
61 const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* MILLISECONDS_PER_SECOND);
62 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* NANOSECONDS_PER_SECOND);
63
64 /**
65  * 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
66  * there is a danger that, on the event-thread we could have:
67  *  1) An update-request where we do nothing as Update/Render thread still running.
68  *  2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
69  *
70  * 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:
71  *  1) MAIN THREAD:           Update Request: COUNTER = 1
72  *  2) UPDATE/RENDER THREAD:  Do Update/Render, then no Updates required -> Sleep Trigger
73  *  3) MAIN THREAD:           Update Request: COUNTER = 2
74  *  4) MAIN THREAD:           Sleep Request:  COUNTER = 1 -> We do not sleep just yet
75  *
76  * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
77  *  1) MAIN THREAD:           Update Request: COUNTER = 1
78  *  2) UPDATE/RENDER THREAD:  Do Update/Render, then no Updates required -> Sleep Trigger
79  *  3) MAIN THREAD:           Sleep Request:  COUNTER = 0 -> Go to sleep
80  */
81 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
82 } // unnamed namespace
83
84 ///////////////////////////////////////////////////////////////////////////////////////////////////
85 // EVENT THREAD
86 ///////////////////////////////////////////////////////////////////////////////////////////////////
87
88 CombinedUpdateRenderController::CombinedUpdateRenderController(AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions, ThreadMode threadMode)
89 : mFpsTracker(environmentOptions),
90   mUpdateStatusLogger(environmentOptions),
91   mEventThreadSemaphore(0),
92   mSurfaceSemaphore(0),
93   mUpdateRenderThreadWaitCondition(),
94   mPostRenderWaitCondition(),
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   mThreadId(0),
110   mThreadMode(threadMode),
111   mUpdateRenderRunCount(0),
112   mDestroyUpdateRenderThread(FALSE),
113   mUpdateRenderThreadCanSleep(FALSE),
114   mPendingRequestUpdate(FALSE),
115   mUseElapsedTimeAfterWait(FALSE),
116   mNewSurface(NULL),
117   mDeletedSurface(nullptr),
118   mPostRendering(FALSE),
119   mSurfaceResized(0),
120   mForceClear(FALSE),
121   mUploadWithoutRendering(FALSE),
122   mFirstFrameAfterResume(FALSE)
123 {
124   LOG_EVENT_TRACE;
125
126   // Initialise frame delta/duration variables first
127   SetRenderRefreshRate(environmentOptions.GetRenderRefreshRate());
128
129   // Set the thread-synchronization interface on the render-surface
130   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
131   if(currentSurface)
132   {
133     currentSurface->SetThreadSynchronization(*this);
134   }
135
136   mSleepTrigger = TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &CombinedUpdateRenderController::ProcessSleepRequest), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
137 }
138
139 CombinedUpdateRenderController::~CombinedUpdateRenderController()
140 {
141   LOG_EVENT_TRACE;
142
143   Stop();
144
145   delete mPreRenderCallback;
146   delete mSleepTrigger;
147 }
148
149 void CombinedUpdateRenderController::Initialize()
150 {
151   LOG_EVENT_TRACE;
152
153   // Ensure Update/Render Thread not already created
154   DALI_ASSERT_ALWAYS(!mUpdateRenderThread);
155
156   // Create Update/Render Thread
157   ConditionalWait::ScopedLock lock(mGraphicsInitializeWait);
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     mEventThreadSemaphore.Acquire();
176   }
177
178   mRunning = TRUE;
179
180   LOG_EVENT("Startup Complete, starting Update/Render Thread");
181
182   RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
183
184   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
185   if(currentSurface)
186   {
187     currentSurface->StartRender();
188   }
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   Dali::RenderSurfaceInterface* 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() || updateMode == UpdateMode::FORCE_RENDER)
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       mNewSurface = newSurface;
312       mUpdateRenderThreadWaitCondition.Notify(lock);
313     }
314
315     // Wait until the surface has been replaced
316     mSurfaceSemaphore.Acquire();
317
318     LOG_EVENT("Surface replaced, event-thread continuing");
319   }
320 }
321
322 void CombinedUpdateRenderController::DeleteSurface(Dali::RenderSurfaceInterface* surface)
323 {
324   LOG_EVENT_TRACE;
325
326   if(mUpdateRenderThread)
327   {
328     LOG_EVENT("Starting to delete the surface, event-thread blocked");
329
330     // Start replacing the surface.
331     {
332       ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
333       mDeletedSurface = surface;
334       mUpdateRenderThreadWaitCondition.Notify(lock);
335     }
336
337     // Wait until the surface has been deleted
338     mSurfaceSemaphore.Acquire();
339
340     LOG_EVENT("Surface deleted, event-thread continuing");
341   }
342 }
343
344 void CombinedUpdateRenderController::WaitForGraphicsInitialization()
345 {
346   ConditionalWait::ScopedLock lk(mGraphicsInitializeWait);
347   LOG_EVENT_TRACE;
348
349   if(mUpdateRenderThread)
350   {
351     LOG_EVENT("Waiting for graphics initialisation, event-thread blocked");
352
353     // Wait until the graphics has been initialised
354     mGraphicsInitializeWait.Wait(lk);
355
356     LOG_EVENT("graphics initialised, event-thread continuing");
357   }
358 }
359
360 void CombinedUpdateRenderController::ResizeSurface()
361 {
362   LOG_EVENT_TRACE;
363
364   LOG_EVENT("Resize the surface");
365
366   {
367     ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
368     // Surface is resized and the surface resized count is increased.
369     mSurfaceResized++;
370     mUpdateRenderThreadWaitCondition.Notify(lock);
371   }
372 }
373
374 void CombinedUpdateRenderController::SetRenderRefreshRate(unsigned int numberOfFramesPerRender)
375 {
376   // Not protected by lock, but written to rarely so not worth adding a lock when reading
377   mDefaultFrameDelta                = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
378   mDefaultFrameDurationMilliseconds = uint64_t(numberOfFramesPerRender) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
379   mDefaultFrameDurationNanoseconds  = uint64_t(numberOfFramesPerRender) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
380   mDefaultHalfFrameNanoseconds      = mDefaultFrameDurationNanoseconds / 2u;
381
382   LOG_EVENT("mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds);
383 }
384
385 void CombinedUpdateRenderController::SetPreRenderCallback(CallbackBase* callback)
386 {
387   LOG_EVENT_TRACE;
388   LOG_EVENT("Set PreRender Callback");
389
390   ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
391   if(mPreRenderCallback)
392   {
393     delete mPreRenderCallback;
394   }
395   mPreRenderCallback = callback;
396 }
397
398 void CombinedUpdateRenderController::AddSurface(Dali::RenderSurfaceInterface* surface)
399 {
400   LOG_EVENT_TRACE;
401   LOG_EVENT("Surface is added");
402   if(mUpdateRenderThread)
403   {
404     // Set the ThreadSyncronizationInterface on the added surface
405     surface->SetThreadSynchronization(*this);
406   }
407 }
408
409 int32_t CombinedUpdateRenderController::GetThreadId() const
410 {
411   return mThreadId;
412 }
413
414 ///////////////////////////////////////////////////////////////////////////////////////////////////
415 // EVENT THREAD
416 ///////////////////////////////////////////////////////////////////////////////////////////////////
417
418 void CombinedUpdateRenderController::RunUpdateRenderThread(int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode)
419 {
420   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
421
422   switch(mThreadMode)
423   {
424     case ThreadMode::NORMAL:
425     {
426       mUpdateRenderRunCount    = numberOfCycles;
427       mUseElapsedTimeAfterWait = (animationProgression == AnimationProgression::USE_ELAPSED_TIME);
428       break;
429     }
430     case ThreadMode::RUN_IF_REQUESTED:
431     {
432       if(updateMode != UpdateMode::FORCE_RENDER)
433       {
434         // Render only if the update mode is FORCE_RENDER which means the application requests it.
435         // We don't want to awake the update thread.
436         return;
437       }
438
439       mUpdateRenderRunCount++;         // Increase the update request count
440       mUseElapsedTimeAfterWait = TRUE; // The elapsed time should be used. We want animations to proceed.
441       break;
442     }
443   }
444
445   mUpdateRenderThreadCanSleep = FALSE;
446   mUploadWithoutRendering     = (updateMode == UpdateMode::SKIP_RENDER);
447   LOG_COUNTER_EVENT("mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait);
448   mUpdateRenderThreadWaitCondition.Notify(lock);
449 }
450
451 void CombinedUpdateRenderController::PauseUpdateRenderThread()
452 {
453   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
454   mUpdateRenderRunCount = 0;
455 }
456
457 void CombinedUpdateRenderController::StopUpdateRenderThread()
458 {
459   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
460   mDestroyUpdateRenderThread = TRUE;
461   mUpdateRenderThreadWaitCondition.Notify(lock);
462 }
463
464 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
465 {
466   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
467
468   if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
469   {
470     return !mRunning || mUpdateRenderThreadCanSleep;
471   }
472
473   return (mUpdateRenderRunCount != CONTINUOUS) || // Report paused if NOT continuously running
474          mUpdateRenderThreadCanSleep;             // Report paused if sleeping
475 }
476
477 void CombinedUpdateRenderController::ProcessSleepRequest()
478 {
479   LOG_EVENT_TRACE;
480
481   // Decrement Update request count
482   if(mUpdateRequestCount > 0)
483   {
484     --mUpdateRequestCount;
485   }
486
487   // Can sleep if our update-request count is 0
488   // Update/Render thread can choose to carry on updating if it determines more update/renders are required
489   if(mUpdateRequestCount == 0)
490   {
491     LOG_EVENT("Going to sleep");
492
493     ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
494     mUpdateRenderThreadCanSleep = TRUE;
495   }
496 }
497
498 ///////////////////////////////////////////////////////////////////////////////////////////////////
499 // UPDATE/RENDER THREAD
500 ///////////////////////////////////////////////////////////////////////////////////////////////////
501
502 void CombinedUpdateRenderController::UpdateRenderThread()
503 {
504   ThreadSettings::SetThreadName("RenderThread\0");
505   mThreadId = ThreadSettings::GetThreadId();
506
507   // Install a function for logging
508   mEnvironmentOptions.InstallLogFunction();
509
510   // Install a function for tracing
511   mEnvironmentOptions.InstallTraceFunction();
512
513   LOG_UPDATE_RENDER("THREAD CREATED");
514
515   // Initialize graphics
516   GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
517   graphics.Initialize();
518
519   Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
520   displayConnection.Initialize(); //@todo Move InitializeGraphics code into graphics implementation
521
522   NotifyGraphicsInitialised();
523
524   //@todo Vk swaps this around, but we need to support surfaceless context for multi-window
525   graphics.ConfigureSurface(mAdaptorInterfaces.GetRenderSurfaceInterface());
526
527   // Tell core it has a context
528   mCore.ContextCreated();
529
530   NotifyThreadInitialised();
531
532   // Update time
533   uint64_t lastFrameTime;
534   TimeService::GetNanoseconds(lastFrameTime);
535   uint64_t lastMemPoolLogTime = lastFrameTime;
536
537   LOG_UPDATE_RENDER("THREAD INITIALISED");
538
539   bool     useElapsedTime     = true;
540   bool     updateRequired     = true;
541   uint64_t timeToSleepUntil   = 0;
542   int      extraFramesDropped = 0;
543
544   const uint64_t memPoolInterval = 1e9 * float(mEnvironmentOptions.GetMemoryPoolInterval());
545
546   const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
547   const bool         renderToFboEnabled  = 0u != renderToFboInterval;
548   unsigned int       frameCount          = 0u;
549
550   while(UpdateRenderReady(useElapsedTime, updateRequired, timeToSleepUntil))
551   {
552     LOG_UPDATE_RENDER_TRACE;
553
554     // For thread safe
555     bool                          uploadOnly     = mUploadWithoutRendering;
556     unsigned int                  surfaceResized = mSurfaceResized;
557     Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
558
559     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
560     AddPerformanceMarker(PerformanceInterface::VSYNC);
561
562     uint64_t currentFrameStartTime = 0;
563     TimeService::GetNanoseconds(currentFrameStartTime);
564
565     uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
566
567     // Optional FPS Tracking when continuously rendering
568     if(useElapsedTime && mFpsTracker.Enabled())
569     {
570       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
571       mFpsTracker.Track(absoluteTimeSinceLastRender);
572     }
573
574     lastFrameTime = currentFrameStartTime; // Store frame start time
575
576     //////////////////////////////
577     // REPLACE SURFACE
578     //////////////////////////////
579
580     Dali::RenderSurfaceInterface* newSurface = ShouldSurfaceBeReplaced();
581     if(DALI_UNLIKELY(newSurface))
582     {
583       LOG_UPDATE_RENDER_TRACE_FMT("Replacing Surface");
584       // This is designed for replacing pixmap surfaces, but should work for window as well
585       // we need to delete the surface and renderable (pixmap / window)
586       // Then create a new pixmap/window and new surface
587       // If the new surface has a different display connection, then the context will be lost
588       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
589       graphics.ActivateSurfaceContext(newSurface);
590       // TODO: ReplaceGraphicsSurface doesn't work, InitializeGraphics()
591       // already creates new surface window, the surface and the context.
592       // We probably don't need ReplaceGraphicsSurface at all.
593       // newSurface->ReplaceGraphicsSurface();
594       SurfaceReplaced();
595     }
596
597     const bool isRenderingToFbo = renderToFboEnabled && ((0u == frameCount) || (0u != frameCount % renderToFboInterval));
598     ++frameCount;
599
600     //////////////////////////////
601     // UPDATE
602     //////////////////////////////
603
604     const uint32_t currentTime   = static_cast<uint32_t>(currentFrameStartTime / NANOSECONDS_PER_MILLISECOND);
605     const uint32_t nextFrameTime = currentTime + static_cast<uint32_t>(mDefaultFrameDurationMilliseconds);
606
607     uint64_t noOfFramesSinceLastUpdate = 1;
608     float    frameDelta                = 0.0f;
609     if(useElapsedTime)
610     {
611       if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
612       {
613         extraFramesDropped = 0;
614         while(timeSinceLastFrame >= mDefaultFrameDurationNanoseconds)
615         {
616           timeSinceLastFrame -= mDefaultFrameDurationNanoseconds;
617           extraFramesDropped++;
618         }
619       }
620
621       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
622       noOfFramesSinceLastUpdate += extraFramesDropped;
623
624       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
625     }
626     LOG_UPDATE_RENDER("timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta);
627
628     Integration::UpdateStatus updateStatus;
629
630     AddPerformanceMarker(PerformanceInterface::UPDATE_START);
631     TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE");
632     mCore.Update(frameDelta,
633                  currentTime,
634                  nextFrameTime,
635                  updateStatus,
636                  renderToFboEnabled,
637                  isRenderingToFbo,
638                  uploadOnly);
639     TRACE_UPDATE_RENDER_END("DALI_UPDATE");
640     AddPerformanceMarker(PerformanceInterface::UPDATE_END);
641
642     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
643
644     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
645     if(updateStatus.NeedsNotification())
646     {
647       mNotificationTrigger.Trigger();
648       LOG_UPDATE_RENDER("Notification Triggered");
649     }
650
651     // Optional logging of update/render status
652     mUpdateStatusLogger.Log(keepUpdatingStatus);
653
654     //////////////////////////////
655     // RENDER
656     //////////////////////////////
657
658     graphics.FrameStart();
659     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
660
661     if(mPreRenderCallback != NULL)
662     {
663       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
664       if(!keepCallback)
665       {
666         delete mPreRenderCallback;
667         mPreRenderCallback = NULL;
668       }
669     }
670
671     graphics.ActivateResourceContext();
672
673     if(mFirstFrameAfterResume)
674     {
675       // mFirstFrameAfterResume is set to true when the thread is resumed
676       // Let graphics know the first frame after thread initialized or resumed.
677       graphics.SetFirstFrameAfterResume();
678       mFirstFrameAfterResume = FALSE;
679     }
680
681     Integration::RenderStatus renderStatus;
682
683     AddPerformanceMarker(PerformanceInterface::RENDER_START);
684     TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER");
685
686     // Upload shared resources
687     mCore.PreRender(renderStatus, mForceClear);
688
689     if(!uploadOnly || surfaceResized)
690     {
691       // Go through each window
692       WindowContainer windows;
693       mAdaptorInterfaces.GetWindowContainerInterface(windows);
694
695       for(auto&& window : windows)
696       {
697         Dali::Integration::Scene      scene         = window->GetScene();
698         Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
699
700         if(scene && windowSurface)
701         {
702           Integration::RenderStatus windowRenderStatus;
703
704           const bool sceneSurfaceResized = scene.IsSurfaceRectChanged();
705
706           // clear previous frame damaged render items rects, buffer history is tracked on surface level
707           mDamagedRects.clear();
708
709           // Collect damage rects
710           mCore.PreRender(scene, mDamagedRects);
711
712           // Render off-screen frame buffers first if any
713           mCore.RenderScene(windowRenderStatus, scene, true);
714
715           Rect<int> clippingRect; // Empty for fbo rendering
716
717           // Switch to the context of the surface, merge damaged areas for previous frames
718           windowSurface->PreRender(sceneSurfaceResized, mDamagedRects, clippingRect); // Switch GL context
719
720           // Render the surface
721           mCore.RenderScene(windowRenderStatus, scene, false, clippingRect);
722
723           // Buffer swapping now happens when the surface render target is presented.
724
725           // If surface is resized, the surface resized count is decreased.
726           if(DALI_UNLIKELY(sceneSurfaceResized))
727           {
728             SurfaceResized();
729           }
730         }
731       }
732     }
733
734     if(!uploadOnly)
735     {
736       graphics.PostRender();
737     }
738
739     mCore.PostRender();
740
741     //////////////////////////////
742     // DELETE SURFACE
743     //////////////////////////////
744     if(DALI_UNLIKELY(deletedSurface))
745     {
746       LOG_UPDATE_RENDER_TRACE_FMT("Deleting Surface");
747
748       deletedSurface->DestroySurface();
749
750       SurfaceDeleted();
751     }
752
753     TRACE_UPDATE_RENDER_END("DALI_RENDER");
754     AddPerformanceMarker(PerformanceInterface::RENDER_END);
755
756     // if the memory pool interval is set and has elapsed, log the graphics memory pools
757     if(0 < memPoolInterval && memPoolInterval < lastFrameTime - lastMemPoolLogTime)
758     {
759       lastMemPoolLogTime = lastFrameTime;
760       graphics.LogMemoryPools();
761     }
762
763     mForceClear = false;
764
765     // Trigger event thread to request Update/Render thread to sleep if update not required
766     if((Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus) && !renderStatus.NeedsUpdate())
767     {
768       mSleepTrigger->Trigger();
769       updateRequired = false;
770       LOG_UPDATE_RENDER("Sleep Triggered");
771     }
772     else
773     {
774       updateRequired = true;
775     }
776
777     //////////////////////////////
778     // FRAME TIME
779     //////////////////////////////
780
781     extraFramesDropped = 0;
782
783     if(timeToSleepUntil == 0)
784     {
785       // If this is the first frame after the thread is initialized or resumed, we
786       // use the actual time the current frame starts from to calculate the time to
787       // sleep until the next frame.
788       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
789     }
790     else
791     {
792       // Otherwise, always use the sleep-until time calculated in the last frame to
793       // calculate the time to sleep until the next frame. In this way, if there is
794       // any time gap between the current frame and the next frame, or if update or
795       // rendering in the current frame takes too much time so that the specified
796       // sleep-until time has already passed, it will try to keep the frames syncing
797       // by shortening the duration of the next frame.
798       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
799
800       // Check the current time at the end of the frame
801       uint64_t currentFrameEndTime = 0;
802       TimeService::GetNanoseconds(currentFrameEndTime);
803       while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
804       {
805         // We are more than one frame behind already, so just drop the next frames
806         // until the sleep-until time is later than the current time so that we can
807         // catch up.
808         timeToSleepUntil += mDefaultFrameDurationNanoseconds;
809         extraFramesDropped++;
810       }
811     }
812
813     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
814     if(0u == renderToFboInterval)
815     {
816       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
817       TimeService::SleepUntil(timeToSleepUntil);
818     }
819   }
820
821   // Inform core of context destruction
822   mCore.ContextDestroyed();
823
824   WindowContainer windows;
825   mAdaptorInterfaces.GetWindowContainerInterface(windows);
826
827   // Destroy surfaces
828   for(auto&& window : windows)
829   {
830     Dali::RenderSurfaceInterface* surface = window->GetSurface();
831     surface->DestroySurface();
832   }
833
834   graphics.Shutdown();
835
836   LOG_UPDATE_RENDER("THREAD DESTROYED");
837
838   // Uninstall the logging function
839   mEnvironmentOptions.UnInstallLogFunction();
840 }
841
842 bool CombinedUpdateRenderController::UpdateRenderReady(bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil)
843 {
844   useElapsedTime = true;
845
846   ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
847   while((!mUpdateRenderRunCount ||                                                      // Should try to wait if event-thread has paused the Update/Render thread
848          (mUpdateRenderThreadCanSleep && !updateRequired && !mPendingRequestUpdate)) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
849         !mDestroyUpdateRenderThread &&                                                  // Ensure we don't wait if the update-render-thread is supposed to be destroyed
850         !mNewSurface &&                                                                 // Ensure we don't wait if we need to replace the surface
851         !mDeletedSurface &&                                                             // Ensure we don't wait if we need to delete the surface
852         !mSurfaceResized)                                                               // Ensure we don't wait if we need to resize the surface
853   {
854     LOG_UPDATE_RENDER("WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount);
855     LOG_UPDATE_RENDER("      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
856     LOG_UPDATE_RENDER("      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread);
857     LOG_UPDATE_RENDER("      mNewSurface:                 %d", mNewSurface);
858     LOG_UPDATE_RENDER("      mDeletedSurface:             %d", mDeletedSurface);
859     LOG_UPDATE_RENDER("      mSurfaceResized:             %d", mSurfaceResized);
860
861     // Reset the time when the thread is waiting, so the sleep-until time for
862     // the first frame after resuming should be based on the actual start time
863     // of the first frame.
864     timeToSleepUntil = 0;
865
866     mUpdateRenderThreadWaitCondition.Wait(updateLock);
867
868     if(!mUseElapsedTimeAfterWait)
869     {
870       useElapsedTime = false;
871     }
872   }
873
874   LOG_COUNTER_UPDATE_RENDER("mUpdateRenderRunCount:       %d", mUpdateRenderRunCount);
875   LOG_COUNTER_UPDATE_RENDER("mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
876   LOG_COUNTER_UPDATE_RENDER("mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread);
877   LOG_COUNTER_UPDATE_RENDER("mNewSurface:                 %d", mNewSurface);
878   LOG_COUNTER_UPDATE_RENDER("mDeletedSurface:             %d", mDeletedSurface);
879   LOG_COUNTER_UPDATE_RENDER("mSurfaceResized:             %d", mSurfaceResized);
880
881   mUseElapsedTimeAfterWait    = FALSE;
882   mUpdateRenderThreadCanSleep = FALSE;
883   mPendingRequestUpdate       = FALSE;
884
885   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
886   // requested number of cycles
887   if(mUpdateRenderRunCount > 0)
888   {
889     --mUpdateRenderRunCount;
890   }
891
892   // Keep the update-render thread alive if this thread is NOT to be destroyed
893   return !mDestroyUpdateRenderThread;
894 }
895
896 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
897 {
898   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
899
900   Dali::RenderSurfaceInterface* newSurface = mNewSurface;
901   mNewSurface                              = NULL;
902
903   return newSurface;
904 }
905
906 void CombinedUpdateRenderController::SurfaceReplaced()
907 {
908   // Just increment the semaphore
909   mSurfaceSemaphore.Release(1);
910 }
911
912 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
913 {
914   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
915
916   Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
917   mDeletedSurface                              = NULL;
918
919   return deletedSurface;
920 }
921
922 void CombinedUpdateRenderController::SurfaceDeleted()
923 {
924   // Just increment the semaphore
925   mSurfaceSemaphore.Release(1);
926 }
927
928 void CombinedUpdateRenderController::SurfaceResized()
929 {
930   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
931   if(mSurfaceResized)
932   {
933     mSurfaceResized--;
934   }
935 }
936
937 ///////////////////////////////////////////////////////////////////////////////////////////////////
938 // ALL THREADS
939 ///////////////////////////////////////////////////////////////////////////////////////////////////
940
941 void CombinedUpdateRenderController::NotifyThreadInitialised()
942 {
943   // Just increment the semaphore
944   mEventThreadSemaphore.Release(1);
945 }
946
947 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
948 {
949   mGraphicsInitializeWait.Notify();
950 }
951
952 void CombinedUpdateRenderController::AddPerformanceMarker(PerformanceInterface::MarkerType type)
953 {
954   if(mPerformanceInterface)
955   {
956     mPerformanceInterface->AddMarker(type);
957   }
958 }
959
960 /////////////////////////////////////////////////////////////////////////////////////////////////
961 // POST RENDERING: EVENT THREAD
962 /////////////////////////////////////////////////////////////////////////////////////////////////
963
964 void CombinedUpdateRenderController::PostRenderComplete()
965 {
966   ConditionalWait::ScopedLock lock(mPostRenderWaitCondition);
967   mPostRendering = FALSE;
968   mPostRenderWaitCondition.Notify(lock);
969 }
970
971 ///////////////////////////////////////////////////////////////////////////////////////////////////
972 // POST RENDERING: RENDER THREAD
973 ///////////////////////////////////////////////////////////////////////////////////////////////////
974
975 void CombinedUpdateRenderController::PostRenderStarted()
976 {
977   ConditionalWait::ScopedLock lock(mPostRenderWaitCondition);
978   mPostRendering = TRUE;
979 }
980
981 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
982 {
983   ConditionalWait::ScopedLock lock(mPostRenderWaitCondition);
984   while(mPostRendering &&
985         !mNewSurface &&     // We should NOT wait if we're replacing the surface
986         !mDeletedSurface && // We should NOT wait if we're deleting the surface
987         !mDestroyUpdateRenderThread)
988   {
989     mPostRenderWaitCondition.Wait(lock);
990   }
991 }
992
993 } // namespace Adaptor
994
995 } // namespace Internal
996
997 } // namespace Dali