Add visualization option for check texture and visual size 55/301955/16
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 28 Nov 2023 09:32:00 +0000 (18:32 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Wed, 6 Dec 2023 01:36:36 +0000 (10:36 +0900)
To support some visualize debugging for app, let we make special
environment value and json script.

By change the json script files by app side, we can debug image visuals freely.

Change-Id: If78d8eb0057ea28ad1b5e0f5f70809c966f2cf3e
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/graphics/shaders/image-visual-shader.frag
dali-toolkit/internal/graphics/shaders/image-visual-shader.vert
dali-toolkit/internal/visuals/image-visual-shader-debug.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/image-visual-shader-debug.h [new file with mode: 0644]
dali-toolkit/internal/visuals/image-visual-shader-factory.cpp
dali-toolkit/styles/debug-image-visual-shader-script.json [new file with mode: 0644]
packaging/dali-toolkit.spec

index 18c086f..e0000ec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -26,7 +26,7 @@
 
 namespace
 {
-const char* DEFAULT_THEME=
+const char* DEFAULT_THEME =
   "{\n"
   "  \"config\":\n"
   "  {\n"
@@ -44,22 +44,37 @@ const char* DEFAULT_THEME=
 
 struct NamedTheme
 {
-  NamedTheme( const std::string& name, const std::string& theme )
-  : name(name), theme(theme)
+  NamedTheme(const std::string& name, const std::string& theme)
+  : name(name),
+    theme(theme)
   {
   }
 
   std::string name;
   std::string theme;
 };
-typedef std::vector< NamedTheme > NamedThemes;
-NamedThemes gThemes;
+typedef std::vector<NamedTheme> NamedThemes;
+NamedThemes                     gThemes;
 
 std::string gTheme;
 std::string gFontFamily("LucidaSans");
 std::string gFontStyle("Regular");
 int         gFontSize(1);
-}
+
+constexpr std::string_view THROW_EXCEPTION_STYLE_FILE_NAME = "throwException";
+class DummyException : public std::exception
+{
+public:
+  DummyException()
+  {
+  }
+
+  const char* what() const throw()
+  {
+    return "DummyException";
+  }
+};
+} // namespace
 
 namespace Dali
 {
@@ -78,12 +93,12 @@ public: // Creation & Destruction
   ~StyleMonitor();
 
 public: // Style Information
-  std::string GetDefaultFontFamily() const;
-  std::string GetDefaultFontStyle() const;
-  float GetDefaultFontSize() const;
+  std::string        GetDefaultFontFamily() const;
+  std::string        GetDefaultFontStyle() const;
+  float              GetDefaultFontSize() const;
   const std::string& GetTheme() const;
-  void SetTheme(std::string theme);
-  bool LoadThemeFile( const std::string& filename, std::string& output );
+  void               SetTheme(std::string theme);
+  bool               LoadThemeFile(const std::string& filename, std::string& output);
 
 public: // Signals
   Dali::StyleMonitor::StyleChangeSignalType& StyleChangeSignal();
@@ -95,18 +110,18 @@ public: // Signals
 
 private:
   Dali::StyleMonitor::StyleChangeSignalType mStyleChangeSignal;
-  static Dali::StyleMonitor mToolkitStyleMonitor;
+  static Dali::StyleMonitor                 mToolkitStyleMonitor;
 
-  std::string mTheme;  ///<< Current theme name
+  std::string mTheme; ///<< Current theme name
 };
 
 Dali::StyleMonitor StyleMonitor::mToolkitStyleMonitor;
 
 Dali::StyleMonitor StyleMonitor::Get()
 {
-  if( ! mToolkitStyleMonitor )
+  if(!mToolkitStyleMonitor)
   {
-    mToolkitStyleMonitor = Dali::StyleMonitor( new Dali::Internal::Adaptor::StyleMonitor() );
+    mToolkitStyleMonitor = Dali::StyleMonitor(new Dali::Internal::Adaptor::StyleMonitor());
   }
   return mToolkitStyleMonitor;
 }
@@ -143,22 +158,27 @@ const std::string& StyleMonitor::GetTheme() const
 void StyleMonitor::SetTheme(std::string path)
 {
   mTheme = path;
-  EmitStyleChangeSignal( StyleChange::THEME_CHANGE );
+  EmitStyleChangeSignal(StyleChange::THEME_CHANGE);
 }
 
-bool StyleMonitor::LoadThemeFile( const std::string& filename, std::string& output )
+bool StyleMonitor::LoadThemeFile(const std::string& filename, std::string& output)
 {
-  for( NamedThemes::iterator iter = gThemes.begin(); iter != gThemes.end(); ++iter )
+  // Throw something exceptions during load file
+  if(filename == THROW_EXCEPTION_STYLE_FILE_NAME)
+  {
+    throw DummyException();
+  }
+  for(NamedThemes::iterator iter = gThemes.begin(); iter != gThemes.end(); ++iter)
   {
     NamedTheme& theme = *iter;
-    if( theme.name == filename )
+    if(theme.name == filename)
     {
       output = theme.theme;
       return true;
     }
   }
 
-  if( !gTheme.empty() )
+  if(!gTheme.empty())
   {
     output = gTheme;
   }
@@ -238,14 +258,14 @@ StyleMonitor::StyleChangeSignalType& StyleMonitor::StyleChangeSignal()
   return GetImplementation(*this).StyleChangeSignal();
 }
 
