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