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