-bool StyleMonitor::LoadThemeFile( const std::string& filename, std::string& output )
+bool StyleMonitor::LoadThemeFile(const std::string& filename, std::string& output)
 {
   return GetImplementation(*this).LoadThemeFile(filename, output);
 }
 
 StyleMonitor& StyleMonitor::operator=(const StyleMonitor& monitor)
 {
-  if( *this != monitor )
+  if(*this != monitor)
   {
     BaseHandle::operator=(monitor);
   }
@@ -263,20 +283,19 @@ namespace Test
 {
 namespace StyleMonitor
 {
-
-void SetThemeFileOutput( const std::string& name, const std::string& output )
+void SetThemeFileOutput(const std::string& name, const std::string& output)
 {
-  for( NamedThemes::iterator iter = gThemes.begin(); iter != gThemes.end(); ++iter )
+  for(NamedThemes::iterator iter = gThemes.begin(); iter != gThemes.end(); ++iter)
   {
     NamedTheme& theme = *iter;
-    if( theme.name == name )
+    if(theme.name == name)
     {
       theme.theme = output;
       return;
     }
   }
 
-  gThemes.push_back( NamedTheme( name, output ) );
+  gThemes.push_back(NamedTheme(name, output));
 }
 
 void SetDefaultFontFamily(const std::string& family)
@@ -289,10 +308,10 @@ void SetDefaultFontStyle(const std::string& style)
   gFontStyle = style;
 }
 
-void SetDefaultFontSize( float size )
+void SetDefaultFontSize(float size)
 {
   gFontSize = size;
 }
 
-} // StyleMonitor
-} // Test
+} // namespace StyleMonitor
+} // namespace Test
index f63b5cf..63222a0 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <toolkit-environment-variable.h>
 #include <toolkit-event-thread-callback.h>
+#include <toolkit-style-monitor.h>
 #include <toolkit-texture-upload-manager.h>
 #include <toolkit-timer.h>
 
@@ -74,6 +75,22 @@ const char* TEST_N_PATCH_IMAGE_FILE_NAME  = TEST_RESOURCE_DIR "/heartsframe.9.pn
 constexpr auto LOAD_IMAGE_YUV_PLANES_ENV         = "DALI_LOAD_IMAGE_YUV_PLANES";
 constexpr auto ENABLE_DECODE_JPEG_TO_YUV_420_ENV = "DALI_ENABLE_DECODE_JPEG_TO_YUV_420";
 
+constexpr auto DALI_DEBUG_IMAGE_VISUAL_SHADER_ENV = "DALI_DEBUG_IMAGE_VISUAL_SHADER";
+
+constexpr auto DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME_ENV = "DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME";
+
+const char* VALID_DEBUG_SHADER_SCRIPT =
+  "{\n"
+  "  \"maximumColorRate\": 0.5,\n"
+  "  \"redChannelCodes\":\n"
+  "  {\n"
+  "    \"triggerCode\":[\"return\",\" false;\"],\n"
+  "    \"ratioCode\":\"return 0.0;\"\n"
+  "  }\n"
+  "}\n";
+
+constexpr std::string_view THROW_EXCEPTION_STYLE_FILE_NAME = "throwException";
+
 bool             gResourceReadySignalFired = false;
 std::vector<int> gReadyIds                 = {};
 void             ResourceReadySignal(Control control)
@@ -3984,4 +4001,139 @@ int UtcDaliImageVisualLoadFastTrackImagePlanes02(void)
   application.Render();
 
   END_TEST;
+}
+
+int UtcDaliImageVisualDebugImageVisualShaderP1(void)
+{
+  EnvironmentVariable::SetTestEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_ENV, "1");
+  EnvironmentVariable::SetTestEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME_ENV, "validFile"); // Try to load not exist file.
+
+  // Set valid script file
+  Test::StyleMonitor::SetThemeFileOutput("validFile", VALID_DEBUG_SHADER_SCRIPT);
+
+  ToolkitTestApplication application;
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+
+  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));
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 1, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualDebugImageVisualShaderN1(void)
+{
+  EnvironmentVariable::SetTestEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_ENV, "1");
+  EnvironmentVariable::SetTestEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME_ENV, "notJsonFile"); // Try to load exist file, but not a json
+
+  // Set invalid script file
+  Test::StyleMonitor::SetThemeFileOutput("notJsonFile", "1");
+
+  ToolkitTestApplication application;
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+
+  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));
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 1, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualDebugImageVisualShaderN2(void)
+{
+  EnvironmentVariable::SetTestEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_ENV, "1");
+  EnvironmentVariable::SetTestEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME_ENV, std::string(THROW_EXCEPTION_STYLE_FILE_NAME).c_str()); // Try to load file that throw some exception
+
+  // Set throw exception script file
+  Test::StyleMonitor::SetThemeFileOutput(std::string(THROW_EXCEPTION_STYLE_FILE_NAME), "1");
+
+  ToolkitTestApplication application;
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+
+  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));
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 1, TEST_LOCATION);
+
+  END_TEST;
 }
\ No newline at end of file
index 7274e9c..e9ae5b7 100644 (file)
@@ -53,6 +53,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/visuals/text-visual-shader-factory.cpp
    ${toolkit_src_dir}/visuals/text/text-visual.cpp
    ${toolkit_src_dir}/visuals/transition-data-impl.cpp
