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 <eunkiki.hong@samsung.com>
/*
- * 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.
}
// callback to be connected to RelayoutSignal
- void RelayoutCallback(Actor actor)
+ virtual void RelayoutCallback(Actor actor)
{
tet_infoline("RelayoutCallback is called");
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)
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<Vector3>(), size, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::POSITION).Get<Vector3>(), 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<Vector3>(), size, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::POSITION).Get<Vector3>(), position, TEST_LOCATION);
+
+ relayoutSignal.mSignalCalled = false;
+
+ application.SendNotification();
+
+ END_TEST;
+}
\ No newline at end of file
/*
- * 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.
mImpl->QueueEvent(event);
}
+void Core::ForceRelayout()
+{
+ mImpl->ForceRelayout();
+}
+
void Core::ProcessEvents()
{
mImpl->ProcessEvents();
#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.
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.
* @pre ProcessEvents should not be called during ProcessEvents.
mGraphicsController(graphicsController),
mProcessingEvent(false),
mProcessorUnregistered(false),
- mPostProcessorUnregistered(false)
+ mPostProcessorUnregistered(false),
+ mRelayoutFlush(false)
{
// Create the thread local storage
CreateThreadLocalStorage();
}
}
+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()
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();
// 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
void QueueEvent(const Integration::Event& event);
/**
+ * @copydoc Dali::Integration::Core::ForceRelayout()
+ */
+ void ForceRelayout();
+
+ /**
* @copydoc Dali::Integration::Core::ProcessEvents()
*/
void ProcessEvents();
BufferIndex GetEventBufferIndex() const override;
private:
+ using SceneContainer = std::vector<ScenePtr>;
+
/**
* Run each registered processor
*/
*/
void RunPostProcessors();
+ /**
+ * Run registered processors, and relayout, and flush messages
+ */
+ void RelayoutAndFlush(SceneContainer& scenes);
+
// for use by ThreadLocalStorage
/**
Dali::Vector<Integration::Processor*> mProcessors; ///< Registered processors (not owned)
Dali::Vector<Integration::Processor*> mPostProcessors; ///< Registered post processors those will called after relayout(not owned)
- using SceneContainer = std::vector<ScenePtr>;
SceneContainer mScenes; ///< A container of scenes that bound to a surface for rendering, owned by Core
// The object registry
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;
};
mImpl->messageQueue.EventProcessingStarted();
}
+void UpdateManager::EventProcessingFinished()
+{
+ mImpl->messageQueue.EventProcessingFinished();
+}
+
bool UpdateManager::FlushQueue()
{
return mImpl->messageQueue.FlushQueue();
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.
*
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)
{
}
}
- mImpl->processingEvents = false;
-
return messagesToProcess;
}
#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.
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'
* @param[in] updateScene If set to true, denotes that the message will cause the scene graph node tree to require an update
private:
// Not copyable:
- MessageQueue() = delete;
- MessageQueue(const MessageQueue& rhs) = delete;
+ MessageQueue() = delete;
+ MessageQueue(const MessageQueue& rhs) = delete;
MessageQueue& operator=(const MessageQueue& rhs) = delete;
private: