From d2cc1da3aea2842d9de3e2f5288d768be711fa5b Mon Sep 17 00:00:00 2001 From: Xiangyin Ma Date: Thu, 12 May 2016 16:37:02 +0100 Subject: [PATCH] ImageRenderer provides property to indicate async/sync resource loading Change-Id: I282c0c9d5f904a6d7358b9997357664fbae90e97 --- automated-tests/resources/test-image-600.jpg | Bin 0 -> 8684 bytes automated-tests/src/dali-toolkit/CMakeLists.txt | 1 + .../toolkit-bitmap-loader.cpp | 51 ++++++- .../toolkit-bitmap-loader.h | 66 ++++++++ .../src/dali-toolkit/utc-Dali-ControlRenderer.cpp | 9 ++ .../src/dali-toolkit/utc-Dali-ImageView.cpp | 125 +++++++++++++++ .../controls/image-view/image-view-impl.cpp | 9 +- .../internal/controls/image-view/image-view-impl.h | 2 - .../renderers/control-renderer-data-impl.h | 3 +- .../controls/renderers/control-renderer-impl.cpp | 10 +- .../controls/renderers/image/image-renderer.cpp | 169 ++++++++++++++++----- .../controls/renderers/image/image-renderer.h | 34 ++++- .../public-api/controls/image-view/image-view.h | 3 +- 13 files changed, 426 insertions(+), 56 deletions(-) create mode 100644 automated-tests/resources/test-image-600.jpg create mode 100644 automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.h diff --git a/automated-tests/resources/test-image-600.jpg b/automated-tests/resources/test-image-600.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c93db33c5256b7ef197efcb0ebde4af21382f039 GIT binary patch literal 8684 zcmeH}YfKbZ6vxlJc4mhaSRQKIG+R&#TbdAj)!MXEpnziH22jC%S;bmylcrItR2z2` zwCWn;1C-XJU05F|U#Q}vZQ6`m!HP{&X|)O_x*{s2HSDfD2AG}OJFU^At_k&%AMTlZ zl1b*?$^U=OZ|)s*1^FSiAa7P4P!t6V@dfBAEMiiqgICyh(%ot0wac{iDSZ=Js!y@p4G2{OQIt^BVE~QHuDj8@i#aJoS3^o9Y z!)gt|_k*GtmNQ{VVicZmA{NVM7#fS^SQgJ-ho1v$<>HbuvrO@Yi}>W_36nPLsuLz; zAN3^`wFM?lE?ZGy7RQbo|ID)~FQ%s1Uz##?+AGsvossiaZeIS(Sp~&&=gluEUGVne zcb2@nblH3Ful#7$>hh1*tgYO*>C??ywz_v$Rqxqb^V#S7y!#IvJXC-9NW-zF<0np@ z`udx1e>l_Ja`wk_t>=IJ?c$~1FJEczxY2pD>(=c%-GB51L-+dn2L{!lVZ#>%%)hoC zIQx$;EA~a>910%K>Rw%y7IOjlf@DgrI9!>a@pnF#1LWm5OS=s0_WK)XJR;)T={w zJf}s^Z$Z%5?pP!HQ+wwns_6)2z+x6B53WCn~QA6`LG!QF9(W`$f0$% z;LF+vS~Y?|8G;uOIFEf9LU7t~tsy;7q9^YR*GkwIp|e5>CTzY-A;^|}*R_Nm zr{>9zs44E3v)5Z42uvBFnEnxaZ-&N(d%OxKKT`D_5fr6(wkx|my2aUL`*Wc9no~88 zT*`Hc2qM(`Q9ZMz=j0Sg8?T&`F8@{kof3#2Y;cbjf*tB!*EGFARx{0AYYIKo}qljG6%k Gwf_w -#include #include +#include using namespace Dali; namespace Dali { -class Adaptor; +namespace +{ +Dali::BitmapLoader gBitmapLoader; +} + namespace Internal { @@ -49,6 +57,7 @@ public: mPixelData(), mUrl(url) { + sem_init( &mySemaphore, 0, 0 ); } ~BitmapLoader(){} @@ -60,6 +69,8 @@ public: memset(buffer, 0, bufferSize); mPixelData = PixelData::New( buffer, mSize.GetWidth(), mSize.GetHeight(), Pixel::RGBA8888, PixelData::FREE); + + sem_post( &mySemaphore ); } PixelDataPtr GetPixelData() const @@ -77,9 +88,19 @@ public: return mPixelData ? true : false; } + void WaitForLoading() + { + if( mPixelData ) + { + return; + } + sem_wait( &mySemaphore ); + } + ImageDimensions mSize; PixelDataPtr mPixelData; const std::string mUrl; + sem_t mySemaphore; }; } // internal @@ -101,7 +122,12 @@ inline const Internal::BitmapLoader& GetImplementation(const Dali::BitmapLoader& Dali::BitmapLoader Dali::BitmapLoader::New(std::string const&url, Dali::Uint16Pair size, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, bool orientationCorrection) { IntrusivePtr internal = Internal::BitmapLoader::New(url, size, fittingMode, samplingMode, orientationCorrection); - return BitmapLoader( internal.Get() ); + gBitmapLoader = BitmapLoader(internal.Get()); + return gBitmapLoader; +} + +BitmapLoader::BitmapLoader() +{ } Dali::BitmapLoader::BitmapLoader(Dali::BitmapLoader const& handle) @@ -115,6 +141,11 @@ Dali::BitmapLoader::BitmapLoader(Internal::BitmapLoader* internal) Dali::BitmapLoader::~BitmapLoader() { } +BitmapLoader& BitmapLoader::operator=(const BitmapLoader& rhs) +{ + BaseHandle::operator=(rhs); + return *this; +} void Dali::BitmapLoader::Load() { GetImplementation(*this).Load(); @@ -131,5 +162,19 @@ bool Dali::BitmapLoader::IsLoaded() { return GetImplementation(*this).IsLoaded(); } +void Dali::BitmapLoader::WaitForLoading() +{ + GetImplementation(*this).WaitForLoading(); +} + +BitmapLoader Dali::BitmapLoader::GetLatestCreated() +{ + return gBitmapLoader; +} + +void Dali::BitmapLoader::ResetLatestCreated() +{ + gBitmapLoader.Reset(); +} } // Dali diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.h new file mode 100644 index 0000000..141903b --- /dev/null +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.h @@ -0,0 +1,66 @@ +#ifndef __DALI_TOOLKIT_BITMAP_LOADER_H__ +#define __DALI_TOOLKIT_BITMAP_LOADER_H__ +/* + * Copyright (c) 2016 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. + */ + +#define __DALI_BITMAP_LOADER_H__ + +#include +#include +#include +#include +#include +#include + +namespace Dali +{ +namespace Internal +{ +class BitmapLoader; +} + +class DALI_IMPORT_API BitmapLoader : public BaseHandle +{ +public: + + static BitmapLoader New( const std::string& url, + ImageDimensions size = ImageDimensions( 0, 0 ), + FittingMode::Type fittingMode = FittingMode::DEFAULT, + SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR, + bool orientationCorrection = true); + BitmapLoader(); + ~BitmapLoader(); + BitmapLoader(const BitmapLoader& handle); + BitmapLoader& operator=(const BitmapLoader& rhs); + +public: + void Load(); + bool IsLoaded(); + std::string GetUrl() const; + PixelDataPtr GetPixelData() const; + + void WaitForLoading(); + static BitmapLoader GetLatestCreated(); // return the latest created BitmapLoader + static void ResetLatestCreated(); + +public: // Not intended for application developers + + explicit DALI_INTERNAL BitmapLoader(Internal::BitmapLoader*); +}; + +} // Dali + +#endif /* __DALI_TOOLKIT_BITMAP_LOADER_H__ */ diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp index f5a2d96..d524b81 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp @@ -483,6 +483,7 @@ int UtcDaliControlRendererGetPropertyMap5(void) propertyMap.Insert( "desiredHeight", 30 ); propertyMap.Insert( "fittingMode", "FIT_HEIGHT" ); propertyMap.Insert( "samplingMode", "BOX_THEN_NEAREST" ); + propertyMap.Insert( "synchronousLoading", true ); ControlRenderer imageRenderer = factory.GetControlRenderer(propertyMap); DALI_TEST_CHECK( imageRenderer ); @@ -515,6 +516,10 @@ int UtcDaliControlRendererGetPropertyMap5(void) DALI_TEST_CHECK( value ); DALI_TEST_CHECK( value->Get() == 30 ); + value = resultMap.Find( "synchronousLoading", Property::BOOLEAN ); + DALI_TEST_CHECK( value ); + DALI_TEST_CHECK( value->Get() == true ); + // Get an image renderer with an image handle, and test the default property values Image image = ResourceImage::New(TEST_IMAGE_FILE_NAME, ImageDimensions(100, 200)); imageRenderer = factory.GetControlRenderer(image); @@ -544,6 +549,10 @@ int UtcDaliControlRendererGetPropertyMap5(void) DALI_TEST_CHECK( value ); DALI_TEST_CHECK( value->Get() == 200 ); + value = resultMap.Find( "synchronousLoading", Property::BOOLEAN ); + DALI_TEST_CHECK( value ); + DALI_TEST_CHECK( value->Get() == false ); + 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 67f054c..5955748 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp @@ -18,6 +18,8 @@ // Need to override adaptor classes for toolkit test harness, so include // test harness headers before dali headers. #include +#include +#include #include #include @@ -73,6 +75,11 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER( const char* TEST_IMAGE_FILE_NAME = "gallery_image_01.jpg"; const char* TEST_IMAGE_FILE_NAME2 = "gallery_image_02.jpg"; +// resolution: 34*34, pixel format: RGBA8888 +static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png"; +// resolution: 600*600, pixel format: RGB888 +static const char* gImage_600_RGB = TEST_RESOURCE_DIR "/test-image-600.jpg"; + void TestImage( ImageView imageView, BufferImage image ) { Property::Value value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) ); @@ -356,6 +363,124 @@ int UtcDaliImageViewSetGetProperty03(void) END_TEST; } +int UtcDaliImageViewAsyncLoadingWithoutAltasing(void) +{ + ToolkitTestApplication application; + + // Async loading, no atlasing for big size image + ImageView imageView = ImageView::New( gImage_600_RGB ); + + // By default, Aysnc loading is used + Stage::GetCurrent().Add( imageView ); + application.SendNotification(); + application.Render(16); + application.Render(16); + application.SendNotification(); + + // BitmapLoader is not used + BitmapLoader loader = BitmapLoader::GetLatestCreated(); + DALI_TEST_CHECK( !loader ); + + END_TEST; +} + +int UtcDaliImageViewAsyncLoadingWithAltasing(void) +{ + ToolkitTestApplication application; + + //Async loading, automatic atlasing for small size image + TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace(); + callStack.Reset(); + callStack.Enable(true); + + ImageView imageView = ImageView::New( gImage_34_RGBA, ImageDimensions( 34, 34 ) ); + + // By default, Aysnc loading is used + // loading is not started if the actor is offStage + BitmapLoader loader = BitmapLoader::GetLatestCreated(); + DALI_TEST_CHECK( !loader ); + + Stage::GetCurrent().Add( imageView ); + application.SendNotification(); + application.Render(16); + application.Render(16); + application.SendNotification(); + + // loading started + loader = BitmapLoader::GetLatestCreated(); + DALI_TEST_CHECK( loader ); + + // worker thread is created + EventThreadCallback* eventTrigger = EventThreadCallback::Get(); + DALI_TEST_CHECK( eventTrigger ); + + loader.WaitForLoading();// waiting until the image to be loaded + DALI_TEST_CHECK( loader.IsLoaded() ); + + CallbackBase* callback = eventTrigger->GetCallback(); + CallbackBase::Execute( *callback ); + + application.SendNotification(); + application.Render(16); + + callStack.Enable(false); + + DALI_TEST_CHECK( callStack.FindMethodAndParams("TexSubImage2D", "0, 0, 34, 34" ) ); + + + END_TEST; +} + +int UtcDaliImageViewSyncLoading(void) +{ + ToolkitTestApplication application; + + Property::Map syncLoadingMap; + syncLoadingMap[ "synchronousLoading" ] = true; + + // Sync loading, no atlasing for big size image + { + ImageView imageView = ImageView::New( gImage_600_RGB ); + + // Sync loading is used + imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap ); + + // BitmapLoader is used, and the loading is started immediately even the actor is not on stage. + BitmapLoader loader = BitmapLoader::GetLatestCreated(); + DALI_TEST_CHECK( loader ); + } + + // Sync loading, automatic atlasing for small size image + { + BitmapLoader::ResetLatestCreated(); + TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace(); + callStack.Reset(); + callStack.Enable(true); + + ImageView imageView = ImageView::New( ); + // Sync loading is used + syncLoadingMap[ "url" ] = gImage_34_RGBA; + syncLoadingMap[ "desiredHeight" ] = 34; + syncLoadingMap[ "desiredWidth" ] = 34; + imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap ); + + // loading is started even if the actor is offStage + BitmapLoader loader = BitmapLoader::GetLatestCreated(); + DALI_TEST_CHECK( loader ); + + loader.WaitForLoading(); + + DALI_TEST_CHECK( loader.IsLoaded() ); + + Stage::GetCurrent().Add( imageView ); + application.SendNotification(); + application.Render(16); + DALI_TEST_CHECK( callStack.FindMethodAndParams("TexSubImage2D", "0, 0, 34, 34" ) ); + } + + END_TEST; +} + int UtcDaliImageViewSizeWithBackground(void) { ToolkitTestApplication application; diff --git a/dali-toolkit/internal/controls/image-view/image-view-impl.cpp b/dali-toolkit/internal/controls/image-view/image-view-impl.cpp index e50e961..03229f9 100644 --- a/dali-toolkit/internal/controls/image-view/image-view-impl.cpp +++ b/dali-toolkit/internal/controls/image-view/image-view-impl.cpp @@ -44,8 +44,7 @@ DALI_TYPE_REGISTRATION_END() using namespace Dali; ImageView::ImageView() -: Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ), - mPremultipledAlphaEnabled( false ) +: Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ) { } @@ -305,10 +304,10 @@ void ImageView::SetProperty( BaseObject* object, Property::Index index, const Pr case Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA: { - bool IsPre; - if( value.Get( IsPre ) ) + bool isPre; + if( value.Get( isPre ) ) { - GetImpl(imageView).EnablePreMultipliedAlpha( IsPre ); + GetImpl(imageView).EnablePreMultipliedAlpha( isPre ); } break; } diff --git a/dali-toolkit/internal/controls/image-view/image-view-impl.h b/dali-toolkit/internal/controls/image-view/image-view-impl.h index c598c26..fcc0c63 100644 --- a/dali-toolkit/internal/controls/image-view/image-view-impl.h +++ b/dali-toolkit/internal/controls/image-view/image-view-impl.h @@ -164,8 +164,6 @@ private: std::string mUrl; ///< the url for the image if the image came from a URL, empty otherwise Image mImage; ///< the Image if the image came from a Image, null otherwise Property::Map mPropertyMap; ///< the Property::Map if the image came from a Property::Map, empty otherwise - - bool mPremultipledAlphaEnabled; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h b/dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h index 2428715..5092075 100644 --- a/dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h +++ b/dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h @@ -39,7 +39,8 @@ struct Internal::ControlRenderer::Impl { IS_ON_STAGE = 1, IS_FROM_CACHE = 1 << 1, - IS_PREMULTIPLIED_ALPHA = 1 << 2 + IS_PREMULTIPLIED_ALPHA = 1 << 2, + IS_SYNCHRONOUS_RESOURCE_LOADING = 1 << 3 }; struct CustomShader diff --git a/dali-toolkit/internal/controls/renderers/control-renderer-impl.cpp b/dali-toolkit/internal/controls/renderers/control-renderer-impl.cpp index 42d9634..2009f8a 100644 --- a/dali-toolkit/internal/controls/renderers/control-renderer-impl.cpp +++ b/dali-toolkit/internal/controls/renderers/control-renderer-impl.cpp @@ -137,7 +137,15 @@ void ControlRenderer::SetOffStage( Actor& actor ) void ControlRenderer::EnablePreMultipliedAlpha( bool preMultipled ) { - mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA; + if(preMultipled) + { + mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA; + } + else + { + mImpl->mFlags &= ~Impl::IS_PREMULTIPLIED_ALPHA; + } + if( mImpl->mRenderer ) { mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, preMultipled); diff --git a/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp b/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp index 90dd616..af155f7 100644 --- a/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp +++ b/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp @@ -22,6 +22,8 @@ #include // for strncasecmp #include #include +#include +#include #include // INTERNAL HEADER @@ -51,6 +53,7 @@ const char * const IMAGE_FITTING_MODE( "fittingMode" ); const char * const IMAGE_SAMPLING_MODE( "samplingMode" ); const char * const IMAGE_DESIRED_WIDTH( "desiredWidth" ); const char * const IMAGE_DESIRED_HEIGHT( "desiredHeight" ); +const char * const SYNCHRONOUS_LOADING( "synchronousLoading" ); // fitting modes const char * const SHRINK_TO_FIT("SHRINK_TO_FIT"); @@ -248,6 +251,29 @@ void ImageRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap } mDesiredSize = ImageDimensions( desiredWidth, desiredHeight ); + + } + + Property::Value* syncLoading = propertyMap.Find( SYNCHRONOUS_LOADING ); + if( syncLoading ) + { + bool sync; + syncLoading->Get( sync ); + if( sync ) + { + mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; + } + else + { + mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; + } + } + + // if sync loading is required, the loading should start immediately when new image url is set or the actor is off stage + // ( for on-stage actor with image url unchanged, resource loading is already finished) + if( ( !mImpl->mRenderer || imageURLValue) && IsSynchronousResourceLoading() ) + { + DoSynchronousResourceLoading(); } // remove old renderer if exit @@ -354,10 +380,7 @@ Renderer ImageRenderer::CreateRenderer() const } } - TextureSet textureSet = TextureSet::New(); - Renderer renderer = Renderer::New( geometry, shader ); - renderer.SetTextures( textureSet ); return renderer; } @@ -378,20 +401,13 @@ Renderer ImageRenderer::CreateNativeImageRenderer() const else { geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize ); - if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() ) + shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader, + mNativeFragmentShaderCode, + mImpl->mCustomShader->mHints ); + if( mImpl->mCustomShader->mVertexShader.empty() ) { - shader = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode ); - } - else - { - shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader, - mNativeFragmentShaderCode, - mImpl->mCustomShader->mHints ); - if( mImpl->mCustomShader->mVertexShader.empty() ) - { - shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT ); - shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT ); - } + shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT ); + shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT ); } } @@ -402,6 +418,82 @@ Renderer ImageRenderer::CreateNativeImageRenderer() const return renderer; } + +bool ImageRenderer::IsSynchronousResourceLoading() const +{ + return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; +} + +void ImageRenderer::DoSynchronousResourceLoading() +{ + if( !mImageUrl.empty() ) + { + BitmapLoader loader = BitmapLoader::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode ); + loader.Load(); + mPixels = loader.GetPixelData(); + } +} + +Image ImageRenderer::LoadImage( const std::string& url, bool synchronousLoading ) +{ + if( synchronousLoading ) + { + if( !mPixels ) + { + // use broken image + return RendererFactory::GetBrokenRendererImage(); + } + Atlas image = Atlas::New( mPixels->GetWidth(), mPixels->GetHeight(), mPixels->GetPixelFormat() ); + image.Upload( mPixels, 0, 0 ); + return image; + } + else + { + ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode ); + resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); + return resourceImage; + } +} + +TextureSet ImageRenderer::CreateTextureSet( Vector4& textureRect, const std::string& url, bool synchronousLoading ) +{ + TextureSet textureSet; + textureRect = FULL_TEXTURE_RECT; + if( synchronousLoading ) + { + if( !mPixels ) + { + // use broken image + textureSet = TextureSet::New(); + textureSet.SetImage( 0u, RendererFactory::GetBrokenRendererImage() ); + } + else + { + textureSet = mAtlasManager.Add(textureRect, mPixels ); + if( !textureSet ) // big image, no atlasing + { + Atlas image = Atlas::New( mPixels->GetWidth(), mPixels->GetHeight(), mPixels->GetPixelFormat() ); + image.Upload( mPixels, 0, 0 ); + textureSet = TextureSet::New(); + textureSet.SetImage( 0u, image ); + } + } + } + else + { + textureSet = mAtlasManager.Add(textureRect, url, mDesiredSize, mFittingMode, mSamplingMode ); + if( !textureSet ) // big image, no atlasing + { + ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode ); + resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); + textureSet = TextureSet::New(); + textureSet.SetImage( 0u, resourceImage ); + } + } + + return textureSet; +} + void ImageRenderer::InitializeRenderer( const std::string& imageUrl ) { if( imageUrl.empty() ) @@ -420,25 +512,15 @@ void ImageRenderer::InitializeRenderer( const std::string& imageUrl ) if( !mImpl->mRenderer ) { Vector4 atlasRect; - TextureSet textureSet = mAtlasManager.Add(atlasRect, imageUrl, mDesiredSize, mFittingMode, mSamplingMode ); - if( textureSet ) + TextureSet textureSet = CreateTextureSet(atlasRect, imageUrl, IsSynchronousResourceLoading() ); + Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) ); + Shader shader( GetImageShader(mFactoryCache) ); + mImpl->mRenderer = Renderer::New( geometry, shader ); + mImpl->mRenderer.SetTextures( textureSet ); + if( atlasRect != FULL_TEXTURE_RECT ) { - Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) ); - Shader shader( GetImageShader(mFactoryCache) ); - mImpl->mRenderer = Renderer::New( geometry, shader ); - mImpl->mRenderer.SetTextures( textureSet ); mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect ); } - else // big image, atlasing is not applied - { - mImpl->mRenderer = CreateRenderer(); - - ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode ); - image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); - TextureSet textureSet = mImpl->mRenderer.GetTextures(); - textureSet.SetImage( 0u, image ); - } - mFactoryCache.SaveRenderer( imageUrl, mImpl->mRenderer ); } @@ -450,9 +532,8 @@ void ImageRenderer::InitializeRenderer( const std::string& imageUrl ) mImpl->mFlags &= ~Impl::IS_FROM_CACHE; mImpl->mRenderer = CreateRenderer(); - ResourceImage resourceImage = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode ); - resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); - ApplyImageToSampler( resourceImage ); + Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() ); + ApplyImageToSampler( image ); } } @@ -502,6 +583,9 @@ void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const { map.Clear(); map.Insert( RENDERER_TYPE, IMAGE_RENDERER ); + + bool sync = IsSynchronousResourceLoading(); + map.Insert( SYNCHRONOUS_LOADING, sync ); if( !mImageUrl.empty() ) { map.Insert( IMAGE_URL_NAME, mImageUrl ); @@ -618,6 +702,11 @@ void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, ImageDi mSamplingMode = samplingMode; mImage.Reset(); + if( IsSynchronousResourceLoading() ) + { + DoSynchronousResourceLoading(); + } + if( mImpl->mRenderer ) { if( GetIsFromCache() ) // if renderer is from cache, remove the old one @@ -641,8 +730,7 @@ void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, ImageDi } else // if renderer is not from cache, reuse the same renderer and only change the texture { - ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode ); - image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded ); + Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() ); ApplyImageToSampler( image ); } } @@ -733,10 +821,12 @@ void ImageRenderer::ApplyImageToSampler( const Image& image ) if( image ) { TextureSet textureSet = mImpl->mRenderer.GetTextures(); - if( textureSet ) + if( !textureSet ) { - textureSet.SetImage( 0u, image ); + textureSet = TextureSet::New(); + mImpl->mRenderer.SetTextures( textureSet ); } + textureSet.SetImage( 0u, image ); } } @@ -795,7 +885,6 @@ void ImageRenderer::SetNativeFragmentShaderCode( Dali::NativeImage& nativeImage { mNativeFragmentShaderCode.replace( mNativeFragmentShaderCode.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename ); } - } } // namespace Internal diff --git a/dali-toolkit/internal/controls/renderers/image/image-renderer.h b/dali-toolkit/internal/controls/renderers/image/image-renderer.h index da7e100..c63a073 100644 --- a/dali-toolkit/internal/controls/renderers/image/image-renderer.h +++ b/dali-toolkit/internal/controls/renderers/image/image-renderer.h @@ -46,13 +46,14 @@ typedef IntrusivePtr< ImageRenderer > ImageRendererPtr; * * The following properties are optional * - * | %Property Name | Type | - * |-------------------------|------------------| + * | %Property Name | Type | + * |--------------------|------------------| * | url | STRING | * | fittingMode | STRING | * | samplingMode | STRING | * | desiredWidth | INT | * | desiredHeight | INT | + * | synchronousLoading | BOOLEAN | * * where imageFittingMode should be one of the following fitting modes: * "SHRINK_TO_FIT" @@ -145,7 +146,7 @@ public: * The renderer will load the Image asynchronously when the associated actor is put on stage, and destroy the image when it is off stage * * @param[in] actor The Actor the renderer is applied to if, empty if the renderer has not been applied to any Actor - * @param[in] imageUrl The URL to to image resource to use + * @param[in] imageUrl The URL of the image resource to use * @param[in] size The width and height to fit the loaded image to. * @param[in] fittingMode The FittingMode of the resource to load * @param[in] samplingMode The SamplingMode of the resource to load @@ -202,6 +203,32 @@ private: Renderer CreateNativeImageRenderer() const; /** + * @brief Query whether resources requires to be loaded synchronously. + * @return Returns true if synchronoud resource loading is required, false otherwise. + */ + bool IsSynchronousResourceLoading() const; + + /** + * @brief Do the synchronous resource loading + */ + void DoSynchronousResourceLoading(); + + /** + * Load the image. + * @param[in] url The URL of the image resource to use. + * @param[in] synchronousLoading If true, the resource is loaded synchronously, otherwise asynchronously. + */ + Image LoadImage( const std::string& url, bool synchronousLoading ); + + /** + * Load the image and create a texture set to hold the texture, with automatic atlasing applied. + * @param [out] textureRect The texture area of the resource image in the atlas. + * @param[in] url The URL of the image resource to use. + * @param[in] synchronousLoading If true, the resource is loaded synchronously, otherwise asynchronously. + */ + TextureSet CreateTextureSet( Vector4& textureRect, const std::string& url, bool synchronousLoading ); + + /** * Callback function of image resource loading succeed * @param[in] image The Image content that we attempted to load from mImageUrl */ @@ -226,6 +253,7 @@ private: private: Image mImage; ImageAtlasManager& mAtlasManager; + PixelDataPtr mPixels; std::string mImageUrl; Dali::ImageDimensions mDesiredSize; diff --git a/dali-toolkit/public-api/controls/image-view/image-view.h b/dali-toolkit/public-api/controls/image-view/image-view.h index 14e3427..bc401f1 100644 --- a/dali-toolkit/public-api/controls/image-view/image-view.h +++ b/dali-toolkit/public-api/controls/image-view/image-view.h @@ -94,12 +94,13 @@ public: */ PRE_MULTIPLIED_ALPHA, + // Animatable properties /** * @brief name "pixelArea", type Vector4 * @details Pixel area is a relative value with the whole image area as [0.0, 0.0, 1.0, 1.0]. - * @SINCE_1_0.18 + * @SINCE_1_1.18 */ PIXEL_AREA = ANIMATABLE_PROPERTY_START_INDEX, }; -- 2.7.4