#include <stdlib.h>
#include <toolkit-event-thread-callback.h>
#include <unistd.h>
+#include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
using namespace Dali;
using namespace Dali::Toolkit;
static const char* gImage_50_RGBA = TEST_RESOURCE_DIR "/icon-delete.png";
// resolution: 128*128, pixel format: RGB888
static const char* gImage_128_RGB = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+// animated image
+static const char* gImage_gif = TEST_RESOURCE_DIR "/canvas-none.gif";
// for testing the ImageLoadedSignal
class ImageLoadedSignalVerifier : public ConnectionTracker
void ImageLoaded(uint32_t id, PixelData pixelData)
{
- mIDs.push_back(id);
- mPixelDataList.push_back(pixelData);
+ if(pixelData)
+ {
+ mIDs.push_back(id);
+ mPixelDataList.push_back(pixelData);
+ }
mCount++;
}
uint32_t id02 = loader.Load(gImage_50_RGBA, ImageDimensions(25, 25));
uint32_t id03 = loader.Load(gImage_128_RGB, ImageDimensions(100, 100), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, true);
- DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
+ // Try load animted image
+ Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New(gImage_gif, true);
+ DevelAsyncImageLoader::LoadAnimatedImage(loader, animatedImageLoading, 0, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF);
+
+ // Try apply mask image
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New(50, 50, Dali::Pixel::RGBA8888);
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New(50, 50, Dali::Pixel::RGBA8888);
+ DevelAsyncImageLoader::ApplyMask(loader, imageData, maskData, 0.0f, false, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF);
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(4), true, TEST_LOCATION);
application.SendNotification();
application.Render();
- DALI_TEST_CHECK(loadedSignalVerifier.LoadedImageCount() == 3);
+ DALI_TEST_CHECK(loadedSignalVerifier.LoadedImageCount() == 4);
DALI_TEST_CHECK(loadedSignalVerifier.Verify(id02, 25, 25));
DALI_TEST_CHECK(loadedSignalVerifier.Verify(id03, 100, 100));
}
// Note: This is not an ideal test, but we cannot guarantee we can call Cancel() before the image has finished loading.
-int UtcDaliAsyncImageLoaderCancel(void)
+int UtcDaliAsyncImageLoaderCancel01(void)
{
ToolkitTestApplication application;
END_TEST;
}
+int UtcDaliAsyncImageLoaderCancel02(void)
+{
+ ToolkitTestApplication application;
+
+ AsyncImageLoader loader = AsyncImageLoader::New();
+ uint32_t id01 = loader.Load(gImage_34_RGBA, ImageDimensions(34, 34));
+ DALI_TEST_CHECK(loader.Cancel(id01)); // Cancle a task
+
+ application.SendNotification();
+ application.Render();
+ END_TEST;
+}
+
int UtcDaliAsyncImageLoaderCancelAll(void)
{
ToolkitTestApplication application;
uint32_t id = 1;
DALI_TEST_CHECK(!(loader.Cancel(id)));
+ uint32_t id01 = loader.Load(gImage_34_RGBA, ImageDimensions(34, 34));
+ uint32_t id02 = loader.Load(gImage_50_RGBA, ImageDimensions(25, 25));
+ uint32_t id03 = loader.Load(gImage_128_RGB, ImageDimensions(100, 100), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, true);
+ loader.CancelAll();
+
+ // Test that cancelling a non-existing loading task will return false
+ DALI_TEST_CHECK(!(loader.Cancel(id01)));
+ DALI_TEST_CHECK(!(loader.Cancel(id02)));
+ DALI_TEST_CHECK(!(loader.Cancel(id03)));
+
+ application.SendNotification();
+ application.Render();
+
END_TEST;
-}
+}
\ No newline at end of file
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/dali-toolkit.h>
-#include <dali-toolkit/devel-api/controls/canvas-view/canvas-view.h>
-#include <dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.h>
+#include <dali-toolkit/internal/controls/canvas-view/canvas-view-impl.h>
+#include <dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-task.h>
#include <dali/devel-api/adaptor-framework/canvas-renderer/canvas-renderer-shape.h>
#include <dali/devel-api/adaptor-framework/canvas-renderer/canvas-renderer.h>
#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
using namespace Dali;
using namespace Toolkit;
END_TEST;
}
-int UtcDaliCanvasViewRasterizeTaskP(void)
+bool gRasterizationCompletedSignal = false;
+void rasteriztionCompleted(IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task)
{
- ToolkitTestApplication application;
-
- Dali::Toolkit::Internal::CanvasView* dummyInternalCanvasView = new Dali::Toolkit::Internal::CanvasView(Vector2(100, 100));
- DALI_TEST_CHECK(dummyInternalCanvasView);
-
- Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
- DALI_TEST_CHECK(dummyCanvasRenderer);
-
- IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
- DALI_TEST_CHECK(task);
-
- END_TEST;
+ gRasterizationCompletedSignal = true;
}
-int UtcDaliCanvasViewRasterizeTaskGetCanvasViewP(void)
-{
- ToolkitTestApplication application;
-
- Dali::Toolkit::Internal::CanvasView* dummyInternalCanvasView = new Dali::Toolkit::Internal::CanvasView(Vector2(100, 100));
- DALI_TEST_CHECK(dummyInternalCanvasView);
-
- Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
- DALI_TEST_CHECK(dummyCanvasRenderer);
-
- IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
- DALI_TEST_CHECK(task);
-
- DALI_TEST_EQUALS(task->GetCanvasView(), dummyInternalCanvasView, TEST_LOCATION);
-
- END_TEST;
-}
-
-int UtcDaliCanvasViewRasterizeThreadP(void)
+int UtcDaliCanvasViewRasterizeTaskP(void)
{
ToolkitTestApplication application;
Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
DALI_TEST_CHECK(dummyCanvasRenderer);
- IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
+ IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyCanvasRenderer, MakeCallback(rasteriztionCompleted));
DALI_TEST_CHECK(task);
- Dali::Toolkit::Internal::CanvasViewRasterizeThread* dummyThread = new Dali::Toolkit::Internal::CanvasViewRasterizeThread();
- DALI_TEST_CHECK(dummyThread);
-
END_TEST;
}
-int UtcDaliCanvasViewRasterizeThreadAddTaskP(void)
+int UtcDaliCanvasViewRasterizeTaskAddTaskP(void)
{
ToolkitTestApplication application;
Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
DALI_TEST_CHECK(dummyCanvasRenderer);
- IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
+ IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyCanvasRenderer, MakeCallback(rasteriztionCompleted));
DALI_TEST_CHECK(task);
- IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task2 = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
+ IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task2 = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyCanvasRenderer, MakeCallback(rasteriztionCompleted));
DALI_TEST_CHECK(task2);
- Dali::Toolkit::Internal::CanvasViewRasterizeThread* dummyThread = new Dali::Toolkit::Internal::CanvasViewRasterizeThread();
- DALI_TEST_CHECK(dummyThread);
-
- dummyThread->AddTask(task);
- dummyThread->AddTask(task2);
-
- END_TEST;
-}
-
-int UtcDaliCanvasViewRasterizeThreadAddRemoveTaskP(void)
-{
- ToolkitTestApplication application;
-
- Dali::Toolkit::Internal::CanvasView* dummyInternalCanvasView = new Dali::Toolkit::Internal::CanvasView(Vector2(100, 100));
- DALI_TEST_CHECK(dummyInternalCanvasView);
-
- Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
- DALI_TEST_CHECK(dummyCanvasRenderer);
-
- IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
- DALI_TEST_CHECK(task);
-
- Dali::Toolkit::Internal::CanvasViewRasterizeThread* dummyThread = new Dali::Toolkit::Internal::CanvasViewRasterizeThread();
- DALI_TEST_CHECK(dummyThread);
-
- dummyThread->AddTask(task);
-
- dummyThread->RemoveTask(dummyInternalCanvasView);
-
- END_TEST;
-}
-
-int UtcDaliCanvasViewRasterizeThreadApplyRasterizedP(void)
-{
- ToolkitTestApplication application;
-
- Dali::Toolkit::Internal::CanvasView* dummyInternalCanvasView = new Dali::Toolkit::Internal::CanvasView(Vector2(100, 100));
- DALI_TEST_CHECK(dummyInternalCanvasView);
-
- Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
- DALI_TEST_CHECK(dummyCanvasRenderer);
+ Dali::AsyncTaskManager asyncTaskManager = Dali::AsyncTaskManager::Get();
+ DALI_TEST_CHECK(asyncTaskManager);
- IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
- DALI_TEST_CHECK(task);
-
- Dali::Toolkit::Internal::CanvasViewRasterizeThread* dummyThread = new Dali::Toolkit::Internal::CanvasViewRasterizeThread();
- DALI_TEST_CHECK(dummyThread);
-
- dummyThread->AddTask(task);
-
- dummyThread->ApplyRasterized();
+ asyncTaskManager.AddTask(task);
+ asyncTaskManager.AddTask(task2);
END_TEST;
}
-int UtcDaliCanvasViewRasterizeThreadTerminateThreadP(void)
+int UtcDaliCanvasViewRasterizeTaskAddRemoveTaskP(void)
{
ToolkitTestApplication application;
Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
DALI_TEST_CHECK(dummyCanvasRenderer);
- IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
+ IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyCanvasRenderer, MakeCallback(rasteriztionCompleted));
DALI_TEST_CHECK(task);
- Dali::Toolkit::Internal::CanvasViewRasterizeThread* dummyThread = new Dali::Toolkit::Internal::CanvasViewRasterizeThread();
- DALI_TEST_CHECK(dummyThread);
+ Dali::AsyncTaskManager asyncTaskManager = Dali::AsyncTaskManager::Get();
+ DALI_TEST_CHECK(asyncTaskManager);
- dummyThread->AddTask(task);
+ asyncTaskManager.AddTask(task);
- Dali::Toolkit::Internal::CanvasViewRasterizeThread::TerminateThread(dummyThread);
+ asyncTaskManager.RemoveTask(task);
END_TEST;
}
return pixelData;
}
-int UtcDaliCanvasViewRasterizeThreadCallProcessP(void)
-{
- ToolkitTestApplication application;
-
- Dali::Toolkit::Internal::CanvasView* dummyInternalCanvasView = new Dali::Toolkit::Internal::CanvasView(Vector2(100, 100));
- DALI_TEST_CHECK(dummyInternalCanvasView);
-
- Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
- DALI_TEST_CHECK(dummyCanvasRenderer);
-
- IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
- DALI_TEST_CHECK(task);
-
- Dali::Toolkit::Internal::CanvasViewRasterizeThread* dummyThread = new Dali::Toolkit::Internal::CanvasViewRasterizeThread();
- DALI_TEST_CHECK(dummyThread);
-
- dummyThread->AddTask(task);
-
- dummyThread->Process(false);
-
- END_TEST;
-}
-
int UtcDaliCanvasViewRasterizeThreadRasterizationCompletedSignalP(void)
{
ToolkitTestApplication application;
+ gRasterizationCompletedSignal = false;
+
Dali::Toolkit::CanvasView canvasView = Dali::Toolkit::CanvasView::New(Vector2(100, 100));
- Dali::Toolkit::Internal::CanvasView& dummyInternalCanvasView = GetImpl(canvasView);
Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
DALI_TEST_CHECK(dummyCanvasRenderer);
- IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(&dummyInternalCanvasView, dummyCanvasRenderer);
+ IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyCanvasRenderer, MakeCallback(rasteriztionCompleted));
DALI_TEST_CHECK(task);
- Dali::Toolkit::Internal::CanvasViewRasterizeThread* dummyThread = new Dali::Toolkit::Internal::CanvasViewRasterizeThread();
- DALI_TEST_CHECK(dummyThread);
+ Dali::AsyncTaskManager asyncTaskManager = Dali::AsyncTaskManager::Get();
+ DALI_TEST_CHECK(asyncTaskManager);
- dummyThread->AddTask(task);
-
- dummyThread->Process(false);
-
- auto texture = Texture::New(Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, 100, 100);
-
- dummyThread->RasterizationCompletedSignal().Connect(&dummyInternalCanvasView, &Dali::Toolkit::Internal::CanvasView::ApplyRasterizedImage);
- dummyThread->RasterizationCompletedSignal().Emit(texture);
+ asyncTaskManager.AddTask(task);
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
application.SendNotification();
application.Render();
+ DALI_TEST_EQUALS(gRasterizationCompletedSignal, true, TEST_LOCATION);
+
END_TEST;
}
void ResourceFailedReload(Control control)
{
gFailCounter++;
- if(gFailCounter < MAX_RETRIES)
- {
- ReloadImage(ImageView::DownCast(control));
- }
}
} // namespace
// loading started, this waits for the loader thread to complete
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
- application.SendNotification();
-
DALI_TEST_EQUALS(gFailCounter, 1, TEST_LOCATION);
+ ReloadImage(imageView);
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
- application.SendNotification();
-
DALI_TEST_EQUALS(gFailCounter, 2, TEST_LOCATION);
+ ReloadImage(imageView);
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
- application.SendNotification();
DALI_TEST_EQUALS(gFailCounter, 3, TEST_LOCATION);
END_TEST;
imageView.ResourceReadySignal().Connect(&OnSimpleResourceReadySignal);
application.GetScene().Add(imageView);
- application.SendNotification();
- application.Render();
// Don't unparent imageView, for keep the cache.
};
// Remain 1 signal due to we use #URL + 1 mask image.
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(expectResourceReadySignalCounter + 1), true, TEST_LOCATION);
-
+ application.SendNotification();
+ application.Render();
DALI_TEST_EQUALS(gResourceReadySignalCounter, expectResourceReadySignalCounter, TEST_LOCATION);
END_TEST;
textureCallStack.EnableLogging(true);
auto TestBorderImage = [&](int index, const std::string& normalImageUrl, const Rect<int> border, const char* location) {
- if(imageView[index])
- {
- imageView[index].Unparent();
- }
Property::Map map;
map[Toolkit::Visual::Property::TYPE] = Toolkit::Visual::N_PATCH;
map[Toolkit::ImageVisual::Property::URL] = normalImageUrl;
application.SendNotification();
application.Render();
+
// Check we use cached npatch data so we don't generate new texture textures
DALI_TEST_EQUALS(textureCallStack.CountMethod("GenTextures"), 0, TEST_LOCATION);
DALI_TEST_EQUALS(actor2.GetRendererCount(), 0u, TEST_LOCATION);
application.GetScene().Add(actor2);
-
- application.SendNotification();
- application.Render();
-
- application.SendNotification();
application.Render();
// Async loading is not finished yet.
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/controls/control-devel.h>
-#include <dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.h>
#include <dali-toolkit/internal/controls/control/control-data-impl.h>
#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
mCanvasRenderer(CanvasRenderer::New(viewBox)),
mTexture(),
mTextureSet(),
- mSize(viewBox),
- mCanvasViewRasterizeThread(nullptr)
+ mSize(viewBox)
{
}
CanvasView::~CanvasView()
{
- if(mCanvasViewRasterizeThread)
- {
- mCanvasViewRasterizeThread->RemoveTask(this);
-
- CanvasViewRasterizeThread::TerminateThread(mCanvasViewRasterizeThread);
- }
-
if(Adaptor::IsAvailable())
{
+ Dali::AsyncTaskManager::Get().RemoveTask(mRasterizingTask);
+ mRasterizingTask.Reset();
Adaptor::Get().UnregisterProcessor(*this, true);
}
}
void CanvasView::AddRasterizationTask()
{
- CanvasRendererRasterizingTaskPtr newTask = new CanvasRendererRasterizingTask(this, mCanvasRenderer);
-
- if(!mCanvasViewRasterizeThread)
- {
- mCanvasViewRasterizeThread = new CanvasViewRasterizeThread();
- mCanvasViewRasterizeThread->RasterizationCompletedSignal().Connect(this, &CanvasView::ApplyRasterizedImage);
- mCanvasViewRasterizeThread->Start();
- }
+ mRasterizingTask = new CanvasRendererRasterizingTask(mCanvasRenderer, MakeCallback(this, &CanvasView::ApplyRasterizedImage));
if(mCanvasRenderer.Commit())
{
- mCanvasViewRasterizeThread->AddTask(newTask);
+ AsyncTaskManager::Get().AddTask(mRasterizingTask);
}
}
-void CanvasView::ApplyRasterizedImage(Texture rasterizedTexture)
+void CanvasView::ApplyRasterizedImage(CanvasRendererRasterizingTaskPtr task)
{
- if(rasterizedTexture && rasterizedTexture.GetWidth() != 0 && rasterizedTexture.GetHeight() != 0)
+ if(task->IsRasterized())
{
- if(!mTextureSet)
+ Texture rasterizedTexture = task->GetRasterizedTexture();
+ if(rasterizedTexture && rasterizedTexture.GetWidth() != 0 && rasterizedTexture.GetHeight() != 0)
{
- std::string fragmentShader = SHADER_CANVAS_VIEW_FRAG.data();
- DevelTexture::ApplyNativeFragmentShader(rasterizedTexture, fragmentShader);
+ if(!mTextureSet)
+ {
+ std::string fragmentShader = SHADER_CANVAS_VIEW_FRAG.data();
+ DevelTexture::ApplyNativeFragmentShader(rasterizedTexture, fragmentShader);
- mTextureSet = TextureSet::New();
- Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
- Shader shader = Shader::New(SHADER_CANVAS_VIEW_VERT, fragmentShader);
- Renderer renderer = Renderer::New(geometry, shader);
+ mTextureSet = TextureSet::New();
+ Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
+ Shader shader = Shader::New(SHADER_CANVAS_VIEW_VERT, fragmentShader);
+ Renderer renderer = Renderer::New(geometry, shader);
- renderer.SetTextures(mTextureSet);
- renderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true);
- Self().AddRenderer(renderer);
+ renderer.SetTextures(mTextureSet);
+ renderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true);
+ Self().AddRenderer(renderer);
+ }
+ mTextureSet.SetTexture(0, rasterizedTexture);
}
- mTextureSet.SetTexture(0, rasterizedTexture);
}
//If there are accumulated changes to CanvasRenderer during Rasterize, Rasterize once again.
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/controls/canvas-view/canvas-view.h>
#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-task.h>
namespace Dali
{
/**
* @bried Apply the rasterized image to the canvas view
*
- * @param[in] rasterizedTexture The texture with the rasterized pixels
+ * @param[in] task CanvasRendererRasterizingTaskPtr
*/
- void ApplyRasterizedImage(Texture rasterizedTexture);
+ void ApplyRasterizedImage(CanvasRendererRasterizingTaskPtr task);
private:
CanvasView(const CanvasView&) = delete;
CanvasView& operator=(const CanvasView&) = delete;
private:
- CanvasRenderer mCanvasRenderer;
- Dali::Texture mTexture;
- TextureSet mTextureSet;
- Vector2 mSize;
- CanvasViewRasterizeThread* mCanvasViewRasterizeThread;
+ CanvasRenderer mCanvasRenderer;
+ Dali::Texture mTexture;
+ TextureSet mTextureSet;
+ Vector2 mSize;
+ CanvasRendererRasterizingTaskPtr mRasterizingTask;
};
} // namespace Internal
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "canvas-view-rasterize-task.h"
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+CanvasRendererRasterizingTask::CanvasRendererRasterizingTask(CanvasRenderer canvasRenderer, CallbackBase* callback)
+: AsyncTask(callback),
+ mCanvasRenderer(canvasRenderer),
+ mRasterizedSuccessed(false)
+{
+}
+
+void CanvasRendererRasterizingTask::Process()
+{
+ mRasterizedSuccessed = Rasterize();
+}
+
+bool CanvasRendererRasterizingTask::IsReady()
+{
+ return true;
+}
+
+bool CanvasRendererRasterizingTask::IsRasterized()
+{
+ return mRasterizedSuccessed;
+}
+
+bool CanvasRendererRasterizingTask::Rasterize()
+{
+ if(mCanvasRenderer && mCanvasRenderer.Rasterize())
+ {
+ return true;
+ }
+ return false;
+}
+
+Texture CanvasRendererRasterizingTask::GetRasterizedTexture()
+{
+ return mCanvasRenderer.GetRasterizedTexture();
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_CANVAS_VIEW_RASTERIZE_TASK_H
+#define DALI_TOOLKIT_CANVAS_VIEW_RASTERIZE_TASK_H
+
+/*
+ * Copyright (c) 2022 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/devel-api/adaptor-framework/canvas-renderer/canvas-renderer.h>
+#include <dali/devel-api/adaptor-framework/event-thread-callback.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/devel-api/threading/thread.h>
+#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <memory>
+#include <vector>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+class CanvasRendererRasterizingTask;
+using CanvasRendererRasterizingTaskPtr = IntrusivePtr<CanvasRendererRasterizingTask>;
+
+/**
+ * The canvasview rasterizing tasks to be processed in the worker thread.
+ *
+ * Life cycle of a rasterizing task is as follows:
+ * 1. Created by CanvasView in the main thread
+ * 2. Queued in the worked thread waiting to be processed.
+ * 3. If this task gets its turn to do the rasterization, it triggers main thread to apply the rasterized image to material then been deleted in main thread call back.
+ * Or if this task is been removed before its turn to be processed, it then been deleted in the worker thread.
+ */
+class CanvasRendererRasterizingTask : public AsyncTask
+{
+public:
+ /**
+ * Constructor
+ * @param[in] canvasRenderer The renderer which the rasterized canvas to be applied.
+ * @param[in] callback The callback that is called when the operation is completed.
+ */
+ CanvasRendererRasterizingTask(CanvasRenderer canvasRenderer, CallbackBase* callback);
+
+ /**
+ * Destructor.
+ */
+ ~CanvasRendererRasterizingTask() = default;
+
+ /**
+ * Process the task
+ */
+ void Process() override;
+
+ /**
+ * Whether the task is ready to process.
+ * @return True if the task is ready to process.
+ */
+ bool IsReady() override;
+
+ /**
+ * Do the rasterization with the mRasterizer.
+ * @return Returns True when it's successful. False otherwise.
+ */
+ bool Rasterize();
+
+ /**
+ * Whether the rasterize is completed
+ * @return Returns True when it's completed
+ */
+ bool IsRasterized();
+
+ /**
+ * Get the rasterization result.
+ * @return The texture with the rasterized pixels.
+ */
+ Texture GetRasterizedTexture();
+
+private:
+ // Undefined
+ CanvasRendererRasterizingTask(const CanvasRendererRasterizingTask& task);
+
+ // Undefined
+ CanvasRendererRasterizingTask& operator=(const CanvasRendererRasterizingTask& task);
+
+private:
+ CanvasRenderer mCanvasRenderer;
+ bool mRasterizedSuccessed;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CANVAS_VIEW_RASTERIZE_TASK_H
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "canvas-view-rasterize-thread.h"
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/thread-settings.h>
-#include <dali/integration-api/adaptor-framework/adaptor.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-CanvasRendererRasterizingTask::CanvasRendererRasterizingTask(CanvasView* canvasView, CanvasRenderer canvasRenderer)
-: mCanvasView(canvasView),
- mCanvasRenderer(canvasRenderer),
- mRasterizedTexture()
-{
-}
-
-bool CanvasRendererRasterizingTask::Rasterize()
-{
- if(mCanvasRenderer && mCanvasRenderer.Rasterize())
- {
- return true;
- }
- return false;
-}
-
-CanvasView* CanvasRendererRasterizingTask::GetCanvasView() const
-{
- return mCanvasView.Get();
-}
-
-Texture CanvasRendererRasterizingTask::GetRasterizedTexture()
-{
- return mCanvasRenderer.GetRasterizedTexture();
-}
-
-CanvasViewRasterizeThread::CanvasViewRasterizeThread()
-: mTrigger(new EventThreadCallback(MakeCallback(this, &CanvasViewRasterizeThread::ApplyRasterized))),
- mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
- mProcessorRegistered(false),
- mRasterizationCompletedSignal()
-{
-}
-
-CanvasViewRasterizeThread::~CanvasViewRasterizeThread()
-{
- if(mProcessorRegistered && Adaptor::IsAvailable())
- {
- Adaptor::Get().UnregisterProcessor(*this);
- }
-}
-
-void CanvasViewRasterizeThread::TerminateThread(CanvasViewRasterizeThread*& thread)
-{
- if(thread)
- {
- // add an empty task would stop the thread from conditional wait.
- thread->AddTask(CanvasRendererRasterizingTaskPtr());
- // stop the thread
- thread->Join();
- // delete the thread
- delete thread;
- thread = NULL;
- }
-}
-
-void CanvasViewRasterizeThread::AddTask(CanvasRendererRasterizingTaskPtr task)
-{
- bool wasEmpty = false;
-
- {
- // Lock while adding task to the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
- wasEmpty = mRasterizeTasks.empty();
- if(!wasEmpty && task)
- {
- // Remove the tasks with the same renderer.
- // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
- for(std::vector<CanvasRendererRasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
- {
- if((*it) && (*it)->GetCanvasView() == task->GetCanvasView()) //Need
- {
- mRasterizeTasks.erase(it);
- break;
- }
- }
- }
- mRasterizeTasks.push_back(task);
-
- if(!mProcessorRegistered && Adaptor::IsAvailable())
- {
- Adaptor::Get().RegisterProcessor(*this);
- mProcessorRegistered = true;
- }
- }
-
- if(wasEmpty)
- {
- // wake up the image loading thread
- mConditionalWait.Notify();
- }
-}
-
-CanvasRendererRasterizingTaskPtr CanvasViewRasterizeThread::NextCompletedTask()
-{
- // Lock while popping task out from the queue
- Mutex::ScopedLock lock(mMutex);
-
- if(mCompletedTasks.empty())
- {
- return CanvasRendererRasterizingTaskPtr();
- }
-
- std::vector<CanvasRendererRasterizingTaskPtr>::iterator next = mCompletedTasks.begin();
- CanvasRendererRasterizingTaskPtr nextTask = *next;
- mCompletedTasks.erase(next);
-
- return nextTask;
-}
-
-void CanvasViewRasterizeThread::RemoveTask(CanvasView* canvasView)
-{
- // Lock while remove task from the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
- if(!mRasterizeTasks.empty())
- {
- for(std::vector<CanvasRendererRasterizingTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
- {
- if((*it) && (*it)->GetCanvasView() == canvasView)
- {
- mRasterizeTasks.erase(it);
- break;
- }
- }
- }
-
- UnregisterProcessor();
-}
-
-CanvasRendererRasterizingTaskPtr CanvasViewRasterizeThread::NextTaskToProcess()
-{
- // Lock while popping task out from the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
-
- // conditional wait
- while(mRasterizeTasks.empty())
- {
- mConditionalWait.Wait(lock);
- }
-
- // pop out the next task from the queue
- std::vector<CanvasRendererRasterizingTaskPtr>::iterator next = mRasterizeTasks.begin();
- CanvasRendererRasterizingTaskPtr nextTask = *next;
- mRasterizeTasks.erase(next);
-
- return nextTask;
-}
-
-void CanvasViewRasterizeThread::AddCompletedTask(CanvasRendererRasterizingTaskPtr task)
-{
- // Lock while adding task to the queue
- Mutex::ScopedLock lock(mMutex);
- mCompletedTasks.push_back(task);
-
- // wake up the main thread
- mTrigger->Trigger();
-}
-
-void CanvasViewRasterizeThread::Run()
-{
- SetThreadName("CanvasViewThread");
- mLogFactory.InstallLogFunction();
-
- while(CanvasRendererRasterizingTaskPtr task = NextTaskToProcess())
- {
- if(task->Rasterize())
- {
- AddCompletedTask(task);
- }
- }
-}
-
-void CanvasViewRasterizeThread::ApplyRasterized()
-{
- while(CanvasRendererRasterizingTaskPtr task = NextCompletedTask())
- {
- RasterizationCompletedSignal().Emit(task->GetRasterizedTexture()); // Here texture get
- }
-
- UnregisterProcessor();
-}
-
-void CanvasViewRasterizeThread::Process(bool postProcessor)
-{
- ApplyRasterized();
-}
-
-CanvasViewRasterizeThread::RasterizationCompletedSignalType& CanvasViewRasterizeThread::RasterizationCompletedSignal()
-{
- return mRasterizationCompletedSignal;
-}
-
-void CanvasViewRasterizeThread::UnregisterProcessor()
-{
- if(mProcessorRegistered)
- {
- if(mRasterizeTasks.empty() && mCompletedTasks.empty() && Adaptor::IsAvailable())
- {
- Adaptor::Get().UnregisterProcessor(*this);
- mProcessorRegistered = false;
- }
- }
-}
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_CANVAS_VIEW_RASTERIZE_THREAD_H
-#define DALI_TOOLKIT_CANVAS_VIEW_RASTERIZE_THREAD_H
-
-/*
- * Copyright (c) 2022 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/devel-api/adaptor-framework/canvas-renderer/canvas-renderer.h>
-#include <dali/devel-api/adaptor-framework/event-thread-callback.h>
-#include <dali/devel-api/threading/conditional-wait.h>
-#include <dali/devel-api/threading/mutex.h>
-#include <dali/devel-api/threading/thread.h>
-#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
-#include <dali/public-api/common/intrusive-ptr.h>
-#include <dali/public-api/object/ref-object.h>
-#include <dali/public-api/rendering/texture-set.h>
-#include <memory>
-#include <vector>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/controls/canvas-view/canvas-view-impl.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-using CanvasViewPtr = IntrusivePtr<CanvasView>;
-class CanvasRendererRasterizingTask;
-using CanvasRendererRasterizingTaskPtr = IntrusivePtr<CanvasRendererRasterizingTask>;
-
-/**
- * The canvasview rasterizing tasks to be processed in the worker thread.
- *
- * Life cycle of a rasterizing task is as follows:
- * 1. Created by CanvasView in the main thread
- * 2. Queued in the worked thread waiting to be processed.
- * 3. If this task gets its turn to do the rasterization, it triggers main thread to apply the rasterized image to material then been deleted in main thread call back.
- * Or if this task is been removed before its turn to be processed, it then been deleted in the worker thread.
- */
-class CanvasRendererRasterizingTask : public RefObject
-{
-public:
- /**
- * Constructor
- * @param[in] canvasRenderer The renderer which the rasterized canvas to be applied.
- */
- CanvasRendererRasterizingTask(CanvasView* canvasView, CanvasRenderer canvasRenderer);
-
- /**
- * Destructor.
- */
- ~CanvasRendererRasterizingTask() = default;
-
- /**
- * Do the rasterization with the mRasterizer.
- * @return Returns True when it's successful. False otherwise.
- */
- bool Rasterize();
-
- /**
- * Get the CanvasView
- * @return The CanvasView pointer.
- */
- CanvasView* GetCanvasView() const;
-
- /**
- * Get the rasterization result.
- * @return The texture with the rasterized pixels.
- */
- Texture GetRasterizedTexture();
-
-private:
- // Undefined
- CanvasRendererRasterizingTask(const CanvasRendererRasterizingTask& task);
-
- // Undefined
- CanvasRendererRasterizingTask& operator=(const CanvasRendererRasterizingTask& task);
-
-private:
- CanvasViewPtr mCanvasView;
- CanvasRenderer mCanvasRenderer;
- Texture mRasterizedTexture;
-};
-
-/**
- * The worker thread for CanvasView rasterization.
- */
-class CanvasViewRasterizeThread : public Thread, Integration::Processor
-{
-public:
- /// @brief ApplyRasterizedImage Event signal type
- using RasterizationCompletedSignalType = Signal<void(Texture)>;
-
-public:
- /**
- * Constructor.
- *
- * @param[in] trigger The trigger to wake up the main thread.
- */
- CanvasViewRasterizeThread();
-
- /**
- * Terminate the CanvasView rasterize thread, join and delete.
- *
- * @param[in] thread The rasterize thread.
- */
- static void TerminateThread(CanvasViewRasterizeThread*& thread);
-
- /**
- * Add a rasterization task into the waiting queue, called by main thread.
- *
- * @param[in] task The task added to the queue.
- */
- void AddTask(CanvasRendererRasterizingTaskPtr task);
-
- /**
- * Remove the task with the given CanvasView from the waiting queue, called by main thread.
- *
- * Typically called when the actor is put off stage, so the renderer is not needed anymore.
- *
- * @param[in] canvasView The CanvasView pointer.
- */
- void RemoveTask(CanvasView* canvasView);
-
- /**
- * Applies the rasterized image to material
- */
- void ApplyRasterized();
-
- /**
- * @copydoc Dali::Integration::Processor::Process()
- */
- void Process(bool postProcessor) override;
-
- /**
- * @brief This signal is emitted when rasterized image is applied.
- *
- * @return The signal to connect to
- */
- RasterizationCompletedSignalType& RasterizationCompletedSignal();
-
-private:
- /**
- * Pop the next task out from the queue.
- *
- * @return The next task to be processed.
- */
- CanvasRendererRasterizingTaskPtr NextTaskToProcess();
-
- /**
- * Pop the next task out from the completed queue, called by main thread.
- *
- * @return The next task in the completed queue.
- */
- CanvasRendererRasterizingTaskPtr NextCompletedTask();
-
- /**
- * Add a task in to the queue
- *
- * @param[in] task The task added to the queue.
- */
- void AddCompletedTask(CanvasRendererRasterizingTaskPtr task);
-
- /**
- * @brief Unregister a previously registered processor
- *
- */
- void UnregisterProcessor();
-
-protected:
- /**
- * Destructor.
- */
- ~CanvasViewRasterizeThread() override;
-
- /**
- * The entry function of the worker thread.
- * It fetches task from the Queue, rasterizes the image and apply to the renderer.
- */
- void Run() override;
-
-private:
- // Undefined
- CanvasViewRasterizeThread(const CanvasViewRasterizeThread& thread);
-
- // Undefined
- CanvasViewRasterizeThread& operator=(const CanvasViewRasterizeThread& thread);
-
-private:
- std::vector<CanvasRendererRasterizingTaskPtr> mRasterizeTasks; //The queue of the tasks waiting to rasterize the CanvasView.
- std::vector<CanvasRendererRasterizingTaskPtr> mCompletedTasks; //The queue of the tasks with the SVG rasterization completed
-
- ConditionalWait mConditionalWait;
- Dali::Mutex mMutex;
- std::unique_ptr<EventThreadCallback> mTrigger;
- const Dali::LogFactoryInterface& mLogFactory;
- bool mProcessorRegistered;
- RasterizationCompletedSignalType mRasterizationCompletedSignal;
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_CANVAS_VIEW_RASTERIZE_THREAD_H
${toolkit_src_dir}/visuals/npatch-loader.cpp
${toolkit_src_dir}/visuals/npatch/npatch-visual.cpp
${toolkit_src_dir}/visuals/primitive/primitive-visual.cpp
- ${toolkit_src_dir}/visuals/svg/svg-rasterize-thread.cpp
+ ${toolkit_src_dir}/visuals/svg/svg-task.cpp
${toolkit_src_dir}/visuals/svg/svg-visual.cpp
${toolkit_src_dir}/visuals/text-visual-shader-factory.cpp
${toolkit_src_dir}/visuals/text/text-visual.cpp
${toolkit_src_dir}/controls/buttons/radio-button-impl.cpp
${toolkit_src_dir}/controls/buttons/toggle-button-impl.cpp
${toolkit_src_dir}/controls/canvas-view/canvas-view-impl.cpp
- ${toolkit_src_dir}/controls/canvas-view/canvas-view-rasterize-thread.cpp
+ ${toolkit_src_dir}/controls/canvas-view/canvas-view-rasterize-task.cpp
${toolkit_src_dir}/controls/control/control-data-impl.cpp
${toolkit_src_dir}/controls/control/control-debug.cpp
${toolkit_src_dir}/controls/control/control-renderers.cpp
${toolkit_src_dir}/controls/gl-view/gl-view-impl.cpp
${toolkit_src_dir}/controls/gl-view/gl-view-render-thread.cpp
${toolkit_src_dir}/accessibility-manager/accessibility-manager-impl.cpp
-
${toolkit_src_dir}/feedback/feedback-style.cpp
-
${toolkit_src_dir}/focus-manager/keyboard-focus-manager-impl.cpp
${toolkit_src_dir}/focus-manager/keyinput-focus-manager-impl.cpp
${toolkit_src_dir}/helpers/color-conversion.cpp
${toolkit_src_dir}/image-loader/async-image-loader-impl.cpp
${toolkit_src_dir}/image-loader/atlas-packer.cpp
${toolkit_src_dir}/image-loader/image-atlas-impl.cpp
- ${toolkit_src_dir}/image-loader/image-load-thread.cpp
+ ${toolkit_src_dir}/image-loader/loading-task.cpp
${toolkit_src_dir}/image-loader/image-url-impl.cpp
${toolkit_src_dir}/styling/style-manager-impl.cpp
${toolkit_src_dir}/text/abstract-style-character-run.cpp
+++ /dev/null
-
-#ifndef DALI_TOOLKIT_INTERNAL_ROUND_ROBIN_CONTAINER_VIEW_H
-#define DALI_TOOLKIT_INTERNAL_ROUND_ROBIN_CONTAINER_VIEW_H
-
-/*
- * Copyright (c) 2022 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 <cstddef>
-#include <vector>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-/**
- * @brief RoundRobinContainerView is a view to a container that allows iterating through the elements cyclically.
- */
-template<typename T>
-class RoundRobinContainerView
-{
-public:
- using ContainerType = std::vector<T>;
-
- /**
- * @brief Constructs a new RoundRobinControlView with the given number elements using the provided factory.
- * @param[in] numberOfElements The number of elements in the container
- * @param[in] factory Factory function of functor that will be used to create instances of the elements
- */
- template<typename FactoryType>
- RoundRobinContainerView(size_t numberOfElements, const FactoryType& factory)
- : mElements(),
- mNextIndex{}
- {
- mElements.reserve(numberOfElements);
- for(unsigned i = {}; i < numberOfElements; ++i)
- {
- mElements.push_back(factory());
- }
- }
-
- /**
- * @brief Clear all elements.
- */
- void Clear()
- {
- mElements.clear();
- }
-
- /**
- * @brief Reset the position of the iterator returned by GetNext() to the first element.
- */
- void Reset()
- {
- mNextIndex = 0u;
- }
-
- /**
- * @brief Returns the next element on the container.
- * @return Iterator for the next element
- */
- typename ContainerType::iterator GetNext()
- {
- SetValidNextIndex();
-
- return mElements.begin() + mNextIndex++;
- }
-
- /**
- * @brief Returns the iterator to the end of the container.
- *
- * Can be used to compare against GetNext() to check if the container is empty.
- *
- * @return The container end() element
- */
- typename ContainerType::const_iterator End() const
- {
- return mElements.cend();
- }
-
- /**
- * @brief Returns the element count.
- * @return The element count
- */
- size_t GetElementCount() const
- {
- return mElements.size();
- }
-
- // default members
- ~RoundRobinContainerView() = default;
-
- RoundRobinContainerView(const RoundRobinContainerView&) = delete;
- RoundRobinContainerView& operator=(const RoundRobinContainerView&) = delete;
- RoundRobinContainerView(RoundRobinContainerView&&) = default;
- RoundRobinContainerView& operator=(RoundRobinContainerView&&) = default;
-
-private:
- /**
- * @brief Check the current index and reset if necessary.
- */
- void SetValidNextIndex()
- {
- if(mNextIndex >= mElements.size())
- {
- Reset();
- }
- }
-
-private:
- ContainerType mElements; //< container of elements
- size_t mNextIndex; //< index to the next element to be viewed
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_INTERNAL_ROUND_ROBIN_CONTAINER_VIEW_H
#include "async-image-loader-impl.h"
// EXTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
#include <dali/integration-api/adaptor-framework/adaptor.h>
namespace Dali
{
AsyncImageLoader::AsyncImageLoader()
: mLoadedSignal(),
- mLoadThread(new EventThreadCallback(MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage))),
- mLoadTaskId(0u),
- mIsLoadThreadStarted(false)
+ mLoadTaskId(0u)
{
}
AsyncImageLoader::~AsyncImageLoader()
{
- mLoadThread.CancelAll();
+ CancelAll();
}
IntrusivePtr<AsyncImageLoader> AsyncImageLoader::New()
uint32_t frameIndex,
DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
{
- if(!mIsLoadThreadStarted)
- {
- mLoadThread.Start();
- mIsLoadThreadStarted = true;
- }
- mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, animatedImageLoading, frameIndex, preMultiplyOnLoad));
-
+ LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, animatedImageLoading, frameIndex, preMultiplyOnLoad,MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage));
+ Dali::AsyncTaskManager::Get().AddTask(loadingTask);
return mLoadTaskId;
}
DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
bool loadPlanes)
{
- if(!mIsLoadThreadStarted)
- {
- mLoadThread.Start();
- mIsLoadThreadStarted = true;
- }
- mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, url, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, loadPlanes));
-
+ LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, url, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, loadPlanes, MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage));
+ AsyncTaskManager::Get().AddTask(loadingTask);
+ mLoadingTasks.push_back(AsyncImageLoadingInfo(loadingTask,mLoadTaskId));
return mLoadTaskId;
}
bool orientationCorrection,
DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
{
- if(!mIsLoadThreadStarted)
- {
- mLoadThread.Start();
- mIsLoadThreadStarted = true;
- }
- mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, encodedImageBuffer, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad));
-
+ LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, encodedImageBuffer, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage));
+ Dali::AsyncTaskManager::Get().AddTask(loadingTask);
+ mLoadingTasks.push_back(AsyncImageLoadingInfo(loadingTask,mLoadTaskId));
return mLoadTaskId;
}
bool cropToMask,
DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
{
- if(!mIsLoadThreadStarted)
- {
- mLoadThread.Start();
- mIsLoadThreadStarted = true;
- }
- mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad));
-
+ LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad, MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage));
+ Dali::AsyncTaskManager::Get().AddTask(loadingTask);
+ mLoadingTasks.push_back(AsyncImageLoadingInfo(loadingTask,mLoadTaskId));
return mLoadTaskId;
}
bool AsyncImageLoader::Cancel(uint32_t loadingTaskId)
{
- return mLoadThread.CancelTask(loadingTaskId);
+ // Remove already completed tasks
+ RemoveCompletedTask();
+
+ auto end = mLoadingTasks.end();
+ for(std::vector<AsyncImageLoadingInfo>::iterator iter = mLoadingTasks.begin(); iter != end; ++iter)
+ {
+ if((*iter).loadId == loadingTaskId)
+ {
+ Dali::AsyncTaskManager::Get().RemoveTask((*iter).loadingTask);
+ mLoadingTasks.erase(iter);
+ return true;
+ }
+ }
+
+ return false;
}
void AsyncImageLoader::CancelAll()
{
- mLoadThread.CancelAll();
+ // Remove already completed tasks
+ RemoveCompletedTask();
+
+ auto end = mLoadingTasks.end();
+ for(std::vector<AsyncImageLoadingInfo>::iterator iter = mLoadingTasks.begin(); iter != end; ++iter)
+ {
+ if((*iter).loadingTask && Dali::AsyncTaskManager::Get())
+ {
+ Dali::AsyncTaskManager::Get().RemoveTask(((*iter).loadingTask));
+ }
+ }
+ mLoadingTasks.clear();
}
-void AsyncImageLoader::ProcessLoadedImage()
+void AsyncImageLoader::ProcessLoadedImage(LoadingTaskPtr task)
{
- while(LoadingTask* next = mLoadThread.NextCompletedTask())
+ if(mPixelBufferLoadedSignal.GetConnectionCount() > 0)
+ {
+ mPixelBufferLoadedSignal.Emit(task->id, task->pixelBuffers);
+ }
+ else if(mLoadedSignal.GetConnectionCount() > 0)
{
- if(mPixelBufferLoadedSignal.GetConnectionCount() > 0)
+ PixelData pixelData;
+ if(!task->pixelBuffers.empty())
{
- mPixelBufferLoadedSignal.Emit(next->id, next->pixelBuffers);
+ pixelData = Devel::PixelBuffer::Convert(task->pixelBuffers[0]);
}
- else if(mLoadedSignal.GetConnectionCount() > 0)
+ mLoadedSignal.Emit(task->id, pixelData);
+ }
+
+ mCompletedTaskIds.push_back(task->id);
+}
+
+void AsyncImageLoader::RemoveCompletedTask()
+{
+ std::uint32_t loadingTaskId;
+ auto end = mLoadingTasks.end();
+ auto endCompletedIter = mCompletedTaskIds.end();
+ for(std::vector<AsyncImageLoadingInfo>::iterator iter = mLoadingTasks.begin(); iter != end; ++iter)
+ {
+ loadingTaskId = (*iter).loadId;
+ for(auto iterCompleted = mCompletedTaskIds.begin(); iterCompleted != endCompletedIter; ++iterCompleted)
{
- PixelData pixelData;
- if(!next->pixelBuffers.empty())
+ if((*iterCompleted) == loadingTaskId)
{
- pixelData = Devel::PixelBuffer::Convert(next->pixelBuffers[0]);
+ mLoadingTasks.erase(iter);
}
- mLoadedSignal.Emit(next->id, pixelData);
}
-
- delete next;
}
}
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
-#include <dali-toolkit/internal/image-loader/image-load-thread.h>
+#include <dali-toolkit/internal/image-loader/loading-task.h>
#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
namespace Dali
{
namespace Internal
{
-class AsyncImageLoader : public BaseObject
+using LoadingTaskPtr = IntrusivePtr<LoadingTask>;
+
+struct AsyncImageLoadingInfo
+{
+ AsyncImageLoadingInfo(LoadingTaskPtr loadingTask,std::uint32_t loadId)
+ : loadingTask(loadingTask),
+ loadId(loadId)
+ {
+ }
+
+ LoadingTaskPtr loadingTask;
+ std::uint32_t loadId;
+};
+
+class AsyncImageLoader : public BaseObject, public ConnectionTracker
{
public:
/**
/**
* Process the completed loading task from the worker thread.
*/
- void ProcessLoadedImage();
+ void ProcessLoadedImage(LoadingTaskPtr task);
protected:
/**
~AsyncImageLoader() override;
private:
+ /**
+ * Remove already completed tasks
+ */
+ void RemoveCompletedTask();
+
+private:
Toolkit::AsyncImageLoader::ImageLoadedSignalType mLoadedSignal;
Toolkit::DevelAsyncImageLoader::PixelBufferLoadedSignalType mPixelBufferLoadedSignal;
-
- ImageLoadThread mLoadThread;
- uint32_t mLoadTaskId;
- bool mIsLoadThreadStarted;
+ std::vector<AsyncImageLoadingInfo> mLoadingTasks;
+ std::vector<uint32_t> mCompletedTaskIds;
+ uint32_t mLoadTaskId;
};
} // namespace Internal
ImageAtlas::~ImageAtlas()
{
+ if(mAsyncLoader)
+ {
+ mAsyncLoader.CancelAll();
+ mAsyncLoader.ImageLoadedSignal().Disconnect(this, &ImageAtlas::UploadToAtlas);
+ }
+
const std::size_t count = mLoadingTaskInfoContainer.Count();
for(std::size_t i = 0; i < count; ++i)
{
{
uint32_t loadId = GetImplementation(mAsyncLoader).LoadEncodedImageBuffer(encodedImageBuffer, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF);
mLoadingTaskInfoContainer.PushBack(new LoadingTaskInfo(loadId, packPositionX, packPositionY, size.GetWidth(), size.GetHeight(), atlasUploadObserver));
+
// apply the half pixel correction
textureRect.x = (static_cast<float>(packPositionX) + 0.5f) / mWidth; // left
textureRect.y = (static_cast<float>(packPositionY) + 0.5f) / mHeight; // top
void ImageAtlas::UploadToAtlas(uint32_t id, PixelData pixelData)
{
- if(mLoadingTaskInfoContainer[0]->loadTaskId == id)
+ auto end = mLoadingTaskInfoContainer.End();
+ for(auto loadingTaskIterator = mLoadingTaskInfoContainer.Begin(); loadingTaskIterator != end; ++loadingTaskIterator)
{
- Rect<uint32_t> packRect(mLoadingTaskInfoContainer[0]->packRect);
- if(!pixelData || (pixelData.GetWidth() == 0 && pixelData.GetHeight() == 0))
+ if((*loadingTaskIterator) && (*loadingTaskIterator)->loadTaskId == id)
{
- if(!mBrokenImageUrl.empty()) // replace with the broken image
+ Rect<uint32_t> packRect((*loadingTaskIterator)->packRect);
+ if(!pixelData || (pixelData.GetWidth() == 0 && pixelData.GetHeight() == 0))
{
- UploadBrokenImage(packRect);
+ if(!mBrokenImageUrl.empty()) // replace with the broken image
+ {
+ UploadBrokenImage(packRect);
+ }
}
- }
- else
- {
- if(pixelData.GetWidth() < packRect.width || pixelData.GetHeight() < packRect.height)
+ else
{
- DALI_LOG_ERROR("Can not upscale the image from actual loaded size [ %d, %d ] to specified size [ %d, %d ]\n",
- pixelData.GetWidth(),
- pixelData.GetHeight(),
- packRect.width,
- packRect.height);
+ if(pixelData.GetWidth() < packRect.width || pixelData.GetHeight() < packRect.height)
+ {
+ DALI_LOG_ERROR("Can not upscale the image from actual loaded size [ %d, %d ] to specified size [ %d, %d ]\n",
+ pixelData.GetWidth(),
+ pixelData.GetHeight(),
+ packRect.width,
+ packRect.height);
+ }
+
+ mAtlas.Upload(pixelData, 0u, 0u, packRect.x, packRect.y, packRect.width, packRect.height);
}
- mAtlas.Upload(pixelData, 0u, 0u, packRect.x, packRect.y, packRect.width, packRect.height);
- }
+ if((*loadingTaskIterator)->observer)
+ {
+ (*loadingTaskIterator)->observer->UploadCompleted();
+ (*loadingTaskIterator)->observer->Unregister(*this);
+ }
- if(mLoadingTaskInfoContainer[0]->observer)
- {
- mLoadingTaskInfoContainer[0]->observer->UploadCompleted();
- mLoadingTaskInfoContainer[0]->observer->Unregister(*this);
+ mLoadingTaskInfoContainer.Erase(loadingTaskIterator);
+ break;
}
-
- mLoadingTaskInfoContainer.Erase(mLoadingTaskInfoContainer.Begin());
}
}
*/
// CLASS HEADER
-#include "image-load-thread.h"
+#include "loading-task.h"
// EXTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/image-loading.h>
{
namespace Internal
{
-LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
-: url(),
+LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
+: AsyncTask(callback),
+ url(),
encodedImageBuffer(),
id(id),
+ textureId(TextureManagerType::INVALID_TEXTURE_ID),
dimensions(),
fittingMode(),
samplingMode(),
orientationCorrection(),
isMaskTask(false),
cropToMask(false),
- loadPlanes(false)
+ loadPlanes(false),
+ isReady(true)
{
}
-LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, bool loadPlanes)
-: url(url),
+LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, bool loadPlanes, CallbackBase* callback)
+: AsyncTask(callback),
+ url(url),
encodedImageBuffer(),
id(id),
+ textureId(TextureManagerType::INVALID_TEXTURE_ID),
dimensions(dimensions),
fittingMode(fittingMode),
samplingMode(samplingMode),
orientationCorrection(orientationCorrection),
isMaskTask(false),
cropToMask(false),
- loadPlanes(loadPlanes)
+ loadPlanes(loadPlanes),
+ isReady(true)
{
}
-LoadingTask::LoadingTask(uint32_t id, const EncodedImageBuffer& encodedImageBuffer, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
-: url(),
+LoadingTask::LoadingTask(uint32_t id, const EncodedImageBuffer& encodedImageBuffer, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
+: AsyncTask(callback),
+ url(),
encodedImageBuffer(encodedImageBuffer),
id(id),
+ textureId(TextureManagerType::INVALID_TEXTURE_ID),
dimensions(dimensions),
fittingMode(fittingMode),
samplingMode(samplingMode),
orientationCorrection(orientationCorrection),
isMaskTask(false),
cropToMask(false),
- loadPlanes(false)
+ loadPlanes(false),
+ isReady(true)
{
}
-LoadingTask::LoadingTask(uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::PixelBuffer maskPixelBuffer, float contentScale, bool cropToMask, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
-: url(""),
+LoadingTask::LoadingTask(uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::PixelBuffer maskPixelBuffer, float contentScale, bool cropToMask, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
+: AsyncTask(callback),
+ url(""),
encodedImageBuffer(),
id(id),
+ textureId(TextureManagerType::INVALID_TEXTURE_ID),
dimensions(),
fittingMode(),
samplingMode(),
orientationCorrection(),
isMaskTask(true),
cropToMask(cropToMask),
- loadPlanes(false)
+ loadPlanes(false),
+ isReady(true)
{
pixelBuffers.push_back(pixelBuffer);
}
+LoadingTask::~LoadingTask()
+{
+}
+
+void LoadingTask::Process()
+{
+ isReady = false;
+ if(!isMaskTask)
+ {
+ Load();
+ }
+ else
+ {
+ ApplyMask();
+ }
+ MultiplyAlpha();
+ isReady = true;
+}
+
+bool LoadingTask::IsReady()
+{
+ return isReady;
+}
+
void LoadingTask::Load()
{
Devel::PixelBuffer pixelBuffer;
}
}
-ImageLoadThread::ImageLoadThread(EventThreadCallback* trigger)
-: mTrigger(trigger),
- mLogFactory(Dali::Adaptor::Get().GetLogFactory())
-{
-}
-
-ImageLoadThread::~ImageLoadThread()
-{
- // add an empty task would stop the thread from conditional wait.
- AddTask(NULL);
- // stop the thread
- Join();
-
- delete mTrigger;
-
- for(auto&& iter : mLoadQueue)
- {
- delete iter;
- }
- mLoadQueue.Clear();
-
- for(auto&& iter : mCompleteQueue)
- {
- delete iter;
- }
- mCompleteQueue.Clear();
-}
-
-void ImageLoadThread::Run()
-{
- SetThreadName("ImageLoadThread");
- mLogFactory.InstallLogFunction();
-
- while(LoadingTask* task = NextTaskToProcess())
- {
- if(!task->isMaskTask)
- {
- task->Load();
- }
- else
- {
- task->ApplyMask();
- }
- task->MultiplyAlpha();
-
- AddCompletedTask(task);
- }
-}
-
-void ImageLoadThread::AddTask(LoadingTask* task)
-{
- bool wasEmpty = false;
- {
- // Lock while adding task to the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
- wasEmpty = mLoadQueue.Empty();
- mLoadQueue.PushBack(task);
- }
-
- if(wasEmpty)
- {
- // wake up the image loading thread
- mConditionalWait.Notify();
- }
-}
-
-LoadingTask* ImageLoadThread::NextCompletedTask()
-{
- // Lock while popping task out from the queue
- Mutex::ScopedLock lock(mMutex);
-
- if(mCompleteQueue.Empty())
- {
- return NULL;
- }
-
- Vector<LoadingTask*>::Iterator next = mCompleteQueue.Begin();
- LoadingTask* nextTask = *next;
- mCompleteQueue.Erase(next);
-
- return nextTask;
-}
-
-bool ImageLoadThread::CancelTask(uint32_t loadingTaskId)
-{
- // Lock while remove task from the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
-
- for(Vector<LoadingTask*>::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter)
- {
- if((*iter)->id == loadingTaskId)
- {
- delete(*iter);
- mLoadQueue.Erase(iter);
- return true;
- }
- }
-
- return false;
-}
-
-void ImageLoadThread::CancelAll()
-{
- // Lock while remove task from the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
-
- for(Vector<LoadingTask*>::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter)
- {
- delete(*iter);
- }
- mLoadQueue.Clear();
-}
-
-LoadingTask* ImageLoadThread::NextTaskToProcess()
+void LoadingTask::SetTextureId(TextureManagerType::TextureId id)
{
- // Lock while popping task out from the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
-
- while(mLoadQueue.Empty())
- {
- mConditionalWait.Wait(lock);
- }
-
- Vector<LoadingTask*>::Iterator next = mLoadQueue.Begin();
- LoadingTask* nextTask = *next;
- mLoadQueue.Erase(next);
-
- return nextTask;
-}
-
-void ImageLoadThread::AddCompletedTask(LoadingTask* task)
-{
- // Lock while adding task to the queue
- Mutex::ScopedLock lock(mMutex);
- mCompleteQueue.PushBack(task);
-
- // wake up the main thread
- mTrigger->Trigger();
+ textureId = id;
}
} // namespace Internal
-#ifndef DALI_TOOLKIT_IMAGE_LOAD_THREAD_H
-#define DALI_TOOLKIT_IMAGE_LOAD_THREAD_H
+#ifndef DALI_TOOLKIT_IMAGE_LOADING_TASK_H
+#define DALI_TOOLKIT_IMAGE_LOADING_TASK_H
/*
* Copyright (c) 2022 Samsung Electronics Co., Ltd.
// EXTERNAL INCLUDES
#include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
#include <dali/devel-api/adaptor-framework/event-thread-callback.h>
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
#include <dali/devel-api/threading/conditional-wait.h>
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/images/image-operations.h>
#include <dali/public-api/object/ref-object.h>
+#include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
namespace Dali
{
{
namespace Internal
{
+
+class LoadingTask;
+using LoadingTaskPtr = IntrusivePtr<LoadingTask>;
+
/**
- * The task of loading and packing an image into the atlas.
+ * The task of loading and packing an image into the atlas
*/
-struct LoadingTask
+class LoadingTask : public AsyncTask
{
+public:
/**
* Constructor.
* @param [in] id of the task
* @param [in] animatedImageLoading The AnimatedImageLoading to load animated image
* @param [in] frameIndex The frame index of a frame to be loaded frame
* @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+ * @param [in] callback The callback that is called when the operation is completed.
*/
LoadingTask(uint32_t id,
Dali::AnimatedImageLoading animatedImageLoading,
uint32_t frameIndex,
- DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+ DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
+ CallbackBase* callback);
/**
* Constructor.
* @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
* @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
* @param [in] loadPlanes true to load image planes or false to load bitmap image.
+ * @param [in] callback The callback that is called when the operation is completed.
*/
LoadingTask(uint32_t id,
const VisualUrl& url,
SamplingMode::Type samplingMode,
bool orientationCorrection,
DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
- bool loadPlanes);
+ bool loadPlanes,
+ CallbackBase* callback);
/**
* Constructor.
* @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
* @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
* @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+ * @param [in] callback The callback that is called when the operation is completed.
*/
LoadingTask(uint32_t id,
const EncodedImageBuffer& encodedImageBuffer,
FittingMode::Type fittingMode,
SamplingMode::Type samplingMode,
bool orientationCorrection,
- DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+ DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
+ CallbackBase* callback);
/**
* Constructor.
* @param [in] contentScale The factor to scale the content
* @param [in] cropToMask Whether to crop the content to the mask size
* @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+ * @param [in] callback The callback that is called when the operation is completed.
*/
LoadingTask(uint32_t id,
Devel::PixelBuffer pixelBuffer,
Devel::PixelBuffer maskPixelBuffer,
float contentScale,
bool cropToMask,
- DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+ DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
+ CallbackBase* callback);
/**
- * Load the image
+ * Destructor.
*/
- void Load();
+ ~LoadingTask() override;
/**
- * Apply mask
+ * Process the task accodring to the type
*/
- void ApplyMask();
+ void Process() override;
/**
- * Multiply alpha
+ * Whether the task is ready to process.
+ * @return True if the task is ready to process.
*/
- void MultiplyAlpha();
+ bool IsReady() override;
+
+ /**
+ * @brief Set the Texture Id
+ *
+ */
+ void SetTextureId(TextureManagerType::TextureId id);
private:
// Undefined
// Undefined
LoadingTask& operator=(const LoadingTask& queue);
+ /**
+ * Load the image
+ */
+ void Load();
+
+ /**
+ * Apply mask
+ */
+ void ApplyMask();
+
+ /**
+ * Multiply alpha
+ */
+ void MultiplyAlpha();
+
public:
std::vector<Devel::PixelBuffer> pixelBuffers{}; ///< pixelBuffer handle after successful load
///< or pixelBuffer to be masked image in the mask task
VisualUrl url; ///< url of the image to load
EncodedImageBuffer encodedImageBuffer; ///< encoded buffer of the image to load
uint32_t id; ///< The unique id associated with this task.
+ TextureManagerType::TextureId textureId; ///< textureId for loading
ImageDimensions dimensions; ///< dimensions to load
FittingMode::Type fittingMode; ///< fitting options
SamplingMode::Type samplingMode; ///< sampling options
bool isMaskTask : 1; ///< whether this task is for mask or not
bool cropToMask : 1; ///< Whether to crop the content to the mask size
bool loadPlanes : 1; ///< Whether to load image planes
-};
-
-/**
- * The worker thread for image loading.
- */
-class ImageLoadThread : public Thread
-{
-public:
- /**
- * Constructor.
- *
- * @param[in] mTrigger The trigger to wake up the main thread.
- */
- ImageLoadThread(EventThreadCallback* mTrigger);
-
- /**
- * Destructor.
- */
- ~ImageLoadThread() override;
-
- /**
- * Add a task in to the loading queue
- *
- * @param[in] task The task added to the queue.
- *
- * @note This class takes ownership of the task object
- */
- void AddTask(LoadingTask* task);
-
- /**
- * Pop the next task out from the completed queue.
- *
- * @return The next task to be processed.
- */
- LoadingTask* NextCompletedTask();
-
- /**
- * Remove the loading task from the waiting queue.
- */
- bool CancelTask(uint32_t loadingTaskId);
-
- /**
- * Remove all the loading tasks in the waiting queue.
- */
- void CancelAll();
-
-private:
- /**
- * Pop the next loading task out from the queue to process.
- *
- * @return The next task to be processed.
- */
- LoadingTask* NextTaskToProcess();
-
- /**
- * Add a task in to the loading queue
- *
- * @param[in] task The task added to the queue.
- */
- void AddCompletedTask(LoadingTask* task);
-
-protected:
- /**
- * The entry function of the worker thread.
- * It fetches loading task from the loadQueue, loads the image and adds to the completeQueue.
- */
- void Run() override;
-
-private:
- // Undefined
- ImageLoadThread(const ImageLoadThread& thread);
-
- // Undefined
- ImageLoadThread& operator=(const ImageLoadThread& thread);
-
-private:
- Vector<LoadingTask*> mLoadQueue; ///<The task queue with images for loading.
- Vector<LoadingTask*> mCompleteQueue; ///<The task queue with images loaded.
- EventThreadCallback* mTrigger;
- const Dali::LogFactoryInterface& mLogFactory; ///< The log factory
-
- ConditionalWait mConditionalWait;
- Dali::Mutex mMutex;
+ bool isReady : 1; ///< Whether this task ready to run
};
} // namespace Internal
#endif
TextureAsyncLoadingHelper::TextureAsyncLoadingHelper(TextureManager& textureManager)
-: TextureAsyncLoadingHelper(Toolkit::AsyncImageLoader::New(), textureManager, AsyncLoadingInfoContainerType())
+: mTextureManager(textureManager),
+ mLoadTaskId(0u)
{
}
const std::uint32_t& frameIndex,
const DevelAsyncImageLoader::PreMultiplyOnLoad& preMultiplyOnLoad)
{
- mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId));
- auto id = GetImplementation(mLoader).LoadAnimatedImage(animatedImageLoading, frameIndex, preMultiplyOnLoad);
- mLoadingInfoContainer.back().loadId = id;
+ LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, animatedImageLoading, frameIndex, preMultiplyOnLoad, MakeCallback(this, &TextureAsyncLoadingHelper::AsyncLoadComplete));
+ loadingTask->SetTextureId(textureId);
+ Dali::AsyncTaskManager::Get().AddTask(loadingTask);
}
void TextureAsyncLoadingHelper::Load(const TextureManager::TextureId& textureId,
const DevelAsyncImageLoader::PreMultiplyOnLoad& preMultiplyOnLoad,
const bool& loadYuvPlanes)
{
- mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId));
+ LoadingTaskPtr loadingTask;
if(DALI_UNLIKELY(url.IsBufferResource()))
{
- auto id = GetImplementation(mLoader).LoadEncodedImageBuffer(mTextureManager.GetEncodedImageBuffer(url.GetUrl()), desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad);
- mLoadingInfoContainer.back().loadId = id;
+ loadingTask = new LoadingTask(++mLoadTaskId, mTextureManager.GetEncodedImageBuffer(url.GetUrl()), desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, MakeCallback(this, &TextureAsyncLoadingHelper::AsyncLoadComplete));
}
else
{
- auto id = GetImplementation(mLoader).Load(url, desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, loadYuvPlanes);
- mLoadingInfoContainer.back().loadId = id;
+ loadingTask = new LoadingTask(++mLoadTaskId, url, desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, loadYuvPlanes, MakeCallback(this, &TextureAsyncLoadingHelper::AsyncLoadComplete));
}
+
+ loadingTask->SetTextureId(textureId);
+ Dali::AsyncTaskManager::Get().AddTask(loadingTask);
}
void TextureAsyncLoadingHelper::ApplyMask(const TextureManager::TextureId& textureId,
const bool& cropToMask,
const DevelAsyncImageLoader::PreMultiplyOnLoad& preMultiplyOnLoad)
{
- mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId));
- auto id = GetImplementation(mLoader).ApplyMask(pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad);
- mLoadingInfoContainer.back().loadId = id;
-}
-
-TextureAsyncLoadingHelper::TextureAsyncLoadingHelper(TextureAsyncLoadingHelper&& rhs)
-: TextureAsyncLoadingHelper(rhs.mLoader, rhs.mTextureManager, std::move(rhs.mLoadingInfoContainer))
-{
-}
-TextureAsyncLoadingHelper::TextureAsyncLoadingHelper(
- Toolkit::AsyncImageLoader loader,
- TextureManager& textureManager,
- AsyncLoadingInfoContainerType&& loadingInfoContainer)
-: mLoader(loader),
- mTextureManager(textureManager),
- mLoadingInfoContainer(std::move(loadingInfoContainer))
-{
- DevelAsyncImageLoader::PixelBufferLoadedSignal(mLoader).Connect(
- this, &TextureAsyncLoadingHelper::AsyncLoadComplete);
+ LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad, MakeCallback(this, &TextureAsyncLoadingHelper::AsyncLoadComplete));
+ loadingTask->SetTextureId(textureId);
+ Dali::AsyncTaskManager::Get().AddTask(loadingTask);
}
-void TextureAsyncLoadingHelper::AsyncLoadComplete(uint32_t id,
- std::vector<Devel::PixelBuffer>& pixelBuffers)
+void TextureAsyncLoadingHelper::AsyncLoadComplete(LoadingTaskPtr task)
{
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureAsyncLoadingHelper::AsyncLoadComplete( loadId :%d )\n", id);
- if(mLoadingInfoContainer.size() >= 1u)
+ // Call TextureManager::AsyncLoadComplete
+ if(task->textureId != TextureManager::INVALID_TEXTURE_ID)
{
- AsyncLoadingInfo loadingInfo = mLoadingInfoContainer.front();
-
- // We can assume that First Loading task comes First.
- if(loadingInfo.loadId == id)
- {
- // Call TextureManager::AsyncLoadComplete
- mTextureManager.AsyncLoadComplete(loadingInfo.textureId, pixelBuffers);
- }
-
- mLoadingInfoContainer.pop_front();
+ mTextureManager.AsyncLoadComplete(task->textureId, task->pixelBuffers);
}
}
#include <deque>
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
+#include <dali-toolkit/internal/image-loader/loading-task.h>
#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
namespace Dali
{
namespace Internal
{
+
/**
* @brief Helper class to keep the relation between AsyncImageLoader and corresponding LoadingInfo container
*/
class TextureAsyncLoadingHelper : public ConnectionTracker
{
- /**
- * Struct to hold information about a requested Async load.
- * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
- */
- struct AsyncLoadingInfo
- {
- AsyncLoadingInfo(TextureManager::TextureId textureId)
- : textureId(textureId),
- loadId(0)
- {
- }
-
- TextureManager::TextureId textureId; ///< The external Texture Id assigned to this load
- std::uint32_t loadId; ///< The load Id used by the async loader to reference this load
- };
-
public:
/**
* @brief Create an TextureAsyncLoadingHelper.
TextureAsyncLoadingHelper(const TextureAsyncLoadingHelper&) = delete;
TextureAsyncLoadingHelper& operator=(const TextureAsyncLoadingHelper&) = delete;
- TextureAsyncLoadingHelper(TextureAsyncLoadingHelper&& rhs);
- TextureAsyncLoadingHelper& operator=(TextureAsyncLoadingHelper&& rhs) = delete;
-
-private: // Private typedefs:
- typedef std::deque<AsyncLoadingInfo> AsyncLoadingInfoContainerType; ///< The container type used to manage Asynchronous loads in progress
-
private:
/**
- * @brief Main constructor that used by all other constructors
- */
- TextureAsyncLoadingHelper(Toolkit::AsyncImageLoader loader,
- TextureManager& textureManager,
- AsyncLoadingInfoContainerType&& loadingInfoContainer);
-
- /**
* @brief Callback to be called when texture loading is complete, it passes the pixel buffer list on to texture manager.
- * @param[in] id Loader id
- * @param[in] pixelBuffers Image data
+ * @param[in] task LoadingTaskPtr
*/
- void AsyncLoadComplete(std::uint32_t id, std::vector<Devel::PixelBuffer>& pixelBuffers);
+ void AsyncLoadComplete(LoadingTaskPtr task);
private: // Member Variables:
- Toolkit::AsyncImageLoader mLoader;
- TextureManager& mTextureManager;
- AsyncLoadingInfoContainerType mLoadingInfoContainer;
+ TextureManager& mTextureManager;
+ uint32_t mLoadTaskId;
};
} // namespace Internal
namespace
{
constexpr auto INITIAL_HASH_NUMBER = size_t{0u};
-constexpr auto DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS = size_t{4u};
-constexpr auto DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS = size_t{8u};
constexpr auto TEXTURE_INDEX = 0u; ///< The Index for texture
constexpr auto MASK_TEXTURE_INDEX = 1u; ///< The Index for mask texture
constexpr auto NUMBER_OF_REMOTE_LOADER_THREADS_ENV = "DALI_TEXTURE_REMOTE_THREADS";
constexpr auto LOAD_IMAGE_YUV_PLANES_ENV = "DALI_LOAD_IMAGE_YUV_PLANES";
-size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue)
-{
- using Dali::EnvironmentVariable::GetEnvironmentVariable;
- auto numberString = GetEnvironmentVariable(environmentVariable);
- auto numberOfThreads = numberString ? std::strtoul(numberString, nullptr, 10) : 0;
- constexpr auto MAX_NUMBER_OF_THREADS = 100u;
- DALI_ASSERT_DEBUG(numberOfThreads < MAX_NUMBER_OF_THREADS);
- return (numberOfThreads > 0 && numberOfThreads < MAX_NUMBER_OF_THREADS) ? numberOfThreads : defaultValue;
-}
-
-size_t GetNumberOfLocalLoaderThreads()
-{
- return GetNumberOfThreads(NUMBER_OF_LOCAL_LOADER_THREADS_ENV, DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS);
-}
-
-size_t GetNumberOfRemoteLoaderThreads()
-{
- return GetNumberOfThreads(NUMBER_OF_REMOTE_LOADER_THREADS_ENV, DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS);
-}
-
bool NeedToLoadYuvPlanes()
{
auto loadYuvPlanesString = Dali::EnvironmentVariable::GetEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV);
TextureManager::TextureManager()
: mTextureCacheManager(),
- mAsyncLocalLoaders(GetNumberOfLocalLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }),
- mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }),
+ mAsyncLoader(std::unique_ptr<TextureAsyncLoadingHelper>(new TextureAsyncLoadingHelper(*this))),
mLifecycleObservers(),
mLoadQueue(),
mRemoveQueue(),
// Update preMultiplyOnLoad value. It should be changed according to preMultiplied value of the cached info.
preMultiplyOnLoad = mTextureCacheManager[cacheIndex].preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
-
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d, maskTextureId=%d, frameindex=%d, premultiplied=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, frameIndex, mTextureCacheManager[cacheIndex].preMultiplied ? 1 : 0);
}
// Cache new texutre, and get cacheIndex.
cacheIndex = mTextureCacheManager.AppendCache(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex, loadYuvPlanes));
-
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d, maskTextureId=%d, frameindex=%d premultiply=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, maskTextureId, frameIndex, preMultiply);
}
TextureManager::LoadState::MASK_CANCELLED != textureInfo.loadState)
{
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d, maskTextureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, maskTextureId);
-
textureInfo.loadState = TextureManager::LoadState::NOT_STARTED;
}
void TextureManager::LoadTexture(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer)
{
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::LoadTexture(): url:%s sync:%s\n", textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously ? "T" : "F");
-
textureInfo.loadState = LoadState::LOADING;
if(!textureInfo.loadSynchronously)
{
- auto& loadersContainer = (textureInfo.url.IsLocalResource() || textureInfo.url.IsBufferResource()) ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
- auto loadingHelperIt = loadersContainer.GetNext();
auto premultiplyOnLoad = (textureInfo.preMultiplyOnLoad && textureInfo.maskTextureId == INVALID_TEXTURE_ID) ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
- DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End());
if(textureInfo.animatedImageLoading)
{
- loadingHelperIt->LoadAnimatedImage(textureInfo.textureId, textureInfo.animatedImageLoading, textureInfo.frameIndex, premultiplyOnLoad);
+ mAsyncLoader->LoadAnimatedImage(textureInfo.textureId, textureInfo.animatedImageLoading, textureInfo.frameIndex, premultiplyOnLoad);
}
else
{
- loadingHelperIt->Load(textureInfo.textureId, textureInfo.url, textureInfo.desiredSize, textureInfo.fittingMode, textureInfo.samplingMode, textureInfo.orientationCorrection, premultiplyOnLoad, textureInfo.loadYuvPlanes);
+ mAsyncLoader->Load(textureInfo.textureId, textureInfo.url, textureInfo.desiredSize, textureInfo.fittingMode, textureInfo.samplingMode, textureInfo.orientationCorrection, premultiplyOnLoad, textureInfo.loadYuvPlanes);
}
}
ObserveTexture(textureInfo, observer);
TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, " textureId:%d Url:%s CacheIndex:%d LoadState: %s\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState));
-
if(textureInfo.loadState != LoadState::CANCELLED && textureInfo.loadState != LoadState::MASK_CANCELLED)
{
// textureInfo can be invalidated after this call (as the mTextureInfoContainer may be modified)
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::ApplyMask(): url:%s sync:%s\n", textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously ? "T" : "F");
textureInfo.loadState = LoadState::MASK_APPLYING;
- auto& loadersContainer = (textureInfo.url.IsLocalResource() || textureInfo.url.IsBufferResource()) ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
- auto loadingHelperIt = loadersContainer.GetNext();
- auto premultiplyOnLoad = textureInfo.preMultiplyOnLoad ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
- DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End());
- loadingHelperIt->ApplyMask(textureInfo.textureId, pixelBuffer, maskPixelBuffer, textureInfo.scaleFactor, textureInfo.cropToMask, premultiplyOnLoad);
+ auto premultiplyOnLoad = textureInfo.preMultiplyOnLoad ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
+ mAsyncLoader->ApplyMask(textureInfo.textureId, pixelBuffer, maskPixelBuffer, textureInfo.scaleFactor, textureInfo.cropToMask, premultiplyOnLoad);
}
}
// Texture load requests for the same URL are deferred until the end of this
// method.
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() textureId:%d url:%s loadState:%s\n", textureId, info->url.GetUrl().c_str(), GET_LOAD_STATE_STRING(info->loadState));
-
// It is possible for the observer to be deleted.
// Disconnect and remove the observer first.
observer->DestructionSignal().Disconnect(this, &TextureManager::ObserverDestroyed);
#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/adaptor-framework/round-robin-container-view.h>
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
-#include <dali-toolkit/internal/helpers/round-robin-container-view.h>
#include <dali-toolkit/internal/texture-manager/texture-cache-manager.h>
#include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
#include <dali-toolkit/internal/texture-manager/texture-upload-observer.h>
private: // Member Variables:
TextureCacheManager mTextureCacheManager; ///< Manager the life-cycle and caching of Textures
-
- RoundRobinContainerView<TextureAsyncLoadingHelper> mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads
- RoundRobinContainerView<TextureAsyncLoadingHelper> mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
-
+ std::unique_ptr<TextureAsyncLoadingHelper> mAsyncLoader; ///< The Asynchronous image loader used to provide all local async loads
Dali::Vector<LifecycleObserver*> mLifecycleObservers; ///< Lifecycle observers of texture manager
Dali::Vector<QueueElement> mLoadQueue; ///< Queue of textures to load after NotifyObservers
Dali::Vector<QueueElement> mRemoveQueue; ///< Queue of textures to remove after NotifyObservers
#include <dali/devel-api/threading/thread.h>
#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
#include <dali/public-api/signals/connection-tracker.h>
+#include <dali/public-api/adaptor-framework/round-robin-container-view.h>
#include <memory>
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/helpers/round-robin-container-view.h>
#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
#include <dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.h>
+++ /dev/null
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "svg-rasterize-thread.h"
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/environment-variable.h>
-#include <dali/devel-api/adaptor-framework/file-loader.h>
-#include <dali/devel-api/adaptor-framework/thread-settings.h>
-#include <dali/integration-api/adaptor-framework/adaptor.h>
-#include <dali/integration-api/debug.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/visuals/svg/svg-visual.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-namespace
-{
-constexpr auto DEFAULT_NUMBER_OF_SVG_RASTERIZE_THREADS = size_t{4u};
-constexpr auto NUMBER_OF_SVG_RASTERIZE_THREADS_ENV = "DALI_SVG_RASTERIZE_THREADS";
-
-size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue)
-{
- auto numberString = EnvironmentVariable::GetEnvironmentVariable(environmentVariable);
- auto numberOfThreads = numberString ? std::strtoul(numberString, nullptr, 10) : 0;
- constexpr auto MAX_NUMBER_OF_THREADS = 10u;
- DALI_ASSERT_DEBUG(numberOfThreads < MAX_NUMBER_OF_THREADS);
- return (numberOfThreads > 0 && numberOfThreads < MAX_NUMBER_OF_THREADS) ? numberOfThreads : defaultValue;
-}
-
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gVectorImageLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_IMAGE");
-#endif
-
-} // unnamed namespace
-
-SvgTask::SvgTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer)
-: mSvgVisual(svgVisual),
- mVectorRenderer(vectorRenderer),
- mHasSucceeded(false)
-{
-}
-
-SvgVisual* SvgTask::GetSvgVisual() const
-{
- return mSvgVisual.Get();
-}
-
-PixelData SvgTask::GetPixelData() const
-{
- return PixelData();
-}
-
-bool SvgTask::HasSucceeded() const
-{
- return mHasSucceeded;
-}
-
-SvgLoadingTask::SvgLoadingTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi)
-: SvgTask(svgVisual, vectorRenderer),
- mUrl(url),
- mDpi(dpi)
-{
-}
-
-SvgLoadingTask::~SvgLoadingTask()
-{
-}
-
-void SvgLoadingTask::Process()
-{
- if(mVectorRenderer.IsLoaded())
- {
- // Already loaded
- mHasSucceeded = true;
- return;
- }
-
- Dali::Vector<uint8_t> buffer;
-
- if(!mUrl.IsLocalResource())
- {
- if(!Dali::FileLoader::DownloadFileSynchronously(mUrl.GetUrl(), buffer))
- {
- DALI_LOG_ERROR("Failed to download file! [%s]\n", mUrl.GetUrl().c_str());
- return;
- }
- }
- else
- {
- if(!Dali::FileLoader::ReadFile(mUrl.GetUrl(), buffer))
- {
- DALI_LOG_ERROR("Failed to read file! [%s]\n", mUrl.GetUrl().c_str());
- return;
- }
- }
-
- buffer.PushBack('\0');
-
- if(!mVectorRenderer.Load(buffer, mDpi))
- {
- DALI_LOG_ERROR("Failed to load data! [%s]\n", mUrl.GetUrl().c_str());
- return;
- }
-
- mHasSucceeded = true;
-}
-
-SvgRasterizingTask::SvgRasterizingTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer, unsigned int width, unsigned int height)
-: SvgTask(svgVisual, vectorRenderer),
- mWidth(width),
- mHeight(height)
-{
-}
-
-SvgRasterizingTask::~SvgRasterizingTask()
-{
-}
-
-void SvgRasterizingTask::Process()
-{
- if(!mVectorRenderer.IsLoaded())
- {
- DALI_LOG_ERROR("File is not loaded!\n");
- return;
- }
-
- DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "Rasterize: (%d x %d) [%p]\n", mWidth, mHeight, this);
-
- Devel::PixelBuffer pixelBuffer = mVectorRenderer.Rasterize(mWidth, mHeight);
- if(!pixelBuffer)
- {
- DALI_LOG_ERROR("Rasterize is failed!\n");
- return;
- }
-
- mPixelData = Devel::PixelBuffer::Convert(pixelBuffer);
- mHasSucceeded = true;
-}
-
-bool SvgRasterizingTask::IsReady()
-{
- return mVectorRenderer.IsLoaded();
-}
-
-PixelData SvgRasterizingTask::GetPixelData() const
-{
- return mPixelData;
-}
-
-SvgRasterizeThread::SvgRasterizeThread(SvgRasterizeManager& svgRasterizeManager)
-: mConditionalWait(),
- mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
- mSvgRasterizeManager(svgRasterizeManager),
- mDestroyThread(false),
- mIsThreadStarted(false),
- mIsThreadIdle(true)
-{
-}
-
-SvgRasterizeThread::~SvgRasterizeThread()
-{
- // Stop the thread
- {
- ConditionalWait::ScopedLock lock(mConditionalWait);
- mDestroyThread = true;
- mConditionalWait.Notify(lock);
- }
-
- Join();
-}
-
-bool SvgRasterizeThread::RequestRasterize()
-{
- if(!mIsThreadStarted)
- {
- Start();
- mIsThreadStarted = true;
- }
-
- {
- // Lock while adding task to the queue
- ConditionalWait::ScopedLock lock(mConditionalWait);
-
- if(mIsThreadIdle)
- {
- mIsThreadIdle = false;
-
- // wake up the thread
- mConditionalWait.Notify(lock);
- return true;
- }
- }
-
- return false;
-}
-
-void SvgRasterizeThread::Run()
-{
- SetThreadName("SvgRasterizeThread");
- mLogFactory.InstallLogFunction();
-
- while(!mDestroyThread)
- {
- SvgTaskPtr task = mSvgRasterizeManager.NextTaskToProcess();
- if(!task)
- {
- ConditionalWait::ScopedLock lock(mConditionalWait);
- mIsThreadIdle = true;
- mConditionalWait.Wait(lock);
- }
- else
- {
- task->Process();
-
- mSvgRasterizeManager.AddCompletedTask(task);
- }
- }
-}
-
-SvgRasterizeManager::SvgRasterizeManager()
-: mRasterizers(GetNumberOfThreads(NUMBER_OF_SVG_RASTERIZE_THREADS_ENV, DEFAULT_NUMBER_OF_SVG_RASTERIZE_THREADS), [&]() { return RasterizeHelper(*this); }),
- mTrigger(new EventThreadCallback(MakeCallback(this, &SvgRasterizeManager::ApplyRasterizedSVGToSampler))),
- mProcessorRegistered(false)
-{
-}
-
-SvgRasterizeManager::~SvgRasterizeManager()
-{
- if(mProcessorRegistered)
- {
- Adaptor::Get().UnregisterProcessor(*this);
- }
-
- mRasterizers.Clear();
-}
-
-void SvgRasterizeManager::AddTask(SvgTaskPtr task)
-{
- {
- // Lock while adding task to the queue
- Mutex::ScopedLock lock(mMutex);
-
- // There are other tasks waiting for the rasterization
- if(!mRasterizeTasks.empty())
- {
- // Remove the tasks with the same renderer.
- // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
- // Rasterizing task only, loading task is not duplicated.
- for(std::vector<SvgTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
- {
- if((*it) && (*it)->GetSvgVisual() == task->GetSvgVisual())
- {
- SvgRasterizingTask* oldTask = dynamic_cast<SvgRasterizingTask*>(it->Get());
- SvgRasterizingTask* newTask = dynamic_cast<SvgRasterizingTask*>(task.Get());
- if(oldTask && newTask)
- {
- mRasterizeTasks.erase(it);
- break;
- }
- }
- }
- }
-
- mRasterizeTasks.push_back(task);
- }
-
- size_t count = mRasterizers.GetElementCount();
- size_t index = 0;
- while(index++ < count)
- {
- auto rasterizerHelperIt = mRasterizers.GetNext();
- DALI_ASSERT_ALWAYS(rasterizerHelperIt != mRasterizers.End());
-
- if(rasterizerHelperIt->RequestRasterize())
- {
- 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(!mProcessorRegistered)
- {
- Adaptor::Get().RegisterProcessor(*this);
- mProcessorRegistered = true;
- }
-
- return;
-}
-
-SvgTaskPtr SvgRasterizeManager::NextCompletedTask()
-{
- // Lock while popping task out from the queue
- Mutex::ScopedLock lock(mMutex);
-
- if(mCompletedTasks.empty())
- {
- return SvgTaskPtr();
- }
-
- std::vector<SvgTaskPtr>::iterator next = mCompletedTasks.begin();
- SvgTaskPtr nextTask = *next;
- mCompletedTasks.erase(next);
-
- return nextTask;
-}
-
-void SvgRasterizeManager::RemoveTask(SvgVisual* visual)
-{
- {
- // Lock while remove task from the queue
- Mutex::ScopedLock lock(mMutex);
- if(!mRasterizeTasks.empty())
- {
- for(std::vector<SvgTaskPtr>::iterator it = mRasterizeTasks.begin(); it != mRasterizeTasks.end();)
- {
- if((*it) && (*it)->GetSvgVisual() == visual)
- {
- it = mRasterizeTasks.erase(it);
- }
- else
- {
- it++;
- }
- }
- }
- }
-
- UnregisterProcessor();
-}
-
-SvgTaskPtr SvgRasterizeManager::NextTaskToProcess()
-{
- // Lock while popping task out from the queue
- Mutex::ScopedLock lock(mMutex);
-
- // pop out the next task from the queue
- SvgTaskPtr nextTask = nullptr;
-
- for(auto iter = mRasterizeTasks.begin(), endIter = mRasterizeTasks.end(); iter != endIter; ++iter)
- {
- if((*iter)->IsReady())
- {
- nextTask = *iter;
- mRasterizeTasks.erase(iter);
- break;
- }
- }
-
- return nextTask;
-}
-
-void SvgRasterizeManager::AddCompletedTask(SvgTaskPtr task)
-{
- // Lock while adding task to the queue
- Mutex::ScopedLock lock(mMutex);
- mCompletedTasks.push_back(task);
-
- // wake up the main thread
- mTrigger->Trigger();
-}
-
-void SvgRasterizeManager::ApplyRasterizedSVGToSampler()
-{
- while(SvgTaskPtr task = NextCompletedTask())
- {
- DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "task = %p\n", task.Get());
-
- task->GetSvgVisual()->ApplyRasterizedImage(task->GetPixelData(), task->HasSucceeded());
- }
-
- UnregisterProcessor();
-}
-
-void SvgRasterizeManager::Process(bool postProcessor)
-{
- ApplyRasterizedSVGToSampler();
-}
-
-void SvgRasterizeManager::UnregisterProcessor()
-{
- Mutex::ScopedLock lock(mMutex);
-
- if(mProcessorRegistered)
- {
- if(mRasterizeTasks.empty() && mCompletedTasks.empty())
- {
- Adaptor::Get().UnregisterProcessor(*this);
- mProcessorRegistered = false;
- }
- }
-}
-
-SvgRasterizeManager::RasterizeHelper::RasterizeHelper(SvgRasterizeManager& svgRasterizeManager)
-: RasterizeHelper(std::unique_ptr<SvgRasterizeThread>(new SvgRasterizeThread(svgRasterizeManager)), svgRasterizeManager)
-{
-}
-
-SvgRasterizeManager::RasterizeHelper::RasterizeHelper(RasterizeHelper&& rhs)
-: RasterizeHelper(std::move(rhs.mRasterizer), rhs.mSvgRasterizeManager)
-{
-}
-
-SvgRasterizeManager::RasterizeHelper::RasterizeHelper(std::unique_ptr<SvgRasterizeThread> rasterizer, SvgRasterizeManager& svgRasterizeManager)
-: mRasterizer(std::move(rasterizer)),
- mSvgRasterizeManager(svgRasterizeManager)
-{
-}
-
-bool SvgRasterizeManager::RasterizeHelper::RequestRasterize()
-{
- return mRasterizer->RequestRasterize();
-}
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_SVG_RASTERIZE_THREAD_H
-#define DALI_TOOLKIT_SVG_RASTERIZE_THREAD_H
-
-/*
- * Copyright (c) 2022 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/devel-api/adaptor-framework/event-thread-callback.h>
-#include <dali/devel-api/adaptor-framework/vector-image-renderer.h>
-#include <dali/devel-api/threading/conditional-wait.h>
-#include <dali/devel-api/threading/mutex.h>
-#include <dali/devel-api/threading/thread.h>
-#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
-#include <dali/integration-api/processor-interface.h>
-#include <dali/public-api/common/intrusive-ptr.h>
-#include <dali/public-api/common/vector-wrapper.h>
-#include <dali/public-api/images/pixel-data.h>
-#include <dali/public-api/object/ref-object.h>
-#include <memory>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/helpers/round-robin-container-view.h>
-#include <dali-toolkit/internal/visuals/visual-url.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-class SvgVisual;
-typedef IntrusivePtr<SvgVisual> SvgVisualPtr;
-class SvgTask;
-typedef IntrusivePtr<SvgTask> SvgTaskPtr;
-class SvgRasterizeManager;
-
-/**
- * The svg rasterizing tasks to be processed in the worker thread.
- *
- * Life cycle of a rasterizing task is as follows:
- * 1. Created by SvgVisual in the main thread
- * 2. Queued in the worked thread waiting to be processed.
- * 3. If this task gets its turn to do the rasterization, it triggers main thread to apply the rasterized image to material then been deleted in main thread call back
- * Or if this task is been removed ( new image/size set to the visual or actor off stage) before its turn to be processed, it then been deleted in the worker thread.
- */
-class SvgTask : public RefObject
-{
-public:
- /**
- * Constructor
- * @param[in] svgVisual The visual which the rasterized image to be applied.
- * @param[in] vectorRenderer The vector rasterizer.
- */
- SvgTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer);
-
- /**
- * Destructor.
- */
- virtual ~SvgTask() = default;
-
- /**
- * Process the task
- */
- virtual void Process() = 0;
-
- /**
- * Whether the task is ready to process.
- * @return True if the task is ready to process.
- */
- virtual bool IsReady()
- {
- return true;
- }
-
- /**
- * Whether the task has succeeded.
- * @return True if the task has succeeded.
- */
- bool HasSucceeded() const;
-
- /**
- * Get the svg visual
- */
- SvgVisual* GetSvgVisual() const;
-
- /**
- * Get the rasterization result.
- * @return The pixel data with the rasterized pixels.
- */
- virtual PixelData GetPixelData() const;
-
-private:
- // Undefined
- SvgTask(const SvgTask& task) = delete;
-
- // Undefined
- SvgTask& operator=(const SvgTask& task) = delete;
-
-protected:
- SvgVisualPtr mSvgVisual;
- VectorImageRenderer mVectorRenderer;
- bool mHasSucceeded;
-};
-
-class SvgLoadingTask : public SvgTask
-{
-public:
- /**
- * Constructor
- * @param[in] svgVisual The visual which the rasterized image to be applied.
- * @param[in] vectorRenderer The vector rasterizer.
- * @param[in] url The URL to svg resource to use.
- * @param[in] dpi The DPI of the screen.
- */
- SvgLoadingTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi);
-
- /**
- * Destructor.
- */
- ~SvgLoadingTask() override;
-
- /**
- * Process the task
- */
- void Process() override;
-
-private:
- // Undefined
- SvgLoadingTask(const SvgLoadingTask& task) = delete;
-
- // Undefined
- SvgLoadingTask& operator=(const SvgLoadingTask& task) = delete;
-
-private:
- VisualUrl mUrl;
- float mDpi;
-};
-
-class SvgRasterizingTask : public SvgTask
-{
-public:
- /**
- * Constructor
- * @param[in] svgVisual The visual which the rasterized image to be applied.
- * @param[in] vectorRenderer The vector rasterizer.
- * @param[in] width The rasterization width.
- * @param[in] height The rasterization height.
- */
- SvgRasterizingTask(SvgVisual* svgVisual, VectorImageRenderer vectorRenderer, unsigned int width, unsigned int height);
-
- /**
- * Destructor.
- */
- ~SvgRasterizingTask() override;
-
- /**
- * Process the task accodring to the type
- */
- void Process() override;
-
- /**
- * Whether the task is ready to process.
- * @return True if the task is ready to process.
- */
- bool IsReady() override;
-
- /**
- * Get the rasterization result.
- * @return The pixel data with the rasterized pixels.
- */
- PixelData GetPixelData() const override;
-
-private:
- // Undefined
- SvgRasterizingTask(const SvgRasterizingTask& task) = delete;
-
- // Undefined
- SvgRasterizingTask& operator=(const SvgRasterizingTask& task) = delete;
-
-private:
- PixelData mPixelData;
- uint32_t mWidth;
- uint32_t mHeight;
-};
-
-/**
- * The worker thread for SVG rasterization.
- */
-class SvgRasterizeThread : public Thread
-{
-public:
- /**
- * Constructor.
- */
- SvgRasterizeThread(SvgRasterizeManager& svgRasterizeManager);
-
- /**
- * Destructor.
- */
- ~SvgRasterizeThread() override;
-
- /**
- * @brief Request the thread to rasterizes the task.
- * @return True if the request succeeds, otherwise false.
- */
- bool RequestRasterize();
-
-protected:
- /**
- * The entry function of the worker thread.
- * It rasterizes the image.
- */
- void Run() override;
-
-private:
- // Undefined
- SvgRasterizeThread(const SvgRasterizeThread& thread) = delete;
-
- // Undefined
- SvgRasterizeThread& operator=(const SvgRasterizeThread& thread) = delete;
-
-private:
- ConditionalWait mConditionalWait;
- const Dali::LogFactoryInterface& mLogFactory;
- SvgRasterizeManager& mSvgRasterizeManager;
- bool mDestroyThread;
- bool mIsThreadStarted;
- bool mIsThreadIdle;
-};
-
-/**
- * The manager for SVG rasterization.
- */
-class SvgRasterizeManager : Integration::Processor
-{
-public:
- /**
- * Constructor.
- *
- * @param[in] trigger The trigger to wake up the main thread.
- */
- SvgRasterizeManager();
-
- /**
- * Destructor.
- */
- ~SvgRasterizeManager() override;
-
- /**
- * Add a rasterization task into the waiting queue, called by main thread.
- *
- * @param[in] task The task added to the queue.
- */
- void AddTask(SvgTaskPtr task);
-
- /**
- * Pop the next task out from the completed queue, called by main thread.
- *
- * @return The next task in the completed queue.
- */
- SvgTaskPtr NextCompletedTask();
-
- /**
- * Remove the task with the given visual from the waiting queue, called by main thread.
- *
- * Typically called when the actor is put off stage, so the renderer is not needed anymore.
- *
- * @param[in] visual The visual pointer.
- */
- void RemoveTask(SvgVisual* visual);
-
- /**
- * @copydoc Dali::Integration::Processor::Process()
- */
- void Process(bool postProcessor) override;
-
- /**
- * Pop the next task out from the queue.
- *
- * @return The next task to be processed.
- */
- SvgTaskPtr NextTaskToProcess();
-
- /**
- * Add a task in to the queue
- *
- * @param[in] task The task added to the queue.
- */
- void AddCompletedTask(SvgTaskPtr task);
-
-private:
- /**
- * Applies the rasterized image to material
- */
- void ApplyRasterizedSVGToSampler();
-
- /**
- * @brief Unregister a previously registered processor
- *
- */
- void UnregisterProcessor();
-
-private:
- /**
- * @brief Helper class to keep the relation between SvgRasterizeThread and corresponding container
- */
- class RasterizeHelper
- {
- public:
- /**
- * @brief Create an RasterizeHelper.
- *
- * @param[in] svgRasterizeManager Reference to the SvgRasterizeManager
- */
- RasterizeHelper(SvgRasterizeManager& svgRasterizeManager);
-
- /**
- * @brief Request the thread to rasterizes the task.
- * @return True if the request succeeds, otherwise false.
- */
- bool RequestRasterize();
-
- public:
- RasterizeHelper(const RasterizeHelper&) = delete;
- RasterizeHelper& operator=(const RasterizeHelper&) = delete;
-
- RasterizeHelper(RasterizeHelper&& rhs);
- RasterizeHelper& operator=(RasterizeHelper&& rhs) = delete;
-
- private:
- /**
- * @brief Main constructor that used by all other constructors
- */
- RasterizeHelper(std::unique_ptr<SvgRasterizeThread> rasterizer, SvgRasterizeManager& svgRasterizeManager);
-
- private:
- std::unique_ptr<SvgRasterizeThread> mRasterizer;
- SvgRasterizeManager& mSvgRasterizeManager;
- };
-
-private:
- // Undefined
- SvgRasterizeManager(const SvgRasterizeManager& thread);
-
- // Undefined
- SvgRasterizeManager& operator=(const SvgRasterizeManager& thread);
-
-private:
- std::vector<SvgTaskPtr> mRasterizeTasks; //The queue of the tasks waiting to rasterize the SVG image
- std::vector<SvgTaskPtr> mCompletedTasks; //The queue of the tasks with the SVG rasterization completed
-
- RoundRobinContainerView<RasterizeHelper> mRasterizers;
-
- Dali::Mutex mMutex;
- std::unique_ptr<EventThreadCallback> mTrigger;
- bool mProcessorRegistered;
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_SVG_RASTERIZE_THREAD_H
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "svg-task.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/svg/svg-visual.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+SvgTask::SvgTask(VectorImageRenderer vectorRenderer, CallbackBase* callback)
+: AsyncTask(callback),
+ mVectorRenderer(vectorRenderer),
+ mHasSucceeded(false)
+{
+}
+
+PixelData SvgTask::GetPixelData() const
+{
+ return PixelData();
+}
+
+bool SvgTask::HasSucceeded() const
+{
+ return mHasSucceeded;
+}
+
+VectorImageRenderer SvgTask::GetRenderer()
+{
+ return mVectorRenderer;
+}
+
+SvgLoadingTask::SvgLoadingTask(VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, CallbackBase* callback)
+: SvgTask(vectorRenderer, callback),
+ mUrl(url),
+ mDpi(dpi)
+{
+}
+
+SvgLoadingTask::~SvgLoadingTask()
+{
+}
+
+void SvgLoadingTask::Process()
+{
+ if(mVectorRenderer.IsLoaded())
+ {
+ // Already loaded
+ mHasSucceeded = true;
+ return;
+ }
+
+ Dali::Vector<uint8_t> buffer;
+
+ if(!mUrl.IsLocalResource())
+ {
+ if(!Dali::FileLoader::DownloadFileSynchronously(mUrl.GetUrl(), buffer))
+ {
+ DALI_LOG_ERROR("Failed to download file! [%s]\n", mUrl.GetUrl().c_str());
+ return;
+ }
+ }
+ else
+ {
+ if(!Dali::FileLoader::ReadFile(mUrl.GetUrl(), buffer))
+ {
+ DALI_LOG_ERROR("Failed to read file! [%s]\n", mUrl.GetUrl().c_str());
+ return;
+ }
+ }
+
+ buffer.PushBack('\0');
+
+ if(!mVectorRenderer.Load(buffer, mDpi))
+ {
+ DALI_LOG_ERROR("Failed to load data! [%s]\n", mUrl.GetUrl().c_str());
+ return;
+ }
+
+ mHasSucceeded = true;
+}
+
+bool SvgLoadingTask::IsReady()
+{
+ return true;
+}
+
+SvgRasterizingTask::SvgRasterizingTask(VectorImageRenderer vectorRenderer, uint32_t width, uint32_t height, CallbackBase* callback)
+: SvgTask(vectorRenderer, callback),
+ mWidth(width),
+ mHeight(height)
+{
+}
+
+SvgRasterizingTask::~SvgRasterizingTask()
+{
+}
+
+void SvgRasterizingTask::Process()
+{
+ if(!mVectorRenderer.IsLoaded())
+ {
+ DALI_LOG_ERROR("File is not loaded!\n");
+ return;
+ }
+
+ Devel::PixelBuffer pixelBuffer = mVectorRenderer.Rasterize(mWidth, mHeight);
+ if(!pixelBuffer)
+ {
+ DALI_LOG_ERROR("Rasterize is failed!\n");
+ return;
+ }
+
+ mPixelData = Devel::PixelBuffer::Convert(pixelBuffer);
+ mHasSucceeded = true;
+}
+
+bool SvgRasterizingTask::IsReady()
+{
+ return mVectorRenderer.IsLoaded();
+}
+
+PixelData SvgRasterizingTask::GetPixelData() const
+{
+ return mPixelData;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_SVG_TASK_H
+#define DALI_TOOLKIT_SVG_TASK_H
+
+/*
+ * Copyright (c) 2022 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/devel-api/adaptor-framework/vector-image-renderer.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+class SvgVisual;
+typedef IntrusivePtr<SvgVisual> SvgVisualPtr;
+class SvgTask;
+typedef IntrusivePtr<SvgTask> SvgTaskPtr;
+
+/**
+ * The svg rasterizing tasks to be processed in the worker thread.
+ *
+ * Life cycle of a rasterizing task is as follows:
+ * 1. Created by SvgVisual in the main thread
+ * 2. Queued in the worked thread waiting to be processed.
+ * 3. If this task gets its turn to do the rasterization, it triggers main thread to apply the rasterized image to material then been deleted in main thread call back
+ * Or if this task is been removed ( new image/size set to the visual or actor off stage) before its turn to be processed, it then been deleted in the worker thread.
+ */
+class SvgTask : public AsyncTask
+{
+public:
+ /**
+ * Constructor
+ * @param[in] vectorRenderer The vector rasterizer.
+ * @param[in] callback The callback that is called when the operation is completed.
+ */
+ SvgTask(VectorImageRenderer vectorRenderer, CallbackBase* callback);
+
+ /**
+ * Destructor.
+ */
+ virtual ~SvgTask() = default;
+
+ /**
+ * Process the task
+ */
+ virtual void Process() = 0;
+
+ /**
+ * Whether the task is ready to process.
+ * @return True if the task is ready to process.
+ */
+ virtual bool IsReady() = 0;
+
+ /**
+ * Whether the task has succeeded.
+ * @return True if the task has succeeded.
+ */
+ bool HasSucceeded() const;
+
+ /**
+ * @brief Get the task's imageRenderer
+ * @return VectorImageRenderer
+ */
+ VectorImageRenderer GetRenderer();
+
+ /**
+ * Get the rasterization result.
+ * @return The pixel data with the rasterized pixels.
+ */
+ virtual PixelData GetPixelData() const;
+
+private:
+ // Undefined
+ SvgTask(const SvgTask& task) = delete;
+
+ // Undefined
+ SvgTask& operator=(const SvgTask& task) = delete;
+
+protected:
+ VectorImageRenderer mVectorRenderer;
+ bool mHasSucceeded;
+};
+
+class SvgLoadingTask : public SvgTask
+{
+public:
+ /**
+ * Constructor
+ * @param[in] vectorRenderer The vector rasterizer.
+ * @param[in] url The URL to svg resource to use.
+ * @param[in] dpi The DPI of the screen.
+ * @param[in] callback The callback that is called when the operation is completed.
+ */
+ SvgLoadingTask(VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, CallbackBase* callback);
+
+ /**
+ * Destructor.
+ */
+ ~SvgLoadingTask() override;
+
+ /**
+ * Process the task
+ */
+ void Process() override;
+
+ /**
+ * Whether the task is ready to process.
+ * @return True if the task is ready to process.
+ */
+ bool IsReady() override;
+
+private:
+ // Undefined
+ SvgLoadingTask(const SvgLoadingTask& task) = delete;
+
+ // Undefined
+ SvgLoadingTask& operator=(const SvgLoadingTask& task) = delete;
+
+private:
+ VisualUrl mUrl;
+ float mDpi;
+};
+
+class SvgRasterizingTask : public SvgTask
+{
+public:
+ /**
+ * Constructor
+ * @param[in] vectorRenderer The vector rasterizer.
+ * @param[in] width The rasterization width.
+ * @param[in] height The rasterization height.
+ * @param[in] callback The callback that is called when the operation is completed.
+ */
+ SvgRasterizingTask(VectorImageRenderer vectorRenderer, uint32_t width, uint32_t height, CallbackBase* callback);
+
+ /**
+ * Destructor.
+ */
+ ~SvgRasterizingTask() override;
+
+ /**
+ * Process the task accodring to the type
+ */
+ void Process() override;
+
+ /**
+ * Whether the task is ready to process.
+ * @return True if the task is ready to process.
+ */
+ bool IsReady() override;
+
+ /**
+ * Get the rasterization result.
+ * @return The pixel data with the rasterized pixels.
+ */
+ PixelData GetPixelData() const override;
+
+private:
+ // Undefined
+ SvgRasterizingTask(const SvgRasterizingTask& task) = delete;
+
+ // Undefined
+ SvgRasterizingTask& operator=(const SvgRasterizingTask& task) = delete;
+
+private:
+ PixelData mPixelData;
+ uint32_t mWidth;
+ uint32_t mHeight;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SVG_TASK_H
// INTERNAL INCLUDES
#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
-#include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
+#include <dali-toolkit/internal/visuals/svg/svg-task.h>
#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
Vector2 dpi = Stage::GetCurrent().GetDpi();
float meanDpi = (dpi.height + dpi.width) * 0.5f;
- SvgTaskPtr newTask = new SvgLoadingTask(this, mVectorRenderer, mImageUrl, meanDpi);
+ mLoadingTask = new SvgLoadingTask(mVectorRenderer, mImageUrl, meanDpi, MakeCallback(this, &SvgVisual::ApplyRasterizedImage));
if(IsSynchronousLoadingRequired() && mImageUrl.IsLocalResource())
{
- newTask->Process();
+ mLoadingTask->Process();
}
else
{
- mFactoryCache.GetSVGRasterizationManager()->AddTask(newTask);
+ Dali::AsyncTaskManager::Get().AddTask(mLoadingTask);
}
}
void SvgVisual::DoSetOffScene(Actor& actor)
{
- mFactoryCache.GetSVGRasterizationManager()->RemoveTask(this);
+ // Remove loading & rasterizing task
+ Dali::AsyncTaskManager::Get().RemoveTask(mLoadingTask);
+ Dali::AsyncTaskManager::Get().RemoveTask(mRasterizingTask);
+ mLoadingTask.Reset();
+ mRasterizingTask.Reset();
actor.RemoveRenderer(mImpl->mRenderer);
mPlacementActor.Reset();
unsigned int width = static_cast<unsigned int>(size.width);
unsigned int height = static_cast<unsigned int>(size.height);
- SvgTaskPtr newTask = new SvgRasterizingTask(this, mVectorRenderer, width, height);
+ mRasterizingTask = new SvgRasterizingTask(mVectorRenderer, width, height, MakeCallback(this, &SvgVisual::ApplyRasterizedImage));
if(IsSynchronousLoadingRequired() && mImageUrl.IsLocalResource())
{
- newTask->Process();
- ApplyRasterizedImage(newTask->GetPixelData(), newTask->HasSucceeded());
+ mRasterizingTask->Process();
+ ApplyRasterizedImage(mRasterizingTask);
}
else
{
- mFactoryCache.GetSVGRasterizationManager()->AddTask(newTask);
+ Dali::AsyncTaskManager::Get().AddTask(mRasterizingTask);
}
}
}
-void SvgVisual::ApplyRasterizedImage(PixelData rasterizedPixelData, bool success)
+void SvgVisual::ApplyRasterizedImage(SvgTaskPtr task)
{
- if(success)
+ if(task->HasSucceeded())
{
+ PixelData rasterizedPixelData = task->GetPixelData();
if(mDefaultWidth == 0 || mDefaultHeight == 0)
{
- mVectorRenderer.GetDefaultSize(mDefaultWidth, mDefaultHeight);
+ task->GetRenderer().GetDefaultSize(mDefaultWidth, mDefaultHeight);
}
// Rasterization success
ResourceReady(Toolkit::Visual::ResourceStatus::READY);
}
}
- else if(!success && !mLoadFailed)
+ else if(!mLoadFailed)
{
mLoadFailed = true;
// INTERNAL INCLUDES
#include <dali-toolkit/internal/visuals/visual-base-impl.h>
#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali-toolkit/internal/visuals/svg/svg-task.h>
namespace Dali
{
/**
* @bried Apply the rasterized image to the visual.
*
- * @param[in] rasterizedPixelData The pixel buffer with the rasterized pixels
- * @param[in] success Whether the task succeeds.
+ * @param[in] task SvgTaskPtr
*/
- void ApplyRasterizedImage(PixelData rasterizedPixelData, bool success);
+ void ApplyRasterizedImage(SvgTaskPtr task);
private:
/**
WeakHandle<Actor> mPlacementActor;
Vector2 mRasterizedSize;
Dali::ImageDimensions mDesiredSize{};
+ SvgTaskPtr mLoadingTask;
+ SvgTaskPtr mRasterizingTask;
bool mLoadFailed;
bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture
};
}
VisualFactoryCache::VisualFactoryCache(bool preMultiplyOnLoad)
-: mSvgRasterizeManager(nullptr),
- mVectorAnimationManager(nullptr),
+: mVectorAnimationManager(nullptr),
mPreMultiplyOnLoad(preMultiplyOnLoad),
mBrokenImageInfoContainer(),
mDefaultBrokenImageUrl(""),
return mNPatchLoader;
}
-SvgRasterizeManager* VisualFactoryCache::GetSVGRasterizationManager()
-{
- if(!mSvgRasterizeManager)
- {
- mSvgRasterizeManager = std::unique_ptr<SvgRasterizeManager>(new SvgRasterizeManager());
- }
- return mSvgRasterizeManager.get();
-}
-
VectorAnimationManager& VisualFactoryCache::GetVectorAnimationManager()
{
if(!mVectorAnimationManager)
// INTERNAL INCLUDES
#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
#include <dali-toolkit/internal/visuals/npatch-loader.h>
-#include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
#include <dali/devel-api/rendering/renderer-devel.h>
namespace Dali
NPatchLoader& GetNPatchLoader();
/**
- * Get the SVG rasterization manager.
- * @return A raw pointer pointing to the SVG rasterization manager.
- */
- SvgRasterizeManager* GetSVGRasterizationManager();
-
- /**
* Get the vector animation manager.
* @return A reference to the vector animation manager.
*/
TextureManager mTextureManager;
NPatchLoader mNPatchLoader;
- std::unique_ptr<SvgRasterizeManager> mSvgRasterizeManager;
std::unique_ptr<VectorAnimationManager> mVectorAnimationManager;
bool mPreMultiplyOnLoad;
std::vector<BrokenImageInfo> mBrokenImageInfoContainer;