Merge "Remove mask internally in texture manager" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / image / image-visual.cpp
index 7676bf8..da12c4f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <dali/devel-api/scripting/scripting.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/actors/layer.h>
+#include <dali/public-api/rendering/decorated-visual-renderer.h>
 #include <cstring> // for strlen()
 
 // 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 +52,8 @@ namespace Internal
 {
 namespace
 {
+const int CUSTOM_PROPERTY_COUNT(7); // ltr, wrap, pixel area, atlas, pixalign, crop to mask, mask texture ratio
+
 // fitting modes
 DALI_ENUM_TO_STRING_TABLE_BEGIN(FITTING_MODE)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SHRINK_TO_FIT)
@@ -97,6 +100,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;
@@ -175,18 +180,6 @@ ImageVisual::~ImageVisual()
 {
   if(Stage::IsInstalled())
   {
-    if(mMaskingData)
-    {
-      // TextureManager could have been deleted before the actor that contains this
-      // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage
-      // is still valid before accessing texture manager.
-      if(mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID)
-      {
-        TextureManager& textureManager = mFactoryCache.GetTextureManager();
-        textureManager.Remove(mMaskingData->mAlphaMaskId, this);
-      }
-    }
-
     if(mImageUrl.IsValid())
     {
       // Decrease reference count of External Resources :
@@ -200,7 +193,7 @@ ImageVisual::~ImageVisual()
       else if(mImageUrl.IsBufferResource())
       {
         TextureManager& textureManager = mFactoryCache.GetTextureManager();
-        textureManager.RemoveExternalEncodedImageBuffer(mImageUrl.GetUrl());
+        textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
       }
     }
 
@@ -272,6 +265,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 +302,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 +421,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 +477,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 +487,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 +519,7 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize)
       }
       else
       {
-        Actor actor = mPlacementActor.GetHandle();
+        Actor   actor     = mPlacementActor.GetHandle();
         Vector2 imageSize = Vector2::ZERO;
         if(actor)
         {
@@ -521,8 +527,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 +571,18 @@ void ImageVisual::OnInitialize()
   Shader shader = GenerateShader();
 
   // Create the renderer
-  mImpl->mRenderer = Renderer::New(geometry, shader);
+  mImpl->mRenderer = DecoratedVisualRenderer::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)
@@ -594,7 +606,7 @@ void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& te
   bool synchronousLoading = IsSynchronousLoadingRequired();
   bool loadingStatus;
 
-  textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mTextureId, atlasRect, mAtlasRectSize, atlasing, loadingStatus, mWrapModeU, mWrapModeV, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection, forceReload, preMultiplyOnLoad);
+  textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mTextureId, atlasRect, mAtlasRectSize, atlasing, loadingStatus, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection, forceReload, preMultiplyOnLoad);
 
   if(textures)
   {
@@ -608,6 +620,12 @@ void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& te
     }
 
     EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
+    if(!atlasing)
+    {
+      Sampler sampler = Sampler::New();
+      sampler.SetWrapMode(mWrapModeU, mWrapModeV);
+      textures.SetSampler(0u, sampler);
+    }
   }
   else if(synchronousLoading)
   {
@@ -617,11 +635,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;
   }
 }
 
@@ -652,13 +670,33 @@ void ImageVisual::InitializeRenderer()
     else
     {
       mTextures = mFactoryCache.GetTextureManager().GetTextureSet(mTextureId);
+      if(!(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED) && mTextures)
+      {
+        Sampler sampler = Sampler::New();
+        sampler.SetWrapMode(mWrapModeU, mWrapModeV);
+        mTextures.SetSampler(0u, sampler);
+      }
     }
   }
 
   if(mTextures)
   {
     mImpl->mRenderer.SetTextures(mTextures);
-    if(DevelTexture::IsNative(mTextures.GetTexture(0)))
+    ComputeTextureSize();
+    CheckMaskTexture();
+
+    bool needToUpdateShader = DevelTexture::IsNative(mTextures.GetTexture(0));
+
+    if(mTextures.GetTextureCount() == 3)
+    {
+      if(mTextures.GetTexture(0).GetPixelFormat() == Pixel::L8 && mTextures.GetTexture(1).GetPixelFormat() == Pixel::CHROMINANCE_U && mTextures.GetTexture(2).GetPixelFormat() == Pixel::CHROMINANCE_V)
+      {
+        mNeedYuvToRgb      = true;
+        needToUpdateShader = true;
+      }
+    }
+
+    if(needToUpdateShader)
     {
       UpdateShader();
     }
@@ -742,6 +780,7 @@ void ImageVisual::DoSetOffScene(Actor& actor)
 
     TextureSet textureSet = TextureSet::New();
     mImpl->mRenderer.SetTextures(textureSet);
+    ComputeTextureSize();
 
     mLoadState = TextureManager::LoadState::NOT_STARTED;
   }
