+ if(index != Property::INVALID_INDEX)
+ {
+ mFactoryCache.GetAtlasManager()->Remove(textureSet, atlasRect);
+ }
+ }
+}
+
+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)));
+
+ 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 & 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
+ {
+ std::string_view vertexShaderView;
+ std::string_view fragmentShaderView;
+
+ if(mImpl->mCustomShader && !mImpl->mCustomShader->mVertexShader.empty())
+ {
+ vertexShaderView = mImpl->mCustomShader->mVertexShader;
+ usesWholeTexture = false; // Impossible to tell.
+ }
+ else
+ {
+ vertexShaderView = mImageVisualShaderFactory.GetVertexShaderSource();
+ }
+
+ if(mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty())
+ {
+ fragmentShaderView = mImpl->mCustomShader->mFragmentShader;
+ }
+ else
+ {
+ fragmentShaderView = mImageVisualShaderFactory.GetFragmentShaderSource();
+ }
+
+ // If the texture is native, we may need to change prefix and sampler in
+ // the fragment shader
+ if(useNativeImage)
+ {
+ bool modifiedFragmentShader = false;
+ Texture nativeTexture = mTextures.GetTexture(0);
+ std::string fragmentShaderString = std::string(fragmentShaderView);
+
+ modifiedFragmentShader = DevelTexture::ApplyNativeFragmentShader(nativeTexture, fragmentShaderString);
+ if(modifiedFragmentShader)
+ {
+ fragmentShaderView = fragmentShaderString;
+ }
+
+ // Create shader here cause fragmentShaderString scope issue
+ shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints);
+ }
+ else
+ {
+ shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints);
+ }
+ }
+
+ if(usesWholeTexture)
+ {
+ shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
+ }
+
+ // Set pixel align off as default.
+ // ToDo: Pixel align causes issues such as rattling image animation.
+ // We should trun it off until issues are resolved
+ shader.RegisterProperty(PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF);
+
+ 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)