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