From: Eunki, Hong Date: Wed, 2 Aug 2023 09:13:43 +0000 (+0900) Subject: Relayout forcibly and flush event messages X-Git-Tag: accepted/tizen/unified/20230822.162250~1^2~2^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4dd987c181cdcd44b05cd4b45e6cc94eefcb644a;p=platform%2Fcore%2Fuifw%2Fdali-core.git Relayout forcibly and flush event messages Make a way to relayout & flush events messages by core API. It will be useful when main thread spend a lots of time, but user want to show the rendering result until now. Change-Id: I70ef492defa9e23790e92f30bb40c036e25c0131 Signed-off-by: Eunki, Hong --- diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-Core.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-Core.cpp index a0b47d081..981eab0e4 100644 --- a/automated-tests/src/dali-internal/utc-Dali-Internal-Core.cpp +++ b/automated-tests/src/dali-internal/utc-Dali-Internal-Core.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,7 +47,7 @@ public: } // callback to be connected to RelayoutSignal - void RelayoutCallback(Actor actor) + virtual void RelayoutCallback(Actor actor) { tet_infoline("RelayoutCallback is called"); @@ -60,6 +60,26 @@ public: bool mSignalCalled; }; +class DoubleRelayoutSignalHandler : public RelayoutSignalHandler +{ +public: + DoubleRelayoutSignalHandler(TestApplication& application) + : RelayoutSignalHandler(application) + { + } + + // callback to be connected to RelayoutSignal + void RelayoutCallback(Actor actor) override + { + tet_infoline("DoubleRelayoutCallback is called"); + + auto& core = mApplication.GetCore(); + core.ForceRelayout(); + + RelayoutSignalHandler::RelayoutCallback(actor); + } +}; + } // anonymous namespace int UtcDaliCoreProcessEvents(void) @@ -88,3 +108,72 @@ int UtcDaliCoreProcessEvents(void) END_TEST; } + +int UtcDaliCoreForceRelayout(void) +{ + TestApplication application; + tet_infoline("Testing Dali::Integration::Core::ForceRelayout"); + + Vector3 size(100.0f, 100.0f, 0.0f); + Vector3 position(100.0f, 100.0f, 0.0f); + + Actor actor = Actor::New(); + actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + actor.SetProperty(Actor::Property::SIZE, size); + actor.SetProperty(Actor::Property::POSITION, position); + application.GetScene().Add(actor); + + RelayoutSignalHandler relayoutSignal(application); + actor.OnRelayoutSignal().Connect(&relayoutSignal, &RelayoutSignalHandler::RelayoutCallback); + + // Call ForceRelayout before application.SendNotification(); + auto& core = application.GetCore(); + core.ForceRelayout(); + + DALI_TEST_EQUALS(relayoutSignal.mSignalCalled, true, TEST_LOCATION); + + DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::SIZE).Get(), size, TEST_LOCATION); + DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::POSITION).Get(), position, TEST_LOCATION); + + relayoutSignal.mSignalCalled = false; + + application.SendNotification(); + + // Check relayout signal not emitted; + DALI_TEST_EQUALS(relayoutSignal.mSignalCalled, false, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliCoreForceRelayout2(void) +{ + TestApplication application; + tet_infoline("Testing Dali::Integration::Core::ForceRelayout during force-relayout"); + + Vector3 size(100.0f, 100.0f, 0.0f); + Vector3 position(100.0f, 100.0f, 0.0f); + + Actor actor = Actor::New(); + actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + actor.SetProperty(Actor::Property::SIZE, size); + actor.SetProperty(Actor::Property::POSITION, position); + application.GetScene().Add(actor); + + DoubleRelayoutSignalHandler relayoutSignal(application); + actor.OnRelayoutSignal().Connect(&relayoutSignal, &DoubleRelayoutSignalHandler::RelayoutCallback); + + // Call ForceRelayout before application.SendNotification(); + auto& core = application.GetCore(); + core.ForceRelayout(); + + DALI_TEST_EQUALS(relayoutSignal.mSignalCalled, true, TEST_LOCATION); + + DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::SIZE).Get(), size, TEST_LOCATION); + DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::POSITION).Get(), position, TEST_LOCATION); + + relayoutSignal.mSignalCalled = false; + + application.SendNotification(); + + END_TEST; +} \ No newline at end of file diff --git a/dali/integration-api/core.cpp b/dali/integration-api/core.cpp index 870861bb2..9caab2201 100644 --- a/dali/integration-api/core.cpp +++ b/dali/integration-api/core.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -90,6 +90,11 @@ void Core::QueueEvent(const Event& event) mImpl->QueueEvent(event); } +void Core::ForceRelayout() +{ + mImpl->ForceRelayout(); +} + void Core::ProcessEvents() { mImpl->ProcessEvents(); diff --git a/dali/integration-api/core.h b/dali/integration-api/core.h index 0b443482d..c8d2a6190 100644 --- a/dali/integration-api/core.h +++ b/dali/integration-api/core.h @@ -2,7 +2,7 @@ #define DALI_INTEGRATION_CORE_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -293,6 +293,13 @@ public: */ void QueueEvent(const Event& event); + /** + * Relayout and flush the messages forcibly. + * Multi-threading note: this method should be called from the main thread. + * @pre ForceRelayout should not be called during ProcessEvents or ForceRelayout. + */ + void ForceRelayout(); + /** * Process the events queued with QueueEvent(). * Multi-threading note: this method should be called from the main thread. diff --git a/dali/internal/common/core-impl.cpp b/dali/internal/common/core-impl.cpp index 34836e5d0..421d2e5c0 100644 --- a/dali/internal/common/core-impl.cpp +++ b/dali/internal/common/core-impl.cpp @@ -90,7 +90,8 @@ Core::Core(RenderController& renderController, mGraphicsController(graphicsController), mProcessingEvent(false), mProcessorUnregistered(false), - mPostProcessorUnregistered(false) + mPostProcessorUnregistered(false), + mRelayoutFlush(false) { // Create the thread local storage CreateThreadLocalStorage(); @@ -258,6 +259,21 @@ void Core::QueueEvent(const Integration::Event& event) } } +void Core::ForceRelayout() +{ + if(mRelayoutFlush) + { + DALI_LOG_ERROR("ForceRelayout should not be called from within RelayoutAndFlush!\n"); + return; + } + + // Scene could be added or removed while processing the events + // Copy the Scene container locally to avoid possibly invalid iterator + SceneContainer scenes = mScenes; + + RelayoutAndFlush(scenes); +} + void Core::ProcessEvents() { // Guard against calls to ProcessEvents() during ProcessEvents() @@ -292,6 +308,47 @@ void Core::ProcessEvents() scene->EmitEventProcessingFinishedSignal(); } + RelayoutAndFlush(scenes); + + mUpdateManager->EventProcessingFinished(); + + // Check if the touch or gestures require updates. + const bool gestureNeedsUpdate = mGestureEventProcessor->NeedsUpdate(); + + if(gestureNeedsUpdate) + { + // tell the render controller to keep update thread running + mRenderController.RequestUpdate(); + } + + mRelayoutController->SetProcessingCoreEvents(false); + + // ProcessEvents() may now be called again + mProcessingEvent = false; +} + +void Core::RelayoutAndFlush(SceneContainer& scenes) +{ + if(mRelayoutFlush) + { + DALI_LOG_ERROR("RelayoutAndFlush should not be called from within RelayoutAndFlush!\n"); + return; + } + + const bool isProcessEvents = mProcessingEvent; + + if(!isProcessEvents) + { + // Fake that we are in ProcessEvents() + mProcessingEvent = true; + mRelayoutController->SetProcessingCoreEvents(true); + + // Signal that any messages received will be flushed soon + mUpdateManager->EventProcessingStarted(); + } + + mRelayoutFlush = true; + // Run any registered processors RunProcessors(); @@ -310,19 +367,22 @@ void Core::ProcessEvents() // Flush any queued messages for the update-thread const bool messagesToProcess = mUpdateManager->FlushQueue(); - // Check if the touch or gestures require updates. - const bool gestureNeedsUpdate = mGestureEventProcessor->NeedsUpdate(); - - if(messagesToProcess || gestureNeedsUpdate) + if(messagesToProcess) { // tell the render controller to keep update thread running mRenderController.RequestUpdate(); } - mRelayoutController->SetProcessingCoreEvents(false); + mRelayoutFlush = false; - // ProcessEvents() may now be called again - mProcessingEvent = false; + if(!isProcessEvents) + { + // Revert fake informations + mProcessingEvent = false; + mRelayoutController->SetProcessingCoreEvents(false); + + mUpdateManager->EventProcessingFinished(); + } } uint32_t Core::GetMaximumUpdateCount() const diff --git a/dali/internal/common/core-impl.h b/dali/internal/common/core-impl.h index ff8940eef..754869c2e 100644 --- a/dali/internal/common/core-impl.h +++ b/dali/internal/common/core-impl.h @@ -160,6 +160,11 @@ public: */ void QueueEvent(const Integration::Event& event); + /** + * @copydoc Dali::Integration::Core::ForceRelayout() + */ + void ForceRelayout(); + /** * @copydoc Dali::Integration::Core::ProcessEvents() */ @@ -233,6 +238,8 @@ public: // Implementation of EventThreadServices BufferIndex GetEventBufferIndex() const override; private: + using SceneContainer = std::vector; + /** * Run each registered processor */ @@ -243,6 +250,11 @@ private: */ void RunPostProcessors(); + /** + * Run registered processors, and relayout, and flush messages + */ + void RelayoutAndFlush(SceneContainer& scenes); + // for use by ThreadLocalStorage /** @@ -342,7 +354,6 @@ private: Dali::Vector mProcessors; ///< Registered processors (not owned) Dali::Vector mPostProcessors; ///< Registered post processors those will called after relayout(not owned) - using SceneContainer = std::vector; SceneContainer mScenes; ///< A container of scenes that bound to a surface for rendering, owned by Core // The object registry @@ -353,6 +364,7 @@ private: bool mProcessingEvent : 1; ///< True during ProcessEvents() bool mProcessorUnregistered : 1; ///< True if the processor is unregistered during RunProcessors() bool mPostProcessorUnregistered : 1; ///< True if the post-processor is unregistered during RunPostProcessors() + bool mRelayoutFlush : 1; ///< True during RelayoutAndFlush() friend class ThreadLocalStorage; }; diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index a01e9be8b..d33fc7b14 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -745,6 +745,11 @@ void UpdateManager::EventProcessingStarted() mImpl->messageQueue.EventProcessingStarted(); } +void UpdateManager::EventProcessingFinished() +{ + mImpl->messageQueue.EventProcessingFinished(); +} + bool UpdateManager::FlushQueue() { return mImpl->messageQueue.FlushQueue(); diff --git a/dali/internal/update/manager/update-manager.h b/dali/internal/update/manager/update-manager.h index 673ae9fd9..8499642c9 100644 --- a/dali/internal/update/manager/update-manager.h +++ b/dali/internal/update/manager/update-manager.h @@ -406,6 +406,11 @@ public: */ void EventProcessingStarted(); + /** + * Called by the event-thread to signal that we need to queue messages. + */ + void EventProcessingFinished(); + /** * Flush the set of messages, which were previously stored with QueueMessage(). * Calls to this thread-safe method should be minimized, to avoid thread blocking. diff --git a/dali/internal/update/queue/update-message-queue.cpp b/dali/internal/update/queue/update-message-queue.cpp index b814715de..cb35cc2d2 100644 --- a/dali/internal/update/queue/update-message-queue.cpp +++ b/dali/internal/update/queue/update-message-queue.cpp @@ -148,6 +148,11 @@ void MessageQueue::EventProcessingStarted() mImpl->processingEvents = true; // called from event thread } +void MessageQueue::EventProcessingFinished() +{ + mImpl->processingEvents = false; // called from event thread +} + // Called from event thread uint32_t* MessageQueue::ReserveMessageSlot(uint32_t requestedSize, bool updateScene) { @@ -234,8 +239,6 @@ bool MessageQueue::FlushQueue() } } - mImpl->processingEvents = false; - return messagesToProcess; } diff --git a/dali/internal/update/queue/update-message-queue.h b/dali/internal/update/queue/update-message-queue.h index cfc47ba42..2d1fa2405 100644 --- a/dali/internal/update/queue/update-message-queue.h +++ b/dali/internal/update/queue/update-message-queue.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_UPDATE_MESSAGE_QUEUE_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -67,6 +67,11 @@ public: */ void EventProcessingStarted(); + /** + * Inform the queue that event processing has finished + */ + void EventProcessingFinished(); + /** * Reserve space for a message * @param[in] size the message size with respect to the size of type 'char' @@ -116,8 +121,8 @@ private: private: // Not copyable: - MessageQueue() = delete; - MessageQueue(const MessageQueue& rhs) = delete; + MessageQueue() = delete; + MessageQueue(const MessageQueue& rhs) = delete; MessageQueue& operator=(const MessageQueue& rhs) = delete; private: