Fix the synchronization issue when window is resized or rotated 29/248429/15
authorWonsik Jung <sidein@samsung.com>
Thu, 26 Nov 2020 10:47:10 +0000 (19:47 +0900)
committerWonsik Jung <sidein@samsung.com>
Sat, 23 Jan 2021 23:59:59 +0000 (08:59 +0900)
Window position, size and rotaton angle information are in both main and update thread.
To complete the works, the information should be synchronized in both main and update thread.
In addition, when multiple windows works and one of them resized or rotated, all windows are resized or rotated.
For fixing them, this patch has the informations are in the related modules (as Intergration::Scene, SceneGraph::Scene ... )
and are compared.

Change-Id: I79f12b8f7e15ce2ae07f161959f3450e65f2f1a0

13 files changed:
automated-tests/src/dali/utc-Dali-Scene.cpp
dali/integration-api/core.h
dali/integration-api/scene.cpp
dali/integration-api/scene.h
dali/internal/common/core-impl.cpp
dali/internal/event/common/scene-impl.cpp
dali/internal/event/common/scene-impl.h
dali/internal/render/common/render-manager.cpp
dali/internal/render/common/render-manager.h
dali/internal/update/common/scene-graph-scene.cpp
dali/internal/update/common/scene-graph-scene.h
dali/internal/update/manager/update-manager.cpp
dali/internal/update/manager/update-manager.h

index 688f7c3..bbfb401 100644 (file)
@@ -921,10 +921,18 @@ int UtcDaliSceneSurfaceResizedDefaultSceneViewport(void)
   auto defaultScene = application.GetScene();
   DALI_TEST_CHECK(defaultScene);
 
+  // consume the resize flag by first rendering
+  defaultScene.IsSurfaceRectChanged();
+
   // Ensure stage size matches the scene size
   auto stage = Stage::GetCurrent();
   DALI_TEST_EQUALS(stage.GetSize(), defaultScene.GetSize(), TEST_LOCATION);
 
+  bool surfaceResized;
+  // check resized flag before surface is resized.
+  surfaceResized = defaultScene.IsSurfaceRectChanged();
+  DALI_TEST_EQUALS(surfaceResized, false, TEST_LOCATION);
+
   // Resize the scene
   Vector2     newSize(1000.0f, 2000.0f);
   std::string viewportParams("0, 0, 1000, 2000"); // to match newSize
@@ -938,6 +946,9 @@ int UtcDaliSceneSurfaceResizedDefaultSceneViewport(void)
   application.SendNotification();
   application.Render(0);
 
+  surfaceResized = defaultScene.IsSurfaceRectChanged();
+  DALI_TEST_EQUALS(surfaceResized, true, TEST_LOCATION);
+
   // Check that the viewport is handled properly
   DALI_TEST_CHECK(callStack.FindMethodAndGetParameters("Viewport", viewportParams));
 
index 686a1ec..4952c57 100644 (file)
@@ -81,7 +81,6 @@ public:
   UpdateStatus()
   : keepUpdating(false),
     needsNotification(false),
-    surfaceRectChanged(false),
     secondsFromLastFrame(0.0f)
   {
   }
@@ -107,15 +106,6 @@ public:
   }
 
   /**
-   * Query wheter the default surface rect is changed or not.
-   * @return true if the default surface rect is changed.
-   */
-  bool SurfaceRectChanged()
-  {
-    return surfaceRectChanged;
-  }
-
-  /**
    * This method is provided so that FPS can be easily calculated with a release version
    * of Core.
    * @return the seconds from last frame as float
@@ -128,7 +118,6 @@ public:
 public:
   uint32_t keepUpdating; ///< A bitmask of KeepUpdating values
   bool     needsNotification;
-  bool     surfaceRectChanged;
   float    secondsFromLastFrame;
 };
 
index 8650fea..bbe1139 100644 (file)
@@ -161,6 +161,11 @@ void Scene::SurfaceRotated(float width, float height, int orientation)
   GetImplementation(*this).SurfaceRotated(width, height, orientation);
 }
 
+bool Scene::IsSurfaceRectChanged() const
+{
+  return GetImplementation(*this).IsSurfaceRectChanged();
+}
+
 Scene::EventProcessingFinishedSignalType& Scene::EventProcessingFinishedSignal()
 {
   return GetImplementation(*this).EventProcessingFinishedSignal();
index d5920da..eeb191f 100644 (file)
@@ -294,6 +294,12 @@ public:
   void SurfaceRotated(float width, float height, int orientation);
 
   /**
+   * Query wheter the surface rect is changed or not.
+   * @return true if the surface rect is changed.
+   */
+  bool IsSurfaceRectChanged() const;
+
+  /**
    * @brief This signal is emitted just after the event processing is finished.
    *
    * @return The signal to connect to
index 9b5c071..41adba0 100644 (file)
@@ -207,9 +207,6 @@ void Core::Update(float elapsedSeconds, uint32_t lastVSyncTimeMilliseconds, uint
   // Check the Notification Manager message queue to set needsNotification
   status.needsNotification = mNotificationManager->MessagesToProcess();
 
-  // Check if the default surface is changed
-  status.surfaceRectChanged = mUpdateManager->IsDefaultSurfaceRectChanged();
-
   // No need to keep update running if there are notifications to process.
   // Any message to update will wake it up anyways
 }
index 4ab5142..e4aa616 100755 (executable)
@@ -131,14 +131,13 @@ void Scene::Initialize(Size size, int orientation)
   // Create the default render-task and ensure clear is enabled on it to show the background color
   RenderTaskPtr renderTask = mRenderTaskList->CreateTask( mRootLayer.Get(), mDefaultCamera.Get() );
   renderTask->SetClearEnabled(true);
-  mSurfaceOrientation = orientation;
-
-  SurfaceRotated( size.width, size.height, mSurfaceOrientation );
 
   // Create scene graph object
   mSceneObject = new SceneGraph::Scene();
   OwnerPointer< SceneGraph::Scene > transferOwnership( const_cast< SceneGraph::Scene* >( mSceneObject ) );
   AddSceneMessage( updateManager, transferOwnership );
+
+  SurfaceRotated( size.width, size.height, orientation );
 }
 
 void Scene::Add(Actor& actor)
@@ -294,7 +293,6 @@ int Scene::GetSurfaceOrientation()
 void Scene::ChangedSurface(float width, float height, int orientation)
 {
   Rect<int32_t> newSize(0, 0, static_cast<int32_t>(width), static_cast<int32_t>(height)); // truncated
-
   mSize.width  = width;
   mSize.height = height;
 
@@ -305,18 +303,21 @@ void Scene::ChangedSurface(float width, float height, int orientation)
 
   mRootLayer->SetSize(width, height);
 
+  // Send the surface rectangle/orientation to SceneGraph::Scene for calculating glViewport/Scissor
   ThreadLocalStorage*        tls           = ThreadLocalStorage::GetInternal();
-  SceneGraph::UpdateManager& updateManager = tls->GetUpdateManager();
-  SetDefaultSurfaceRectMessage(updateManager, newSize);
-
-  // Send the surface orientation to render manager for calculating glViewport/Scissor
-  SetDefaultSurfaceOrientationMessage(updateManager, orientation);
+  SetSurfaceRectMessage(tls->GetEventThreadServices(), *mSceneObject, newSize);
+  SetSurfaceOrientationMessage(tls->GetEventThreadServices(), *mSceneObject, static_cast<int32_t>(orientation));
 
   // set default render-task viewport parameters
   RenderTaskPtr defaultRenderTask = mRenderTaskList->GetTask(0u);
   defaultRenderTask->SetViewport(newSize);
 }
 
+bool Scene::IsSurfaceRectChanged() const
+{
+  return mSceneObject->IsSurfaceRectChanged();
+}
+
 bool Scene::EmitKeyEventGeneratedSignal(const Dali::KeyEvent& event)
 {
   // Emit the KeyEventGenerated signal when KeyEvent is generated
index 01e4b47..1346448 100644 (file)
@@ -252,6 +252,11 @@ public:
   int GetSurfaceOrientation();
 
   /**
+   * @copydoc Dali::Integration::Scene::IsSurfaceRectChanged
+   */
+  bool IsSurfaceRectChanged() const;
+
+  /**
    * Used by the EventProcessor to emit key event signals.
    * @param[in] event The key event.
    */
