Make PreMultiplied as true if image doesn't have alpha channel 79/318079/9
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 24 Sep 2024 08:01:28 +0000 (17:01 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Fri, 1 Nov 2024 01:54:58 +0000 (10:54 +0900)
Since the rendering result don't have any effort if image don't have
alpha channel, we can assume that non-alpha pixel format like RGB888
is alpha premultiplied.

PreMultiplyAlpha will increase the rendering performance usally.
So we can assume that they are pre muliplied already.

Change-Id: I286ad70aa20cadc09eebee2c01a30c22a289fcf4
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
dali-toolkit/internal/image-loader/fast-track-loading-task.cpp
dali-toolkit/internal/image-loader/loading-task.cpp
dali-toolkit/internal/texture-manager/texture-cache-manager.cpp
dali-toolkit/internal/texture-manager/texture-manager-impl.cpp

index 04f95370dd2d706ef11d47bf4e9d44a542fcf950..aef362b7e935bfca34ac143572b406ce1c9017d0 100644 (file)
@@ -66,6 +66,8 @@ const char* TEST_IMAGE_3_FILE_NAME = TEST_RESOURCE_DIR "/icon-edit.png";
 const char* TEST_IMAGE_4_FILE_NAME = TEST_RESOURCE_DIR "/application-icon-20.png";
 const char* TEST_MASK_FILE_NAME    = TEST_RESOURCE_DIR "/mask.png";
 
+const char* TEST_COMPRESSED_ALPHA_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/RGBA_ASTC_4x4.ktx";
+
 const char* TEST_SVG_FILE_NAME                   = TEST_RESOURCE_DIR "/svg1.svg";
 const char* TEST_ANIMATED_VECTOR_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/insta_camera.json";
 
@@ -2330,7 +2332,7 @@ int UtcTextureManagerCachingForDifferentMultiplyOnLoad(void)
   ToolkitTestApplication application;
   tet_infoline("UtcTextureManagerCachingForDifferentMultiplyOnLoad");
   tet_infoline("Observe1 multiply on load, and Observer2, 3 don't multiply on load.");
-  tet_infoline("We will use jpg image, with will not premultiply alpha even if we try to load without multiply.");
+  tet_infoline("We will use compressed image with alpha channel, with will not premultiply alpha even if we try to load without multiply.");
 
   tet_infoline("Let we request Observer1 and Observer2 sequencely.");
   tet_infoline("After Observer1 complete, we will cache -premultiplyOnLoad = true, premultiplied = false;");
@@ -2342,7 +2344,7 @@ int UtcTextureManagerCachingForDifferentMultiplyOnLoad(void)
   TestObserver observer1;
   TestObserver observer2;
   TestObserver observer3;
-  std::string  filename(TEST_IMAGE_FILE_NAME);
+  std::string  filename(TEST_COMPRESSED_ALPHA_IMAGE_FILE_NAME);
   auto         preMultiply = TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD;
   textureManager.RequestLoad(
     filename,
index c60d4eeb24b07a5755d70ba9952be821502b183c..c53e1c25ea00541754fc3dcdca434bd243ee5462 100644 (file)
@@ -78,6 +78,8 @@ static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
 // resolution: 600*600, pixel format: RGB888
 static const char* gImage_600_RGB = TEST_RESOURCE_DIR "/test-image-600.jpg";
 
+const char* TEST_COMPRESSED_ALPHA_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/RGBA_ASTC_4x4.ktx";
+
 // resolution: 50*50, frame count: 4, frame delay: 0.2 second for each frame
 const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif";
 
@@ -437,7 +439,97 @@ int UtcDaliImageViewPreMultipliedAlphaJpg(void)
 
   value = imageView1.GetProperty(ImageView::Property::PRE_MULTIPLIED_ALPHA);
   DALI_TEST_CHECK(value.Get(enable));
-  DALI_TEST_CHECK(!enable); // Should be false after loading
+  DALI_TEST_CHECK(enable); // Should be true after loading, Since RGB format works same as premuliplied alpha with 1.0.
+
+  // conventional alpha blending
+  Renderer renderer1 = imageView1.GetRendererAt(0);
+  value              = renderer1.GetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA);
+  DALI_TEST_CHECK(value.Get(enable));
+  DALI_TEST_CHECK(enable);
+
+  int srcFactorRgb    = renderer1.GetProperty<int>(Renderer::Property::BLEND_FACTOR_SRC_RGB);
+  int destFactorRgb   = renderer1.GetProperty<int>(Renderer::Property::BLEND_FACTOR_DEST_RGB);
+  int srcFactorAlpha  = renderer1.GetProperty<int>(Renderer::Property::BLEND_FACTOR_SRC_ALPHA);
+  int destFactorAlpha = renderer1.GetProperty<int>(Renderer::Property::BLEND_FACTOR_DEST_ALPHA);
+  DALI_TEST_CHECK(srcFactorRgb == BlendFactor::ONE);
+  DALI_TEST_CHECK(destFactorRgb == BlendFactor::ONE_MINUS_SRC_ALPHA);
+  DALI_TEST_CHECK(srcFactorAlpha == BlendFactor::ONE);
+  DALI_TEST_CHECK(destFactorAlpha == BlendFactor::ONE_MINUS_SRC_ALPHA);
+
+  DALI_TEST_EQUALS(textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION); // A new texture should be generated.
+  textureTrace.Reset();
+
+  ImageView imageView2 = ImageView::New();
+  imageView2.SetProperty(ImageView::Property::IMAGE, imageMap);
+
+  // Disable pre-multiplied alpha blending
+  imageView2.SetProperty(ImageView::Property::PRE_MULTIPLIED_ALPHA, false);
+
+  application.GetScene().Add(imageView2);
+
+  application.SendNotification();
+  application.Render();
+
+  // TODO : Could we use cached jpg image here? For now, just load again.
+  // Please remove this line if you impelemt cache for non-alpha channel image cases.
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  value = imageView2.GetProperty(ImageView::Property::PRE_MULTIPLIED_ALPHA);
+  DALI_TEST_CHECK(value.Get(enable));
+  DALI_TEST_CHECK(!enable); // Should be false after loading, to match with old legacy behavior. TODO : Could we change this behavior?
+
+  // conventional alpha blending
+  Renderer renderer2 = imageView2.GetRendererAt(0);
+  value              = renderer2.GetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA);
+  DALI_TEST_CHECK(value.Get(enable));
+  DALI_TEST_CHECK(!enable);
+
+  srcFactorRgb    = renderer2.GetProperty<int>(Renderer::Property::BLEND_FACTOR_SRC_RGB);
+  destFactorRgb   = renderer2.GetProperty<int>(Renderer::Property::BLEND_FACTOR_DEST_RGB);
+  srcFactorAlpha  = renderer2.GetProperty<int>(Renderer::Property::BLEND_FACTOR_SRC_ALPHA);
+  destFactorAlpha = renderer2.GetProperty<int>(Renderer::Property::BLEND_FACTOR_DEST_ALPHA);
+  DALI_TEST_CHECK(srcFactorRgb == BlendFactor::SRC_ALPHA);
+  DALI_TEST_CHECK(destFactorRgb == BlendFactor::ONE_MINUS_SRC_ALPHA);
+  DALI_TEST_CHECK(srcFactorAlpha == BlendFactor::ONE);
+  DALI_TEST_CHECK(destFactorAlpha == BlendFactor::ONE_MINUS_SRC_ALPHA);
+
+  DALI_TEST_EQUALS(textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION); // The cached texture should be used.
+
+  END_TEST;
+}
+
+int UtcDaliImageViewPreMultipliedAlphaCompressed(void)
+{
+  ToolkitTestApplication application;
+
+  // Set up trace debug
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  Property::Map imageMap;
+  imageMap[ImageVisual::Property::URL]            = TEST_COMPRESSED_ALPHA_IMAGE_FILE_NAME;
+  imageMap[ImageVisual::Property::RELEASE_POLICY] = ImageVisual::ReleasePolicy::NEVER; // To keep the texture cache
+
+  ImageView imageView1 = ImageView::New();
+  imageView1.SetProperty(ImageView::Property::IMAGE, imageMap);
+
+  application.GetScene().Add(imageView1);
+
+  Property::Value value = imageView1.GetProperty(ImageView::Property::PRE_MULTIPLIED_ALPHA);
+  bool            enable;
+  DALI_TEST_CHECK(value.Get(enable));
+  DALI_TEST_CHECK(enable); // Default value is true
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  value = imageView1.GetProperty(ImageView::Property::PRE_MULTIPLIED_ALPHA);
+  DALI_TEST_CHECK(value.Get(enable));
+  DALI_TEST_CHECK(!enable); // Should be false after loading, Since compressed format doesn't allow to premuliply alpha.
 
   // conventional alpha blending
   Renderer renderer1 = imageView1.GetRendererAt(0);
index 3053c7f2cf267fe562559aecde71348a4f8c7c14..f4f6f0eb81f8171f28929b31a4cfa555f47cf723 100644 (file)
@@ -72,6 +72,8 @@ const char* TEST_ROTATED_IMAGE            = TEST_RESOURCE_DIR "/keyboard-Landsca
 const char* TEST_YUV420_IMAGE_FILE_NAME   = TEST_RESOURCE_DIR "/gallery-small-1-yuv420.jpg";
 const char* TEST_N_PATCH_IMAGE_FILE_NAME  = TEST_RESOURCE_DIR "/heartsframe.9.png";
 
+const char* TEST_COMPRESSED_ALPHA_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/RGBA_ASTC_4x4.ktx";
+
 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";
 
@@ -312,14 +314,14 @@ int UtcDaliImageVisualNoPremultipliedAlpha01(void)
 int UtcDaliImageVisualNoPremultipliedAlpha02(void)
 {
   ToolkitTestApplication application;
-  tet_infoline("Request image visual with no alpha channel");
+  tet_infoline("Request image visual with alpha channel and compressed format");
 
   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);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_COMPRESSED_ALPHA_IMAGE_FILE_NAME);
 
   Visual::Base visual = factory.CreateVisual(propertyMap);
   DALI_TEST_CHECK(visual);
