From bb0b70627855200b8830ccab2ff45b226a4135bf Mon Sep 17 00:00:00 2001 From: seungho Date: Mon, 16 May 2022 15:09:59 +0900 Subject: [PATCH] GPU Alpha Masking for Animated Image Visual Change-Id: I7d0f44a73063a16d1e57acf40739c58239487c43 Signed-off-by: seungho --- .../dali-toolkit/utc-Dali-AnimatedImageVisual.cpp | 175 ++++++++++++++++++++- .../visuals/image-visual-properties-devel.h | 22 ++- .../graphics/shaders/image-visual-shader.frag | 15 ++ .../graphics/shaders/image-visual-shader.vert | 21 ++- .../texture-manager/texture-cache-manager.cpp | 2 + .../texture-manager/texture-cache-manager.h | 2 + .../texture-manager/texture-manager-impl.cpp | 114 +++++++++++--- .../texture-manager/texture-manager-impl.h | 4 + .../texture-manager/texture-manager-type.h | 1 + .../animated-image/animated-image-visual.cpp | 69 +++++++- .../visuals/animated-image/animated-image-visual.h | 6 + .../visuals/image-visual-shader-factory.cpp | 69 +++++--- .../internal/visuals/image-visual-shader-factory.h | 29 +++- .../internal/visuals/visual-factory-cache.h | 8 + .../internal/visuals/visual-string-constants.cpp | 1 + .../internal/visuals/visual-string-constants.h | 1 + 16 files changed, 480 insertions(+), 59 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp index b6b45a6..80836e3 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp @@ -82,6 +82,7 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void) .Add(ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME) .Add(ImageVisual::Property::MASK_CONTENT_SCALE, 1.6f) .Add(ImageVisual::Property::CROP_TO_MASK, true) + .Add(DevelImageVisual::Property::MASKING_TYPE, DevelImageVisual::MaskingType::MASKING_ON_RENDERING) .Add(DevelVisual::Property::CORNER_RADIUS, 22.2f) .Add(DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::ABSOLUTE) .Add(DevelVisual::Property::BORDERLINE_WIDTH, 33.3f) @@ -132,6 +133,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void) DALI_TEST_CHECK(value); DALI_TEST_EQUALS(value->Get(), true, TEST_LOCATION); + value = resultMap.Find(DevelImageVisual::Property::MASKING_TYPE, Property::INTEGER); + DALI_TEST_CHECK(value); + DALI_TEST_CHECK(value->Get() == DevelImageVisual::MaskingType::MASKING_ON_RENDERING); + Vector2 naturalSize; animatedImageVisual.GetNaturalSize(naturalSize); DALI_TEST_EQUALS(naturalSize, Vector2(100, 100), TEST_LOCATION); @@ -176,6 +181,7 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void) .Add("alphaMaskUrl", TEST_MASK_IMAGE_FILE_NAME) .Add("maskContentScale", 1.6f) .Add("cropToMask", true) + .Add(DevelImageVisual::Property::MASKING_TYPE, DevelImageVisual::MaskingType::MASKING_ON_RENDERING) .Add("cornerRadius", Vector4(50.0f, 25.0f, 12.5f, 33.0f)) .Add("cornerRadiusPolicy", Visual::Transform::Policy::RELATIVE) .Add("borderlineWidth", 20.0f) @@ -248,6 +254,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void) DALI_TEST_CHECK(value); DALI_TEST_EQUALS(value->Get(), true, TEST_LOCATION); + value = resultMap.Find(DevelImageVisual::Property::MASKING_TYPE, Property::INTEGER); + DALI_TEST_CHECK(value); + DALI_TEST_CHECK(value->Get() == DevelImageVisual::MaskingType::MASKING_ON_RENDERING); + END_TEST; } @@ -275,6 +285,7 @@ int UtcDaliAnimatedImageVisualGetPropertyMap03(void) .Add("alphaMaskUrl", TEST_MASK_IMAGE_FILE_NAME) .Add("maskContentScale", 1.6f) .Add("cropToMask", true) + .Add(DevelImageVisual::Property::MASKING_TYPE, DevelImageVisual::MaskingType::MASKING_ON_RENDERING) .Add("cornerRadius", 50.5f)); Property::Map resultMap; @@ -343,6 +354,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap03(void) DALI_TEST_CHECK(value); DALI_TEST_EQUALS(value->Get(), true, TEST_LOCATION); + value = resultMap.Find(DevelImageVisual::Property::MASKING_TYPE, Property::INTEGER); + DALI_TEST_CHECK(value); + DALI_TEST_CHECK(value->Get() == DevelImageVisual::MaskingType::MASKING_ON_RENDERING); + END_TEST; } @@ -525,10 +540,11 @@ int UtcDaliAnimatedImageVisualSynchronousLoading(void) END_TEST; } -int UtcDaliAnimatedImageVisualSynchronousLoadingWithAlphaMask(void) +int UtcDaliAnimatedImageVisualSynchronousLoadingWithAlphaMask01(void) { ToolkitTestApplication application; - TestGlAbstraction& gl = application.GetGlAbstraction(); + tet_infoline("UtcDaliAnimatedImageVisualSynchronousLoadingWithAlphaMask01 for CPU Alpha Masking"); + TestGlAbstraction& gl = application.GetGlAbstraction(); { Property::Map propertyMap; @@ -581,6 +597,64 @@ int UtcDaliAnimatedImageVisualSynchronousLoadingWithAlphaMask(void) END_TEST; } +int UtcDaliAnimatedImageVisualSynchronousLoadingWithAlphaMask02(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliAnimatedImageVisualSynchronousLoadingWithAlphaMask02 for GPU Alpha Masking"); + TestGlAbstraction& gl = application.GetGlAbstraction(); + + { + Property::Map propertyMap; + propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, TEST_GIF_FILE_NAME); + propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 2); + propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 2); + propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 20); + propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true); + propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME); + propertyMap.Insert(DevelImageVisual::Property::MASKING_TYPE, DevelImageVisual::MaskingType::MASKING_ON_RENDERING); + propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, 0.23f); + propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::ABSOLUTE); + + VisualFactory factory = VisualFactory::Get(); + Visual::Base visual = factory.CreateVisual(propertyMap); + + Property::Map testMap; + visual.CreatePropertyMap(testMap); + DALI_TEST_EQUALS(*testMap.Find(ImageVisual::Property::ALPHA_MASK_URL), Property::Value(TEST_MASK_IMAGE_FILE_NAME), TEST_LOCATION); + + DummyControl dummyControl = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual); + + dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); + application.GetScene().Add(dummyControl); + + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + application.SendNotification(); + application.Render(20); + + // The first frame is loaded synchronously and load next batch with masking + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::GetTimerCount(), 1, TEST_LOCATION); + DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 4, TEST_LOCATION); + + dummyControl.Unparent(); + } + tet_infoline("Test that removing the visual from stage deletes all textures"); + application.SendNotification(); + application.Render(16); + DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION); + + END_TEST; +} + int UtcDaliAnimatedImageVisualJumpToAction(void) { ToolkitTestApplication application; @@ -894,7 +968,8 @@ int UtcDaliAnimatedImageVisualAnimatedImage01(void) int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask01(void) { ToolkitTestApplication application; - TestGlAbstraction& gl = application.GetGlAbstraction(); + tet_infoline("UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask01 for CPU Alpha Masking"); + TestGlAbstraction& gl = application.GetGlAbstraction(); { Property::Map propertyMap; @@ -936,6 +1011,100 @@ int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask01(void) END_TEST; } +int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask02(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask02 for GPU Alpha Masking"); + TestGlAbstraction& gl = application.GetGlAbstraction(); + + { + Property::Map propertyMap; + propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, TEST_GIF_FILE_NAME); + propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 2); + propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 4); + propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 20); + propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME); + propertyMap.Insert(DevelImageVisual::Property::MASKING_TYPE, DevelImageVisual::MaskingType::MASKING_ON_RENDERING); + + VisualFactory factory = VisualFactory::Get(); + Visual::Base visual = factory.CreateVisual(propertyMap); + + DummyControl dummyControl = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual); + + dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); + application.GetScene().Add(dummyControl); + + application.SendNotification(); + application.Render(); + + // load two frame(batch size), load mask image, and request two masking + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION); + + application.SendNotification(); + application.Render(20); + + DALI_TEST_EQUALS(gl.GetLastGenTextureId(), 3, TEST_LOCATION); + + dummyControl.Unparent(); + } + tet_infoline("Test that removing the visual from stage deletes all textures"); + application.SendNotification(); + application.Render(20); + DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask03(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliAnimatedImageVisualAnimatedImageWithAlphaMask03 for GPU Alpha Masking with broken mask texture"); + TestGlAbstraction& gl = application.GetGlAbstraction(); + + { + Property::Map propertyMap; + propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, TEST_GIF_FILE_NAME); + propertyMap.Insert(ImageVisual::Property::BATCH_SIZE, 2); + propertyMap.Insert(ImageVisual::Property::CACHE_SIZE, 4); + propertyMap.Insert(ImageVisual::Property::FRAME_DELAY, 20); + propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, ""); + propertyMap.Insert(DevelImageVisual::Property::MASKING_TYPE, DevelImageVisual::MaskingType::MASKING_ON_RENDERING); + + VisualFactory factory = VisualFactory::Get(); + Visual::Base visual = factory.CreateVisual(propertyMap); + + DummyControl dummyControl = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual); + + dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); + application.GetScene().Add(dummyControl); + + application.SendNotification(); + application.Render(); + + // load two frame(batch size), load mask image, and request two masking + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION); + + application.SendNotification(); + application.Render(20); + + DALI_TEST_EQUALS(gl.GetLastGenTextureId(), 3, TEST_LOCATION); + + dummyControl.Unparent(); + } + tet_infoline("Test that removing the visual from stage deletes all textures"); + application.SendNotification(); + application.Render(20); + DALI_TEST_EQUALS(gl.GetNumGeneratedTextures(), 0, TEST_LOCATION); + + END_TEST; +} + int UtcDaliAnimatedImageVisualMultiImage01(void) { ToolkitTestApplication application; diff --git a/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h index 413b556..7deaf7a 100644 --- a/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h +++ b/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h @@ -145,7 +145,14 @@ enum Type * @details Name "redrawInScalingDown", type Property::BOOLEAN. * @note It is used in the AnimatedVectorImageVisual. The default is true. */ - REDRAW_IN_SCALING_DOWN + REDRAW_IN_SCALING_DOWN = ORIENTATION_CORRECTION + 11, + + /** + * @brief Whether to apply mask in loading time or rendering time. + * @details Name "maskingType", type PlayState::Type (Property::INTEGER). + * @note It is used in the ImageVisual and AnimatedImageVisual. The default is MASKING_ON_LOADING. + */ + MASKING_TYPE = ORIENTATION_CORRECTION + 12 }; } //namespace Property @@ -191,6 +198,19 @@ enum Type } // namespace LoopingMode +/** + * @brief Enumeration for what masking type is in. + */ +namespace MaskingType +{ +enum Type +{ + MASKING_ON_RENDERING, ///< Alpha masking is applied for each rendering time. (On GPU) + MASKING_ON_LOADING ///< Alpha masking is applied when the image is loading. (On CPU) +}; + +} + } // namespace DevelImageVisual } // namespace Toolkit diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag index 703c649..c2324e7 100644 --- a/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag +++ b/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag @@ -4,6 +4,9 @@ #ifndef IS_REQUIRED_BORDERLINE #define IS_REQUIRED_BORDERLINE 0 #endif +#ifndef IS_REQUIRED_ALPHA_MASKING +#define IS_REQUIRED_ALPHA_MASKING 0 +#endif #ifndef ATLAS_DEFAULT_WARP #define ATLAS_DEFAULT_WARP 0 #endif @@ -22,6 +25,12 @@ INPUT mediump vec4 vCornerRadius; #endif uniform sampler2D sTexture; + +#if IS_REQUIRED_ALPHA_MASKING +uniform sampler2D sMaskTexture; +INPUT mediump vec2 vMaskTexCoord; +#endif + #if ATLAS_DEFAULT_WARP uniform mediump vec4 uAtlasRect; #elif ATLAS_CUSTOM_WARP @@ -228,6 +237,12 @@ void main() lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * vec4( mixColor, 1.0 ) * uColor; +#if IS_REQUIRED_ALPHA_MASKING + mediump float maskAlpha = TEXTURE(sMaskTexture, vMaskTexCoord).a; + textureColor.a *= maskAlpha; + textureColor.rgb *= mix(1.0, maskAlpha, preMultipliedAlpha); +#endif + #if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE // skip most potential calculate for performance if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y) diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-shader.vert b/dali-toolkit/internal/graphics/shaders/image-visual-shader.vert index 21d4084..d563c78 100644 --- a/dali-toolkit/internal/graphics/shaders/image-visual-shader.vert +++ b/dali-toolkit/internal/graphics/shaders/image-visual-shader.vert @@ -4,6 +4,9 @@ #ifndef IS_REQUIRED_BORDERLINE #define IS_REQUIRED_BORDERLINE 0 #endif +#ifndef IS_REQUIRED_ALPHA_MASKING +#define IS_REQUIRED_ALPHA_MASKING 0 +#endif INPUT mediump vec2 aPosition; OUTPUT mediump vec2 vTexCoord; @@ -34,6 +37,11 @@ uniform mediump float borderlineOffset; uniform mediump vec4 cornerRadius; uniform mediump float cornerRadiusPolicy; #endif +#if IS_REQUIRED_ALPHA_MASKING +OUTPUT mediump vec2 vMaskTexCoord; +uniform lowp float cropToMask; +uniform mediump vec2 maskTextureRatio; +#endif uniform mediump vec2 extraSize; vec4 ComputeVertexPosition() @@ -68,7 +76,18 @@ vec4 ComputeVertexPosition() mediump vec2 vPosition = aPosition * visualSize; #endif - vTexCoord = pixelArea.xy + pixelArea.zw * (vPosition.xy / max(vec2(1.0), visualSize) + vec2(0.5)); + vec4 finalPixelArea = pixelArea; +#if IS_REQUIRED_ALPHA_MASKING + finalPixelArea = mix(pixelArea, + vec4( + vec2(0.5) + (pixelArea.xy - vec2(0.5)) * maskTextureRatio, + pixelArea.zw * maskTextureRatio + ), + cropToMask); + vMaskTexCoord = pixelArea.xy + pixelArea.zw * (vPosition.xy / max(vec2(1.0), visualSize) + vec2(0.5)); +#endif + vTexCoord = finalPixelArea.xy + finalPixelArea.zw * (vPosition.xy / max(vec2(1.0), visualSize) + vec2(0.5)); + return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0); } diff --git a/dali-toolkit/internal/texture-manager/texture-cache-manager.cpp b/dali-toolkit/internal/texture-manager/texture-cache-manager.cpp index 85d2e87..24a8ea2 100644 --- a/dali-toolkit/internal/texture-manager/texture-cache-manager.cpp +++ b/dali-toolkit/internal/texture-manager/texture-cache-manager.cpp @@ -569,6 +569,7 @@ TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedTexture( const Dali::FittingMode::Type& fittingMode, const Dali::SamplingMode::Type& samplingMode, const TextureCacheManager::UseAtlas& useAtlas, + const StorageType& storageType, const TextureCacheManager::TextureId& maskTextureId, const bool& cropToMask, const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad, @@ -593,6 +594,7 @@ TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedTexture( (cropToMask == textureInfo.cropToMask) && (size == textureInfo.desiredSize) && (isAnimatedImage == textureInfo.isAnimatedImageFormat) && + (storageType == textureInfo.storageType) && (frameIndex == textureInfo.frameIndex) && ((size.GetWidth() == 0 && size.GetHeight() == 0) || (fittingMode == textureInfo.fittingMode && diff --git a/dali-toolkit/internal/texture-manager/texture-cache-manager.h b/dali-toolkit/internal/texture-manager/texture-cache-manager.h index ac70426..fb7dfd7 100644 --- a/dali-toolkit/internal/texture-manager/texture-cache-manager.h +++ b/dali-toolkit/internal/texture-manager/texture-cache-manager.h @@ -230,6 +230,7 @@ public: * @param[in] fittingMode The FittingMode to use * @param[in] samplingMode The SamplingMode to use * @param[in] useAtlas True if atlased + * @param[in] storageType Whether the pixel data is stored in the cache or uploaded to the GPU * @param[in] maskTextureId Optional texture ID to use to mask this image * @param[in] cropToMask True if crop to mask * @param[in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha. @@ -244,6 +245,7 @@ public: const Dali::FittingMode::Type& fittingMode, const Dali::SamplingMode::Type& samplingMode, const TextureCacheManager::UseAtlas& useAtlas, + const StorageType& storageType, const TextureCacheManager::TextureId& maskTextureId, const bool& cropToMask, const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad, diff --git a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp index 20aedab..cac3b47 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp @@ -113,14 +113,18 @@ TextureManager::MaskingData::MaskingData() : mAlphaMaskUrl(), mAlphaMaskId(INVALID_TEXTURE_ID), mContentScaleFactor(1.0f), - mCropToMask(true) + mCropToMask(true), + mPreappliedMasking(true), + mMaskImageLoadingFailed(false) { } TextureManager::TextureManager() : mTextureCacheManager(), - mAsyncLocalLoaders(GetNumberOfLocalLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }), - mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }), + mAsyncLocalLoaders(GetNumberOfLocalLoaderThreads(), [&]() + { return TextureAsyncLoadingHelper(*this); }), + mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() + { return TextureAsyncLoadingHelper(*this); }), mLifecycleObservers(), mLoadQueue(), mRemoveQueue(), @@ -166,12 +170,22 @@ TextureSet TextureManager::LoadAnimatedImageTexture( } else { + Texture maskTexture; if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) { Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true); if(maskPixelBuffer) { - pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask); + if(!maskInfo->mPreappliedMasking) + { + PixelData maskPixelData = Devel::PixelBuffer::Convert(maskPixelBuffer); // takes ownership of buffer + maskTexture = Texture::New(Dali::TextureType::TEXTURE_2D, maskPixelData.GetPixelFormat(), maskPixelData.GetWidth(), maskPixelData.GetHeight()); + maskTexture.Upload(maskPixelData); + } + else + { + pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask); + } } else { @@ -191,6 +205,10 @@ TextureSet TextureManager::LoadAnimatedImageTexture( texture.Upload(pixelData); textureSet = TextureSet::New(); textureSet.SetTexture(0u, texture); + if(maskTexture) + { + textureSet.SetTexture(1u, maskTexture); + } } } } @@ -201,13 +219,16 @@ TextureSet TextureManager::LoadAnimatedImageTexture( bool cropToMask = false; if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) { - maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl); + maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? StorageType::KEEP_PIXEL_BUFFER : StorageType::KEEP_TEXTURE); alphaMaskId = maskInfo->mAlphaMaskId; - contentScaleFactor = maskInfo->mContentScaleFactor; - cropToMask = maskInfo->mCropToMask; + if(maskInfo->mPreappliedMasking) + { + contentScaleFactor = maskInfo->mContentScaleFactor; + cropToMask = maskInfo->mCropToMask; + } } - textureId = RequestLoadInternal(url, alphaMaskId, contentScaleFactor, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, UseAtlas::NO_ATLAS, cropToMask, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad, animatedImageLoading, frameIndex, false); + textureId = RequestLoadInternal(url, alphaMaskId, contentScaleFactor, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, UseAtlas::NO_ATLAS, cropToMask, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad, animatedImageLoading, frameIndex, false); TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId); if(loadState == TextureManager::LoadState::UPLOADED) @@ -397,7 +418,7 @@ TextureSet TextureManager::LoadTexture( } else { - maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, synchronousLoading); + maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? StorageType::KEEP_PIXEL_BUFFER : StorageType::KEEP_TEXTURE, synchronousLoading); textureId = RequestLoad( url, maskInfo->mAlphaMaskId, @@ -487,11 +508,12 @@ TextureManager::TextureId TextureManager::RequestLoad( TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl, + StorageType storageType, const bool& synchronousLoading) { // 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, UseAtlas::NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading); + return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, UseAtlas::NO_ATLAS, false, storageType, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, synchronousLoading); } TextureManager::TextureId TextureManager::RequestLoadInternal( @@ -519,7 +541,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( textureHash = mTextureCacheManager.GenerateHash(url, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask, frameIndex); // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision. - cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask, preMultiplyOnLoad, (animatedImageLoading) ? true : false, frameIndex); + cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url, desiredSize, fittingMode, samplingMode, useAtlas, storageType, maskTextureId, cropToMask, preMultiplyOnLoad, (animatedImageLoading) ? true : false, frameIndex); } TextureManager::TextureId textureId = INVALID_TEXTURE_ID; @@ -928,10 +950,31 @@ void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, Devel::P { textureInfo.loadState = LoadState::WAITING_FOR_MASK; } - else if(maskLoadState == LoadState::LOAD_FINISHED) + else if(maskLoadState == LoadState::LOAD_FINISHED || maskLoadState == LoadState::UPLOADED) { // Send New Task to Thread - ApplyMask(textureInfo, textureInfo.maskTextureId); + TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureInfo.maskTextureId); + if(maskCacheIndex != INVALID_CACHE_INDEX) + { + TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]); + if(maskTextureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER) + { + // Send New Task to Thread + ApplyMask(textureInfo, textureInfo.maskTextureId); + } + else if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE) + { + // Upload image texture. textureInfo.loadState will be UPLOADED. + UploadTexture(textureInfo.pixelBuffer, textureInfo); + if(maskTextureInfo.textureSet.GetTextureCount() > 0u) + { + Texture maskTexture = maskTextureInfo.textureSet.GetTexture(0u); + textureInfo.textureSet.SetTexture(1u, maskTexture); + } + // notify mask texture set. + NotifyObservers(textureInfo, true); + } + } } else // maskLoadState == LoadState::LOAD_FAILED { @@ -957,7 +1000,7 @@ void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, Devel::P { NotifyObservers(textureInfo, true); } - else + else // for the StorageType::KEEP_PIXEL_BUFFER and StorageType::KEEP_TEXTURE { // 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) @@ -968,27 +1011,32 @@ void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, Devel::P else { textureInfo.loadState = LoadState::LOAD_FAILED; - if(textureInfo.storageType != StorageType::KEEP_PIXEL_BUFFER) - { - NotifyObservers(textureInfo, false); - } - else // if(textureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER) // image mask case + if(textureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER || textureInfo.storageType == StorageType::KEEP_TEXTURE) { // 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); } + else + { + NotifyObservers(textureInfo, false); + } } } void TextureManager::CheckForWaitingTexture(TextureManager::TextureInfo& maskTextureInfo) { + if(maskTextureInfo.loadState == LoadState::LOAD_FINISHED && + maskTextureInfo.storageType == StorageType::KEEP_TEXTURE) + { + // Upload mask texture. textureInfo.loadState will be UPLOADED. + UploadTexture(maskTextureInfo.pixelBuffer, maskTextureInfo); + } + // Search the cache, checking if any texture has this texture id as a // maskTextureId: const std::size_t size = mTextureCacheManager.size(); - const bool maskLoadSuccess = maskTextureInfo.loadState == LoadState::LOAD_FINISHED ? true : false; - // TODO : Refactorize here to not iterate whole cached image. for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index) { @@ -997,10 +1045,28 @@ void TextureManager::CheckForWaitingTexture(TextureManager::TextureInfo& maskTex { TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]); - if(maskLoadSuccess) + if(maskTextureInfo.loadState == LoadState::LOAD_FINISHED) + { + if(maskTextureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER) + { + // Send New Task to Thread + ApplyMask(textureInfo, maskTextureInfo.textureId); + } + } + else if(maskTextureInfo.loadState == LoadState::UPLOADED) { - // Send New Task to Thread - ApplyMask(textureInfo, maskTextureInfo.textureId); + if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE) + { + // Upload image texture. textureInfo.loadState will be UPLOADED. + UploadTexture(textureInfo.pixelBuffer, textureInfo); + if(maskTextureInfo.textureSet.GetTextureCount() > 0u) + { + Texture maskTexture = maskTextureInfo.textureSet.GetTexture(0u); + textureInfo.textureSet.SetTexture(1u, maskTexture); + } + // notify mask texture set. + NotifyObservers(textureInfo, true); + } } else { diff --git a/dali-toolkit/internal/texture-manager/texture-manager-impl.h b/dali-toolkit/internal/texture-manager/texture-manager-impl.h index dcd065c..4248904 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.h +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.h @@ -80,6 +80,8 @@ public: TextureManager::TextureId mAlphaMaskId; float mContentScaleFactor; bool mCropToMask; + bool mPreappliedMasking; + bool mMaskImageLoadingFailed; }; using MaskingDataPointer = std::unique_ptr; @@ -416,12 +418,14 @@ public: // Load Request API * @brief Requests a masking image to be loaded. This mask is not uploaded to GL, * instead, it is stored in CPU memory, and can be used for CPU blending. * @param[in] maskUrl The URL of the mask image to load + * @param[in] storageType, Whether the pixel data is stored in the cache or uploaded to the GPU * @param[in] synchronousLoading True if the frame should be loaded synchronously. If you skip this parameter, * default is false. * @return A TextureId to use as a handle to reference this mask Texture */ TextureId RequestMaskLoad( const VisualUrl& maskUrl, + StorageType storageType, const bool& synchronousLoading = false); private: diff --git a/dali-toolkit/internal/texture-manager/texture-manager-type.h b/dali-toolkit/internal/texture-manager/texture-manager-type.h index 366e7cb..567d876 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-type.h +++ b/dali-toolkit/internal/texture-manager/texture-manager-type.h @@ -175,6 +175,7 @@ enum class StorageType KEEP_PIXEL_BUFFER, ///< Keep loaded pixel buffer inside of texture manager without making texture. This could be used for inside pixel process like mask image. RETURN_PIXEL_BUFFER, ///< Return loaded pixel buffer without making texture. /// Because a pixel buffer cannot be used multiple texture, this pixel buffer only cached during loading, and is removed after loading is finished. + KEEP_TEXTURE, ///< Keep loaded texture inside of texture manager. This could be used for pixel processing like GPU masking. UPLOAD_TO_TEXTURE ///< Loaded image will be uploaded to texture and the texture will be returned. }; diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp index 2b4a3d0..72f44cf 100644 --- a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp @@ -46,7 +46,7 @@ namespace Internal { namespace { -const int CUSTOM_PROPERTY_COUNT(3); // ltr, wrap, pixel area, +const int CUSTOM_PROPERTY_COUNT(10); // ltr, wrap, pixel area, crop to mask, mask texture ratio + border/corner // stop behavior DALI_ENUM_TO_STRING_TABLE_BEGIN(STOP_BEHAVIOR) @@ -83,6 +83,9 @@ static constexpr Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f); static constexpr auto LOOP_FOREVER = -1; static constexpr auto FIRST_LOOP = 0u; +const char* const MASK_TEXTURE_RATIO_NAME("maskTextureRatio"); +constexpr uint32_t TEXTURE_COUNT_FOR_GPU_ALPHA_MASK = 2u; + #if defined(DEBUG_ENABLED) Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE"); #endif @@ -317,6 +320,7 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const map.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl()); map.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor); map.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask); + map.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, mMaskingData->mPreappliedMasking ? DevelImageVisual::MaskingType::MASKING_ON_LOADING : DevelImageVisual::MaskingType::MASKING_ON_RENDERING); } map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy); @@ -446,6 +450,10 @@ void AnimatedImageVisual::DoSetProperties(const Property::Map& propertyMap) { DoSetProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second); } + else if(keyValue.first == MASKING_TYPE_NAME) + { + DoSetProperty(Toolkit::DevelImageVisual::Property::MASKING_TYPE, keyValue.second); + } else if(keyValue.first == LOAD_POLICY_NAME) { DoSetProperty(Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second); @@ -620,6 +628,17 @@ void AnimatedImageVisual::DoSetProperty(Property::Index index, break; } + case Toolkit::DevelImageVisual::Property::MASKING_TYPE: + { + int maskingType = 0; + if(value.Get(maskingType)) + { + AllocateMaskData(); + mMaskingData->mPreappliedMasking = Toolkit::DevelImageVisual::MaskingType::Type(maskingType) == Toolkit::DevelImageVisual::MaskingType::MASKING_ON_LOADING ? true : false; + } + break; + } + case Toolkit::ImageVisual::Property::RELEASE_POLICY: { int releasePolicy = 0; @@ -690,14 +709,16 @@ void AnimatedImageVisual::UpdateShader() Shader AnimatedImageVisual::GenerateShader() const { - bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE; + bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE; + bool requiredAlphaMaskingOnRendering = (mMaskingData && !mMaskingData->mMaskImageLoadingFailed) ? !mMaskingData->mPreappliedMasking : false; Shader shader; shader = mImageVisualShaderFactory.GetShader( mFactoryCache, ImageVisualShaderFeature::FeatureBuilder() .ApplyDefaultTextureWrapMode(defaultWrapMode) .EnableRoundedCorner(IsRoundedCornerRequired()) - .EnableBorderline(IsBorderlineRequired())); + .EnableBorderline(IsBorderlineRequired()) + .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering)); return shader; } @@ -728,6 +749,11 @@ void AnimatedImageVisual::OnInitialize() mImpl->mRenderer.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, mPixelArea); } + if(mMaskingData) + { + mImpl->mRenderer.RegisterProperty(CROP_TO_MASK_NAME, static_cast(mMaskingData->mCropToMask)); + } + // Enable PreMultipliedAlpha if it need premultiplied auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD @@ -743,6 +769,7 @@ void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t first if(mImpl->mRenderer) { mImpl->mRenderer.SetTextures(textureSet); + CheckMaskTexture(); Actor actor = mPlacementActor.GetHandle(); if(actor) @@ -793,6 +820,22 @@ void AnimatedImageVisual::SetImageSize(TextureSet& textureSet) mImageSize.SetWidth(texture.GetWidth()); mImageSize.SetHeight(texture.GetHeight()); } + + if(textureSet.GetTextureCount() > 1u && mMaskingData && mMaskingData->mCropToMask) + { + Texture maskTexture = textureSet.GetTexture(1); + if(maskTexture) + { + mImageSize.SetWidth(std::min(static_cast(mImageSize.GetWidth() * mMaskingData->mContentScaleFactor), maskTexture.GetWidth())); + mImageSize.SetHeight(std::min(static_cast(mImageSize.GetHeight() * mMaskingData->mContentScaleFactor), maskTexture.GetHeight())); + + float textureWidth = std::max(static_cast(texture.GetWidth() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1); + float textureHeight = std::max(static_cast(texture.GetHeight() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1); + Vector2 textureRatio(std::min(static_cast(maskTexture.GetWidth()), textureWidth) / textureWidth, + std::min(static_cast(maskTexture.GetHeight()), textureHeight) / textureHeight); + mImpl->mRenderer.RegisterProperty(MASK_TEXTURE_RATIO_NAME, textureRatio); + } + } } } @@ -819,6 +862,7 @@ void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval) mFrameDelayTimer.SetInterval(interval); } mImpl->mRenderer.SetTextures(textureSet); + CheckMaskTexture(); } } } @@ -887,6 +931,7 @@ bool AnimatedImageVisual::DisplayNextFrame() if(mImpl->mRenderer) { mImpl->mRenderer.SetTextures(textureSet); + CheckMaskTexture(); } mFrameDelayTimer.SetInterval(mImageCache->GetFrameInterval(frameIndex)); } @@ -931,6 +976,24 @@ void AnimatedImageVisual::AllocateMaskData() } } +void AnimatedImageVisual::CheckMaskTexture() +{ + if(mMaskingData && !mMaskingData->mPreappliedMasking) + { + bool maskLoadFailed = true; + TextureSet textures = mImpl->mRenderer.GetTextures(); + if(textures && textures.GetTextureCount() >= TEXTURE_COUNT_FOR_GPU_ALPHA_MASK) + { + maskLoadFailed = false; + } + if(mMaskingData->mMaskImageLoadingFailed != maskLoadFailed) + { + mMaskingData->mMaskImageLoadingFailed = maskLoadFailed; + UpdateShader(); + } + } +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h index 4acb736..8fc0f59 100644 --- a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h @@ -247,6 +247,12 @@ private: */ void AllocateMaskData(); + /** + * @brief Check whether the mask texture is loaded or not. + * If MaskingType is MASKING_ON_LOADING and mask texture is failed to load, update shader. + */ + void CheckMaskTexture(); + // Undefined AnimatedImageVisual(const AnimatedImageVisual& animatedImageVisual); diff --git a/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp b/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp index f5753fa..16ba9ca 100644 --- a/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp +++ b/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp @@ -43,6 +43,28 @@ static std::string gFragmentShaderNoAtlas; const int NATIVE_SHADER_TYPE_OFFSET = VisualFactoryCache::ShaderType::NATIVE_IMAGE_SHADER - VisualFactoryCache::ShaderType::IMAGE_SHADER; +// enum of required list when we select shader +enum class ImageVisualRequireFlag : uint32_t +{ + DEFAULT = 0, + ROUNDED_CORNER = 1 << 0, + BORDERLINE = 1 << 1, + ALPHA_MASKING = 1 << 2, +}; + +static constexpr auto SHADER_TYPE_COUNT = 8u; +VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[SHADER_TYPE_COUNT] = +{ + VisualFactoryCache::IMAGE_SHADER, + VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER, + VisualFactoryCache::IMAGE_SHADER_BORDERLINE, + VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE, + VisualFactoryCache::IMAGE_SHADER_MASKING, + VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_MASKING, + VisualFactoryCache::IMAGE_SHADER_BORDERLINE_MASKING, + VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING +}; + } // unnamed namespace namespace ImageVisualShaderFeature @@ -72,6 +94,11 @@ FeatureBuilder& FeatureBuilder::SetTextureForFragmentShaderCheck(const Dali::Tex mTexture = texture; return *this; } +FeatureBuilder& FeatureBuilder::EnableAlphaMaskingOnRendering(bool enableAlphaMaskingOnRendering) +{ + mAlphaMaskingOnRendering = (enableAlphaMaskingOnRendering ? AlphaMaskingOnRendering::ENABLED : AlphaMaskingOnRendering::DISABLED); + return *this; +} } // namespace ImageVisualShaderFeature ImageVisualShaderFactory::ImageVisualShaderFactory() @@ -88,13 +115,14 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, con Shader shader; VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::IMAGE_SHADER; - const auto& atlasing = featureBuilder.mTextureAtlas; - const auto& defaultTextureWrapping = featureBuilder.mDefaultTextureWrapMode; - const auto& roundedCorner = featureBuilder.mRoundedCorner; - const auto& borderline = featureBuilder.mBorderline; - const auto& changeFragmentShader = (featureBuilder.mTexture && DevelTexture::IsNative(featureBuilder.mTexture)) - ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE - : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE; + const auto& atlasing = featureBuilder.mTextureAtlas; + const auto& defaultTextureWrapping = featureBuilder.mDefaultTextureWrapMode; + const auto& roundedCorner = featureBuilder.mRoundedCorner; + const auto& borderline = featureBuilder.mBorderline; + const auto& alphaMaskingOnRendering = featureBuilder.mAlphaMaskingOnRendering; + const auto& changeFragmentShader = (featureBuilder.mTexture && DevelTexture::IsNative(featureBuilder.mTexture)) + ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE + : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE; if(atlasing == ImageVisualShaderFeature::TextureAtlas::ENABLED) { @@ -109,24 +137,20 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, con } else { + uint32_t shaderTypeFlag = static_cast(ImageVisualRequireFlag::DEFAULT); if(roundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED) { - if(borderline == ImageVisualShaderFeature::Borderline::ENABLED) - { - shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE; - } - else - { - shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER; - } + shaderTypeFlag |= static_cast(ImageVisualRequireFlag::ROUNDED_CORNER); } - else + if(borderline == ImageVisualShaderFeature::Borderline::ENABLED) { - if(borderline == ImageVisualShaderFeature::Borderline::ENABLED) - { - shaderType = VisualFactoryCache::IMAGE_SHADER_BORDERLINE; - } + shaderTypeFlag |= static_cast(ImageVisualRequireFlag::BORDERLINE); + } + if(alphaMaskingOnRendering == ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED) + { + shaderTypeFlag |= static_cast(ImageVisualRequireFlag::ALPHA_MASKING); } + shaderType = SHADER_TYPE_TABLE[shaderTypeFlag]; } if(changeFragmentShader == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE && @@ -164,6 +188,11 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, con vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n"; fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n"; } + if(alphaMaskingOnRendering == ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED) + { + vertexShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING 1\n"; + fragmentShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING 1\n"; + } } std::string vertexShader = std::string(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_VERT.data()); diff --git a/dali-toolkit/internal/visuals/image-visual-shader-factory.h b/dali-toolkit/internal/visuals/image-visual-shader-factory.h index 1459614..e0070ed 100644 --- a/dali-toolkit/internal/visuals/image-visual-shader-factory.h +++ b/dali-toolkit/internal/visuals/image-visual-shader-factory.h @@ -96,6 +96,18 @@ enum Type }; } // namespace ChangeFragmentShader +namespace AlphaMaskingOnRendering +{ +/** + * @brief Whether use runtime alpha masking in shader, or not + */ +enum Type +{ + DISABLED = 0, ///< Image visual doesn't use runtime alpha masking + ENABLED ///< Image visual uses runtime alpha masking +}; +} // namespace AlphaMaskingOnRendering + /** * @brief Collection of current image visual feature. Only use for ImageVisualShaderFactory::GetShader() */ @@ -106,6 +118,7 @@ struct FeatureBuilder mDefaultTextureWrapMode(DefaultTextureWrapMode::APPLY), mRoundedCorner(RoundedCorner::DISABLED), mBorderline(Borderline::DISABLED), + mAlphaMaskingOnRendering(AlphaMaskingOnRendering::DISABLED), mTexture() { } @@ -115,15 +128,17 @@ struct FeatureBuilder FeatureBuilder& EnableRoundedCorner(bool enableRoundedCorner); FeatureBuilder& EnableBorderline(bool enableBorderline); FeatureBuilder& SetTextureForFragmentShaderCheck(const Dali::Texture& texture); - - TextureAtlas::Type mTextureAtlas : 2; ///< Whether use texture with atlas, or not. default as TextureAtlas::DISABLED - DefaultTextureWrapMode::Type mDefaultTextureWrapMode : 2; ///< Whether apply to texture wraping in default, or not. default as DefaultTextureWrapMode::APPLY - RoundedCorner::Type mRoundedCorner : 2; ///< Whether use rounded corner, or not. default as RoundedCorner::DISABLED - Borderline::Type mBorderline : 2; ///< Whether use borderline, or not. default as Borderline::DISABLED - Dali::Texture mTexture; ///< Texture to check whether we need to change fragment shader or not + FeatureBuilder& EnableAlphaMaskingOnRendering(bool enableAlphaMaskingOnRendering); + + TextureAtlas::Type mTextureAtlas : 2; ///< Whether use texture with atlas, or not. default as TextureAtlas::DISABLED + DefaultTextureWrapMode::Type mDefaultTextureWrapMode : 2; ///< Whether apply to texture wraping in default, or not. default as DefaultTextureWrapMode::APPLY + RoundedCorner::Type mRoundedCorner : 2; ///< Whether use rounded corner, or not. default as RoundedCorner::DISABLED + Borderline::Type mBorderline : 2; ///< Whether use borderline, or not. default as Borderline::DISABLED + AlphaMaskingOnRendering::Type mAlphaMaskingOnRendering : 2; ///< Whether use runtime alpha masking, or not. default as AlphaMaskingOnRendering::DISABLED + Dali::Texture mTexture; ///< Texture to check whether we need to change fragment shader or not }; -} // namespace ImageVisualShaderFactoryFeature +} // namespace ImageVisualShaderFeature /** * ImageVisualShaderFactory is an object that provides and shares shaders between image visuals diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.h b/dali-toolkit/internal/visuals/visual-factory-cache.h index 417f4d4..193799c 100644 --- a/dali-toolkit/internal/visuals/visual-factory-cache.h +++ b/dali-toolkit/internal/visuals/visual-factory-cache.h @@ -84,12 +84,20 @@ public: IMAGE_SHADER_ROUNDED_CORNER, IMAGE_SHADER_BORDERLINE, IMAGE_SHADER_ROUNDED_BORDERLINE, + IMAGE_SHADER_MASKING, + IMAGE_SHADER_ROUNDED_CORNER_MASKING, + IMAGE_SHADER_BORDERLINE_MASKING, + IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING, IMAGE_SHADER_ATLAS_DEFAULT_WRAP, IMAGE_SHADER_ATLAS_CUSTOM_WRAP, NATIVE_IMAGE_SHADER, NATIVE_IMAGE_SHADER_ROUNDED_CORNER, NATIVE_IMAGE_SHADER_BORDERLINE, NATIVE_IMAGE_SHADER_ROUNDED_BORDERLINE, + NATIVE_IMAGE_SHADER_MASKING, + NATIVE_IMAGE_SHADER_ROUNDED_CORNER_MASKING, + NATIVE_IMAGE_SHADER_BORDERLINE_MASKING, + NATIVE_IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING, NINE_PATCH_SHADER, NINE_PATCH_MASK_SHADER, TEXT_SHADER_MULTI_COLOR_TEXT, diff --git a/dali-toolkit/internal/visuals/visual-string-constants.cpp b/dali-toolkit/internal/visuals/visual-string-constants.cpp index 643fb21..6b48a2d 100644 --- a/dali-toolkit/internal/visuals/visual-string-constants.cpp +++ b/dali-toolkit/internal/visuals/visual-string-constants.cpp @@ -122,6 +122,7 @@ const char* const IMAGE_DESIRED_WIDTH("desiredWidth"); const char* const IMAGE_DESIRED_HEIGHT("desiredHeight"); const char* const ALPHA_MASK_URL("alphaMaskUrl"); const char* const REDRAW_IN_SCALING_DOWN_NAME("redrawInScalingDown"); +const char* const MASKING_TYPE_NAME("maskingType"); // Text visual const char* const TEXT_PROPERTY("text"); diff --git a/dali-toolkit/internal/visuals/visual-string-constants.h b/dali-toolkit/internal/visuals/visual-string-constants.h index 1544206..e736132 100644 --- a/dali-toolkit/internal/visuals/visual-string-constants.h +++ b/dali-toolkit/internal/visuals/visual-string-constants.h @@ -106,6 +106,7 @@ extern const char* const IMAGE_DESIRED_WIDTH; extern const char* const IMAGE_DESIRED_HEIGHT; extern const char* const ALPHA_MASK_URL; extern const char* const REDRAW_IN_SCALING_DOWN_NAME; +extern const char* const MASKING_TYPE_NAME; // Text visual extern const char* const TEXT_PROPERTY; -- 2.7.4