index f132736..027deb7 100644 (file)
@@ -69,7 +69,6 @@ struct RenderManager::Impl
     renderAlgorithms(),
     frameCount(0u),
     renderBufferIndex(SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX),
-    defaultSurfaceRect(),
     rendererContainer(),
     samplerContainer(),
     textureContainer(),
@@ -78,8 +77,7 @@ struct RenderManager::Impl
     programController(graphicsController),
     depthBufferAvailable(depthBufferAvailableParam),
     stencilBufferAvailable(stencilBufferAvailableParam),
-    partialUpdateAvailable(partialUpdateAvailableParam),
-    defaultSurfaceOrientation(0)
+    partialUpdateAvailable(partialUpdateAvailableParam)
   {
     // Create thread pool with just one thread ( there may be a need to create more threads in the future ).
     threadPool = std::unique_ptr<Dali::ThreadPool>(new Dali::ThreadPool());
@@ -152,8 +150,6 @@ struct RenderManager::Impl
   uint32_t    frameCount;        ///< The current frame count
   BufferIndex renderBufferIndex; ///< The index of the buffer to read from; this is opposite of the "update" buffer
 
-  Rect<int32_t> defaultSurfaceRect; ///< Rectangle for the default surface we are rendering to
-
   OwnerContainer<Render::Renderer*>     rendererContainer;     ///< List of owned renderers
   OwnerContainer<Render::Sampler*>      samplerContainer;      ///< List of owned samplers
   OwnerContainer<Render::Texture*>      textureContainer;      ///< List of owned textures
@@ -174,8 +170,6 @@ struct RenderManager::Impl
   std::unique_ptr<Dali::ThreadPool> threadPool;            ///< The thread pool
   Vector<GLuint>                    boundTextures;         ///< The textures bound for rendering
   Vector<GLuint>                    textureDependencyList; ///< The dependency list of binded textures
-
-  int defaultSurfaceOrientation; ///< defaultSurfaceOrientation for the default surface we are rendering to
 };
 
 RenderManager* RenderManager::New(Graphics::Controller&               graphicsController,
@@ -250,16 +244,6 @@ void RenderManager::SetShaderSaver(ShaderSaver& upstream)
   mImpl->programController.SetShaderSaver(upstream);
 }
 
-void RenderManager::SetDefaultSurfaceRect(const Rect<int32_t>& rect)
-{
-  mImpl->defaultSurfaceRect = rect;
-}
-
-void RenderManager::SetDefaultSurfaceOrientation(int orientation)
-{
-  mImpl->defaultSurfaceOrientation = orientation;
-}
-
 void RenderManager::AddRenderer(OwnerPointer<Render::Renderer>& renderer)
 {
   // Initialize the renderer as we are now in render thread
@@ -601,7 +585,7 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector<Rect<int>>&
     bool                    mCleanOnReturn;
   };
 
-  Rect<int32_t> surfaceRect = Rect<int32_t>(0, 0, static_cast<int32_t>(scene.GetSize().width), static_cast<int32_t>(scene.GetSize().height));
+  Rect<int32_t> surfaceRect = sceneObject->GetSurfaceRect();
 
   // Clean collected dirty/damaged rects on exit if 3d layer or 3d node or other conditions.
   DamagedRectsCleaner damagedRectCleaner(damagedRects);
@@ -822,10 +806,11 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
       clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR;
     }
 