+   ${toolkit_src_dir}/visuals/image-visual-shader-debug.cpp
    ${toolkit_src_dir}/visuals/image-visual-shader-factory.cpp
    ${toolkit_src_dir}/visuals/image-visual-shader-feature-builder.cpp
    ${toolkit_src_dir}/visuals/visual-base-data-impl.cpp
index f13f865..12ba3c4 100644 (file)
@@ -1,5 +1,5 @@
 INPUT mediump vec2 vTexCoord;
-#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
+#if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
 INPUT mediump vec2 vPosition;
 INPUT mediump vec2 vRectSize;
 INPUT mediump vec2 vOptRectSize;
@@ -28,6 +28,11 @@ uniform mediump vec4 uAtlasRect;
 uniform lowp vec2 wrapMode;
 #endif
 
+
+#if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER)
+uniform highp vec3 uScale;
+#endif
+
 uniform lowp vec4 uColor;
 uniform lowp vec3 mixColor;
 uniform lowp float preMultipliedAlpha;
@@ -50,7 +55,7 @@ mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp
 }
 #endif
 
-#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
+#if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
 // Global values both rounded corner and borderline use
 
 // radius of rounded corner on this quadrant
@@ -238,6 +243,122 @@ lowp vec4 ConvertYuvToRgba(mediump vec2 texCoord)
 }
 #endif
 
+#ifdef IS_REQUIRED_DEBUG_VISUAL_SHADER
+
+// Predefined values whether some macro defined or not.
+// Since we make debug codes replace by macro,
+// sharp if keyword cannot be used.
+// Instead, let we use bool values so we can use define checked in script
+#ifdef IS_REQUIRED_ROUNDED_CORNER
+const bool IS_REQUIRED_ROUNDED_CORNER_BOOL = true;
+#else
+const bool IS_REQUIRED_ROUNDED_CORNER_BOOL = false;
+#endif
+#ifdef IS_REQUIRED_BORDERLINE
+const bool IS_REQUIRED_BORDERLINE_BOOL = true;
+#else
+const bool IS_REQUIRED_BORDERLINE_BOOL = false;
+#endif
+#ifdef IS_REQUIRED_YUV_TO_RGB
+const bool IS_REQUIRED_YUV_TO_RGB_BOOL = true;
+#else
+const bool IS_REQUIRED_YUV_TO_RGB_BOOL = false;
+#endif
+#ifdef IS_REQUIRED_UNIFIED_YUV_AND_RGB
+const bool IS_REQUIRED_UNIFIED_YUV_AND_RGB_BOOL = true;
+#else
+const bool IS_REQUIRED_UNIFIED_YUV_AND_RGB_BOOL = false;
+#endif
+#ifdef IS_REQUIRED_ALPHA_MASKING
+const bool IS_REQUIRED_ALPHA_MASKING_BOOL = true;
+#else
+const bool IS_REQUIRED_ALPHA_MASKING_BOOL = false;
+#endif
+#ifdef ATLAS_DEFAULT_WARP
+const bool ATLAS_DEFAULT_WARP_BOOL = true;
+#else
+const bool ATLAS_DEFAULT_WARP_BOOL = false;
+#endif
+#ifdef ATLAS_CUSTOM_WARP
+const bool ATLAS_CUSTOM_WARP_BOOL = true;
+#else
+const bool ATLAS_CUSTOM_WARP_BOOL = false;
+#endif
+
+// These lines in the shader may be replaced with actual definitions by the debug-image-visual-shader-script.json.
+// DEBUG_TRIGGER_CODE return bool type, and DEBUG_RATIO_CODE return float value which will be clamped between 0.0 and 1.0
+// If DEBUG_TRIGGER_CODE return true, it mean we will change final color's channel value.
+// If ratio is 0.0, debug color rate become MINIMUM_DEBUG_COLOR_RATE, and 1.0 than MAXIMUM_DEBUG_COLOR_RATE.
+#define MINIMUM_DEBUG_COLOR_RATE
+#define MAXIMUM_DEBUG_COLOR_RATE
+#define DEBUG_TRIGGER_RED_CODE
+#define DEBUG_TRIGGER_GREEN_CODE
+#define DEBUG_TRIGGER_BLUE_CODE
+#define DEBUG_RATIO_RED_CODE
+#define DEBUG_RATIO_GREEN_CODE
+#define DEBUG_RATIO_BLUE_CODE
+
+const mediump float gMinDebugColorRate = MINIMUM_DEBUG_COLOR_RATE;
+const mediump float gMaxDebugColorRate = MAXIMUM_DEBUG_COLOR_RATE;
+
+bool DebugTriggerRed(mediump vec4 originColor)
+{
+  DEBUG_TRIGGER_RED_CODE
+}
+
+bool DebugTriggerGreen(mediump vec4 originColor)
+{
+  DEBUG_TRIGGER_GREEN_CODE
+}
+
+bool DebugTriggerBlue(mediump vec4 originColor)
+{
+  DEBUG_TRIGGER_BLUE_CODE
+}
+
+mediump float DebugRatioRed(mediump vec4 originColor)
+{
+  DEBUG_RATIO_RED_CODE
+}
+
+mediump float DebugRatioGreen(mediump vec4 originColor)
+{
+  DEBUG_RATIO_GREEN_CODE
+}
+
+mediump float DebugRatioBlue(mediump vec4 originColor)
+{
+  DEBUG_RATIO_BLUE_CODE
+}
+
+mediump vec3 ApplyDebugMixColor(mediump vec4 originColor)
+{
+  mediump float debugColorRateRed = 0.0;
+  mediump float debugColorRateGreen = 0.0;
+  mediump float debugColorRateBlue = 0.0;
+
+  if(DebugTriggerRed(originColor))
+  {
+    debugColorRateRed = mix(gMinDebugColorRate, gMaxDebugColorRate, smoothstep(0.0, 1.0, DebugRatioRed(originColor)));
+  }
+  if(DebugTriggerGreen(originColor))
+  {
+    debugColorRateGreen = mix(gMinDebugColorRate, gMaxDebugColorRate, smoothstep(0.0, 1.0, DebugRatioGreen(originColor)));
+  }
+  if(DebugTriggerBlue(originColor))
+  {
+    debugColorRateBlue = mix(gMinDebugColorRate, gMaxDebugColorRate, smoothstep(0.0, 1.0, DebugRatioBlue(originColor)));
+  }
+
+  mediump float colorRate = max(debugColorRateRed, max(debugColorRateGreen, debugColorRateBlue));
+  mediump vec3 debugColor = vec3(debugColorRateRed, debugColorRateGreen, debugColorRateBlue);
+
+  debugColor *= mix(1.0, originColor.a, preMultipliedAlpha);
+
+  return originColor.rgb * (1.0 - colorRate) + debugColor;
+}
+#endif
+
 void main()
 {
 #ifdef ATLAS_DEFAULT_WARP
@@ -263,13 +384,15 @@ void main()
   textureColor.rgb *= mix(1.0, maskAlpha, preMultipliedAlpha);
 #endif
 
-#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
+#if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
+#ifndef IS_REQUIRED_DEBUG_VISUAL_SHADER
   // skip most potential calculate for performance
   if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
   {
     OUT_COLOR = textureColor;
   }
   else
+#endif
   {
     PreprocessPotential();
 #endif
@@ -285,7 +408,11 @@ void main()
     OUT_COLOR.rgb *= mix(1.0, opacity, preMultipliedAlpha);
 #endif
 
-#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
+#if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
   }
 #endif
+
+#ifdef IS_REQUIRED_DEBUG_VISUAL_SHADER
+  OUT_COLOR.rgb = ApplyDebugMixColor(OUT_COLOR);
+#endif
 }
