Let we retry canvas rasterizing if last commit was failed.
Change-Id: Id8cc862f0c640ed34567e54a6f8218ad5578ddae
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
void RunIdles();
void RequestUpdateOnce();
+ void RequestProcessEventsOnIdle();
static Integration::Scene GetScene(Dali::Window window);
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());
}
}
}
+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());
{
}
+void Adaptor::RequestProcessEventsOnIdle()
+{
+ mImpl->RequestProcessEventsOnIdle();
+}
+
class LogFactory : public LogFactoryInterface
{
public:
/*
- * 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.
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;
}
}
- 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)
{
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;
}
/// 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.
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();
/*
- * 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)
{
bool Commit()
{
- return true;
+ return true;
}
bool IsCanvasChanged() const
{
- return true;
+ return true;
}
Dali::Texture GetRasterizedTexture()
bool Rasterize()
{
- return true;
+ gRasterizeCalled = true;
+ return gRasterizeResult;
}
bool AddDrawable(Dali::CanvasRenderer::Drawable& drawable)
{
- if (!drawable)
+ if(!drawable)
{
return false;
}
bool RemoveDrawable(Dali::CanvasRenderer::Drawable& drawable)
{
- if (!drawable)
+ if(!drawable)
{
return false;
}
- if (mDrawable == &drawable)
+ if(mDrawable == &drawable)
{
mDrawable = nullptr;
return true;
bool RemoveAllDrawables()
{
- if (mDrawable)
+ if(mDrawable)
{
return true;
}
{
mSize = size;
// For negative test
- if ( size.width == -999 && size.height == -999 )
+ if(size.width == -999 && size.height == -999)
{
return false;
}
{
mViewBox = viewBox;
// For negative test
- if ( viewBox.width == -999 && viewBox.height == -999 )
+ if(viewBox.width == -999 && viewBox.height == -999)
{
return false;
}
}
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()
{
}
-CanvasRenderer::CanvasRenderer( Internal::Adaptor::CanvasRenderer* internal )
-: BaseHandle( internal )
+CanvasRenderer::CanvasRenderer(Internal::Adaptor::CanvasRenderer* internal)
+: BaseHandle(internal)
{
}
}
} // 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
--- /dev/null
+#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
#include <stdlib.h>
#include <iostream>
+#include <toolkit-canvas-renderer.h>
#include <toolkit-event-thread-callback.h>
#include <toolkit-timer.h>
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;
}
END_TEST;
}
+namespace
+{
bool gRasterizationCompletedSignal = false;
void rasteriztionCompleted(IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task)
{
gRasterizationCompletedSignal = true;
}
+} // namespace
int UtcDaliCanvasViewRasterizeTaskP(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;
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();
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);
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);
// 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);
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();
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;
}
#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>
mSize(viewBox),
mIsSynchronous(true),
mManualRasterization(false),
- mProcessorRegistered(false)
+ mProcessorRegistered(false),
+ mLastCommitRasterized(false)
{
}
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));
}
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)
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);
}
}
if(!mManualRasterization)
{
RequestRasterization();
+
+ if(DALI_LIKELY(Adaptor::IsAvailable()))
+ {
+ // To make sure we will process next time.
+ Adaptor::Get().RequestProcessEventsOnIdle();
+ }
}
}
}
/**
* @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:
/**
bool mIsSynchronous : 1;
bool mManualRasterization : 1;
bool mProcessorRegistered : 1;
+ bool mLastCommitRasterized : 1;
};
} // namespace Internal