-    Rect<int32_t>                       surfaceRect            = mImpl->defaultSurfaceRect;
+    Rect<int32_t> surfaceRect = sceneObject->GetSurfaceRect();
+    int32_t surfaceOrientation = sceneObject->GetSurfaceOrientation();
+
     Integration::DepthBufferAvailable   depthBufferAvailable   = mImpl->depthBufferAvailable;
     Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable;
-    int                                 surfaceOrientation     = sceneInternal.GetSurfaceOrientation();
 
     if(instruction.mFrameBuffer)
     {
@@ -857,8 +842,6 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::
           mImpl->programController.ClearCurrentProgram();
         }
       }
-
-      surfaceRect = Rect<int32_t>(0, 0, static_cast<int32_t>(scene.GetSize().width), static_cast<int32_t>(scene.GetSize().height));
     }
 
     // Make sure that GL context must be created
index 0e48c76..e3b2297 100644 (file)
@@ -120,18 +120,6 @@ public:
   void SetFrameDeltaTime(float deltaTime);
 
   /**
-   * Returns the rectangle for the default surface (probably the application window).
-   * @return Rectangle for the surface.
-   */
-  void SetDefaultSurfaceRect(const Rect<int>& rect);
-
-  /**
-   * Returns the orintation for the default surface (probably the application window).
-   * @param[in] orientation the surface's orientation.
-   */
-  void SetDefaultSurfaceOrientation(int orientation);
-
-  /**
    * Add a Renderer to the render manager.
    * @param[in] renderer The renderer to add.
    * @post renderer is owned by RenderManager
@@ -411,7 +399,6 @@ public:
   void PostRender(bool uploadOnly);
 
 private:
-private:
   /**
    * Construct a new RenderManager.
    */
index fa14393..0d80de2 100644 (file)
@@ -32,7 +32,10 @@ Scene::Scene()
 : mContext( nullptr ),
   mFrameRenderedCallbacks(),
   mFramePresentedCallbacks(),
-  mSkipRendering( false )
+  mSkipRendering( false ),
+  mSurfaceRect(),
+  mSurfaceOrientation( 0 ),
+  mSurfaceRectChanged( false )
 {
 }
 
@@ -99,6 +102,35 @@ bool Scene::IsRenderingSkipped() const
   return mSkipRendering;
 }
 
+void Scene::SetSurfaceRect( const Rect<int32_t>& rect )
+{
+  mSurfaceRect = rect;
+  mSurfaceRectChanged = true;
+}
+
+const Rect<int32_t>& Scene::GetSurfaceRect() const
+{
+  return mSurfaceRect;
+}
+
+void Scene::SetSurfaceOrientation( int32_t orientation )
+{
+  mSurfaceOrientation = orientation;
+}
+
+int32_t Scene::GetSurfaceOrientation() const
+{
+  return mSurfaceOrientation;
+}
+
+bool Scene::IsSurfaceRectChanged()
+{
+  bool surfaceRectChanged = mSurfaceRectChanged;
+  mSurfaceRectChanged = false;
+
+  return surfaceRectChanged;
+}
+
 } //SceneGraph
 
 } //Internal
index 140d49a..230eea5 100644 (file)
@@ -127,6 +127,42 @@ public:
    */
   bool IsRenderingSkipped() const;
 
+  /**
+   * Set the surface rectangle when surface is resized.
+   *
+   * @param[in] scene The resized scene.
+   * @param[in] rect The retangle representing the surface.
+   */
+  void SetSurfaceRect( const Rect<int32_t>& rect );
+
+  /**
+   * Get the surface rectangle.
+   *
+   * @return the current surface rectangle
+   */
+  const Rect<int32_t>& GetSurfaceRect() const;
+
+  /**
+   * Set the surface orientation when surface is rotated.
+   *
+   * @param[in] scene The rotated scene.
+   * @param[in] orientation The orientation value representing the surface.
+   */
+  void SetSurfaceOrientation( int32_t orientation );
+
+  /**
+   * Get the surface orientation.
+   *
+   * @return the current surface orientation
+   */
+  int32_t GetSurfaceOrientation() const;
+
+  /**
+   * Query wheter the surface rect is changed or not.
+   * @return true if the surface rect is changed.
+   */
+  bool IsSurfaceRectChanged();
+
 private:
 
   Context*                    mContext;   ///< The context holding the GL state of rendering for the scene, not owned