@@ -755,7 +794,7 @@ void ImageVisual::DoCreatePropertyMap(Property::Map& map) const
   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
 
   bool sync = IsSynchronousLoadingRequired();
-  map.Insert(SYNCHRONOUS_LOADING, sync);
+  map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, sync);
   if(mImageUrl.IsValid())
   {
     map.Insert(Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl());
@@ -777,6 +816,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 +854,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)
@@ -853,17 +887,17 @@ void ImageVisual::UploadCompleted()
 }
 
 // From Texture Manager
-void ImageVisual::UploadComplete(bool loadingSuccess, int32_t textureId, TextureSet textureSet, bool usingAtlas, const Vector4& atlasRectangle, bool preMultiplied)
+void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureInformation)
 {
   Toolkit::Visual::ResourceStatus resourceStatus;
   if(mImpl->mRenderer)
   {
-    if(usingAtlas)
+    if(textureInformation.useAtlasing)
     {
       mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect);
     }
 
-    EnablePreMultipliedAlpha(preMultiplied);
+    EnablePreMultipliedAlpha(textureInformation.preMultiplied);
 
     Actor actor = mPlacementActor.GetHandle();
     if(!loadingSuccess)
@@ -874,14 +908,29 @@ void ImageVisual::UploadComplete(bool loadingSuccess, int32_t textureId, Texture
         imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
       }
       mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
-      textureSet = mImpl->mRenderer.GetTextures();
+      textureInformation.textureSet = mImpl->mRenderer.GetTextures();
     }
     else
     {
-      Sampler sampler = Sampler::New();
-      sampler.SetWrapMode(mWrapModeU, mWrapModeV);
-      textureSet.SetSampler(0u, sampler);
-      mImpl->mRenderer.SetTextures(textureSet);
+      if(!textureInformation.useAtlasing)
+      {
+        Sampler sampler = Sampler::New();
+        sampler.SetWrapMode(mWrapModeU, mWrapModeV);
+        textureInformation.textureSet.SetSampler(0u, sampler);
+      }
+
+      mImpl->mRenderer.SetTextures(textureInformation.textureSet);
+      ComputeTextureSize();
+      CheckMaskTexture();
+
+      if(textureInformation.textureSet.GetTextureCount() == 3)
+      {
+        if(textureInformation.textureSet.GetTexture(0).GetPixelFormat() == Pixel::L8 && textureInformation.textureSet.GetTexture(1).GetPixelFormat() == Pixel::CHROMINANCE_U && textureInformation.textureSet.GetTexture(2).GetPixelFormat() == Pixel::CHROMINANCE_V)
+        {
+          mNeedYuvToRgb = true;
+          UpdateShader();
+        }
+      }
     }
 
     if(actor)
@@ -895,7 +944,7 @@ void ImageVisual::UploadComplete(bool loadingSuccess, int32_t textureId, Texture
   // Storing TextureSet needed when renderer staged.
   if(!mImpl->mRenderer)
   {
-    mTextures = textureSet;
+    mTextures = textureInformation.textureSet;
   }
 
   // Image loaded, set status regardless of staged status.
@@ -970,26 +1019,82 @@ 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)
+        .EnableYuvToRgb(mNeedYuvToRgb));
   }
   else
   {
@@ -1051,6 +1156,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