Fix SceneView Capture Signal 76/316076/7
authorSeungho Baek <sbsh.baek@samsung.com>
Tue, 13 Aug 2024 08:08:59 +0000 (17:08 +0900)
committerSeungho Baek <sbsh.baek@samsung.com>
Fri, 16 Aug 2024 04:02:11 +0000 (13:02 +0900)
 - SceneView Capture Finished Signal uses CaptureResult struct as a return parameter.
 - It is not easy to use.
 - Remove State and check success or fail by using nullcheck of ImageUrl

Change-Id: I32b885d93c670d5ad90601872e47f8c4fd6c03f9
Signed-off-by: Seungho Baek <sbsh.baek@samsung.com>
automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp
dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp
dali-scene3d/internal/controls/scene-view/scene-view-impl.h
dali-scene3d/public-api/controls/scene-view/scene-view.h

index cef724d1c42797cc3869d299a8b6afb7aefbdb2a..bc9baaa4ab3a7963489db8d0f62b7b3efb45ca9d 100644 (file)
@@ -1202,30 +1202,26 @@ int UtcDaliSceneViewMasking(void)
 
 namespace
 {
-static bool                                   gCaptureFinishedCalled{false};
-static int32_t                                gCaptureId{-1};
-static Toolkit::ImageUrl                      gCapturedImageUrl;
-static Scene3D::SceneView::CaptureFinishState gCaptureFinishState{Scene3D::SceneView::CaptureFinishState::FAILED};
+static bool              gCaptureFinishedCalled{false};
+static int32_t           gCaptureId{-1};
+static Toolkit::ImageUrl gCapturedImageUrl;
 
-void OnCaptureFinished(Scene3D::SceneView sceneView, Scene3D::SceneView::CaptureResult& captureResult)
+void OnCaptureFinished(Scene3D::SceneView sceneView, int32_t captureId, const Toolkit::ImageUrl& capturedImageUrl)
 {
   gCaptureFinishedCalled = true;
-  gCaptureId             = captureResult.captureId;
-  gCapturedImageUrl      = captureResult.imageUrl;
-  gCaptureFinishState    = captureResult.state;
+  gCaptureId             = captureId;
+  gCapturedImageUrl      = capturedImageUrl;
 }
 
 static int32_t                                             gCapturedCount{0};
 static std::vector<int32_t>                                gCaptureIds;
 static std::vector<Toolkit::ImageUrl>                      gCapturedImageUrls;
-static std::vector<Scene3D::SceneView::CaptureFinishState> gCaptureFinishStates;
 
-void OnCaptureMultipleFinished(Scene3D::SceneView sceneView, Scene3D::SceneView::CaptureResult& captureResult)
+void OnCaptureMultipleFinished(Scene3D::SceneView sceneView, int32_t captureId, const Toolkit::ImageUrl& capturedImageUrl)
 {
   gCapturedCount++;
-  gCaptureIds.push_back(captureResult.captureId);
-  gCapturedImageUrls.push_back(captureResult.imageUrl);
-  gCaptureFinishStates.push_back(captureResult.state);
+  gCaptureIds.push_back(captureId);
+  gCapturedImageUrls.push_back(capturedImageUrl);
 }
 } // namespace
 
@@ -1265,7 +1261,6 @@ int UtcDaliSceneViewCapture01(void)
   gCaptureFinishedCalled = false;
   gCaptureId = -1;
   gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
   int32_t captureId = view.Capture(camera, Vector2(300, 300));
 
   application.SendNotification();
@@ -1276,15 +1271,14 @@ int UtcDaliSceneViewCapture01(void)
 
   DALI_TEST_EQUALS(gCaptureFinishedCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gCaptureId, captureId, TEST_LOCATION);