@@ -140,6 +176,10 @@ private:
   Dali::Integration::Scene::FrameCallbackContainer mFramePresentedCallbacks;  ///< Frame presented callbacks
 
   bool                        mSkipRendering;  ///< A flag to skip rendering
+
+  Rect<int32_t>               mSurfaceRect;           ///< The rectangle of surface which is related ot this scene.
+  int32_t                     mSurfaceOrientation;    ///< The orientation of surface which is related of this scene
+  bool                        mSurfaceRectChanged;    ///< The flag of surface's rectangle is changed when is resized, moved or rotated.
 };
 
 /// Messages
@@ -165,6 +205,28 @@ inline void AddFramePresentedCallbackMessage( EventThreadServices& eventThreadSe
   new (slot) LocalType( &scene, &Scene::AddFramePresentedCallback, const_cast< CallbackBase* >( callback ), frameId );
 }
 
+inline void SetSurfaceRectMessage( EventThreadServices& eventThreadServices, const Scene& scene, const Rect<int32_t>& rect )
+{
+  using LocalType = MessageValue1<Scene, Rect<int32_t> >;
+
+  // Reserve some memory inside the message queue
+  uint32_t* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new (slot) LocalType( &scene, &Scene::SetSurfaceRect, rect );
+}
+
+inline void SetSurfaceOrientationMessage( EventThreadServices& eventThreadServices, const Scene& scene, int32_t orientation )
+{
+  using LocalType = MessageValue1<Scene, int32_t>;
+
+  // Reserve some memory inside the message queue
+  uint32_t* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new (slot) LocalType( &scene, &Scene::SetSurfaceOrientation, orientation );
+}
+
 } // namespace SceneGraph
 
 } // namespace Internal
index f60bbdf..171665f 100644 (file)
@@ -189,7 +189,6 @@ struct UpdateManager::Impl
     previousUpdateScene( false ),
     renderTaskWaiting( false ),
     renderersAdded( false ),
-    surfaceRectChanged( false ),
     renderingRequired( false )
   {
     sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue );
@@ -298,7 +297,6 @@ struct UpdateManager::Impl
   bool                                 previousUpdateScene;           ///< True if the scene was updated in the previous frame (otherwise it was optimized out)
   bool                                 renderTaskWaiting;             ///< A REFRESH_ONCE render task is waiting to be rendered
   bool                                 renderersAdded;                ///< Flag to keep track when renderers have been added to avoid unnecessary processing
-  bool                                 surfaceRectChanged;            ///< True if the default surface rect is changed
   bool                                 renderingRequired;             ///< True if required to render the current frame
 
 private:
@@ -1129,19 +1127,6 @@ uint32_t UpdateManager::KeepUpdatingCheck( float elapsedSeconds ) const
   return keepUpdatingRequest;
 }
 
-void UpdateManager::SetDefaultSurfaceRect( const Rect<int32_t>& rect )
-{
-  mImpl->surfaceRectChanged = true;
-
-  using DerivedType = MessageValue1<RenderManager, Rect<int32_t> >;
-
-  // Reserve some memory inside the render queue
-  uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
-
-  // Construct message in the render queue memory; note that delete should not be called on the return value
-  new (slot) DerivedType( &mImpl->renderManager,  &RenderManager::SetDefaultSurfaceRect, rect );
-}
-
 void UpdateManager::SurfaceReplaced( Scene* scene )
 {
   using DerivedType = MessageValue1<RenderManager, Scene*>;
@@ -1153,17 +1138,6 @@ void UpdateManager::SurfaceReplaced( Scene* scene )
   new (slot) DerivedType( &mImpl->renderManager,  &RenderManager::SurfaceReplaced, scene );
 }
 
