Refactoring ImageVisualShaderFactory::GetShader 96/265996/8
authorEunki, Hong <eunkiki.hong@samsung.com>
Wed, 3 Nov 2021 13:02:00 +0000 (22:02 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Fri, 19 Nov 2021 05:42:53 +0000 (14:42 +0900)
There are two Intention this patch
1. Clean up GetShader params
2. Allow that native image also use visual features (a.k.a. RoundedCorner + Borderline)

Change-Id: I8b0cbd0a4c7c622268c90d3cbbbd345ae83dfa07
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
dali-toolkit/internal/visuals/image-visual-shader-factory.cpp
dali-toolkit/internal/visuals/image-visual-shader-factory.h
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/svg/svg-visual.cpp
dali-toolkit/internal/visuals/visual-factory-cache.h

index cd834df..51b9923 100644 (file)
@@ -422,7 +422,6 @@ int UtcDaliImageVisualRemoteImageLoad(void)
   END_TEST;
 }
 
-
 int UtcDaliImageVisualWithNativeImage(void)
 {
   ToolkitTestApplication application;
@@ -468,6 +467,71 @@ int UtcDaliImageVisualWithNativeImage(void)
   END_TEST;
 }
 
+int UtcDaliImageVisualWithNativeImageCustomShader(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Use Native Image as url and Use custom shader" );
+
+  NativeImageSourcePtr nativeImageSource = NativeImageSource::New(500, 500, NativeImageSource::COLOR_DEPTH_DEFAULT);
+  ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(nativeImageSource);
+  std::string url = imageUrl.GetUrl();
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  Property::Map shaderMap;
+  const std::string customVertexShaderSource = "Foobar";
+  const std::string customFragmentShaderSource = "Foobar";
+  shaderMap[Toolkit::Visual::Shader::Property::FRAGMENT_SHADER] = customFragmentShaderSource;
+  shaderMap[Toolkit::Visual::Shader::Property::VERTEX_SHADER] = customVertexShaderSource;
+
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,   Visual::IMAGE );
+  propertyMap.Insert( Toolkit::Visual::Property::SHADER, shaderMap );
+  propertyMap.Insert( ImageVisual::Property::URL,        url );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+  actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  application.GetScene().Add( actor );
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(16);
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Shader shader = renderer.GetShader();
+
+  Property::Value value = shader.GetProperty(Shader::Property::PROGRAM);
+  DALI_TEST_CHECK(value.GetType() == Property::MAP);
+  const Property::Map* outMap = value.GetMap();
+  std::string fragmentShaderSource = (*outMap)["fragment"].Get<std::string>();
+  std::string vertexShaderSource = (*outMap)["vertex"].Get<std::string>();
+
+  // Compare vertex shader is equal
+  DALI_TEST_EQUALS( customVertexShaderSource, vertexShaderSource, TEST_LOCATION );
+
+  // Check fragment shader changed
+  const char* fragmentPrefix = Dali::NativeImageSourceTest::GetCustomFragmentPrefix();
+  size_t pos = fragmentShaderSource.find(fragmentPrefix);
+
+  DALI_TEST_EQUALS( pos != std::string::npos, true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( std::string(fragmentPrefix) + customFragmentShaderSource, fragmentShaderSource, TEST_LOCATION );
+
+  END_TEST;
+}
+
 int UtcDaliImageVisualWithNativeImageRemoved(void)
 {
   ToolkitTestApplication application;
index d8d61d3..da7fb09 100644 (file)
@@ -833,10 +833,11 @@ Shader AnimatedImageVisual::GenerateShader() const
   Shader shader;
   shader = mImageVisualShaderFactory.GetShader(
     mFactoryCache,
-    TextureAtlas::DISABLED,
-    defaultWrapMode ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY,
-    IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
-    IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED);
+    ImageVisualShaderFeature::FeatureBuilder()
+    .ApplyDefaultTextureWrapMode(defaultWrapMode)
+    .EnableRoundedCorner(IsRoundedCornerRequired())
+    .EnableBorderline(IsBorderlineRequired())
+  );
   return shader;
 }
 
