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