-void UpdateManager::SetDefaultSurfaceOrientation(int orientation)
-{
-  using DerivedType = MessageValue1<RenderManager, int>;
-
-  // Reserve some memory inside the render queue
-  unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
-
-  // Construct message in the render queue memory; note that delete should not be called on the return value
-  new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetDefaultSurfaceOrientation, orientation);
-}
-
 void UpdateManager::KeepRendering( float durationSeconds )
 {
   mImpl->keepRenderingSeconds = std::max( mImpl->keepRenderingSeconds, durationSeconds );
@@ -1210,16 +1184,6 @@ void UpdateManager::SetDepthIndices( OwnerPointer< NodeDepths >& nodeDepths )
   }
 }
 
-bool UpdateManager::IsDefaultSurfaceRectChanged()
-{
-  bool surfaceRectChanged = mImpl->surfaceRectChanged;
-
-  // Reset the flag
-  mImpl->surfaceRectChanged = false;
-
-  return surfaceRectChanged;
-}
-
 void UpdateManager::AddFrameCallback( OwnerPointer< FrameCallback >& frameCallback, const Node* rootNode )
 {
   mImpl->GetFrameCallbackProcessor( *this ).AddFrameCallback( frameCallback, rootNode );
index b966cfc..881b844 100644 (file)
@@ -603,18 +603,6 @@ public:
                   bool     isRenderingToFbo);
 
   /**
-   * Set the default surface rect.
-   * @param[in] rect The rect value representing the surface.
-   */
-  void SetDefaultSurfaceRect(const Rect<int>& rect);
-
-  /**
-   * Set the default surface orientation.
-   * @param[in] orientation The orientation value representing the surface.
-   */
-  void SetDefaultSurfaceOrientation(int orientation);
-
-  /**
    * @copydoc Dali::Stage::KeepRendering()
    */
   void KeepRendering(float durationSeconds);
@@ -646,12 +634,6 @@ public:
   void SetDepthIndices(OwnerPointer<NodeDepths>& nodeDepths);
 
   /**
-   * Query wheter the default surface rect is changed or not.
-   * @return true if the default surface rect is changed.
-   */
-  bool IsDefaultSurfaceRectChanged();
-
-  /**
    * Adds an 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
@@ -1048,18 +1030,7 @@ inline void SetShaderProgramMessage(UpdateManager&          manager,
   new(slot) LocalType(&manager, &UpdateManager::SetShaderProgram, const_cast<Shader*>(&shader), shaderData, modifiesGeometry);
 }
 
-inline void SetDefaultSurfaceRectMessage(UpdateManager& manager, const Rect<int32_t>& rect)
-{
-  using LocalType = MessageValue1<UpdateManager, Rect<int32_t> >;
-
-  // 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::SetDefaultSurfaceRect, rect);
-}
-
-inline void SurfaceReplacedMessage(UpdateManager& manager, const SceneGraph::Scene& constScene)
+inline void SurfaceReplacedMessage( UpdateManager& manager, const SceneGraph::Scene& constScene )
 {
   // The scene-graph thread owns this object so it can safely edit it.
   Scene& scene = const_cast<Scene&>(constScene);
@@ -1073,18 +1044,7 @@ inline void SurfaceReplacedMessage(UpdateManager& manager, const SceneGraph::Sce
   new(slot) LocalType(&manager, &UpdateManager::SurfaceReplaced, &scene);
 }
 
-inline void SetDefaultSurfaceOrientationMessage(UpdateManager& manager, int orientation)
-{
-  using LocalType = MessageValue1<UpdateManager, int>;
-
-  // Reserve some memory inside the message queue
-  unsigned int* 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::SetDefaultSurfaceOrientation, orientation);
-}
-
-inline void KeepRenderingMessage(UpdateManager& manager, float durationSeconds)
+inline void KeepRenderingMessage( UpdateManager& manager, float durationSeconds )
 {
   using LocalType = MessageValue1<UpdateManager, float>;