Relayout forcibly and flush event messages 29/296629/5
authorEunki, Hong <eunkiki.hong@samsung.com>
Wed, 2 Aug 2023 09:13:43 +0000 (18:13 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Wed, 16 Aug 2023 06:29:40 +0000 (15:29 +0900)
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>
automated-tests/src/dali-internal/utc-Dali-Internal-Core.cpp
dali/integration-api/core.cpp
dali/integration-api/core.h
dali/internal/common/core-impl.cpp
dali/internal/common/core-impl.h
dali/internal/update/manager/update-manager.cpp
dali/internal/update/manager/update-manager.h
dali/internal/update/queue/update-message-queue.cpp
dali/internal/update/queue/update-message-queue.h

index a0b47d0..981eab0 100644 (file)
@@ -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<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
index 870861b..9caab22 100644 (file)
@@ -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();
index 0b44348..c8d2a61 100644 (file)
@@ -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.
@@ -294,6 +294,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.
    * @pre ProcessEvents should not be called during ProcessEvents.
index 34836e5..421d2e5 100644 (file)
@@ -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
index ff8940e..754869c 100644 (file)
@@ -161,6 +161,11 @@ public:
   void QueueEvent(const Integration::Event& event);
 
   /**
+   * @copydoc Dali::Integration::Core::ForceRelayout()
+   */
+  void ForceRelayout();
+
+  /**
    * @copydoc Dali::Integration::Core::ProcessEvents()
    */
   void ProcessEvents();
@@ -233,6 +238,8 @@ public: // Implementation of EventThreadServices
   BufferIndex GetEventBufferIndex() const override;
 
 private:
+  using SceneContainer = std::vector<ScenePtr>;
+
   /**
    * 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<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
@@ -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;
 };
index a01e9be..d33fc7b 100644 (file)
@@ -745,6 +745,11 @@ void UpdateManager::EventProcessingStarted()
   mImpl->messageQueue.EventProcessingStarted();
 }
 
+void UpdateManager::EventProcessingFinished()
+{
+  mImpl->messageQueue.EventProcessingFinished();
+}
+
 bool UpdateManager::FlushQueue()
 {
   return mImpl->messageQueue.FlushQueue();
index 673ae9f..8499642 100644 (file)
@@ -407,6 +407,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.
    *
index b814715..cb35cc2 100644 (file)
@@ -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;
 }
 
index cfc47ba..2d1fa24 100644 (file)
@@ -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.
@@ -68,6 +68,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'
    * @param[in] updateScene If set to true, denotes that the message will cause the scene graph node tree to require an update
@@ -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: