(FrameCallback) Ensure Update doesn't invoke removed FrameCallbacks 48/191648/11
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 19 Oct 2018 15:26:01 +0000 (16:26 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 24 Oct 2018 12:34:22 +0000 (13:34 +0100)
Change-Id: I28a37a5fe109b62e29626e66470258fa2f94392e

13 files changed:
automated-tests/src/dali/utc-Dali-FrameCallbackInterface.cpp
dali/devel-api/common/stage-devel.h
dali/devel-api/update/frame-callback-interface.cpp
dali/devel-api/update/frame-callback-interface.h
dali/internal/event/common/stage-impl.cpp
dali/internal/event/update/frame-callback-interface-impl.h [new file with mode: 0644]
dali/internal/file.list
dali/internal/update/manager/frame-callback-processor.cpp
dali/internal/update/manager/frame-callback-processor.h
dali/internal/update/manager/scene-graph-frame-callback.cpp [new file with mode: 0644]
dali/internal/update/manager/scene-graph-frame-callback.h [new file with mode: 0644]
dali/internal/update/manager/update-manager.cpp
dali/internal/update/manager/update-manager.h

index 858e20b..c932e02 100644 (file)
@@ -60,8 +60,6 @@ public:
   bool mCalled{ false };
 };
 
-} // anon namespace
-
 class FrameCallbackOneActor : public FrameCallbackBasic
 {
 public:
@@ -270,6 +268,8 @@ public:
   bool mBakeScaleCallSuccess{ false };
 };
 
+} // anon namespace
+
 ///////////////////////////////////////////////////////////////////////////////
 
 int UtcDaliFrameCallbackCheckInstallationAndRemoval(void)
@@ -879,3 +879,26 @@ int UtcDaliFrameCallbackDestroyedBeforeRemoving(void)
 
   END_TEST;
 }
+
+int UtcDaliFrameCallbackDoubleAddition(void)
+{
+  // Ensure we don't connect the same frame-callback twice
+
+  TestApplication application;
+  Stage stage = Stage::GetCurrent();
+  Actor rootActor = stage.GetRootLayer();
+
+  FrameCallbackBasic frameCallback;
+  DevelStage::AddFrameCallback( stage, frameCallback, rootActor );
+
+  try
+  {
+    DevelStage::AddFrameCallback( stage, frameCallback, rootActor );
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
index 05b7390..ca754f9 100644 (file)
@@ -74,6 +74,7 @@ DALI_CORE_API Rendering GetRenderingBehavior( Dali::Stage stage );
  * @param[in] frameCallback An implementation of the FrameCallbackInterface
  * @param[in] rootActor The root-actor in the scene that the callback applies to
  *
+ * @note The frameCallback cannot be added more than once. This will assert if that is attempted.
  * @note Only the rootActor and it's children will be parsed by the UpdateProxy.
  * @note If the rootActor is destroyed, then the callback is automatically removed
  * @see FrameCallbackInterface
@@ -86,6 +87,7 @@ DALI_IMPORT_API void AddFrameCallback( Dali::Stage stage, FrameCallbackInterface
  * @param[in] stage The stage to clear the FrameCallbackInterface on
  * @param[in] frameCallback The FrameCallbackInterface implementation to remove
  *
+ * @note This function will block if the FrameCallbackInterface::Update method is being processed in the update-thread.
  * @note If the callback implementation has already been removed, then this is a no-op.
  */
 DALI_IMPORT_API void RemoveFrameCallback( Dali::Stage stage, FrameCallbackInterface& frameCallback );
index bf4de08..238f881 100644 (file)
 // INTERNAL INCLUDES
 #include <dali/devel-api/update/update-proxy.h>
 #include <dali/internal/event/common/stage-impl.h>
+#include <dali/internal/event/update/frame-callback-interface-impl.h>
 
 namespace Dali
 {
 
+FrameCallbackInterface::FrameCallbackInterface()
+: mImpl( std::unique_ptr< Impl >( new Impl ) )
+{
+}
+
 FrameCallbackInterface::~FrameCallbackInterface()
 {
   if( Internal::Stage::IsInstalled() )
index e6ad997..eed5ad3 100644 (file)
@@ -18,6 +18,9 @@
  *
  */
 
+// EXTERNAL INCLUDES
+#include <memory>
+
 // INTERNAL INCLUDES
 #include <dali/public-api/common/dali-common.h>
 
@@ -59,12 +62,20 @@ protected:
   /**
    * @brief Protected constructor.
    */
-  FrameCallbackInterface() {}
+  FrameCallbackInterface();
 
   /**
    * @brief Protected virtual destructor.
    */
   virtual ~FrameCallbackInterface();
+
+public:
+  /// @cond internal
+  class Impl;
+
+private:
+  std::unique_ptr< Impl > mImpl;
+  /// @endcond
 };
 
 } // namespace Dali
index 99a6683..b205860 100644 (file)
@@ -32,7 +32,9 @@
 #include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/internal/event/common/property-notification-manager.h>
 #include <dali/internal/event/render-tasks/render-task-list-impl.h>
+#include <dali/internal/event/update/frame-callback-interface-impl.h>
 #include <dali/internal/update/nodes/node.h>
+#include <dali/internal/update/manager/scene-graph-frame-callback.h>
 #include <dali/internal/event/common/object-registry-impl.h>
 #include <dali/integration-api/platform-abstraction.h>
 #include <dali/public-api/common/constants.h>
@@ -658,11 +660,17 @@ Dali::DevelStage::KeyEventGeneratedSignalType& Stage::KeyEventGeneratedSignal()
 
 void Stage::AddFrameCallback( FrameCallbackInterface& frameCallback, Actor& rootActor )
 {
-  AddFrameCallbackMessage( mUpdateManager, frameCallback, rootActor.GetNode() );
+  DALI_ASSERT_ALWAYS( ( ! FrameCallbackInterface::Impl::Get( frameCallback ).IsConnectedToSceneGraph() )
+                      && "FrameCallbackInterface implementation already added" );
+
+  // Create scene-graph object and transfer to UpdateManager
+  OwnerPointer< SceneGraph::FrameCallback > transferOwnership( SceneGraph::FrameCallback::New( frameCallback ) );
+  AddFrameCallbackMessage( mUpdateManager, transferOwnership, rootActor.GetNode() );
 }
 
 void Stage::RemoveFrameCallback( FrameCallbackInterface& frameCallback )
 {
+  FrameCallbackInterface::Impl::Get( frameCallback ).Invalidate();
   RemoveFrameCallbackMessage( mUpdateManager, frameCallback );
 }
 
diff --git a/dali/internal/event/update/frame-callback-interface-impl.h b/dali/internal/event/update/frame-callback-interface-impl.h
new file mode 100644 (file)
index 0000000..ce92562
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef DALI_FRAME_CALLBACK_INTERFACE_IMPL_H
+#define DALI_FRAME_CALLBACK_INTERFACE_IMPL_H
+
+/*
+ * Copyright (c) 2018 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/update/frame-callback-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+namespace SceneGraph
+{
+class FrameCallback;
+}
+}
+
+/**
+ * The Implementation of the FrameCallbackInterface
+ * @see FrameCallbackInterface
+ */
+class FrameCallbackInterface::Impl final
+{
+public:
+
+  Impl() = default; ///< Default constructor.
+  ~Impl() = default; ///< Default non-virtual destructor.
+
+  /**
+   * Retrieve the Impl of a FrameCallbackInterface.
+   * @param[in]  frameCallback  The frame-callb
+   */
+  static inline Impl& Get( FrameCallbackInterface& frameCallback )
+  {
+    return *frameCallback.mImpl;
+  }
+
+  /**
+   * Links this FrameCallback to the given scene-graph-frame-callback.
+   * @param[in]  sceneGraphObject  The scene-graph-frame-callback to link this with.
+   */
+  void ConnectToSceneGraphObject( Internal::SceneGraph::FrameCallback& sceneGraphObject )
+  {
+    mSceneGraphFrameCallback = &sceneGraphObject;
+  }
+
+  /**
+   * Disconnects this FrameCallback from the scene-graph-frame-callback.
+   */
+  void DisconnectFromSceneGraphObject()
+  {
+    mSceneGraphFrameCallback = nullptr;
+  }
+
+  /**
+   * Checks whether we are connected to a scene-graph-frame-callback.
+   * @return True if connected, false otherwise.
+   */
+  bool IsConnectedToSceneGraph() const
+  {
+    return mSceneGraphFrameCallback;
+  }
+
+  /**
+   * Invalidates this FrameCallback and linked SceneGraph::FrameCallback.
+   */
+  void Invalidate()
+  {
+    if( mSceneGraphFrameCallback )
+    {
+      mSceneGraphFrameCallback->Invalidate();
+    }
+  }
+
+private:
+  Internal::SceneGraph::FrameCallback* mSceneGraphFrameCallback{ nullptr }; ///< Pointer to the scene-graph object, not owned.
+};
+
+} // namespace Dali
+
+#endif // DALI_FRAME_CALLBACK_INTERFACE_IMPL_H
index 72e8e0f..4376b0f 100644 (file)
@@ -130,6 +130,7 @@ internal_src_files = \
   $(internal_src_dir)/update/manager/frame-callback-processor.cpp \
   $(internal_src_dir)/update/manager/render-instruction-processor.cpp \
   $(internal_src_dir)/update/manager/render-task-processor.cpp \
+  $(internal_src_dir)/update/manager/scene-graph-frame-callback.cpp \
   $(internal_src_dir)/update/manager/transform-manager.cpp \
   $(internal_src_dir)/update/manager/update-algorithms.cpp \
   $(internal_src_dir)/update/manager/update-manager.cpp \
index f837ce2..57459cf 100644 (file)
@@ -34,34 +34,6 @@ namespace Internal
 namespace SceneGraph
 {
 
-namespace
-{
-
-/**
- * Given a node, it matches all update-proxies using that node as their root-node.
- */
-template< typename FrameCallbackInfoT >
-class MatchRootNode
-{
-public:
-
-  MatchRootNode( PropertyOwner& rootNode )
-  : mRootNode( rootNode )
-  {
-  }
-
-  bool operator() ( const FrameCallbackInfoT& info )
-  {
-    return &info.updateProxyImpl->GetRootNode() == &mRootNode;
-  }
-
-private:
-
-  const PropertyOwner& mRootNode;
-};
-
-} // unnamed namespace
-
 FrameCallbackProcessor::FrameCallbackProcessor( TransformManager& transformManager )
 : mFrameCallbacks(),
   mTransformManager( transformManager ),
@@ -73,74 +45,37 @@ FrameCallbackProcessor::~FrameCallbackProcessor()
 {
 }
 
-void FrameCallbackProcessor::AddFrameCallback( FrameCallbackInterface* frameCallback, const Node* rootNode )
+void FrameCallbackProcessor::AddFrameCallback( OwnerPointer< FrameCallback >& frameCallback, const Node* rootNode )
 {
   Node& node = const_cast< Node& >( *rootNode ); // Was sent as const from event thread, we need to be able to use non-const version here.
 
-  // We want to be notified when the node is destroyed (if we're not observing it already)
-  auto iter = std::find_if( mFrameCallbacks.begin(), mFrameCallbacks.end(), MatchRootNode< FrameCallbackInfo >( node ) );
-  if( iter == mFrameCallbacks.end() )
-  {
-    node.AddObserver( *this );
-  }
+  frameCallback->ConnectToSceneGraph( mTransformManager, node );
 
-  mFrameCallbacks.emplace_back( FrameCallbackInfo( frameCallback , new UpdateProxy( mTransformManager, node ) ) );
+  mFrameCallbacks.emplace_back( frameCallback );
 }
 
 void FrameCallbackProcessor::RemoveFrameCallback( FrameCallbackInterface* frameCallback )
 {
-  std::vector< SceneGraph::Node* > nodesToStopObserving;
-
-  // Find and remove all matching frame-callbacks
-  auto iter =
-    std::remove_if( mFrameCallbacks.begin(), mFrameCallbacks.end(),
-                    [ frameCallback, &nodesToStopObserving ] ( FrameCallbackInfo& info )
-                    {
-                      bool match = false;
-                      if( info.frameCallback == frameCallback )
-                      {
-                        nodesToStopObserving.push_back( &info.updateProxyImpl->GetRootNode() );
-                        match = true;
-                      }
-                      return match;
-                    } );
+  // Find and remove all frame-callbacks that use the given frame-callback-interface
+  auto iter = std::remove( mFrameCallbacks.begin(), mFrameCallbacks.end(), frameCallback );
   mFrameCallbacks.erase( iter, mFrameCallbacks.end() );
-
-  // Only stop observing the removed frame-callback nodes if none of the other frame-callbacks use them as root nodes
-  for( auto&& node : nodesToStopObserving )
-  {
-    auto nodeMatchingIter = std::find_if( mFrameCallbacks.begin(), mFrameCallbacks.end(), MatchRootNode< FrameCallbackInfo >( *node ) );
-    if( nodeMatchingIter == mFrameCallbacks.end() )
-    {
-      node->RemoveObserver( *this );
-    }
-  }
 }
 
 void FrameCallbackProcessor::Update( BufferIndex bufferIndex, float elapsedSeconds )
 {
-  for( auto&& iter : mFrameCallbacks )
-  {
-    UpdateProxy& updateProxyImpl = *iter.updateProxyImpl;
-    updateProxyImpl.SetCurrentBufferIndex( bufferIndex );
-
-    if( mNodeHierarchyChanged )
+  // If any of the FrameCallback::Update calls returns false, then they are no longer required & can be removed.
+  auto iter = std::remove_if(
+    mFrameCallbacks.begin(), mFrameCallbacks.end(),
+    [ & ]( OwnerPointer< FrameCallback >& frameCallback )
     {
-      updateProxyImpl.NodeHierarchyChanged();
+      return ! frameCallback->Update( bufferIndex, elapsedSeconds, mNodeHierarchyChanged );
     }
+  );
+  mFrameCallbacks.erase( iter, mFrameCallbacks.end() );
 
-    Dali::UpdateProxy updateProxy( updateProxyImpl );
-    iter.frameCallback->Update( updateProxy, elapsedSeconds );
-  }
   mNodeHierarchyChanged = false;
 }
 
-void FrameCallbackProcessor::PropertyOwnerDestroyed( PropertyOwner& owner )
-{
-  auto iter = std::remove_if( mFrameCallbacks.begin(), mFrameCallbacks.end(), MatchRootNode< FrameCallbackInfo >( owner )  );
-  mFrameCallbacks.erase( iter, mFrameCallbacks.end() );
-}
-
 } // namespace SceneGraph
 
 } // namespace Internal
index 440227d..06f03c4 100644 (file)
@@ -24,7 +24,8 @@
 // INTERNAL INCLUDES
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/internal/common/buffer-index.h>
-#include <dali/internal/update/common/property-owner.h>
+#include <dali/internal/common/owner-pointer.h>
+#include <dali/internal/update/manager/scene-graph-frame-callback.h>
 #include <dali/internal/update/manager/update-proxy-impl.h>
 
 namespace Dali
@@ -44,7 +45,7 @@ class TransformManager;
 /**
  * This class processes all the registered frame-callbacks.
  */
-class FrameCallbackProcessor : public PropertyOwner::Observer
+class FrameCallbackProcessor
 {
 public:
 
@@ -67,10 +68,10 @@ public:
 
   /**
    * Adds an implementation of the FrameCallbackInterface.
-   * @param[in]  frameCallback  A pointer to the implementation of the FrameCallbackInterface
+   * @param[in]  frameCallback  An OwnerPointer to the SceneGraph FrameCallback object
    * @param[in]  rootNode       A pointer to the root node to apply the FrameCallback to
    */
-  void AddFrameCallback( FrameCallbackInterface* frameCallback, const Node* rootNode );
+  void AddFrameCallback( OwnerPointer< FrameCallback >& frameCallback, const Node* rootNode );
 
   /**
    * Removes the specified implementation of FrameCallbackInterface.
@@ -95,55 +96,7 @@ public:
 
 private:
 
-  // From PropertyOwner::Observer
-
-  /**
-   * @copydoc PropertyOwner::Observer::PropertyOwnerConnected()
-   */
-  virtual void PropertyOwnerConnected( PropertyOwner& owner ) { /* Nothing to do */ }
-
-  /**
-   * @copydoc PropertyOwner::Observer::PropertyOwnerDisconnected()
-   */
-  virtual void PropertyOwnerDisconnected( BufferIndex updateBufferIndex, PropertyOwner& owner ) { /* Nothing to do */ }
-
-  /**
-   * @copydoc PropertyOwner::Observer::PropertyOwnerDisconnected()
-   *
-   * Will use this to disconnect the frame-callback if the accompanying node is destroyed
-   */
-  virtual void PropertyOwnerDestroyed( PropertyOwner& owner );
-
-private:
-
-  struct FrameCallbackInfo
-  {
-    /**
-     * Default Constructor
-     * @param[in]  frameCallbackObject  A pointer to the frame-callback object
-     * @param[in]  updateProxyPtr       A raw pointer to the newly created updateProxy
-     * @note Ownership of @updateProxyPtr is passed to this class.
-     */
-    FrameCallbackInfo( FrameCallbackInterface* frameCallbackObject, UpdateProxy* updateProxyPtr )
-    : frameCallback( frameCallbackObject ),
-      updateProxyImpl( updateProxyPtr )
-    {
-    }
-
-    ~FrameCallbackInfo() = default; ///< Default destructor.
-
-    // Movable but not copyable
-    FrameCallbackInfo( const FrameCallbackInfo& )            = delete;  ///< Deleted copy constructor.
-    FrameCallbackInfo( FrameCallbackInfo&& )                 = default; ///< Default move constructor.
-    FrameCallbackInfo& operator=( const FrameCallbackInfo& ) = delete;  ///< Deleted copy assignment operator.
-    FrameCallbackInfo& operator=( FrameCallbackInfo&& )      = default; ///< Default move assignment operator.
-
-    // Data
-    FrameCallbackInterface* frameCallback{ nullptr }; ///< Pointer to the implementation of the FrameCallbackInterface.
-    std::unique_ptr< UpdateProxy > updateProxyImpl{ nullptr }; ///< A unique pointer to the implementation of the UpdateProxy.
-  };
-
-  std::vector< FrameCallbackInfo > mFrameCallbacks; ///< A container of all the frame-callbacks & accompanying update-proxies.
+  std::vector< OwnerPointer< FrameCallback > > mFrameCallbacks; ///< A container of all the frame-callbacks & accompanying update-proxies.
 
   TransformManager& mTransformManager;
 
diff --git a/dali/internal/update/manager/scene-graph-frame-callback.cpp b/dali/internal/update/manager/scene-graph-frame-callback.cpp
new file mode 100644 (file)
index 0000000..14cbe6f
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/update/manager/scene-graph-frame-callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/devel-api/update/frame-callback-interface.h>
+#include <dali/devel-api/update/update-proxy.h>
+#include <dali/internal/event/update/frame-callback-interface-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace SceneGraph
+{
+
+FrameCallback* FrameCallback::New( FrameCallbackInterface& frameCallbackInterface )
+{
+  return new FrameCallback( &frameCallbackInterface );
+}
+
+FrameCallback::~FrameCallback()
+{
+  if( mUpdateProxy )
+  {
+    mUpdateProxy->GetRootNode().RemoveObserver( *this );
+  }
+
+  {
+    Mutex::ScopedLock lock( mMutex );
+    if( mFrameCallbackInterface )
+    {
+      FrameCallbackInterface::Impl::Get( *mFrameCallbackInterface ).DisconnectFromSceneGraphObject();
+    }
+  }
+}
+
+void FrameCallback::ConnectToSceneGraph( TransformManager& transformManager, Node& rootNode )
+{
+  mUpdateProxy = std::unique_ptr< UpdateProxy >( new UpdateProxy( transformManager, rootNode ) );
+  rootNode.AddObserver( *this );
+}
+
+bool FrameCallback::Update( BufferIndex bufferIndex, float elapsedSeconds, bool nodeHierarchyChanged )
+{
+  bool continueCalling = false;
+  if( mUpdateProxy )
+  {
+    mUpdateProxy->SetCurrentBufferIndex( bufferIndex );
+
+    if( nodeHierarchyChanged )
+    {
+      mUpdateProxy->NodeHierarchyChanged();
+    }
+
+    Mutex::ScopedLock lock( mMutex );
+    if( mFrameCallbackInterface )
+    {
+      Dali::UpdateProxy updateProxy( *mUpdateProxy );
+      mFrameCallbackInterface->Update( updateProxy, elapsedSeconds );
+      continueCalling = true;
+    }
+  }
+  return continueCalling;
+}
+
+void FrameCallback::Invalidate()
+{
+  Mutex::ScopedLock lock( mMutex );
+  if( mFrameCallbackInterface )
+  {
+    FrameCallbackInterface::Impl::Get( *mFrameCallbackInterface ).DisconnectFromSceneGraphObject();
+    mFrameCallbackInterface = nullptr;
+  }
+}
+
+void FrameCallback::PropertyOwnerDestroyed( PropertyOwner& owner )
+{
+  Invalidate();
+}
+
+FrameCallback::FrameCallback( FrameCallbackInterface* frameCallbackInterface )
+: mMutex(),
+  mFrameCallbackInterface( frameCallbackInterface )
+{
+  if( frameCallbackInterface )
+  {
+    FrameCallbackInterface::Impl::Get( *mFrameCallbackInterface ).ConnectToSceneGraphObject( *this );
+  }
+}
+
+} // namespace SceneGraph
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/update/manager/scene-graph-frame-callback.h b/dali/internal/update/manager/scene-graph-frame-callback.h
new file mode 100644 (file)
index 0000000..ae801da
--- /dev/null
@@ -0,0 +1,155 @@
+#ifndef DALI_INTERNAL_SCENE_GRAPH_FRAME_CALLBACK_H
+#define DALI_INTERNAL_SCENE_GRAPH_FRAME_CALLBACK_H
+
+/*
+ * Copyright (c) 2018 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/devel-api/update/frame-callback-interface.h>
+#include <dali/internal/common/owner-pointer.h>
+#include <dali/internal/update/common/property-owner.h>
+#include <dali/internal/update/manager/update-proxy-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace SceneGraph
+{
+
+class Node;
+class TransformManager;
+
+/**
+ * This is the update-thread owned entity of the FrameCallbackInterface.
+ * @see Dali::FrameCallbackInterface
+ */
+class FrameCallback final : public PropertyOwner::Observer
+{
+public:
+
+  /**
+   * Creates a new FrameCallback.
+   * @param[in]  frameCallbackInterface  A reference to the FrameCallbackInterface implementation
+   * @return A new FrameCallback.
+   */
+  static FrameCallback* New( FrameCallbackInterface& frameCallbackInterface );
+
+  /**
+   * Non-virtual Destructor.
+   */
+  ~FrameCallback();
+
+  /**
+   * Called from the update-thread when connecting to the scene-graph.
+   * @param[in]  transformManager  The transform Manager
+   * @param[in]  rootNode          The rootNode of this frame-callback
+   */
+  void ConnectToSceneGraph( TransformManager& transformManager, Node& rootNode );
+
+  // Movable but not copyable
+
+  FrameCallback( const FrameCallback& )            = delete;  ///< Deleted copy constructor.
+  FrameCallback( FrameCallback&& )                 = default; ///< Default move constructor.
+  FrameCallback& operator=( const FrameCallback& ) = delete;  ///< Deleted copy assignment operator.
+  FrameCallback& operator=( FrameCallback&& )      = default; ///< Default move assignment operator.
+
+  /**
+   * Called from the update-thread after the scene has been updated, and is ready to render.
+   * @param[in]  bufferIndex           The bufferIndex to use
+   * @param[in]  elapsedSeconds        Time elapsed time since the last frame (in seconds)
+   * @param[in]  nodeHierarchyChanged  Whether the node hierarchy has changed
+   * @return Whether to continue calling this FrameCallback or not.
+   */
+  bool Update( BufferIndex bufferIndex, float elapsedSeconds, bool nodeHierarchyChanged );
+
+  /**
+   * Invalidates this FrameCallback and will no longer be associated with the FrameCallbackInterface.
+   * @note This method is thread-safe.
+   */
+  void Invalidate();
+
+  /**
+   * Comparison operator between a FrameCallback and a FrameCallbackInterface pointer.
+   * @param[in]  iFace  The FrameCallbackInterface pointer to compare with
+   * @return True if iFace matches our internally stored FrameCallbackInterface.
+   */
+  inline bool operator==( const FrameCallbackInterface* iFace )
+  {
+    return mFrameCallbackInterface == iFace;
+  }
+
+private:
+
+  // From PropertyOwner::Observer
+
+  /**
+   * @copydoc PropertyOwner::Observer::PropertyOwnerConnected()
+   */
+  virtual void PropertyOwnerConnected( PropertyOwner& owner ) { /* Nothing to do */ }
+
+  /**
+   * @copydoc PropertyOwner::Observer::PropertyOwnerDisconnected()
+   */
+  virtual void PropertyOwnerDisconnected( BufferIndex updateBufferIndex, PropertyOwner& owner ) { /* Nothing to do */ }
+
+  /**
+   * @copydoc PropertyOwner::Observer::PropertyOwnerDisconnected()
+   *
+   * Will use this to disconnect the frame-callback if the accompanying node is destroyed
+   */
+  virtual void PropertyOwnerDestroyed( PropertyOwner& owner );
+
+  // Construction
+
+  /**
+   * Constructor.
+   * @param[in]  frameCallbackInterface  A pointer to the FrameCallbackInterface implementation
+   */
+  FrameCallback( FrameCallbackInterface* frameCallbackInterface );
+
+private:
+
+  Mutex mMutex;
+  std::unique_ptr< UpdateProxy > mUpdateProxy{ nullptr }; ///< A unique pointer to the implementation of the UpdateProxy.
+  FrameCallbackInterface* mFrameCallbackInterface;
+};
+
+/**
+ * Checks if FrameCallback store iFace internally.
+ * @param[in]  frameCallback  Reference to the owner-pointer of frame-callback
+ * @param[in]  iFace          The FrameCallbackInterface pointer
+ * @return True if iFace matches the internally stored FrameCallbackInterface.
+ */
+inline bool operator==( const OwnerPointer< FrameCallback >& frameCallback, const FrameCallbackInterface* iFace )
+{
+  return *frameCallback == iFace;
+}
+
+} // namespace SceneGraph
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_SCENE_GRAPH_FRAME_CALLBACK_H
index 7574d32..8b21b09 100644 (file)
@@ -47,6 +47,7 @@
 #include <dali/internal/update/manager/frame-callback-processor.h>
 #include <dali/internal/update/manager/render-task-processor.h>
 #include <dali/internal/update/manager/sorted-layers.h>
+#include <dali/internal/update/manager/scene-graph-frame-callback.h>
 #include <dali/internal/update/manager/update-algorithms.h>
 #include <dali/internal/update/manager/update-manager-debug.h>
 #include <dali/internal/update/manager/transform-manager.h>
@@ -1102,7 +1103,7 @@ bool UpdateManager::IsDefaultSurfaceRectChanged()
   return surfaceRectChanged;
 }
 
-void UpdateManager::AddFrameCallback( FrameCallbackInterface* frameCallback, const Node* rootNode )
+void UpdateManager::AddFrameCallback( OwnerPointer< FrameCallback >& frameCallback, const Node* rootNode )
 {
   mImpl->GetFrameCallbackProcessor().AddFrameCallback( frameCallback, rootNode );
 }
index 401eb8b..f35e816 100644 (file)
@@ -34,6 +34,7 @@
 #include <dali/internal/update/common/scene-graph-property-notification.h>
 #include <dali/internal/update/nodes/node.h>
 #include <dali/internal/update/nodes/scene-graph-layer.h>
+#include <dali/internal/update/manager/scene-graph-frame-callback.h> // for OwnerPointer< FrameCallback >
 #include <dali/internal/update/rendering/scene-graph-renderer.h>  // for OwnerPointer< Renderer >
 #include <dali/internal/update/rendering/scene-graph-texture-set.h> // for OwnerPointer< TextureSet >
 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
@@ -614,10 +615,10 @@ public:
 
   /**
    * Adds an implementation of the FrameCallbackInterface.
-   * @param[in] frameCallback A pointer to the implementation of the FrameCallbackInterface
+   * @param[in] frameCallback An OwnerPointer to the SceneGraph FrameCallback object
    * @param[in] rootNode A pointer to the root node to apply the FrameCallback to
    */
-  void AddFrameCallback( FrameCallbackInterface* frameCallback, const Node* rootNode );
+  void AddFrameCallback( OwnerPointer< FrameCallback >& frameCallback, const Node* rootNode );
 
   /**
    * Removes the specified implementation of FrameCallbackInterface.
@@ -1352,15 +1353,15 @@ inline void AddResetterMessage( UpdateManager& manager, OwnerPointer<PropertyRes
   new (slot) LocalType( &manager, &UpdateManager::AddPropertyResetter, resetter );
 }
 
-inline void AddFrameCallbackMessage( UpdateManager& manager, FrameCallbackInterface& frameCallback, const Node& rootNode )
+inline void AddFrameCallbackMessage( UpdateManager& manager, OwnerPointer< FrameCallback >& frameCallback, const Node& rootNode )
 {
-  typedef MessageValue2< UpdateManager, FrameCallbackInterface*, const Node* > LocalType;
+  typedef MessageValue2< UpdateManager, OwnerPointer< FrameCallback >, const Node* > LocalType;
 
   // Reserve some memory inside the message queue
   uint32_t* slot = manager.ReserveMessageSlot( sizeof( LocalType ) );
 
   // Construct message in the message queue memory; note that delete should not be called on the return value
-  new (slot) LocalType( &manager, &UpdateManager::AddFrameCallback, &frameCallback, &rootNode );
+  new (slot) LocalType( &manager, &UpdateManager::AddFrameCallback, frameCallback, &rootNode );
 }
 
 inline void RemoveFrameCallbackMessage( UpdateManager& manager, FrameCallbackInterface& frameCallback )