From 6648cdfb9e2dd90cb8a34da7aaad71fce83ca05b Mon Sep 17 00:00:00 2001 From: tscholb Date: Tue, 20 Sep 2022 18:03:46 +0900 Subject: [PATCH] Add async task manager Change-Id: Id9b14090fa21bdc249f826a68d260fb5d013887e --- .../src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp | 53 ++- .../src/dali-toolkit/utc-Dali-CanvasView.cpp | 162 ++------ .../src/dali-toolkit/utc-Dali-ImageView.cpp | 21 +- .../src/dali-toolkit/utc-Dali-VisualFactory.cpp | 5 - .../controls/canvas-view/canvas-view-impl.cpp | 54 ++- .../controls/canvas-view/canvas-view-impl.h | 15 +- .../canvas-view/canvas-view-rasterize-task.cpp | 67 ++++ .../canvas-view/canvas-view-rasterize-task.h | 114 ++++++ .../canvas-view/canvas-view-rasterize-thread.cpp | 239 ----------- .../canvas-view/canvas-view-rasterize-thread.h | 222 ----------- dali-toolkit/internal/file.list | 8 +- .../internal/helpers/round-robin-container-view.h | 137 ------- .../image-loader/async-image-loader-impl.cpp | 112 +++--- .../image-loader/async-image-loader-impl.h | 33 +- .../internal/image-loader/image-atlas-impl.cpp | 56 +-- .../{image-load-thread.cpp => loading-task.cpp} | 201 +++------- .../{image-load-thread.h => loading-task.h} | 150 +++---- .../texture-async-loading-helper.cpp | 60 +-- .../texture-manager/texture-async-loading-helper.h | 42 +- .../texture-manager/texture-manager-impl.cpp | 45 +-- .../texture-manager/texture-manager-impl.h | 7 +- .../vector-animation-thread.h | 2 +- .../internal/visuals/svg/svg-rasterize-thread.cpp | 438 --------------------- .../internal/visuals/svg/svg-rasterize-thread.h | 378 ------------------ dali-toolkit/internal/visuals/svg/svg-task.cpp | 157 ++++++++ dali-toolkit/internal/visuals/svg/svg-task.h | 200 ++++++++++ dali-toolkit/internal/visuals/svg/svg-visual.cpp | 31 +- dali-toolkit/internal/visuals/svg/svg-visual.h | 8 +- .../internal/visuals/visual-factory-cache.cpp | 12 +- .../internal/visuals/visual-factory-cache.h | 8 - 30 files changed, 940 insertions(+), 2097 deletions(-) create mode 100644 dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-task.cpp create mode 100644 dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-task.h delete mode 100644 dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.cpp delete mode 100644 dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.h delete mode 100644 dali-toolkit/internal/helpers/round-robin-container-view.h rename dali-toolkit/internal/image-loader/{image-load-thread.cpp => loading-task.cpp} (60%) rename dali-toolkit/internal/image-loader/{image-load-thread.h => loading-task.h} (78%) delete mode 100644 dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp delete mode 100644 dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h create mode 100644 dali-toolkit/internal/visuals/svg/svg-task.cpp create mode 100644 dali-toolkit/internal/visuals/svg/svg-task.h diff --git a/automated-tests/src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp b/automated-tests/src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp index 067a34a..f68397d 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp @@ -21,6 +21,7 @@ #include #include #include +#include using namespace Dali; using namespace Dali::Toolkit; @@ -33,6 +34,8 @@ static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png"; 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 @@ -49,8 +52,11 @@ public: 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++; } @@ -210,12 +216,21 @@ int UtcDaliAsyncImageLoaderLoadAndLoadedSignal(void) 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)); @@ -223,7 +238,7 @@ int UtcDaliAsyncImageLoaderLoadAndLoadedSignal(void) } // 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; @@ -252,6 +267,19 @@ int UtcDaliAsyncImageLoaderCancel(void) 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; @@ -272,5 +300,18 @@ int UtcDaliAsyncImageLoaderCancelAll(void) 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 diff --git a/automated-tests/src/dali-toolkit/utc-Dali-CanvasView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-CanvasView.cpp index b55622f..1a9c1db 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-CanvasView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-CanvasView.cpp @@ -26,11 +26,12 @@ #include #include -#include -#include +#include +#include #include #include #include +#include using namespace Dali; using namespace Toolkit; @@ -270,41 +271,13 @@ int UtcDaliCanvasViewSizeN(void) END_TEST; } -int UtcDaliCanvasViewRasterizeTaskP(void) +bool gRasterizationCompletedSignal = false; +void rasteriztionCompleted(IntrusivePtr 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 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 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; @@ -314,16 +287,13 @@ int UtcDaliCanvasViewRasterizeThreadP(void) Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100)); DALI_TEST_CHECK(dummyCanvasRenderer); - IntrusivePtr task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer); + IntrusivePtr 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; @@ -333,68 +303,22 @@ int UtcDaliCanvasViewRasterizeThreadAddTaskP(void) Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100)); DALI_TEST_CHECK(dummyCanvasRenderer); - IntrusivePtr task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer); + IntrusivePtr task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyCanvasRenderer, MakeCallback(rasteriztionCompleted)); DALI_TEST_CHECK(task); - IntrusivePtr task2 = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer); + IntrusivePtr 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 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 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; @@ -404,15 +328,15 @@ int UtcDaliCanvasViewRasterizeThreadTerminateThreadP(void) Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100)); DALI_TEST_CHECK(dummyCanvasRenderer); - IntrusivePtr task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer); + IntrusivePtr 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; } @@ -427,57 +351,31 @@ PixelData CreatePixelData(unsigned int width, unsigned int height) 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 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 task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(&dummyInternalCanvasView, dummyCanvasRenderer); + IntrusivePtr 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; } diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp index 5797b88..3ca8543 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp @@ -2694,10 +2694,6 @@ void ReloadImage(ImageView imageView) void ResourceFailedReload(Control control) { gFailCounter++; - if(gFailCounter < MAX_RETRIES) - { - ReloadImage(ImageView::DownCast(control)); - } } } // namespace @@ -2716,17 +2712,14 @@ int UtcDaliImageViewReloadFailedOnResourceReadySignal(void) // 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; @@ -3866,8 +3859,6 @@ int UtcDaliImageViewOnResourceReadySignalWithBrokenAlphaMask02(void) imageView.ResourceReadySignal().Connect(&OnSimpleResourceReadySignal); application.GetScene().Add(imageView); - application.SendNotification(); - application.Render(); // Don't unparent imageView, for keep the cache. }; @@ -3885,7 +3876,8 @@ int UtcDaliImageViewOnResourceReadySignalWithBrokenAlphaMask02(void) // 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; @@ -4339,10 +4331,6 @@ int UtcDaliImageViewNpatchImageCacheTest02(void) textureCallStack.EnableLogging(true); auto TestBorderImage = [&](int index, const std::string& normalImageUrl, const Rect 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; @@ -4375,6 +4363,7 @@ int UtcDaliImageViewNpatchImageCacheTest02(void) 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); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp index e2081c4..92e54d4 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp @@ -1226,11 +1226,6 @@ int UtcDaliVisualFactoryGetNPatchVisual9(void) 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. diff --git a/dali-toolkit/internal/controls/canvas-view/canvas-view-impl.cpp b/dali-toolkit/internal/controls/canvas-view/canvas-view-impl.cpp index e298f10..2fff921 100644 --- a/dali-toolkit/internal/controls/canvas-view/canvas-view-impl.cpp +++ b/dali-toolkit/internal/controls/canvas-view/canvas-view-impl.cpp @@ -27,7 +27,6 @@ // INTERNAL INCLUDES #include -#include #include #include #include @@ -57,22 +56,16 @@ CanvasView::CanvasView(const Vector2& viewBox) 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); } } @@ -179,40 +172,37 @@ void CanvasView::Process(bool postProcessor) 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. diff --git a/dali-toolkit/internal/controls/canvas-view/canvas-view-impl.h b/dali-toolkit/internal/controls/canvas-view/canvas-view-impl.h index 92110f0..d7c8c4b 100644 --- a/dali-toolkit/internal/controls/canvas-view/canvas-view-impl.h +++ b/dali-toolkit/internal/controls/canvas-view/canvas-view-impl.h @@ -28,6 +28,7 @@ // INTERNAL INCLUDES #include #include +#include namespace Dali { @@ -135,20 +136,20 @@ public: /** * @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 diff --git a/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-task.cpp b/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-task.cpp new file mode 100644 index 0000000..21b4205 --- /dev/null +++ b/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-task.cpp @@ -0,0 +1,67 @@ +/* + * 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 diff --git a/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-task.h b/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-task.h new file mode 100644 index 0000000..ac375c0 --- /dev/null +++ b/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-task.h @@ -0,0 +1,114 @@ +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ +class CanvasRendererRasterizingTask; +using CanvasRendererRasterizingTaskPtr = IntrusivePtr; + +/** + * 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 diff --git a/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.cpp b/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.cpp deleted file mode 100644 index e3de638..0000000 --- a/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* - * 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 -#include - -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::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::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::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::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 diff --git a/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.h b/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.h deleted file mode 100644 index 8e96367..0000000 --- a/dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.h +++ /dev/null @@ -1,222 +0,0 @@ -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// INTERNAL INCLUDES -#include - -namespace Dali -{ -namespace Toolkit -{ -namespace Internal -{ -using CanvasViewPtr = IntrusivePtr; -class CanvasRendererRasterizingTask; -using CanvasRendererRasterizingTaskPtr = IntrusivePtr; - -/** - * 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; - -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 mRasterizeTasks; //The queue of the tasks waiting to rasterize the CanvasView. - std::vector mCompletedTasks; //The queue of the tasks with the SVG rasterization completed - - ConditionalWait mConditionalWait; - Dali::Mutex mMutex; - std::unique_ptr mTrigger; - const Dali::LogFactoryInterface& mLogFactory; - bool mProcessorRegistered; - RasterizationCompletedSignalType mRasterizationCompletedSignal; -}; - -} // namespace Internal - -} // namespace Toolkit - -} // namespace Dali - -#endif // DALI_TOOLKIT_CANVAS_VIEW_RASTERIZE_THREAD_H diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index ac79b42..698d8a4 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -42,7 +42,7 @@ SET( toolkit_src_files ${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 @@ -65,7 +65,7 @@ SET( toolkit_src_files ${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 @@ -124,9 +124,7 @@ SET( toolkit_src_files ${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 @@ -138,7 +136,7 @@ SET( toolkit_src_files ${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 diff --git a/dali-toolkit/internal/helpers/round-robin-container-view.h b/dali-toolkit/internal/helpers/round-robin-container-view.h deleted file mode 100644 index 5a5f07c..0000000 --- a/dali-toolkit/internal/helpers/round-robin-container-view.h +++ /dev/null @@ -1,137 +0,0 @@ - -#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 -#include - -namespace Dali -{ -namespace Toolkit -{ -namespace Internal -{ -/** - * @brief RoundRobinContainerView is a view to a container that allows iterating through the elements cyclically. - */ -template -class RoundRobinContainerView -{ -public: - using ContainerType = std::vector; - - /** - * @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 - 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 diff --git a/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp b/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp index 880db04..7ce566e 100644 --- a/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp +++ b/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp @@ -19,6 +19,7 @@ #include "async-image-loader-impl.h" // EXTERNAL INCLUDES +#include #include namespace Dali @@ -29,15 +30,13 @@ namespace Internal { AsyncImageLoader::AsyncImageLoader() : mLoadedSignal(), - mLoadThread(new EventThreadCallback(MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage))), - mLoadTaskId(0u), - mIsLoadThreadStarted(false) + mLoadTaskId(0u) { } AsyncImageLoader::~AsyncImageLoader() { - mLoadThread.CancelAll(); + CancelAll(); } IntrusivePtr AsyncImageLoader::New() @@ -50,13 +49,8 @@ uint32_t AsyncImageLoader::LoadAnimatedImage(Dali::AnimatedImageLoading 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; } @@ -68,13 +62,9 @@ uint32_t AsyncImageLoader::Load(const VisualUrl& url, 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; } @@ -85,13 +75,9 @@ uint32_t AsyncImageLoader::LoadEncodedImageBuffer(const EncodedImageBuffer& 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; } @@ -101,13 +87,9 @@ uint32_t AsyncImageLoader::ApplyMask(Devel::PixelBuffer pi 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; } @@ -123,33 +105,73 @@ Toolkit::DevelAsyncImageLoader::PixelBufferLoadedSignalType& AsyncImageLoader::P bool AsyncImageLoader::Cancel(uint32_t loadingTaskId) { - return mLoadThread.CancelTask(loadingTaskId); + // Remove already completed tasks + RemoveCompletedTask(); + + auto end = mLoadingTasks.end(); + for(std::vector::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::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::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; } } diff --git a/dali-toolkit/internal/image-loader/async-image-loader-impl.h b/dali-toolkit/internal/image-loader/async-image-loader-impl.h index 34496b1..a75fa32 100644 --- a/dali-toolkit/internal/image-loader/async-image-loader-impl.h +++ b/dali-toolkit/internal/image-loader/async-image-loader-impl.h @@ -23,7 +23,7 @@ // INTERNAL INCLUDES #include -#include +#include #include namespace Dali @@ -32,7 +32,21 @@ namespace Toolkit { namespace Internal { -class AsyncImageLoader : public BaseObject +using LoadingTaskPtr = IntrusivePtr; + +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: /** @@ -126,7 +140,7 @@ public: /** * Process the completed loading task from the worker thread. */ - void ProcessLoadedImage(); + void ProcessLoadedImage(LoadingTaskPtr task); protected: /** @@ -135,12 +149,17 @@ 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 mLoadingTasks; + std::vector mCompletedTaskIds; + uint32_t mLoadTaskId; }; } // namespace Internal diff --git a/dali-toolkit/internal/image-loader/image-atlas-impl.cpp b/dali-toolkit/internal/image-loader/image-atlas-impl.cpp index be946ab..2e86294 100644 --- a/dali-toolkit/internal/image-loader/image-atlas-impl.cpp +++ b/dali-toolkit/internal/image-loader/image-atlas-impl.cpp @@ -89,6 +89,12 @@ ImageAtlas::ImageAtlas(SizeType width, SizeType height, Pixel::Format pixelForma 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) { @@ -211,6 +217,7 @@ bool ImageAtlas::Upload(Vector4& textureRect, { 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(packPositionX) + 0.5f) / mWidth; // left textureRect.y = (static_cast(packPositionY) + 0.5f) / mHeight; // top @@ -273,37 +280,42 @@ void ImageAtlas::ObserverDestroyed(AtlasUploadObserver* observer) 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 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 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()); } } diff --git a/dali-toolkit/internal/image-loader/image-load-thread.cpp b/dali-toolkit/internal/image-loader/loading-task.cpp similarity index 60% rename from dali-toolkit/internal/image-loader/image-load-thread.cpp rename to dali-toolkit/internal/image-loader/loading-task.cpp index deb0178..29f3bdb 100644 --- a/dali-toolkit/internal/image-loader/image-load-thread.cpp +++ b/dali-toolkit/internal/image-loader/loading-task.cpp @@ -16,7 +16,7 @@ */ // CLASS HEADER -#include "image-load-thread.h" +#include "loading-task.h" // EXTERNAL INCLUDES #include @@ -31,10 +31,12 @@ namespace Toolkit { 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(), @@ -46,14 +48,17 @@ LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLo 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), @@ -65,14 +70,17 @@ LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dime 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), @@ -84,14 +92,17 @@ LoadingTask::LoadingTask(uint32_t id, const EncodedImageBuffer& encodedImageBuff 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(), @@ -103,11 +114,36 @@ LoadingTask::LoadingTask(uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::Pix 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; @@ -165,144 +201,9 @@ void LoadingTask::MultiplyAlpha() } } -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::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::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::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::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 diff --git a/dali-toolkit/internal/image-loader/image-load-thread.h b/dali-toolkit/internal/image-loader/loading-task.h similarity index 78% rename from dali-toolkit/internal/image-loader/image-load-thread.h rename to dali-toolkit/internal/image-loader/loading-task.h index 520d2b2..09208b4 100644 --- a/dali-toolkit/internal/image-loader/image-load-thread.h +++ b/dali-toolkit/internal/image-loader/loading-task.h @@ -1,5 +1,5 @@ -#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. @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include namespace Dali { @@ -37,22 +39,29 @@ namespace Toolkit { namespace Internal { + +class LoadingTask; +using LoadingTaskPtr = IntrusivePtr; + /** - * 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. @@ -64,6 +73,7 @@ struct LoadingTask * @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, @@ -72,7 +82,8 @@ struct LoadingTask SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, - bool loadPlanes); + bool loadPlanes, + CallbackBase* callback); /** * Constructor. @@ -83,6 +94,7 @@ struct LoadingTask * @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, @@ -90,7 +102,8 @@ struct LoadingTask FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, - DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad); + DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, + CallbackBase* callback); /** * Constructor. @@ -100,28 +113,37 @@ struct LoadingTask * @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 @@ -130,12 +152,28 @@ private: // Undefined LoadingTask& operator=(const LoadingTask& queue); + /** + * Load the image + */ + void Load(); + + /** + * Apply mask + */ + void ApplyMask(); + + /** + * Multiply alpha + */ + void MultiplyAlpha(); + public: std::vector 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 @@ -150,89 +188,7 @@ public: 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 mLoadQueue; /// mCompleteQueue; ///SetTextureId(textureId); + Dali::AsyncTaskManager::Get().AddTask(loadingTask); } void TextureAsyncLoadingHelper::Load(const TextureManager::TextureId& textureId, @@ -59,17 +60,18 @@ void TextureAsyncLoadingHelper::Load(const TextureManager::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, @@ -79,44 +81,18 @@ void TextureAsyncLoadingHelper::ApplyMask(const TextureManager::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& 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); } } diff --git a/dali-toolkit/internal/texture-manager/texture-async-loading-helper.h b/dali-toolkit/internal/texture-manager/texture-async-loading-helper.h index d8830f7..d993737 100644 --- a/dali-toolkit/internal/texture-manager/texture-async-loading-helper.h +++ b/dali-toolkit/internal/texture-manager/texture-async-loading-helper.h @@ -22,7 +22,7 @@ #include // INTERNAL INCLUDES -#include +#include #include namespace Dali @@ -31,27 +31,12 @@ namespace Toolkit { 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. @@ -113,31 +98,16 @@ public: TextureAsyncLoadingHelper(const TextureAsyncLoadingHelper&) = delete; TextureAsyncLoadingHelper& operator=(const TextureAsyncLoadingHelper&) = delete; - TextureAsyncLoadingHelper(TextureAsyncLoadingHelper&& rhs); - TextureAsyncLoadingHelper& operator=(TextureAsyncLoadingHelper&& rhs) = delete; - -private: // Private typedefs: - typedef std::deque 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& pixelBuffers); + void AsyncLoadComplete(LoadingTaskPtr task); private: // Member Variables: - Toolkit::AsyncImageLoader mLoader; - TextureManager& mTextureManager; - AsyncLoadingInfoContainerType mLoadingInfoContainer; + TextureManager& mTextureManager; + uint32_t mLoadTaskId; }; } // namespace Internal diff --git a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp index 643fced..8930d2d 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp @@ -34,8 +34,6 @@ 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 @@ -44,26 +42,6 @@ constexpr auto NUMBER_OF_LOCAL_LOADER_THREADS_ENV = "DALI_TEXTURE_LOCAL_THREADS 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); @@ -132,8 +110,7 @@ TextureManager::MaskingData::MaskingData() TextureManager::TextureManager() : mTextureCacheManager(), - mAsyncLocalLoaders(GetNumberOfLocalLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }), - mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }), + mAsyncLoader(std::unique_ptr(new TextureAsyncLoadingHelper(*this))), mLifecycleObservers(), mLoadQueue(), mRemoveQueue(), @@ -551,7 +528,6 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( // 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); } @@ -563,7 +539,6 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( // 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); } @@ -587,7 +562,6 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( 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; } @@ -898,21 +872,17 @@ void TextureManager::QueueLoadTexture(const TextureManager::TextureInfo& texture 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); @@ -986,7 +956,6 @@ void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureI 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) @@ -1226,11 +1195,8 @@ void TextureManager::ApplyMask(TextureManager::TextureInfo& textureInfo, const T 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); } } @@ -1305,7 +1271,6 @@ void TextureManager::NotifyObservers(TextureManager::TextureInfo& textureInfo, c // 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); diff --git a/dali-toolkit/internal/texture-manager/texture-manager-impl.h b/dali-toolkit/internal/texture-manager/texture-manager-impl.h index 6b3f1a7..791553c 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.h +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.h @@ -23,10 +23,10 @@ #include #include #include +#include // INTERNAL INCLUDES #include -#include #include #include #include @@ -650,10 +650,7 @@ private: private: // Member Variables: TextureCacheManager mTextureCacheManager; ///< Manager the life-cycle and caching of Textures - - RoundRobinContainerView mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads - RoundRobinContainerView mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads - + std::unique_ptr mAsyncLoader; ///< The Asynchronous image loader used to provide all local async loads Dali::Vector mLifecycleObservers; ///< Lifecycle observers of texture manager Dali::Vector mLoadQueue; ///< Queue of textures to load after NotifyObservers Dali::Vector mRemoveQueue; ///< Queue of textures to remove after NotifyObservers diff --git a/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h b/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h index b752105..0d2dfb0 100644 --- a/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h +++ b/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h @@ -22,10 +22,10 @@ #include #include #include +#include #include // INTERNAL INCLUDES -#include #include #include diff --git a/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp b/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp deleted file mode 100644 index c1ebd67..0000000 --- a/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -// INTERNAL INCLUDES -#include - -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 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::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it) - { - if((*it) && (*it)->GetSvgVisual() == task->GetSvgVisual()) - { - SvgRasterizingTask* oldTask = dynamic_cast(it->Get()); - SvgRasterizingTask* newTask = dynamic_cast(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::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::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(new SvgRasterizeThread(svgRasterizeManager)), svgRasterizeManager) -{ -} - -SvgRasterizeManager::RasterizeHelper::RasterizeHelper(RasterizeHelper&& rhs) -: RasterizeHelper(std::move(rhs.mRasterizer), rhs.mSvgRasterizeManager) -{ -} - -SvgRasterizeManager::RasterizeHelper::RasterizeHelper(std::unique_ptr rasterizer, SvgRasterizeManager& svgRasterizeManager) -: mRasterizer(std::move(rasterizer)), - mSvgRasterizeManager(svgRasterizeManager) -{ -} - -bool SvgRasterizeManager::RasterizeHelper::RequestRasterize() -{ - return mRasterizer->RequestRasterize(); -} -} // namespace Internal - -} // namespace Toolkit - -} // namespace Dali diff --git a/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h b/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h deleted file mode 100644 index c9c305b..0000000 --- a/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h +++ /dev/null @@ -1,378 +0,0 @@ -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// INTERNAL INCLUDES -#include -#include - -namespace Dali -{ -namespace Toolkit -{ -namespace Internal -{ -class SvgVisual; -typedef IntrusivePtr SvgVisualPtr; -class SvgTask; -typedef IntrusivePtr 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 rasterizer, SvgRasterizeManager& svgRasterizeManager); - - private: - std::unique_ptr mRasterizer; - SvgRasterizeManager& mSvgRasterizeManager; - }; - -private: - // Undefined - SvgRasterizeManager(const SvgRasterizeManager& thread); - - // Undefined - SvgRasterizeManager& operator=(const SvgRasterizeManager& thread); - -private: - std::vector mRasterizeTasks; //The queue of the tasks waiting to rasterize the SVG image - std::vector mCompletedTasks; //The queue of the tasks with the SVG rasterization completed - - RoundRobinContainerView mRasterizers; - - Dali::Mutex mMutex; - std::unique_ptr mTrigger; - bool mProcessorRegistered; -}; - -} // namespace Internal - -} // namespace Toolkit - -} // namespace Dali - -#endif // DALI_TOOLKIT_SVG_RASTERIZE_THREAD_H diff --git a/dali-toolkit/internal/visuals/svg/svg-task.cpp b/dali-toolkit/internal/visuals/svg/svg-task.cpp new file mode 100644 index 0000000..67cff0f --- /dev/null +++ b/dali-toolkit/internal/visuals/svg/svg-task.cpp @@ -0,0 +1,157 @@ +/* + * 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 +#include +#include + +// INTERNAL INCLUDES +#include + +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 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 diff --git a/dali-toolkit/internal/visuals/svg/svg-task.h b/dali-toolkit/internal/visuals/svg/svg-task.h new file mode 100644 index 0000000..31855b9 --- /dev/null +++ b/dali-toolkit/internal/visuals/svg/svg-task.h @@ -0,0 +1,200 @@ +#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 +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ +class SvgVisual; +typedef IntrusivePtr SvgVisualPtr; +class SvgTask; +typedef IntrusivePtr 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 diff --git a/dali-toolkit/internal/visuals/svg/svg-visual.cpp b/dali-toolkit/internal/visuals/svg/svg-visual.cpp index cd59107..733141a 100644 --- a/dali-toolkit/internal/visuals/svg/svg-visual.cpp +++ b/dali-toolkit/internal/visuals/svg/svg-visual.cpp @@ -21,7 +21,7 @@ // INTERNAL INCLUDES #include #include -#include +#include #include #include #include @@ -93,15 +93,15 @@ void SvgVisual::OnInitialize() 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); } } @@ -218,7 +218,11 @@ void SvgVisual::DoSetOnScene(Actor& actor) 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(); @@ -291,27 +295,28 @@ void SvgVisual::AddRasterizationTask(const Vector2& size) unsigned int width = static_cast(size.width); unsigned int height = static_cast(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 @@ -382,7 +387,7 @@ void SvgVisual::ApplyRasterizedImage(PixelData rasterizedPixelData, bool success ResourceReady(Toolkit::Visual::ResourceStatus::READY); } } - else if(!success && !mLoadFailed) + else if(!mLoadFailed) { mLoadFailed = true; diff --git a/dali-toolkit/internal/visuals/svg/svg-visual.h b/dali-toolkit/internal/visuals/svg/svg-visual.h index 93decde..faf8a22 100644 --- a/dali-toolkit/internal/visuals/svg/svg-visual.h +++ b/dali-toolkit/internal/visuals/svg/svg-visual.h @@ -25,6 +25,7 @@ // INTERNAL INCLUDES #include #include +#include namespace Dali { @@ -153,10 +154,9 @@ public: /** * @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: /** @@ -189,6 +189,8 @@ private: WeakHandle mPlacementActor; Vector2 mRasterizedSize; Dali::ImageDimensions mDesiredSize{}; + SvgTaskPtr mLoadingTask; + SvgTaskPtr mRasterizingTask; bool mLoadFailed; bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture }; diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.cpp b/dali-toolkit/internal/visuals/visual-factory-cache.cpp index 6b4bf10..6bf66cb 100644 --- a/dali-toolkit/internal/visuals/visual-factory-cache.cpp +++ b/dali-toolkit/internal/visuals/visual-factory-cache.cpp @@ -43,8 +43,7 @@ const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f); } VisualFactoryCache::VisualFactoryCache(bool preMultiplyOnLoad) -: mSvgRasterizeManager(nullptr), - mVectorAnimationManager(nullptr), +: mVectorAnimationManager(nullptr), mPreMultiplyOnLoad(preMultiplyOnLoad), mBrokenImageInfoContainer(), mDefaultBrokenImageUrl(""), @@ -130,15 +129,6 @@ NPatchLoader& VisualFactoryCache::GetNPatchLoader() return mNPatchLoader; } -SvgRasterizeManager* VisualFactoryCache::GetSVGRasterizationManager() -{ - if(!mSvgRasterizeManager) - { - mSvgRasterizeManager = std::unique_ptr(new SvgRasterizeManager()); - } - return mSvgRasterizeManager.get(); -} - VectorAnimationManager& VisualFactoryCache::GetVectorAnimationManager() { if(!mVectorAnimationManager) diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.h b/dali-toolkit/internal/visuals/visual-factory-cache.h index 0edda01..43fee4c 100644 --- a/dali-toolkit/internal/visuals/visual-factory-cache.h +++ b/dali-toolkit/internal/visuals/visual-factory-cache.h @@ -27,7 +27,6 @@ // INTERNAL INCLUDES #include #include -#include #include namespace Dali @@ -245,12 +244,6 @@ public: 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. */ @@ -348,7 +341,6 @@ private: TextureManager mTextureManager; NPatchLoader mNPatchLoader; - std::unique_ptr mSvgRasterizeManager; std::unique_ptr mVectorAnimationManager; bool mPreMultiplyOnLoad; std::vector mBrokenImageInfoContainer; -- 2.7.4