From: David Steele Date: Wed, 3 Jan 2018 16:20:19 +0000 (+0000) Subject: Added automatic premultiplication of image visual images X-Git-Tag: dali_1.3.6~1^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=235a3efd5d00a20adbcae39dfce2c29a6c0344b7 Added automatic premultiplication of image visual images To prevent scaling quality issues, image visual images are pre-multiplied after loading. By default, this is on, but it can be turned off via a new API in VisualFactory. Change-Id: I53757be33894effdd61b719631fb79527e8a4fbe Signed-off-by: David Steele --- diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.cpp b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.cpp index d792609..bd88e76 100644 --- a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.cpp +++ b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.cpp @@ -28,13 +28,11 @@ namespace Toolkit namespace Internal { -typedef IntrusivePtr VisualFactoryCachePtr; - DummyVisualPtr DummyVisual::New( const Property::Map& properties ) { - VisualFactoryCachePtr factoryCache = new VisualFactoryCache; + VisualFactoryCache* factoryCache = new VisualFactoryCache(false); - DummyVisualPtr dummyVisualPtr( new DummyVisual( *( factoryCache.Get() ) ) ); + DummyVisualPtr dummyVisualPtr( new DummyVisual( *factoryCache ) ); return dummyVisualPtr; } 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 e09dd06..ebada51 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp @@ -34,7 +34,8 @@ public: { } - void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect ) + virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, + bool useAtlasing, const Vector4& atlasRect, bool preMultiplied ) override { mLoaded = loadSuccess; mObserverCalled = true; @@ -53,7 +54,7 @@ int UtcTextureManagerRequestLoad(void) TestObserver observer; std::string filename("image.png"); - + auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; TextureManager::TextureId textureId = textureManager.RequestLoad( filename, ImageDimensions(), @@ -62,7 +63,8 @@ int UtcTextureManagerRequestLoad(void) TextureManager::NO_ATLAS, &observer, true, - TextureManager::ReloadPolicy::CACHED ); + TextureManager::ReloadPolicy::CACHED, + preMultiply); const VisualUrl& url = textureManager.GetVisualUrl( textureId ); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp index a2adf41..1a15ec6 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp @@ -154,6 +154,7 @@ int UtcDaliImageVisualPropertyMap(void) VisualFactory factory = VisualFactory::Get(); DALI_TEST_CHECK( factory ); + factory.SetPreMultiplyOnLoad( true ); Property::Map propertyMap; propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE ); @@ -171,6 +172,119 @@ int UtcDaliImageVisualPropertyMap(void) DummyControl actor = DummyControl::New(); 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 ); + auto renderer = actor.GetRendererAt(0); + auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" ); + DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX ); + auto preMultipliedAlpha = renderer.GetProperty( preMultipliedIndex ); + auto preMultipliedAlpha2 = renderer.GetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA ); + DALI_TEST_EQUALS( preMultipliedAlpha, 1.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( preMultipliedAlpha2, true, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); + + Stage::GetCurrent().Remove( actor ); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + + END_TEST; +} + + +int UtcDaliImageVisualNoPremultipliedAlpha01(void) +{ + ToolkitTestApplication application; + tet_infoline( "Request image visual without pre-multiplied alpha" ); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK( factory ); + factory.SetPreMultiplyOnLoad( false ); + + Property::Map propertyMap; + propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE ); + propertyMap.Insert( ImageVisual::Property::URL, TEST_LARGE_IMAGE_FILE_NAME ); + + Visual::Base visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied. + // Image with a size smaller than 512*512 will be uploaded as a part of the atlas. + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + DummyControl actor = DummyControl::New(); + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, 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 ); + auto renderer = actor.GetRendererAt(0); + auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" ); + DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX ); + auto preMultipliedAlpha = renderer.GetProperty( preMultipliedIndex ); + auto preMultipliedAlpha2 = renderer.GetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA ); + + DALI_TEST_EQUALS( preMultipliedAlpha, false, TEST_LOCATION ); + DALI_TEST_EQUALS( preMultipliedAlpha2, false, TEST_LOCATION ); + + DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); + + Stage::GetCurrent().Remove( actor ); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + + END_TEST; +} + + +int UtcDaliImageVisualNoPremultipliedAlpha02(void) +{ + ToolkitTestApplication application; + tet_infoline( "Request image visual with no alpha channel" ); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK( factory ); + + Property::Map propertyMap; + propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE ); + propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ); + + Visual::Base visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied. + // Image with a size smaller than 512*512 will be uploaded as a part of the atlas. + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + DummyControl actor = DummyControl::New(); + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual ); actor.SetSize( 200.f, 200.f ); @@ -186,6 +300,14 @@ int UtcDaliImageVisualPropertyMap(void) application.Render(); DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION ); + auto renderer = actor.GetRendererAt(0); + auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" ); + DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX ); + auto preMultipliedAlpha = renderer.GetProperty( preMultipliedIndex ); + auto preMultipliedAlpha2 = renderer.GetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA ); + + DALI_TEST_EQUALS( preMultipliedAlpha, false, TEST_LOCATION ); + DALI_TEST_EQUALS( preMultipliedAlpha2, false, TEST_LOCATION ); DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); diff --git a/dali-toolkit/devel-api/visual-factory/visual-factory.cpp b/dali-toolkit/devel-api/visual-factory/visual-factory.cpp index b91d79d..666a2a1 100644 --- a/dali-toolkit/devel-api/visual-factory/visual-factory.cpp +++ b/dali-toolkit/devel-api/visual-factory/visual-factory.cpp @@ -109,6 +109,16 @@ Visual::Base VisualFactory::CreateVisual( const std::string& url, ImageDimension return GetImplementation( *this ).CreateVisual( url, size ); } +void VisualFactory::SetPreMultiplyOnLoad( bool preMultiply ) +{ + GetImplementation( *this ).SetPreMultiplyOnLoad( preMultiply ); +} + +bool VisualFactory::GetPreMultiplyOnLoad() const +{ + return GetImplementation( *this ).GetPreMultiplyOnLoad(); +} + } // namespace Toolkit } // namespace Dali diff --git a/dali-toolkit/devel-api/visual-factory/visual-factory.h b/dali-toolkit/devel-api/visual-factory/visual-factory.h index 25c17cc..856360b 100644 --- a/dali-toolkit/devel-api/visual-factory/visual-factory.h +++ b/dali-toolkit/devel-api/visual-factory/visual-factory.h @@ -117,6 +117,25 @@ public: */ Visual::Base CreateVisual( const std::string& url, ImageDimensions size ); + /** + * @brief Enable or disable premultiplying alpha in images and image visuals. + * + * The default is to enable pre-multiplication on load. + * + * Applications that have assets with pre-multiplied alpha already applied should turn this option off. + * + * @param[in] preMultiply True if loaded images for image visuals should have alpha multiplied into the color + * channels. + */ + void SetPreMultiplyOnLoad( bool preMultiply ); + + /** + * @brief Get the setting for automatically pre-multiplying image visual images on load. + * + * @return True if loaded images have pre-multiplied alpha applied on load, false otherwise. + */ + bool GetPreMultiplyOnLoad() const; + private: explicit DALI_INTERNAL VisualFactory(Internal::VisualFactory *impl); 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 3764500..b1713d2 100644 --- a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp @@ -113,6 +113,7 @@ void FixedImageCache::LoadBatch() AtlasUploadObserver* atlasObserver = nullptr; ImageAtlasManagerPtr imageAtlasManager = nullptr; Vector4 textureRect; + auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; mTextureManager.LoadTexture( url, ImageDimensions(), FittingMode::SCALE_TO_FILL, @@ -120,7 +121,8 @@ void FixedImageCache::LoadBatch() synchronousLoading, mImageUrls[ mUrlIndex ].mTextureId, textureRect, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, - atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED ); + atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, + preMultiply ); if( loadingStatus == false ) // not loading, means it's already ready. { @@ -164,7 +166,8 @@ void FixedImageCache::UploadComplete( int32_t textureId, TextureSet textureSet, bool useAtlasing, - const Vector4& atlasRect ) + const Vector4& atlasRect, + bool preMultiplied) { bool frontFrameReady = IsFrontReady(); 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 b9b2ddb..570b2d7 100644 --- a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h @@ -95,7 +95,8 @@ protected: int32_t textureId, TextureSet textureSet, bool useAtlasing, - const Vector4& atlasRect ); + const Vector4& atlasRect, + bool premultiplied) override; private: std::vector& mImageUrls; diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp index 5922f74..ed61adb 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp @@ -147,6 +147,7 @@ void RollingGifImageCache::LoadBatch() AtlasUploadObserver* atlasObserver = nullptr; ImageAtlasManagerPtr imageAtlasManager = nullptr; Vector4 textureRect; + auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; mTextureManager.LoadTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL, @@ -154,7 +155,7 @@ void RollingGifImageCache::LoadBatch() synchronousLoading, mImageUrls[ imageFrame.mFrameNumber ].mTextureId, textureRect, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, NULL, - atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED ); + atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply ); } mFrameIndex += batchSize; 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 62599e5..37c7a7d 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp @@ -148,6 +148,7 @@ void RollingImageCache::LoadBatch() AtlasUploadObserver* atlasObserver = nullptr; ImageAtlasManagerPtr imageAtlasManager = nullptr; Vector4 textureRect; + auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; mTextureManager.LoadTexture( url, ImageDimensions(), FittingMode::SCALE_TO_FILL, @@ -155,7 +156,8 @@ void RollingImageCache::LoadBatch() synchronousLoading, mImageUrls[ imageFrame.mUrlIndex ].mTextureId, textureRect, atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT, this, - atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED ); + atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, + preMultiply ); mRequestingLoad = false; } @@ -200,7 +202,8 @@ void RollingImageCache::UploadComplete( int32_t textureId, TextureSet textureSet, bool useAtlasing, - const Vector4& atlasRect ) + const Vector4& atlasRect, + bool preMultiplied ) { DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::UploadComplete(textureId:%d) start\n", textureId); LOG_CACHE; 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 b1fcce3..76a79ec 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h @@ -111,7 +111,8 @@ protected: int32_t textureId, TextureSet textureSet, bool useAtlasing, - const Vector4& atlasRect ); + const Vector4& atlasRect, + bool preMultiplied ) override; private: /** diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index 51924f0..d9ea9cd 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -698,6 +698,11 @@ void ImageVisual::CreateRenderer( TextureSet& textureSet ) //Register transform properties mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); + + if( IsPreMultipliedAlphaEnabled() ) + { + EnablePreMultipliedAlpha( true ); + } } void ImageVisual::CreateNativeImageRenderer( NativeImage& nativeImage ) @@ -754,7 +759,6 @@ void ImageVisual::CreateNativeImageRenderer( NativeImage& nativeImage ) mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); } - bool ImageVisual::IsSynchronousResourceLoading() const { return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; @@ -775,12 +779,20 @@ void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& t atlasUploadObserver = this; } + auto preMultiplyOnLoad = mFactoryCache.GetPreMultiplyOnLoad() + ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD + : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + textures = textureManager.LoadTexture( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, IsSynchronousResourceLoading(), mTextureId, atlasRect, atlasing, mLoading, mWrapModeU, mWrapModeV, textureObserver, atlasUploadObserver, atlasManager, - mOrientationCorrection, - forceReload ); + mOrientationCorrection, forceReload, preMultiplyOnLoad); + + if( textures && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) + { + EnablePreMultipliedAlpha( true ); + } if( atlasing ) // Flag needs to be set before creating renderer { @@ -1073,7 +1085,7 @@ void ImageVisual::UploadCompleted() // From Texture Manager void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, TextureSet textureSet, bool usingAtlas, - const Vector4& atlasRectangle ) + const Vector4& atlasRectangle, bool preMultiplied ) { Toolkit::Visual::ResourceStatus resourceStatus; Actor actor = mPlacementActor.GetHandle(); @@ -1085,6 +1097,10 @@ void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, Textur { mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect ); } + else if( preMultiplied ) + { + EnablePreMultipliedAlpha( true ); + } actor.AddRenderer( mImpl->mRenderer ); // reset the weak handle so that the renderer only get added to actor once diff --git a/dali-toolkit/internal/visuals/image/image-visual.h b/dali-toolkit/internal/visuals/image/image-visual.h index d78ceca..1a9230c 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.h +++ b/dali-toolkit/internal/visuals/image/image-visual.h @@ -256,7 +256,7 @@ public: * 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. */ - virtual void UploadCompleted(); + virtual void UploadCompleted() override; /** * @copydoc TextureUploadObserver::UploadCompleted @@ -264,7 +264,8 @@ public: * 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. */ - virtual void UploadComplete( bool success, int32_t textureId, TextureSet textureSet, bool usingAtlas, const Vector4& atlasRectangle ); + virtual void UploadComplete( bool success, int32_t textureId, TextureSet textureSet, + bool usingAtlas, const Vector4& atlasRectangle, bool preMultiplied ) override; private: diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp index 6b31322..7f62d22 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.cpp +++ b/dali-toolkit/internal/visuals/texture-manager-impl.cpp @@ -87,6 +87,22 @@ const char * const BROKEN_IMAGE_URL( DALI_IMAGE_DIR "broken.png" ); ///< URL Fo const int INVALID_INDEX( -1 ); ///< Invalid index used to represent a non-existant TextureInfo struct const int INVALID_CACHE_INDEX( -1 ); ///< Invalid Cache index + +void PreMultiply( Devel::PixelBuffer pixelBuffer, TextureManager::MultiplyOnLoad& preMultiplyOnLoad ) +{ + if( Pixel::HasAlpha( pixelBuffer.GetPixelFormat() ) ) + { + if( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ) + { + pixelBuffer.MultiplyColorByAlpha(); + } + } + else + { + preMultiplyOnLoad = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + } +} + } // Anonymous namespace TextureManager::MaskingData::MaskingData() @@ -111,7 +127,7 @@ TextureSet TextureManager::LoadTexture( bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU, Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver, AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager, bool orientationCorrection, - TextureManager::ReloadPolicy reloadPolicy ) + TextureManager::ReloadPolicy reloadPolicy, TextureManager::MultiplyOnLoad& preMultiplyOnLoad ) { TextureSet textureSet; @@ -143,6 +159,7 @@ TextureSet TextureManager::LoadTexture( orientationCorrection ); if( pixelBuffer ) { + PreMultiply( pixelBuffer, preMultiplyOnLoad ); data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer } } @@ -153,6 +170,7 @@ TextureSet TextureManager::LoadTexture( Devel::PixelBuffer pixelBuffer = LoadImageFromFile( BROKEN_IMAGE_URL ); if( pixelBuffer ) { + PreMultiply( pixelBuffer, preMultiplyOnLoad ); data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer } Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(), @@ -191,7 +209,7 @@ TextureSet TextureManager::LoadTexture( if( !maskInfo ) { textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, - textureObserver, orientationCorrection, reloadPolicy ); + textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad ); } else { @@ -204,7 +222,7 @@ TextureSet TextureManager::LoadTexture( maskInfo->mCropToMask, textureObserver, orientationCorrection, - reloadPolicy ); + reloadPolicy, preMultiplyOnLoad ); } TextureManager::LoadState loadState = GetTextureStateInternal( textureId ); @@ -229,46 +247,51 @@ TextureSet TextureManager::LoadTexture( } TextureManager::TextureId TextureManager::RequestLoad( - const VisualUrl& url, - const ImageDimensions desiredSize, - FittingMode::Type fittingMode, - Dali::SamplingMode::Type samplingMode, - const UseAtlas useAtlas, - TextureUploadObserver* observer, - bool orientationCorrection, - TextureManager::ReloadPolicy reloadPolicy ) + const VisualUrl& url, + const ImageDimensions desiredSize, + FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode, + const UseAtlas useAtlas, + TextureUploadObserver* observer, + bool orientationCorrection, + TextureManager::ReloadPolicy reloadPolicy, + TextureManager::MultiplyOnLoad& preMultiplyOnLoad ) { return RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, - false, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy ); + false, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, + preMultiplyOnLoad ); } TextureManager::TextureId TextureManager::RequestLoad( - const VisualUrl& url, - TextureId maskTextureId, - float contentScale, - const ImageDimensions desiredSize, - FittingMode::Type fittingMode, - Dali::SamplingMode::Type samplingMode, - const UseAtlas useAtlas, - bool cropToMask, - TextureUploadObserver* observer, - bool orientationCorrection, - TextureManager::ReloadPolicy reloadPolicy ) + const VisualUrl& url, + TextureId maskTextureId, + float contentScale, + const ImageDimensions desiredSize, + FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode, + const UseAtlas useAtlas, + bool cropToMask, + TextureUploadObserver* observer, + bool orientationCorrection, + TextureManager::ReloadPolicy reloadPolicy, + TextureManager::MultiplyOnLoad& preMultiplyOnLoad ) { return RequestLoadInternal( url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, - cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy ); + cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, + preMultiplyOnLoad ); } TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl ) { // Use the normal load procedure to get the alpha 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 ); + TextureManager::ReloadPolicy::CACHED, preMultiply ); } TextureManager::TextureId TextureManager::RequestLoadInternal( - const VisualUrl& url, + const VisualUrl& url, TextureId maskTextureId, float contentScale, const ImageDimensions desiredSize, @@ -279,17 +302,18 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( StorageType storageType, TextureUploadObserver* observer, bool orientationCorrection, - TextureManager::ReloadPolicy reloadPolicy ) + TextureManager::ReloadPolicy reloadPolicy, + TextureManager::MultiplyOnLoad& preMultiplyOnLoad) { // First check if the requested Texture is cached. const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, - maskTextureId ); + maskTextureId, preMultiplyOnLoad ); TextureManager::TextureId textureId = INVALID_TEXTURE_ID; // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision. int cacheIndex = FindCachedTexture( textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, - maskTextureId ); + maskTextureId, preMultiplyOnLoad ); // Check if the requested Texture exists in the cache. if( cacheIndex != INVALID_CACHE_INDEX ) @@ -309,9 +333,11 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( { // We need a new Texture. textureId = GenerateUniqueTextureId(); + bool preMultiply = ( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ); mTextureInfoContainer.push_back( TextureInfo( textureId, maskTextureId, url.GetUrl(), desiredSize, contentScale, fittingMode, samplingMode, - false, cropToMask, useAtlas, textureHash, orientationCorrection ) ); + false, cropToMask, useAtlas, textureHash, orientationCorrection, + preMultiply ) ); cacheIndex = mTextureInfoContainer.size() - 1u; DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", @@ -364,7 +390,8 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( // The Texture has already loaded. The other observers have already been notified. // We need to send a "late" loaded notification for this observer. observer->UploadComplete( true, textureInfo.textureId, textureInfo.textureSet, - textureInfo.useAtlas, textureInfo.atlasRect ); + textureInfo.useAtlas, textureInfo.atlasRect, + textureInfo.preMultiplied ); } break; } @@ -706,14 +733,24 @@ void TextureManager::ApplyMask( pixelBuffer.ApplyMask( maskPixelBuffer, contentScale, cropToMask ); } + void TextureManager::UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo ) { if( textureInfo.useAtlas != USE_ATLAS ) { DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, " TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId ); + // If the texture doesn't have an alpha channel, can't pre-multiply it. + // Ensure that we don't change the load parameter (it's used for hashing), and instead set + // the status for use in the observer. + auto preMultiply = textureInfo.preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : + TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + PreMultiply( pixelBuffer, preMultiply ); + textureInfo.preMultiplied = (preMultiply == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ); + Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight() ); + PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer ); texture.Upload( pixelData ); if ( ! textureInfo.textureSet ) @@ -754,7 +791,8 @@ void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success ) // because new load requests can modify the mTextureInfoContainer list // (e.g. if more requests are pushed back it can cause the list to be // resized invalidating the reference to the TextureInfo ). - observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect ); + 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 @@ -810,7 +848,8 @@ TextureManager::TextureHash TextureManager::GenerateHash( const FittingMode::Type fittingMode, const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas, - TextureId maskTextureId ) + TextureId maskTextureId, + TextureManager::MultiplyOnLoad preMultiplyOnLoad) { std::string hashTarget( url ); const size_t urlLength = hashTarget.length(); @@ -844,10 +883,11 @@ TextureManager::TextureHash TextureManager::GenerateHash( if( maskTextureId != INVALID_TEXTURE_ID ) { - hashTarget.resize( urlLength + sizeof( TextureId ) ); - TextureId* hashTargetPtr = reinterpret_cast(&( hashTarget[ urlLength ] )); + auto textureIdIndex = hashTarget.length(); + hashTarget.resize( hashTarget.length() + sizeof( TextureId ) ); + unsigned char* hashTargetPtr = reinterpret_cast(&( hashTarget[ textureIdIndex ] )); - // Append the hash target to the end of the URL byte by byte: + // Append the texture id to the end of the URL byte by byte: // (to avoid SIGBUS / alignment issues) for( size_t byteIter = 0; byteIter < sizeof( TextureId ); ++byteIter ) { @@ -856,6 +896,22 @@ TextureManager::TextureHash TextureManager::GenerateHash( } } + auto premultipliedIndex = hashTarget.length(); + hashTarget.resize( premultipliedIndex + 1 ); + switch( preMultiplyOnLoad ) + { + case TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD: + { + hashTarget[ premultipliedIndex ] = 't'; + break; + } + case TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY: + { + hashTarget[ premultipliedIndex ] = 'f'; + break; + } + } + return Dali::CalculateHash( hashTarget ); } @@ -866,7 +922,8 @@ int TextureManager::FindCachedTexture( const FittingMode::Type fittingMode, const Dali::SamplingMode::Type samplingMode, const bool useAtlas, - TextureId maskTextureId) + TextureId maskTextureId, + TextureManager::MultiplyOnLoad preMultiplyOnLoad ) { // Default to an invalid ID, in case we do not find a match. int cacheIndex = INVALID_CACHE_INDEX; @@ -879,11 +936,14 @@ int TextureManager::FindCachedTexture( { // We have a match, now we check all the original parameters in case of a hash collision. TextureInfo& textureInfo( mTextureInfoContainer[i] ); + auto multiplyOnLoad = textureInfo.preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : + TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; if( ( url == textureInfo.url.GetUrl() ) && ( useAtlas == textureInfo.useAtlas ) && ( maskTextureId == textureInfo.maskTextureId ) && ( size == textureInfo.desiredSize ) && + ( preMultiplyOnLoad == multiplyOnLoad ) && ( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) || ( fittingMode == textureInfo.fittingMode && samplingMode == textureInfo.samplingMode ) ) ) @@ -919,6 +979,7 @@ void TextureManager::ObserverDestroyed( TextureUploadObserver* observer ) } } + TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureManager) : AsyncLoadingHelper(Toolkit::AsyncImageLoader::New(), textureManager, AsyncLoadingInfoContainerType()) diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.h b/dali-toolkit/internal/visuals/texture-manager-impl.h index 8d46f04..5b6a98e 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.h +++ b/dali-toolkit/internal/visuals/texture-manager-impl.h @@ -105,14 +105,23 @@ public: }; /** - * @breif Types of reloading policies - */ + * @brief Types of reloading policies + */ enum class ReloadPolicy { CACHED = 0, ///< Loads cached texture if it exists. FORCED ///< Forces reloading of texture. }; + /** + * @brief Whether to multiply alpha into color channels on load + */ + enum class MultiplyOnLoad + { + LOAD_WITHOUT_MULTIPLY = 0, ///< Don't modify the image + MULTIPLY_ON_LOAD ///< Multiply alpha into color channels on load + }; + public: struct MaskingData @@ -140,16 +149,59 @@ public: // TextureManager Main API: - TextureSet LoadTexture(const VisualUrl& url, Dali::ImageDimensions desiredSize, - Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, - const MaskingDataPointer& maskInfo, bool synchronousLoading, - TextureManager::TextureId& textureId, Vector4& textureRect, - bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU, - Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver, - AtlasUploadObserver* atlasObserver, - ImageAtlasManagerPtr imageAtlasManager, - bool orientationCorrection, - TextureManager::ReloadPolicy reloadPolicy ); + /** + * @brief Requests an image load of the given URL. + * + * The parameters are used to specify how the image is loaded. + * The observer has the UploadComplete method called when the load is ready. + * + * When the client has finished with the Texture, Remove() should be called. + * + * @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] maskInfo Mask info structure + * @param[in] synchronousLoading true if the URL should be loaded synchronously + * @param[out] textureId, The textureId of the URL + * @param[out] textureRect The rectangle within the texture atlas that this URL occupies + * @param[in,out] atlasingStatus Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still + * be loaded, and marked successful, but this will be set to false. + * If atlasing succeeds, this will be set to true. + * @param[out] loadingStatus The loading status of the texture + * @param[in] wrapModeU Horizontal Wrap mode + * @param[in] wrapModeV Vertical Wrap mode + * @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] atlasObserver This is used if the texture is atlased, and will be called instead of + * textureObserver.UploadCompleted + * @param[in] imageAtlasManager The atlas manager to use for atlasing textures + * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data + * @param[in] reloadPolicy Forces a reload of the texture even if already cached + * @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 texture set containing the image, or empty if still loading. + */ + + TextureSet LoadTexture( const VisualUrl& url, + Dali::ImageDimensions desiredSize, + Dali::FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode, + const MaskingDataPointer& maskInfo, + bool synchronousLoading, + TextureManager::TextureId& textureId, + Vector4& textureRect, + bool& atlasingStatus, + bool& loadingStatus, + Dali::WrapMode::Type wrapModeU, + Dali::WrapMode::Type wrapModeV, + TextureUploadObserver* textureObserver, + AtlasUploadObserver* atlasObserver, + ImageAtlasManagerPtr imageAtlasManager, + bool orientationCorrection, + TextureManager::ReloadPolicy reloadPolicy, + MultiplyOnLoad& preMultiplyOnLoad ); /** * @brief Requests an image load of the given URL. @@ -169,6 +221,7 @@ public: * This is called when an image load completes (or fails). * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data * @param[in] reloadPolicy Forces a reload of the texture even if already cached + * @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 A TextureId to use as a handle to reference this Texture */ TextureId RequestLoad( const VisualUrl& url, @@ -178,7 +231,8 @@ public: const UseAtlas useAtlasing, TextureUploadObserver* observer, bool orientationCorrection, - TextureManager::ReloadPolicy reloadPolicy ); + TextureManager::ReloadPolicy reloadPolicy, + MultiplyOnLoad& preMultiplyOnLoad ); /** * @brief Requests an image load of the given URL, when the texture has @@ -208,6 +262,8 @@ public: * This is called when an image load completes (or fails). * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data * @param[in] reloadPolicy Forces a reload of the texture even if already cached + * @param[in] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the + * image has no alpha channel * @return A TextureId to use as a handle to reference this Texture */ TextureId RequestLoad( const VisualUrl& url, @@ -220,7 +276,8 @@ public: bool cropToMask, TextureUploadObserver* observer, bool orientationCorrection, - TextureManager::ReloadPolicy reloadPolicy ); + TextureManager::ReloadPolicy reloadPolicy, + MultiplyOnLoad& preMultiplyOnLoad ); /** * Requests a masking image to be loaded. This mask is not uploaded to GL, @@ -302,6 +359,8 @@ private: * This is called when an image load completes (or fails). * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data * @param[in] reloadPolicy Forces a reload of the texture even if already cached + * @param[in] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if + * there is no alpha * @return A TextureId to use as a handle to reference this Texture */ TextureId RequestLoadInternal( @@ -316,7 +375,8 @@ private: StorageType storageType, TextureUploadObserver* observer, bool orientationCorrection, - TextureManager::ReloadPolicy reloadPolicy ); + TextureManager::ReloadPolicy reloadPolicy, + MultiplyOnLoad& preMultiplyOnLoad ); /** * @brief Get the current state of a texture @@ -344,7 +404,8 @@ private: bool cropToMask, UseAtlas useAtlas, TextureManager::TextureHash hash, - bool orientationCorrection ) + bool orientationCorrection, + bool preMultiplyOnLoad ) : url( url ), desiredSize( desiredSize ), useSize( desiredSize ), @@ -361,7 +422,9 @@ private: loadSynchronously( loadSynchronously ), useAtlas( useAtlas ), cropToMask( cropToMask ), - orientationCorrection( true ) + orientationCorrection( true ), + preMultiplyOnLoad( preMultiplyOnLoad ), + preMultiplied( false ) { } @@ -392,6 +455,8 @@ private: ///< This is updated to false if atlas is not used bool cropToMask:1; ///< true if the image should be cropped to the mask size. 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 }; // Structs: @@ -530,7 +595,8 @@ private: TextureHash GenerateHash( const std::string& url, const ImageDimensions size, const FittingMode::Type fittingMode, const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas, - TextureId maskTextureId ); + TextureId maskTextureId, + MultiplyOnLoad preMultiplyOnLoad); /** * @brief Looks up a cached texture by its hash. * If found, the given parameters are used to check there is no hash-collision. @@ -550,7 +616,8 @@ private: const FittingMode::Type fittingMode, const Dali::SamplingMode::Type samplingMode, const bool useAtlas, - TextureId maskTextureId ); + TextureId maskTextureId, + MultiplyOnLoad preMultiplyOnLoad); private: @@ -644,7 +711,6 @@ private: // Member Variables: RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads std::vector< ExternalTextureInfo > mExternalTextures; ///< Externally provided textures TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation - }; diff --git a/dali-toolkit/internal/visuals/texture-upload-observer.h b/dali-toolkit/internal/visuals/texture-upload-observer.h index d83a89e..a8623f0 100644 --- a/dali-toolkit/internal/visuals/texture-upload-observer.h +++ b/dali-toolkit/internal/visuals/texture-upload-observer.h @@ -61,8 +61,10 @@ public: * @param[in] textureSet The TextureSet containing the Texture * @param[in] useAtlasing True if atlasing was used (note: this may be different to what was requested) * @param[in] atlasRect If using atlasing, this is the rectangle within the atlas to use. + * @param[in] preMultiplied True if the image had pre-multiplied alpha applied */ - virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect ) = 0; + virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, + const Vector4& atlasRect, bool preMultiplied ) = 0; /** * @brief Returns the destruction signal. diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.cpp b/dali-toolkit/internal/visuals/visual-factory-cache.cpp index d9a566d..307791b 100644 --- a/dali-toolkit/internal/visuals/visual-factory-cache.cpp +++ b/dali-toolkit/internal/visuals/visual-factory-cache.cpp @@ -40,8 +40,9 @@ namespace Toolkit namespace Internal { -VisualFactoryCache::VisualFactoryCache() -: mSvgRasterizeThread( NULL ) +VisualFactoryCache::VisualFactoryCache( bool preMultiplyOnLoad ) +: mSvgRasterizeThread( NULL ), + mPreMultiplyOnLoad( preMultiplyOnLoad ) { } @@ -214,6 +215,16 @@ Image VisualFactoryCache::GetBrokenVisualImage() return ResourceImage::New( BROKEN_VISUAL_IMAGE_URL ); } +void VisualFactoryCache::SetPreMultiplyOnLoad( bool preMultiply ) +{ + mPreMultiplyOnLoad = preMultiply; +} + +bool VisualFactoryCache::GetPreMultiplyOnLoad() +{ + return mPreMultiplyOnLoad; +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.h b/dali-toolkit/internal/visuals/visual-factory-cache.h index 778a48f..bb4744c 100644 --- a/dali-toolkit/internal/visuals/visual-factory-cache.h +++ b/dali-toolkit/internal/visuals/visual-factory-cache.h @@ -47,7 +47,7 @@ typedef IntrusivePtr ImageAtlasManagerPtr; /** * Caches shaders and geometries. Owned by VisualFactory. */ -class VisualFactoryCache : public RefObject +class VisualFactoryCache { public: @@ -108,8 +108,15 @@ public: /** * @brief Constructor + * + * @param[in] preMultiplyOnLoad True if image visuals should pre-multiply alpha on image load. */ - VisualFactoryCache(); + VisualFactoryCache( bool preMultiplyOnLoad ); + + /** + * @brief Destructor + */ + ~VisualFactoryCache(); /** * Request geometry of the given type. @@ -156,6 +163,16 @@ public: */ static Image GetBrokenVisualImage(); + /** + * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad() + */ + void SetPreMultiplyOnLoad( bool preMultiply ); + + /** + * @copydoc Toolkit::VisualFactory::GetPreMultiplyOnLoad() + */ + bool GetPreMultiplyOnLoad(); + public: /** * Get the image atlas manager. @@ -191,11 +208,6 @@ private: // for svg rasterization thread protected: /** - * A reference counted object may only be deleted by calling Unreference() - */ - virtual ~VisualFactoryCache(); - - /** * Undefined copy constructor. */ VisualFactoryCache(const VisualFactoryCache&); @@ -213,6 +225,7 @@ private: TextureManager mTextureManager; NPatchLoader mNPatchLoader; SvgRasterizeThread* mSvgRasterizeThread; + bool mPreMultiplyOnLoad; }; } // namespace Internal diff --git a/dali-toolkit/internal/visuals/visual-factory-impl.cpp b/dali-toolkit/internal/visuals/visual-factory-impl.cpp index c368580..90bb937 100644 --- a/dali-toolkit/internal/visuals/visual-factory-impl.cpp +++ b/dali-toolkit/internal/visuals/visual-factory-impl.cpp @@ -71,7 +71,8 @@ DALI_TYPE_REGISTRATION_END() } // namespace VisualFactory::VisualFactory( bool debugEnabled ) -:mDebugEnabled( debugEnabled ) +: mDebugEnabled( debugEnabled ), + mPreMultiplyOnLoad( true ) { } @@ -81,12 +82,6 @@ VisualFactory::~VisualFactory() Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& propertyMap ) { - // Create factory cache if it hasn't already been - if( !mFactoryCache ) - { - mFactoryCache = new VisualFactoryCache(); - } - Visual::BasePtr visualPtr; Property::Value* typeValue = propertyMap.Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE ); @@ -100,19 +95,19 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property { case Toolkit::Visual::BORDER: { - visualPtr = BorderVisual::New( *( mFactoryCache.Get() ), propertyMap ); + visualPtr = BorderVisual::New( GetFactoryCache(), propertyMap ); break; } case Toolkit::Visual::COLOR: { - visualPtr = ColorVisual::New( *( mFactoryCache.Get() ), propertyMap ); + visualPtr = ColorVisual::New( GetFactoryCache(), propertyMap ); break; } case Toolkit::Visual::GRADIENT: { - visualPtr = GradientVisual::New( *( mFactoryCache.Get() ), propertyMap ); + visualPtr = GradientVisual::New( GetFactoryCache(), propertyMap ); break; } @@ -132,22 +127,22 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property { case VisualUrl::N_PATCH: { - visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap ); + visualPtr = NPatchVisual::New( GetFactoryCache(), visualUrl, propertyMap ); break; } case VisualUrl::SVG: { - visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap ); + visualPtr = SvgVisual::New( GetFactoryCache(), visualUrl, propertyMap ); break; } case VisualUrl::GIF: { - visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap ); + visualPtr = AnimatedImageVisual::New( GetFactoryCache(), visualUrl, propertyMap ); break; } case VisualUrl::REGULAR_IMAGE: { - visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap ); + visualPtr = ImageVisual::New( GetFactoryCache(), visualUrl, propertyMap ); break; } } @@ -158,7 +153,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property Property::Array* array = imageURLValue->GetArray(); if( array ) { - visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), *array, propertyMap ); + visualPtr = AnimatedImageVisual::New( GetFactoryCache(), *array, propertyMap ); } } } @@ -167,25 +162,25 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property case Toolkit::Visual::MESH: { - visualPtr = MeshVisual::New( *( mFactoryCache.Get() ), propertyMap ); + visualPtr = MeshVisual::New( GetFactoryCache(), propertyMap ); break; } case Toolkit::Visual::PRIMITIVE: { - visualPtr = PrimitiveVisual::New( *( mFactoryCache.Get() ), propertyMap ); + visualPtr = PrimitiveVisual::New( GetFactoryCache(), propertyMap ); break; } case Toolkit::Visual::WIREFRAME: { - visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), propertyMap ); + visualPtr = WireframeVisual::New( GetFactoryCache(), propertyMap ); break; } case Toolkit::Visual::TEXT: { - visualPtr = TextVisual::New( *( mFactoryCache.Get() ), propertyMap ); + visualPtr = TextVisual::New( GetFactoryCache(), propertyMap ); break; } @@ -195,7 +190,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property std::string imageUrl; if( imageURLValue && imageURLValue->Get( imageUrl ) ) { - visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap ); + visualPtr = NPatchVisual::New( GetFactoryCache(), imageUrl, propertyMap ); } break; } @@ -206,7 +201,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property std::string imageUrl; if( imageURLValue && imageURLValue->Get( imageUrl ) ) { - visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap ); + visualPtr = SvgVisual::New( GetFactoryCache(), imageUrl, propertyMap ); } break; } @@ -219,14 +214,14 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property { if( imageURLValue->Get( imageUrl ) ) { - visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap ); + visualPtr = AnimatedImageVisual::New( GetFactoryCache(), imageUrl, propertyMap ); } else { Property::Array* array = imageURLValue->GetArray(); if( array ) { - visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), *array, propertyMap ); + visualPtr = AnimatedImageVisual::New( GetFactoryCache(), *array, propertyMap ); } } } @@ -235,7 +230,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property case Toolkit::DevelVisual::ANIMATED_GRADIENT: { - visualPtr = AnimatedGradientVisual::New( *( mFactoryCache.Get() ), propertyMap ); + visualPtr = AnimatedGradientVisual::New( GetFactoryCache(), propertyMap ); break; } } @@ -248,7 +243,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property if( mDebugEnabled && visualType != Toolkit::DevelVisual::WIREFRAME ) { //Create a WireframeVisual if we have debug enabled - visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), visualPtr, propertyMap ); + visualPtr = WireframeVisual::New(GetFactoryCache(), visualPtr, propertyMap ); } return Toolkit::Visual::Base( visualPtr.Get() ); @@ -256,11 +251,6 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property Toolkit::Visual::Base VisualFactory::CreateVisual( const Image& image ) { - if( !mFactoryCache ) - { - mFactoryCache = new VisualFactoryCache(); - } - Visual::BasePtr visualPtr; if( image ) @@ -268,18 +258,18 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Image& image ) NinePatchImage npatchImage = NinePatchImage::DownCast( image ); if( npatchImage ) { - visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), npatchImage ); + visualPtr = NPatchVisual::New( GetFactoryCache(), npatchImage ); } else { - visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), image ); + visualPtr = ImageVisual::New(GetFactoryCache(), image ); } } if( mDebugEnabled ) { //Create a WireframeVisual if we have debug enabled - visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), visualPtr ); + visualPtr = WireframeVisual::New( GetFactoryCache(), visualPtr ); } return Toolkit::Visual::Base( visualPtr.Get() ); @@ -287,11 +277,6 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Image& image ) Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, ImageDimensions size ) { - if( !mFactoryCache ) - { - mFactoryCache = new VisualFactoryCache(); - } - Visual::BasePtr visualPtr; if( !url.empty() ) @@ -302,22 +287,22 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, Image { case VisualUrl::N_PATCH: { - visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), visualUrl ); + visualPtr = NPatchVisual::New( GetFactoryCache(), visualUrl ); break; } case VisualUrl::SVG: { - visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), visualUrl ); + visualPtr = SvgVisual::New( GetFactoryCache(), visualUrl ); break; } case VisualUrl::GIF: { - visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), visualUrl ); + visualPtr = AnimatedImageVisual::New( GetFactoryCache(), visualUrl ); break; } case VisualUrl::REGULAR_IMAGE: { - visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), visualUrl, size ); + visualPtr = ImageVisual::New(GetFactoryCache(), visualUrl, size ); break; } } @@ -326,19 +311,38 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, Image if( mDebugEnabled ) { //Create a WireframeVisual if we have debug enabled - visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), visualPtr ); + visualPtr = WireframeVisual::New( GetFactoryCache(), visualPtr ); } return Toolkit::Visual::Base( visualPtr.Get() ); } +void VisualFactory::SetPreMultiplyOnLoad( bool preMultiply ) +{ + if( mPreMultiplyOnLoad != preMultiply ) + { + GetFactoryCache().SetPreMultiplyOnLoad( preMultiply ); + } + mPreMultiplyOnLoad = preMultiply; +} + +bool VisualFactory::GetPreMultiplyOnLoad() const +{ + return mPreMultiplyOnLoad; +} + Internal::TextureManager& VisualFactory::GetTextureManager() { + return GetFactoryCache().GetTextureManager(); +} + +Internal::VisualFactoryCache& VisualFactory::GetFactoryCache() +{ if( !mFactoryCache ) { - mFactoryCache = new VisualFactoryCache(); + mFactoryCache = std::unique_ptr( new VisualFactoryCache( mPreMultiplyOnLoad ) ); } - return mFactoryCache->GetTextureManager(); + return *mFactoryCache; } } // namespace Internal diff --git a/dali-toolkit/internal/visuals/visual-factory-impl.h b/dali-toolkit/internal/visuals/visual-factory-impl.h index 257b03c..999a0c4 100644 --- a/dali-toolkit/internal/visuals/visual-factory-impl.h +++ b/dali-toolkit/internal/visuals/visual-factory-impl.h @@ -35,7 +35,6 @@ namespace Internal { class VisualFactoryCache; -typedef IntrusivePtr VisualFactoryCachePtr; /** * @copydoc Toolkit::VisualFactory @@ -52,21 +51,31 @@ public: VisualFactory( bool debugEnabled ); /** - * @copydoc Toolkit::RenderFactory::CreateVisual( const Property::Map& ) + * @copydoc Toolkit::VisualFactory::CreateVisual( const Property::Map& ) */ Toolkit::Visual::Base CreateVisual( const Property::Map& propertyMap ); /** - * @copydoc Toolkit::RenderFactory::CreateVisual( const Image& ) + * @copydoc Toolkit::VisualFactory::CreateVisual( const Image& ) */ Toolkit::Visual::Base CreateVisual( const Image& image ); /** - * @copydoc Toolkit::RenderFactory::CreateVisual( const std::string&, ImageDimensions ) + * @copydoc Toolkit::VisualFactory::CreateVisual( const std::string&, ImageDimensions ) */ Toolkit::Visual::Base CreateVisual( const std::string& image, ImageDimensions size ); /** + * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad() + */ + void SetPreMultiplyOnLoad( bool preMultiply ); + + /** + * @copydoc Toolkit::VisualFactory::GetPreMultiplyOnLoad() + */ + bool GetPreMultiplyOnLoad() const; + + /** * @return the reference to texture manager */ Internal::TextureManager& GetTextureManager(); @@ -79,21 +88,19 @@ protected: virtual ~VisualFactory(); private: - /** - * Undefined copy constructor. + * Get the factory cache, creating it if necessary. */ - VisualFactory(const VisualFactory&); + Internal::VisualFactoryCache& GetFactoryCache(); - /** - * Undefined assignment operator. - */ - VisualFactory& operator=(const VisualFactory& rhs); + VisualFactory(const VisualFactory&) = delete; -private: + VisualFactory& operator=(const VisualFactory& rhs) = delete; - VisualFactoryCachePtr mFactoryCache; - bool mDebugEnabled; +private: + std::unique_ptr mFactoryCache; + bool mDebugEnabled:1; + bool mPreMultiplyOnLoad:1; ///< Local store for this flag }; /**