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