Support FastTrackUploading for YUV images 99/298299/14
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 5 Sep 2023 08:10:11 +0000 (17:10 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 14 Sep 2023 06:13:10 +0000 (15:13 +0900)
Let we support YUV image case without additional image loading
or image operation.

Instead, let we think that FastTrackUploading will use
YUV format always if DALI_LOAD_IMAGE_YUV_PLANES=1.
And then, revert as standard shader if we are not use
YUV case actually.

To support this feature. let we make unified YUV + RGB shader can use
standard rgb image color for special case.
After load completed, we can determine the type of shader.

Change-Id: Ia4ffa288e705af751e722cd1440de2a014ad19b4
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
12 files changed:
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
dali-toolkit/internal/graphics/shaders/image-visual-shader.frag
dali-toolkit/internal/image-loader/fast-track-loading-task.cpp
dali-toolkit/internal/image-loader/fast-track-loading-task.h
dali-toolkit/internal/texture-manager/texture-manager-impl.cpp
dali-toolkit/internal/texture-manager/texture-manager-impl.h
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/image/image-visual.h
dali-toolkit/internal/visuals/visual-factory-cache.cpp
dali-toolkit/internal/visuals/visual-factory-cache.h

index 4b5e546..e1c93f6 100644 (file)
@@ -3803,7 +3803,6 @@ int UtcDaliImageVisualLoadFastTrackImageReload(void)
 
 int UtcDaliImageVisualLoadFastTrackImagePlanes01(void)
 {
-#if 0 //< Do not open this UTC yet.
   EnvironmentVariable::SetTestEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV, "1");
   EnvironmentVariable::SetTestEnvironmentVariable(ENABLE_DECODE_JPEG_TO_YUV_420_ENV, "1");
 
@@ -3853,19 +3852,65 @@ int UtcDaliImageVisualLoadFastTrackImagePlanes01(void)
 
   DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 3, TEST_LOCATION);
 
-  // Event thread don't know the result yet.
-  DALI_TEST_EQUALS(actor.IsResourceReady(), false, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
 
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadFastTrackImagePlanes02(void)
+{
+  EnvironmentVariable::SetTestEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV, "1");
+  EnvironmentVariable::SetTestEnvironmentVariable(ENABLE_DECODE_JPEG_TO_YUV_420_ENV, "1");
+
+  ToolkitTestApplication application;
+
+  Test::TextureUploadManager::InitalizeGraphicsController(application.GetGraphicsController());
+
+  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(DevelImageVisual::Property::FAST_TRACK_UPLOADING, true);
+
+  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));
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  application.GetScene().Add(actor);
 
-  // Check resource ready comes after
   application.SendNotification();
+  application.Render();
 
-  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
-  DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+  // EventThread without callback
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 30, false), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION);
+
+  {
+    // TODO : There is no way to flush TextureUploadManager in test-application's Render() now.
+    // How can we make it? Should it be integration-api?
+    auto textureUploadManager = Dali::Devel::TextureUploadManager::Get();
+    textureUploadManager.ResourceUpload();
+    application.Render();
+  }
+  // Render only without SendNotification(). And check whether glTexImage2D called or not.
+  application.Render();
+
+  DALI_TEST_GREATER(textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
 
-#else
-  DALI_TEST_CHECK(true);
-#endif
   END_TEST;
 }
\ No newline at end of file
index cb5e765..c2c17e5 100644 (file)
@@ -9,7 +9,7 @@ INPUT mediump vec4 vCornerRadius;
 #endif
 
 uniform sampler2D sTexture;
-#ifdef IS_REQUIRED_YUV_TO_RGB
+#if defined(IS_REQUIRED_YUV_TO_RGB) || defined(IS_REQUIRED_UNIFIED_YUV_AND_RGB)
 uniform sampler2D sTextureU;
 uniform sampler2D sTextureV;
 #endif
@@ -213,17 +213,27 @@ mediump float calculateCornerOpacity()
 }
 #endif
 
