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