From 69ca1d127beedc5bc18d30f59b50afa14aa07f0d Mon Sep 17 00:00:00 2001 From: "Seungho, Baek" Date: Mon, 30 Dec 2019 21:36:37 +0900 Subject: [PATCH] Asynchronous Load N-patch resource Change-Id: I1e0a25ca7599198ca5793a585af80e2b7d2e8f48 Signed-off-by: Seungho, Baek --- .../utc-Dali-TextureManager.cpp | 8 +- .../src/dali-toolkit/utc-Dali-Visual.cpp | 10 +- .../src/dali-toolkit/utc-Dali-VisualFactory.cpp | 199 +++++++++++++++++++-- .../visuals/animated-image/fixed-image-cache.cpp | 15 +- .../visuals/animated-image/fixed-image-cache.h | 10 +- .../visuals/animated-image/rolling-image-cache.cpp | 13 +- .../visuals/animated-image/rolling-image-cache.h | 8 +- dali-toolkit/internal/visuals/image/image-visual.h | 10 +- dali-toolkit/internal/visuals/npatch-loader.cpp | 154 +++++++++------- dali-toolkit/internal/visuals/npatch-loader.h | 24 ++- .../internal/visuals/npatch/npatch-visual.cpp | 135 +++++++++++--- .../internal/visuals/npatch/npatch-visual.h | 30 +++- .../internal/visuals/texture-manager-impl.cpp | 69 ++++++- .../internal/visuals/texture-manager-impl.h | 42 ++++- .../internal/visuals/texture-upload-observer.h | 20 ++- 15 files changed, 619 insertions(+), 128 deletions(-) diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp index 823c7bb..21f6f7c 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -53,6 +53,12 @@ public: mObserverCalled = true; } + virtual void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) override + { + mLoaded = loadSuccess; + mObserverCalled = true; + } + bool mLoaded; bool mObserverCalled; }; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp index d1df2ac..b605cc6 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -2977,8 +2977,11 @@ int UtcDaliVisualSetTransform7(void) tet_infoline( "UtcDaliVisualSetTransform: NPatch visual" ); VisualFactory factory = VisualFactory::Get(); - Image image = ResourceImage::New(TEST_NPATCH_FILE_NAME, ImageDimensions(100, 200)); - Visual::Base visual = factory.CreateVisual(image); + Property::Map propertyMap; + propertyMap[Toolkit::Visual::Property::TYPE] = Toolkit::Visual::IMAGE; + propertyMap[Toolkit::ImageVisual::Property::URL] = TEST_NPATCH_FILE_NAME; + propertyMap[Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING] = true; + Visual::Base visual = factory.CreateVisual(propertyMap); TestTransform( application, visual ); TestMixColor( visual, Visual::Property::MIX_COLOR, Color::WHITE ); @@ -3048,6 +3051,7 @@ int UtcDaliNPatchVisualCustomShader(void) properties[Visual::Property::MIX_COLOR] = Color::BLUE; properties[Visual::Property::SHADER]=shader; properties[ImageVisual::Property::URL] = TEST_NPATCH_FILE_NAME; + properties[ImageVisual::Property::SYNCHRONOUS_LOADING] = true; Visual::Base visual = factory.CreateVisual( properties ); TestMixColor( visual, Visual::Property::MIX_COLOR, Color::BLUE ); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp index 69df067..df2d7be 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -26,6 +26,8 @@ #include #include "dummy-control.h" +#include + using namespace Dali; using namespace Dali::Toolkit; @@ -84,6 +86,29 @@ void TestVisualRender( ToolkitTestApplication& application, DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION ); } +void TestVisualAsynchronousRender( ToolkitTestApplication& application, + DummyControl& actor, + Visual::Base& visual ) +{ + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual ); + + actor.SetSize( 200.f, 200.f ); + DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION ); + + Stage::GetCurrent().Add( actor ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION ); +} + } // namespace @@ -439,10 +464,10 @@ int UtcDaliVisualFactoryDefaultOffsetsGradientVisual(void) END_TEST; } -int UtcDaliVisualFactoryGetNPatchVisual1(void) +int UtcDaliVisualFactoryGetNPatchVisualSynchronousLoad1(void) { ToolkitTestApplication application; - tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual1: Request 9-patch visual with a Property::Map" ); + tet_infoline( "UtcDaliVisualFactoryGetNPatchVisualSynchronousLoad1: Request 9-patch visual with a Property::Map" ); VisualFactory factory = VisualFactory::Get(); DALI_TEST_CHECK( factory ); @@ -453,6 +478,7 @@ int UtcDaliVisualFactoryGetNPatchVisual1(void) Property::Map propertyMap; propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH ); propertyMap.Insert( ImageVisual::Property::URL, TEST_9_PATCH_FILE_NAME ); + propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true ); { tet_infoline( "whole grid" ); Visual::Base visual = factory.CreateVisual( propertyMap ); @@ -495,10 +521,10 @@ int UtcDaliVisualFactoryGetNPatchVisual1(void) END_TEST; } -int UtcDaliVisualFactoryGetNPatchVisual2(void) +int UtcDaliVisualFactoryGetNPatchVisualSynchronousLoad2(void) { ToolkitTestApplication application; - tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual1: Request 9-patch visual with a Property::Map including border" ); + tet_infoline( "UtcDaliVisualFactoryGetNPatchVisualSynchronousLoad2: Request 9-patch visual with a Property::Map including border" ); VisualFactory factory = VisualFactory::Get(); DALI_TEST_CHECK( factory ); @@ -510,6 +536,7 @@ int UtcDaliVisualFactoryGetNPatchVisual2(void) propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH ); propertyMap.Insert( ImageVisual::Property::URL, gImage_34_RGBA ); propertyMap.Insert( ImageVisual::Property::BORDER, Rect< int >( 2, 2, 2, 2 ) ); + propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true ); { tet_infoline( "whole grid" ); Visual::Base visual = factory.CreateVisual( propertyMap ); @@ -553,6 +580,147 @@ int UtcDaliVisualFactoryGetNPatchVisual2(void) propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH ); propertyMap.Insert( ImageVisual::Property::URL, gImage_34_RGBA ); propertyMap.Insert( ImageVisual::Property::BORDER, Rect< int >( 1, 1, 1, 1 ) ); + propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true ); + { + tet_infoline( "whole grid" ); + Visual::Base visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + DummyControl actor = DummyControl::New(true); + TestVisualRender( application, actor, visual ); + + DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); + + Vector2 naturalSize( 0.0f, 0.0f ); + visual.GetNaturalSize( naturalSize ); + DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION ); + } + + END_TEST; +} + +int UtcDaliVisualFactoryGetNPatchVisual1(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual1: Request 9-patch visual with a Property::Map" ); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK( factory ); + + // Get actual size of test image + ImageDimensions imageSize = Dali::GetClosestImageSize( TEST_9_PATCH_FILE_NAME ); + + Property::Map propertyMap; + propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH ); + propertyMap.Insert( ImageVisual::Property::URL, TEST_9_PATCH_FILE_NAME ); + propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, false ); + { + tet_infoline( "whole grid" ); + Visual::Base visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + Vector2 naturalSize( 0.0f, 0.0f ); + visual.GetNaturalSize( naturalSize ); + DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + DummyControl actor = DummyControl::New(true); + TestVisualAsynchronousRender( application, actor, visual ); + + DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); + + visual.GetNaturalSize( naturalSize ); + DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION ); + } + + propertyMap.Insert( ImageVisual::Property::BORDER_ONLY, true ); + { + tet_infoline( "border only" ); + Visual::Base visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + DummyControl actor = DummyControl::New(true); + TestVisualRender( application, actor, visual ); + + DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); + + Vector2 naturalSize( 0.0f, 0.0f ); + visual.GetNaturalSize( naturalSize ); + DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION ); + } + + END_TEST; +} + +int UtcDaliVisualFactoryGetNPatchVisual2(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual2: Request 9-patch visual with a Property::Map including border" ); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK( factory ); + + // Get actual size of test image + ImageDimensions imageSize = Dali::GetClosestImageSize( gImage_34_RGBA ); + + Property::Map propertyMap; + propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH ); + propertyMap.Insert( ImageVisual::Property::URL, gImage_34_RGBA ); + propertyMap.Insert( ImageVisual::Property::BORDER, Rect< int >( 2, 2, 2, 2 ) ); + { + tet_infoline( "whole grid" ); + Visual::Base visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + DummyControl actor = DummyControl::New(true); + TestVisualAsynchronousRender( application, actor, visual ); + + DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); + + Vector2 naturalSize( 0.0f, 0.0f ); + visual.GetNaturalSize( naturalSize ); + DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION ); + } + + propertyMap.Insert( ImageVisual::Property::BORDER_ONLY, true ); + { + tet_infoline( "border only" ); + Visual::Base visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + DummyControl actor = DummyControl::New(true); + TestVisualRender( application, actor, visual ); + + DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); + + Vector2 naturalSize( 0.0f, 0.0f ); + visual.GetNaturalSize( naturalSize ); + DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION ); + } + + propertyMap.Clear(); + propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH ); + propertyMap.Insert( ImageVisual::Property::URL, gImage_34_RGBA ); + propertyMap.Insert( ImageVisual::Property::BORDER, Rect< int >( 1, 1, 1, 1 ) ); { tet_infoline( "whole grid" ); Visual::Base visual = factory.CreateVisual( propertyMap ); @@ -598,7 +766,7 @@ int UtcDaliVisualFactoryGetNPatchVisual3(void) textureTrace.Enable(true); DummyControl actor = DummyControl::New(true); - TestVisualRender( application, actor, visual ); + TestVisualAsynchronousRender( application, actor, visual ); DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); @@ -652,9 +820,8 @@ int UtcDaliVisualFactoryGetNPatchVisual4(void) TestGlAbstraction& gl = application.GetGlAbstraction(); TraceCallStack& textureTrace = gl.GetTextureTrace(); textureTrace.Enable(true); - DummyControl actor = DummyControl::New(true); - TestVisualRender( application, actor, visual ); + TestVisualAsynchronousRender( application, actor, visual ); DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); @@ -698,7 +865,7 @@ int UtcDaliVisualFactoryGetNPatchVisual5(void) textureTrace.Enable(true); DummyControl actor = DummyControl::New(true); - TestVisualRender( application, actor, visual ); + TestVisualAsynchronousRender( application, actor, visual ); DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); @@ -733,7 +900,7 @@ int UtcDaliVisualFactoryGetNPatchVisual6(void) textureTrace.Enable(true); DummyControl actor = DummyControl::New(true); - TestVisualRender( application, actor, visual ); + TestVisualAsynchronousRender( application, actor, visual ); DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); @@ -761,7 +928,7 @@ int UtcDaliVisualFactoryGetNPatchVisual6(void) textureTrace.Enable(true); DummyControl actor = DummyControl::New(true); - TestVisualRender( application, actor, visual ); + TestVisualAsynchronousRender( application, actor, visual ); DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); @@ -810,6 +977,12 @@ int UtcDaliNPatchVisualAuxiliaryImage(void) dummy.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS ); dummy.SetParentOrigin(ParentOrigin::CENTER); Stage::GetCurrent().Add(dummy); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION ); + application.SendNotification(); application.Render(); @@ -839,7 +1012,7 @@ int UtcDaliVisualFactoryGetNPatchVisualN1(void) textureTrace.Enable(true); DummyControl actor = DummyControl::New(true); - TestVisualRender( application, actor, visual ); + TestVisualAsynchronousRender( application, actor, visual ); DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); @@ -870,7 +1043,7 @@ int UtcDaliVisualFactoryGetNPatchVisualN2(void) drawTrace.Enable(true); DummyControl actor = DummyControl::New(true); - TestVisualRender( application, actor, visual ); + TestVisualAsynchronousRender( application, actor, visual ); DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); diff --git a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp index e64a51b..9acf1af 100644 --- a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -190,6 +190,17 @@ void FixedImageCache::UploadComplete( } } +void FixedImageCache::LoadComplete( + bool loadSuccess, + Devel::PixelBuffer pixelBuffer, + const VisualUrl& url, + bool preMultiplied ) +{ + // LoadComplete is called if this TextureUploadObserver requested to load + // an image that will be returned as a type of PixelBuffer by using a method + // TextureManager::LoadPixelBuffer. +} + } //namespace Internal } //namespace Toolkit -} //namespace Dali +} //namespace Dali \ No newline at end of file diff --git a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h index ceb9fff..72484a4 100644 --- a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_INTERNAL_FIXED_IMAGE_CACHE_H /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -96,7 +96,13 @@ protected: TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, - bool premultiplied) override; + bool premultiplied ) override; + + void LoadComplete( + bool loadSuccess, + Devel::PixelBuffer pixelBuffer, + const VisualUrl& url, + bool preMultiplied ) override; private: std::vector& mImageUrls; diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp index c39be7e..b7b45ff 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -231,6 +231,17 @@ void RollingImageCache::UploadComplete( LOG_CACHE; } +void RollingImageCache::LoadComplete( + bool loadSuccess, + Devel::PixelBuffer pixelBuffer, + const VisualUrl& url, + bool preMultiplied ) +{ + // LoadComplete is called if this TextureUploadObserver requested to load + // an image that will be returned as a type of PixelBuffer by using a method + // TextureManager::LoadPixelBuffer. +} + } //namespace Internal } //namespace Toolkit } //namespace Dali diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h index c5650cf..a0d734d 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_INTERNAL_ROLLING_IMAGE_CACHE_H /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -114,6 +114,12 @@ protected: const Vector4& atlasRect, bool preMultiplied ) override; + void LoadComplete( + bool loadSuccess, + Devel::PixelBuffer pixelBuffer, + const VisualUrl& url, + bool preMultiplied ) override; + private: /** * Secondary class to hold readiness and index into url diff --git a/dali-toolkit/internal/visuals/image/image-visual.h b/dali-toolkit/internal/visuals/image/image-visual.h index dcd76f6..ea46680 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.h +++ b/dali-toolkit/internal/visuals/image/image-visual.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_INTERNAL_IMAGE_VISUAL_H /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -271,6 +271,14 @@ public: private: /** + * @copydoc TextureUploadObserver::LoadComplete + * + * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready. + * This callback is the place to add the renderer as it would be called once the PixelBuffer loading is finished. + */ + void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) override {} + + /** * Allocate the mask data when a masking property is defined in the property map */ void AllocateMaskData(); diff --git a/dali-toolkit/internal/visuals/npatch-loader.cpp b/dali-toolkit/internal/visuals/npatch-loader.cpp index e89ebcb..6745adf 100644 --- a/dali-toolkit/internal/visuals/npatch-loader.cpp +++ b/dali-toolkit/internal/visuals/npatch-loader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -20,7 +20,6 @@ // EXTERNAL HEADER #include -#include #include #include @@ -248,6 +247,35 @@ void ParseBorders( Devel::PixelBuffer& pixelBuffer, NPatchLoader::Data* data ) } } +void SetLoadedNPatchData( NPatchLoader::Data* data, Devel::PixelBuffer& pixelBuffer ) +{ + if( data->border == Rect< int >( 0, 0, 0, 0 ) ) + { + NPatchBuffer::ParseBorders( pixelBuffer, data ); + + // Crop the image + pixelBuffer.Crop( 1, 1, pixelBuffer.GetWidth() - 2, pixelBuffer.GetHeight() - 2 ); + } + else + { + data->stretchPixelsX.PushBack( Uint16Pair( data->border.left, ( (pixelBuffer.GetWidth() >= static_cast< unsigned int >( data->border.right )) ? pixelBuffer.GetWidth() - data->border.right : 0 ) ) ); + data->stretchPixelsY.PushBack( Uint16Pair( data->border.top, ( (pixelBuffer.GetHeight() >= static_cast< unsigned int >( data->border.bottom )) ? pixelBuffer.GetHeight() - data->border.bottom : 0 ) ) ); + } + + data->croppedWidth = pixelBuffer.GetWidth(); + data->croppedHeight = pixelBuffer.GetHeight(); + + PixelData pixels = Devel::PixelBuffer::Convert( pixelBuffer ); // takes ownership of buffer + + Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() ); + texture.Upload( pixels ); + + data->textureSet = TextureSet::New(); + data->textureSet.SetTexture( 0u, texture ); + + data->loadCompleted = true; +} + } // namespace NPatchBuffer NPatchLoader::NPatchLoader() @@ -258,12 +286,13 @@ NPatchLoader::~NPatchLoader() { } -std::size_t NPatchLoader::Load( const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad ) +std::size_t NPatchLoader::Load( TextureManager& textureManager, TextureUploadObserver* textureObserver, const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad, bool synchronousLoading ) { std::size_t hash = CalculateHash( url ); OwnerContainer< Data* >::SizeType index = UNINITIALIZED_ID; const OwnerContainer< Data* >::SizeType count = mCache.Count(); int cachedIndex = -1; + Data* data; for( ; index < count; ++index ) { @@ -275,92 +304,85 @@ std::size_t NPatchLoader::Load( const std::string& url, const Rect< int >& borde // Use cached data if( mCache[ index ]->border == border ) { - return index+1u; // valid indices are from 1 onwards + if( mCache[ index ]->loadCompleted ) + { + return index + 1u; // valid indices are from 1 onwards + } + data = mCache[ index ]; + cachedIndex = index + 1u; // valid indices are from 1 onwards + break; } else { - cachedIndex = index; - } - } - } - } + if( mCache[ index ]->loadCompleted ) + { + // Same url but border is different - use the existing texture + Data* data = new Data(); + data->hash = hash; + data->url = url; + data->croppedWidth = mCache[ index ]->croppedWidth; + data->croppedHeight = mCache[ index ]->croppedHeight; - if( cachedIndex != -1 ) - { - // Same url but border is different - use the existing texture - Data* data = new Data(); - data->hash = hash; - data->url = url; - data->croppedWidth = mCache[ cachedIndex ]->croppedWidth; - data->croppedHeight = mCache[ cachedIndex ]->croppedHeight; + data->textureSet = mCache[ index ]->textureSet; - data->textureSet = mCache[ cachedIndex ]->textureSet; + StretchRanges stretchRangesX; + stretchRangesX.PushBack( Uint16Pair( border.left, ( (data->croppedWidth >= static_cast< unsigned int >( border.right )) ? data->croppedWidth - border.right : 0 ) ) ); - StretchRanges stretchRangesX; - stretchRangesX.PushBack( Uint16Pair( border.left, ( (data->croppedWidth >= static_cast< unsigned int >( border.right )) ? data->croppedWidth - border.right : 0 ) ) ); + StretchRanges stretchRangesY; + stretchRangesY.PushBack( Uint16Pair( border.top, ( (data->croppedHeight >= static_cast< unsigned int >( border.bottom )) ? data->croppedHeight - border.bottom : 0 ) ) ); - StretchRanges stretchRangesY; - stretchRangesY.PushBack( Uint16Pair( border.top, ( (data->croppedHeight >= static_cast< unsigned int >( border.bottom )) ? data->croppedHeight - border.bottom : 0 ) ) ); + data->stretchPixelsX = stretchRangesX; + data->stretchPixelsY = stretchRangesY; + data->border = border; - data->stretchPixelsX = stretchRangesX; - data->stretchPixelsY = stretchRangesY; - data->border = border; + data->loadCompleted = mCache[ index ]->loadCompleted; - mCache.PushBack( data ); + mCache.PushBack( data ); - return mCache.Count(); // valid ids start from 1u + return mCache.Count(); // valid ids start from 1u + } + } + } + } } - // got to the end so no match, decode N patch and append new item to cache - Devel::PixelBuffer pixelBuffer = Dali::LoadImageFromFile( url, ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true ); - if( pixelBuffer ) + if( cachedIndex == -1 ) { - Data* data = new Data(); + data = new Data(); + data->loadCompleted = false; data->hash = hash; data->url = url; + data->border = border; - if( border == Rect< int >( 0, 0, 0, 0 ) ) - { - NPatchBuffer::ParseBorders( pixelBuffer, data ); - - data->border = Rect< int >( 0, 0, 0, 0 ); - - // Crop the image - pixelBuffer.Crop( 1, 1, pixelBuffer.GetWidth() - 2, pixelBuffer.GetHeight() - 2 ); - } - else - { - data->stretchPixelsX.PushBack( Uint16Pair( border.left, ( (pixelBuffer.GetWidth() >= static_cast< unsigned int >( border.right )) ? pixelBuffer.GetWidth() - border.right : 0 ) ) ); - data->stretchPixelsY.PushBack( Uint16Pair( border.top, ( (pixelBuffer.GetHeight() >= static_cast< unsigned int >( border.bottom )) ? pixelBuffer.GetHeight() - border.bottom : 0 ) ) ); - data->border = border; - } - - data->croppedWidth = pixelBuffer.GetWidth(); - data->croppedHeight = pixelBuffer.GetHeight(); + mCache.PushBack( data ); - if( preMultiplyOnLoad && Pixel::HasAlpha( pixelBuffer.GetPixelFormat() ) ) - { - pixelBuffer.MultiplyColorByAlpha(); - } - else - { - preMultiplyOnLoad = false; - } + cachedIndex = mCache.Count(); + } - PixelData pixels = Devel::PixelBuffer::Convert( pixelBuffer ); // takes ownership of buffer + auto preMultiplyOnLoading = preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD + : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer( url, Dali::ImageDimensions(), FittingMode::DEFAULT, + SamplingMode::BOX_THEN_LINEAR, synchronousLoading, + textureObserver, true, preMultiplyOnLoading ); - Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() ); - texture.Upload( pixels ); + if( pixelBuffer ) + { + NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer ); + preMultiplyOnLoad = ( preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ) ? true : false; + } - data->textureSet = TextureSet::New(); - data->textureSet.SetTexture( 0u, texture ); + return cachedIndex; +} - mCache.PushBack( data ); +void NPatchLoader::SetNPatchData( std::size_t id, Devel::PixelBuffer& pixelBuffer ) +{ + Data* data; + data = mCache[ id - 1u ]; - return mCache.Count(); // valid ids start from 1u + if( !data->loadCompleted ) + { + NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer ); } - - return 0u; } bool NPatchLoader::GetNPatchData( std::size_t id, const Data*& data ) diff --git a/dali-toolkit/internal/visuals/npatch-loader.h b/dali-toolkit/internal/visuals/npatch-loader.h index 8c75477..0d39d0d 100644 --- a/dali-toolkit/internal/visuals/npatch-loader.h +++ b/dali-toolkit/internal/visuals/npatch-loader.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_NPATCH_LOADER_H /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -22,6 +22,10 @@ #include #include #include +#include + +// INTERNAL HEADERS +#include namespace Dali { @@ -61,6 +65,10 @@ public: struct Data { + Data() + : loadCompleted( false ) + {} + std::string url; ///< Url of the N-Patch TextureSet textureSet; ///< Texture containing the cropped image StretchRanges stretchPixelsX; ///< X stretch pixels @@ -69,6 +77,7 @@ public: uint32_t croppedWidth; ///< Width of the cropped middle part of N-patch uint32_t croppedHeight; ///< Height of the cropped middle part of N-patch Rect< int > border; ///< The size of the border + bool loadCompleted; ///< True if the data loading is completed }; public: @@ -86,13 +95,24 @@ public: /** * @brief Retrieve a texture matching the n-patch url. * + * @param [in] textureManager that will be used to loading image + * @param [in] textureObserver The NPatchVisual that requested loading. * @param [in] url to retrieve * @param [in] border The border size of the image * @param [in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the * image has no alpha channel + * @param [in] synchronousLoading True if the image will be loaded in synchronous time. * @return id of the texture. */ - std::size_t Load( const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad ); + std::size_t Load( TextureManager& textureManager, TextureUploadObserver* textureObserver, const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad, bool synchronousLoading ); + + /** + * @brief Set loaded PixelBuffer and its information + * + * @param [in] id cache data id + * @param [in] pixelBuffer of loaded image + */ + void SetNPatchData( std::size_t id, Devel::PixelBuffer& pixelBuffer ); /** * @brief Retrieve N patch data matching to an id diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp index 85fc08c..af09393 100755 --- a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp +++ b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -52,6 +52,7 @@ const char * const BORDER_ONLY( "borderOnly" ); const char * const BORDER( "border" ); const char * const AUXILIARY_IMAGE_NAME( "auxiliaryImage" ); const char * const AUXILIARY_IMAGE_ALPHA_NAME( "auxiliaryImageAlpha" ); +const char * const SYNCHRONOUS_LOADING( "synchronousLoading" ); const char* VERTEX_SHADER = DALI_COMPOSE_SHADER( attribute mediump vec2 aPosition;\n @@ -288,20 +289,28 @@ NPatchVisualPtr NPatchVisual::New( VisualFactoryCache& factoryCache, NinePatchIm void NPatchVisual::LoadImages() { + TextureManager& textureManager = mFactoryCache.GetTextureManager(); + bool synchronousLoading = mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; + if( NPatchLoader::UNINITIALIZED_ID == mId && mImageUrl.IsLocalResource() ) { bool preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader ? true : false; + mId = mLoader.Load( textureManager, this, mImageUrl.GetUrl(), mBorder, preMultiplyOnLoad, synchronousLoading ); - mId = mLoader.Load( mImageUrl.GetUrl(), mBorder, preMultiplyOnLoad ); - - EnablePreMultipliedAlpha( preMultiplyOnLoad ); + const NPatchLoader::Data* data; + if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted ) + { + EnablePreMultipliedAlpha( preMultiplyOnLoad ); + } } - if( ! mAuxiliaryPixelBuffer && mAuxiliaryUrl.IsValid() && mAuxiliaryUrl.IsLocalResource() ) + if( !mAuxiliaryPixelBuffer && mAuxiliaryUrl.IsValid() && mAuxiliaryUrl.IsLocalResource() ) { - // Load the auxiliary image synchronously - mAuxiliaryPixelBuffer = Dali::LoadImageFromFile( mAuxiliaryUrl.GetUrl(), ImageDimensions(), - FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true ); + // Load the auxiliary image + auto preMultiplyOnLoading = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + mAuxiliaryPixelBuffer = textureManager.LoadPixelBuffer( mAuxiliaryUrl, Dali::ImageDimensions(), FittingMode::DEFAULT, + SamplingMode::BOX_THEN_LINEAR, synchronousLoading, + this, true, preMultiplyOnLoading ); } } @@ -311,14 +320,24 @@ void NPatchVisual::GetNaturalSize( Vector2& naturalSize ) naturalSize.y = 0u; // load now if not already loaded - LoadImages(); - const NPatchLoader::Data* data; - if( mLoader.GetNPatchData( mId, data ) ) + if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted ) { naturalSize.x = data->croppedWidth; naturalSize.y = data->croppedHeight; } + else + { + if( mImageUrl.IsValid() ) + { + ImageDimensions dimensions = Dali::GetOriginalImageSize( mImageUrl.GetUrl() ); + if( dimensions != ImageDimensions( 0, 0 ) ) + { + naturalSize.x = dimensions.GetWidth(); + naturalSize.y = dimensions.GetHeight(); + } + } + } if( mAuxiliaryPixelBuffer ) { @@ -366,6 +385,21 @@ void NPatchVisual::DoSetProperties( const Property::Map& propertyMap ) { auxImageAlpha->Get( mAuxiliaryImageAlpha ); } + + Property::Value* synchronousLoading = propertyMap.Find( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, SYNCHRONOUS_LOADING ); + if( synchronousLoading ) + { + bool sync = false; + synchronousLoading->Get( sync ); + if( sync ) + { + mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; + } + else + { + mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; + } + } } void NPatchVisual::DoSetOnStage( Actor& actor ) @@ -373,22 +407,32 @@ void NPatchVisual::DoSetOnStage( Actor& actor ) // load when first go on stage LoadImages(); - Geometry geometry = CreateGeometry(); - Shader shader = CreateShader(); - mImpl->mRenderer = Renderer::New( geometry, shader ); + const NPatchLoader::Data* data; + if( mLoader.GetNPatchData( mId, data ) ) + { + Geometry geometry = CreateGeometry(); + Shader shader = CreateShader(); - ApplyTextureAndUniforms(); + mImpl->mRenderer = Renderer::New( geometry, shader ); - actor.AddRenderer( mImpl->mRenderer ); + mPlacementActor = actor; + if( data->loadCompleted ) + { + ApplyTextureAndUniforms(); + actor.AddRenderer( mImpl->mRenderer ); + mPlacementActor.Reset(); - // npatch loaded and ready to display - ResourceReady( Toolkit::Visual::ResourceStatus::READY ); + // npatch loaded and ready to display + ResourceReady( Toolkit::Visual::ResourceStatus::READY ); + } + } } void NPatchVisual::DoSetOffStage( Actor& actor ) { actor.RemoveRenderer( mImpl->mRenderer ); mImpl->mRenderer.Reset(); + mPlacementActor.Reset(); } void NPatchVisual::OnSetTransform() @@ -425,6 +469,7 @@ void NPatchVisual::DoCreateInstancePropertyMap( Property::Map& map ) const NPatchVisual::NPatchVisual( VisualFactoryCache& factoryCache ) : Visual::Base( factoryCache, Visual::FittingMode::FILL ), + mPlacementActor(), mLoader( factoryCache.GetNPatchLoader() ), mImageUrl(), mAuxiliaryUrl(), @@ -444,7 +489,7 @@ Geometry NPatchVisual::CreateGeometry() { Geometry geometry; const NPatchLoader::Data* data; - if( mLoader.GetNPatchData( mId, data ) ) + if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted ) { if( data->stretchPixelsX.Size() == 1 && data->stretchPixelsY.Size() == 1 ) { @@ -556,7 +601,7 @@ void NPatchVisual::ApplyTextureAndUniforms() const NPatchLoader::Data* data; TextureSet textureSet; - if( mLoader.GetNPatchData( mId, data ) ) + if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted ) { textureSet = data->textureSet; @@ -773,6 +818,56 @@ Geometry NPatchVisual::CreateBorderGeometry( Uint16Pair gridSize ) return GenerateGeometry( vertices, indices ); } +void NPatchVisual::SetResource() +{ + const NPatchLoader::Data* data; + if( mLoader.GetNPatchData( mId, data ) ) + { + Geometry geometry = CreateGeometry(); + Shader shader = CreateShader(); + + mImpl->mRenderer.SetGeometry( geometry ); + mImpl->mRenderer.SetShader( shader ); + + Actor actor = mPlacementActor.GetHandle(); + if( actor ) + { + ApplyTextureAndUniforms(); + actor.AddRenderer( mImpl->mRenderer ); + mPlacementActor.Reset(); + + // npatch loaded and ready to display + ResourceReady( Toolkit::Visual::ResourceStatus::READY ); + } + } +} + +void NPatchVisual::LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) +{ + if( url.GetUrl() == mAuxiliaryUrl.GetUrl() ) + { + mAuxiliaryPixelBuffer = pixelBuffer; + const NPatchLoader::Data* data; + if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted ) + { + SetResource(); + } + } + else + { + if( loadSuccess ) + { + mLoader.SetNPatchData( mId, pixelBuffer ); + EnablePreMultipliedAlpha( preMultiplied ); + } + + if( mAuxiliaryPixelBuffer || !mAuxiliaryUrl.IsValid() ) + { + SetResource(); + } + } +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.h b/dali-toolkit/internal/visuals/npatch/npatch-visual.h index a761628..7816e84 100644 --- a/dali-toolkit/internal/visuals/npatch/npatch-visual.h +++ b/dali-toolkit/internal/visuals/npatch/npatch-visual.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_INTERNAL_N_PATCH_VISUAL_H /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -26,8 +26,10 @@ #include #include #include +#include // INTERNAL INCLUDES +#include #include #include @@ -56,7 +58,7 @@ typedef IntrusivePtr< NPatchVisual > NPatchVisualPtr; * | auxiliaryImage | STRING | * | auxiliaryImageAlpha | FLOAT | */ -class NPatchVisual: public Visual::Base +class NPatchVisual: public Visual::Base, public TextureUploadObserver { public: @@ -206,8 +208,32 @@ private: */ Geometry CreateBorderGeometry( Uint16Pair gridSize ); + /** + * @brief Creates a renderer by using loaded resource. + */ + void SetResource(); + +private: + + /** + * @copydoc TextureUploadObserver::UploadCompleted + * + * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready. + * This callback is the place to add the renderer as it would be called once the loading is finished. + */ + void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, bool preMultiplied ) override {} + + /** + * @copydoc TextureUploadObserver::LoadComplete + * + * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready. + * This callback is the place to add the renderer as it would be called once the loading is finished. + */ + void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) override; + private: + WeakHandle mPlacementActor; ///< Weakhandle to contain Actor during texture loading NPatchLoader& mLoader; ///< reference to N patch loader for fast access VisualUrl mImageUrl; ///< The url to the N patch to load VisualUrl mAuxiliaryUrl; ///< An auxiliary image that can be displayed on top of the N-Patch diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp index bf78d25..b34b9f1 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.cpp +++ b/dali-toolkit/internal/visuals/texture-manager-impl.cpp @@ -144,6 +144,32 @@ TextureManager::~TextureManager() } } +Devel::PixelBuffer TextureManager::LoadPixelBuffer( + const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, bool synchronousLoading, TextureUploadObserver* textureObserver, bool orientationCorrection, TextureManager::MultiplyOnLoad& preMultiplyOnLoad ) +{ + Devel::PixelBuffer pixelBuffer; + if( synchronousLoading ) + { + if( url.IsValid() ) + { + pixelBuffer = LoadImageFromFile( url.GetUrl(), desiredSize, fittingMode, samplingMode, + orientationCorrection ); + if( pixelBuffer && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ) + { + PreMultiply( pixelBuffer, preMultiplyOnLoad ); + } + } + } + else + { + RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, + false, KEEP_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, + preMultiplyOnLoad, true ); + } + + return pixelBuffer; +} + TextureSet TextureManager::LoadTexture( const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, MaskingDataPointer& maskInfo, @@ -311,7 +337,7 @@ TextureManager::TextureId TextureManager::RequestLoad( { return RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, - preMultiplyOnLoad ); + preMultiplyOnLoad, false ); } TextureManager::TextureId TextureManager::RequestLoad( @@ -330,7 +356,7 @@ TextureManager::TextureId TextureManager::RequestLoad( { return RequestLoadInternal( url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, - preMultiplyOnLoad ); + preMultiplyOnLoad, false ); } TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl ) @@ -339,7 +365,7 @@ TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& mask auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; return RequestLoadInternal( maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, KEEP_PIXEL_BUFFER, NULL, true, - TextureManager::ReloadPolicy::CACHED, preMultiply ); + TextureManager::ReloadPolicy::CACHED, preMultiply, false ); } TextureManager::TextureId TextureManager::RequestLoadInternal( @@ -355,7 +381,8 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( TextureUploadObserver* observer, bool orientationCorrection, TextureManager::ReloadPolicy reloadPolicy, - TextureManager::MultiplyOnLoad& preMultiplyOnLoad) + TextureManager::MultiplyOnLoad& preMultiplyOnLoad, + bool loadPixelBuffer ) { // First check if the requested Texture is cached. const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, @@ -393,7 +420,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( mTextureInfoContainer.push_back( TextureInfo( textureId, maskTextureId, url.GetUrl(), desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, - preMultiply ) ); + preMultiply, loadPixelBuffer ) ); cacheIndex = mTextureInfoContainer.size() - 1u; DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", @@ -459,7 +486,11 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( break; } case TextureManager::LOAD_FINISHED: - // Loading has already completed. Do nothing. + // Loading has already completed. + if( observer && textureInfo.loadPixelBuffer ) + { + LoadOrQueueTexture( textureInfo, observer ); + } break; } @@ -755,6 +786,10 @@ void TextureManager::ProcessQueuedTextures() textureInfo.useAtlas, textureInfo.atlasRect, textureInfo.preMultiplied ); } + else if ( textureInfo.loadState == LOAD_FINISHED && textureInfo.loadPixelBuffer ) + { + element.mObserver->LoadComplete( true, textureInfo.pixelBuffer, textureInfo.url, textureInfo.preMultiplied ); + } else { LoadTexture( textureInfo, element.mObserver ); @@ -820,6 +855,7 @@ void TextureManager::PostLoad( TextureInfo& textureInfo, Devel::PixelBuffer& pix { // No atlas support for now textureInfo.useAtlas = NO_ATLAS; + textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied(); if( textureInfo.storageType == UPLOAD_TO_TEXTURE ) { @@ -860,6 +896,10 @@ void TextureManager::PostLoad( TextureInfo& textureInfo, Devel::PixelBuffer& pix textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data textureInfo.loadState = LOAD_FINISHED; + if( textureInfo.loadPixelBuffer ) + { + NotifyObservers( textureInfo, true ); + } // Check if there was another texture waiting for this load to complete // (e.g. if this was an image mask, and its load is on a different thread) CheckForWaitingTexture( textureInfo ); @@ -976,8 +1016,16 @@ void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success ) DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "NotifyObservers() url:%s loadState:%s\n", textureInfo.url.GetUrl().c_str(), GET_LOAD_STATE_STRING(textureInfo.loadState ) ); - observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect, - info->preMultiplied ); + if( info->loadPixelBuffer ) + { + observer->LoadComplete( success, info->pixelBuffer, info->url, info->preMultiplied ); + } + else + { + observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect, + info->preMultiplied ); + } + observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed ); // Get the textureInfo from the container again as it may have been invalidated. @@ -1001,6 +1049,11 @@ void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success ) mQueueLoadFlag = false; ProcessQueuedTextures(); + + if( info->loadPixelBuffer && info->observerList.Count() == 0 ) + { + Remove( info->textureId, nullptr ); + } } TextureManager::TextureId TextureManager::GenerateUniqueTextureId() diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.h b/dali-toolkit/internal/visuals/texture-manager-impl.h index 7d66256..5146991 100755 --- a/dali-toolkit/internal/visuals/texture-manager-impl.h +++ b/dali-toolkit/internal/visuals/texture-manager-impl.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -163,6 +163,36 @@ public: // TextureManager Main API: /** + * @brief Requests an image load of the given URL to get PixelBuffer. + * + * The parameters are used to specify how the image is loaded. + * The observer has the LoadComplete method called when the load is ready. + * + * @param[in] url The URL of the image to load + * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic + * @param[in] fittingMode The FittingMode to use + * @param[in] samplingMode The SamplingMode to use + * @param[in] synchronousLoading true if the URL should be loaded synchronously + * @param[in] textureObserver The client object should inherit from this and provide the "UploadCompleted" virtual. + * This is called when an image load completes (or fails). + * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data + * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the + * image has no alpha channel + * + * @return The pixel buffer containing the image, or empty if still loading. + */ + + Devel::PixelBuffer LoadPixelBuffer( const VisualUrl& url, + Dali::ImageDimensions desiredSize, + Dali::FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode, + bool synchronousLoading, + TextureUploadObserver* textureObserver, + bool orientationCorrection, + TextureManager::MultiplyOnLoad& preMultiplyOnLoad ); + + + /** * @brief Requests an image load of the given URL. * * The parameters are used to specify how the image is loaded. @@ -415,7 +445,8 @@ private: TextureUploadObserver* observer, bool orientationCorrection, TextureManager::ReloadPolicy reloadPolicy, - MultiplyOnLoad& preMultiplyOnLoad ); + MultiplyOnLoad& preMultiplyOnLoad, + bool loadPixelBuffer ); /** * @brief Get the current state of a texture @@ -446,7 +477,8 @@ private: UseAtlas useAtlas, TextureManager::TextureHash hash, bool orientationCorrection, - bool preMultiplyOnLoad ) + bool preMultiplyOnLoad, + bool loadPixelBuffer ) : url( url ), desiredSize( desiredSize ), useSize( desiredSize ), @@ -465,7 +497,8 @@ private: cropToMask( cropToMask ), orientationCorrection( true ), preMultiplyOnLoad( preMultiplyOnLoad ), - preMultiplied( false ) + preMultiplied( false ), + loadPixelBuffer( loadPixelBuffer ) { } @@ -498,6 +531,7 @@ private: bool orientationCorrection:1; ///< true if the image should be rotated to match exif orientation data bool preMultiplyOnLoad:1; ///< true if the image's color should be multiplied by it's alpha bool preMultiplied:1; ///< true if the image's color was multiplied by it's alpha + bool loadPixelBuffer:1; ///< true if the image is needed to be returned as PixelBuffer }; /** diff --git a/dali-toolkit/internal/visuals/texture-upload-observer.h b/dali-toolkit/internal/visuals/texture-upload-observer.h index 1bf9944..b00722c 100644 --- a/dali-toolkit/internal/visuals/texture-upload-observer.h +++ b/dali-toolkit/internal/visuals/texture-upload-observer.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_INTERNAL_TEXTURE_UPLOAD_OBSERVER_H /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -18,9 +18,14 @@ * */ -#include +// EXTERNAL INCLUDES +#include #include +// INTERNAL INCLUDES +#include +#include + namespace Dali { @@ -67,6 +72,17 @@ public: const Vector4& atlasRect, bool preMultiplied ) = 0; /** + * The action to be taken once the async load has finished. + * This should be overridden by the deriving class. + * + * @param[in] loadSuccess True if the image load was successful (i.e. the resource is available). If false, then the resource failed to load. + * @param[in] pixelBuffer The PixelBuffer of the loaded image. + * @param[in] url The url address of the loaded image. + * @param[in] preMultiplied True if the image had pre-multiplied alpha applied + */ + virtual void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const Internal::VisualUrl& url, bool preMultiplied ) = 0; + + /** * @brief Returns the destruction signal. * This is emitted when the observer is destroyed. * This is used by the observer notifier to mark this observer as destroyed (IE. It no longer needs notifying). -- 2.7.4