index 6109c29..d5b4fcf 100644 (file)
@@ -1,6 +1,6 @@
 INPUT mediump vec2 aPosition;
 OUTPUT mediump vec2 vTexCoord;
-#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
+#if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
 OUTPUT mediump vec2 vPosition;
 OUTPUT mediump vec2 vRectSize;
 OUTPUT mediump vec2 vOptRectSize;
@@ -14,7 +14,7 @@ uniform highp mat4 uMvpMatrix;
 uniform highp vec3 uSize;
 uniform mediump vec4 pixelArea;
 
-#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
+#if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
 // Be used when we calculate anti-alias range near 1 pixel.
 uniform highp vec3 uScale;
 #endif
@@ -45,7 +45,7 @@ vec4 ComputeVertexPosition()
   vec2 visualSize = mix(size * uSize.xy, size, offsetSizeMode.zw) + extraSize;
   vec2 visualOffset = mix(offset * uSize.xy, offset, offsetSizeMode.xy);
 
-#if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
+#if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
   vRectSize = visualSize * 0.5;
   vOptRectSize = vRectSize;
 
@@ -86,7 +86,7 @@ vec4 ComputeVertexPosition()
 #ifdef IS_REQUIRED_BORDERLINE
   vPosition = aPosition * (visualSize + outerBorderlineSize + vertexMargin);
   vOptRectSize -= (borderlineWidth - outerBorderlineSize * 0.5) + 1.0;
-#elif defined(IS_REQUIRED_ROUNDED_CORNER)
+#elif defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER)
   vPosition = aPosition * (visualSize + vertexMargin);
 #else
   mediump vec2 vPosition = aPosition * visualSize;
