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