-#ifdef IS_REQUIRED_YUV_TO_RGB
-lowp vec3 ConvertYuvToRgb(mediump vec2 texCoord)
+#if defined(IS_REQUIRED_YUV_TO_RGB) || defined(IS_REQUIRED_UNIFIED_YUV_AND_RGB)
+lowp vec4 ConvertYuvToRgba(mediump vec2 texCoord)
 {
+#ifdef IS_REQUIRED_UNIFIED_YUV_AND_RGB
+  // Special case when shader use YUV but actual textures are not YUV format.
+  // In this case, just resturn sTexture.
+  if(textureSize(sTextureU, 0) != textureSize(sTextureV, 0))
+  {
+    return texture(sTexture, texCoord);
+  }
+#endif
+
   lowp float y = texture(sTexture, texCoord).r;
   lowp float u = texture(sTextureU, texCoord).r - 0.5;
   lowp float v = texture(sTextureV, texCoord).r - 0.5;
-  lowp vec3 rgb;
-  rgb.r = y + (1.403 * v);
-  rgb.g = y - (0.344 * u) - (0.714 * v);
-  rgb.b = y + (1.770 * u);
-  return rgb;
+  lowp vec4 rgba;
+  rgba.r = y + (1.403 * v);
+  rgba.g = y - (0.344 * u) - (0.714 * v);
+  rgba.b = y + (1.770 * u);
+  rgba.a = 1.0;
+  return rgba;
 }
 #endif
 
@@ -238,8 +248,8 @@ void main()
   mediump vec2 texCoord = vTexCoord;
 #endif
 
-#ifdef IS_REQUIRED_YUV_TO_RGB
-  lowp vec4 textureColor = vec4(ConvertYuvToRgb(texCoord), 1.0) * vec4( mixColor, 1.0 ) * uColor;
+#if defined(IS_REQUIRED_YUV_TO_RGB) || defined(IS_REQUIRED_UNIFIED_YUV_AND_RGB)
+  lowp vec4 textureColor = ConvertYuvToRgba(texCoord) * vec4( mixColor, 1.0 ) * uColor;
 #else
   lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * vec4( mixColor, 1.0 ) * uColor;
 #endif
index cd97cc2..25d40de 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/integration-api/debug.h>
 #include <dali/integration-api/texture-integ.h>
 #include <dali/integration-api/trace.h>
+#include <dali/public-api/common/vector-wrapper.h>
 
 #ifdef TRACE_ENABLED
 #include <sstream>
@@ -38,26 +39,41 @@ namespace Internal
 namespace
 {
 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false);
+
+constexpr uint32_t CHROMINANCE_U_INDEX = 1u;
+constexpr uint32_t CHROMINANCE_V_INDEX = 2u;
+
+Dali::PixelData GetDummyChrominanceUPixelData()
+{
+  static Dali::PixelData pixelDataU = PixelData::New(new uint8_t[2]{0x00, 0x00}, 2, 1, 2, Pixel::L8, PixelData::DELETE_ARRAY);
+  return pixelDataU;
+}
+
+Dali::PixelData GetDummyChrominanceVPixelData()
+{
+  static Dali::PixelData pixelDataV = PixelData::New(new uint8_t[2]{0x00, 0x00}, 2, 2, 1, Pixel::L8, PixelData::DELETE_ARRAY);
+  return pixelDataV;
 }
 
-FastTrackLoadingTask::FastTrackLoadingTask(const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
+} // namespace
+
+FastTrackLoadingTask::FastTrackLoadingTask(const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, bool loadPlanes, CallbackBase* callback)
 : AsyncTask(MakeCallback(this, &FastTrackLoadingTask::OnComplete), url.GetProtocolType() == VisualUrl::ProtocolType::REMOTE ? AsyncTask::PriorityType::LOW : AsyncTask::PriorityType::HIGH),
   mUrl(url),
-  mTexture(),
+  mTextures(),
   mDimensions(dimensions),
   mFittingMode(fittingMode),
   mSamplingMode(samplingMode),
   mPreMultiplyOnLoad(preMultiplyOnLoad),
   mCallback(),
   mTextureUploadManager(Dali::Devel::TextureUploadManager::Get()),
-  mImageWidth(0u),
-  mImageHeight(0u),
-  mImageFormat(Pixel::INVALID),
+  mImageInformations(),
   mPixelData(),
-  mResourceId(0u),
   mOrientationCorrection(orientationCorrection),
   mLoadSuccess(false),
