(CanvasView) Retry rasterization again if last rasterization failed 18/320618/10
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 19 Nov 2024 10:36:07 +0000 (19:36 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Mon, 25 Nov 2024 02:06:40 +0000 (11:06 +0900)
Let we retry canvas rasterizing if last commit was failed.

Change-Id: Id8cc862f0c640ed34567e54a6f8218ad5578ddae
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor-impl.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-async-task-manager.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-canvas-renderer.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-canvas-renderer.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-CanvasView.cpp
dali-toolkit/internal/controls/canvas-view/canvas-view-impl.cpp
dali-toolkit/internal/controls/canvas-view/canvas-view-impl.h

index f4a61f82b3ac8cedee0bfadeeb4f6c3c8e89b313..e56a83c48b876c63a32abec54bb2691412de201b 100644 (file)
@@ -72,6 +72,7 @@ public:
   void RunIdles();
 
   void RequestUpdateOnce();
+  void RequestProcessEventsOnIdle();
 
   static Integration::Scene GetScene(Dali::Window window);
 
index 488d2d6d43eef2ae793b6e4727c25d077473ea86..7291db8b864048005609ec55758bba4c22b90118 100644 (file)
@@ -114,11 +114,9 @@ bool Adaptor::AddIdle(CallbackBase* callback, bool hasReturnValue)
 
 void Adaptor::RemoveIdle(CallbackBase* callback)
 {
-  mCallbacks.Erase(std::remove_if(mCallbacks.Begin(), mCallbacks.End(), [&callback](CallbackBase* current)
-                                  { return callback == current; }),
+  mCallbacks.Erase(std::remove_if(mCallbacks.Begin(), mCallbacks.End(), [&callback](CallbackBase* current) { return callback == current; }),
                    mCallbacks.End());
-  mReturnCallbacks.Erase(std::remove_if(mReturnCallbacks.Begin(), mReturnCallbacks.End(), [&callback](CallbackBase* current)
-                                        { return callback == current; }),
+  mReturnCallbacks.Erase(std::remove_if(mReturnCallbacks.Begin(), mReturnCallbacks.End(), [&callback](CallbackBase* current) { return callback == current; }),
                          mReturnCallbacks.End());
 }
 
@@ -156,6 +154,19 @@ void Adaptor::RequestUpdateOnce()
   }
 }
 
+void Adaptor::RequestProcessEventsOnIdle()
+{
+  if(mTestApplication)
+  {
+    tet_printf("Adaptor::RequestProcessEventsOnIdle()\n");
+
+    // Note that, toolkit-adaptor is not subclass of RenderController.
+    // So we should call this function directly.
+    auto& renderController = mTestApplication->GetRenderController();
+    renderController.RequestProcessEventsOnIdle();
+  }
+}
+
 Dali::Integration::RenderSurfaceInterface& Adaptor::GetSurface()
 {
   DALI_ASSERT_ALWAYS(!mWindows.empty());
@@ -413,6 +424,11 @@ void Adaptor::SceneCreated()
 {
 }
 
+void Adaptor::RequestProcessEventsOnIdle()
+{
+  mImpl->RequestProcessEventsOnIdle();
+}
+
 class LogFactory : public LogFactoryInterface
 {
 public:
index c6922a59f26dc85b94f9cd4eec033192d42df810..2f0ecbcd59982f9d1d113f9bea5f96ef96d10f29 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -154,6 +154,7 @@ private:
   Dali::Mutex mWaitingTasksMutex;   ///< Mutex for mWaitingTasks. We can lock mRunningTasksMutex and mCompletedTasksMutex under this scope.
   Dali::Mutex mRunningTasksMutex;   ///< Mutex for mRunningTasks. We can lock mCompletedTasksMutex under this scope.
   Dali::Mutex mCompletedTasksMutex; ///< Mutex for mCompletedTasks. We cannot lock any mutex under this scope.
+  Dali::Mutex mTasksMutex;          ///< Mutex for mTasks.        We cannot lock any mutex under this scope.
 
   std::unique_ptr<EventThreadCallback> mTrigger;
 
@@ -678,18 +679,23 @@ void AsyncTaskManager::AddTask(AsyncTaskPtr task)
     }
   }
 
-  size_t count = mTasks.GetElementCount();
-  size_t index = 0;
-  while(index++ < count)
   {
-    auto processHelperIt = mTasks.GetNext();
-    DALI_ASSERT_ALWAYS(processHelperIt != mTasks.End());
-    if(processHelperIt->Request())
+    Mutex::ScopedLock lock(mTasksMutex);
+    size_t            count = mTasks.GetElementCount();
+    size_t            index = 0;
+    while(index++ < count)
     {
-      break;
+      auto processHelperIt = mTasks.GetNext();
+      DALI_ASSERT_ALWAYS(processHelperIt != mTasks.End());
+      if(processHelperIt->Request())
+      {
+        break;
+      }
+      // If all threads are busy, then it's ok just to push the task because they will try to get the next job.
     }
-    // If all threads are busy, then it's ok just to push the task because they will try to get the next job.
   }
+
+  // Note : We will not use Processor for toolkit utc
 }
 
 void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
