From: Eunki, Hong Date: Tue, 5 Sep 2023 08:10:11 +0000 (+0900) Subject: Support FastTrackUploading for YUV images X-Git-Tag: dali_2.2.44~2^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=e6146791d3bbce09a573a5864b94b58ca8006522 Support FastTrackUploading for YUV images 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 --- diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp index 4b5e546..e1c93f6 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp @@ -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(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 diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag index cb5e765..c2c17e5 100644 --- a/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag +++ b/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag @@ -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 diff --git a/dali-toolkit/internal/image-loader/fast-track-loading-task.cpp b/dali-toolkit/internal/image-loader/fast-track-loading-task.cpp index cd97cc2..25d40de 100644 --- a/dali-toolkit/internal/image-loader/fast-track-loading-task.cpp +++ b/dali-toolkit/internal/image-loader/fast-track-loading-task.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef TRACE_ENABLED #include @@ -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(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(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 diff --git a/dali-toolkit/internal/image-loader/fast-track-loading-task.h b/dali-toolkit/internal/image-loader/fast-track-loading-task.h index 0458352..2140794 100644 --- a/dali-toolkit/internal/image-loader/fast-track-loading-task.h +++ b/dali-toolkit/internal/image-loader/fast-track-loading-task.h @@ -18,15 +18,18 @@ */ // EXTERNAL INCLUDES -#include -#include -#include #include #include #include #include +#include #include +// INTERNAL INCLUDES +#include +#include +#include + 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 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 mImageInformations; - uint32_t mResourceId; + std::vector 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 diff --git a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp index 11c9105..3b212c3 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.cpp @@ -19,7 +19,6 @@ #include // EXTERNAL HEADERS -#include #include #include #include @@ -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(new TextureAsyncLoadingHelper(*this))), mLifecycleObservers(), mLoadQueue(), mLoadingQueueTextureId(INVALID_TEXTURE_ID), mRemoveQueue(), - mLoadYuvPlanes(NeedToLoadYuvPlanes()), + mLoadYuvPlanes(loadYuvPlanes), mRemoveProcessorRegistered(false) { // Initialize the AddOn diff --git a/dali-toolkit/internal/texture-manager/texture-manager-impl.h b/dali-toolkit/internal/texture-manager/texture-manager-impl.h index a753099..59aa9b7 100644 --- a/dali-toolkit/internal/texture-manager/texture-manager-impl.h +++ b/dali-toolkit/internal/texture-manager/texture-manager-impl.h @@ -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 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 diff --git a/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp b/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp index 2c98a4f..53810b1 100644 --- a/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp +++ b/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp @@ -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(ImageVisualRequireFlag::COLOR_CONVERSION); } + else if(colorConversion == ImageVisualShaderFeature::ColorConversion::UNIFIED_YUV_AND_RGB) + { + shaderTypeFlag |= static_cast(ImageVisualRequireFlag::COLOR_CONVERSION); + shaderTypeFlag |= static_cast(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()); diff --git a/dali-toolkit/internal/visuals/image-visual-shader-factory.h b/dali-toolkit/internal/visuals/image-visual-shader-factory.h index 7dfefbc..02ea83e 100644 --- a/dali-toolkit/internal/visuals/image-visual-shader-factory.h +++ b/dali-toolkit/internal/visuals/image-visual-shader-factory.h @@ -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 diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index 49635e4..2f0e800 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -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 { diff --git a/dali-toolkit/internal/visuals/image/image-visual.h b/dali-toolkit/internal/visuals/image/image-visual.h index 925cdad..7358f8a 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.h +++ b/dali-toolkit/internal/visuals/image/image-visual.h @@ -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. diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.cpp b/dali-toolkit/internal/visuals/visual-factory-cache.cpp index 7e7a0b0..7cf9d14 100644 --- a/dali-toolkit/internal/visuals/visual-factory-cache.cpp +++ b/dali-toolkit/internal/visuals/visual-factory-cache.cpp @@ -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 #include #include #include @@ -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& brokenImageUrlList) { mUseDefaultBrokenImageOnly = false; diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.h b/dali-toolkit/internal/visuals/visual-factory-cache.h index 43fee4c..f1d9703 100644 --- a/dali-toolkit/internal/visuals/visual-factory-cache.h +++ b/dali-toolkit/internal/visuals/visual-factory-cache.h @@ -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;