-  mPremultiplied(false)
+  mLoadPlanesAvaliable(loadPlanes),
+  mPremultiplied(false),
+  mPlanesLoaded(false)
 {
   mCallback = std::unique_ptr<CallbackBase>(callback);
   PrepareTexture();
@@ -69,17 +85,45 @@ FastTrackLoadingTask::~FastTrackLoadingTask()
 
 void FastTrackLoadingTask::PrepareTexture()
 {
-  mTexture    = mTextureUploadManager.GenerateTexture2D();
-  mResourceId = Integration::GetTextureResourceId(mTexture);
+  const uint32_t requiredTexturesCount = mLoadPlanesAvaliable ? 3u : 1u;
+
+  mTextures.resize(requiredTexturesCount);
+  mImageInformations.resize(requiredTexturesCount);
+  for(uint32_t index = 0u; index < requiredTexturesCount; ++index)
+  {
+    mTextures[index] = mTextureUploadManager.GenerateTexture2D();
+
+    mImageInformations[index].resourceId = Integration::GetTextureResourceId(mTextures[index]);
+  }
+
+  if(mLoadPlanesAvaliable)
+  {
+    // Create static dummy chrominance pixel data now, for thread safety.
+    [[maybe_unused]] auto pixelDataU = GetDummyChrominanceUPixelData();
+    [[maybe_unused]] auto pixelDataV = GetDummyChrominanceVPixelData();
+  }
 }
 
 void FastTrackLoadingTask::OnComplete(AsyncTaskPtr task)
 {
   if(mLoadSuccess)
   {
-    Dali::Integration::SetTextureSize(mTexture, Dali::ImageDimensions(mImageWidth, mImageHeight));
-    Dali::Integration::SetTexturePixelFormat(mTexture, mImageFormat);
+    for(uint32_t index = 0u; index < mImageInformations.size(); ++index)
+    {
+      Dali::Integration::SetTextureSize(mTextures[index], Dali::ImageDimensions(mImageInformations[index].width, mImageInformations[index].height));
+      Dali::Integration::SetTexturePixelFormat(mTextures[index], mImageInformations[index].format);
+    }
+    if(mLoadPlanesAvaliable && !mPlanesLoaded)
+    {
+      // We will not use ChrominanceU and ChrominanceV texture anymore.
+      mTextures.resize(1u);
+    }
+  }
+  else
+  {
+    mTextures.clear();
   }
+
   if(mCallback)
   {
     CallbackBase::Execute(*mCallback, FastTrackLoadingTaskPtr(reinterpret_cast<FastTrackLoadingTask*>(task.Get())));
@@ -115,10 +159,14 @@ void FastTrackLoadingTask::Load()
 
   if(mUrl.IsValid() && mUrl.IsLocalResource())
   {
-    // TODO : We need to consider YUV case in future.
-    //Dali::LoadImagePlanesFromFile(mUrl.GetUrl(), pixelBuffers, mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
-
-    pixelBuffer = Dali::LoadImageFromFile(mUrl.GetUrl(), mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
+    if(mLoadPlanesAvaliable)
+    {
+      Dali::LoadImagePlanesFromFile(mUrl.GetUrl(), pixelBuffers, mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
+    }
+    else
+    {
+      pixelBuffer = Dali::LoadImageFromFile(mUrl.GetUrl(), mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
+    }
   }
   else if(mUrl.IsValid())
   {
@@ -127,24 +175,43 @@ void FastTrackLoadingTask::Load()
 
   if(pixelBuffer)
   {
-    pixelBuffers.push_back(pixelBuffer);
+    pixelBuffers.emplace_back(std::move(pixelBuffer));
   }
 
   if(pixelBuffers.empty())
   {
-    DALI_LOG_ERROR("FastTrackLoadingTask::Load: Loading is failed: ResourceId : %d, url : [%s]\n", mResourceId, mUrl.GetUrl().c_str());
+    mLoadSuccess = false;
+    DALI_LOG_ERROR("FastTrackLoadingTask::Load: Loading is failed: ResourceId : %d url : [%s]\n", mImageInformations[0u].resourceId, mUrl.GetUrl().c_str());
   }
   else
   {
-    if(pixelBuffers.size() == 1u)
+    mPixelData.resize(pixelBuffers.size());
+
+    mLoadSuccess = true;
+    MultiplyAlpha(pixelBuffers[0]);
+    uint32_t index = 0u;
+    for(auto&& pixelBuffer : pixelBuffers)
     {
-      mLoadSuccess = true;
-      MultiplyAlpha(pixelBuffers[0]);
-      mPixelData = Dali::Devel::PixelBuffer::Convert(pixelBuffers[0]);
+      mPixelData[index++] = Dali::Devel::PixelBuffer::Convert(pixelBuffer);
     }
-    else
+
+    if(pixelBuffers.size() > 1u)
     {
-      DALI_LOG_ERROR("FastTrackLoadingTask::Load: ??? Undefined case. PixelBuffers.size() : %zu : ResourceId : %d, url : [%s]\n", pixelBuffers.size(), mResourceId, mUrl.GetUrl().c_str());
+      mPlanesLoaded = true;
+    }
+    else if(mLoadPlanesAvaliable && pixelBuffers.size() == 1u && mTextures.size() == 3u) ///< Case when we prepare three textures to render YUV, but loaded image is not YUV.
+    {
+      // Dummy pixel data for fake shader that we don't use actual YUV format.
+      // To fake shader, let we use indivisual sizes of texture for U and V.
+      mPixelData.resize(3u);
+      mPixelData[CHROMINANCE_U_INDEX] = GetDummyChrominanceUPixelData();
+      mPixelData[CHROMINANCE_V_INDEX] = GetDummyChrominanceVPixelData();
+    }
+
+    if(DALI_UNLIKELY(mPixelData.size() != mImageInformations.size()))
+    {
+      DALI_LOG_ERROR("FastTrackLoadingTask::Load: Undefined case. pixelBuffers.size() : %zu, image size : %zu, ResourceId : %d, url : [%s]\n", pixelBuffers.size(), mImageInformations.size(), mImageInformations[0u].resourceId, mUrl.GetUrl().c_str());
+      mLoadSuccess = false;
     }
   }
 
@@ -177,14 +244,24 @@ void FastTrackLoadingTask::UploadToTexture()
 {
   if(mLoadSuccess)
   {
-    mImageWidth  = mPixelData.GetWidth();
-    mImageHeight = mPixelData.GetHeight();
-    mImageFormat = mPixelData.GetPixelFormat();
+    DALI_ASSERT_DEBUG(mPixelData.size() == mImageInformations.size());
 
-    mTextureUploadManager.RequestUpload(mResourceId, mPixelData);
+    uint32_t index = 0u;
+    for(auto&& pixelData : mPixelData)
+    {
+      mImageInformations[index].width  = pixelData.GetWidth();
+      mImageInformations[index].height = pixelData.GetHeight();
+      mImageInformations[index].format = pixelData.GetPixelFormat();
+
+      mTextureUploadManager.RequestUpload(mImageInformations[index].resourceId, pixelData);
+
+      pixelData.Reset();
+
+      ++index;
+    }
   }
 
-  mPixelData.Reset();
+  mPixelData.clear();
 }
 
 } // namespace Internal
index 0458352..2140794 100644 (file)
  */
 
 // EXTERNAL INCLUDES
-#include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
-#include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
-#include <dali-toolkit/internal/visuals/visual-url.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 #include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
 #include <dali/integration-api/adaptor-framework/log-factory-interface.h>
 #include <dali/public-api/adaptor-framework/async-task-manager.h>
+#include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/rendering/texture.h>
 
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
+#include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+
 namespace Dali
 {
 namespace Toolkit
@@ -52,6 +55,7 @@ public:
                        SamplingMode::Type                       samplingMode,
                        bool                                     orientationCorrection,
                        DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
+                       bool                                     loadPlanes,
                        CallbackBase*                            callback);
 
   /**
@@ -107,8 +111,8 @@ private:
   void OnComplete(AsyncTaskPtr task);
 
 public:
-  VisualUrl     mUrl;     ///< url of the image to load.
-  Dali::Texture mTexture; ///< texture for regular image.
+  VisualUrl                  mUrl;      ///< url of the image to load.
+  std::vector<Dali::Texture> mTextures; ///< textures for regular image.
 
 private:
   ImageDimensions                          mDimensions;   ///< dimensions to load
@@ -121,19 +125,25 @@ private:
   Dali::Devel::TextureUploadManager mTextureUploadManager;
 
   // Note : mPixelData is invalid after upload requested. We should keep image size informations.
-  uint32_t      mImageWidth;
-  uint32_t      mImageHeight;
-  Pixel::Format mImageFormat;
+  struct ImageInformation
+  {
+    uint32_t resourceId;
 
-  Dali::PixelData mPixelData;
+    uint32_t      width;
+    uint32_t      height;
+    Pixel::Format format;
+  };
+  std::vector<ImageInformation> mImageInformations;
 
-  uint32_t mResourceId;
+  std::vector<Dali::PixelData> mPixelData;
 
   bool mOrientationCorrection : 1; ///< If orientation correction is needed
 
 public:
-  bool mLoadSuccess : 1;   ///< Whether image load successed or not.
-  bool mPremultiplied : 1; ///< True if the image's color was multiplied by it's alpha
+  bool mLoadSuccess : 1;         ///< Whether image load successed or not.
+  bool mLoadPlanesAvaliable : 1; ///< If image valid to load as planes or not.
+  bool mPremultiplied : 1;       ///< True if the image's color was multiplied by it's alpha
+  bool mPlanesLoaded : 1;        ///< True if the image load as planes.
 };
 
 } // namespace Internal
index 11c9105..3b212c3 100644 (file)
@@ -19,7 +19,6 @@
 #include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
 
 // EXTERNAL HEADERS
-#include <dali/devel-api/adaptor-framework/environment-variable.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 #include <dali/integration-api/adaptor-framework/adaptor.h>
@@ -38,17 +37,6 @@ constexpr auto INITIAL_HASH_NUMBER = size_t{0u};
 
 constexpr auto TEXTURE_INDEX      = 0u; ///< The Index for texture
 constexpr auto MASK_TEXTURE_INDEX = 1u; ///< The Index for mask texture
-
-constexpr auto NUMBER_OF_LOCAL_LOADER_THREADS_ENV  = "DALI_TEXTURE_LOCAL_THREADS";
-constexpr auto NUMBER_OF_REMOTE_LOADER_THREADS_ENV = "DALI_TEXTURE_REMOTE_THREADS";
-constexpr auto LOAD_IMAGE_YUV_PLANES_ENV           = "DALI_LOAD_IMAGE_YUV_PLANES";
-
-bool NeedToLoadYuvPlanes()
-{
-  auto loadYuvPlanesString = Dali::EnvironmentVariable::GetEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV);
-  bool loadYuvPlanes       = loadYuvPlanesString ? std::atoi(loadYuvPlanesString) : false;
-  return loadYuvPlanes;
-}
 } // namespace
 
 namespace Dali
@@ -109,14 +97,14 @@ TextureManager::MaskingData::MaskingData()
 {
 }
 
-TextureManager::TextureManager()
+TextureManager::TextureManager(bool loadYuvPlanes)
 : mTextureCacheManager(),
   mAsyncLoader(std::unique_ptr<TextureAsyncLoadingHelper>(new TextureAsyncLoadingHelper(*this))),
   mLifecycleObservers(),
   mLoadQueue(),
   mLoadingQueueTextureId(INVALID_TEXTURE_ID),
   mRemoveQueue(),
-  mLoadYuvPlanes(NeedToLoadYuvPlanes()),
+  mLoadYuvPlanes(loadYuvPlanes),
   mRemoveProcessorRegistered(false)
 {
   // Initialize the AddOn
index a753099..59aa9b7 100644 (file)
@@ -99,8 +99,10 @@ public:
 
   /**
    * Constructor.
+   *
+   * @param[in] loadYuvPlanes Whether we allow to load YuvPlanes or not. Default is false.
    */
-  TextureManager();
+  TextureManager(bool loadYuvPlanes = false);
 
   /**
    * Destructor.
@@ -687,8 +689,8 @@ private:                                    // Member Variables:
 
   Dali::Vector<TextureManager::TextureId> mRemoveQueue; ///< Queue of textures to remove at PostProcess. It will be cleared after PostProcess.
 
-  bool mLoadYuvPlanes;             ///< A global flag to specify if the image should be loaded as yuv planes
-  bool mRemoveProcessorRegistered; ///< Flag if remove processor registered or not.
+  const bool mLoadYuvPlanes;             ///< A global flag to specify if the image should be loaded as yuv planes
+  bool       mRemoveProcessorRegistered; ///< Flag if remove processor registered or not.
 };
 
 } // namespace Internal
index 2c98a4f..53810b1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 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.
@@ -45,9 +45,11 @@ enum class ImageVisualRequireFlag : uint32_t
   BORDERLINE       = 1 << 1,
   ALPHA_MASKING    = 1 << 2,
   COLOR_CONVERSION = 1 << 3,
+
+  UNIFIED_YUV_AND_RGB = 1 << 2, // Special enum to trick unified YUV and RGB.
 };
 
-static constexpr auto          SHADER_TYPE_COUNT = 12u;
+static constexpr auto          SHADER_TYPE_COUNT = 16u;
 VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[SHADER_TYPE_COUNT] =
   {
     VisualFactoryCache::IMAGE_SHADER,
@@ -61,7 +63,11 @@ VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[SHADER_TYPE_COUNT] =
     VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
     VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
     VisualFactoryCache::IMAGE_SHADER_BORDERLINE_YUV_TO_RGB,
-    VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_YUV_TO_RGB};
+    VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_YUV_TO_RGB,
+    VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
+    VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
+    VisualFactoryCache::IMAGE_SHADER_BORDERLINE_YUV_AND_RGB,
+    VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_YUV_AND_RGB};
 } // unnamed namespace
 
 namespace ImageVisualShaderFeature
@@ -102,9 +108,9 @@ FeatureBuilder& FeatureBuilder::EnableAlphaMaskingOnRendering(bool enableAlphaMa
   return *this;
 }
 
-FeatureBuilder& FeatureBuilder::EnableYuvToRgb(bool enableYuvToRgb)
+FeatureBuilder& FeatureBuilder::EnableYuvToRgb(bool enableYuvToRgb, bool enableUnifiedYuvAndRgb)
 {
-  mColorConversion = (enableYuvToRgb ? ColorConversion::YUV_TO_RGB : ColorConversion::DONT_NEED);
+  mColorConversion = (enableUnifiedYuvAndRgb ? ColorConversion::UNIFIED_YUV_AND_RGB : (enableYuvToRgb ? ColorConversion::YUV_TO_RGB : ColorConversion::DONT_NEED));
   return *this;
 }
 } // namespace ImageVisualShaderFeature
@@ -163,6 +169,11 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, con
     {
       shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::COLOR_CONVERSION);
     }
+    else if(colorConversion == ImageVisualShaderFeature::ColorConversion::UNIFIED_YUV_AND_RGB)
+    {
+      shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::COLOR_CONVERSION);
+      shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::UNIFIED_YUV_AND_RGB);
+    }
     shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
   }
 
@@ -210,6 +221,10 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, con
       {
         fragmentShaderPrefixList += "#define IS_REQUIRED_YUV_TO_RGB\n";
       }
+      else if(colorConversion == ImageVisualShaderFeature::ColorConversion::UNIFIED_YUV_AND_RGB)
+      {
+        fragmentShaderPrefixList += "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n";
+      }
     }
 
     std::string vertexShader   = std::string(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_VERT.data());
index 7dfefbc..02ea83e 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
 
 /*
- * Copyright (c) 2022 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.
@@ -114,8 +114,9 @@ namespace ColorConversion
  */
 enum Type
 {
-  DONT_NEED = 0, ///< Not need to convert
-  YUV_TO_RGB     ///< Need yuv to rgb conversion
+  DONT_NEED = 0,      ///< Not need to convert
+  YUV_TO_RGB,         ///< Need yuv to rgb conversion
+  UNIFIED_YUV_AND_RGB ///< Need to support both yuv conversion case and normal case.
 };
 } // namespace ColorConversion
 
@@ -141,7 +142,7 @@ struct FeatureBuilder
   FeatureBuilder& EnableBorderline(bool enableBorderline);
   FeatureBuilder& SetTextureForFragmentShaderCheck(const Dali::Texture& texture);
   FeatureBuilder& EnableAlphaMaskingOnRendering(bool enableAlphaMaskingOnRendering);
-  FeatureBuilder& EnableYuvToRgb(bool enableYuvToRgb);
+  FeatureBuilder& EnableYuvToRgb(bool enableYuvToRgb, bool enableUnifiedYuvAndRgb = false);
 
   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
index 49635e4..2f0e800 100644 (file)
@@ -707,10 +707,26 @@ void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& te
     EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
 
     // Set new TextureSet with fast track loading task
-    mFastTrackLoadingTask = new FastTrackLoadingTask(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mOrientationCorrection, preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF, MakeCallback(this, &ImageVisual::FastLoadComplete));
+    mFastTrackLoadingTask = new FastTrackLoadingTask(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mOrientationCorrection, preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF, mFactoryCache.GetLoadYuvPlanes(), MakeCallback(this, &ImageVisual::FastLoadComplete));
 
     TextureSet textureSet = TextureSet::New();
-    textureSet.SetTexture(0u, mFastTrackLoadingTask->mTexture);
+    if(!mFastTrackLoadingTask->mLoadPlanesAvaliable)
+    {
+      DALI_ASSERT_ALWAYS(mFastTrackLoadingTask->mTextures.size() >= 1u);
+      textureSet.SetTexture(0u, mFastTrackLoadingTask->mTextures[0]);
+    }
+    else
+    {
+      DALI_ASSERT_ALWAYS(mFastTrackLoadingTask->mTextures.size() >= 3u);
+      textureSet.SetTexture(0u, mFastTrackLoadingTask->mTextures[0]);
+      textureSet.SetTexture(1u, mFastTrackLoadingTask->mTextures[1]);
+      textureSet.SetTexture(2u, mFastTrackLoadingTask->mTextures[2]);
+
+      // We cannot determine what kind of shader will be used.
+      // Just use unified shader, and then change shader after load completed.
+      mNeedUnifiedYuvAndRgb = true;
+      UpdateShader();
+    }
     mImpl->mRenderer.SetTextures(textureSet);
 
     Dali::AsyncTaskManager::Get().AddTask(mFastTrackLoadingTask);
@@ -1009,6 +1025,31 @@ void ImageVisual::FastLoadComplete(FastTrackLoadingTaskPtr task)
 
     // Change premultiplied alpha flag after change renderer.
     EnablePreMultipliedAlpha(mFastTrackLoadingTask->mPremultiplied);
+
+    if(mFastTrackLoadingTask->mLoadPlanesAvaliable)
+    {
+      if(mFastTrackLoadingTask->mPlanesLoaded)
+      {
+        // Let we use regular yuv cases.
+        mNeedYuvToRgb = true;
+      }
+      else
+      {
+        // Let we use regular image cases.
+        mNeedYuvToRgb = false;
+
+        auto textureSet = mImpl->mRenderer.GetTextures();
+        DALI_ASSERT_ALWAYS(textureSet && textureSet.GetTextureCount() > 0u && "Previous texture set must exist!");
+
+        Dali::TextureSet newTextureSet = TextureSet::New();
+        newTextureSet.SetTexture(0u, textureSet.GetTexture(0u));
+        mImpl->mRenderer.SetTextures(newTextureSet);
+      }
+
+      // We can specify what kind of shader we need to use now. Update shader.
+      mNeedUnifiedYuvAndRgb = false;
+      UpdateShader();
+    }
   }
   else
   {
@@ -1230,7 +1271,7 @@ Shader ImageVisual::GenerateShader() const
         .EnableBorderline(IsBorderlineRequired())
         .SetTextureForFragmentShaderCheck(useNativeImage ? mTextures.GetTexture(0) : Dali::Texture())
         .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering)
-        .EnableYuvToRgb(mNeedYuvToRgb));
+        .EnableYuvToRgb(mNeedYuvToRgb, mNeedUnifiedYuvAndRgb));
   }
   else
   {
index 925cdad..7358f8a 100644 (file)
@@ -375,6 +375,7 @@ private:
   bool                                            mAttemptAtlasing;              ///< If true will attempt atlasing, otherwise create unique texture
   bool                                            mOrientationCorrection;        ///< true if the image will have it's orientation corrected.
   bool                                            mNeedYuvToRgb{false};          ///< true if we need to convert yuv to rgb.
+  bool                                            mNeedUnifiedYuvAndRgb{false};  ///< true if we need to support both yuv and rgb.
   bool                                            mEnableBrokenImage{true};      ///< true if enable broken image.
   bool                                            mUseFastTrackUploading{false}; ///< True if we use fast tack feature.
   bool                                            mRendererAdded{false};         ///< True if renderer added into actor.
index 7e7a0b0..7cf9d14 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 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.
@@ -18,6 +18,7 @@
 #include "visual-factory-cache.h"
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/devel-api/common/hash.h>
 #include <dali/integration-api/debug.h>
@@ -41,10 +42,21 @@ namespace Internal
 namespace
 {
 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+
+constexpr auto LOAD_IMAGE_YUV_PLANES_ENV = "DALI_LOAD_IMAGE_YUV_PLANES";
+
+bool NeedToLoadYuvPlanes()
+{
+  auto loadYuvPlanesString = Dali::EnvironmentVariable::GetEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV);
+  bool loadYuvPlanes       = loadYuvPlanesString ? std::atoi(loadYuvPlanesString) : false;
+  return loadYuvPlanes;
 }
+} // namespace
 
 VisualFactoryCache::VisualFactoryCache(bool preMultiplyOnLoad)
-: mVectorAnimationManager(nullptr),
+: mLoadYuvPlanes(NeedToLoadYuvPlanes()),
+  mTextureManager(mLoadYuvPlanes),
+  mVectorAnimationManager(nullptr),
   mPreMultiplyOnLoad(preMultiplyOnLoad),
   mBrokenImageInfoContainer(),
   mDefaultBrokenImageUrl(""),
@@ -230,11 +242,16 @@ void VisualFactoryCache::SetPreMultiplyOnLoad(bool preMultiply)
   mPreMultiplyOnLoad = preMultiply;
 }
 
