2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/adaptor/common/combined-update-render-controller.h>
22 #include <dali/integration-api/platform-abstraction.h>
25 #include "dali/public-api/common/dali-common.h"
28 #include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
29 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
30 #include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
31 #include <dali/internal/graphics/common/graphics-interface.h>
32 #include <dali/internal/graphics/gles/egl-graphics.h>
33 #include <dali/internal/system/common/environment-options.h>
34 #include <dali/internal/system/common/time-service.h>
35 #include <dali/internal/thread/common/thread-settings-impl.h>
36 #include <dali/internal/window-system/common/window-impl.h>
46 const unsigned int CREATED_THREAD_COUNT = 1u;
48 const int CONTINUOUS = -1;
51 const unsigned int TRUE = 1u;
52 const unsigned int FALSE = 0u;
54 const unsigned int MILLISECONDS_PER_SECOND(1e+3);
55 const float NANOSECONDS_TO_SECOND(1e-9f);
56 const unsigned int NANOSECONDS_PER_SECOND(1e+9);
57 const unsigned int NANOSECONDS_PER_MILLISECOND(1e+6);
59 // The following values will get calculated at compile time
60 const float DEFAULT_FRAME_DURATION_IN_SECONDS(1.0f / 60.0f);
61 const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* MILLISECONDS_PER_SECOND);
62 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* NANOSECONDS_PER_SECOND);
65 * 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
66 * there is a danger that, on the event-thread we could have:
67 * 1) An update-request where we do nothing as Update/Render thread still running.
68 * 2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
70 * 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:
71 * 1) MAIN THREAD: Update Request: COUNTER = 1
72 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
73 * 3) MAIN THREAD: Update Request: COUNTER = 2
74 * 4) MAIN THREAD: Sleep Request: COUNTER = 1 -> We do not sleep just yet
76 * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
77 * 1) MAIN THREAD: Update Request: COUNTER = 1
78 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
79 * 3) MAIN THREAD: Sleep Request: COUNTER = 0 -> Go to sleep
81 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
82 } // unnamed namespace
84 ///////////////////////////////////////////////////////////////////////////////////////////////////
86 ///////////////////////////////////////////////////////////////////////////////////////////////////
88 CombinedUpdateRenderController::CombinedUpdateRenderController(AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions, ThreadMode threadMode)
89 : mFpsTracker(environmentOptions),
90 mUpdateStatusLogger(environmentOptions),
91 mEventThreadSemaphore(0),
93 mUpdateRenderThreadWaitCondition(),
94 mAdaptorInterfaces(adaptorInterfaces),
95 mPerformanceInterface(adaptorInterfaces.GetPerformanceInterface()),
96 mCore(adaptorInterfaces.GetCore()),
97 mEnvironmentOptions(environmentOptions),
98 mNotificationTrigger(adaptorInterfaces.GetProcessCoreEventsTrigger()),
100 mPreRenderCallback(NULL),
101 mUpdateRenderThread(NULL),
102 mDefaultFrameDelta(0.0f),
103 mDefaultFrameDurationMilliseconds(0u),
104 mDefaultFrameDurationNanoseconds(0u),
105 mDefaultHalfFrameNanoseconds(0u),
106 mUpdateRequestCount(0u),
109 mThreadMode(threadMode),
110 mUpdateRenderRunCount(0),
111 mDestroyUpdateRenderThread(FALSE),
112 mUpdateRenderThreadCanSleep(FALSE),
113 mPendingRequestUpdate(FALSE),
114 mUseElapsedTimeAfterWait(FALSE),
116 mDeletedSurface(nullptr),
117 mPostRendering(FALSE),
120 mUploadWithoutRendering(FALSE),
121 mFirstFrameAfterResume(FALSE)
125 // Initialise frame delta/duration variables first
126 SetRenderRefreshRate(environmentOptions.GetRenderRefreshRate());
128 // Set the thread-synchronization interface on the render-surface
129 Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
132 currentSurface->SetThreadSynchronization(*this);
135 mSleepTrigger = TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &CombinedUpdateRenderController::ProcessSleepRequest), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
138 CombinedUpdateRenderController::~CombinedUpdateRenderController()
144 delete mPreRenderCallback;
145 delete mSleepTrigger;
148 void CombinedUpdateRenderController::Initialize()
152 // Ensure Update/Render Thread not already created
153 DALI_ASSERT_ALWAYS(!mUpdateRenderThread);
155 // Create Update/Render Thread
156 ConditionalWait::ScopedLock lock(mGraphicsInitializeWait);
157 mUpdateRenderThread = new pthread_t();
158 int error = pthread_create(mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this);
159 DALI_ASSERT_ALWAYS(!error && "Return code from pthread_create() when creating UpdateRenderThread");
161 // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called
162 // When this function returns, the application initialisation on the event thread should occur
165 void CombinedUpdateRenderController::Start()
169 DALI_ASSERT_ALWAYS(!mRunning && mUpdateRenderThread);
171 // Wait until all threads created in Initialise are up and running
172 for(unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i)
174 mEventThreadSemaphore.Acquire();
179 LOG_EVENT("Startup Complete, starting Update/Render Thread");
181 RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
183 Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
186 currentSurface->StartRender();
189 DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Start\n");
192 void CombinedUpdateRenderController::Pause()
198 PauseUpdateRenderThread();
200 AddPerformanceMarker(PerformanceInterface::PAUSED);
202 DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Pause\n");
205 void CombinedUpdateRenderController::Resume()
209 if(!mRunning && IsUpdateRenderThreadPaused())
211 LOG_EVENT("Resuming");
213 RunUpdateRenderThread(CONTINUOUS, AnimationProgression::USE_ELAPSED_TIME, UpdateMode::NORMAL);
215 AddPerformanceMarker(PerformanceInterface::RESUME);
219 mFirstFrameAfterResume = TRUE;
221 DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Resume\n");
225 DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Resume: Already resumed [%d, %d, %d]\n", mRunning, mUpdateRenderRunCount, mUpdateRenderThreadCanSleep);
229 void CombinedUpdateRenderController::Stop()
233 // Stop Rendering and the Update/Render Thread
234 Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
237 currentSurface->StopRender();
240 StopUpdateRenderThread();
242 if(mUpdateRenderThread)
244 LOG_EVENT("Destroying UpdateRenderThread");
246 // wait for the thread to finish
247 pthread_join(*mUpdateRenderThread, NULL);
249 delete mUpdateRenderThread;
250 mUpdateRenderThread = NULL;
255 DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Stop\n");
258 void CombinedUpdateRenderController::RequestUpdate()
262 // Increment the update-request count to the maximum
263 if(mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS)
265 ++mUpdateRequestCount;
268 if(mRunning && IsUpdateRenderThreadPaused())
270 LOG_EVENT("Processing");
272 RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
275 ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
276 mPendingRequestUpdate = TRUE;
279 void CombinedUpdateRenderController::RequestUpdateOnce(UpdateMode updateMode)
281 // Increment the update-request count to the maximum
282 if(mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS)
284 ++mUpdateRequestCount;
287 if(IsUpdateRenderThreadPaused() || updateMode == UpdateMode::FORCE_RENDER)
291 // Run Update/Render once
292 RunUpdateRenderThread(ONCE, AnimationProgression::NONE, updateMode);
296 void CombinedUpdateRenderController::ReplaceSurface(Dali::RenderSurfaceInterface* newSurface)
300 if(mUpdateRenderThread)
302 // Set the ThreadSyncronizationInterface on the new surface
303 newSurface->SetThreadSynchronization(*this);
305 LOG_EVENT("Starting to replace the surface, event-thread blocked");
307 // Start replacing the surface.
309 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
310 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
311 mNewSurface = newSurface;
312 mUpdateRenderThreadWaitCondition.Notify(lock);
315 // Wait until the surface has been replaced
316 mSurfaceSemaphore.Acquire();
318 LOG_EVENT("Surface replaced, event-thread continuing");
322 void CombinedUpdateRenderController::DeleteSurface(Dali::RenderSurfaceInterface* surface)
326 if(mUpdateRenderThread)
328 LOG_EVENT("Starting to delete the surface, event-thread blocked");
330 // Start replacing the surface.
332 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
333 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will delete the surface now
334 mDeletedSurface = surface;
335 mUpdateRenderThreadWaitCondition.Notify(lock);
338 // Wait until the surface has been deleted
339 mSurfaceSemaphore.Acquire();
341 LOG_EVENT("Surface deleted, event-thread continuing");
345 void CombinedUpdateRenderController::WaitForGraphicsInitialization()
347 ConditionalWait::ScopedLock lk(mGraphicsInitializeWait);
350 if(mUpdateRenderThread)
352 LOG_EVENT("Waiting for graphics initialisation, event-thread blocked");
354 // Wait until the graphics has been initialised
355 mGraphicsInitializeWait.Wait(lk);
357 LOG_EVENT("graphics initialised, event-thread continuing");
361 void CombinedUpdateRenderController::ResizeSurface()
365 LOG_EVENT("Resize the surface");
368 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
369 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
370 // Surface is resized and the surface resized count is increased.
372 mUpdateRenderThreadWaitCondition.Notify(lock);
376 void CombinedUpdateRenderController::SetRenderRefreshRate(unsigned int numberOfFramesPerRender)
378 // Not protected by lock, but written to rarely so not worth adding a lock when reading
379 mDefaultFrameDelta = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
380 mDefaultFrameDurationMilliseconds = uint64_t(numberOfFramesPerRender) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
381 mDefaultFrameDurationNanoseconds = uint64_t(numberOfFramesPerRender) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
382 mDefaultHalfFrameNanoseconds = mDefaultFrameDurationNanoseconds / 2u;
384 LOG_EVENT("mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds);
387 void CombinedUpdateRenderController::SetPreRenderCallback(CallbackBase* callback)
390 LOG_EVENT("Set PreRender Callback");
392 ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
393 if(mPreRenderCallback)
395 delete mPreRenderCallback;
397 mPreRenderCallback = callback;
400 void CombinedUpdateRenderController::AddSurface(Dali::RenderSurfaceInterface* surface)
403 LOG_EVENT("Surface is added");
404 if(mUpdateRenderThread)
406 // Set the ThreadSyncronizationInterface on the added surface
407 surface->SetThreadSynchronization(*this);
411 int32_t CombinedUpdateRenderController::GetThreadId() const
416 ///////////////////////////////////////////////////////////////////////////////////////////////////
418 ///////////////////////////////////////////////////////////////////////////////////////////////////
420 void CombinedUpdateRenderController::RunUpdateRenderThread(int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode)
422 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
426 case ThreadMode::NORMAL:
428 mUpdateRenderRunCount = numberOfCycles;
429 mUseElapsedTimeAfterWait = (animationProgression == AnimationProgression::USE_ELAPSED_TIME);
432 case ThreadMode::RUN_IF_REQUESTED:
434 if(updateMode != UpdateMode::FORCE_RENDER)
436 // Render only if the update mode is FORCE_RENDER which means the application requests it.
437 // We don't want to awake the update thread.
441 mUpdateRenderRunCount++; // Increase the update request count
442 mUseElapsedTimeAfterWait = TRUE; // The elapsed time should be used. We want animations to proceed.
447 mUpdateRenderThreadCanSleep = FALSE;
448 mUploadWithoutRendering = (updateMode == UpdateMode::SKIP_RENDER);
449 LOG_COUNTER_EVENT("mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait);
450 mUpdateRenderThreadWaitCondition.Notify(lock);
453 void CombinedUpdateRenderController::PauseUpdateRenderThread()
455 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
456 mUpdateRenderRunCount = 0;
459 void CombinedUpdateRenderController::StopUpdateRenderThread()
461 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
462 mDestroyUpdateRenderThread = TRUE;
463 mUpdateRenderThreadWaitCondition.Notify(lock);
466 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
468 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
470 if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
472 return !mRunning || mUpdateRenderThreadCanSleep;
475 return (mUpdateRenderRunCount != CONTINUOUS) || // Report paused if NOT continuously running
476 mUpdateRenderThreadCanSleep; // Report paused if sleeping
479 void CombinedUpdateRenderController::ProcessSleepRequest()
483 // Decrement Update request count
484 if(mUpdateRequestCount > 0)
486 --mUpdateRequestCount;
489 // Can sleep if our update-request count is 0
490 // Update/Render thread can choose to carry on updating if it determines more update/renders are required
491 if(mUpdateRequestCount == 0)
493 LOG_EVENT("Going to sleep");
495 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
496 mUpdateRenderThreadCanSleep = TRUE;
500 ///////////////////////////////////////////////////////////////////////////////////////////////////
501 // UPDATE/RENDER THREAD
502 ///////////////////////////////////////////////////////////////////////////////////////////////////
504 void CombinedUpdateRenderController::UpdateRenderThread()
506 ThreadSettings::SetThreadName("RenderThread\0");
507 mThreadId = ThreadSettings::GetThreadId();
509 // Install a function for logging
510 mEnvironmentOptions.InstallLogFunction();
512 // Install a function for tracing
513 mEnvironmentOptions.InstallTraceFunction();
515 LOG_UPDATE_RENDER("THREAD CREATED");
517 // Initialize graphics
518 GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
519 graphics.Initialize();
521 Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
522 displayConnection.Initialize(); //@todo Move InitializeGraphics code into graphics implementation
524 NotifyGraphicsInitialised();
526 //@todo Vk swaps this around, but we need to support surfaceless context for multi-window
527 graphics.ConfigureSurface(mAdaptorInterfaces.GetRenderSurfaceInterface());
529 // Tell core it has a context
530 mCore.ContextCreated();
532 NotifyThreadInitialised();
535 uint64_t lastFrameTime;
536 TimeService::GetNanoseconds(lastFrameTime);
537 uint64_t lastMemPoolLogTime = lastFrameTime;
539 LOG_UPDATE_RENDER("THREAD INITIALISED");
541 bool useElapsedTime = true;
542 bool updateRequired = true;
543 uint64_t timeToSleepUntil = 0;
544 int extraFramesDropped = 0;
546 const uint64_t memPoolInterval = 1e9 * float(mEnvironmentOptions.GetMemoryPoolInterval());
548 const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
549 const bool renderToFboEnabled = 0u != renderToFboInterval;
550 unsigned int frameCount = 0u;
552 while(UpdateRenderReady(useElapsedTime, updateRequired, timeToSleepUntil))
554 LOG_UPDATE_RENDER_TRACE;
557 bool uploadOnly = mUploadWithoutRendering;
558 unsigned int surfaceResized = mSurfaceResized;
559 Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
561 // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
562 AddPerformanceMarker(PerformanceInterface::VSYNC);
564 uint64_t currentFrameStartTime = 0;
565 TimeService::GetNanoseconds(currentFrameStartTime);
567 uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
569 // Optional FPS Tracking when continuously rendering
570 if(useElapsedTime && mFpsTracker.Enabled())
572 float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
573 mFpsTracker.Track(absoluteTimeSinceLastRender);
576 lastFrameTime = currentFrameStartTime; // Store frame start time
578 //////////////////////////////
580 //////////////////////////////
582 Dali::RenderSurfaceInterface* newSurface = ShouldSurfaceBeReplaced();
583 if(DALI_UNLIKELY(newSurface))
585 LOG_UPDATE_RENDER_TRACE_FMT("Replacing Surface");
586 // This is designed for replacing pixmap surfaces, but should work for window as well
587 // we need to delete the surface and renderable (pixmap / window)
588 // Then create a new pixmap/window and new surface
589 // If the new surface has a different display connection, then the context will be lost
590 mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
591 graphics.ActivateSurfaceContext(newSurface);
592 // TODO: ReplaceGraphicsSurface doesn't work, InitializeGraphics()
593 // already creates new surface window, the surface and the context.
594 // We probably don't need ReplaceGraphicsSurface at all.
595 // newSurface->ReplaceGraphicsSurface();
599 const bool isRenderingToFbo = renderToFboEnabled && ((0u == frameCount) || (0u != frameCount % renderToFboInterval));
602 //////////////////////////////
604 //////////////////////////////
606 const uint32_t currentTime = static_cast<uint32_t>(currentFrameStartTime / NANOSECONDS_PER_MILLISECOND);
607 const uint32_t nextFrameTime = currentTime + static_cast<uint32_t>(mDefaultFrameDurationMilliseconds);
609 uint64_t noOfFramesSinceLastUpdate = 1;
610 float frameDelta = 0.0f;
613 if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
615 extraFramesDropped = 0;
616 while(timeSinceLastFrame >= mDefaultFrameDurationNanoseconds)
618 timeSinceLastFrame -= mDefaultFrameDurationNanoseconds;
619 extraFramesDropped++;
623 // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
624 noOfFramesSinceLastUpdate += extraFramesDropped;
626 frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
628 LOG_UPDATE_RENDER("timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta);
630 Integration::UpdateStatus updateStatus;
632 AddPerformanceMarker(PerformanceInterface::UPDATE_START);
633 TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE");
634 mCore.Update(frameDelta,
641 TRACE_UPDATE_RENDER_END("DALI_UPDATE");
642 AddPerformanceMarker(PerformanceInterface::UPDATE_END);
644 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
646 // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
647 if(updateStatus.NeedsNotification())
649 mNotificationTrigger.Trigger();
650 LOG_UPDATE_RENDER("Notification Triggered");
653 // Optional logging of update/render status
654 mUpdateStatusLogger.Log(keepUpdatingStatus);
656 //////////////////////////////
658 //////////////////////////////
660 graphics.FrameStart();
661 mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
663 if(mPreRenderCallback != NULL)
665 bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
668 delete mPreRenderCallback;
669 mPreRenderCallback = NULL;
673 graphics.ActivateResourceContext();
675 if(mFirstFrameAfterResume)
677 // mFirstFrameAfterResume is set to true when the thread is resumed
678 // Let graphics know the first frame after thread initialized or resumed.
679 graphics.SetFirstFrameAfterResume();
680 mFirstFrameAfterResume = FALSE;
683 Integration::RenderStatus renderStatus;
685 AddPerformanceMarker(PerformanceInterface::RENDER_START);
686 TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER");
688 // Upload shared resources
689 mCore.PreRender(renderStatus, mForceClear);
691 if(!uploadOnly || surfaceResized)
693 // Go through each window
694 WindowContainer windows;
695 mAdaptorInterfaces.GetWindowContainerInterface(windows);
697 for(auto&& window : windows)
699 Dali::Integration::Scene scene = window->GetScene();
700 Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
702 if(scene && windowSurface)
704 Integration::RenderStatus windowRenderStatus;
706 const bool sceneSurfaceResized = scene.IsSurfaceRectChanged();
708 // clear previous frame damaged render items rects, buffer history is tracked on surface level
709 mDamagedRects.clear();
711 // Collect damage rects
712 mCore.PreRender(scene, mDamagedRects);
714 // Render off-screen frame buffers first if any
715 mCore.RenderScene(windowRenderStatus, scene, true);
717 Rect<int> clippingRect; // Empty for fbo rendering
719 // Switch to the context of the surface, merge damaged areas for previous frames
720 windowSurface->PreRender(sceneSurfaceResized, mDamagedRects, clippingRect); // Switch GL context
722 // Render the surface
723 mCore.RenderScene(windowRenderStatus, scene, false, clippingRect);
725 // Buffer swapping now happens when the surface render target is presented.
727 // If surface is resized, the surface resized count is decreased.
728 if(DALI_UNLIKELY(sceneSurfaceResized))
738 graphics.PostRender();
743 //////////////////////////////
745 //////////////////////////////
746 if(DALI_UNLIKELY(deletedSurface))
748 LOG_UPDATE_RENDER_TRACE_FMT("Deleting Surface");
750 deletedSurface->DestroySurface();
755 TRACE_UPDATE_RENDER_END("DALI_RENDER");
756 AddPerformanceMarker(PerformanceInterface::RENDER_END);
758 // if the memory pool interval is set and has elapsed, log the graphics memory pools
759 if(0 < memPoolInterval && memPoolInterval < lastFrameTime - lastMemPoolLogTime)
761 lastMemPoolLogTime = lastFrameTime;
762 graphics.LogMemoryPools();
767 // Trigger event thread to request Update/Render thread to sleep if update not required
768 if((Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus) && !renderStatus.NeedsUpdate())
770 mSleepTrigger->Trigger();
771 updateRequired = false;
772 LOG_UPDATE_RENDER("Sleep Triggered");
776 updateRequired = true;
779 //////////////////////////////
781 //////////////////////////////
783 extraFramesDropped = 0;
785 if(timeToSleepUntil == 0)
787 // If this is the first frame after the thread is initialized or resumed, we
788 // use the actual time the current frame starts from to calculate the time to
789 // sleep until the next frame.
790 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
794 // Otherwise, always use the sleep-until time calculated in the last frame to
795 // calculate the time to sleep until the next frame. In this way, if there is
796 // any time gap between the current frame and the next frame, or if update or
797 // rendering in the current frame takes too much time so that the specified
798 // sleep-until time has already passed, it will try to keep the frames syncing
799 // by shortening the duration of the next frame.
800 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
802 // Check the current time at the end of the frame
803 uint64_t currentFrameEndTime = 0;
804 TimeService::GetNanoseconds(currentFrameEndTime);
805 while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
807 // We are more than one frame behind already, so just drop the next frames
808 // until the sleep-until time is later than the current time so that we can
810 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
811 extraFramesDropped++;
815 // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
816 if(0u == renderToFboInterval)
818 // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
819 TimeService::SleepUntil(timeToSleepUntil);
823 // Inform core of context destruction
824 mCore.ContextDestroyed();
826 WindowContainer windows;
827 mAdaptorInterfaces.GetWindowContainerInterface(windows);
830 for(auto&& window : windows)
832 Dali::RenderSurfaceInterface* surface = window->GetSurface();
833 surface->DestroySurface();
838 LOG_UPDATE_RENDER("THREAD DESTROYED");
840 // Uninstall the logging function
841 mEnvironmentOptions.UnInstallLogFunction();
844 bool CombinedUpdateRenderController::UpdateRenderReady(bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil)
846 useElapsedTime = true;
848 ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
849 while((!mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
850 (mUpdateRenderThreadCanSleep && !updateRequired && !mPendingRequestUpdate)) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
851 !mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
852 !mNewSurface && // Ensure we don't wait if we need to replace the surface
853 !mDeletedSurface && // Ensure we don't wait if we need to delete the surface
854 !mSurfaceResized) // Ensure we don't wait if we need to resize the surface
856 LOG_UPDATE_RENDER("WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount);
857 LOG_UPDATE_RENDER(" mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
858 LOG_UPDATE_RENDER(" mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread);
859 LOG_UPDATE_RENDER(" mNewSurface: %d", mNewSurface);
860 LOG_UPDATE_RENDER(" mDeletedSurface: %d", mDeletedSurface);
861 LOG_UPDATE_RENDER(" mSurfaceResized: %d", mSurfaceResized);
863 // Reset the time when the thread is waiting, so the sleep-until time for
864 // the first frame after resuming should be based on the actual start time
865 // of the first frame.
866 timeToSleepUntil = 0;
868 mUpdateRenderThreadWaitCondition.Wait(updateLock);
870 if(!mUseElapsedTimeAfterWait)
872 useElapsedTime = false;
876 LOG_COUNTER_UPDATE_RENDER("mUpdateRenderRunCount: %d", mUpdateRenderRunCount);
877 LOG_COUNTER_UPDATE_RENDER("mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
878 LOG_COUNTER_UPDATE_RENDER("mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread);
879 LOG_COUNTER_UPDATE_RENDER("mNewSurface: %d", mNewSurface);
880 LOG_COUNTER_UPDATE_RENDER("mDeletedSurface: %d", mDeletedSurface);
881 LOG_COUNTER_UPDATE_RENDER("mSurfaceResized: %d", mSurfaceResized);
883 mUseElapsedTimeAfterWait = FALSE;
884 mUpdateRenderThreadCanSleep = FALSE;
885 mPendingRequestUpdate = FALSE;
887 // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
888 // requested number of cycles
889 if(mUpdateRenderRunCount > 0)
891 --mUpdateRenderRunCount;
894 // Keep the update-render thread alive if this thread is NOT to be destroyed
895 return !mDestroyUpdateRenderThread;
898 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
900 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
902 Dali::RenderSurfaceInterface* newSurface = mNewSurface;
908 void CombinedUpdateRenderController::SurfaceReplaced()
910 // Just increment the semaphore
911 mSurfaceSemaphore.Release(1);
914 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
916 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
918 Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
919 mDeletedSurface = NULL;
921 return deletedSurface;
924 void CombinedUpdateRenderController::SurfaceDeleted()
926 // Just increment the semaphore
927 mSurfaceSemaphore.Release(1);
930 void CombinedUpdateRenderController::SurfaceResized()
932 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
939 ///////////////////////////////////////////////////////////////////////////////////////////////////
941 ///////////////////////////////////////////////////////////////////////////////////////////////////
943 void CombinedUpdateRenderController::NotifyThreadInitialised()
945 // Just increment the semaphore
946 mEventThreadSemaphore.Release(1);
949 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
951 mGraphicsInitializeWait.Notify();
954 void CombinedUpdateRenderController::AddPerformanceMarker(PerformanceInterface::MarkerType type)
956 if(mPerformanceInterface)
958 mPerformanceInterface->AddMarker(type);
962 /////////////////////////////////////////////////////////////////////////////////////////////////
963 // POST RENDERING: EVENT THREAD
964 /////////////////////////////////////////////////////////////////////////////////////////////////
966 void CombinedUpdateRenderController::PostRenderComplete()
968 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
969 mPostRendering = FALSE;
970 mUpdateRenderThreadWaitCondition.Notify(lock);
973 ///////////////////////////////////////////////////////////////////////////////////////////////////
974 // POST RENDERING: RENDER THREAD
975 ///////////////////////////////////////////////////////////////////////////////////////////////////
977 void CombinedUpdateRenderController::PostRenderStarted()
979 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
980 mPostRendering = TRUE;
983 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
985 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
986 while(mPostRendering &&
987 !mNewSurface && // We should NOT wait if we're replacing the surface
988 !mDeletedSurface && // We should NOT wait if we're deleting the surface
989 !mDestroyUpdateRenderThread)
991 mUpdateRenderThreadWaitCondition.Wait(lock);
995 } // namespace Adaptor
997 } // namespace Internal