index 26495bf..75b71f2 100644 (file)
@@ -626,10 +626,9 @@ Shader AnimatedVectorImageVisual::GenerateShader() const
   {
     shader = mImageVisualShaderFactory.GetShader(
       mFactoryCache,
-      TextureAtlas::DISABLED,
-      DefaultTextureWrapMode::APPLY,
-      IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
-      IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+      ImageVisualShaderFeature::FeatureBuilder()
+      .EnableRoundedCorner(IsRoundedCornerRequired())
+      .EnableBorderline(IsBorderlineRequired())
     );
   }
   return shader;
index 7f2cac7..f5753fa 100644 (file)
@@ -18,6 +18,7 @@
 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/rendering/texture-devel.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
@@ -40,9 +41,41 @@ static std::string gVertexShader;
 // global string variable to caching complate fragment shader (no atlas)
 static std::string gFragmentShaderNoAtlas;
 
+const int NATIVE_SHADER_TYPE_OFFSET = VisualFactoryCache::ShaderType::NATIVE_IMAGE_SHADER - VisualFactoryCache::ShaderType::IMAGE_SHADER;
+
 } // unnamed namespace
 
+namespace ImageVisualShaderFeature
+{
+FeatureBuilder& FeatureBuilder::EnableTextureAtlas(bool enableAtlas)
+{
+  mTextureAtlas = (enableAtlas ? TextureAtlas::ENABLED : TextureAtlas::DISABLED);
+  return *this;
+}
+FeatureBuilder& FeatureBuilder::ApplyDefaultTextureWrapMode(bool applyDefaultTextureWrapMode)
+{
+  mDefaultTextureWrapMode = (applyDefaultTextureWrapMode ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY);
+  return *this;
+}
+FeatureBuilder& FeatureBuilder::EnableRoundedCorner(bool enableRoundedCorner)
+{
+  mRoundedCorner = (enableRoundedCorner ? RoundedCorner::ENABLED : RoundedCorner::DISABLED);
+  return *this;
+}
+FeatureBuilder& FeatureBuilder::EnableBorderline(bool enableBorderline)
+{
+  mBorderline = (enableBorderline ? Borderline::ENABLED : Borderline::DISABLED);
+  return *this;
+}
+FeatureBuilder& FeatureBuilder::SetTextureForFragmentShaderCheck(const Dali::Texture& texture)
+{
+  mTexture = texture;
+  return *this;
+}
+} // namespace ImageVisualShaderFeature
+
 ImageVisualShaderFactory::ImageVisualShaderFactory()
+: mFragmentShaderNeedChange(ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED)
 {
 }
 
@@ -50,13 +83,22 @@ ImageVisualShaderFactory::~ImageVisualShaderFactory()
 {
 }
 
-Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, TextureAtlas atlasing, DefaultTextureWrapMode defaultTextureWrapping, RoundedCorner roundedCorner, Borderline borderline)
+Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, const ImageVisualShaderFeature::FeatureBuilder& featureBuilder)
 {
   Shader shader;
   VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::IMAGE_SHADER;
-  if(atlasing == TextureAtlas::ENABLED)
+
+  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;
+
+  if(atlasing == ImageVisualShaderFeature::TextureAtlas::ENABLED)
   {
-    if(defaultTextureWrapping == DefaultTextureWrapMode::APPLY)
+    if(defaultTextureWrapping == ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY)
     {
       shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP;
     }
@@ -67,9 +109,9 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, Tex
   }
   else
   {
-    if(roundedCorner == RoundedCorner::ENABLED)
+    if(roundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
     {
-      if(borderline == Borderline::ENABLED)
+      if(borderline == ImageVisualShaderFeature::Borderline::ENABLED)
       {
         shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE;
       }
@@ -80,21 +122,28 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, Tex
     }
     else
     {
-      if(borderline == Borderline::ENABLED)
+      if(borderline == ImageVisualShaderFeature::Borderline::ENABLED)
       {
         shaderType = VisualFactoryCache::IMAGE_SHADER_BORDERLINE;
       }
     }
   }
 
+  if(changeFragmentShader == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE &&
+     (mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED ||
+      mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE))
+  {
+    shaderType = static_cast<VisualFactoryCache::ShaderType>(static_cast<int>(shaderType) + NATIVE_SHADER_TYPE_OFFSET);
+  }
+
   shader = factoryCache.GetShader(shaderType);
   if(!shader)
   {
     std::string vertexShaderPrefixList;
     std::string fragmentShaderPrefixList;
-    if(atlasing == TextureAtlas::ENABLED)
+    if(atlasing == ImageVisualShaderFeature::TextureAtlas::ENABLED)
     {
-      if(defaultTextureWrapping == DefaultTextureWrapMode::APPLY)
+      if(defaultTextureWrapping == ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY)
       {
         fragmentShaderPrefixList += "#define ATLAS_DEFAULT_WARP 1\n";
       }
@@ -105,20 +154,70 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, Tex
     }
     else
     {
-      if(roundedCorner == RoundedCorner::ENABLED)
+      if(roundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
       {
         vertexShaderPrefixList   += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
         fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
       }
-      if(borderline == Borderline::ENABLED)
+      if(borderline == ImageVisualShaderFeature::Borderline::ENABLED)
       {
         vertexShaderPrefixList   += "#define IS_REQUIRED_BORDERLINE 1\n";
         fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
       }
     }
 
-    shader = Shader::New(Dali::Shader::GetVertexShaderPrefix()   + vertexShaderPrefixList   + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
-                         Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_FRAG.data());
+    std::string vertexShader   = std::string(Dali::Shader::GetVertexShaderPrefix()   + vertexShaderPrefixList   + SHADER_IMAGE_VISUAL_SHADER_VERT.data());
+    std::string fragmentShader = std::string(Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_FRAG.data());
+
+    if(changeFragmentShader == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE)
+    {
+      if(DALI_UNLIKELY(mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED))
+      {
+        // NOTE : This routine will run exist one times.
+        //
+        // First, we will run ApplyNativeFragmentShader
+        //  - If fragment shader is modified, then current platform allow to change fragment shader.
+        //    We cache this result mFragmentShaderNeedChange = ChangeFragmentShader::NEED_CHANGE.
+        //  - If fragment shader is not modified, then current platform will always don't change fragment shader.
+        //    We cache this result mFragmentShaderNeedChange = ChangeFragmentShader::DONT_CHANGE.
+        //    And change current shaderType into normal image range.
+        //    After cached the result, shaderType never become NATIVE_IMAGE_SHADER anymore.
+        // Second, save shader result.
+
+        // Try to apply fragmentShader
+        bool modified = DevelTexture::ApplyNativeFragmentShader(featureBuilder.mTexture, fragmentShader);
+        if(modified)
+        {
+          // Now we know that fragment shader need to change.
+          mFragmentShaderNeedChange = ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE;
+        }
+        else
+        {
+          // Now we know that fragment shader even don't need to change.
+          // We can skip ApplyNativeFragmentShader routine after now.
+          mFragmentShaderNeedChange = ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
+
+          // Now we need normal shader type
+          // So decrease NATIVE_SHADER_TYPE_OFFSET.
+          shaderType = static_cast<VisualFactoryCache::ShaderType>(static_cast<int>(shaderType) - NATIVE_SHADER_TYPE_OFFSET);
+
+          // If we already compiled this type already, just use that cached shader.
+          // Else, just go forward.
+          shader = factoryCache.GetShader(shaderType);
+          if(shader)
+          {
+            return shader;
+          }
+        }
+      }
+      else if(mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE)
+      {
+        // Always need to apply fragmentShader
+        bool modified = DevelTexture::ApplyNativeFragmentShader(featureBuilder.mTexture, fragmentShader);
+        DALI_ASSERT_ALWAYS(modified && "NativeImageTexture need to change fragment shader. But DALI default image shader doesn't changed!");
+      }
+    }
+    shader = Shader::New(vertexShader, fragmentShader);
     shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
     factoryCache.SaveShader(shaderType, shader);
   }
index 604b49b..1459614 100644 (file)
@@ -29,41 +29,101 @@ namespace Toolkit
 {
 namespace Internal
 {
+
+/**
+ * ImageVisualShaderFeature contains feature lists what image visual shader need to know.
+ */
+namespace ImageVisualShaderFeature
+{
+namespace TextureAtlas
+{
 /**
  * @brief Whether use texture with atlas, or not
  */
-enum class TextureAtlas
+enum Type
 {
-  DISABLED = 0, ///< Image visual use ATLAS
-  ENABLED       ///< Image visual doesn't use ATLAS
+  DISABLED = 0, ///< Image visual doesn't use ATLAS
+  ENABLED       ///< Image visual uses ATLAS
 };
+} // namespace TextureAtlas
 
+namespace DefaultTextureWrapMode
+{
 /**
  * @brief Whether apply to texture wraping in default, or not
  */
-enum class DefaultTextureWrapMode
+enum Type
 {
-  DO_NOT_APPLY = 0, ///< Image visual doesn't apply to wraping texture in default
-  APPLY             ///< Image visual apply to wraping texture in default
+  APPLY = 0,   ///< Image visual applies to wraping texture in default
+  DO_NOT_APPLY ///< Image visual doesn't apply to wraping texture in default
 };
+} // namespace DefaultTextureWrapMode
 
+namespace RoundedCorner
+{
 /**
  * @brief Whether use rounded corner, or not
  */
-enum class RoundedCorner
+enum Type
 {
   DISABLED = 0, ///< Image visual doesn't use rounded corner
-  ENABLED       ///< Image visual use rounded corner
+  ENABLED       ///< Image visual uses rounded corner
 };
+} // namespace RoundedCorner
 
+namespace Borderline
+{
 /**
  * @brief Whether use borderline, or not
  */
-enum class Borderline
+enum Type
 {
   DISABLED = 0, ///< Image visual doesn't use borderline
-  ENABLED       ///< Image visual use borderline
+  ENABLED       ///< Image visual uses borderline
 };
+} // namespace Borderline
+
+namespace ChangeFragmentShader
+{
+/**
+ * @brief Whether native image change the default fragment shader, or not
+ */
+enum Type
+{
+  DONT_CHANGE = 0, ///< Native image doesn't change default fragment shader.
+  NEED_CHANGE,     ///< Native image changes default fragment shader. We need another shader cache.
+  UNDECIDED,       ///< Undecided.
+};
+} // namespace ChangeFragmentShader
+
+/**
+ * @brief Collection of current image visual feature. Only use for ImageVisualShaderFactory::GetShader()
+ */
+struct FeatureBuilder
+{
+  FeatureBuilder()
+  : mTextureAtlas(TextureAtlas::DISABLED),
+    mDefaultTextureWrapMode(DefaultTextureWrapMode::APPLY),
+    mRoundedCorner(RoundedCorner::DISABLED),
+    mBorderline(Borderline::DISABLED),
+    mTexture()
+  {
+  }
+
+  FeatureBuilder& EnableTextureAtlas(bool enableTextureAtlas);
+  FeatureBuilder& ApplyDefaultTextureWrapMode(bool applyDefaultTextureWrapMode);
+  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
+};
+
+} // namespace ImageVisualShaderFactoryFeature
 
 /**
  * ImageVisualShaderFactory is an object that provides and shares shaders between image visuals
@@ -83,23 +143,21 @@ public:
   ~ImageVisualShaderFactory();
 
   /**
-   * Get the standard image rendering shader.
+   * @brief Get the standard image rendering shader.
    * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
-   * @param[in] atlasing Whether texture atlasing is applied.
-   * @param[in] defaultTextureWrapping Whether the default texture wrap mode is applied.
-   * @param[in] roundedCorner Whether the rounded corder is applied.
-   * @param[in] borderline Whether the borderline of visual is applied.
+   * @param[in] featureBuilder Collection of current image shader's features
+   * @return The standard image rendering shader with features.
    */
-  Shader GetShader(VisualFactoryCache& factoryCache, TextureAtlas atlasing, DefaultTextureWrapMode defaultTextureWrapping, RoundedCorner roundedCorner, Borderline borderline);
+  Shader GetShader(VisualFactoryCache& factoryCache, const ImageVisualShaderFeature::FeatureBuilder& featureBuilder);
 
   /**
-   * Request the default vertex shader source.
+   * @brief Request the default vertex shader source.
    * @return The default vertex shader source.
    */
   std::string_view GetVertexShaderSource();
 
   /**
-   * Request the default fragment shader source.
+   * @brief Request the default fragment shader source.
    * @return The default fragment shader source.
    */
   std::string_view GetFragmentShaderSource();
@@ -116,6 +174,19 @@ protected:
   ImageVisualShaderFactory& operator=(const ImageVisualShaderFactory& rhs);
 
 private:
+
+  /**
+   * @brief Cached information whether native image should change fragment shader.
+   * Default it is ChangeFragmentShader::UNDECIDED.
+   * If we have any chance to check native image source apply fragment shader,
+   * this vaule will be changed one of these : ChangeFragmentShader::DONT_CHANGE or ChangeFragmentShader::NEED_CHANGE
+   *
+   * After result cached, this value will not be changed.
+   *
+   * If value is DONT_CHANGE, ImageVisualShaderFactory::GetShader never call ApplyNativeFragmentShader.
+   * Else, ImageVisualShaderFactory::GetShader will call ApplyNativeFragmentShader if native image source texture come.
+   */
+  ImageVisualShaderFeature::ChangeFragmentShader::Type mFragmentShaderNeedChange : 3;
 };
 
 } // namespace Internal
index 7e404ca..650c508 100644 (file)
@@ -974,59 +974,68 @@ Shader ImageVisual::GenerateShader() const
 {
   Shader shader;
 
-  std::string_view vertexShaderView;
-  bool             usesWholeTexture = true;
-  if(mImpl->mCustomShader && !mImpl->mCustomShader->mVertexShader.empty())
-  {
-    vertexShaderView = mImpl->mCustomShader->mVertexShader;
-    usesWholeTexture = false; // Impossible to tell.
-  }
-  else
-  {
-    vertexShaderView = mImageVisualShaderFactory.GetVertexShaderSource();
-  }
+  bool             usesWholeTexture  = true;
+  const bool       useStandardShader = !mImpl->mCustomShader;
+  const bool       useNativeImage    = (mTextures && DevelTexture::IsNative(mTextures.GetTexture(0)));
 
-  std::string_view fragmentShaderView;
-  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
-  bool        modifiedFragmentShader = false;
-  std::string fragmentShaderString;
-  if(mTextures && DevelTexture::IsNative(mTextures.GetTexture(0)))
-  {
-    Texture nativeTexture  = mTextures.GetTexture(0);
-    fragmentShaderString   = std::string(fragmentShaderView);
-    modifiedFragmentShader = DevelTexture::ApplyNativeFragmentShader(nativeTexture, fragmentShaderString);
-    fragmentShaderView     = fragmentShaderString;
-  }
-
-  const bool useStandardShader = !mImpl->mCustomShader && !modifiedFragmentShader;
   if(useStandardShader)
   {
     // Create and cache the standard shader
     shader = mImageVisualShaderFactory.GetShader(
       mFactoryCache,
-      mImpl->mFlags & Impl::IS_ATLASING_APPLIED ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
-      mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY,
-      IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
-      IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+      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())
     );
   }
-  else if(mImpl->mCustomShader)
-  {
-    shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints);
-  }
   else
   {
-    shader = Shader::New(vertexShaderView, fragmentShaderView);
+    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)
index e87e244..1f48eca 100644 (file)
@@ -378,10 +378,7 @@ void NPatchVisual::OnInitialize()
   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
   Shader   shader   = mImageVisualShaderFactory.GetShader(
     mFactoryCache,
-    TextureAtlas::DISABLED,
-    DefaultTextureWrapMode::APPLY,
-    RoundedCorner::DISABLED,
-    Borderline::DISABLED
+    ImageVisualShaderFeature::FeatureBuilder()
   );
 
   mImpl->mRenderer = Renderer::New(geometry, shader);
index 5d1fff1..25e84fd 100644 (file)
@@ -378,10 +378,10 @@ Shader SvgVisual::GenerateShader() const
   {
     shader = mImageVisualShaderFactory.GetShader(
       mFactoryCache,
-      mAttemptAtlasing ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
-      DefaultTextureWrapMode::APPLY,
-      IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
-      IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+      ImageVisualShaderFeature::FeatureBuilder()
+      .EnableTextureAtlas(mAttemptAtlasing)
+      .EnableRoundedCorner(IsRoundedCornerRequired())
+      .EnableBorderline(IsBorderlineRequired())
     );
   }
   else
index b23c010..deae0b0 100644 (file)
@@ -81,11 +81,15 @@ public:
     GRADIENT_SHADER_RADIAL_USER_SPACE_BORDERLINE,
     GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_BORDERLINE,
     IMAGE_SHADER,
-    IMAGE_SHADER_ATLAS_DEFAULT_WRAP,
-    IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
     IMAGE_SHADER_ROUNDED_CORNER,
     IMAGE_SHADER_BORDERLINE,
     IMAGE_SHADER_ROUNDED_BORDERLINE,
+    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,
     NINE_PATCH_SHADER,
     NINE_PATCH_MASK_SHADER,
     TEXT_SHADER_MULTI_COLOR_TEXT,