-bool VisualFactoryCache::GetPreMultiplyOnLoad()
+bool VisualFactoryCache::GetPreMultiplyOnLoad() const
 {
   return mPreMultiplyOnLoad;
 }
 
+bool VisualFactoryCache::GetLoadYuvPlanes() const
+{
+  return mLoadYuvPlanes;
+}
+
 void VisualFactoryCache::SetBrokenImageUrl(std::string& defaultBrokenUrl, const std::vector<std::string>& brokenImageUrlList)
 {
   mUseDefaultBrokenImageOnly = false;
index 43fee4c..f1d9703 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_VISUAL_FACTORY_CACHE_H
 
 /*
- * Copyright (c) 2022 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.
@@ -93,6 +93,10 @@ public:
     IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
     IMAGE_SHADER_BORDERLINE_YUV_TO_RGB,
     IMAGE_SHADER_ROUNDED_BORDERLINE_YUV_TO_RGB,
+    IMAGE_SHADER_YUV_AND_RGB,
+    IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
+    IMAGE_SHADER_BORDERLINE_YUV_AND_RGB,
+    IMAGE_SHADER_ROUNDED_BORDERLINE_YUV_AND_RGB,
     NATIVE_IMAGE_SHADER,
     NATIVE_IMAGE_SHADER_ROUNDED_CORNER,
     NATIVE_IMAGE_SHADER_BORDERLINE,
@@ -206,7 +210,7 @@ public:
   /**
    * @copydoc Toolkit::VisualFactory::GetPreMultiplyOnLoad()
    */
-  bool GetPreMultiplyOnLoad();
+  bool GetPreMultiplyOnLoad() const;
 
   /**
    * @brief Set an image to be used when a visual has failed to correctly render
@@ -224,6 +228,13 @@ public:
    */
   void UpdateBrokenImageRenderer(Renderer& renderer, const Vector2& size, const bool& rendererIsImage = true);
 
+  /**
+   * @brief Get whether we support YUV Planes load or not.
+   *
+   * @return True if we support to load YUV Planes. False otherwise.
+   */
+  bool GetLoadYuvPlanes() const;
+
 public:
   /**
    * Get the image atlas manager.
@@ -337,6 +348,8 @@ private:
   Geometry mGeometry[GEOMETRY_TYPE_MAX + 1];
   Shader   mShader[SHADER_TYPE_MAX + 1];
 
+  bool mLoadYuvPlanes; ///< A global flag to specify if the image should be loaded as yuv planes
+
   ImageAtlasManagerPtr mAtlasManager;
   TextureManager       mTextureManager;
   NPatchLoader         mNPatchLoader;