[Tizen] Make another ConditionalWait for post-rendearing
[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   mPostRenderWaitCondition(),
96   mAdaptorInterfaces(adaptorInterfaces),
97   mPerformanceInterface(adaptorInterfaces.GetPerformanceInterface()),
98   mCore(adaptorInterfaces.GetCore()),
99   mEnvironmentOptions(environmentOptions),
100   mNotificationTrigger(adaptorInterfaces.GetProcessCoreEventsTrigger()),
101   mSleepTrigger(NULL),
102   mPreRenderCallback(NULL),
103   mUpdateRenderThread(NULL),
104   mDefaultFrameDelta(0.0f),
105   mDefaultFrameDurationMilliseconds(0u),
106   mDefaultFrameDurationNanoseconds(0u),
107   mDefaultHalfFrameNanoseconds(0u),
108   mUpdateRequestCount(0u),
109   mRunning(FALSE),
110   mThreadId(0),
111   mThreadMode(threadMode),
112   mUpdateRenderRunCount(0),
113   mDestroyUpdateRenderThread(FALSE),
114   mUpdateRenderThreadCanSleep(FALSE),
115   mPendingRequestUpdate(FALSE),
116   mUseElapsedTimeAfterWait(FALSE),
117   mNewSurface(NULL),
118   mDeletedSurface(nullptr),
119   mPostRendering(FALSE),
120   mSurfaceResized(0),
121   mForceClear(FALSE),
122   mUploadWithoutRendering(FALSE),
123   mFirstFrameAfterResume(FALSE)
124 {
125   LOG_EVENT_TRACE;
126
127   // Initialise frame delta/duration variables first
128   SetRenderRefreshRate(environmentOptions.GetRenderRefreshRate());
129
130   // Set the thread-synchronization interface on the render-surface
131   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
132   if(currentSurface)
133   {
134     currentSurface->SetThreadSynchronization(*this);
135   }
136
137   mSleepTrigger = TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &CombinedUpdateRenderController::ProcessSleepRequest), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
138 }
139
140 CombinedUpdateRenderController::~CombinedUpdateRenderController()
141 {
142   LOG_EVENT_TRACE;
143
144   Stop();
145
146   delete mPreRenderCallback;
147   delete mSleepTrigger;
148 }
149
150 void CombinedUpdateRenderController::Initialize()
151 {
152   LOG_EVENT_TRACE;
153
154   // Ensure Update/Render Thread not already created
155   DALI_ASSERT_ALWAYS(!mUpdateRenderThread);
156
157   // Create Update/Render Thread
158   ConditionalWait::ScopedLock lock(mGraphicsInitializeWait);
159   mUpdateRenderThread = new pthread_t();
160   int error           = pthread_create(mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this);
161   DALI_ASSERT_ALWAYS(!error && "Return code from pthread_create() when creating UpdateRenderThread");
162
163   // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called
164   // When this function returns, the application initialisation on the event thread should occur
165 }
166
167 void CombinedUpdateRenderController::Start()
168 {
169   LOG_EVENT_TRACE;
170
171   DALI_ASSERT_ALWAYS(!mRunning && mUpdateRenderThread);
172
173   // Wait until all threads created in Initialise are up and running
174   for(unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i)
175   {
176     mEventThreadSemaphore.Acquire();
177   }
178
179   mRunning = TRUE;
180
181   LOG_EVENT("Startup Complete, starting Update/Render Thread");
182
183   RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
184
185   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
186   if(currentSurface)
187   {
188     currentSurface->StartRender();
189   }
190
191   DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Start\n");
192 }
193
194 void CombinedUpdateRenderController::Pause()
195 {
196   LOG_EVENT_TRACE;
197
198   mRunning = FALSE;
199
200   PauseUpdateRenderThread();
201
202   AddPerformanceMarker(PerformanceInterface::PAUSED);
203
204   DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Pause\n");
205 }
206
207 void CombinedUpdateRenderController::Resume()
208 {
209   LOG_EVENT_TRACE;
210
211   if(!mRunning && IsUpdateRenderThreadPaused())
212   {
213     LOG_EVENT("Resuming");
214
215     RunUpdateRenderThread(CONTINUOUS, AnimationProgression::USE_ELAPSED_TIME, UpdateMode::NORMAL);
216
217     AddPerformanceMarker(PerformanceInterface::RESUME);
218
219     mRunning               = TRUE;
220     mForceClear            = TRUE;
221     mFirstFrameAfterResume = TRUE;
222
223     DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Resume\n");
224   }
225   else
226   {
227     DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Resume: Already resumed [%d, %d, %d]\n", mRunning, mUpdateRenderRunCount, mUpdateRenderThreadCanSleep);
228   }
229 }
230
231 void CombinedUpdateRenderController::Stop()
232 {
233   LOG_EVENT_TRACE;
234
235   // Stop Rendering and the Update/Render Thread
236   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
237   if(currentSurface)
238   {
239     currentSurface->StopRender();
240   }
241
242   StopUpdateRenderThread();
243
244   if(mUpdateRenderThread)
245   {
246     LOG_EVENT("Destroying UpdateRenderThread");
247
248     // wait for the thread to finish
249     pthread_join(*mUpdateRenderThread, NULL);
250
251     delete mUpdateRenderThread;
252     mUpdateRenderThread = NULL;
253   }
254
255   mRunning = FALSE;
256
257   DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Stop\n");
258 }
259
260 void CombinedUpdateRenderController::RequestUpdate()
261 {
262   LOG_EVENT_TRACE;
263
264   // Increment the update-request count to the maximum
265   if(mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS)
266   {
267     ++mUpdateRequestCount;
268   }
269
270   if(mRunning && IsUpdateRenderThreadPaused())
271   {
272     LOG_EVENT("Processing");
273
274     RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
275   }
276
277   ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
278   mPendingRequestUpdate = TRUE;
279 }
280
281 void CombinedUpdateRenderController::RequestUpdateOnce(UpdateMode updateMode)
282 {
283   // Increment the update-request count to the maximum
284   if(mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS)
285   {
286     ++mUpdateRequestCount;
287   }
288
289   if(IsUpdateRenderThreadPaused() || updateMode == UpdateMode::FORCE_RENDER)
290   {
291     LOG_EVENT_TRACE;
292
293     // Run Update/Render once
294     RunUpdateRenderThread(ONCE, AnimationProgression::NONE, updateMode);
295   }
296 }
297
298 void CombinedUpdateRenderController::ReplaceSurface(Dali::RenderSurfaceInterface* newSurface)
299 {
300   LOG_EVENT_TRACE;
301
302   if(mUpdateRenderThread)
303   {
304     // Set the ThreadSyncronizationInterface on the new surface
305     newSurface->SetThreadSynchronization(*this);
306
307     LOG_EVENT("Starting to replace the surface, event-thread blocked");
308
309     // Start replacing the surface.
310     {
311       ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
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       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
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 unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
545   const bool         renderToFboEnabled  = 0u != renderToFboInterval;
546   unsigned int       frameCount          = 0u;
547
548   while(UpdateRenderReady(useElapsedTime, updateRequired, timeToSleepUntil))
549   {
550     LOG_UPDATE_RENDER_TRACE;
551
552     // For thread safe
553     bool         uploadOnly     = mUploadWithoutRendering;
554     unsigned int surfaceResized = mSurfaceResized;
555
556     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
557     AddPerformanceMarker(PerformanceInterface::VSYNC);
558
559     uint64_t currentFrameStartTime = 0;
560     TimeService::GetNanoseconds(currentFrameStartTime);
561
562     uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
563
564     // Optional FPS Tracking when continuously rendering
565     if(useElapsedTime && mFpsTracker.Enabled())
566     {
567       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
568       mFpsTracker.Track(absoluteTimeSinceLastRender);
569     }
570
571     lastFrameTime = currentFrameStartTime; // Store frame start time
572
573     //////////////////////////////
574     // REPLACE SURFACE
575     //////////////////////////////
576
577     Dali::RenderSurfaceInterface* newSurface = ShouldSurfaceBeReplaced();
578     if(DALI_UNLIKELY(newSurface))
579     {
580       LOG_UPDATE_RENDER_TRACE_FMT("Replacing Surface");
581       // This is designed for replacing pixmap surfaces, but should work for window as well
582       // we need to delete the surface and renderable (pixmap / window)
583       // Then create a new pixmap/window and new surface
584       // If the new surface has a different display connection, then the context will be lost
585       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
586       graphics.ActivateSurfaceContext(newSurface);
587       // TODO: ReplaceGraphicsSurface doesn't work, InitializeGraphics()
588       // already creates new surface window, the surface and the context.
589       // We probably don't need ReplaceGraphicsSurface at all.
590       // newSurface->ReplaceGraphicsSurface();
591       SurfaceReplaced();
592     }
593
594     const bool isRenderingToFbo = renderToFboEnabled && ((0u == frameCount) || (0u != frameCount % renderToFboInterval));
595     ++frameCount;
596
597     //////////////////////////////
598     // UPDATE
599     //////////////////////////////
600
601     const unsigned int currentTime   = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
602     const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
603
604     uint64_t noOfFramesSinceLastUpdate = 1;
605     float    frameDelta                = 0.0f;
606     if(useElapsedTime)
607     {
608       if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
609       {
610         extraFramesDropped = 0;
611         while(timeSinceLastFrame >= mDefaultFrameDurationNanoseconds)
612         {
613           timeSinceLastFrame -= mDefaultFrameDurationNanoseconds;
614           extraFramesDropped++;
615         }
616       }
617
618       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
619       noOfFramesSinceLastUpdate += extraFramesDropped;
620
621       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
622     }
623     LOG_UPDATE_RENDER("timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta);
624
625     Integration::UpdateStatus updateStatus;
626
627     AddPerformanceMarker(PerformanceInterface::UPDATE_START);
628     TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE");
629     mCore.Update(frameDelta,
630                  currentTime,
631                  nextFrameTime,
632                  updateStatus,
633                  renderToFboEnabled,
634                  isRenderingToFbo,
635                  uploadOnly);
636     TRACE_UPDATE_RENDER_END("DALI_UPDATE");
637     AddPerformanceMarker(PerformanceInterface::UPDATE_END);
638
639     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
640
641     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
642     if(updateStatus.NeedsNotification())
643     {
644       mNotificationTrigger.Trigger();
645       LOG_UPDATE_RENDER("Notification Triggered");
646     }
647
648     // Optional logging of update/render status
649     mUpdateStatusLogger.Log(keepUpdatingStatus);
650
651     //////////////////////////////
652     // RENDER
653     //////////////////////////////
654
655     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
656
657     if(mPreRenderCallback != NULL)
658     {
659       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
660       if(!keepCallback)
661       {
662         delete mPreRenderCallback;
663         mPreRenderCallback = NULL;
664       }
665     }
666
667     graphics.ActivateResourceContext();
668
669     if(mFirstFrameAfterResume)
670     {
671       // mFirstFrameAfterResume is set to true when the thread is resumed
672       // Let graphics know the first frame after thread initialized or resumed.
673       graphics.SetFirstFrameAfterResume();
674       mFirstFrameAfterResume = FALSE;
675     }
676
677     Integration::RenderStatus renderStatus;
678
679     AddPerformanceMarker(PerformanceInterface::RENDER_START);
680     TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER");
681
682     // Upload shared resources
683     mCore.PreRender(renderStatus, mForceClear);
684
685     if(!uploadOnly || surfaceResized)
686     {
687       // Go through each window
688       WindowContainer windows;
689       mAdaptorInterfaces.GetWindowContainerInterface(windows);
690
691       for(auto&& window : windows)
692       {
693         Dali::Integration::Scene      scene         = window->GetScene();
694         Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
695
696         if(scene && windowSurface)
697         {
698           Integration::RenderStatus windowRenderStatus;
699
700           const bool sceneSurfaceResized = scene.IsSurfaceRectChanged();
701
702           // clear previous frame damaged render items rects, buffer history is tracked on surface level
703           mDamagedRects.clear();
704
705           // Collect damage rects
706           mCore.PreRender(scene, mDamagedRects);
707
708           // Render off-screen frame buffers first if any
709           mCore.RenderScene(windowRenderStatus, scene, true);
710
711           Rect<int> clippingRect; // Empty for fbo rendering
712
713           // Switch to the context of the surface, merge damaged areas for previous frames
714           windowSurface->PreRender(sceneSurfaceResized, mDamagedRects, clippingRect); // Switch GL context
715
716           // Render the surface
717           mCore.RenderScene(windowRenderStatus, scene, false, clippingRect);
718
719           // Buffer swapping now happens when the surface render target is presented.
720
721           // If surface is resized, the surface resized count is decreased.
722           if(DALI_UNLIKELY(sceneSurfaceResized))
723           {
724             SurfaceResized();
725           }
726         }
727       }
728     }
729
730     if(!uploadOnly)
731     {
732       graphics.PostRender();
733     }
734
735     mCore.PostRender();
736
737     //////////////////////////////
738     // DELETE SURFACE
739     //////////////////////////////
740
741     Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
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()
920 {
921   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
922   if(mSurfaceResized)
923   {
924     mSurfaceResized--;
925   }
926 }
927
928 ///////////////////////////////////////////////////////////////////////////////////////////////////
929 // ALL THREADS
930 ///////////////////////////////////////////////////////////////////////////////////////////////////
931
932 void CombinedUpdateRenderController::NotifyThreadInitialised()
933 {
934   // Just increment the semaphore
935   mEventThreadSemaphore.Release(1);
936 }
937
938 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
939 {
940   mGraphicsInitializeWait.Notify();
941 }
942
943 void CombinedUpdateRenderController::AddPerformanceMarker(PerformanceInterface::MarkerType type)
944 {
945   if(mPerformanceInterface)
946   {
947     mPerformanceInterface->AddMarker(type);
948   }
949 }
950
951 /////////////////////////////////////////////////////////////////////////////////////////////////
952 // POST RENDERING: EVENT THREAD
953 /////////////////////////////////////////////////////////////////////////////////////////////////
954
955 void CombinedUpdateRenderController::PostRenderComplete()
956 {
957   ConditionalWait::ScopedLock lock(mPostRenderWaitCondition);
958   mPostRendering = FALSE;
959   mPostRenderWaitCondition.Notify(lock);
960 }
961
962 ///////////////////////////////////////////////////////////////////////////////////////////////////
963 // POST RENDERING: RENDER THREAD
964 ///////////////////////////////////////////////////////////////////////////////////////////////////
965
966 void CombinedUpdateRenderController::PostRenderStarted()
967 {
968   ConditionalWait::ScopedLock lock(mPostRenderWaitCondition);
969   mPostRendering = TRUE;
970 }
971
972 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
973 {
974   ConditionalWait::ScopedLock lock(mPostRenderWaitCondition);
975   while(mPostRendering &&
976         !mNewSurface &&     // We should NOT wait if we're replacing the surface
977         !mDeletedSurface && // We should NOT wait if we're deleting the surface
978         !mDestroyUpdateRenderThread)
979   {
980     mPostRenderWaitCondition.Wait(lock);
981   }
982 }
983
984 } // namespace Adaptor
985
986 } // namespace Internal
987
988 } // namespace Dali