@@ -924,16 +930,32 @@ AsyncTaskPtr AsyncTaskManager::PopNextTaskToProcess()
   {
     if((*iter)->IsReady())
     {
-      nextTask = *iter;
+      bool taskAvaliable = true;
 
-      // Add Running queue
+      // Check whether we try to running same task at multiple threads.
       {
-        // Lock while popping task out from the queue
         Mutex::ScopedLock lock(mRunningTasksMutex); // We can lock this mutex under mWaitingTasksMutex.
+        auto              task = *iter;
+        auto              jter = std::find_if(mRunningTasks.begin(), mRunningTasks.end(), [task](const AsyncRunningTaskPair& element) { return element.first == task; });
+        if(jter != mRunningTasks.end())
+        {
+          taskAvaliable = false;
+        }
+      }
+
+      if(taskAvaliable)
+      {
+        nextTask = *iter;
+
+        // Add Running queue
+        {
+          // Lock while popping task out from the queue
+          Mutex::ScopedLock lock(mRunningTasksMutex); // We can lock this mutex under mWaitingTasksMutex.
 
-        mRunningTasks.insert(mRunningTasks.end(), std::make_pair(nextTask, RunningTaskState::RUNNING));
+          mRunningTasks.insert(mRunningTasks.end(), std::make_pair(nextTask, RunningTaskState::RUNNING));
 
-        mWaitingTasks.erase(iter);
+          mWaitingTasks.erase(iter);
+        }
       }
       break;
     }
@@ -945,52 +967,64 @@ AsyncTaskPtr AsyncTaskManager::PopNextTaskToProcess()
 /// Worker thread called
 void AsyncTaskManager::CompleteTask(AsyncTaskPtr&& task)
 {
-  bool notify = false;
-
   if(task)
   {
     bool needTrigger = false;
 
-    // Lock while check validation of task.
+    // Check now whether we need to execute callback or not, for worker thread cases.
+    if(task->GetCallbackInvocationThread() == AsyncTask::ThreadType::WORKER_THREAD)
     {
-      Mutex::ScopedLock lock(mRunningTasksMutex);
+      bool notify = false;
 
-      auto iter = std::find_if(mRunningTasks.begin(), mRunningTasks.end(), [task](const AsyncRunningTaskPair& element) { return element.first == task; });
-      if(iter != mRunningTasks.end())
+      // Lock while check validation of task.
       {
-        if(iter->second == RunningTaskState::RUNNING)
+        Mutex::ScopedLock lock(mRunningTasksMutex);
+
+        auto iter = std::find_if(mRunningTasks.begin(), mRunningTasks.end(), [task](const AsyncRunningTaskPair& element) { return element.first == task; });
+        if(iter != mRunningTasks.end())
         {
-          // This task is valid.
-          notify = true;
+          if(iter->second == RunningTaskState::RUNNING)
+          {
+            // This task is valid.
+            notify = true;
+          }
         }
       }
-    }
-
-    // We should execute this tasks complete callback out of mutex
-    if(notify && task->GetCallbackInvocationThread() == AsyncTask::ThreadType::WORKER_THREAD)
-    {
-      CallbackBase::Execute(*(task->GetCompletedCallback()), task);
 
-      // We need to remove task trace now.
-      if(mTasksCompletedImpl->IsTasksCompletedCallbackExist())
+      // We should execute this tasks complete callback out of mutex
+      if(notify)
       {
-        mTasksCompletedImpl->RemoveTaskTrace(task);
+        CallbackBase::Execute(*(task->GetCompletedCallback()), task);
 
-        if(mTasksCompletedImpl->IsExecuteCallbackExist())
+        // We need to remove task trace now.
+        if(mTasksCompletedImpl->IsTasksCompletedCallbackExist())
         {
-          // We need to call EmitCompletedTasks(). Trigger main thread.
-          needTrigger = true;
+          mTasksCompletedImpl->RemoveTaskTrace(task);
+
+          if(mTasksCompletedImpl->IsExecuteCallbackExist())
+          {
+            // We need to call EmitCompletedTasks(). Trigger main thread.
+            needTrigger = true;
+          }
         }
       }
     }
 
     // Lock while adding task to the queue
     {
+      bool notify = false;
+
       Mutex::ScopedLock lock(mRunningTasksMutex);
 
       auto iter = std::find_if(mRunningTasks.begin(), mRunningTasks.end(), [task](const AsyncRunningTaskPair& element) { return element.first == task; });
       if(iter != mRunningTasks.end())
       {
+        if(iter->second == RunningTaskState::RUNNING)
+        {
+          // This task is valid.
+          notify = true;
+        }
+
         // Move task into completed, for ensure that AsyncTask destroy at main thread.
         {
           Mutex::ScopedLock lock(mCompletedTasksMutex); // We can lock this mutex under mRunningTasksMutex.
@@ -1098,13 +1132,13 @@ void DestroyAsyncTaskManager()
   Dali::Internal::Adaptor::gAsyncTaskManager.Reset();
 }
 
-void ProcessSingleCompletedTask()
+void ProcessSingleCompletedTasks()
 {
   auto asyncTaskManager = Dali::AsyncTaskManager::Get();
   Dali::Internal::Adaptor::GetImplementation(asyncTaskManager).TaskCompleted();
 }
 
-void ProcessAllCompletedTask()
+void ProcessAllCompletedTasks()
 {
   auto asyncTaskManager = Dali::AsyncTaskManager::Get();
   Dali::Internal::Adaptor::GetImplementation(asyncTaskManager).TaskAllCompleted();
index 726648a0499136523e7f5a920a86f400e292b9fd..a0b3564bd128c374e2900571a5d5aa578f58b101 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
  *
  */
 
-#include <dali/devel-api/adaptor-framework/canvas-renderer/canvas-renderer.h>
 #include <dali/devel-api/adaptor-framework/canvas-renderer/canvas-renderer-drawable.h>
+#include <dali/devel-api/adaptor-framework/canvas-renderer/canvas-renderer.h>
 #include <dali/public-api/object/base-object.h>
 #include <dali/public-api/rendering/renderer.h>
+#include <sys/stat.h>
 #include <toolkit-application.h>
 #include <toolkit-event-thread-callback.h>
-#include <memory>
 #include <cstring>
-#include <sys/stat.h>
+#include <memory>
 
+namespace
+{
+bool gRasterizeCalled = false;
+bool gRasterizeResult = true; ///< Default rasterization result as success
+} // namespace
 namespace Dali
 {
-
 namespace Internal
 {
-
 namespace Adaptor
 {
-
-class CanvasRenderer: public Dali::BaseObject
+class CanvasRenderer : public Dali::BaseObject
 {
 public:
-  CanvasRenderer( const Vector2& size )
+  CanvasRenderer(const Vector2& size)
   : mDrawable(nullptr),
-    mTexture ( Dali::Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, size.width, size.height ) ),
+    mTexture(Dali::Texture::New(Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, size.width, size.height)),
     mSize(size),
     mViewBox(size)
   {
@@ -51,12 +53,12 @@ public:
 
   bool Commit()
   {
-     return true;
+    return true;
   }
 
   bool IsCanvasChanged() const
   {
-     return true;
+    return true;
   }
 
   Dali::Texture GetRasterizedTexture()
@@ -66,12 +68,13 @@ public:
 
   bool Rasterize()
   {
-     return true;
+    gRasterizeCalled = true;
+    return gRasterizeResult;
   }
 
   bool AddDrawable(Dali::CanvasRenderer::Drawable& drawable)
   {
-    if (!drawable)
+    if(!drawable)
     {
       return false;
     }
@@ -81,11 +84,11 @@ public:
 
   bool RemoveDrawable(Dali::CanvasRenderer::Drawable& drawable)
   {
-    if (!drawable)
+    if(!drawable)
     {
       return false;
     }
-    if (mDrawable == &drawable)
+    if(mDrawable == &drawable)
     {
       mDrawable = nullptr;
       return true;
@@ -95,7 +98,7 @@ public:
 
   bool RemoveAllDrawables()
   {
-    if (mDrawable)
+    if(mDrawable)
     {
       return true;
     }
@@ -106,7 +109,7 @@ public:
   {
     mSize = size;
     // For negative test
-    if ( size.width == -999 && size.height == -999 )
+    if(size.width == -999 && size.height == -999)
     {
       return false;
     }
@@ -122,7 +125,7 @@ public:
   {
     mViewBox = viewBox;
     // For negative test
-    if ( viewBox.width == -999 && viewBox.height == -999 )
+    if(viewBox.width == -999 && viewBox.height == -999)
     {
       return false;
     }
@@ -135,40 +138,39 @@ public:
   }
 
 public:
-   Dali::CanvasRenderer::Drawable* mDrawable;
-   Dali::Texture mTexture;
-   Vector2 mSize;
-   Vector2 mViewBox;
+  Dali::CanvasRenderer::Drawable* mDrawable;
+  Dali::Texture                   mTexture;
+  Vector2                         mSize;
+  Vector2                         mViewBox;
 };
 
-inline CanvasRenderer& GetImplementation( Dali::CanvasRenderer& renderer )
+inline CanvasRenderer& GetImplementation(Dali::CanvasRenderer& renderer)
 {
-  DALI_ASSERT_ALWAYS( renderer && "CanvasRenderer handle is empty." );
+  DALI_ASSERT_ALWAYS(renderer && "CanvasRenderer handle is empty.");
   BaseObject& handle = renderer.GetBaseObject();
-  return static_cast< Internal::Adaptor::CanvasRenderer& >( handle );
+  return static_cast<Internal::Adaptor::CanvasRenderer&>(handle);
 }
 
-inline const CanvasRenderer& GetImplementation( const Dali::CanvasRenderer& renderer )
+inline const CanvasRenderer& GetImplementation(const Dali::CanvasRenderer& renderer)
 {
-  DALI_ASSERT_ALWAYS( renderer && "CanvasRenderer handle is empty." );
+  DALI_ASSERT_ALWAYS(renderer && "CanvasRenderer handle is empty.");
   const BaseObject& handle = renderer.GetBaseObject();
-  return static_cast< const Internal::Adaptor::CanvasRenderer& >( handle );
+  return static_cast<const Internal::Adaptor::CanvasRenderer&>(handle);
 }
 
 } // namespace Adaptor
 
 } // namespace Internal
 
-
 /********************************************************************************/
 /*********************************  PUBLIC CLASS  *******************************/
 /********************************************************************************/
 
-CanvasRenderer CanvasRenderer::New( const Vector2& size )
+CanvasRenderer CanvasRenderer::New(const Vector2& size)
 {
   Internal::Adaptor::CanvasRenderer* imageRenderer = new Internal::Adaptor::CanvasRenderer(size);
 
-  return CanvasRenderer( imageRenderer );
+  return CanvasRenderer(imageRenderer);
 }
 
 CanvasRenderer::CanvasRenderer()
@@ -179,8 +181,8 @@ CanvasRenderer::~CanvasRenderer()
 {
 }
 
-CanvasRenderer::CanvasRenderer( Internal::Adaptor::CanvasRenderer* internal )
-: BaseHandle( internal )
+CanvasRenderer::CanvasRenderer(Internal::Adaptor::CanvasRenderer* internal)
+: BaseHandle(internal)
 {
 }
 
@@ -240,3 +242,21 @@ const Vector2& CanvasRenderer::GetViewBox()
 }
 
 } // namespace Dali
+
+namespace Test::CanvasRenderer
+{
+void MarkRasterizationResult(bool result)
+{
+  gRasterizeResult = result;
+}
+
+void ResetRasterizationFlag()
+{
+  gRasterizeCalled = false;
+}
+
+bool IsRasterizationCalled()
+{
+  return gRasterizeCalled;
+}
+} // namespace Test::CanvasRenderer
\ No newline at end of file
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-canvas-renderer.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-canvas-renderer.h
new file mode 100644 (file)
index 0000000..1087fb6
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef DALI_TOOLKIT_TOOLKIT_CANVAS_RENDERER_H
+#define DALI_TOOLKIT_TOOLKIT_CANVAS_RENDERER_H
+
+/*
+ * Copyright (c) 2024 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 <dali/public-api/adaptor-framework/async-task-manager.h>
+
+namespace Test::CanvasRenderer
+{
+// Set global rasterization result for CanvaseRender Rasterize() function.
+void MarkRasterizationResult(bool result);
+
+// Reset CanvaseRender Rasterize() function called signal.
+void ResetRasterizationFlag();
+
+// Get CanvaseRender Rasterize() function called or not.
+bool IsRasterizationCalled();
+
+} // namespace Test::CanvasRenderer
+
+#endif // DALI_TOOLKIT_TOOLKIT_CANVAS_RENDERER_H
index febdf970e24512bcb0b4fb66dd9445d23ccd2403..e0bbdb4cb6bad15d76c30da5e712253952f06278 100644 (file)
@@ -18,6 +18,7 @@
 #include <stdlib.h>
 #include <iostream>
 
+#include <toolkit-canvas-renderer.h>
 #include <toolkit-event-thread-callback.h>
 #include <toolkit-timer.h>
 
@@ -43,10 +44,18 @@ namespace
 void utc_dali_toolkit_canvasview_startup(void)
 {
   test_return_value = TET_UNDEF;
+
+  // Make sure we clean up test result before start.
+  Test::CanvasRenderer::MarkRasterizationResult(true);
+  Test::CanvasRenderer::ResetRasterizationFlag();
 }
 
 void utc_dali_toolkit_canvasview_cleanup(void)
 {
+  // Make sure we clean up test result after finish.
+  Test::CanvasRenderer::MarkRasterizationResult(true);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
   test_return_value = TET_PASS;
 }
 
@@ -271,11 +280,14 @@ int UtcDaliCanvasViewSizeN(void)
   END_TEST;
 }
 
+namespace
+{
 bool gRasterizationCompletedSignal = false;
 void rasteriztionCompleted(IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task)
 {
   gRasterizationCompletedSignal = true;
 }
+} // namespace
 
 int UtcDaliCanvasViewRasterizeTaskP(void)
 {
@@ -341,16 +353,6 @@ int UtcDaliCanvasViewRasterizeTaskAddRemoveTaskP(void)
   END_TEST;
 }
 
-PixelData CreatePixelData(unsigned int width, unsigned int height)
-{
-  unsigned int bufferSize = width * height * Pixel::GetBytesPerPixel(Pixel::RGBA8888);
-
-  unsigned char* buffer    = reinterpret_cast<unsigned char*>(malloc(bufferSize));
-  PixelData      pixelData = PixelData::New(buffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::FREE);
-
-  return pixelData;
-}
-
 int UtcDaliCanvasViewRasterizeThreadRasterizationCompletedSignalP(void)
 {
   ToolkitTestApplication application;
@@ -511,10 +513,12 @@ int UtcDaliCanvasViewRasterizationRequestManually(void)
   CanvasView canvasView = CanvasView::New(Vector2(300, 300));
   DALI_TEST_CHECK(canvasView);
 
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
   application.GetScene().Add(canvasView);
 
   canvasView.SetProperty(Actor::Property::SIZE, Vector2(300, 300));
-  canvasView.SetProperty(Toolkit::CanvasView::Property::SYNCHRONOUS_LOADING, false);
+  canvasView.SetProperty(Toolkit::CanvasView::Property::SYNCHRONOUS_LOADING, true);
 
   Dali::CanvasRenderer::Shape shape = Dali::CanvasRenderer::Shape::New();
 
@@ -526,7 +530,8 @@ int UtcDaliCanvasViewRasterizationRequestManually(void)
   application.Render();
 
   // Rasterization occured
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
 
   bool isRasterizationManually = canvasView.GetProperty(Toolkit::CanvasView::Property::RASTERIZATION_REQUEST_MANUALLY).Get<bool>();
   DALI_TEST_EQUALS(isRasterizationManually, false, TEST_LOCATION);
@@ -540,8 +545,8 @@ int UtcDaliCanvasViewRasterizationRequestManually(void)
   application.Render();
 
   // Check if the canvasView is rasterized.
-  // Rasterization occured
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
 
   canvasView.SetProperty(Toolkit::CanvasView::Property::RASTERIZATION_REQUEST_MANUALLY, true);
 
@@ -550,7 +555,11 @@ int UtcDaliCanvasViewRasterizationRequestManually(void)
 
   // Rasterization occured
   // (Note that we cannot 'cancel' the latest rasterization request even if we set RASTERIZATION_REQUEST_MANUALLY to true)
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  application.SendNotification();
+  application.Render();
 
   isRasterizationManually = canvasView.GetProperty(Toolkit::CanvasView::Property::RASTERIZATION_REQUEST_MANUALLY).Get<bool>();
   DALI_TEST_EQUALS(isRasterizationManually, true, TEST_LOCATION);
@@ -560,7 +569,8 @@ int UtcDaliCanvasViewRasterizationRequestManually(void)
   application.Render();
 
   // Check if the canvasView is not rasterized.
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 0), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), false, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
 
   Dali::CanvasRenderer::Shape shape2 = Dali::CanvasRenderer::Shape::New();
 
@@ -572,16 +582,209 @@ int UtcDaliCanvasViewRasterizationRequestManually(void)
   application.Render();
 
   // Check whether the canvasView is not rasterized even if we add drawables.
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), false, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  // Request rasterize manually
+  canvasView.RequestRasterization();
+
+  application.SendNotification();
+  application.Render();
+
+  // Check if the canvasView is rasterized.
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  END_TEST;
+}
+
+int UtcDaliCanvasViewRasterizationRequestIfRasterizeFailed01(void)
+{
+  tet_infoline("Test rasterization failed case for synchronous loading mode.");
+  ToolkitTestApplication application;
+
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  CanvasView canvasView = CanvasView::New(Vector2(300, 300));
+  DALI_TEST_CHECK(canvasView);
+
+  application.GetScene().Add(canvasView);
+
+  canvasView.SetProperty(Actor::Property::SIZE, Vector2(300, 300));
+  canvasView.SetProperty(Toolkit::CanvasView::Property::SYNCHRONOUS_LOADING, true);
+  canvasView.SetProperty(Toolkit::CanvasView::Property::RASTERIZATION_REQUEST_MANUALLY, true);
+
+  Dali::CanvasRenderer::Shape shape = Dali::CanvasRenderer::Shape::New();
+
+  shape.AddRect(Rect<float>(10, 10, 10, 10), Vector2(0, 0));
+
+  canvasView.AddDrawable(shape);
+
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  // Rasterization occured
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  application.SendNotification();
+  application.Render();
+
+  // Check whether the canvasView is not rasterized.
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), false, TEST_LOCATION);
+
+  // Make rasterization failed.
+  Test::CanvasRenderer::MarkRasterizationResult(false);
+
+  shape.AddRect(Rect<float>(10, 10, 10, 10), Vector2(0, 0));
+
+  canvasView.AddDrawable(shape);
+
+  // Request rasterize manually
+  canvasView.RequestRasterization();
+
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  // Check if the canvasView is rasterized.
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  application.SendNotification();
+  application.Render();
+
+  // Check if the canvasView is rasterized again automatically.
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  application.SendNotification();
+  application.Render();
+
+  // Check if the canvasView is rasterized again automatically.
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  // Make rasterization success.
+  Test::CanvasRenderer::MarkRasterizationResult(true);
+
+  application.SendNotification();
+  application.Render();
+
+  // Check if the canvasView is rasterized.
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  application.SendNotification();
+  application.Render();
+
+  // Check whether the canvasView is not rasterized again.
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), false, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliCanvasViewRasterizationRequestIfRasterizeFailed02(void)
+{
+  tet_infoline("Test rasterization failed case for async loading mode.");
+  ToolkitTestApplication application;
+
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  CanvasView canvasView = CanvasView::New(Vector2(300, 300));
+  DALI_TEST_CHECK(canvasView);
+
+  application.GetScene().Add(canvasView);
+
+  canvasView.SetProperty(Actor::Property::SIZE, Vector2(300, 300));
+  canvasView.SetProperty(Toolkit::CanvasView::Property::SYNCHRONOUS_LOADING, false);
+  canvasView.SetProperty(Toolkit::CanvasView::Property::RASTERIZATION_REQUEST_MANUALLY, true);
+
+  Dali::CanvasRenderer::Shape shape = Dali::CanvasRenderer::Shape::New();
+
+  shape.AddRect(Rect<float>(10, 10, 10, 10), Vector2(0, 0));
+
+  canvasView.AddDrawable(shape);
+
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  // Rasterization occured
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  application.SendNotification();
+  application.Render();
+
+  // Check whether the canvasView is not rasterized.
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 0), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), false, TEST_LOCATION);
+
+  // Make rasterization failed.
+  Test::CanvasRenderer::MarkRasterizationResult(false);
+
+  shape.AddRect(Rect<float>(10, 10, 10, 10), Vector2(0, 0));
+
+  canvasView.AddDrawable(shape);
 
   // Request rasterize manually
   canvasView.RequestRasterization();
 
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), false, TEST_LOCATION);
+
   application.SendNotification();
   application.Render();
 
   // Check if the canvasView is rasterized.
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  application.SendNotification();
+  application.Render();
+
+  // Check if the canvasView is rasterized again automatically.
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  application.SendNotification();
+  application.Render();
+
+  // Check if the canvasView is rasterized again automatically.
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  // Make rasterization success.
+  Test::CanvasRenderer::MarkRasterizationResult(true);
+
+  application.SendNotification();
+  application.Render();
+
+  // Check if the canvasView is rasterized.
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), true, TEST_LOCATION);
+  Test::CanvasRenderer::ResetRasterizationFlag();
+
+  application.SendNotification();
+  application.Render();
+
+  // Check whether the canvasView is not rasterized again.
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 0), false, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(Test::CanvasRenderer::IsRasterizationCalled(), false, TEST_LOCATION);
+
   END_TEST;
 }
index 1b3cae79a68f46fbdffcab1433522dd960603c46..8079ba4582bfd664e062dc12882b7ff2b3838373 100644 (file)
@@ -19,6 +19,7 @@
 #include "canvas-view-impl.h"
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/common/stage.h>
 #include <dali/devel-api/rendering/texture-devel.h>
 #include <dali/devel-api/scripting/scripting.h>
 #include <dali/integration-api/adaptor-framework/adaptor.h>
@@ -61,7 +62,8 @@ CanvasView::CanvasView(const Vector2& viewBox)
   mSize(viewBox),
   mIsSynchronous(true),
   mManualRasterization(false),
-  mProcessorRegistered(false)
+  mProcessorRegistered(false),
+  mLastCommitRasterized(false)
 {
 }
 
@@ -201,25 +203,42 @@ Property::Value CanvasView::GetProperty(BaseObject* object, Property::Index prop
 
 void CanvasView::Process(bool postProcessor)
 {
+  bool rasterizeRequired = false;
+
   mProcessorRegistered = false;
 
-  if(mCanvasRenderer && mCanvasRenderer.IsCanvasChanged() && mSize.width > 0 && mSize.height > 0)
+  if(mCanvasRenderer && mSize.width > 0 && mSize.height > 0)
   {
-    AddRasterizationTask();
+    const bool forcibleRasterization = (mIsSynchronous && !mLastCommitRasterized);
+    rasterizeRequired                = (forcibleRasterization) || (mCanvasRenderer.IsCanvasChanged());
+
+    if(rasterizeRequired)
+    {
+      AddRasterizationTask(forcibleRasterization);
+    }
   }
 
+  const bool isSynchronousRasterizationFailed = (rasterizeRequired && mIsSynchronous && !mLastCommitRasterized);
+
   // If we are not doing manual rasterization, register processor once again.
   // TODO : Could we reqest it only if IsCanvasChagned() is true?
-  if(!mManualRasterization)
+  if(!mManualRasterization || isSynchronousRasterizationFailed)
   {
     RequestRasterization();
+
+    if(isSynchronousRasterizationFailed && DALI_LIKELY(Adaptor::IsAvailable()))
+    {
+      // To make sure we will process next time.
+      Adaptor::Get().RequestProcessEventsOnIdle();
+    }
   }
 }
 
-void CanvasView::AddRasterizationTask()
+void CanvasView::AddRasterizationTask(bool forceProcess)
 {
-  if(mCanvasRenderer && mCanvasRenderer.Commit())
+  if(mCanvasRenderer && (mCanvasRenderer.Commit() || forceProcess))
   {
+    mLastCommitRasterized = false;
     if(mIsSynchronous)
     {
       CanvasRendererRasterizingTaskPtr rasterizingTask = new CanvasRendererRasterizingTask(mCanvasRenderer, MakeCallback(this, &CanvasView::ApplyRasterizedImage));
@@ -229,18 +248,24 @@ void CanvasView::AddRasterizationTask()
     }
     else
     {
-      if(!mRasterizingTask)
+      if(mRasterizingTask)
       {
-        mRasterizingTask = new CanvasRendererRasterizingTask(mCanvasRenderer, MakeCallback(this, &CanvasView::ApplyRasterizedImage));
-        AsyncTaskManager::Get().AddTask(mRasterizingTask);
+        // Cancel previous request task.
+        AsyncTaskManager::Get().RemoveTask(mRasterizingTask);
+        mRasterizingTask.Reset();
       }
+
+      mRasterizingTask = new CanvasRendererRasterizingTask(mCanvasRenderer, MakeCallback(this, &CanvasView::ApplyRasterizedImage));
+      AsyncTaskManager::Get().AddTask(mRasterizingTask);
     }
   }
 }
 
 void CanvasView::ApplyRasterizedImage(CanvasRendererRasterizingTaskPtr task)
 {
-  if(task->IsRasterized())
+  mLastCommitRasterized = task->IsRasterized();
+
+  if(mLastCommitRasterized)
   {
     Texture rasterizedTexture = task->GetRasterizedTexture();
     if(rasterizedTexture && rasterizedTexture.GetWidth() != 0 && rasterizedTexture.GetHeight() != 0)
@@ -268,10 +293,10 @@ void CanvasView::ApplyRasterizedImage(CanvasRendererRasterizingTaskPtr task)
     mRasterizingTask.Reset(); // We don't need it anymore
   }
 
-  //If there are accumulated changes to CanvasRenderer during Rasterize, Rasterize once again.
-  if(!mIsSynchronous && !mManualRasterization && mCanvasRenderer && mCanvasRenderer.IsCanvasChanged())
+  //If there are accumulated changes to CanvasRenderer during Rasterize, or previous rasterization failed, Rasterize once again.
+  if(!mIsSynchronous && mCanvasRenderer && (!mLastCommitRasterized || (!mManualRasterization && mCanvasRenderer.IsCanvasChanged())))
   {
-    AddRasterizationTask();
+    AddRasterizationTask(!mLastCommitRasterized);
   }
 }
 
@@ -347,6 +372,12 @@ void CanvasView::SetRasterizationRequestManually(const bool isRasterizationManua
     if(!mManualRasterization)
     {
       RequestRasterization();
+
+      if(DALI_LIKELY(Adaptor::IsAvailable()))
+      {
+        // To make sure we will process next time.
+        Adaptor::Get().RequestProcessEventsOnIdle();
+      }
     }
   }
 }
index 82f7ff36753a2527883a758dc47879e87b7c6eb6..563b3bfd3ce9216bee6371311e7dc3a5ef77ecdd 100644 (file)
@@ -155,9 +155,9 @@ private: // From Control
   /**
    * @bried Rasterize the canvas, and add it to the view.
    *
-   * @param[in] size The target size of the canvas view rasterization.
+   * @param[in] forceProcess True if we need to rasterize forcibly without changeness check.
    */
-  void AddRasterizationTask();
+  void AddRasterizationTask(bool forceProcess);
 
 protected:
   /**
@@ -194,6 +194,7 @@ private:
   bool                             mIsSynchronous : 1;
   bool                             mManualRasterization : 1;
   bool                             mProcessorRegistered : 1;
+  bool                             mLastCommitRasterized : 1;
 };
 
 } // namespace Internal