diff --git a/dali-toolkit/internal/visuals/image-visual-shader-debug.cpp b/dali-toolkit/internal/visuals/image-visual-shader-debug.cpp
new file mode 100644 (file)
index 0000000..057d356
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/visuals/image-visual-shader-debug.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
+#include <dali/devel-api/adaptor-framework/style-monitor.h> ///< for load json file.
+
+#include <regex> ///< for redefine shader
+#include <string_view>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/devel-api/builder/json-parser.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+constexpr auto DALI_DEBUG_IMAGE_VISUAL_SHADER_ENV = "DALI_DEBUG_IMAGE_VISUAL_SHADER";
+
+bool DebugImageVisualShaderEnvironmentEnabled()
+{
+  static bool enabled       = false;
+  static bool enabledSetted = false;
+  if(!enabledSetted)
+  {
+    enabledSetted           = true;
+    auto debugEnabledString = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_ENV);
+    enabled                 = debugEnabledString ? std::atoi(debugEnabledString) : false;
+  }
+  return enabled;
+}
+
+constexpr auto DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME_ENV = "DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME";
+constexpr auto DEFAULT_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME  = "debug-image-visual-shader-script.json";
+
+const std::string& GetScriptFilename()
+{
+  // Set the full path for the default script file.
+  const static std::string styleDirPath{AssetManager::GetDaliStylePath()};
+  static std::string       mScriptFileName{};
+
+  if(DALI_UNLIKELY(mScriptFileName.empty()))
+  {
+    // Use user's own script if exist.
+    auto environmentScriptFilename = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME_ENV);
+
+    mScriptFileName = environmentScriptFilename ? std::string(environmentScriptFilename) : styleDirPath + std::string(DEFAULT_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME);
+
+    DALI_ASSERT_DEBUG(0 != mScriptFileName.length());
+  }
+
+  return mScriptFileName;
+}
+
+bool LoadJsonScript(std::string& stringOut)
+{
+  auto styleMonitor = StyleMonitor::Get();
+
+  // as toolkit is platform agnostic, it cannot load files from filesystem
+  // ask style monitor to load the style sheet
+  if(styleMonitor)
+  {
+    try
+    {
+      return styleMonitor.LoadThemeFile(GetScriptFilename(), stringOut);
+    }
+    catch(const std::exception& e)
+    {
+      DALI_LOG_ERROR("Something system exception throwed during load script file![%s]\n", GetScriptFilename().c_str());
+      DALI_LOG_ERROR("Error message : [%s]\n", e.what());
+    }
+    catch(const Dali::DaliException& e)
+    {
+      DALI_LOG_ERROR("Something Dali exception throwed during load script file![%s]\n", GetScriptFilename().c_str());
+      DALI_LOG_ERROR("Error message : [%s]\n", e.condition);
+    }
+    catch(...)
+    {
+      DALI_LOG_ERROR("Something unkown exception throwed during load script file![%s]\n", GetScriptFilename().c_str());
+    }
+  }
+
+  return false;
+}
+// Json keywords what we will get information from json.
+constexpr std::string_view MINIMUM_DEBUG_COLOR_RATE_JSON_KEY = "minimumColorRate";
+constexpr std::string_view MAXIMUM_DEBUG_COLOR_RATE_JSON_KEY = "maximumColorRate";
+constexpr std::string_view DEBUG_RED_CHANNEL_CODE_JSON_KEY   = "redChannelCodes";
+constexpr std::string_view DEBUG_GREEN_CHANNEL_CODE_JSON_KEY = "greenChannelCodes";
+constexpr std::string_view DEBUG_BLUE_CHANNEL_CODE_JSON_KEY  = "blueChannelCodes";
+constexpr std::string_view DEBUG_TRIGGER_CODE_JSON_KEY       = "triggerCode";
+constexpr std::string_view DEBUG_RATIO_CODE_JSON_KEY         = "ratioCode";
+
+// Macro keywords what we will replace at fragment shader.
+constexpr std::string_view MINIMUM_DEBUG_COLOR_RATE_MACRO_KEY = "MINIMUM_DEBUG_COLOR_RATE";
+constexpr std::string_view MAXIMUM_DEBUG_COLOR_RATE_MACRO_KEY = "MAXIMUM_DEBUG_COLOR_RATE";
+constexpr std::string_view DEBUG_TRIGGER_RED_CODE_MACRO_KEY   = "DEBUG_TRIGGER_RED_CODE";
+constexpr std::string_view DEBUG_TRIGGER_GREEN_CODE_MACRO_KEY = "DEBUG_TRIGGER_GREEN_CODE";
+constexpr std::string_view DEBUG_TRIGGER_BLUE_CODE_MACRO_KEY  = "DEBUG_TRIGGER_BLUE_CODE";
+constexpr std::string_view DEBUG_RATIO_RED_CODE_MACRO_KEY     = "DEBUG_RATIO_RED_CODE";
+constexpr std::string_view DEBUG_RATIO_GREEN_CODE_MACRO_KEY   = "DEBUG_RATIO_GREEN_CODE";
+constexpr std::string_view DEBUG_RATIO_BLUE_CODE_MACRO_KEY    = "DEBUG_RATIO_BLUE_CODE";
+
+// Default macro keywords when we fail to parse script.
+constexpr std::string_view DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE   = "0.0";
+constexpr std::string_view DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE = "return false;";
+constexpr std::string_view DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE   = "return 0.0;";
+
+bool ParseScriptInfomation(Property::Map& result)
+{
+  std::string stringOut;
+  if(!LoadJsonScript(stringOut))
+  {
+    DALI_LOG_ERROR("Fail to load script file [%s]\n", GetScriptFilename().c_str());
+    return false;
+  }
+
+  Toolkit::JsonParser parser = Toolkit::JsonParser::New();
+
+  if(!parser.Parse(stringOut))
+  {
+    std::ostringstream stream;
+    if(parser.ParseError())
+    {
+      stream << "position: " << parser.GetErrorPosition() << ", line: " << parser.GetErrorLineNumber() << ", column: " << parser.GetErrorColumn() << ", description: " << parser.GetErrorDescription() << ".";
+    }
+    DALI_LOG_ERROR("Fail to parse json script\nError : %s\nJson : %s\n", stream.str().c_str(), stringOut.c_str());
+    return false;
+  }
+
+  const auto* rootNode = parser.GetRoot();
+  if(!rootNode)
+  {
+    DALI_LOG_ERROR("Fail to get root node\n");
+    return false;
+  }
+
+  auto InsertScriptMap = [](Property::Map& result, const TreeNode* node, const std::string_view& jsonKey, const std::string_view& macroKey, const std::string_view& defaultValue) {
+    std::ostringstream oss;
+    oss.clear();
+
+    if(node)
+    {
+      const auto* childNode = node->GetChild(jsonKey);
+
+      if(childNode)
+      {
+        if(childNode->GetType() == TreeNode::FLOAT)
+        {
+          oss << childNode->GetFloat();
+        }
+        else if(childNode->GetType() == TreeNode::STRING)
+        {
+          oss << childNode->GetString();
+        }
+        else if(childNode->GetType() == TreeNode::ARRAY)
+        {
+          // Concat strings with line feed
+          bool isFirst = true;
+          for(auto iter = childNode->CBegin(), endIter = childNode->CEnd(); iter != endIter; ++iter)
+          {
+            if((*iter).second.GetType() == TreeNode::STRING)
+            {
+              if(isFirst)
+              {
+                isFirst = false;
+              }
+              else
+              {
+                oss << "\n";
+              }
+              oss << (*iter).second.GetString();
+            }
+          }
+        }
+      }
+    }
+
+    if(oss.str().empty())
+    {
+      oss << defaultValue;
+    }
+    result.Insert(std::string(macroKey), oss.str());
+  };
+
+  auto InsertChannelScriptMap = [&InsertScriptMap](Property::Map& result, const TreeNode* node, const std::string_view& channelJsonKey, const std::string_view& triggerMacroKey, const std::string_view& ratioMacroKey) {
+    const auto* channelNode = node->GetChild(channelJsonKey);
+    InsertScriptMap(result, channelNode, DEBUG_TRIGGER_CODE_JSON_KEY, triggerMacroKey, DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE);
+    InsertScriptMap(result, channelNode, DEBUG_RATIO_CODE_JSON_KEY, ratioMacroKey, DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE);
+  };
+
+  // Get color rate
+  InsertScriptMap(result, rootNode, MINIMUM_DEBUG_COLOR_RATE_JSON_KEY, MINIMUM_DEBUG_COLOR_RATE_MACRO_KEY, DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE);
+  InsertScriptMap(result, rootNode, MAXIMUM_DEBUG_COLOR_RATE_JSON_KEY, MAXIMUM_DEBUG_COLOR_RATE_MACRO_KEY, DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE);
+
+  // Get each color ChannelCodes
+  InsertChannelScriptMap(result, rootNode, DEBUG_RED_CHANNEL_CODE_JSON_KEY, DEBUG_TRIGGER_RED_CODE_MACRO_KEY, DEBUG_RATIO_RED_CODE_MACRO_KEY);
+  InsertChannelScriptMap(result, rootNode, DEBUG_GREEN_CHANNEL_CODE_JSON_KEY, DEBUG_TRIGGER_GREEN_CODE_MACRO_KEY, DEBUG_RATIO_GREEN_CODE_MACRO_KEY);
+  InsertChannelScriptMap(result, rootNode, DEBUG_BLUE_CHANNEL_CODE_JSON_KEY, DEBUG_TRIGGER_BLUE_CODE_MACRO_KEY, DEBUG_RATIO_BLUE_CODE_MACRO_KEY);
+
+  return true;
+}
+
+const Property::Map& GetScriptInfomation()
+{
+  static Property::Map result;
+
+  if(DALI_UNLIKELY(result.Empty()))
+  {
+    if(!ParseScriptInfomation(result))
+    {
+      // Use default script information if parse failed.
+      result.Clear();
+
+      result.Insert(std::string(MINIMUM_DEBUG_COLOR_RATE_MACRO_KEY), std::string(DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE));
+      result.Insert(std::string(MAXIMUM_DEBUG_COLOR_RATE_MACRO_KEY), std::string(DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE));
+      result.Insert(std::string(DEBUG_TRIGGER_RED_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE));
+      result.Insert(std::string(DEBUG_TRIGGER_GREEN_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE));
+      result.Insert(std::string(DEBUG_TRIGGER_BLUE_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE));
+      result.Insert(std::string(DEBUG_RATIO_RED_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE));
+      result.Insert(std::string(DEBUG_RATIO_GREEN_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE));
+      result.Insert(std::string(DEBUG_RATIO_BLUE_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE));
+    }
+  }
+
+  return result;
+}
+
+void RedefineMacro(std::string& shaderCode, std::string macro, std::string value)
+{
+  std::string definition = "#define " + macro;
+  std::size_t found      = shaderCode.find(definition);
+  DALI_ASSERT_ALWAYS(found != std::string::npos && "Macro keyword was not exist in shader code!");
+
+  std::size_t insertionPoint = found + definition.length();
+
+  // Automatically insert line-continuation character into value
+  std::regex                 re("\n");
+  std::sregex_token_iterator first{value.begin(), value.end(), re, -1}, last;
+  for(auto i = first; i != last; ++i)
+  {
+    std::string line = std::string(" \\\n") + (*i).str();
+    shaderCode.insert(insertionPoint, line);
+    insertionPoint += line.length();
+  }
+}
+
+} // namespace
+
+namespace ImageVisualShaderDebug
+{
+bool DebugImageVisualShaderEnabled()
+{
+  return DebugImageVisualShaderEnvironmentEnabled();
+}
+
+void ApplyImageVisualShaderDebugScriptCode(std::string& fragmentShader)
+{
+  const auto& resultMap = GetScriptInfomation();
+
+  for(std::size_t i = 0u; i < resultMap.Count(); ++i)
+  {
+    auto key   = resultMap.GetKeyAt(i);
+    auto value = resultMap.GetValue(i);
+
+    RedefineMacro(fragmentShader, std::move(key.stringKey), std::move(value.Get<std::string>()));
+  }
+}
+} // namespace ImageVisualShaderDebug
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/image-visual-shader-debug.h b/dali-toolkit/internal/visuals/image-visual-shader-debug.h
new file mode 100644 (file)
index 0000000..972ff56
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef DALI_TOOLKIT_IMAGE_VISUAL_SHADER_DEBUG_H
+#define DALI_TOOLKIT_IMAGE_VISUAL_SHADER_DEBUG_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace ImageVisualShaderDebug
+{
+/**
+ * @brief Check whether we need to use debug option for image visual.
+ *
+ * @return True if ImageVisualShader relative environment on. False otherwise.
+ */
+bool DebugImageVisualShaderEnabled();
+
+/**
+ * @brief Apply fragment shader use debug script.
+ *
+ * @param[in, out] fragmentShader Shader code to apply debug script.
+ */
+void ApplyImageVisualShaderDebugScriptCode(std::string& fragmentShader);
+
+} // namespace ImageVisualShaderDebug
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_VISUAL_SHADER_DEBUG_H
index 7bbe186..1f3092f 100644 (file)
@@ -22,6 +22,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+#include <dali-toolkit/internal/visuals/image-visual-shader-debug.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali/integration-api/debug.h>
 