+  DALI_TEST_EQUALS(!!gCapturedImageUrl, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gCapturedImageUrl.GetUrl().empty(), false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishState, Scene3D::SceneView::CaptureFinishState::SUCCEEDED, TEST_LOCATION);
 
   Toolkit::ImageUrl tempImageUrl = gCapturedImageUrl;
 
   gCaptureFinishedCalled = false;
   gCaptureId = -1;
   gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
   int32_t captureId2 = view.Capture(camera, Vector2(400, 400));
 
   application.SendNotification();
@@ -1296,9 +1290,9 @@ int UtcDaliSceneViewCapture01(void)
   DALI_TEST_EQUALS(gCaptureFinishedCalled, true, TEST_LOCATION);
   DALI_TEST_NOT_EQUALS(captureId, captureId2, 0.1f, TEST_LOCATION);
   DALI_TEST_EQUALS(gCaptureId, captureId2, TEST_LOCATION);
+  DALI_TEST_EQUALS(!!gCapturedImageUrl, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gCapturedImageUrl.GetUrl().empty(), false, TEST_LOCATION);
   DALI_TEST_NOT_EQUALS(gCapturedImageUrl, tempImageUrl, 0.1f, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishState, Scene3D::SceneView::CaptureFinishState::SUCCEEDED, TEST_LOCATION);
 
   END_TEST;
 }
@@ -1339,7 +1333,6 @@ int UtcDaliSceneViewCaptureCancel(void)
   gCaptureFinishedCalled = false;
   gCaptureId = -1;
   gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
   int32_t captureId = view.Capture(camera, Vector2(300, 300));
 
   view.Unparent();
@@ -1347,13 +1340,11 @@ int UtcDaliSceneViewCaptureCancel(void)
   DALI_TEST_EQUALS(gCaptureFinishedCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gCaptureId, captureId, TEST_LOCATION);
   DALI_TEST_EQUALS(!!gCapturedImageUrl, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishState, Scene3D::SceneView::CaptureFinishState::FAILED, TEST_LOCATION);
 
 
   gCaptureFinishedCalled = false;
   gCaptureId = -1;
   gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
 
   application.SendNotification();
   application.Render();
@@ -1402,7 +1393,6 @@ int UtcDaliSceneViewCaptureFailed(void)
   gCaptureFinishedCalled = false;
   gCaptureId = -1;
   gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
   int32_t captureId = view.Capture(camera, Vector2(300, 300));
 
   Test::EmitGlobalTimerSignal();
@@ -1412,12 +1402,10 @@ int UtcDaliSceneViewCaptureFailed(void)
   DALI_TEST_EQUALS(gCaptureFinishedCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gCaptureId, captureId, TEST_LOCATION);
   DALI_TEST_EQUALS(!!gCapturedImageUrl, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishState, Scene3D::SceneView::CaptureFinishState::FAILED, TEST_LOCATION);
 
   gCaptureFinishedCalled = false;
   gCaptureId = -1;
   gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
 
   application.SendNotification();
   application.Render();
@@ -1466,7 +1454,6 @@ int UtcDaliSceneViewCapture02(void)
   gCapturedCount = 0;
   gCaptureIds.clear();
   gCapturedImageUrls.clear();
-  gCaptureFinishStates.clear();
   int32_t captureId = view.Capture(camera, Vector2(300, 300));
   int32_t captureId2 = view.Capture(camera, Vector2(300, 300));
 
@@ -1486,9 +1473,9 @@ int UtcDaliSceneViewCapture02(void)
   DALI_TEST_EQUALS(isIter2, true, TEST_LOCATION);
 
   DALI_TEST_EQUALS(gCapturedImageUrls.size(), 2, TEST_LOCATION);
+  DALI_TEST_EQUALS(!!gCapturedImageUrls[0], true, TEST_LOCATION);
+  DALI_TEST_EQUALS(!!gCapturedImageUrls[1], true, TEST_LOCATION);
   DALI_TEST_NOT_EQUALS(gCapturedImageUrls[0], gCapturedImageUrls[1], 0.1f, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishStates[0], Scene3D::SceneView::CaptureFinishState::SUCCEEDED, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishStates[1], Scene3D::SceneView::CaptureFinishState::SUCCEEDED, TEST_LOCATION);
 
   END_TEST;
 }
