Revert "[Tizen] Apply Precompile shader"
[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   TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER_THREAD_INIT");
517
518   LOG_UPDATE_RENDER("THREAD CREATED");
519
520   // Initialize graphics
521   GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
522   graphics.Initialize();
523
524   Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
525   displayConnection.Initialize(); //@todo Move InitializeGraphics code into graphics implementation
526
527   // Setup graphics controller into upload manager.
528   GetImplementation(mTextureUploadManager).InitalizeGraphicsController(graphics.GetController());
529
530   NotifyGraphicsInitialised();
531
532   //@todo Vk swaps this around, but we need to support surfaceless context for multi-window
533   graphics.ConfigureSurface(mAdaptorInterfaces.GetRenderSurfaceInterface());
534
535   // Tell core it has a context
536   mCore.ContextCreated();
537
538   NotifyThreadInitialised();
539
540   // Update time
541   uint64_t lastFrameTime;
542   TimeService::GetNanoseconds(lastFrameTime);
543   uint64_t lastMemPoolLogTime = lastFrameTime;
544
545   LOG_UPDATE_RENDER("THREAD INITIALISED");
546
547   bool     useElapsedTime     = true;
548   bool     updateRequired     = true;
549   uint64_t timeToSleepUntil   = 0;
550   int      extraFramesDropped = 0;
551
552   const uint64_t memPoolInterval = 1e9 * float(mEnvironmentOptions.GetMemoryPoolInterval());
553
554   const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
555   const bool         renderToFboEnabled  = 0u != renderToFboInterval;
556   unsigned int       frameCount          = 0u;
557
558   TRACE_UPDATE_RENDER_END("DALI_RENDER_THREAD_INIT");
559
560   while(UpdateRenderReady(useElapsedTime, updateRequired, timeToSleepUntil))
561   {
562     LOG_UPDATE_RENDER_TRACE;
563     TRACE_UPDATE_RENDER_SCOPE("DALI_UPDATE_RENDER");
564
565     // For thread safe
566     bool                          uploadOnly     = mUploadWithoutRendering;
567     unsigned int                  surfaceResized = mSurfaceResized;
568     Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
569
570     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
571     AddPerformanceMarker(PerformanceInterface::VSYNC);
572
573     uint64_t currentFrameStartTime = 0;
574     TimeService::GetNanoseconds(currentFrameStartTime);
575
576     uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
577
578     // Optional FPS Tracking when continuously rendering
579     if(useElapsedTime && mFpsTracker.Enabled())
580     {
581       float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
582       mFpsTracker.Track(absoluteTimeSinceLastRender);
583     }
584
585     lastFrameTime = currentFrameStartTime; // Store frame start time
586
587     //////////////////////////////
588     // REPLACE SURFACE
589     //////////////////////////////
590
591     Dali::RenderSurfaceInterface* newSurface = ShouldSurfaceBeReplaced();
592     if(DALI_UNLIKELY(newSurface))
593     {
594       LOG_UPDATE_RENDER_TRACE_FMT("Replacing Surface");
595       // This is designed for replacing pixmap surfaces, but should work for window as well
596       // we need to delete the surface and renderable (pixmap / window)
597       // Then create a new pixmap/window and new surface
598       // If the new surface has a different display connection, then the context will be lost
599       mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
600       graphics.ActivateSurfaceContext(newSurface);
601       // TODO: ReplaceGraphicsSurface doesn't work, InitializeGraphics()
602       // already creates new surface window, the surface and the context.
603       // We probably don't need ReplaceGraphicsSurface at all.
604       // newSurface->ReplaceGraphicsSurface();
605       SurfaceReplaced();
606     }
607
608     //////////////////////////////
609     // TextureUploadRequest (phase #1)
610     //////////////////////////////
611
612     // Upload requested resources after resource context activated.
613     graphics.ActivateResourceContext();
614
615     const bool textureUploaded = mTextureUploadManager.ResourceUpload();
616
617     // Update & Render forcely if there exist some uploaded texture.
618     uploadOnly = textureUploaded ? false : uploadOnly;
619
620     const bool isRenderingToFbo = renderToFboEnabled && ((0u == frameCount) || (0u != frameCount % renderToFboInterval));
621     ++frameCount;
622
623     //////////////////////////////
624     // UPDATE
625     //////////////////////////////
626
627     const uint32_t currentTime   = static_cast<uint32_t>(currentFrameStartTime / NANOSECONDS_PER_MILLISECOND);
628     const uint32_t nextFrameTime = currentTime + static_cast<uint32_t>(mDefaultFrameDurationMilliseconds);
629
630     uint64_t noOfFramesSinceLastUpdate = 1;
631     float    frameDelta                = 0.0f;
632     if(useElapsedTime)
633     {
634       if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
635       {
636         extraFramesDropped = 0;
637         while(timeSinceLastFrame >= mDefaultFrameDurationNanoseconds)
638         {
639           timeSinceLastFrame -= mDefaultFrameDurationNanoseconds;
640           extraFramesDropped++;
641         }
642       }
643
644       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
645       noOfFramesSinceLastUpdate += extraFramesDropped;
646
647       frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
648     }
649     LOG_UPDATE_RENDER("timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta);
650
651     Integration::UpdateStatus updateStatus;
652
653     AddPerformanceMarker(PerformanceInterface::UPDATE_START);
654     TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE");
655     mCore.Update(frameDelta,
656                  currentTime,
657                  nextFrameTime,
658                  updateStatus,
659                  renderToFboEnabled,
660                  isRenderingToFbo,
661                  uploadOnly);
662     TRACE_UPDATE_RENDER_END("DALI_UPDATE");
663     AddPerformanceMarker(PerformanceInterface::UPDATE_END);
664
665     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
666
667     // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
668     if(updateStatus.NeedsNotification())
669     {
670       mNotificationTrigger.Trigger();
671       LOG_UPDATE_RENDER("Notification Triggered");
672     }
673
674     // Optional logging of update/render status
675     mUpdateStatusLogger.Log(keepUpdatingStatus);
676
677     //////////////////////////////
678     // RENDER
679     //////////////////////////////
680
681     graphics.FrameStart();
682     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
683
684     if(mPreRenderCallback != NULL)
685     {
686       bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
687       if(!keepCallback)
688       {
689         delete mPreRenderCallback;
690         mPreRenderCallback = NULL;
691       }
692     }
693
694     //////////////////////////////
695     // TextureUploadRequest (phase #2)
696     //////////////////////////////
697
698     // Upload requested resources after resource context activated.
699     graphics.ActivateResourceContext();
700
701     // Since uploadOnly value used at Update side, we should not change uploadOnly value now even some textures are uploaded.
702     mTextureUploadManager.ResourceUpload();
703
704     if(mFirstFrameAfterResume)
705     {
706       // mFirstFrameAfterResume is set to true when the thread is resumed
707       // Let graphics know the first frame after thread initialized or resumed.
708       graphics.SetFirstFrameAfterResume();
709       mFirstFrameAfterResume = FALSE;
710     }
711
712     Integration::RenderStatus renderStatus;
713
714     AddPerformanceMarker(PerformanceInterface::RENDER_START);
715     TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER");
716
717     // Upload shared resources
718     TRACE_UPDATE_RENDER_BEGIN("DALI_PRE_RENDER");
719     mCore.PreRender(renderStatus, mForceClear);
720     TRACE_UPDATE_RENDER_END("DALI_PRE_RENDER");
721
722     if(!uploadOnly || surfaceResized)
723     {
724       // Go through each window
725       WindowContainer windows;
726       mAdaptorInterfaces.GetWindowContainerInterface(windows);
727
728       for(auto&& window : windows)
729       {
730         Dali::Integration::Scene      scene         = window->GetScene();
731         Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
732
733         if(scene && windowSurface)
734         {
735           TRACE_UPDATE_RENDER_SCOPE("DALI_RENDER_SCENE");
736           Integration::RenderStatus windowRenderStatus;
737
738           const bool sceneSurfaceResized = scene.IsSurfaceRectChanged();
739
740           // clear previous frame damaged render items rects, buffer history is tracked on surface level
741           mDamagedRects.clear();
742
743           // Collect damage rects
744           mCore.PreRender(scene, mDamagedRects);
745
746           // Render off-screen frame buffers first if any
747           mCore.RenderScene(windowRenderStatus, scene, true);
748
749           Rect<int> clippingRect; // Empty for fbo rendering
750
751           // Switch to the context of the surface, merge damaged areas for previous frames
752           windowSurface->PreRender(sceneSurfaceResized, mDamagedRects, clippingRect); // Switch GL context
753
754           // Render the surface
755           mCore.RenderScene(windowRenderStatus, scene, false, clippingRect);
756
757           // Buffer swapping now happens when the surface render target is presented.
758
759           // If surface is resized, the surface resized count is decreased.
760           if(DALI_UNLIKELY(sceneSurfaceResized))
761           {
762             SurfaceResized();
763           }
764         }
765       }
766     }
767
768     TRACE_UPDATE_RENDER_BEGIN("DALI_POST_RENDER");
769     if(!uploadOnly)
770     {
771       graphics.PostRender();
772     }
773
774     mCore.PostRender();
775     TRACE_UPDATE_RENDER_END("DALI_POST_RENDER");
776
777     //////////////////////////////
778     // DELETE SURFACE
779     //////////////////////////////
780     if(DALI_UNLIKELY(deletedSurface))
781     {
782       LOG_UPDATE_RENDER_TRACE_FMT("Deleting Surface");
783
784       deletedSurface->DestroySurface();
785
786       SurfaceDeleted();
787     }
788
789     TRACE_UPDATE_RENDER_END("DALI_RENDER");
790     AddPerformanceMarker(PerformanceInterface::RENDER_END);
791
792     // if the memory pool interval is set and has elapsed, log the graphics memory pools
793     if(0 < memPoolInterval && memPoolInterval < lastFrameTime - lastMemPoolLogTime)
794     {
795       lastMemPoolLogTime = lastFrameTime;
796       graphics.LogMemoryPools();
797     }
798
799     mForceClear = false;
800
801     // Trigger event thread to request Update/Render thread to sleep if update not required
802     if((Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus) && !renderStatus.NeedsUpdate())
803     {
804       mSleepTrigger->Trigger();
805       updateRequired = false;
806       LOG_UPDATE_RENDER("Sleep Triggered");
807     }
808     else
809     {
810       updateRequired = true;
811     }
812
813     //////////////////////////////
814     // FRAME TIME
815     //////////////////////////////
816
817     extraFramesDropped = 0;
818
819     if(timeToSleepUntil == 0)
820     {
821       // If this is the first frame after the thread is initialized or resumed, we
822       // use the actual time the current frame starts from to calculate the time to
823       // sleep until the next frame.
824       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
825     }
826     else
827     {
828       // Otherwise, always use the sleep-until time calculated in the last frame to
829       // calculate the time to sleep until the next frame. In this way, if there is
830       // any time gap between the current frame and the next frame, or if update or
831       // rendering in the current frame takes too much time so that the specified
832       // sleep-until time has already passed, it will try to keep the frames syncing
833       // by shortening the duration of the next frame.
834       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
835
836       // Check the current time at the end of the frame
837       uint64_t currentFrameEndTime = 0;
838       TimeService::GetNanoseconds(currentFrameEndTime);
839       while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
840       {
841         // We are more than one frame behind already, so just drop the next frames
842         // until the sleep-until time is later than the current time so that we can
843         // catch up.
844         timeToSleepUntil += mDefaultFrameDurationNanoseconds;
845         extraFramesDropped++;
846       }
847     }
848
849     // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
850     if(0u == renderToFboInterval)
851     {
852       TRACE_UPDATE_RENDER_SCOPE("DALI_UPDATE_RENDER_SLEEP");
853       // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
854       TimeService::SleepUntil(timeToSleepUntil);
855     }
856   }
857   TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER_THREAD_FINISH");
858
859   // Inform core of context destruction
860   mCore.ContextDestroyed();
861
862   WindowContainer windows;
863   mAdaptorInterfaces.GetWindowContainerInterface(windows);
864
865   // Destroy surfaces
866   for(auto&& window : windows)
867   {
868     Dali::RenderSurfaceInterface* surface = window->GetSurface();
869     surface->DestroySurface();
870   }
871
872   graphics.Shutdown();
873
874   LOG_UPDATE_RENDER("THREAD DESTROYED");
875
876   TRACE_UPDATE_RENDER_END("DALI_RENDER_THREAD_FINISH");
877
878   // Uninstall the logging function
879   mEnvironmentOptions.UnInstallLogFunction();
880 }
881
882 bool CombinedUpdateRenderController::UpdateRenderReady(bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil)
883 {
884   useElapsedTime = true;
885
886   ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
887   while((!mUpdateRenderRunCount ||                                                      // Should try to wait if event-thread has paused the Update/Render thread
888          (mUpdateRenderThreadCanSleep && !updateRequired && !mPendingRequestUpdate)) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
889         !mDestroyUpdateRenderThread &&                                                  // Ensure we don't wait if the update-render-thread is supposed to be destroyed
890         !mNewSurface &&                                                                 // Ensure we don't wait if we need to replace the surface
891         !mDeletedSurface &&                                                             // Ensure we don't wait if we need to delete the surface
892         !mSurfaceResized)                                                               // Ensure we don't wait if we need to resize the surface
893   {
894     LOG_UPDATE_RENDER("WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount);
895     LOG_UPDATE_RENDER("      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
896     LOG_UPDATE_RENDER("      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread);
897     LOG_UPDATE_RENDER("      mNewSurface:                 %d", mNewSurface);
898     LOG_UPDATE_RENDER("      mDeletedSurface:             %d", mDeletedSurface);
899     LOG_UPDATE_RENDER("      mSurfaceResized:             %d", mSurfaceResized);
900
901     // Reset the time when the thread is waiting, so the sleep-until time for
902     // the first frame after resuming should be based on the actual start time
903     // of the first frame.
904     timeToSleepUntil = 0;
905
906     TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE_RENDER_THREAD_WAIT_CONDITION");
907     mUpdateRenderThreadWaitCondition.Wait(updateLock);
908     TRACE_UPDATE_RENDER_END("DALI_UPDATE_RENDER_THREAD_WAIT_CONDITION");
909
910     if(!mUseElapsedTimeAfterWait)
911     {
912       useElapsedTime = false;
913     }
914   }
915
916   LOG_COUNTER_UPDATE_RENDER("mUpdateRenderRunCount:       %d", mUpdateRenderRunCount);
917   LOG_COUNTER_UPDATE_RENDER("mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
918   LOG_COUNTER_UPDATE_RENDER("mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread);
919   LOG_COUNTER_UPDATE_RENDER("mNewSurface:                 %d", mNewSurface);
920   LOG_COUNTER_UPDATE_RENDER("mDeletedSurface:             %d", mDeletedSurface);
921   LOG_COUNTER_UPDATE_RENDER("mSurfaceResized:             %d", mSurfaceResized);
922
923   mUseElapsedTimeAfterWait    = FALSE;
924   mUpdateRenderThreadCanSleep = FALSE;
925   mPendingRequestUpdate       = FALSE;
926
927   // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
928   // requested number of cycles
929   if(mUpdateRenderRunCount > 0)
930   {
931     --mUpdateRenderRunCount;
932   }
933
934   // Keep the update-render thread alive if this thread is NOT to be destroyed
935   return !mDestroyUpdateRenderThread;
936 }
937
938 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
939 {
940   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
941
942   Dali::RenderSurfaceInterface* newSurface = mNewSurface;
943   mNewSurface                              = NULL;
944
945   return newSurface;
946 }
947
948 void CombinedUpdateRenderController::SurfaceReplaced()
949 {
950   // Just increment the semaphore
951   mSurfaceSemaphore.Release(1);
952 }
953
954 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
955 {
956   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
957
958   Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
959   mDeletedSurface                              = NULL;
960
961   return deletedSurface;
962 }
963
964 void CombinedUpdateRenderController::SurfaceDeleted()
965 {
966   // Just increment the semaphore
967   mSurfaceSemaphore.Release(1);
968 }
969
970 void CombinedUpdateRenderController::SurfaceResized()
971 {
972   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
973   if(mSurfaceResized)
974   {
975     mSurfaceResized--;
976   }
977 }
978
979 ///////////////////////////////////////////////////////////////////////////////////////////////////
980 // ALL THREADS
981 ///////////////////////////////////////////////////////////////////////////////////////////////////
982
983 void CombinedUpdateRenderController::NotifyThreadInitialised()
984 {
985   // Just increment the semaphore
986   mEventThreadSemaphore.Release(1);
987 }
988
989 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
990 {
991   mGraphicsInitializeWait.Notify();
992 }
993
994 void CombinedUpdateRenderController::AddPerformanceMarker(PerformanceInterface::MarkerType type)
995 {
996   if(mPerformanceInterface)
997   {
998     mPerformanceInterface->AddMarker(type);
999   }
1000 }
1001
1002 /////////////////////////////////////////////////////////////////////////////////////////////////
1003 // POST RENDERING: EVENT THREAD
1004 /////////////////////////////////////////////////////////////////////////////////////////////////
1005
1006 void CombinedUpdateRenderController::PostRenderComplete()
1007 {
1008   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
1009   mPostRendering = FALSE;
1010   mUpdateRenderThreadWaitCondition.Notify(lock);
1011 }
1012
1013 ///////////////////////////////////////////////////////////////////////////////////////////////////
1014 // POST RENDERING: RENDER THREAD
1015 ///////////////////////////////////////////////////////////////////////////////////////////////////
1016
1017 void CombinedUpdateRenderController::PostRenderStarted()
1018 {
1019   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
1020   mPostRendering = TRUE;
1021 }
1022
1023 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
1024 {
1025   ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
1026   while(mPostRendering &&
1027         !mNewSurface &&     // We should NOT wait if we're replacing the surface
1028         !mDeletedSurface && // We should NOT wait if we're deleting the surface
1029         !mDestroyUpdateRenderThread)
1030   {
1031     mUpdateRenderThreadWaitCondition.Wait(lock);
1032   }
1033 }
1034
1035 } // namespace Adaptor
1036
1037 } // namespace Internal
1038
1039 } // namespace Dali