@@ -35,31 +36,29 @@ namespace
 {
 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 
-const int                         NATIVE_SHADER_TYPE_OFFSET = VisualFactoryCache::ShaderType::NATIVE_IMAGE_SHADER - VisualFactoryCache::ShaderType::IMAGE_SHADER;
-static constexpr std::string_view Y_FLIP_MASK_TEXTURE       = "uYFlipMaskTexture";
-static constexpr float            NOT_FLIP_MASK_TEXTURE     = 0.0f;
-} // unnamed namespace
+constexpr int              NATIVE_SHADER_TYPE_OFFSET = VisualFactoryCache::ShaderType::NATIVE_IMAGE_SHADER - VisualFactoryCache::ShaderType::IMAGE_SHADER;
+constexpr std::string_view Y_FLIP_MASK_TEXTURE       = "uYFlipMaskTexture";
+constexpr float            NOT_FLIP_MASK_TEXTURE     = 0.0f;
 
-static constexpr auto          SHADER_TYPE_COUNT = 6u;
+constexpr auto SHADER_TYPE_COUNT = 6u;
 
-const std::string_view VertexPredefines[SHADER_TYPE_COUNT]
-{
-  "", // VisualFactoryCache::IMAGE_SHADER,
-  "#define IS_REQUIRED_ROUNDED_CORNER\n", //VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
-  "",//VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
-  "#define IS_REQUIRED_ROUNDED_CORNER\n",//VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
-  "",//VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
-  "#define IS_REQUIRED_ROUNDED_CORNER\n",//VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
+constexpr std::string_view VertexPredefines[SHADER_TYPE_COUNT]{
+  "",                                     // VisualFactoryCache::IMAGE_SHADER,
+  "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
+  "",                                     // VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
+  "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
+  "",                                     // VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
+  "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
 };
-const std::string_view FragmentPredefines[SHADER_TYPE_COUNT]
-{
-  "", // VisualFactoryCache::IMAGE_SHADER,
-  "#define IS_REQUIRED_ROUNDED_CORNER\n", //VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
-  "#define IS_REQUIRED_YUV_TO_RGB\n",//VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
-  "#define IS_REQUIRED_YUV_TO_RGB\n#define IS_REQUIRED_ROUNDED_CORNER\n",//VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
-  "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n",//VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
-  "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n#define IS_REQUIRED_ROUNDED_CORNER\n",//VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
+constexpr std::string_view FragmentPredefines[SHADER_TYPE_COUNT]{
+  "",                                                                              // VisualFactoryCache::IMAGE_SHADER,
+  "#define IS_REQUIRED_ROUNDED_CORNER\n",                                          // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
+  "#define IS_REQUIRED_YUV_TO_RGB\n",                                              // VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
+  "#define IS_REQUIRED_YUV_TO_RGB\n#define IS_REQUIRED_ROUNDED_CORNER\n",          // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
+  "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n",                                     // VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
+  "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
 };
+} // unnamed namespace
 
 ImageVisualShaderFactory::ImageVisualShaderFactory()
 : mFragmentShaderNeedChange(ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED)
@@ -93,9 +92,20 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, Ima
   featureBuilder.GetVertexShaderPrefixList(vertexShaderPrefixList);
   featureBuilder.GetFragmentShaderPrefixList(fragmentShaderPrefixList);
 
+  if(Dali::Toolkit::Internal::ImageVisualShaderDebug::DebugImageVisualShaderEnabled())
+  {
+    vertexShaderPrefixList += "#define IS_REQUIRED_DEBUG_VISUAL_SHADER\n";
+    fragmentShaderPrefixList += "#define IS_REQUIRED_DEBUG_VISUAL_SHADER\n";
+  }
+
   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(Dali::Toolkit::Internal::ImageVisualShaderDebug::DebugImageVisualShaderEnabled())
+  {
+    Dali::Toolkit::Internal::ImageVisualShaderDebug::ApplyImageVisualShaderDebugScriptCode(fragmentShader);
+  }
+
   if(featureBuilder.NeedToChangeFragmentShader() == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE)
   {
     bool modified = DevelTexture::ApplyNativeFragmentShader(featureBuilder.GetTexture(), fragmentShader);
@@ -159,19 +169,19 @@ void ImageVisualShaderFactory::GetPreCompiledShader(RawShaderData& shaders)
   std::vector<std::string_view> vertexPrefix;
   std::vector<std::string_view> fragmentPrefix;
   shaders.shaderCount = 0;
-  int shaderCount = 0;
-  for(uint32_t i=0; i< SHADER_TYPE_COUNT; ++i)
+  int shaderCount     = 0;
+  for(uint32_t i = 0; i < SHADER_TYPE_COUNT; ++i)
   {
     vertexPrefix.push_back(VertexPredefines[i]);
     fragmentPrefix.push_back(FragmentPredefines[i]);
     shaderCount++;
   }
 
-  shaders.vertexPrefix= vertexPrefix;
+  shaders.vertexPrefix   = vertexPrefix;
   shaders.fragmentPrefix = fragmentPrefix;
-  shaders.vertexShader = SHADER_IMAGE_VISUAL_SHADER_VERT;
+  shaders.vertexShader   = SHADER_IMAGE_VISUAL_SHADER_VERT;
   shaders.fragmentShader = SHADER_IMAGE_VISUAL_SHADER_FRAG;
-  shaders.shaderCount = shaderCount;
+  shaders.shaderCount    = shaderCount;
 }
 
 } // namespace Internal