index ff774d60fd80fafb717166c700770b3027caecaf..71c02025b680916d43182b27632e96136a0b9254 100644 (file)
@@ -363,6 +363,13 @@ SceneView::~SceneView()
       ResetTransition();
     }
 
+    for(auto&& capture : mCaptureContainer)
+    {
+      ResetCaptureData(capture.second);
+    }
+    mCaptureContainer.clear();
+    ResetCaptureTimer();
+
     // Request image resource GC
     Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
   }
@@ -902,14 +909,14 @@ Quaternion SceneView::GetSkyboxOrientation() const
 
 int32_t SceneView::Capture(Dali::CameraActor camera, const Vector2& size)
 {
-  if(size.x <= 0.0f || size.y <= 0.0f)
+  if(size.x < 0.0f || size.y < 0.0f)
   {
     DALI_LOG_ERROR("The width and height should be positive.\n");
     return INVALID_CAPTURE_ID;
   }
 
-  uint32_t width = unsigned(size.width);
-  uint32_t height = unsigned(size.height);
+  uint32_t width = std::max(1u, unsigned(size.width));
+  uint32_t height = std::max(1u, unsigned(size.height));
   if(width > Dali::GetMaxTextureSize() || height > Dali::GetMaxTextureSize())
   {
     DALI_LOG_ERROR("The input size is too large.\n");
@@ -934,13 +941,17 @@ int32_t SceneView::Capture(Dali::CameraActor camera, const Vector2& size)
   DevelFrameBuffer::SetMultiSamplingLevel(captureData->mCaptureFrameBuffer, mFrameBufferMultiSamplingLevel);
   captureData->mCaptureFrameBuffer.AttachColorTexture(captureData->mCaptureTexture);
 
+  captureData->mCaptureCamera = camera;
+  captureData->mCaptureCameraOriginalAspectRatio = captureData->mCaptureCamera.GetAspectRatio();
+  captureData->mCaptureCamera.SetAspectRatio((float)width/(float)height);
+
   RenderTaskList taskList   = mSceneHolder.GetRenderTaskList();
   captureData->mCaptureTask = taskList.CreateTask();
   captureData->mCaptureTask.SetSourceActor(mRootLayer);
   captureData->mCaptureTask.SetExclusive(true);
   captureData->mCaptureTask.SetCullMode(false);
   captureData->mCaptureTask.SetOrderIndex(SCENE_ORDER_INDEX + 1);
-  captureData->mCaptureTask.SetCameraActor(camera);
+  captureData->mCaptureTask.SetCameraActor(captureData->mCaptureCamera);
   captureData->mCaptureTask.SetFrameBuffer(captureData->mCaptureFrameBuffer);
   captureData->mCaptureTask.SetClearEnabled(true);
   captureData->mCaptureTask.SetClearColor(Color::TRANSPARENT);
@@ -1191,33 +1202,17 @@ void SceneView::OnSceneDisconnection()
   std::vector<std::pair<Dali::RenderTask, std::shared_ptr<CaptureData>>> tempContainer(mCaptureContainer);
   for(auto&& capture : tempContainer)
   {
-    Dali::Scene3D::SceneView::CaptureResult result{capture.second->mCaptureId, Dali::Toolkit::ImageUrl(), Dali::Scene3D::SceneView::CaptureFinishState::FAILED};
-    mCaptureFinishedSignal.Emit(handle, result);
+    mCaptureFinishedSignal.Emit(handle, capture.second->mCaptureId, Dali::Toolkit::ImageUrl());
   }
   tempContainer.clear();
 
   for(auto && capture : mCaptureContainer)
   {
-    if(mSceneHolder)
-    {
-      RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
-      taskList.RemoveTask(capture.second->mCaptureTask);
-      taskList.RemoveTask(capture.second->mCaptureInvertTask);
-    }
-    capture.second->mCaptureTask.Reset();
-    capture.second->mCaptureInvertTask.Reset();
-    capture.second->mCaptureTexture.Reset();
-    capture.second->mCaptureInvertTexture.Reset();
-    capture.second->mCaptureFrameBuffer.Reset();
-    capture.second->mCaptureInvertFrameBuffer.Reset();
-    capture.second->mCaptureUrl.Reset();
-    capture.second->mCaptureImageView.Unparent();
-    capture.second->mCaptureImageView.Reset();
-    capture.second->mCaptureInvertCamera.Unparent();
-    capture.second->mCaptureInvertCamera.Reset();
+    ResetCaptureData(capture.second);
   }
   mCaptureContainer.clear();
 
+  ResetCaptureTimer();
 
   if(mSceneHolder)
   {
@@ -1637,36 +1632,18 @@ void SceneView::OnCaptureFinished(Dali::RenderTask& task)
 
   if(iter != mCaptureContainer.end())
   {
-    captureId               = iter->second->mCaptureId;
-    imageUrl                = Dali::Toolkit::ImageUrl::New(iter->second->mCaptureInvertTexture);
-    if(mSceneHolder)
-    {
-      RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
-      taskList.RemoveTask(iter->second->mCaptureTask);
-      taskList.RemoveTask(iter->second->mCaptureInvertTask);
-    }
-    iter->second->mCaptureTexture.Reset();
-    iter->second->mCaptureInvertTexture.Reset();
-    iter->second->mCaptureFrameBuffer.Reset();
-    iter->second->mCaptureInvertFrameBuffer.Reset();
-    iter->second->mCaptureUrl.Reset();
-    iter->second->mCaptureImageView.Unparent();
-    iter->second->mCaptureImageView.Reset();
+    captureId = iter->second->mCaptureId;
+    imageUrl  = Dali::Toolkit::ImageUrl::New(iter->second->mCaptureInvertTexture);
+
+    ResetCaptureData(iter->second);
     mCaptureContainer.erase(iter);
 
     auto                     self = Self();
     Dali::Scene3D::SceneView handle(Dali::Scene3D::SceneView::DownCast(self));
-
-    Dali::Scene3D::SceneView::CaptureResult result{captureId, imageUrl, Dali::Scene3D::SceneView::CaptureFinishState::SUCCEEDED};
-    mCaptureFinishedSignal.Emit(handle, result);
+    mCaptureFinishedSignal.Emit(handle, captureId, imageUrl);
   }
 
-  if(mCaptureContainer.empty() && mCaptureTimer)
-  {
-    mCaptureTimer.Stop();
-    mCaptureTimer.Reset();
-    mTimerTickCount = 0;
-  }
+  ResetCaptureTimer();
 }
 
 bool SceneView::OnTimeOut()
@@ -1685,10 +1662,15 @@ bool SceneView::OnTimeOut()
 
   for(auto&& capture : tempContainer)
   {
-    Dali::Scene3D::SceneView::CaptureResult result{capture.second->mCaptureId, Dali::Toolkit::ImageUrl(), Dali::Scene3D::SceneView::CaptureFinishState::FAILED};
-    mCaptureFinishedSignal.Emit(handle, result);
+    mCaptureFinishedSignal.Emit(handle, capture.second->mCaptureId, Dali::Toolkit::ImageUrl());
   }
 
+  for(auto && capture : tempContainer)
+  {
+    ResetCaptureData(capture.second);
+  }
+  tempContainer.clear();
+
   int32_t tickCount = mTimerTickCount;
   auto it = std::remove_if(mCaptureContainer.begin(), mCaptureContainer.end(), [tickCount](std::pair<Dali::RenderTask, std::shared_ptr<CaptureData>> item) {
     return item.second->mStartTick + 1 < tickCount;
@@ -1696,12 +1678,7 @@ bool SceneView::OnTimeOut()
   mCaptureContainer.erase(it, mCaptureContainer.end());
   mCaptureContainer.shrink_to_fit();
 
-  if(mCaptureContainer.empty() && mCaptureTimer)
-  {
-    mCaptureTimer.Stop();
-    mCaptureTimer.Reset();
-    mTimerTickCount = 0;
-  }
+  ResetCaptureTimer();
 
   return !mCaptureContainer.empty();
 }
@@ -1869,6 +1846,38 @@ void SceneView::OnTransitionFinished(Animation& animation)
   mCameraTransitionFinishedSignal.Emit(handle);
 }
 
+void SceneView::ResetCaptureData(std::shared_ptr<CaptureData> captureData)
+{
+  captureData->mCaptureCamera.SetAspectRatio(captureData->mCaptureCameraOriginalAspectRatio);
+  if(mSceneHolder)
+  {
+    RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
+    taskList.RemoveTask(captureData->mCaptureTask);
+    taskList.RemoveTask(captureData->mCaptureInvertTask);
+  }
+  captureData->mCaptureTask.Reset();
+  captureData->mCaptureInvertTask.Reset();
+  captureData->mCaptureTexture.Reset();
+  captureData->mCaptureInvertTexture.Reset();
+  captureData->mCaptureFrameBuffer.Reset();
+  captureData->mCaptureInvertFrameBuffer.Reset();
+  captureData->mCaptureUrl.Reset();
+  captureData->mCaptureImageView.Unparent();
+  captureData->mCaptureImageView.Reset();
+  captureData->mCaptureInvertCamera.Unparent();
+  captureData->mCaptureInvertCamera.Reset();
+}
+
+void SceneView::ResetCaptureTimer()
+{
+  if(mCaptureContainer.empty() && mCaptureTimer)
+  {
+    mCaptureTimer.Stop();
+    mCaptureTimer.Reset();
+    mTimerTickCount = 0;
+  }
+}
+
 void SceneView::Process(bool postProcessor)
 {
   CameraActor selectedCamera = GetSelectedCamera();
index ccc98e9a17773b4f47f84b68a18d6f98bec18329..316b47a382d7f307aea931ec22020ccb82b77a74 100644 (file)
@@ -54,6 +54,28 @@ namespace Internal
  */
 class SceneView : public Dali::Toolkit::Internal::Control, public Integration::Processor
 {
+
+private:
+  /**
+   * Data to store Capture related objects.
+   */
+  struct CaptureData
+  {
+    int32_t                  mStartTick;
+    int32_t                  mCaptureId;                        // Unique Key to distinguish requested Captures.
+    float                    mCaptureCameraOriginalAspectRatio; // Original AspectRatio of the input cameras
+    Dali::Toolkit::ImageUrl  mCaptureUrl;                       // URL for first captured buffer, but it is Y-inverted.
+    Dali::Toolkit::ImageView mCaptureImageView;                 // ImageView to draw first capture buffer to be transfered as input for invert.
+    Dali::CameraActor        mCaptureCamera;                    // CameraActor to draw first capture buffer
+    Dali::RenderTask         mCaptureTask;                      // RenderTask that is used to capture first buffer.
+    Dali::Texture            mCaptureTexture;                   // First Captured texture, but it is Y-inverted.
+    Dali::FrameBuffer        mCaptureFrameBuffer;               // First Captured FBO, but it is Y-inverted.
+    Dali::CameraActor        mCaptureInvertCamera;              // CameraActor to invert first captured buffer by second pass.
+    Dali::RenderTask         mCaptureInvertTask;                // RenderTask to invert first captured buffer.
+    Dali::Texture            mCaptureInvertTexture;             // Result texture of second pass. This is final Texture result.
+    Dali::FrameBuffer        mCaptureInvertFrameBuffer;         // FBO for firnal Texture result
+  };
+
 public:
   /**
    * @brief Creates a new SceneView.
@@ -499,6 +521,17 @@ private:
    */
   void OnTransitionFinished(Animation& animation);
 
+  /**
+   * @brief Reset CaptureData when the capture is finished or failed.
+   * @param[in] captureData CaptureData to be reset.
+   */
+  void ResetCaptureData(std::shared_ptr<CaptureData> captureData);
+
+  /**
+   * @brief Reset Capture timer when there isn't any capture in progress.
+   */
+  void ResetCaptureTimer();
+
 private: // Implementation of Processor
 
   /**
@@ -517,25 +550,6 @@ private: // Implementation of Processor
     return "SceneViewImpl";
   }
 
-private:
-  /**
-   * Data to store Capture related objects.
-   */
-  struct CaptureData
-  {
-    int32_t                  mStartTick;
-    int32_t                  mCaptureId;                // Unique Key to distinguish requested Captures.
-    Dali::Toolkit::ImageUrl  mCaptureUrl;               // URL for first captured buffer, but it is Y-inverted.
-    Dali::Toolkit::ImageView mCaptureImageView;         // ImageView to draw first capture buffer to be transfered as input for invert.
-    Dali::RenderTask         mCaptureTask;              // RenderTask that is used to capture first buffer.
-    Dali::Texture            mCaptureTexture;           // First Captured texture, but it is Y-inverted.
-    Dali::FrameBuffer        mCaptureFrameBuffer;       // First Captured FBO, but it is Y-inverted.
-    Dali::CameraActor        mCaptureInvertCamera;      // CameraActor to invert first captured buffer by second pass.
-    Dali::RenderTask         mCaptureInvertTask;        // RenderTask to invert first captured buffer.
-    Dali::Texture            mCaptureInvertTexture;     // Result texture of second pass. This is final Texture result.
-    Dali::FrameBuffer        mCaptureInvertFrameBuffer; // FBO for firnal Texture result
-  };
-
   Toolkit::Visual::Base mVisual;
 
   /////////////////////////////////////////////////////////////
index 88a21a0ef7d7a39267107a37b484755a11f7e0e8..4e72412cbb09ed3c91355e183b7976b05bbd50c1 100644 (file)
@@ -152,30 +152,14 @@ public:
     };
   };
 
-  /**
-   * @brief The enumerations used for checking capture success
-   * @SINCE_2_3.25
-   */
-  enum class CaptureFinishState
-  {
-    SUCCEEDED, ///< Succeeded to capture
-    FAILED     ///< Failed to capture by time out
-  };
-
 public:
-  struct CaptureResult
-  {
-    int32_t                 captureId;
-    Dali::Toolkit::ImageUrl imageUrl;
-    CaptureFinishState      state;
-  };
 
   /**
    * @brief Typedef for capture finished signals sent by this class.
    *
-   * @SINCE_2_3.25
+   * @SINCE_2_3.37
    */
-  typedef Signal<void(SceneView, CaptureResult&)> CaptureFinishedSignalType;
+  typedef Signal<void(SceneView, int32_t, const Dali::Toolkit::ImageUrl&)> CaptureFinishedSignalType;
 
   /**
    * @brief Typedef for camera transition finished signals sent by this class.
@@ -555,7 +539,9 @@ public:
    * @SINCE_2_3.25
    * @param[in] camera CameraActor to be used for capture.
    * @param[in] size captured size.
-   * @note The camera is required to be added in this SceneView. (Not need to be a selected camera)
+   * @note The input camera should not be used for any other purpose during Capture.
+   * (Simultaneous usage elsewhere may result in incorrect rendering.)
+   * @note The camera is required to be added in this SceneView. (But should not be a selected camera.)
    * @note If the SceneView is disconnected from Scene, the left capture requests are canceled.
    * @return capture id that id unique value to distinguish each requiest.
    */