@@ -1572,7 +1574,7 @@ int UtcDaliImageVisualAnimateMixColor(void)
   VisualFactory factory = VisualFactory::Get();
   Property::Map propertyMap;
   propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
-  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_COMPRESSED_ALPHA_IMAGE_FILE_NAME);
   propertyMap.Insert("mixColor", Color::BLUE);
   propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
   Visual::Base visual = factory.CreateVisual(propertyMap);
@@ -3719,7 +3721,9 @@ int UtcDaliImageVisualLoadImagePlanes01(void)
 
   Renderer renderer           = actor.GetRendererAt(0);
   auto     preMultipliedAlpha = renderer.GetProperty<bool>(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA);
-  DALI_TEST_EQUALS(preMultipliedAlpha, false, TEST_LOCATION);
+
+  // Let we allow to premultiply alpha for YUV case, since it doesn't have alpha channel.
+  DALI_TEST_EQUALS(preMultipliedAlpha, true, TEST_LOCATION);
 
   END_TEST;
 }
index 867c79740d1de9219b27e756e200348902376fef..b811b80e718021ac2257c804ecf2c3d40dca96e0 100644 (file)
@@ -246,7 +246,7 @@ void FastTrackLoadingTask::Load()
 
 void FastTrackLoadingTask::MultiplyAlpha(Dali::Devel::PixelBuffer pixelBuffer)
 {
-  if(mPreMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON && Pixel::HasAlpha(pixelBuffer.GetPixelFormat()))
+  if(mPreMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON)
   {
     pixelBuffer.MultiplyColorByAlpha();
     mPremultiplied = pixelBuffer.IsAlphaPreMultiplied();
index 126a9810a9d42aae200452c5dc46a1259cccf418..2bf69e0e2b12243af747a0df39f66c4e66baa5bc 100644 (file)
@@ -275,7 +275,7 @@ void LoadingTask::ApplyMask()
 
 void LoadingTask::MultiplyAlpha()
 {
-  if(!pixelBuffers.empty() && Pixel::HasAlpha(pixelBuffers[0].GetPixelFormat()))
+  if(!pixelBuffers.empty())
   {
     if(preMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON)
     {
index 0d8925704a2ea292c55b37b0badbef449a8ab59b..868d57da36d14c0d2ce1ef110d4b94cbcf93dcc8 100644 (file)
@@ -615,7 +615,8 @@ TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedTexture(
         {
           // 1. If preMultiplyOnLoad is MULTIPLY_ON_LOAD, then textureInfo.preMultiplyOnLoad should be true. The premultiplication result can be different.
           // 2. If preMultiplyOnLoad is LOAD_WITHOUT_MULTIPLY, then textureInfo.preMultiplied should be false.
-          if((preMultiplyOnLoad == MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad) || (preMultiplyOnLoad == MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied))
+          if((preMultiplyOnLoad == MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad) ||
+             (preMultiplyOnLoad == MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied))
           {
             // The found Texture is a match.
             return cacheIndex;
index 2b55f6aab4e6ba745c77ce98f0813627eed2294a..9030c5a64c1671ed762cade59be56ab964bffa3a 100644 (file)
@@ -74,17 +74,15 @@ const Vector4 FULL_ATLAS_RECT(0.0f, 0.0f, 1.0f, 1.0f); ///< UV Rectangle that co
 
 void PreMultiply(Devel::PixelBuffer pixelBuffer, TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
 {
-  if(Pixel::HasAlpha(pixelBuffer.GetPixelFormat()))
+  if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
   {
-    if(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
+    pixelBuffer.MultiplyColorByAlpha();
+
+    if(!pixelBuffer.IsAlphaPreMultiplied())
     {
-      pixelBuffer.MultiplyColorByAlpha();
+      preMultiplyOnLoad = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
     }
   }
-  else
-  {
-    preMultiplyOnLoad = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
-  }
 }
 
 } // Anonymous namespace
@@ -1111,7 +1109,7 @@ void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, std::vec
     else
     {
       // YUV case
-      textureInfo.preMultiplied = false;
+      textureInfo.preMultiplied = textureInfo.preMultiplyOnLoad;
 
       UploadTextures(pixelBuffers, textureInfo);
       NotifyObservers(textureInfo, true);