Merge branch 'devel/master' into tizen
[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     TRACE_UPDATE_RENDER_BEGIN("DALI_PRE_RENDER");
706     mCore.PreRender(renderStatus, mForceClear);
707     TRACE_UPDATE_RENDER_END("DALI_PRE_RENDER");
708
709     if(!uploadOnly || surfaceResized)
710     {
711       // Go through each window
712       WindowContainer windows;
713       mAdaptorInterfaces.GetWindowContainerInterface(windows);
714
715       for(auto&& window : windows)
716       {
717         Dali::Integration::Scene      scene         = window->GetScene();
718         Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
719
720         if(scene && windowSurface)
721         {
722           TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER_SCENE");
723           Integration::RenderStatus windowRenderStatus;
724
725           const bool sceneSurfaceResized = scene.IsSurfaceRectChanged();
726
727           // clear previous frame damaged render items rects, buffer history is tracked on surface level
728           mDamagedRects.clear();
729
730           // Collect damage rects
731           mCore.PreRender(scene, mDamagedRects);
732
733           // Render off-screen frame buffers first if any
734           mCore.RenderScene(windowRenderStatus, scene, true);
735
736           Rect<int> clippingRect; // Empty for fbo rendering
737
738           // Switch to the context of the surface, merge damaged areas for previous frames
739           windowSurface->PreRender(sceneSurfaceResized, mDamagedRects, clippingRect); // Switch GL context
740
741           // Render the surface
742           mCore.RenderScene(windowRenderStatus, scene, false, clippingRect);
743
744           // Buffer swapping now happens when the surface render target is presented.
745
746           // If surface is resized, the surface resized count is decreased.
747           if(DALI_UNLIKELY(sceneSurfaceResized))
748           {
749             SurfaceResized();
750           }
751           TRACE_UPDATE_RENDER_END("DALI_RENDER_SCENE");
752         }
753       }
754     }
755
756     TRACE_UPDATE_RENDER_BEGIN("DALI_POST_RENDER");
757     if(!uploadOnly)
758     {
759       graphics.PostRender();
760     }
761
762     mCore.PostRender();
763     TRACE_UPDATE_RENDER_END("DALI_POST_RENDER");
764
765     //////////////////////////////
766     // DELETE SURFACE
767     //////////////////////////////
768     if(DALI_UNLIKELY(deletedSurface))
769     {
770       LOG_UPDATE_RENDER_TRACE_FMT("Deleting Surface");
771
772       deletedSurface->DestroySurface();
773
774       SurfaceDeleted();
775     }
776
777     TRACE_UPDATE_RENDER_END("DALI_RENDER");
778     AddPerformanceMarker(PerformanceInterface::RENDER_END);
779
780     // if the memory pool interval is set and has elapsed, log the graphics memory pools
781     if(0 < memPoolInterval && memPoolInterval < lastFrameTime - lastMemPoolLogTime)
782     {
783       lastMemPoolLogTime = lastFrameTime;
784       graphics.LogMemoryPools();
785     }
786
787     mForceClear = false;
788
789     // Trigger event thread to request Update/Render thread to sleep if update not required
790     if((Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus) && !renderStatus.NeedsUpdate())
791     {
792       mSleepTrigger->Trigger();
793       updateRequired = false;
794       LOG_UPDATE_RENDER("Sleep Triggered");
795     }
796     else
797     {
798       updateRequired = true;
799     }
800
801     //////////////////////////////
802     // FRAME TIME
803     //////////////////////////////
804
805     extraFramesDropped = 0;
806
807     if(timeToSleepUntil == 0)
808     {
809       // If this is the first frame after the thread is initialized or resumed, we
810       // use the actual time the current frame starts from to calculate the time to
811       // sleep until the next frame.
812       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
813     }
814     else
815     {
816       // Otherwise, always use the sleep-until time calculated in the last frame to
817       // calculate the time to sleep until the next frame. In this way, if there is
818       // any time gap between the current frame and the next frame, or if update or
819       // rendering in the current frame takes too much time so that the specified
820       // sleep-until time has already passed, it will try to keep the frames syncing
821       // by shortening the duration of the next frame.
822       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
823
824       // Check the current time at the end of the frame
825       uint64_t currentFrameEndTime = 0;
826       TimeService::GetNanoseconds(currentFrameEndTime);
827       while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
828       {
829         // We are more than one frame behind already, so just drop the next frames
830         // until the sleep-until time is later than the current time so that we can
831         // catch up.
832         timeToSleepUntil += mDefaultFrameDurationNanoseconds;
833         extraFramesDropped++;
834       }
835     }
836
837     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
838     if(0u == renderToFboInterval)
839     {
840       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
841       TimeService::SleepUntil(timeToSleepUntil);
842     }
843   }
844
845   // Inform core of context destruction
846   mCore.ContextDestroyed();
847
848   WindowContainer windows;
849   mAdaptorInterfaces.GetWindowContainerInterface(windows);
850
851   // Destroy surfaces
852   for(auto&& window : windows)
853   {
854     Dali::RenderSurfaceInterface* surface = window->GetSurface();
855     surface->DestroySurface();
856   }
857
858   graphics.Shutdown();
859
860   LOG_UPDATE_RENDER("THREAD DESTROYED");
861
862   // Uninstall the logging function
863   mEnvironmentOptions.UnInstallLogFunction();
864 }
865
866 bool CombinedUpdateRenderController::UpdateRenderReady(bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil)
867 {
868   useElapsedTime = true;
869
870   ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
871   while((!mUpdateRenderRunCount ||                                                      // Should try to wait if event-thread has paused the Update/Render thread
872          (mUpdateRenderThreadCanSleep && !updateRequired && !mPendingRequestUpdate)) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
873         !mDestroyUpdateRenderThread &&                                                  // Ensure we don't wait if the update-render-thread is supposed to be destroyed
874         !mNewSurface &&                                                                 // Ensure we don't wait if we need to replace the surface
875         !mDeletedSurface &&                                                             // Ensure we don't wait if we need to delete the surface
876         !mSurfaceResized)                                                               // Ensure we don't wait if we need to resize the surface
877   {
878     LOG_UPDATE_RENDER("WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount);
879     LOG_UPDATE_RENDER("      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
880     LOG_UPDATE_RENDER("      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread);
881     LOG_UPDATE_RENDER("      mNewSurface:                 %d", mNewSurface);
882     LOG_UPDATE_RENDER("      mDeletedSurface:             %d", mDeletedSurface);
883     LOG_UPDATE_RENDER("      mSurfaceResized:             %d", mSurfaceResized);
884
885     // Reset the time when the thread is waiting, so the sleep-until time for
886     // the first frame after resuming should be based on the actual start time
887     // of the first frame.
888     timeToSleepUntil = 0;
889
890     mUpdateRenderThreadWaitCondition.Wait(updateLock);
891
892     if(!mUseElapsedTimeAfterWait)
893     {
894       useElapsedTime = false;
895     }
896   }
897
898   LOG_COUNTER_UPDATE_RENDER("mUpdateRenderRunCount:       %d", mUpdateRenderRunCount);
899   LOG_COUNTER_UPDATE_RENDER("mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
900   LOG_COUNTER_UPDATE_RENDER("mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread);
901   LOG_COUNTER_UPDATE_RENDER("mNewSurface:                 %d", mNewSurface);
902   LOG_COUNTER_UPDATE_RENDER("mDeletedSurface:             %d", mDeletedSurface);
903   LOG_COUNTER_UPDATE_RENDER("mSurfaceResized:             %d", mSurfaceResized);
904
905   mUseElapsedTimeAfterWait    = FALSE;
906   mUpdateRenderThreadCanSleep = FALSE;
907   mPendingRequestUpdate       = FALSE;
908
909   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
910   // requested number of cycles
911   if(mUpdateRenderRunCount > 0)
912   {
913     --mUpdateRenderRunCount;
914   }
915
916   // Keep the update-render thread alive if this thread is NOT to be destroyed
917   return !mDestroyUpdateRenderThread;
918 }
919
920 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
921 {
922   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
923
924   Dali::RenderSurfaceInterface* newSurface = mNewSurface;
925   mNewSurface                              = NULL;
926
927   return newSurface;
928 }
929
930 void CombinedUpdateRenderController::SurfaceReplaced()
931 {
932   // Just increment the semaphore
933   mSurfaceSemaphore.Release(1);
934 }
935
936 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
937 {
938   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
939
940   Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
941   mDeletedSurface                              = NULL;
942
943   return deletedSurface;
944 }
945
946 void CombinedUpdateRenderController::SurfaceDeleted()
947 {
948   // Just increment the semaphore
949   mSurfaceSemaphore.Release(1);
950 }
951
952 void CombinedUpdateRenderController::SurfaceResized()
953 {
954   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
955   if(mSurfaceResized)
956   {
957     mSurfaceResized--;
958   }
959 }
960
961 ///////////////////////////////////////////////////////////////////////////////////////////////////
962 // ALL THREADS
963 ///////////////////////////////////////////////////////////////////////////////////////////////////
964
965 void CombinedUpdateRenderController::NotifyThreadInitialised()
966 {
967   // Just increment the semaphore
968   mEventThreadSemaphore.Release(1);
969 }
970
971 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
972 {
973   mGraphicsInitializeWait.Notify();
974 }
975
976 void CombinedUpdateRenderController::AddPerformanceMarker(PerformanceInterface::MarkerType type)
977 {
978   if(mPerformanceInterface)
979   {
980     mPerformanceInterface->AddMarker(type);
981   }
982 }
983
984 /////////////////////////////////////////////////////////////////////////////////////////////////
985 // POST RENDERING: EVENT THREAD
986 /////////////////////////////////////////////////////////////////////////////////////////////////
987
988 void CombinedUpdateRenderController::PostRenderComplete()
989 {
990   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
991   mPostRendering = FALSE;
992   mUpdateRenderThreadWaitCondition.Notify(lock);
993 }
994
995 ///////////////////////////////////////////////////////////////////////////////////////////////////
996 // POST RENDERING: RENDER THREAD
997 ///////////////////////////////////////////////////////////////////////////////////////////////////
998
999 void CombinedUpdateRenderController::PostRenderStarted()
1000 {
1001   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
1002   mPostRendering = TRUE;
1003 }
1004
1005 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
1006 {
1007   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
1008   while(mPostRendering &&
1009         !mNewSurface &&     // We should NOT wait if we're replacing the surface
1010         !mDeletedSurface && // We should NOT wait if we're deleting the surface
1011         !mDestroyUpdateRenderThread)
1012   {
1013     mUpdateRenderThreadWaitCondition.Wait(lock);
1014   }
1015 }
1016
1017 } // namespace Adaptor
1018
1019 } // namespace Internal
1020
1021 } // namespace Dali