diff --git a/dali-toolkit/styles/debug-image-visual-shader-script.json b/dali-toolkit/styles/debug-image-visual-shader-script.json
new file mode 100644 (file)
index 0000000..eb53e94
--- /dev/null
@@ -0,0 +1,49 @@
+//******************************************************************************
+//
+// Default debug image visual shader script for dali-toolkit
+// It will be used only if export DALI_DEBUG_IMAGE_VISUAL_SHADER=1
+//
+//******************************************************************************
+{
+  // Range of color rate for debug
+  "minimumColorRate": 0.2,
+  "maximumColorRate": "0.7",
+
+  // Logic for red. (It show if we use YUV image)
+  // We can use macro keyword was defined or not by ~~_BOOL value.
+  "redChannelCodes":
+  {
+    "triggerCode":
+    [
+      "return IS_REQUIRED_YUV_TO_RGB_BOOL;"
+    ],
+    "ratioCode": "return 1.0;"
+  },
+
+  // Logic for green. (It show if we use unified YUV and RGB shader)
+  "greenChannelCodes":
+  {
+    "triggerCode": "return IS_REQUIRED_UNIFIED_YUV_AND_RGB_BOOL;",
+    "ratioCode":
+    [
+      "return 1.0;"
+    ]
+  },
+
+  // Logic for blue. (It show when we use GPU masking)
+  // Note that we can seperate each line as array.
+  "blueChannelCodes":
+  {
+    "triggerCode":
+    [
+      "bool triggerReturn = IS_REQUIRED_ALPHA_MASKING_BOOL;",
+      "",
+      "return triggerReturn;"
+    ],
+    "ratioCode":
+    [
+      "mediump float alpha = originColor.a;",
+      "return step(0.5, alpha);"
+    ]
+  }
+}
index 2e4dd65..a87c81b 100644 (file)
@@ -262,6 +262,9 @@ cp -r dali-toolkit/styles/1920x1080_rpi/* %{buildroot}%{dali_toolkit_style_files
 
 # Copy default feedback theme
 cp dali-toolkit/styles/default-feedback-theme.json %{buildroot}%{dali_toolkit_style_files}
+
+# Copy default debug image visual shader script
+cp dali-toolkit/styles/debug-image-visual-shader-script.json %{buildroot}%{dali_toolkit_style_files}
 popd
 
 ##############################
@@ -481,6 +484,7 @@ esac
 %{dali_toolkit_image_files}/*
 %{dali_toolkit_sound_files}/*
 %{dali_toolkit_style_files}/360x360/*
+%{dali_toolkit_style_files}/debug-image-visual-shader-script.json
 %{dali_toolkit_style_files}/default-feedback-theme.json
 %{_datadir}/locale/*/LC_MESSAGES/*
 
@@ -490,6 +494,7 @@ esac
 %{dali_toolkit_image_files}/*
 %{dali_toolkit_sound_files}/*
 %{dali_toolkit_style_files}/480x800/*
+%{dali_toolkit_style_files}/debug-image-visual-shader-script.json
 %{dali_toolkit_style_files}/default-feedback-theme.json
 %{_datadir}/locale/*/LC_MESSAGES/*
 
@@ -499,6 +504,7 @@ esac
 %{dali_toolkit_image_files}/*
 %{dali_toolkit_sound_files}/*
 %{dali_toolkit_style_files}/720x1280/*
+%{dali_toolkit_style_files}/debug-image-visual-shader-script.json
 %{dali_toolkit_style_files}/default-feedback-theme.json
 %{_datadir}/locale/*/LC_MESSAGES/*
 
@@ -508,6 +514,7 @@ esac
 %{dali_toolkit_image_files}/*
 %{dali_toolkit_sound_files}/*
 %{dali_toolkit_style_files}/1920x1080/*
+%{dali_toolkit_style_files}/debug-image-visual-shader-script.json
 %{dali_toolkit_style_files}/default-feedback-theme.json
 %{_datadir}/locale/*/LC_MESSAGES/*
 
@@ -517,6 +524,7 @@ esac
 %{dali_toolkit_image_files}/*
 %{dali_toolkit_sound_files}/*
 %{dali_toolkit_style_files}/1920x1080_rpi/*
+%{dali_toolkit_style_files}/debug-image-visual-shader-script.json
 %{dali_toolkit_style_files}/default-feedback-theme.json
 %{_datadir}/locale/*/LC_MESSAGES/*