2 * Copyright (c) 2023 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/texture-upload-manager-impl.h>
35 #include <dali/internal/system/common/time-service.h>
36 #include <dali/internal/thread/common/thread-settings-impl.h>
37 #include <dali/internal/window-system/common/window-impl.h>
47 const unsigned int CREATED_THREAD_COUNT = 1u;
49 const int CONTINUOUS = -1;
52 const unsigned int TRUE = 1u;
53 const unsigned int FALSE = 0u;
55 const unsigned int MILLISECONDS_PER_SECOND(1e+3);
56 const float NANOSECONDS_TO_SECOND(1e-9f);
57 const unsigned int NANOSECONDS_PER_SECOND(1e+9);
58 const unsigned int NANOSECONDS_PER_MILLISECOND(1e+6);
60 // The following values will get calculated at compile time
61 const float DEFAULT_FRAME_DURATION_IN_SECONDS(1.0f / 60.0f);
62 const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* MILLISECONDS_PER_SECOND);
63 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* NANOSECONDS_PER_SECOND);
66 * Handles the use case when an update-request is received JUST before we process a sleep-request. If we did not have an update-request count then
67 * there is a danger that, on the event-thread we could have:
68 * 1) An update-request where we do nothing as Update/Render thread still running.
69 * 2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
71 * Using a counter means we increment the counter on an update-request, and decrement it on a sleep-request. This handles the above scenario because:
72 * 1) MAIN THREAD: Update Request: COUNTER = 1
73 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
74 * 3) MAIN THREAD: Update Request: COUNTER = 2
75 * 4) MAIN THREAD: Sleep Request: COUNTER = 1 -> We do not sleep just yet
77 * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
78 * 1) MAIN THREAD: Update Request: COUNTER = 1
79 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
80 * 3) MAIN THREAD: Sleep Request: COUNTER = 0 -> Go to sleep
82 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
83 } // unnamed namespace
85 ///////////////////////////////////////////////////////////////////////////////////////////////////
87 ///////////////////////////////////////////////////////////////////////////////////////////////////
89 CombinedUpdateRenderController::CombinedUpdateRenderController(AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions, ThreadMode threadMode)
90 : mFpsTracker(environmentOptions),
91 mUpdateStatusLogger(environmentOptions),
92 mEventThreadSemaphore(0),
94 mUpdateRenderThreadWaitCondition(),
95 mAdaptorInterfaces(adaptorInterfaces),
96 mPerformanceInterface(adaptorInterfaces.GetPerformanceInterface()),
97 mCore(adaptorInterfaces.GetCore()),
98 mEnvironmentOptions(environmentOptions),
99 mNotificationTrigger(adaptorInterfaces.GetProcessCoreEventsTrigger()),
101 mPreRenderCallback(NULL),
102 mTextureUploadManager(adaptorInterfaces.GetTextureUploadManager()),
103 mUpdateRenderThread(NULL),
104 mDefaultFrameDelta(0.0f),
105 mDefaultFrameDurationMilliseconds(0u),
106 mDefaultFrameDurationNanoseconds(0u),
107 mDefaultHalfFrameNanoseconds(0u),
108 mUpdateRequestCount(0u),
111 mThreadMode(threadMode),
112 mUpdateRenderRunCount(0),
113 mDestroyUpdateRenderThread(FALSE),
114 mUpdateRenderThreadCanSleep(FALSE),
115 mPendingRequestUpdate(FALSE),
116 mUseElapsedTimeAfterWait(FALSE),
118 mDeletedSurface(nullptr),
119 mPostRendering(FALSE),
122 mUploadWithoutRendering(FALSE),
123 mFirstFrameAfterResume(FALSE)
127 // Initialise frame delta/duration variables first
128 SetRenderRefreshRate(environmentOptions.GetRenderRefreshRate());
130 // Set the thread-synchronization interface on the render-surface
131 Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
134 currentSurface->SetThreadSynchronization(*this);
137 mSleepTrigger = TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &CombinedUpdateRenderController::ProcessSleepRequest), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
140 CombinedUpdateRenderController::~CombinedUpdateRenderController()
146 delete mPreRenderCallback;
147 delete mSleepTrigger;
150 void CombinedUpdateRenderController::Initialize()
154 // Ensure Update/Render Thread not already created
155 DALI_ASSERT_ALWAYS(!mUpdateRenderThread);
157 // Create Update/Render Thread
158 ConditionalWait::ScopedLock lock(mGraphicsInitializeWait);
159 mUpdateRenderThread = new pthread_t();
160 int error = pthread_create(mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this);
161 DALI_ASSERT_ALWAYS(!error && "Return code from pthread_create() when creating UpdateRenderThread");
163 // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called
164 // When this function returns, the application initialisation on the event thread should occur
167 void CombinedUpdateRenderController::Start()
171 DALI_ASSERT_ALWAYS(!mRunning && mUpdateRenderThread);
173 // Wait until all threads created in Initialise are up and running
174 for(unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i)
176 mEventThreadSemaphore.Acquire();
181 LOG_EVENT("Startup Complete, starting Update/Render Thread");
183 RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
185 Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
188 currentSurface->StartRender();
191 DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Start\n");
194 void CombinedUpdateRenderController::Pause()
200 PauseUpdateRenderThread();
202 AddPerformanceMarker(PerformanceInterface::PAUSED);
204 DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Pause\n");
207 void CombinedUpdateRenderController::Resume()
211 if(!mRunning && IsUpdateRenderThreadPaused())
213 LOG_EVENT("Resuming");
215 RunUpdateRenderThread(CONTINUOUS, AnimationProgression::USE_ELAPSED_TIME, UpdateMode::NORMAL);
217 AddPerformanceMarker(PerformanceInterface::RESUME);
221 mFirstFrameAfterResume = TRUE;
223 DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Resume\n");
227 DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Resume: Already resumed [%d, %d, %d]\n", mRunning, mUpdateRenderRunCount, mUpdateRenderThreadCanSleep);
231 void CombinedUpdateRenderController::Stop()
235 // Stop Rendering and the Update/Render Thread
236 Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
239 currentSurface->StopRender();
242 StopUpdateRenderThread();
244 if(mUpdateRenderThread)
246 LOG_EVENT("Destroying UpdateRenderThread");
248 // wait for the thread to finish
249 pthread_join(*mUpdateRenderThread, NULL);
251 delete mUpdateRenderThread;
252 mUpdateRenderThread = NULL;
257 DALI_LOG_RELEASE_INFO("CombinedUpdateRenderController::Stop\n");
260 void CombinedUpdateRenderController::RequestUpdate()
264 // Increment the update-request count to the maximum
265 if(mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS)
267 ++mUpdateRequestCount;
270 if(mRunning && IsUpdateRenderThreadPaused())
272 LOG_EVENT("Processing");
274 RunUpdateRenderThread(CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL);
277 ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
278 mPendingRequestUpdate = TRUE;
281 void CombinedUpdateRenderController::RequestUpdateOnce(UpdateMode updateMode)
283 // Increment the update-request count to the maximum
284 if(mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS)
286 ++mUpdateRequestCount;
289 if(IsUpdateRenderThreadPaused() || updateMode == UpdateMode::FORCE_RENDER)
293 // Run Update/Render once
294 RunUpdateRenderThread(ONCE, AnimationProgression::NONE, updateMode);
298 void CombinedUpdateRenderController::ReplaceSurface(Dali::RenderSurfaceInterface* newSurface)
302 if(mUpdateRenderThread)
304 // Set the ThreadSyncronizationInterface on the new surface
305 newSurface->SetThreadSynchronization(*this);
307 LOG_EVENT("Starting to replace the surface, event-thread blocked");
309 // Start replacing the surface.
311 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
312 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
313 mNewSurface = newSurface;
314 mUpdateRenderThreadWaitCondition.Notify(lock);
317 // Wait until the surface has been replaced
318 mSurfaceSemaphore.Acquire();
320 LOG_EVENT("Surface replaced, event-thread continuing");
324 void CombinedUpdateRenderController::DeleteSurface(Dali::RenderSurfaceInterface* surface)
328 if(mUpdateRenderThread)
330 LOG_EVENT("Starting to delete the surface, event-thread blocked");
332 // Start replacing the surface.
334 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
335 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will delete the surface now
336 mDeletedSurface = surface;
337 mUpdateRenderThreadWaitCondition.Notify(lock);
340 // Wait until the surface has been deleted
341 mSurfaceSemaphore.Acquire();
343 LOG_EVENT("Surface deleted, event-thread continuing");
347 void CombinedUpdateRenderController::WaitForGraphicsInitialization()
349 ConditionalWait::ScopedLock lk(mGraphicsInitializeWait);
352 if(mUpdateRenderThread)
354 LOG_EVENT("Waiting for graphics initialisation, event-thread blocked");
356 // Wait until the graphics has been initialised
357 mGraphicsInitializeWait.Wait(lk);
359 LOG_EVENT("graphics initialised, event-thread continuing");
363 void CombinedUpdateRenderController::ResizeSurface()
367 LOG_EVENT("Resize the surface");
370 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
371 // Surface is resized and the surface resized count is increased.
373 mUpdateRenderThreadWaitCondition.Notify(lock);
377 void CombinedUpdateRenderController::SetRenderRefreshRate(unsigned int numberOfFramesPerRender)
379 // Not protected by lock, but written to rarely so not worth adding a lock when reading
380 mDefaultFrameDelta = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
381 mDefaultFrameDurationMilliseconds = uint64_t(numberOfFramesPerRender) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
382 mDefaultFrameDurationNanoseconds = uint64_t(numberOfFramesPerRender) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
383 mDefaultHalfFrameNanoseconds = mDefaultFrameDurationNanoseconds / 2u;
385 LOG_EVENT("mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds);
388 void CombinedUpdateRenderController::SetPreRenderCallback(CallbackBase* callback)
391 LOG_EVENT("Set PreRender Callback");
393 ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
394 if(mPreRenderCallback)
396 delete mPreRenderCallback;
398 mPreRenderCallback = callback;
401 void CombinedUpdateRenderController::AddSurface(Dali::RenderSurfaceInterface* surface)
404 LOG_EVENT("Surface is added");
405 if(mUpdateRenderThread)
407 // Set the ThreadSyncronizationInterface on the added surface
408 surface->SetThreadSynchronization(*this);
412 int32_t CombinedUpdateRenderController::GetThreadId() const
417 ///////////////////////////////////////////////////////////////////////////////////////////////////
419 ///////////////////////////////////////////////////////////////////////////////////////////////////
421 void CombinedUpdateRenderController::RunUpdateRenderThread(int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode)
423 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
427 case ThreadMode::NORMAL:
429 mUpdateRenderRunCount = numberOfCycles;
430 mUseElapsedTimeAfterWait = (animationProgression == AnimationProgression::USE_ELAPSED_TIME);
433 case ThreadMode::RUN_IF_REQUESTED:
435 if(updateMode != UpdateMode::FORCE_RENDER)
437 // Render only if the update mode is FORCE_RENDER which means the application requests it.
438 // We don't want to awake the update thread.
442 mUpdateRenderRunCount++; // Increase the update request count
443 mUseElapsedTimeAfterWait = TRUE; // The elapsed time should be used. We want animations to proceed.
448 mUpdateRenderThreadCanSleep = FALSE;
449 mUploadWithoutRendering = (updateMode == UpdateMode::SKIP_RENDER);
450 LOG_COUNTER_EVENT("mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait);
451 mUpdateRenderThreadWaitCondition.Notify(lock);
454 void CombinedUpdateRenderController::PauseUpdateRenderThread()
456 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
457 mUpdateRenderRunCount = 0;
460 void CombinedUpdateRenderController::StopUpdateRenderThread()
462 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
463 mDestroyUpdateRenderThread = TRUE;
464 mUpdateRenderThreadWaitCondition.Notify(lock);
467 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
469 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
471 if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
473 return !mRunning || mUpdateRenderThreadCanSleep;
476 return (mUpdateRenderRunCount != CONTINUOUS) || // Report paused if NOT continuously running
477 mUpdateRenderThreadCanSleep; // Report paused if sleeping
480 void CombinedUpdateRenderController::ProcessSleepRequest()
484 // Decrement Update request count
485 if(mUpdateRequestCount > 0)
487 --mUpdateRequestCount;
490 // Can sleep if our update-request count is 0
491 // Update/Render thread can choose to carry on updating if it determines more update/renders are required
492 if(mUpdateRequestCount == 0)
494 LOG_EVENT("Going to sleep");
496 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
497 mUpdateRenderThreadCanSleep = TRUE;
501 ///////////////////////////////////////////////////////////////////////////////////////////////////
502 // UPDATE/RENDER THREAD
503 ///////////////////////////////////////////////////////////////////////////////////////////////////
505 void CombinedUpdateRenderController::UpdateRenderThread()
507 ThreadSettings::SetThreadName("RenderThread\0");
508 mThreadId = ThreadSettings::GetThreadId();
510 // Install a function for logging
511 mEnvironmentOptions.InstallLogFunction();
513 // Install a function for tracing
514 mEnvironmentOptions.InstallTraceFunction();
516 LOG_UPDATE_RENDER("THREAD CREATED");
518 // Initialize graphics
519 GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
520 graphics.Initialize();
522 Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
523 displayConnection.Initialize(); //@todo Move InitializeGraphics code into graphics implementation
525 // Setup graphics controller into upload manager.
526 GetImplementation(mTextureUploadManager).InitalizeGraphicsController(graphics.GetController());
528 NotifyGraphicsInitialised();
530 //@todo Vk swaps this around, but we need to support surfaceless context for multi-window
531 graphics.ConfigureSurface(mAdaptorInterfaces.GetRenderSurfaceInterface());
533 // Tell core it has a context
534 mCore.ContextCreated();
536 NotifyThreadInitialised();
539 uint64_t lastFrameTime;
540 TimeService::GetNanoseconds(lastFrameTime);
541 uint64_t lastMemPoolLogTime = lastFrameTime;
543 LOG_UPDATE_RENDER("THREAD INITIALISED");
545 bool useElapsedTime = true;
546 bool updateRequired = true;
547 uint64_t timeToSleepUntil = 0;
548 int extraFramesDropped = 0;
550 const uint64_t memPoolInterval = 1e9 * float(mEnvironmentOptions.GetMemoryPoolInterval());
552 const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
553 const bool renderToFboEnabled = 0u != renderToFboInterval;
554 unsigned int frameCount = 0u;
556 while(UpdateRenderReady(useElapsedTime, updateRequired, timeToSleepUntil))
558 LOG_UPDATE_RENDER_TRACE;
561 bool uploadOnly = mUploadWithoutRendering;
562 unsigned int surfaceResized = mSurfaceResized;
563 Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
565 // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
566 AddPerformanceMarker(PerformanceInterface::VSYNC);
568 uint64_t currentFrameStartTime = 0;
569 TimeService::GetNanoseconds(currentFrameStartTime);
571 uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
573 // Optional FPS Tracking when continuously rendering
574 if(useElapsedTime && mFpsTracker.Enabled())
576 float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
577 mFpsTracker.Track(absoluteTimeSinceLastRender);
580 lastFrameTime = currentFrameStartTime; // Store frame start time
582 //////////////////////////////
584 //////////////////////////////
586 Dali::RenderSurfaceInterface* newSurface = ShouldSurfaceBeReplaced();
587 if(DALI_UNLIKELY(newSurface))
589 LOG_UPDATE_RENDER_TRACE_FMT("Replacing Surface");
590 // This is designed for replacing pixmap surfaces, but should work for window as well
591 // we need to delete the surface and renderable (pixmap / window)
592 // Then create a new pixmap/window and new surface
593 // If the new surface has a different display connection, then the context will be lost
594 mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
595 graphics.ActivateSurfaceContext(newSurface);
596 // TODO: ReplaceGraphicsSurface doesn't work, InitializeGraphics()
597 // already creates new surface window, the surface and the context.
598 // We probably don't need ReplaceGraphicsSurface at all.
599 // newSurface->ReplaceGraphicsSurface();
603 //////////////////////////////
604 // TextureUploadRequest (phase #1)
605 //////////////////////////////
607 // Upload requested resources after resource context activated.
608 graphics.ActivateResourceContext();
610 const bool textureUploaded = mTextureUploadManager.ResourceUpload();
612 // Update & Render forcely if there exist some uploaded texture.
613 uploadOnly = textureUploaded ? false : uploadOnly;
615 const bool isRenderingToFbo = renderToFboEnabled && ((0u == frameCount) || (0u != frameCount % renderToFboInterval));
618 //////////////////////////////
620 //////////////////////////////
622 const uint32_t currentTime = static_cast<uint32_t>(currentFrameStartTime / NANOSECONDS_PER_MILLISECOND);
623 const uint32_t nextFrameTime = currentTime + static_cast<uint32_t>(mDefaultFrameDurationMilliseconds);
625 uint64_t noOfFramesSinceLastUpdate = 1;
626 float frameDelta = 0.0f;
629 if(mThreadMode == ThreadMode::RUN_IF_REQUESTED)
631 extraFramesDropped = 0;
632 while(timeSinceLastFrame >= mDefaultFrameDurationNanoseconds)
634 timeSinceLastFrame -= mDefaultFrameDurationNanoseconds;
635 extraFramesDropped++;
639 // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
640 noOfFramesSinceLastUpdate += extraFramesDropped;
642 frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
644 LOG_UPDATE_RENDER("timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta);
646 Integration::UpdateStatus updateStatus;
648 AddPerformanceMarker(PerformanceInterface::UPDATE_START);
649 TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE");
650 mCore.Update(frameDelta,
657 TRACE_UPDATE_RENDER_END("DALI_UPDATE");
658 AddPerformanceMarker(PerformanceInterface::UPDATE_END);
660 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
662 // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
663 if(updateStatus.NeedsNotification())
665 mNotificationTrigger.Trigger();
666 LOG_UPDATE_RENDER("Notification Triggered");
669 // Optional logging of update/render status
670 mUpdateStatusLogger.Log(keepUpdatingStatus);
672 //////////////////////////////
674 //////////////////////////////
676 graphics.FrameStart();
677 mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
679 if(mPreRenderCallback != NULL)
681 bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
684 delete mPreRenderCallback;
685 mPreRenderCallback = NULL;
689 //////////////////////////////
690 // TextureUploadRequest (phase #2)
691 //////////////////////////////
693 // Upload requested resources after resource context activated.
694 graphics.ActivateResourceContext();
696 // Since uploadOnly value used at Update side, we should not change uploadOnly value now even some textures are uploaded.
697 mTextureUploadManager.ResourceUpload();
699 if(mFirstFrameAfterResume)
701 // mFirstFrameAfterResume is set to true when the thread is resumed
702 // Let graphics know the first frame after thread initialized or resumed.
703 graphics.SetFirstFrameAfterResume();
704 mFirstFrameAfterResume = FALSE;
707 Integration::RenderStatus renderStatus;
709 AddPerformanceMarker(PerformanceInterface::RENDER_START);
710 TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER");
712 // Upload shared resources
713 TRACE_UPDATE_RENDER_BEGIN("DALI_PRE_RENDER");
714 mCore.PreRender(renderStatus, mForceClear);
715 TRACE_UPDATE_RENDER_END("DALI_PRE_RENDER");
717 if(!uploadOnly || surfaceResized)
719 // Go through each window
720 WindowContainer windows;
721 mAdaptorInterfaces.GetWindowContainerInterface(windows);
723 for(auto&& window : windows)
725 Dali::Integration::Scene scene = window->GetScene();
726 Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
728 if(scene && windowSurface)
730 TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER_SCENE");
731 Integration::RenderStatus windowRenderStatus;
733 const bool sceneSurfaceResized = scene.IsSurfaceRectChanged();
735 // clear previous frame damaged render items rects, buffer history is tracked on surface level
736 mDamagedRects.clear();
738 // Collect damage rects
739 mCore.PreRender(scene, mDamagedRects);
741 // Render off-screen frame buffers first if any
742 mCore.RenderScene(windowRenderStatus, scene, true);
744 Rect<int> clippingRect; // Empty for fbo rendering
746 // Switch to the context of the surface, merge damaged areas for previous frames
747 windowSurface->PreRender(sceneSurfaceResized, mDamagedRects, clippingRect); // Switch GL context
749 // Render the surface
750 mCore.RenderScene(windowRenderStatus, scene, false, clippingRect);
752 // Buffer swapping now happens when the surface render target is presented.
754 // If surface is resized, the surface resized count is decreased.
755 if(DALI_UNLIKELY(sceneSurfaceResized))
759 TRACE_UPDATE_RENDER_END("DALI_RENDER_SCENE");
764 TRACE_UPDATE_RENDER_BEGIN("DALI_POST_RENDER");
767 graphics.PostRender();
771 TRACE_UPDATE_RENDER_END("DALI_POST_RENDER");
773 //////////////////////////////
775 //////////////////////////////
776 if(DALI_UNLIKELY(deletedSurface))
778 LOG_UPDATE_RENDER_TRACE_FMT("Deleting Surface");
780 deletedSurface->DestroySurface();
785 TRACE_UPDATE_RENDER_END("DALI_RENDER");
786 AddPerformanceMarker(PerformanceInterface::RENDER_END);
788 // if the memory pool interval is set and has elapsed, log the graphics memory pools
789 if(0 < memPoolInterval && memPoolInterval < lastFrameTime - lastMemPoolLogTime)
791 lastMemPoolLogTime = lastFrameTime;
792 graphics.LogMemoryPools();
797 // Trigger event thread to request Update/Render thread to sleep if update not required
798 if((Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus) && !renderStatus.NeedsUpdate())
800 mSleepTrigger->Trigger();
801 updateRequired = false;
802 LOG_UPDATE_RENDER("Sleep Triggered");
806 updateRequired = true;
809 //////////////////////////////
811 //////////////////////////////
813 extraFramesDropped = 0;
815 if(timeToSleepUntil == 0)
817 // If this is the first frame after the thread is initialized or resumed, we
818 // use the actual time the current frame starts from to calculate the time to
819 // sleep until the next frame.
820 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
824 // Otherwise, always use the sleep-until time calculated in the last frame to
825 // calculate the time to sleep until the next frame. In this way, if there is
826 // any time gap between the current frame and the next frame, or if update or
827 // rendering in the current frame takes too much time so that the specified
828 // sleep-until time has already passed, it will try to keep the frames syncing
829 // by shortening the duration of the next frame.
830 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
832 // Check the current time at the end of the frame
833 uint64_t currentFrameEndTime = 0;
834 TimeService::GetNanoseconds(currentFrameEndTime);
835 while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
837 // We are more than one frame behind already, so just drop the next frames
838 // until the sleep-until time is later than the current time so that we can
840 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
841 extraFramesDropped++;
845 // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
846 if(0u == renderToFboInterval)
848 // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
849 TimeService::SleepUntil(timeToSleepUntil);
853 // Inform core of context destruction
854 mCore.ContextDestroyed();
856 WindowContainer windows;
857 mAdaptorInterfaces.GetWindowContainerInterface(windows);
860 for(auto&& window : windows)
862 Dali::RenderSurfaceInterface* surface = window->GetSurface();
863 surface->DestroySurface();
868 LOG_UPDATE_RENDER("THREAD DESTROYED");
870 // Uninstall the logging function
871 mEnvironmentOptions.UnInstallLogFunction();
874 bool CombinedUpdateRenderController::UpdateRenderReady(bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil)
876 useElapsedTime = true;
878 ConditionalWait::ScopedLock updateLock(mUpdateRenderThreadWaitCondition);
879 while((!mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
880 (mUpdateRenderThreadCanSleep && !updateRequired && !mPendingRequestUpdate)) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
881 !mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
882 !mNewSurface && // Ensure we don't wait if we need to replace the surface
883 !mDeletedSurface && // Ensure we don't wait if we need to delete the surface
884 !mSurfaceResized) // Ensure we don't wait if we need to resize the surface
886 LOG_UPDATE_RENDER("WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount);
887 LOG_UPDATE_RENDER(" mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
888 LOG_UPDATE_RENDER(" mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread);
889 LOG_UPDATE_RENDER(" mNewSurface: %d", mNewSurface);
890 LOG_UPDATE_RENDER(" mDeletedSurface: %d", mDeletedSurface);
891 LOG_UPDATE_RENDER(" mSurfaceResized: %d", mSurfaceResized);
893 // Reset the time when the thread is waiting, so the sleep-until time for
894 // the first frame after resuming should be based on the actual start time
895 // of the first frame.
896 timeToSleepUntil = 0;
898 mUpdateRenderThreadWaitCondition.Wait(updateLock);
900 if(!mUseElapsedTimeAfterWait)
902 useElapsedTime = false;
906 LOG_COUNTER_UPDATE_RENDER("mUpdateRenderRunCount: %d", mUpdateRenderRunCount);
907 LOG_COUNTER_UPDATE_RENDER("mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate);
908 LOG_COUNTER_UPDATE_RENDER("mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread);
909 LOG_COUNTER_UPDATE_RENDER("mNewSurface: %d", mNewSurface);
910 LOG_COUNTER_UPDATE_RENDER("mDeletedSurface: %d", mDeletedSurface);
911 LOG_COUNTER_UPDATE_RENDER("mSurfaceResized: %d", mSurfaceResized);
913 mUseElapsedTimeAfterWait = FALSE;
914 mUpdateRenderThreadCanSleep = FALSE;
915 mPendingRequestUpdate = FALSE;
917 // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
918 // requested number of cycles
919 if(mUpdateRenderRunCount > 0)
921 --mUpdateRenderRunCount;
924 // Keep the update-render thread alive if this thread is NOT to be destroyed
925 return !mDestroyUpdateRenderThread;
928 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
930 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
932 Dali::RenderSurfaceInterface* newSurface = mNewSurface;
938 void CombinedUpdateRenderController::SurfaceReplaced()
940 // Just increment the semaphore
941 mSurfaceSemaphore.Release(1);
944 Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
946 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
948 Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
949 mDeletedSurface = NULL;
951 return deletedSurface;
954 void CombinedUpdateRenderController::SurfaceDeleted()
956 // Just increment the semaphore
957 mSurfaceSemaphore.Release(1);
960 void CombinedUpdateRenderController::SurfaceResized()
962 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
969 ///////////////////////////////////////////////////////////////////////////////////////////////////
971 ///////////////////////////////////////////////////////////////////////////////////////////////////
973 void CombinedUpdateRenderController::NotifyThreadInitialised()
975 // Just increment the semaphore
976 mEventThreadSemaphore.Release(1);
979 void CombinedUpdateRenderController::NotifyGraphicsInitialised()
981 mGraphicsInitializeWait.Notify();
984 void CombinedUpdateRenderController::AddPerformanceMarker(PerformanceInterface::MarkerType type)
986 if(mPerformanceInterface)
988 mPerformanceInterface->AddMarker(type);
992 /////////////////////////////////////////////////////////////////////////////////////////////////
993 // POST RENDERING: EVENT THREAD
994 /////////////////////////////////////////////////////////////////////////////////////////////////
996 void CombinedUpdateRenderController::PostRenderComplete()
998 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
999 mPostRendering = FALSE;
1000 mUpdateRenderThreadWaitCondition.Notify(lock);
1003 ///////////////////////////////////////////////////////////////////////////////////////////////////
1004 // POST RENDERING: RENDER THREAD
1005 ///////////////////////////////////////////////////////////////////////////////////////////////////
1007 void CombinedUpdateRenderController::PostRenderStarted()
1009 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
1010 mPostRendering = TRUE;
1013 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
1015 ConditionalWait::ScopedLock lock(mUpdateRenderThreadWaitCondition);
1016 while(mPostRendering &&
1017 !mNewSurface && // We should NOT wait if we're replacing the surface
1018 !mDeletedSurface && // We should NOT wait if we're deleting the surface
1019 !mDestroyUpdateRenderThread)
1021 mUpdateRenderThreadWaitCondition.Wait(lock);
1025 } // namespace Adaptor
1027 } // namespace Internal