Revert "[Tizen] TextureUploadManager implement"
[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   mAdaptorInterfaces(adaptorInterfaces),
95   mPerformanceInterface(adaptorInterfaces.GetPerformanceInterface()),
96   mCore(adaptorInterfaces.GetCore()),
97   mEnvironmentOptions(environmentOptions),
98   mNotificationTrigger(adaptorInterfaces.GetProcessCoreEventsTrigger()),
99   mSleepTrigger(NULL),
100   mPreRenderCallback(NULL),
101   mUpdateRenderThread(NULL),
102   mDefaultFrameDelta(0.0f),
103   mDefaultFrameDurationMilliseconds(0u),
104   mDefaultFrameDurationNanoseconds(0u),
105   mDefaultHalfFrameNanoseconds(0u),
106   mUpdateRequestCount(0u),
107   mRunning(FALSE),
108   mThreadId(0),
109   mThreadMode(threadMode),
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(0),
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
138 CombinedUpdateRenderController::~CombinedUpdateRenderController()
139 {
140   LOG_EVENT_TRACE;
141
142   Stop();
143
144   delete mPreRenderCallback;
145   delete mSleepTrigger;
146 }
147
148 void CombinedUpdateRenderController::Initialize()
149 {
150   LOG_EVENT_TRACE;
151
152   // Ensure Update/Render Thread not already created
153   DALI_ASSERT_ALWAYS(!mUpdateRenderThread);
154
155   // Create Update/Render Thread
156   ConditionalWait::ScopedLock lock(mGraphicsInitializeWait);
157   mUpdateRenderThread = new pthread_t();
158   int error           = pthread_create(mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this);
159   DALI_ASSERT_ALWAYS(!error && "Return code from pthread_create() when creating UpdateRenderThread");
160
161   // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called
162   // When this function returns, the application initialisation on the event thread should occur
163 }
164
165 void CombinedUpdateRenderController::Start()
166 {
167   LOG_EVENT_TRACE;
168
169   DALI_ASSERT_ALWAYS(!mRunning && mUpdateRenderThread);
170
171   // Wait until all threads created in Initialise are up and running
172   for(unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i)
173   {
174     mEventThreadSemaphore.Acquire();
175   }
176
177   mRunning = TRUE;
178
179   LOG_EVENT("Startup Complete, starting Update/Render Thread");
180
181   RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
182
183   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
184   if(currentSurface)
185   {
186     currentSurface->StartRender();
187   }
188
189   DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Start\n");
190 }
191
192 void CombinedUpdateRenderController::Pause()
193 {
194   LOG_EVENT_TRACE;
195
196   mRunning = FALSE;
197
198   PauseUpdateRenderThread();
199
200   AddPerformanceMarker(PerformanceInterface::PAUSED);
201
202   DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Pause\n");
203 }
204
205 void CombinedUpdateRenderController::Resume()
206 {
207   LOG_EVENT_TRACE;
208
209   if(!mRunning && IsUpdateRenderThreadPaused())
210   {
211     LOG_EVENT("Resuming");
212
213     RunUpdateRenderThread(CONTINUOUS, AnimationProgression::USE_ELAPSED_TIME, UpdateMode::NORMAL);
214
215     AddPerformanceMarker(PerformanceInterface::RESUME);
216
217     mRunning               = TRUE;
218     mForceClear            = TRUE;
219     mFirstFrameAfterResume = TRUE;
220
221     DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Resume\n");
222   }
223   else
224   {
225     DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Resume: Already resumed [%d, %d, %d]\n", mRunning, mUpdateRenderRunCount, mUpdateRenderThreadCanSleep);
226   }
227 }
228
229 void CombinedUpdateRenderController::Stop()
230 {
231   LOG_EVENT_TRACE;
232
233   // Stop Rendering and the Update/Render Thread
234   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
235   if(currentSurface)
236   {
237     currentSurface->StopRender();
238   }
239
240   StopUpdateRenderThread();
241
242   if(mUpdateRenderThread)
243   {
244     LOG_EVENT("Destroying UpdateRenderThread");
245
246     // wait for the thread to finish
247     pthread_join(*mUpdateRenderThread, NULL);
248
249     delete mUpdateRenderThread;
250     mUpdateRenderThread = NULL;
251   }
252
253   mRunning = FALSE;
254
255   DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Stop\n");
256 }
257
258 void CombinedUpdateRenderController::RequestUpdate()
259 {
260   LOG_EVENT_TRACE;
261
262   // Increment the update-request count to the maximum
263   if(mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS)
264   {
265     ++mUpdateRequestCount;
266   }
267
268   if(mRunning && IsUpdateRenderThreadPaused())
269   {
270     LOG_EVENT("Processing");
271
272     RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
273   }
274
275   ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
276   mPendingRequestUpdate = TRUE;
277 }
278
279 void CombinedUpdateRenderController::RequestUpdateOnce(UpdateMode updateMode)
280 {
281   // Increment the update-request count to the maximum
282   if(mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS)
283   {
284     ++mUpdateRequestCount;
285   }
286
287   if(IsUpdateRenderThreadPaused() || updateMode == UpdateMode::FORCE_RENDER)
288   {
289     LOG_EVENT_TRACE;
290
291     // Run Update/Render once
292     RunUpdateRenderThread(ONCE, AnimationProgression::NONE, updateMode);
293   }
294 }
295
296 void CombinedUpdateRenderController::ReplaceSurface(Dali::RenderSurfaceInterface* newSurface)
297 {
298   LOG_EVENT_TRACE;
299
300   if(mUpdateRenderThread)
301   {
302     // Set the ThreadSyncronizationInterface on the new surface
303     newSurface->SetThreadSynchronization(*this);
304
305     LOG_EVENT("Starting to replace the surface, event-thread blocked");
306
307     // Start replacing the surface.
308     {
309       ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
310       mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
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       mPostRendering  = FALSE; // Clear the post-rendering flag as Update/Render thread will delete the surface now
334       mDeletedSurface = surface;
335       mUpdateRenderThreadWaitCondition.Notify(lock);
336     }
337
338     // Wait until the surface has been deleted
339     mSurfaceSemaphore.Acquire();
340
341     LOG_EVENT("Surface deleted, event-thread continuing");
342   }
343 }
344
345 void CombinedUpdateRenderController::WaitForGraphicsInitialization()
346 {
347   ConditionalWait::ScopedLock lk(mGraphicsInitializeWait);
348   LOG_EVENT_TRACE;
349
350   if(mUpdateRenderThread)
351   {
352     LOG_EVENT("Waiting for graphics initialisation, event-thread blocked");
353
354     // Wait until the graphics has been initialised
355     mGraphicsInitializeWait.Wait(lk);
356
357     LOG_EVENT("graphics initialised, event-thread continuing");
358   }
359 }
360
361 void CombinedUpdateRenderController::ResizeSurface()
362 {
363   LOG_EVENT_TRACE;
364
365   LOG_EVENT("Resize the surface");
366
367   {
368     ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
369     // Surface is resized and the surface resized count is increased.
370     mSurfaceResized++;
371     mUpdateRenderThreadWaitCondition.Notify(lock);
372   }
373 }
374
375 void CombinedUpdateRenderController::SetRenderRefreshRate(unsigned int numberOfFramesPerRender)
376 {
377   // Not protected by lock, but written to rarely so not worth adding a lock when reading
378   mDefaultFrameDelta                = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
379   mDefaultFrameDurationMilliseconds = uint64_t(numberOfFramesPerRender) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
380   mDefaultFrameDurationNanoseconds  = uint64_t(numberOfFramesPerRender) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
381   mDefaultHalfFrameNanoseconds      = mDefaultFrameDurationNanoseconds / 2u;
382
383   LOG_EVENT("mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds);
384 }
385
386 void CombinedUpdateRenderController::SetPreRenderCallback(CallbackBase* callback)
387 {
388   LOG_EVENT_TRACE;
389   LOG_EVENT("Set PreRender Callback");
390
391   ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
392   if(mPreRenderCallback)
393   {
394     delete mPreRenderCallback;
395   }
396   mPreRenderCallback = callback;
397 }
398
399 void CombinedUpdateRenderController::AddSurface(Dali::RenderSurfaceInterface* surface)
400 {
401   LOG_EVENT_TRACE;
402   LOG_EVENT("Surface is added");
403   if(mUpdateRenderThread)
404   {
405     // Set the ThreadSyncronizationInterface on the added surface
406     surface->SetThreadSynchronization(*this);
407   }
408 }
409
410 int32_t CombinedUpdateRenderController::GetThreadId() const
411 {
412   return mThreadId;
413 }
414
415 ///////////////////////////////////////////////////////////////////////////////////////////////////
416 // EVENT THREAD
417 ///////////////////////////////////////////////////////////////////////////////////////////////////
418
419 void CombinedUpdateRenderController::RunUpdateRenderThread(int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode)
420 {
421   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
422
423   switch(mThreadMode)
424   {
425     case ThreadMode::NORMAL:
426     {
427       mUpdateRenderRunCount    = numberOfCycles;
428       mUseElapsedTimeAfterWait = (animationProgression == AnimationProgression::USE_ELAPSED_TIME);
429       break;
430     }
431     case ThreadMode::RUN_IF_REQUESTED:
432     {
433       if(updateMode != UpdateMode::FORCE_RENDER)
434       {
435         // Render only if the update mode is FORCE_RENDER which means the application requests it.
436         // We don't want to awake the update thread.
437         return;
438       }
439
440       mUpdateRenderRunCount++;         // Increase the update request count
441       mUseElapsedTimeAfterWait = TRUE; // The elapsed time should be used. We want animations to proceed.
442       break;
443     }
444   }
445
446   mUpdateRenderThreadCanSleep = FALSE;
447   mUploadWithoutRendering     = (updateMode == UpdateMode::SKIP_RENDER);
448   LOG_COUNTER_EVENT("mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait);
449   mUpdateRenderThreadWaitCondition.Notify(lock);
450 }
451
452 void CombinedUpdateRenderController::PauseUpdateRenderThread()
453 {
454   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
455   mUpdateRenderRunCount = 0;
456 }
457
458 void CombinedUpdateRenderController::StopUpdateRenderThread()
459 {
460   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
461   mDestroyUpdateRenderThread = TRUE;
462   mUpdateRenderThreadWaitCondition.Notify(lock);
463 }
464
465 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
466 {
467   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
468
469   if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
470   {
471     return !mRunning || mUpdateRenderThreadCanSleep;
472   }
473
474   return (mUpdateRenderRunCount != CONTINUOUS) || // Report paused if NOT continuously running
475          mUpdateRenderThreadCanSleep;             // Report paused if sleeping
476 }
477
478 void CombinedUpdateRenderController::ProcessSleepRequest()
479 {
480   LOG_EVENT_TRACE;
481
482   // Decrement Update request count
483   if(mUpdateRequestCount > 0)
484   {
485     --mUpdateRequestCount;
486   }
487
488   // Can sleep if our update-request count is 0
489   // Update/Render thread can choose to carry on updating if it determines more update/renders are required
490   if(mUpdateRequestCount == 0)
491   {
492     LOG_EVENT("Going to sleep");
493
494     ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
495     mUpdateRenderThreadCanSleep = TRUE;
496   }
497 }
498
499 ///////////////////////////////////////////////////////////////////////////////////////////////////
500 // UPDATE/RENDER THREAD
501 ///////////////////////////////////////////////////////////////////////////////////////////////////
502
503 void CombinedUpdateRenderController::UpdateRenderThread()
504 {
505   ThreadSettings::SetThreadName("RenderThread\0");
506   mThreadId = ThreadSettings::GetThreadId();
507
508   // Install a function for logging
509   mEnvironmentOptions.InstallLogFunction();
510
511   // Install a function for tracing
512   mEnvironmentOptions.InstallTraceFunction();
513
514   LOG_UPDATE_RENDER("THREAD CREATED");
515
516   // Initialize graphics
517   GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
518   graphics.Initialize();
519
520   Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
521   displayConnection.Initialize(); //@todo Move InitializeGraphics code into graphics implementation
522
523   NotifyGraphicsInitialised();
524
525   //@todo Vk swaps this around, but we need to support surfaceless context for multi-window
526   graphics.ConfigureSurface(mAdaptorInterfaces.GetRenderSurfaceInterface());
527
528   // Tell core it has a context
529   mCore.ContextCreated();
530
531   NotifyThreadInitialised();
532
533   // Update time
534   uint64_t lastFrameTime;
535   TimeService::GetNanoseconds(lastFrameTime);
536   uint64_t lastMemPoolLogTime = lastFrameTime;
537
538   LOG_UPDATE_RENDER("THREAD INITIALISED");
539
540   bool     useElapsedTime     = true;
541   bool     updateRequired     = true;
542   uint64_t timeToSleepUntil   = 0;
543   int      extraFramesDropped = 0;
544
545   const uint64_t memPoolInterval = 1e9 * float(mEnvironmentOptions.GetMemoryPoolInterval());
546
547   const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
548   const bool         renderToFboEnabled  = 0u != renderToFboInterval;
549   unsigned int       frameCount          = 0u;
550
551   while(UpdateRenderReady(useElapsedTime, updateRequired, timeToSleepUntil))
552   {
553     LOG_UPDATE_RENDER_TRACE;
554
555     // For thread safe
556     bool                          uploadOnly     = mUploadWithoutRendering;
557     unsigned int                  surfaceResized = mSurfaceResized;
558     Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
559
560     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
561     AddPerformanceMarker(PerformanceInterface::VSYNC);
562
563     uint64_t currentFrameStartTime = 0;
564     TimeService::GetNanoseconds(currentFrameStartTime);
565
566     uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
567
568     // Optional FPS Tracking when continuously rendering
569     if(useElapsedTime && mFpsTracker.Enabled())
570     {
571       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
572       mFpsTracker.Track(absoluteTimeSinceLastRender);
573     }
574
575     lastFrameTime = currentFrameStartTime; // Store frame start time
576
577     //////////////////////////////
578     // REPLACE SURFACE
579     //////////////////////////////
580
581     Dali::RenderSurfaceInterface* newSurface = ShouldSurfaceBeReplaced();
582     if(DALI_UNLIKELY(newSurface))
583     {
584       LOG_UPDATE_RENDER_TRACE_FMT("Replacing Surface");
585       // This is designed for replacing pixmap surfaces, but should work for window as well
586       // we need to delete the surface and renderable (pixmap / window)
587       // Then create a new pixmap/window and new surface
588       // If the new surface has a different display connection, then the context will be lost
589       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
590       graphics.ActivateSurfaceContext(newSurface);
591       // TODO: ReplaceGraphicsSurface doesn't work, InitializeGraphics()
592       // already creates new surface window, the surface and the context.
593       // We probably don't need ReplaceGraphicsSurface at all.
594       // newSurface->ReplaceGraphicsSurface();
595       SurfaceReplaced();
596     }
597
598     const bool isRenderingToFbo = renderToFboEnabled && ((0u == frameCount) || (0u != frameCount % renderToFboInterval));
599     ++frameCount;
600
601     //////////////////////////////
602     // UPDATE
603     //////////////////////////////
604
605     const uint32_t currentTime   = static_cast<uint32_t>(currentFrameStartTime / NANOSECONDS_PER_MILLISECOND);
606     const uint32_t nextFrameTime = currentTime + static_cast<uint32_t>(mDefaultFrameDurationMilliseconds);
607
608     uint64_t noOfFramesSinceLastUpdate = 1;
609     float    frameDelta                = 0.0f;
610     if(useElapsedTime)
611     {
612       if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
613       {
614         extraFramesDropped = 0;
615         while(timeSinceLastFrame >= mDefaultFrameDurationNanoseconds)
616         {
617           timeSinceLastFrame -= mDefaultFrameDurationNanoseconds;
618           extraFramesDropped++;
619         }
620       }
621
622       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
623       noOfFramesSinceLastUpdate += extraFramesDropped;
624
625       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
626     }
627     LOG_UPDATE_RENDER("timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta);
628
629     Integration::UpdateStatus updateStatus;
630
631     AddPerformanceMarker(PerformanceInterface::UPDATE_START);
632     TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE");
633     mCore.Update(frameDelta,
634                  currentTime,
635                  nextFrameTime,
636                  updateStatus,
637                  renderToFboEnabled,
638                  isRenderingToFbo,
639                  uploadOnly);
640     TRACE_UPDATE_RENDER_END("DALI_UPDATE");
641     AddPerformanceMarker(PerformanceInterface::UPDATE_END);
642
643     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
644
645     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
646     if(updateStatus.NeedsNotification())
647     {
648       mNotificationTrigger.Trigger();
649       LOG_UPDATE_RENDER("Notification Triggered");
650     }
651
652     // Optional logging of update/render status
653     mUpdateStatusLogger.Log(keepUpdatingStatus);
654
655     //////////////////////////////
656     // RENDER
657     //////////////////////////////
658
659     graphics.FrameStart();
660     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
661
662     if(mPreRenderCallback != NULL)
663     {
664       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
665       if(!keepCallback)
666       {
667         delete mPreRenderCallback;
668         mPreRenderCallback = NULL;
669       }
670     }
671
672     graphics.ActivateResourceContext();
673
674     if(mFirstFrameAfterResume)
675     {
676       // mFirstFrameAfterResume is set to true when the thread is resumed
677       // Let graphics know the first frame after thread initialized or resumed.
678       graphics.SetFirstFrameAfterResume();
679       mFirstFrameAfterResume = FALSE;
680     }
681
682     Integration::RenderStatus renderStatus;
683
684     AddPerformanceMarker(PerformanceInterface::RENDER_START);
685     TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER");
686
687     // Upload shared resources
688     mCore.PreRender(renderStatus, mForceClear);
689
690     if(!uploadOnly || surfaceResized)
691     {
692       // Go through each window
693       WindowContainer windows;
694       mAdaptorInterfaces.GetWindowContainerInterface(windows);
695
696       for(auto&& window : windows)
697       {
698         Dali::Integration::Scene      scene         = window->GetScene();
699         Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
700
701         if(scene && windowSurface)
702         {
703           Integration::RenderStatus windowRenderStatus;
704
705           const bool sceneSurfaceResized = scene.IsSurfaceRectChanged();
706
707           // clear previous frame damaged render items rects, buffer history is tracked on surface level
708           mDamagedRects.clear();
709
710           // Collect damage rects
711           mCore.PreRender(scene, mDamagedRects);
712
713           // Render off-screen frame buffers first if any
714           mCore.RenderScene(windowRenderStatus, scene, true);
715
716           Rect<int> clippingRect; // Empty for fbo rendering
717
718           // Switch to the context of the surface, merge damaged areas for previous frames
719           windowSurface->PreRender(sceneSurfaceResized, mDamagedRects, clippingRect); // Switch GL context
720
721           // Render the surface
722           mCore.RenderScene(windowRenderStatus, scene, false, clippingRect);
723
724           // Buffer swapping now happens when the surface render target is presented.
725
726           // If surface is resized, the surface resized count is decreased.
727           if(DALI_UNLIKELY(sceneSurfaceResized))
728           {
729             SurfaceResized();
730           }
731         }
732       }
733     }
734
735     if(!uploadOnly)
736     {
737       graphics.PostRender();
738     }
739
740     mCore.PostRender();
741
742     //////////////////////////////
743     // DELETE SURFACE
744     //////////////////////////////
745     if(DALI_UNLIKELY(deletedSurface))
746     {
747       LOG_UPDATE_RENDER_TRACE_FMT("Deleting Surface");
748
749       deletedSurface->DestroySurface();
750
751       SurfaceDeleted();
752     }
753
754     TRACE_UPDATE_RENDER_END("DALI_RENDER");
755     AddPerformanceMarker(PerformanceInterface::RENDER_END);
756
757     // if the memory pool interval is set and has elapsed, log the graphics memory pools
758     if(0 < memPoolInterval && memPoolInterval < lastFrameTime - lastMemPoolLogTime)
759     {
760       lastMemPoolLogTime = lastFrameTime;
761       graphics.LogMemoryPools();
762     }
763
764     mForceClear = false;
765
766     // Trigger event thread to request Update/Render thread to sleep if update not required
767     if((Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus) && !renderStatus.NeedsUpdate())
768     {
769       mSleepTrigger->Trigger();
770       updateRequired = false;
771       LOG_UPDATE_RENDER("Sleep Triggered");
772     }
773     else
774     {
775       updateRequired = true;
776     }
777
778     //////////////////////////////
779     // FRAME TIME
780     //////////////////////////////
781
782     extraFramesDropped = 0;
783
784     if(timeToSleepUntil == 0)
785     {
786       // If this is the first frame after the thread is initialized or resumed, we
787       // use the actual time the current frame starts from to calculate the time to
788       // sleep until the next frame.
789       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
790     }
791     else
792     {
793       // Otherwise, always use the sleep-until time calculated in the last frame to
794       // calculate the time to sleep until the next frame. In this way, if there is
795       // any time gap between the current frame and the next frame, or if update or
796       // rendering in the current frame takes too much time so that the specified
797       // sleep-until time has already passed, it will try to keep the frames syncing
798       // by shortening the duration of the next frame.
799       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
800
801       // Check the current time at the end of the frame
802       uint64_t currentFrameEndTime = 0;
803       TimeService::GetNanoseconds(currentFrameEndTime);
804       while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
805       {
806         // We are more than one frame behind already, so just drop the next frames
807         // until the sleep-until time is later than the current time so that we can
808         // catch up.
809         timeToSleepUntil += mDefaultFrameDurationNanoseconds;
810         extraFramesDropped++;
811       }
812     }
813
814     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
815     if(0u == renderToFboInterval)
816     {
817       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
818       TimeService::SleepUntil(timeToSleepUntil);
819     }
820   }
821
822   // Inform core of context destruction
823   mCore.ContextDestroyed();
824
825   WindowContainer windows;
826   mAdaptorInterfaces.GetWindowContainerInterface(windows);
827
828   // Destroy surfaces
829   for(auto&& window : windows)
830   {
831     Dali::RenderSurfaceInterface* surface = window->GetSurface();
832     surface->DestroySurface();
833   }
834
835   graphics.Shutdown();
836
837   LOG_UPDATE_RENDER("THREAD DESTROYED");
838
839   // Uninstall the logging function
840   mEnvironmentOptions.UnInstallLogFunction();
841 }
842
843 bool CombinedUpdateRenderController::UpdateRenderReady(bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil)
844 {
845   useElapsedTime = true;
846
847   ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
848   while((!mUpdateRenderRunCount ||                                                      // Should try to wait if event-thread has paused the Update/Render thread
849          (mUpdateRenderThreadCanSleep && !updateRequired && !mPendingRequestUpdate)) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
850         !mDestroyUpdateRenderThread &&                                                  // Ensure we don't wait if the update-render-thread is supposed to be destroyed
851         !mNewSurface &&                                                                 // Ensure we don't wait if we need to replace the surface
852         !mDeletedSurface &&                                                             // Ensure we don't wait if we need to delete the surface
853         !mSurfaceResized)                                                               // Ensure we don't wait if we need to resize the surface
854   {
855     LOG_UPDATE_RENDER("WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount);
856     LOG_UPDATE_RENDER("      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
857     LOG_UPDATE_RENDER("      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread);
858     LOG_UPDATE_RENDER("      mNewSurface:                 %d", mNewSurface);
859     LOG_UPDATE_RENDER("      mDeletedSurface:             %d", mDeletedSurface);
860     LOG_UPDATE_RENDER("      mSurfaceResized:             %d", mSurfaceResized);
861
862     // Reset the time when the thread is waiting, so the sleep-until time for
863     // the first frame after resuming should be based on the actual start time
864     // of the first frame.
865     timeToSleepUntil = 0;
866
867     mUpdateRenderThreadWaitCondition.Wait(updateLock);
868
869     if(!mUseElapsedTimeAfterWait)
870     {
871       useElapsedTime = false;
872     }
873   }
874
875   LOG_COUNTER_UPDATE_RENDER("mUpdateRenderRunCount:       %d", mUpdateRenderRunCount);
876   LOG_COUNTER_UPDATE_RENDER("mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
877   LOG_COUNTER_UPDATE_RENDER("mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread);
878   LOG_COUNTER_UPDATE_RENDER("mNewSurface:                 %d", mNewSurface);
879   LOG_COUNTER_UPDATE_RENDER("mDeletedSurface:             %d", mDeletedSurface);
880   LOG_COUNTER_UPDATE_RENDER("mSurfaceResized:             %d", mSurfaceResized);
881
882   mUseElapsedTimeAfterWait    = FALSE;
883   mUpdateRenderThreadCanSleep = FALSE;
884   mPendingRequestUpdate       = FALSE;
885
886   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
887   // requested number of cycles
888   if(mUpdateRenderRunCount > 0)
889   {
890     --mUpdateRenderRunCount;
891   }
892
893   // Keep the update-render thread alive if this thread is NOT to be destroyed
894   return !mDestroyUpdateRenderThread;
895 }
896
897 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
898 {
899   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
900
901   Dali::RenderSurfaceInterface* newSurface = mNewSurface;
902   mNewSurface                              = NULL;
903
904   return newSurface;
905 }
906
907 void CombinedUpdateRenderController::SurfaceReplaced()
908 {
909   // Just increment the semaphore
910   mSurfaceSemaphore.Release(1);
911 }
912
913 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
914 {
915   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
916
917   Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
918   mDeletedSurface                              = NULL;
919
920   return deletedSurface;
921 }
922
923 void CombinedUpdateRenderController::SurfaceDeleted()
924 {
925   // Just increment the semaphore
926   mSurfaceSemaphore.Release(1);
927 }
928
929 void CombinedUpdateRenderController::SurfaceResized()
930 {
931   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
932   if(mSurfaceResized)
933   {
934     mSurfaceResized--;
935   }
936 }
937
938 ///////////////////////////////////////////////////////////////////////////////////////////////////
939 // ALL THREADS
940 ///////////////////////////////////////////////////////////////////////////////////////////////////
941
942 void CombinedUpdateRenderController::NotifyThreadInitialised()
943 {
944   // Just increment the semaphore
945   mEventThreadSemaphore.Release(1);
946 }
947
948 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
949 {
950   mGraphicsInitializeWait.Notify();
951 }
952
953 void CombinedUpdateRenderController::AddPerformanceMarker(PerformanceInterface::MarkerType type)
954 {
955   if(mPerformanceInterface)
956   {
957     mPerformanceInterface->AddMarker(type);
958   }
959 }
960
961 /////////////////////////////////////////////////////////////////////////////////////////////////
962 // POST RENDERING: EVENT THREAD
963 /////////////////////////////////////////////////////////////////////////////////////////////////
964
965 void CombinedUpdateRenderController::PostRenderComplete()
966 {
967   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
968   mPostRendering = FALSE;
969   mUpdateRenderThreadWaitCondition.Notify(lock);
970 }
971
972 ///////////////////////////////////////////////////////////////////////////////////////////////////
973 // POST RENDERING: RENDER THREAD
974 ///////////////////////////////////////////////////////////////////////////////////////////////////
975
976 void CombinedUpdateRenderController::PostRenderStarted()
977 {
978   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
979   mPostRendering = TRUE;
980 }
981
982 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
983 {
984   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
985   while(mPostRendering &&
986         !mNewSurface &&     // We should NOT wait if we're replacing the surface
987         !mDeletedSurface && // We should NOT wait if we're deleting the surface
988         !mDestroyUpdateRenderThread)
989   {
990     mUpdateRenderThreadWaitCondition.Wait(lock);
991   }
992 }
993
994 } // namespace Adaptor
995
996 } // namespace Internal
997
998 } // namespace Dali