Enable to use GPU masking in image visual
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / image / image-visual.cpp
index 970e309..44c9fac 100644 (file)
@@ -31,9 +31,9 @@
 
 // INTERNAL HEADERS
 #include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
+#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
-#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
@@ -51,6 +51,8 @@ namespace Internal
 {
 namespace
 {
+const int CUSTOM_PROPERTY_COUNT(12); // ltr, wrap, pixel area, atlas, pixalign, crop to mask, mask texture ratio + border/corner
+
 // fitting modes
 DALI_ENUM_TO_STRING_TABLE_BEGIN(FITTING_MODE)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SHRINK_TO_FIT)
@@ -97,6 +99,8 @@ const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 const float PIXEL_ALIGN_ON  = 1.0f;
 const float PIXEL_ALIGN_OFF = 0.0f;
 
+constexpr uint32_t TEXTURE_COUNT_FOR_GPU_ALPHA_MASK = 2u;
+
 Geometry CreateGeometry(VisualFactoryCache& factoryCache, ImageDimensions gridSize)
 {
   Geometry geometry;
@@ -200,7 +204,7 @@ ImageVisual::~ImageVisual()
       else if(mImageUrl.IsBufferResource())
       {
         TextureManager& textureManager = mFactoryCache.GetTextureManager();
-        textureManager.RemoveExternalEncodedImageBuffer(mImageUrl.GetUrl());
+        textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
       }
     }
 
@@ -272,6 +276,10 @@ void ImageVisual::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);
@@ -305,11 +313,11 @@ void ImageVisual::DoSetProperty(Property::Index index, const Property::Value& va
       {
         if(sync)
         {
-          mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+          mImpl->mFlags |= Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
         }
         else
         {
-          mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+          mImpl->mFlags &= ~Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
         }
       }
       else
@@ -424,6 +432,17 @@ void ImageVisual::DoSetProperty(Property::Index index, const Property::Value& va
       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;
@@ -469,7 +488,7 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize)
   }
   else if(mImpl->mRenderer) // Check if we have a loaded image
   {
-    if(mImpl->mFlags & Impl::IS_ATLASING_APPLIED)
+    if(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED)
     {
       naturalSize.x = mAtlasRectSize.GetWidth();
       naturalSize.y = mAtlasRectSize.GetHeight();
@@ -479,11 +498,9 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize)
     auto textureSet = mImpl->mRenderer.GetTextures();
     if(textureSet && textureSet.GetTextureCount())
     {
-      auto texture = textureSet.GetTexture(0);
-      if(texture)
+      if(mTextureSize != Vector2::ZERO)
       {
-        naturalSize.x = texture.GetWidth();
-        naturalSize.y = texture.GetHeight();
+        naturalSize = mTextureSize;
         return;
       }
     }
@@ -513,7 +530,7 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize)
       }
       else
       {
-        Actor actor = mPlacementActor.GetHandle();
+        Actor   actor     = mPlacementActor.GetHandle();
         Vector2 imageSize = Vector2::ZERO;
         if(actor)
         {
@@ -521,8 +538,8 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize)
         }
         mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
         Texture brokenImage = mImpl->mRenderer.GetTextures().GetTexture(0);
-        naturalSize.x = brokenImage.GetWidth();
-        naturalSize.y = brokenImage.GetWidth();
+        naturalSize.x       = brokenImage.GetWidth();
+        naturalSize.y       = brokenImage.GetWidth();
       }
       return;
     }
@@ -565,12 +582,18 @@ void ImageVisual::OnInitialize()
   Shader shader = GenerateShader();
 
   // Create the renderer
-  mImpl->mRenderer = Renderer::New(geometry, shader);
+  mImpl->mRenderer = VisualRenderer::New(geometry, shader);
+  mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
 
   //Register transform properties
-  mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
+  mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
 
   EnablePreMultipliedAlpha(IsPreMultipliedAlphaEnabled());
+
+  if(mMaskingData)
+  {
+    mImpl->mRenderer.RegisterProperty(CROP_TO_MASK_NAME, static_cast<float>(mMaskingData->mCropToMask));
+  }
 }
 
 void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection, TextureManager::ReloadPolicy forceReload)
@@ -617,11 +640,11 @@ void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& te
 
   if(atlasing) // Flag needs to be set before creating renderer
   {
-    mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+    mImpl->mFlags |= Visual::Base::Impl::IS_ATLASING_APPLIED;
   }
   else
   {
-    mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+    mImpl->mFlags &= ~Visual::Base::Impl::IS_ATLASING_APPLIED;
   }
 }
 
@@ -658,6 +681,8 @@ void ImageVisual::InitializeRenderer()
   if(mTextures)
   {
     mImpl->mRenderer.SetTextures(mTextures);
+    ComputeTextureSize();
+    CheckMaskTexture();
     if(DevelTexture::IsNative(mTextures.GetTexture(0)))
     {
       UpdateShader();
@@ -742,6 +767,7 @@ void ImageVisual::DoSetOffScene(Actor& actor)
 
     TextureSet textureSet = TextureSet::New();
     mImpl->mRenderer.SetTextures(textureSet);
+    ComputeTextureSize();
 
     mLoadState = TextureManager::LoadState::NOT_STARTED;
   }
@@ -777,6 +803,7 @@ void ImageVisual::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);
@@ -814,16 +841,10 @@ void ImageVisual::OnSetTransform()
 {
   if(mImpl->mRenderer)
   {
-    mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
+    mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
   }
 }
 
