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