Add GetRenderThreadId()
[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/integration-api/adaptor-framework/trigger-event-factory.h>
29 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
30 #include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
31 #include <dali/internal/graphics/common/graphics-interface.h>
32 #include <dali/internal/graphics/gles/egl-graphics.h>
33 #include <dali/internal/system/common/environment-options.h>
34 #include <dali/internal/system/common/time-service.h>
35 #include <dali/internal/thread/common/thread-settings-impl.h>
36 #include <dali/internal/window-system/common/window-impl.h>
37
38 namespace Dali
39 {
40 namespace Internal
41 {
42 namespace Adaptor
43 {
44 namespace
45 {
46 const unsigned int CREATED_THREAD_COUNT = 1u;
47
48 const int CONTINUOUS = -1;
49 const int ONCE       = 1;
50
51 const unsigned int TRUE  = 1u;
52 const unsigned int FALSE = 0u;
53
54 const unsigned int MILLISECONDS_PER_SECOND(1e+3);
55 const float        NANOSECONDS_TO_SECOND(1e-9f);
56 const unsigned int NANOSECONDS_PER_SECOND(1e+9);
57 const unsigned int NANOSECONDS_PER_MILLISECOND(1e+6);
58
59 // The following values will get calculated at compile time
60 const float    DEFAULT_FRAME_DURATION_IN_SECONDS(1.0f / 60.0f);
61 const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* MILLISECONDS_PER_SECOND);
62 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* NANOSECONDS_PER_SECOND);
63
64 /**
65  * Handles the use case when an update-request is received JUST before we process a sleep-request. If we did not have an update-request count then
66  * there is a danger that, on the event-thread we could have:
67  *  1) An update-request where we do nothing as Update/Render thread still running.
68  *  2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
69  *
70  * Using a counter means we increment the counter on an update-request, and decrement it on a sleep-request. This handles the above scenario because:
71  *  1) MAIN THREAD:           Update Request: COUNTER = 1
72  *  2) UPDATE/RENDER THREAD:  Do Update/Render, then no Updates required -> Sleep Trigger
73  *  3) MAIN THREAD:           Update Request: COUNTER = 2
74  *  4) MAIN THREAD:           Sleep Request:  COUNTER = 1 -> We do not sleep just yet
75  *
76  * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
77  *  1) MAIN THREAD:           Update Request: COUNTER = 1
78  *  2) UPDATE/RENDER THREAD:  Do Update/Render, then no Updates required -> Sleep Trigger
79  *  3) MAIN THREAD:           Sleep Request:  COUNTER = 0 -> Go to sleep
80  */
81 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
82 } // unnamed namespace
83
84 ///////////////////////////////////////////////////////////////////////////////////////////////////
85 // EVENT THREAD
86 ///////////////////////////////////////////////////////////////////////////////////////////////////
87
88 CombinedUpdateRenderController::CombinedUpdateRenderController(AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions, ThreadMode threadMode)
89 : mFpsTracker(environmentOptions),
90   mUpdateStatusLogger(environmentOptions),
91   mEventThreadSemaphore(0),
92   mSurfaceSemaphore(0),
93   mUpdateRenderThreadWaitCondition(),
94   mAdaptorInterfaces(adaptorInterfaces),
95   mPerformanceInterface(adaptorInterfaces.GetPerformanceInterface()),
96   mCore(adaptorInterfaces.GetCore()),
97   mEnvironmentOptions(environmentOptions),
98   mNotificationTrigger(adaptorInterfaces.GetProcessCoreEventsTrigger()),
99   mSleepTrigger(NULL),
100   mPreRenderCallback(NULL),
101   mUpdateRenderThread(NULL),
102   mDefaultFrameDelta(0.0f),
103   mDefaultFrameDurationMilliseconds(0u),
104   mDefaultFrameDurationNanoseconds(0u),
105   mDefaultHalfFrameNanoseconds(0u),
106   mUpdateRequestCount(0u),
107   mRunning(FALSE),
108   mThreadId(0),
109   mThreadMode(threadMode),
110   mUpdateRenderRunCount(0),
111   mDestroyUpdateRenderThread(FALSE),
112   mUpdateRenderThreadCanSleep(FALSE),
113   mPendingRequestUpdate(FALSE),
114   mUseElapsedTimeAfterWait(FALSE),
115   mNewSurface(NULL),
116   mDeletedSurface(nullptr),
117   mPostRendering(FALSE),
118   mSurfaceResized(0),
119   mForceClear(FALSE),
120   mUploadWithoutRendering(FALSE),
121   mFirstFrameAfterResume(FALSE)
122 {
123   LOG_EVENT_TRACE;
124
125   // Initialise frame delta/duration variables first
126   SetRenderRefreshRate(environmentOptions.GetRenderRefreshRate());
127
128   // Set the thread-synchronization interface on the render-surface
129   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
130   if(currentSurface)
131   {
132     currentSurface->SetThreadSynchronization(*this);
133   }
134
135   mSleepTrigger = TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &CombinedUpdateRenderController::ProcessSleepRequest), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
136 }
137
138 CombinedUpdateRenderController::~CombinedUpdateRenderController()
139 {
140   LOG_EVENT_TRACE;
141
142   Stop();
143
144   delete mPreRenderCallback;
145   delete mSleepTrigger;
146 }
147
148 void CombinedUpdateRenderController::Initialize()
149 {
150   LOG_EVENT_TRACE;
151
152   // Ensure Update/Render Thread not already created
153   DALI_ASSERT_ALWAYS(!mUpdateRenderThread);
154
155   // Create Update/Render Thread
156   ConditionalWait::ScopedLock lock(mGraphicsInitializeWait);
157   mUpdateRenderThread = new pthread_t();
158   int error           = pthread_create(mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this);
159   DALI_ASSERT_ALWAYS(!error && "Return code from pthread_create() when creating UpdateRenderThread");
160
161   // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called
162   // When this function returns, the application initialisation on the event thread should occur
163 }
164
165 void CombinedUpdateRenderController::Start()
166 {
167   LOG_EVENT_TRACE;
168
169   DALI_ASSERT_ALWAYS(!mRunning && mUpdateRenderThread);
170
171   // Wait until all threads created in Initialise are up and running
172   for(unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i)
173   {
174     mEventThreadSemaphore.Acquire();
175   }
176
177   mRunning = TRUE;
178
179   LOG_EVENT("Startup Complete, starting Update/Render Thread");
180
181   RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
182
183   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
184   if(currentSurface)
185   {
186     currentSurface->StartRender();
187   }
188
189   DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Start\n");
190 }
191
192 void CombinedUpdateRenderController::Pause()
193 {
194   LOG_EVENT_TRACE;
195
196   mRunning = FALSE;
197
198   PauseUpdateRenderThread();
199
200   AddPerformanceMarker(PerformanceInterface::PAUSED);
201
202   DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Pause\n");
203 }
204
205 void CombinedUpdateRenderController::Resume()
206 {
207   LOG_EVENT_TRACE;
208
209   if(!mRunning && IsUpdateRenderThreadPaused())
210   {
211     LOG_EVENT("Resuming");
212
213     RunUpdateRenderThread(CONTINUOUS, AnimationProgression::USE_ELAPSED_TIME, UpdateMode::NORMAL);
214
215     AddPerformanceMarker(PerformanceInterface::RESUME);
216
217     mRunning               = TRUE;
218     mForceClear            = TRUE;
219     mFirstFrameAfterResume = TRUE;
220
221     DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Resume\n");
222   }
223   else
224   {
225     DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Resume: Already resumed [%d, %d, %d]\n", mRunning, mUpdateRenderRunCount, mUpdateRenderThreadCanSleep);
226   }
227 }
228
229 void CombinedUpdateRenderController::Stop()
230 {
231   LOG_EVENT_TRACE;
232
233   // Stop Rendering and the Update/Render Thread
234   Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
235   if(currentSurface)
236   {
237     currentSurface->StopRender();
238   }
239
240   StopUpdateRenderThread();
241
242   if(mUpdateRenderThread)
243   {
244     LOG_EVENT("Destroying UpdateRenderThread");
245
246     // wait for the thread to finish
247     pthread_join(*mUpdateRenderThread, NULL);
248
249     delete mUpdateRenderThread;
250     mUpdateRenderThread = NULL;
251   }
252
253   mRunning = FALSE;
254
255   DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Stop\n");
256 }
257
258 void CombinedUpdateRenderController::RequestUpdate()
259 {
260   LOG_EVENT_TRACE;
261
262   // Increment the update-request count to the maximum
263   if(mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS)
264   {
265     ++mUpdateRequestCount;
266   }
267
268   if(mRunning && IsUpdateRenderThreadPaused())
269   {
270     LOG_EVENT("Processing");
271
272     RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
273   }
274
275   ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
276   mPendingRequestUpdate = TRUE;
277 }
278
279 void CombinedUpdateRenderController::RequestUpdateOnce(UpdateMode updateMode)
280 {
281   // Increment the update-request count to the maximum
282   if(mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS)
283   {
284     ++mUpdateRequestCount;
285   }
286
287   if(IsUpdateRenderThreadPaused() || updateMode == UpdateMode::FORCE_RENDER)
288   {
289     LOG_EVENT_TRACE;
290
291     // Run Update/Render once
292     RunUpdateRenderThread(ONCE, AnimationProgression::NONE, updateMode);
293   }
294 }
295
296 void CombinedUpdateRenderController::ReplaceSurface(Dali::RenderSurfaceInterface* newSurface)
297 {
298   LOG_EVENT_TRACE;
299
300   if(mUpdateRenderThread)
301   {
302     // Set the ThreadSyncronizationInterface on the new surface
303     newSurface->SetThreadSynchronization(*this);
304
305     LOG_EVENT("Starting to replace the surface, event-thread blocked");
306
307     // Start replacing the surface.
308     {
309       ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
310       mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
311       mNewSurface    = newSurface;
312       mUpdateRenderThreadWaitCondition.Notify(lock);
313     }
314
315     // Wait until the surface has been replaced
316     mSurfaceSemaphore.Acquire();
317
318     LOG_EVENT("Surface replaced, event-thread continuing");
319   }
320 }
321
322 void CombinedUpdateRenderController::DeleteSurface(Dali::RenderSurfaceInterface* surface)
323 {
324   LOG_EVENT_TRACE;
325
326   if(mUpdateRenderThread)
327   {
328     LOG_EVENT("Starting to delete the surface, event-thread blocked");
329
330     // Start replacing the surface.
331     {
332       ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
333       mPostRendering  = FALSE; // Clear the post-rendering flag as Update/Render thread will delete the surface now
334       mDeletedSurface = surface;
335       mUpdateRenderThreadWaitCondition.Notify(lock);
336     }
337
338     // Wait until the surface has been deleted
339     mSurfaceSemaphore.Acquire();
340
341     LOG_EVENT("Surface deleted, event-thread continuing");
342   }
343 }
344
345 void CombinedUpdateRenderController::WaitForGraphicsInitialization()
346 {
347   ConditionalWait::ScopedLock lk(mGraphicsInitializeWait);
348   LOG_EVENT_TRACE;
349
350   if(mUpdateRenderThread)
351   {
352     LOG_EVENT("Waiting for graphics initialisation, event-thread blocked");
353
354     // Wait until the graphics has been initialised
355     mGraphicsInitializeWait.Wait(lk);
356
357     LOG_EVENT("graphics initialised, event-thread continuing");
358   }
359 }
360
361 void CombinedUpdateRenderController::ResizeSurface()
362 {
363   LOG_EVENT_TRACE;
364
365   LOG_EVENT("Resize the surface");
366
367   {
368     ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
369     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 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   uint64_t lastMemPoolLogTime = lastFrameTime;
538
539   LOG_UPDATE_RENDER("THREAD INITIALISED");
540
541   bool     useElapsedTime     = true;
542   bool     updateRequired     = true;
543   uint64_t timeToSleepUntil   = 0;
544   int      extraFramesDropped = 0;
545
546   const uint64_t memPoolInterval = 1e9 * float(mEnvironmentOptions.GetMemoryPoolInterval());
547
548   const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
549   const bool         renderToFboEnabled  = 0u != renderToFboInterval;
550   unsigned int       frameCount          = 0u;
551
552   while(UpdateRenderReady(useElapsedTime, updateRequired, timeToSleepUntil))
553   {
554     LOG_UPDATE_RENDER_TRACE;
555
556     // For thread safe
557     bool         uploadOnly     = mUploadWithoutRendering;
558     unsigned int surfaceResized = mSurfaceResized;
559
560     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
561     AddPerformanceMarker(PerformanceInterface::VSYNC);
562
563     uint64_t currentFrameStartTime = 0;
564     TimeService::GetNanoseconds(currentFrameStartTime);
565
566     uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
567
568     // Optional FPS Tracking when continuously rendering
569     if(useElapsedTime && mFpsTracker.Enabled())
570     {
571       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
572       mFpsTracker.Track(absoluteTimeSinceLastRender);
573     }
574
575     lastFrameTime = currentFrameStartTime; // Store frame start time
576
577     //////////////////////////////
578     // REPLACE SURFACE
579     //////////////////////////////
580
581     Dali::RenderSurfaceInterface* newSurface = ShouldSurfaceBeReplaced();
582     if(DALI_UNLIKELY(newSurface))
583     {
584       LOG_UPDATE_RENDER_TRACE_FMT("Replacing Surface");
585       // This is designed for replacing pixmap surfaces, but should work for window as well
586       // we need to delete the surface and renderable (pixmap / window)
587       // Then create a new pixmap/window and new surface
588       // If the new surface has a different display connection, then the context will be lost
589       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
590       graphics.ActivateSurfaceContext(newSurface);
591       // TODO: ReplaceGraphicsSurface doesn't work, InitializeGraphics()
592       // already creates new surface window, the surface and the context.
593       // We probably don't need ReplaceGraphicsSurface at all.
594       // newSurface->ReplaceGraphicsSurface();
595       SurfaceReplaced();
596     }
597
598     const bool isRenderingToFbo = renderToFboEnabled && ((0u == frameCount) || (0u != frameCount % renderToFboInterval));
599     ++frameCount;
600
601     //////////////////////////////
602     // UPDATE
603     //////////////////////////////
604
605     const uint32_t currentTime   = static_cast<uint32_t>(currentFrameStartTime / NANOSECONDS_PER_MILLISECOND);
606     const uint32_t nextFrameTime = currentTime + static_cast<uint32_t>(mDefaultFrameDurationMilliseconds);
607
608     uint64_t noOfFramesSinceLastUpdate = 1;
609     float    frameDelta                = 0.0f;
610     if(useElapsedTime)
611     {
612       if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
613       {
614         extraFramesDropped = 0;
615         while(timeSinceLastFrame >= mDefaultFrameDurationNanoseconds)
616         {
617           timeSinceLastFrame -= mDefaultFrameDurationNanoseconds;
618           extraFramesDropped++;
619         }
620       }
621
622       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
623       noOfFramesSinceLastUpdate += extraFramesDropped;
624
625       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
626     }
627     LOG_UPDATE_RENDER("timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta);
628
629     Integration::UpdateStatus updateStatus;
630
631     AddPerformanceMarker(PerformanceInterface::UPDATE_START);
632     TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE");
633     mCore.Update(frameDelta,
634                  currentTime,
635                  nextFrameTime,
636                  updateStatus,
637                  renderToFboEnabled,
638                  isRenderingToFbo,
639                  uploadOnly);
640     TRACE_UPDATE_RENDER_END("DALI_UPDATE");
641     AddPerformanceMarker(PerformanceInterface::UPDATE_END);
642
643     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
644
645     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
646     if(updateStatus.NeedsNotification())
647     {
648       mNotificationTrigger.Trigger();
649       LOG_UPDATE_RENDER("Notification Triggered");
650     }
651
652     // Optional logging of update/render status
653     mUpdateStatusLogger.Log(keepUpdatingStatus);
654
655     //////////////////////////////
656     // RENDER
657     //////////////////////////////
658
659     graphics.FrameStart();
660     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
661
662     if(mPreRenderCallback != NULL)
663     {
664       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
665       if(!keepCallback)
666       {
667         delete mPreRenderCallback;
668         mPreRenderCallback = NULL;
669       }
670     }
671
672     graphics.ActivateResourceContext();
673
674     if(mFirstFrameAfterResume)
675     {
676       // mFirstFrameAfterResume is set to true when the thread is resumed
677       // Let graphics know the first frame after thread initialized or resumed.
678       graphics.SetFirstFrameAfterResume();
679       mFirstFrameAfterResume = FALSE;
680     }
681
682     Integration::RenderStatus renderStatus;
683
684     AddPerformanceMarker(PerformanceInterface::RENDER_START);
685     TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER");
686
687     // Upload shared resources
688     mCore.PreRender(renderStatus, mForceClear);
689
690     if(!uploadOnly || surfaceResized)
691     {
692       // Go through each window
693       WindowContainer windows;
694       mAdaptorInterfaces.GetWindowContainerInterface(windows);
695
696       for(auto&& window : windows)
697       {
698         Dali::Integration::Scene      scene         = window->GetScene();
699         Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
700
701         if(scene && windowSurface)
702         {
703           Integration::RenderStatus windowRenderStatus;
704
705           const bool sceneSurfaceResized = scene.IsSurfaceRectChanged();
706
707           // clear previous frame damaged render items rects, buffer history is tracked on surface level
708           mDamagedRects.clear();
709
710           // Collect damage rects
711           mCore.PreRender(scene, mDamagedRects);
712
713           // Render off-screen frame buffers first if any
714           mCore.RenderScene(windowRenderStatus, scene, true);
715
716           Rect<int> clippingRect; // Empty for fbo rendering
717
718           // Switch to the context of the surface, merge damaged areas for previous frames
719           windowSurface->PreRender(sceneSurfaceResized, mDamagedRects, clippingRect); // Switch GL context
720
721           // Render the surface
722           mCore.RenderScene(windowRenderStatus, scene, false, clippingRect);
723
724           // Buffer swapping now happens when the surface render target is presented.
725
726           // If surface is resized, the surface resized count is decreased.
727           if(DALI_UNLIKELY(sceneSurfaceResized))
728           {
729             SurfaceResized();
730           }
731         }
732       }
733     }
734
735     if(!uploadOnly)
736     {
737       graphics.PostRender();
738     }
739
740     mCore.PostRender();
741
742     //////////////////////////////
743     // DELETE SURFACE
744     //////////////////////////////
745
746     Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
747     if(DALI_UNLIKELY(deletedSurface))
748     {
749       LOG_UPDATE_RENDER_TRACE_FMT("Deleting Surface");
750
751       deletedSurface->DestroySurface();
752
753       SurfaceDeleted();
754     }
755
756     TRACE_UPDATE_RENDER_END("DALI_RENDER");
757     AddPerformanceMarker(PerformanceInterface::RENDER_END);
758
759     // if the memory pool interval is set and has elapsed, log the graphics memory pools
760     if(0 < memPoolInterval && memPoolInterval < lastFrameTime - lastMemPoolLogTime)
761     {
762       lastMemPoolLogTime = lastFrameTime;
763       graphics.LogMemoryPools();
764     }
765
766     mForceClear = false;
767
768     // Trigger event thread to request Update/Render thread to sleep if update not required
769     if((Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus) && !renderStatus.NeedsUpdate())
770     {
771       mSleepTrigger->Trigger();
772       updateRequired = false;
773       LOG_UPDATE_RENDER("Sleep Triggered");
774     }
775     else
776     {
777       updateRequired = true;
778     }
779
780     //////////////////////////////
781     // FRAME TIME
782     //////////////////////////////
783
784     extraFramesDropped = 0;
785
786     if(timeToSleepUntil == 0)
787     {
788       // If this is the first frame after the thread is initialized or resumed, we
789       // use the actual time the current frame starts from to calculate the time to
790       // sleep until the next frame.
791       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
792     }
793     else
794     {
795       // Otherwise, always use the sleep-until time calculated in the last frame to
796       // calculate the time to sleep until the next frame. In this way, if there is
797       // any time gap between the current frame and the next frame, or if update or
798       // rendering in the current frame takes too much time so that the specified
799       // sleep-until time has already passed, it will try to keep the frames syncing
800       // by shortening the duration of the next frame.
801       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
802
803       // Check the current time at the end of the frame
804       uint64_t currentFrameEndTime = 0;
805       TimeService::GetNanoseconds(currentFrameEndTime);
806       while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
807       {
808         // We are more than one frame behind already, so just drop the next frames
809         // until the sleep-until time is later than the current time so that we can
810         // catch up.
811         timeToSleepUntil += mDefaultFrameDurationNanoseconds;
812         extraFramesDropped++;
813       }
814     }
815
816     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
817     if(0u == renderToFboInterval)
818     {
819       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
820       TimeService::SleepUntil(timeToSleepUntil);
821     }
822   }
823
824   // Inform core of context destruction
825   mCore.ContextDestroyed();
826
827   WindowContainer windows;
828   mAdaptorInterfaces.GetWindowContainerInterface(windows);
829
830   // Destroy surfaces
831   for(auto&& window : windows)
832   {
833     Dali::RenderSurfaceInterface* surface = window->GetSurface();
834     surface->DestroySurface();
835   }
836
837   graphics.Shutdown();
838
839   LOG_UPDATE_RENDER("THREAD DESTROYED");
840
841   // Uninstall the logging function
842   mEnvironmentOptions.UnInstallLogFunction();
843 }
844
845 bool CombinedUpdateRenderController::UpdateRenderReady(bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil)
846 {
847   useElapsedTime = true;
848
849   ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
850   while((!mUpdateRenderRunCount ||                                                      // Should try to wait if event-thread has paused the Update/Render thread
851          (mUpdateRenderThreadCanSleep && !updateRequired && !mPendingRequestUpdate)) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
852         !mDestroyUpdateRenderThread &&                                                  // Ensure we don't wait if the update-render-thread is supposed to be destroyed
853         !mNewSurface &&                                                                 // Ensure we don't wait if we need to replace the surface
854         !mDeletedSurface &&                                                             // Ensure we don't wait if we need to delete the surface
855         !mSurfaceResized)                                                               // Ensure we don't wait if we need to resize the surface
856   {
857     LOG_UPDATE_RENDER("WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount);
858     LOG_UPDATE_RENDER("      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
859     LOG_UPDATE_RENDER("      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread);
860     LOG_UPDATE_RENDER("      mNewSurface:                 %d", mNewSurface);
861     LOG_UPDATE_RENDER("      mDeletedSurface:             %d", mDeletedSurface);
862     LOG_UPDATE_RENDER("      mSurfaceResized:             %d", mSurfaceResized);
863
864     // Reset the time when the thread is waiting, so the sleep-until time for
865     // the first frame after resuming should be based on the actual start time
866     // of the first frame.
867     timeToSleepUntil = 0;
868
869     mUpdateRenderThreadWaitCondition.Wait(updateLock);
870
871     if(!mUseElapsedTimeAfterWait)
872     {
873       useElapsedTime = false;
874     }
875   }
876
877   LOG_COUNTER_UPDATE_RENDER("mUpdateRenderRunCount:       %d", mUpdateRenderRunCount);
878   LOG_COUNTER_UPDATE_RENDER("mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
879   LOG_COUNTER_UPDATE_RENDER("mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread);
880   LOG_COUNTER_UPDATE_RENDER("mNewSurface:                 %d", mNewSurface);
881   LOG_COUNTER_UPDATE_RENDER("mDeletedSurface:             %d", mDeletedSurface);
882   LOG_COUNTER_UPDATE_RENDER("mSurfaceResized:             %d", mSurfaceResized);
883
884   mUseElapsedTimeAfterWait    = FALSE;
885   mUpdateRenderThreadCanSleep = FALSE;
886   mPendingRequestUpdate       = FALSE;
887
888   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
889   // requested number of cycles
890   if(mUpdateRenderRunCount > 0)
891   {
892     --mUpdateRenderRunCount;
893   }
894
895   // Keep the update-render thread alive if this thread is NOT to be destroyed
896   return !mDestroyUpdateRenderThread;
897 }
898
899 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
900 {
901   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
902
903   Dali::RenderSurfaceInterface* newSurface = mNewSurface;
904   mNewSurface                              = NULL;
905
906   return newSurface;
907 }
908
909 void CombinedUpdateRenderController::SurfaceReplaced()
910 {
911   // Just increment the semaphore
912   mSurfaceSemaphore.Release(1);
913 }
914
915 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
916 {
917   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
918
919   Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
920   mDeletedSurface                              = NULL;
921
922   return deletedSurface;
923 }
924
925 void CombinedUpdateRenderController::SurfaceDeleted()
926 {
927   // Just increment the semaphore
928   mSurfaceSemaphore.Release(1);
929 }
930
931 void CombinedUpdateRenderController::SurfaceResized()
932 {
933   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
934   if(mSurfaceResized)
935   {
936     mSurfaceResized--;
937   }
938 }
939
940 ///////////////////////////////////////////////////////////////////////////////////////////////////
941 // ALL THREADS
942 ///////////////////////////////////////////////////////////////////////////////////////////////////
943
944 void CombinedUpdateRenderController::NotifyThreadInitialised()
945 {
946   // Just increment the semaphore
947   mEventThreadSemaphore.Release(1);
948 }
949
950 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
951 {
952   mGraphicsInitializeWait.Notify();
953 }
954
955 void CombinedUpdateRenderController::AddPerformanceMarker(PerformanceInterface::MarkerType type)
956 {
957   if(mPerformanceInterface)
958   {
959     mPerformanceInterface->AddMarker(type);
960   }
961 }
962
963 /////////////////////////////////////////////////////////////////////////////////////////////////
964 // POST RENDERING: EVENT THREAD
965 /////////////////////////////////////////////////////////////////////////////////////////////////
966
967 void CombinedUpdateRenderController::PostRenderComplete()
968 {
969   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
970   mPostRendering = FALSE;
971   mUpdateRenderThreadWaitCondition.Notify(lock);
972 }
973
974 ///////////////////////////////////////////////////////////////////////////////////////////////////
975 // POST RENDERING: RENDER THREAD
976 ///////////////////////////////////////////////////////////////////////////////////////////////////
977
978 void CombinedUpdateRenderController::PostRenderStarted()
979 {
980   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
981   mPostRendering = TRUE;
982 }
983
984 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
985 {
986   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
987   while(mPostRendering &&
988         !mNewSurface &&     // We should NOT wait if we're replacing the surface
989         !mDeletedSurface && // We should NOT wait if we're deleting the surface
990         !mDestroyUpdateRenderThread)
991   {
992     mUpdateRenderThreadWaitCondition.Wait(lock);
993   }
994 }
995
996 } // namespace Adaptor
997
998 } // namespace Internal
999
1000 } // namespace Dali