-bool ImageVisual::IsResourceReady() const
-{
-  return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY ||
-          mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED);
-}
-
 void ImageVisual::UpdateShader()
 {
   if(mImpl->mRenderer)
@@ -882,6 +903,8 @@ void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureIn
       sampler.SetWrapMode(mWrapModeU, mWrapModeV);
       textureInformation.textureSet.SetSampler(0u, sampler);
       mImpl->mRenderer.SetTextures(textureInformation.textureSet);
+      ComputeTextureSize();
+      CheckMaskTexture();
     }
 
     if(actor)
@@ -970,26 +993,81 @@ void ImageVisual::RemoveTexture()
   }
 }
 
+void ImageVisual::ComputeTextureSize()
+{
+  if(mImpl->mRenderer)
+  {
+    auto textureSet = mImpl->mRenderer.GetTextures();
+    if(textureSet && textureSet.GetTextureCount())
+    {
+      auto texture = textureSet.GetTexture(0);
+      if(texture)
+      {
+        mTextureSize.x = texture.GetWidth();
+        mTextureSize.y = texture.GetHeight();
+        if(textureSet.GetTextureCount() > 1u && mMaskingData && !mMaskingData->mPreappliedMasking && mMaskingData->mCropToMask)
+        {
+          Texture maskTexture = textureSet.GetTexture(1);
+          if(maskTexture)
+          {
+            mTextureSize.x = std::min(static_cast<uint32_t>(mTextureSize.x * mMaskingData->mContentScaleFactor), maskTexture.GetWidth());
+            mTextureSize.y = std::min(static_cast<uint32_t>(mTextureSize.y * mMaskingData->mContentScaleFactor), maskTexture.GetHeight());
+          }
+        }
+      }
+    }
+  }
+}
+
+Vector2 ImageVisual::ComputeMaskTextureRatio()
+{
+  Vector2 maskTextureRatio;
+  if(mImpl->mRenderer)
+  {
+    auto textureSet = mImpl->mRenderer.GetTextures();
+    if(textureSet && textureSet.GetTextureCount())
+    {
+      auto texture = textureSet.GetTexture(0);
+      if(texture)
+      {
+        if(textureSet.GetTextureCount() > 1u && mMaskingData && !mMaskingData->mPreappliedMasking && mMaskingData->mCropToMask)
+        {
+          Texture maskTexture = textureSet.GetTexture(1);
+          if(maskTexture)
+          {
+            float textureWidth  = std::max(static_cast<float>(texture.GetWidth() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
+            float textureHeight = std::max(static_cast<float>(texture.GetHeight() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
+            maskTextureRatio    = Vector2(std::min(static_cast<float>(maskTexture.GetWidth()), textureWidth) / textureWidth,
+                                       std::min(static_cast<float>(maskTexture.GetHeight()), textureHeight) / textureHeight);
+          }
+        }
+      }
+    }
+  }
+  return maskTextureRatio;
+}
+
 Shader ImageVisual::GenerateShader() const
 {
   Shader shader;
 
-  bool             usesWholeTexture  = true;
-  const bool       useStandardShader = !mImpl->mCustomShader;
-  const bool       useNativeImage    = (mTextures && DevelTexture::IsNative(mTextures.GetTexture(0)));
+  bool       usesWholeTexture  = true;
+  const bool useStandardShader = !mImpl->mCustomShader;
+  const bool useNativeImage    = (mTextures && DevelTexture::IsNative(mTextures.GetTexture(0)));
 
   if(useStandardShader)
   {
+    bool   requiredAlphaMaskingOnRendering = (mMaskingData && !mMaskingData->mMaskImageLoadingFailed) ? !mMaskingData->mPreappliedMasking : false;
     // Create and cache the standard shader
     shader = mImageVisualShaderFactory.GetShader(
       mFactoryCache,
       ImageVisualShaderFeature::FeatureBuilder()
-      .EnableTextureAtlas(mImpl->mFlags & Impl::IS_ATLASING_APPLIED && !useNativeImage)
-      .ApplyDefaultTextureWrapMode(mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE)
-      .EnableRoundedCorner(IsRoundedCornerRequired())
-      .EnableBorderline(IsBorderlineRequired())
-      .SetTextureForFragmentShaderCheck(useNativeImage ? mTextures.GetTexture(0) : Dali::Texture())
-    );
+        .EnableTextureAtlas(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED && !useNativeImage)
+        .ApplyDefaultTextureWrapMode(mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE)
+        .EnableRoundedCorner(IsRoundedCornerRequired())
+        .EnableBorderline(IsBorderlineRequired())
+        .SetTextureForFragmentShaderCheck(useNativeImage ? mTextures.GetTexture(0) : Dali::Texture())
+        .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering));
   }
   else
   {
@@ -1051,6 +1129,29 @@ Shader ImageVisual::GenerateShader() const
   return shader;
 }
 
+void ImageVisual::CheckMaskTexture()
+{
+  if(mMaskingData && !mMaskingData->mPreappliedMasking)
+  {
+    bool maskLoadFailed = true;
+    TextureSet textures = mImpl->mRenderer.GetTextures();
+    if(textures && textures.GetTextureCount() >= TEXTURE_COUNT_FOR_GPU_ALPHA_MASK)
+    {
+      if(mMaskingData->mCropToMask)
+      {
+        mImpl->mRenderer.RegisterProperty(MASK_TEXTURE_RATIO_NAME, ComputeMaskTextureRatio());
+      }
+      maskLoadFailed = false;
+    }
+
+    if(mMaskingData->mMaskImageLoadingFailed != maskLoadFailed)
+    {
+      mMaskingData->mMaskImageLoadingFailed = maskLoadFailed;
+      UpdateShader();
+    }
+  }
+}
+
 } // namespace Internal
 
 } // namespace Toolkit