From: Heeyong Song Date: Fri, 28 Jan 2022 04:46:20 +0000 (+0900) Subject: [Tizen] Support YUV decoding for JPEG X-Git-Tag: accepted/tizen/6.5/unified/20220218.152712^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4181642a0d1c0fc6a2dbd64453eea98a99c21df9;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git [Tizen] Support YUV decoding for JPEG Change-Id: Iea9312b49bc9e4d4d395dd53afde947c4e577d41 --- diff --git a/dali-toolkit/devel-api/image-loader/async-image-loader-devel.cpp b/dali-toolkit/devel-api/image-loader/async-image-loader-devel.cpp index df9499e..92757e2 100644 --- a/dali-toolkit/devel-api/image-loader/async-image-loader-devel.cpp +++ b/dali-toolkit/devel-api/image-loader/async-image-loader-devel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -38,7 +38,7 @@ uint32_t Load(AsyncImageLoader asyncImageLoader, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad) { - return GetImplementation(asyncImageLoader).Load(Toolkit::Internal::VisualUrl(url), dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad); + return GetImplementation(asyncImageLoader).Load(Toolkit::Internal::VisualUrl(url), dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, false); } uint32_t ApplyMask(AsyncImageLoader asyncImageLoader, diff --git a/dali-toolkit/devel-api/image-loader/async-image-loader-devel.h b/dali-toolkit/devel-api/image-loader/async-image-loader-devel.h index 9cf1589..ce91e09 100644 --- a/dali-toolkit/devel-api/image-loader/async-image-loader-devel.h +++ b/dali-toolkit/devel-api/image-loader/async-image-loader-devel.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_DEVEL_API_IMAGE_LOADER_ASYNC_IMAGE_LOADER_DEVEL_H /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -31,7 +31,7 @@ namespace Toolkit { namespace DevelAsyncImageLoader { -typedef Signal PixelBufferLoadedSignalType; +typedef Signal&)> PixelBufferLoadedSignalType; /** * @brief Whether to multiply alpha into color channels on load diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag index c2324e7..edbdba9 100644 --- a/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag +++ b/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag @@ -13,6 +13,9 @@ #ifndef ATLAS_CUSTOM_WARP #define ATLAS_CUSTOM_WARP 0 #endif +#ifndef IS_REQUIRED_YUV_TO_RGB +#define IS_REQUIRED_YUV_TO_RGB 0 +#endif INPUT mediump vec2 vTexCoord; #if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE @@ -25,6 +28,10 @@ INPUT mediump vec4 vCornerRadius; #endif uniform sampler2D sTexture; +#if IS_REQUIRED_YUV_TO_RGB +uniform sampler2D sTextureU; +uniform sampler2D sTextureV; +#endif #if IS_REQUIRED_ALPHA_MASKING uniform sampler2D sMaskTexture; @@ -224,6 +231,20 @@ mediump float calculateCornerOpacity() } #endif +#if IS_REQUIRED_YUV_TO_RGB +lowp vec3 ConvertYuvToRgb(mediump vec2 texCoord) +{ + 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; +} +#endif + void main() { #if ATLAS_DEFAULT_WARP @@ -235,7 +256,11 @@ void main() mediump vec2 texCoord = vTexCoord; #endif +#if IS_REQUIRED_YUV_TO_RGB + lowp vec4 textureColor = vec4(ConvertYuvToRgb(texCoord), 1.0) * vec4( mixColor, 1.0 ) * uColor; +#else lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * vec4( mixColor, 1.0 ) * uColor; +#endif #if IS_REQUIRED_ALPHA_MASKING mediump float maskAlpha = TEXTURE(sMaskTexture, vMaskTexCoord).a; diff --git a/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp b/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp index 64639b5..b084fa8 100644 --- a/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp +++ b/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -64,14 +64,15 @@ uint32_t AsyncImageLoader::Load(const VisualUrl& url, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, - DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad) + DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, + bool loadYuvPlanes) { if(!mIsLoadThreadStarted) { mLoadThread.Start(); mIsLoadThreadStarted = true; } - mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, url, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad)); + mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, url, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, loadYuvPlanes)); return mLoadTaskId; } @@ -135,7 +136,7 @@ void AsyncImageLoader::ProcessLoadedImage() { if(mPixelBufferLoadedSignal.GetConnectionCount() > 0) { - mPixelBufferLoadedSignal.Emit(next->id, next->pixelBuffer); + mPixelBufferLoadedSignal.Emit(next->id, next->pixelBuffers); } else if(mLoadedSignal.GetConnectionCount() > 0) { diff --git a/dali-toolkit/internal/image-loader/async-image-loader-impl.h b/dali-toolkit/internal/image-loader/async-image-loader-impl.h index 39e4690..1b45bf1 100644 --- a/dali-toolkit/internal/image-loader/async-image-loader-impl.h +++ b/dali-toolkit/internal/image-loader/async-image-loader-impl.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_ASYNC_IMAGE_LOADER_IMPL_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -59,7 +59,8 @@ public: FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, - DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad); + DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, + bool loadYuvPlanes); /** * @brief Starts an image loading task by encoded image buffer. diff --git a/dali-toolkit/internal/image-loader/image-atlas-impl.cpp b/dali-toolkit/internal/image-loader/image-atlas-impl.cpp index 31c3351..5a04a0f 100644 --- a/dali-toolkit/internal/image-loader/image-atlas-impl.cpp +++ b/dali-toolkit/internal/image-loader/image-atlas-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -162,7 +162,7 @@ bool ImageAtlas::Upload(Vector4& textureRect, unsigned int packPositionY = 0; if(mPacker.Pack(dimensions.GetWidth(), dimensions.GetHeight(), packPositionX, packPositionY)) { - unsigned short loadId = GetImplementation(mAsyncLoader).Load(url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF); + unsigned short loadId = GetImplementation(mAsyncLoader).Load(url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF, false); mLoadingTaskInfoContainer.PushBack(new LoadingTaskInfo(loadId, packPositionX, packPositionY, dimensions.GetWidth(), dimensions.GetHeight(), atlasUploadObserver)); // apply the half pixel correction textureRect.x = (static_cast(packPositionX) + 0.5f) / mWidth; // left diff --git a/dali-toolkit/internal/image-loader/image-load-thread.cpp b/dali-toolkit/internal/image-loader/image-load-thread.cpp index 3c4ee19..6d795a2 100644 --- a/dali-toolkit/internal/image-loader/image-load-thread.cpp +++ b/dali-toolkit/internal/image-loader/image-load-thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -19,11 +19,11 @@ #include "image-load-thread.h" // EXTERNAL INCLUDES -#include #include #include #include #include +#include namespace Dali { @@ -50,7 +50,7 @@ LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLo { } -LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad) +LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, bool loadYuvPlanes) : pixelBuffer(), url(url), encodedImageBuffer(), @@ -65,7 +65,8 @@ LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dime contentScale(1.0f), cropToMask(false), animatedImageLoading(), - frameIndex(0u) + frameIndex(0u), + loadYuvPlanes(loadYuvPlanes) { } @@ -119,7 +120,18 @@ void LoadingTask::Load() } else if(url.IsValid() && url.IsLocalResource()) { - pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection); + if(!loadYuvPlanes) + { + pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection); + } + else + { + Dali::LoadImagePlanesFromFile(url.GetUrl(), pixelBuffers, dimensions, fittingMode, samplingMode, orientationCorrection); + if(!pixelBuffers.empty()) + { + pixelBuffer = pixelBuffers.front(); + } + } } else if(url.IsValid()) { @@ -284,6 +296,11 @@ void ImageLoadThread::AddCompletedTask(LoadingTask* task) Mutex::ScopedLock lock(mMutex); mCompleteQueue.PushBack(task); + if(task->pixelBuffers.empty() && task->pixelBuffer) + { + task->pixelBuffers.push_back(task->pixelBuffer); + } + // wake up the main thread mTrigger->Trigger(); } diff --git a/dali-toolkit/internal/image-loader/image-load-thread.h b/dali-toolkit/internal/image-loader/image-load-thread.h index 95ec260..b575539 100644 --- a/dali-toolkit/internal/image-loader/image-load-thread.h +++ b/dali-toolkit/internal/image-loader/image-load-thread.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_IMAGE_LOAD_THREAD_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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,10 +26,10 @@ #include #include #include +#include #include #include #include -#include namespace Dali { @@ -68,7 +68,8 @@ struct LoadingTask FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, - DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad); + DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, + bool loadYuvPlanes); /** * Constructor. @@ -144,6 +145,9 @@ public: bool cropToMask; ///< Whether to crop the content to the mask size Dali::AnimatedImageLoading animatedImageLoading; uint32_t frameIndex; + bool loadYuvPlanes{false}; + + std::vector pixelBuffers{}; }; /** diff --git a/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp b/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp index 8e7e304..fcbd744 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) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -46,24 +46,23 @@ const int NATIVE_SHADER_TYPE_OFFSET = VisualFactoryCache::ShaderType::NATIVE_IMA // enum of required list when we select shader enum class ImageVisualRequireFlag : uint32_t { - DEFAULT = 0, - ROUNDED_CORNER = 1 << 0, - BORDERLINE = 1 << 1, - ALPHA_MASKING = 1 << 2, + DEFAULT = 0, + ROUNDED_CORNER = 1 << 0, + BORDERLINE = 1 << 1, + ALPHA_MASKING = 1 << 2, }; -static constexpr auto SHADER_TYPE_COUNT = 8u; +static constexpr auto SHADER_TYPE_COUNT = 8u; VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[SHADER_TYPE_COUNT] = -{ - VisualFactoryCache::IMAGE_SHADER, - VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER, - VisualFactoryCache::IMAGE_SHADER_BORDERLINE, - VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE, - VisualFactoryCache::IMAGE_SHADER_MASKING, - VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_MASKING, - VisualFactoryCache::IMAGE_SHADER_BORDERLINE_MASKING, - VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING -}; + { + VisualFactoryCache::IMAGE_SHADER, + VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER, + VisualFactoryCache::IMAGE_SHADER_BORDERLINE, + VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE, + VisualFactoryCache::IMAGE_SHADER_MASKING, + VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_MASKING, + VisualFactoryCache::IMAGE_SHADER_BORDERLINE_MASKING, + VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING}; } // unnamed namespace @@ -74,31 +73,42 @@ FeatureBuilder& FeatureBuilder::EnableTextureAtlas(bool enableAtlas) mTextureAtlas = (enableAtlas ? TextureAtlas::ENABLED : TextureAtlas::DISABLED); return *this; } + FeatureBuilder& FeatureBuilder::ApplyDefaultTextureWrapMode(bool applyDefaultTextureWrapMode) { mDefaultTextureWrapMode = (applyDefaultTextureWrapMode ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY); return *this; } + FeatureBuilder& FeatureBuilder::EnableRoundedCorner(bool enableRoundedCorner) { mRoundedCorner = (enableRoundedCorner ? RoundedCorner::ENABLED : RoundedCorner::DISABLED); return *this; } + FeatureBuilder& FeatureBuilder::EnableBorderline(bool enableBorderline) { mBorderline = (enableBorderline ? Borderline::ENABLED : Borderline::DISABLED); return *this; } + FeatureBuilder& FeatureBuilder::SetTextureForFragmentShaderCheck(const Dali::Texture& texture) { mTexture = texture; return *this; } + FeatureBuilder& FeatureBuilder::EnableAlphaMasking(bool enableAlphaMasking) { mAlphaMasking = (enableAlphaMasking ? AlphaMasking::ENABLED : AlphaMasking::DISABLED); return *this; } + +FeatureBuilder& FeatureBuilder::EnableYuvToRgb(bool enableYuvToRgb) +{ + mColorConversion = (enableYuvToRgb ? ColorConversion::YUV_TO_RGB : ColorConversion::DONT_NEED); + return *this; +} } // namespace ImageVisualShaderFeature ImageVisualShaderFactory::ImageVisualShaderFactory() @@ -112,7 +122,7 @@ ImageVisualShaderFactory::~ImageVisualShaderFactory() Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, const ImageVisualShaderFeature::FeatureBuilder& featureBuilder) { - Shader shader; + Shader shader; VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::IMAGE_SHADER; const auto& atlasing = featureBuilder.mTextureAtlas; @@ -120,6 +130,7 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, con const auto& roundedCorner = featureBuilder.mRoundedCorner; const auto& borderline = featureBuilder.mBorderline; const auto& alphaMasking = featureBuilder.mAlphaMasking; + const auto& colorConversion = featureBuilder.mColorConversion; const auto& changeFragmentShader = (featureBuilder.mTexture && DevelTexture::IsNative(featureBuilder.mTexture)) ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE; @@ -160,42 +171,56 @@ Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, con shaderType = static_cast(static_cast(shaderType) + NATIVE_SHADER_TYPE_OFFSET); } + if(colorConversion == ImageVisualShaderFeature::ColorConversion::YUV_TO_RGB) + { + shaderType = VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB; + } + shader = factoryCache.GetShader(shaderType); if(!shader) { std::string vertexShaderPrefixList; std::string fragmentShaderPrefixList; - if(atlasing == ImageVisualShaderFeature::TextureAtlas::ENABLED) + + // We don't support other properties in case of yuv format for now. + if(colorConversion == ImageVisualShaderFeature::ColorConversion::YUV_TO_RGB) { - if(defaultTextureWrapping == ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY) - { - fragmentShaderPrefixList += "#define ATLAS_DEFAULT_WARP 1\n"; - } - else - { - fragmentShaderPrefixList += "#define ATLAS_CUSTOM_WARP 1\n"; - } + fragmentShaderPrefixList += "#define IS_REQUIRED_YUV_TO_RGB 1\n"; } else { - if(roundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED) - { - vertexShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n"; - fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n"; - } - if(borderline == ImageVisualShaderFeature::Borderline::ENABLED) + if(atlasing == ImageVisualShaderFeature::TextureAtlas::ENABLED) { - vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n"; - fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n"; + if(defaultTextureWrapping == ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY) + { + fragmentShaderPrefixList += "#define ATLAS_DEFAULT_WARP 1\n"; + } + else + { + fragmentShaderPrefixList += "#define ATLAS_CUSTOM_WARP 1\n"; + } } - if(alphaMasking == ImageVisualShaderFeature::AlphaMasking::ENABLED) + else { - vertexShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING 1\n"; - fragmentShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING 1\n"; + if(roundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED) + { + vertexShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n"; + fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n"; + } + if(borderline == ImageVisualShaderFeature::Borderline::ENABLED) + { + vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n"; + fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n"; + } + if(alphaMasking == ImageVisualShaderFeature::AlphaMasking::ENABLED) + { + vertexShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING 1\n"; + fragmentShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING 1\n"; + } } } - std::string vertexShader = std::string(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_VERT.data()); + std::string vertexShader = std::string(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_VERT.data()); std::string fragmentShader = std::string(Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_FRAG.data()); if(changeFragmentShader == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE) diff --git a/dali-toolkit/internal/visuals/image-visual-shader-factory.h b/dali-toolkit/internal/visuals/image-visual-shader-factory.h index 1e1974d..20ae85e 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) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -107,6 +107,18 @@ enum Type }; } // namespace AlphaMasking +namespace ColorConversion +{ +/** + * @brief Whether the color format conversion is needed or not + */ +enum Type +{ + DONT_NEED = 0, ///< Not need to convert + YUV_TO_RGB ///< Need yuv to rgb conversion +}; +} // namespace ColorConversion + /** * @brief Collection of current image visual feature. Only use for ImageVisualShaderFactory::GetShader() */ @@ -118,6 +130,7 @@ struct FeatureBuilder mRoundedCorner(RoundedCorner::DISABLED), mBorderline(Borderline::DISABLED), mAlphaMasking(AlphaMasking::DISABLED), + mColorConversion(ColorConversion::DONT_NEED), mTexture() { } @@ -128,12 +141,14 @@ struct FeatureBuilder FeatureBuilder& EnableBorderline(bool enableBorderline); FeatureBuilder& SetTextureForFragmentShaderCheck(const Dali::Texture& texture); FeatureBuilder& EnableAlphaMasking(bool enableAlphaMasking); + FeatureBuilder& EnableYuvToRgb(bool enableYuvToRgb); TextureAtlas::Type mTextureAtlas : 2; ///< Whether use texture with atlas, or not. default as TextureAtlas::DISABLED DefaultTextureWrapMode::Type mDefaultTextureWrapMode : 2; ///< Whether apply to texture wraping in default, or not. default as DefaultTextureWrapMode::APPLY RoundedCorner::Type mRoundedCorner : 2; ///< Whether use rounded corner, or not. default as RoundedCorner::DISABLED Borderline::Type mBorderline : 2; ///< Whether use borderline, or not. default as Borderline::DISABLED AlphaMasking::Type mAlphaMasking : 2; ///< Whether use runtime alpha masking, or not. default as AlphaMasking::DISABLED + ColorConversion::Type mColorConversion : 2; ///< Whether the color format conversion is needed or not Dali::Texture mTexture; ///< Texture to check whether we need to change fragment shader or not }; diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index 650c508..406b85d 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -477,7 +477,7 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize) } auto textureSet = mImpl->mRenderer.GetTextures(); - if(textureSet) + if(textureSet && textureSet.GetTextureCount()) { auto texture = textureSet.GetTexture(0); if(texture) @@ -513,7 +513,7 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize) } else { - Actor actor = mPlacementActor.GetHandle(); + Actor actor = mPlacementActor.GetHandle(); Vector2 imageSize = Vector2::ZERO; if(actor) { @@ -521,8 +521,8 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize) } mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize); Texture brokenImage = mImpl->mRenderer.GetTextures().GetTexture(0); - naturalSize.x = brokenImage.GetWidth(); - naturalSize.y = brokenImage.GetWidth(); + naturalSize.x = brokenImage.GetWidth(); + naturalSize.y = brokenImage.GetWidth(); } return; } @@ -658,10 +658,19 @@ void ImageVisual::InitializeRenderer() if(mTextures) { mImpl->mRenderer.SetTextures(mTextures); - if(DevelTexture::IsNative(mTextures.GetTexture(0))) + + bool needToUpdateShader = DevelTexture::IsNative(mTextures.GetTexture(0)); + if(mTextures.GetTextureCount() > 1) + { + mNeedYuvToRgb = true; + needToUpdateShader = true; + } + + if(needToUpdateShader) { UpdateShader(); } + mTextures.Reset(); // Visual should not keep a handle to the texture after this point. } @@ -882,6 +891,13 @@ void ImageVisual::UploadComplete(bool loadingSuccess, int32_t textureId, Texture sampler.SetWrapMode(mWrapModeU, mWrapModeV); textureSet.SetSampler(0u, sampler); mImpl->mRenderer.SetTextures(textureSet); + + if(textureSet.GetTextureCount() > 1) + { + mNeedYuvToRgb = true; + + UpdateShader(); + } } if(actor) @@ -974,9 +990,9 @@ Shader ImageVisual::GenerateShader() const { Shader shader; - bool usesWholeTexture = true; - const bool useStandardShader = !mImpl->mCustomShader; - const bool useNativeImage = (mTextures && DevelTexture::IsNative(mTextures.GetTexture(0))); + bool usesWholeTexture = true; + const bool useStandardShader = !mImpl->mCustomShader; + const bool useNativeImage = (mTextures && DevelTexture::IsNative(mTextures.GetTexture(0))); if(useStandardShader) { @@ -984,12 +1000,12 @@ Shader ImageVisual::GenerateShader() const shader = mImageVisualShaderFactory.GetShader( mFactoryCache, ImageVisualShaderFeature::FeatureBuilder() - .EnableTextureAtlas(mImpl->mFlags & Impl::IS_ATLASING_APPLIED && !useNativeImage) - .ApplyDefaultTextureWrapMode(mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE) - .EnableRoundedCorner(IsRoundedCornerRequired()) - .EnableBorderline(IsBorderlineRequired()) - .SetTextureForFragmentShaderCheck(useNativeImage ? mTextures.GetTexture(0) : Dali::Texture()) - ); + .EnableTextureAtlas(mImpl->mFlags & Impl::IS_ATLASING_APPLIED && !useNativeImage) + .ApplyDefaultTextureWrapMode(mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE) + .EnableRoundedCorner(IsRoundedCornerRequired()) + .EnableBorderline(IsBorderlineRequired()) + .SetTextureForFragmentShaderCheck(useNativeImage ? mTextures.GetTexture(0) : Dali::Texture()) + .EnableYuvToRgb(mNeedYuvToRgb)); } else { diff --git a/dali-toolkit/internal/visuals/image/image-visual.h b/dali-toolkit/internal/visuals/image/image-visual.h index c0a3f75..1c61a3a 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.h +++ b/dali-toolkit/internal/visuals/image/image-visual.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_INTERNAL_IMAGE_VISUAL_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -343,6 +343,7 @@ private: TextureManager::LoadState mLoadState; ///< The texture loading state 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. }; } // namespace Internal diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp index 5286717..7334cf7 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.cpp +++ b/dali-toolkit/internal/visuals/texture-manager-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -38,9 +38,9 @@ namespace { -constexpr auto INITIAL_CACHE_NUMBER = size_t{0u}; -constexpr auto DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS = size_t{4u}; -constexpr auto DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS = size_t{8u}; +constexpr auto INITIAL_CACHE_NUMBER = size_t{0u}; +constexpr auto DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS = size_t{4u}; +constexpr auto DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS = size_t{8u}; constexpr auto NUMBER_OF_LOCAL_LOADER_THREADS_ENV = "DALI_TEXTURE_LOCAL_THREADS"; constexpr auto NUMBER_OF_REMOTE_LOADER_THREADS_ENV = "DALI_TEXTURE_REMOTE_THREADS"; @@ -234,7 +234,8 @@ TextureSet TextureManager::LoadAnimatedImageTexture(Dali::AnimatedImageLoading a preMultiply, animatedImageLoading, frameIndex, - useCache); + useCache, + false); TextureManager::LoadState loadState = GetTextureStateInternal(textureId); if(loadState == TextureManager::LoadState::UPLOADED) @@ -291,7 +292,7 @@ Devel::PixelBuffer TextureManager::LoadPixelBuffer( } else { - RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, false, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false); + RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, false, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false, false); } return pixelBuffer; @@ -470,7 +471,7 @@ TextureManager::TextureId TextureManager::RequestLoad( TextureManager::ReloadPolicy reloadPolicy, TextureManager::MultiplyOnLoad& preMultiplyOnLoad) { - return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, false, desiredSize, fittingMode, samplingMode, useAtlas, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, true); + return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, false, desiredSize, fittingMode, samplingMode, useAtlas, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, true, true); } TextureManager::TextureId TextureManager::RequestLoad( @@ -487,14 +488,15 @@ TextureManager::TextureId TextureManager::RequestLoad( TextureManager::ReloadPolicy reloadPolicy, TextureManager::MultiplyOnLoad& preMultiplyOnLoad) { - return RequestLoadInternal(url, maskTextureId, contentScale, cropToMask, desiredSize, fittingMode, samplingMode, useAtlas, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, true); + bool loadYuvPlanes = (maskTextureId == INVALID_TEXTURE_ID) ? true : false; + return RequestLoadInternal(url, maskTextureId, contentScale, cropToMask, desiredSize, fittingMode, samplingMode, useAtlas, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, true, loadYuvPlanes); } TextureManager::TextureId TextureManager::RequestMaskLoad(const VisualUrl& maskUrl, StorageType storageType) { // Use the normal load procedure to get the alpha mask. auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; - return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, false, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, storageType, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, true); + return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, false, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, storageType, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, true, false); } TextureManager::TextureId TextureManager::RequestLoadInternal( @@ -513,7 +515,8 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( TextureManager::MultiplyOnLoad& preMultiplyOnLoad, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, - bool useCache) + bool useCache, + bool loadYuvPlanes) { // First check if the requested Texture is cached. TextureHash textureHash = INITIAL_CACHE_NUMBER; @@ -523,8 +526,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( textureHash = GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId); // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision. - cacheIndex = FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, - storageType, maskTextureId, preMultiplyOnLoad, (animatedImageLoading) ? true : false); + cacheIndex = FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, storageType, maskTextureId, preMultiplyOnLoad, (animatedImageLoading) ? true : false); } TextureManager::TextureId textureId = INVALID_TEXTURE_ID; @@ -564,7 +566,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( // Insert this buffer at mTextureInfoContainer. // This buffer will decode at ImageLoaderThread. bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD); - mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex)); + mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex, false)); cacheIndex = mTextureInfoContainer.size() - 1u; DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New buffered texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId); @@ -577,7 +579,7 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( // We need a new Texture. textureId = GenerateUniqueTextureId(); bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD); - mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex)); + mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex, loadYuvPlanes)); cacheIndex = mTextureInfoContainer.size() - 1u; DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId); @@ -846,7 +848,8 @@ std::string TextureManager::AddExternalEncodedImageBuffer(const EncodedImageBuff { // If same buffer added, increase reference count and return. elem.referenceCount++; - return VisualUrl::CreateBufferUrl(std::to_string(elem.textureId));; + return VisualUrl::CreateBufferUrl(std::to_string(elem.textureId)); + ; } } TextureManager::EncodedBufferTextureInfo info(GenerateUniqueTextureId(), encodedImageBuffer); @@ -894,7 +897,7 @@ EncodedImageBuffer TextureManager::RemoveExternalEncodedImageBuffer(const std::s std::string location = VisualUrl::GetLocation(url); if(location.size() > 0u) { - TextureId id = std::stoi(location); + TextureId id = std::stoi(location); const auto end = mEncodedBufferTextures.end(); for(auto iter = mEncodedBufferTextures.begin(); iter != end; ++iter) { @@ -1048,7 +1051,7 @@ void TextureManager::LoadTexture(TextureInfo& textureInfo, TextureUploadObserver } else { - loadingHelperIt->Load(textureInfo.textureId, textureInfo.url, textureInfo.desiredSize, textureInfo.fittingMode, textureInfo.samplingMode, textureInfo.orientationCorrection, premultiplyOnLoad); + loadingHelperIt->Load(textureInfo.textureId, textureInfo.url, textureInfo.desiredSize, textureInfo.fittingMode, textureInfo.samplingMode, textureInfo.orientationCorrection, premultiplyOnLoad, textureInfo.loadYuvPlanes); } } ObserveTexture(textureInfo, observer); @@ -1103,7 +1106,7 @@ void TextureManager::ObserveTexture(TextureInfo& textureInfo, } } -void TextureManager::AsyncLoadComplete(AsyncLoadingInfoContainerType& loadingContainer, uint32_t id, Devel::PixelBuffer pixelBuffer) +void TextureManager::AsyncLoadComplete(AsyncLoadingInfoContainerType& loadingContainer, uint32_t id, std::vector& pixelBuffers) { DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( id:%d )\n", id); @@ -1123,7 +1126,7 @@ void TextureManager::AsyncLoadComplete(AsyncLoadingInfoContainerType& loadingCon if(textureInfo.loadState != LoadState::CANCELLED) { // textureInfo can be invalidated after this call (as the mTextureInfoContainer may be modified) - PostLoad(textureInfo, pixelBuffer); + PostLoad(textureInfo, pixelBuffers); } else { @@ -1136,92 +1139,111 @@ void TextureManager::AsyncLoadComplete(AsyncLoadingInfoContainerType& loadingCon } } -void TextureManager::PostLoad(TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer) +void TextureManager::PostLoad(TextureInfo& textureInfo, std::vector& pixelBuffers) { // Was the load successful? - if(pixelBuffer && (pixelBuffer.GetWidth() != 0) && (pixelBuffer.GetHeight() != 0)) + // if(pixelBuffer && (pixelBuffer.GetWidth() != 0) && (pixelBuffer.GetHeight() != 0)) + if(!pixelBuffers.empty()) { - // No atlas support for now - textureInfo.useAtlas = NO_ATLAS; - textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied(); - - if(textureInfo.storageType == StorageType::UPLOAD_TO_TEXTURE) + if(pixelBuffers.size() == 1) { - // If there is a mask texture ID associated with this texture, then apply the mask - // if it's already loaded. If it hasn't, and the mask is still loading, - // wait for the mask to finish loading. - if(textureInfo.maskTextureId != INVALID_TEXTURE_ID) + Devel::PixelBuffer pixelBuffer = pixelBuffers[0]; + + // No atlas support for now + textureInfo.useAtlas = NO_ATLAS; + textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied(); + + if(textureInfo.storageType == StorageType::UPLOAD_TO_TEXTURE) { - if(textureInfo.loadState == LoadState::MASK_APPLYING) + // If there is a mask texture ID associated with this texture, then apply the mask + // if it's already loaded. If it hasn't, and the mask is still loading, + // wait for the mask to finish loading. + if(textureInfo.maskTextureId != INVALID_TEXTURE_ID) { - textureInfo.loadState = LoadState::MASK_APPLIED; - UploadTexture(pixelBuffer, textureInfo); - NotifyObservers(textureInfo, true); - } - else - { - LoadState maskLoadState = GetTextureStateInternal(textureInfo.maskTextureId); - textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily - if(maskLoadState == LoadState::LOADING) + if(textureInfo.loadState == LoadState::MASK_APPLYING) { - textureInfo.loadState = LoadState::WAITING_FOR_MASK; + textureInfo.loadState = LoadState::MASK_APPLIED; + UploadTexture(pixelBuffer, textureInfo); + NotifyObservers(textureInfo, true); } - else if(maskLoadState == LoadState::LOAD_FINISHED) + else { - int32_t maskCacheIndex = GetCacheIndexFromId(textureInfo.maskTextureId); - if(maskCacheIndex != INVALID_CACHE_INDEX) + LoadState maskLoadState = GetTextureStateInternal(textureInfo.maskTextureId); + textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily + if(maskLoadState == LoadState::LOADING) { - TextureInfo& maskTextureInfo(mTextureInfoContainer[maskCacheIndex]); - if(maskTextureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER) + textureInfo.loadState = LoadState::WAITING_FOR_MASK; + } + else if(maskLoadState == LoadState::LOAD_FINISHED) + { + int32_t maskCacheIndex = GetCacheIndexFromId(textureInfo.maskTextureId); + if(maskCacheIndex != INVALID_CACHE_INDEX) { - // Send New Task to Thread - ApplyMask(textureInfo, textureInfo.maskTextureId); + TextureInfo& maskTextureInfo(mTextureInfoContainer[maskCacheIndex]); + if(maskTextureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER) + { + // Send New Task to Thread + ApplyMask(textureInfo, textureInfo.maskTextureId); + } } } - } - else if(maskLoadState == LoadState::UPLOADED) - { - int32_t maskCacheIndex = GetCacheIndexFromId(textureInfo.maskTextureId); - if(maskCacheIndex != INVALID_CACHE_INDEX) + else if(maskLoadState == LoadState::UPLOADED) { - TextureInfo& maskTextureInfo(mTextureInfoContainer[maskCacheIndex]); - if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE) + int32_t maskCacheIndex = GetCacheIndexFromId(textureInfo.maskTextureId); + if(maskCacheIndex != INVALID_CACHE_INDEX) { - // Upload image texture. textureInfo.loadState will be UPLOADED. - UploadTexture(textureInfo.pixelBuffer, textureInfo); - if(maskTextureInfo.textureSet.GetTextureCount() > 0u) + TextureInfo& maskTextureInfo(mTextureInfoContainer[maskCacheIndex]); + if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE) { - Texture maskTexture = maskTextureInfo.textureSet.GetTexture(0u); - textureInfo.textureSet.SetTexture(1u, maskTexture); + // Upload image texture. textureInfo.loadState will be UPLOADED. + UploadTexture(textureInfo.pixelBuffer, textureInfo); + if(maskTextureInfo.textureSet.GetTextureCount() > 0u) + { + Texture maskTexture = maskTextureInfo.textureSet.GetTexture(0u); + textureInfo.textureSet.SetTexture(1u, maskTexture); + } + // notify mask texture set. + NotifyObservers(textureInfo, true); } - // notify mask texture set. - NotifyObservers(textureInfo, true); } } } } + else + { + UploadTexture(pixelBuffer, textureInfo); + NotifyObservers(textureInfo, true); + } } else { - UploadTexture(pixelBuffer, textureInfo); - NotifyObservers(textureInfo, true); + textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data + textureInfo.loadState = LoadState::LOAD_FINISHED; + + if(textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER) + { + NotifyObservers(textureInfo, true); + } + else // for the StorageType::KEEP_PIXEL_BUFFER and StorageType::KEEP_TEXTURE + { + // Check if there was another texture waiting for this load to complete + // (e.g. if this was an image mask, and its load is on a different thread) + CheckForWaitingTexture(textureInfo); + } } } else { - textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data - textureInfo.loadState = LoadState::LOAD_FINISHED; + // YUV case + // No atlas support for now + textureInfo.useAtlas = NO_ATLAS; + textureInfo.preMultiplied = false; - if(textureInfo.storageType == StorageType::RETURN_PIXEL_BUFFER) + if(textureInfo.storageType == StorageType::UPLOAD_TO_TEXTURE) { + UploadTextures(pixelBuffers, textureInfo); NotifyObservers(textureInfo, true); } - else // for the StorageType::KEEP_PIXEL_BUFFER and StorageType::KEEP_TEXTURE - { - // Check if there was another texture waiting for this load to complete - // (e.g. if this was an image mask, and its load is on a different thread) - CheckForWaitingTexture(textureInfo); - } } } else @@ -1259,7 +1281,7 @@ void TextureManager::CheckForWaitingTexture(TextureInfo& maskTextureInfo) ApplyMask(textureInfo, maskTextureInfo.textureId); } } - else if (maskTextureInfo.loadState == LoadState::UPLOADED) + else if(maskTextureInfo.loadState == LoadState::UPLOADED) { if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE) { @@ -1338,6 +1360,46 @@ void TextureManager::UploadTexture(Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo.loadState = LoadState::UPLOADED; } +void TextureManager::UploadTextures(std::vector& pixelBuffers, TextureInfo& textureInfo) +{ + if(textureInfo.loadState != LoadState::UPLOADED && textureInfo.useAtlas != USE_ATLAS) + { + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::UploadTextures() New Texture for textureId:%d\n", textureInfo.textureId); + + // Not premultiplied + textureInfo.preMultiplied = false; + + auto& renderingAddOn = RenderingAddOn::Get(); + if(renderingAddOn.IsValid()) + { + renderingAddOn.CreateGeometry(textureInfo.textureId, pixelBuffers[0]); + } + + if(!textureInfo.textureSet) + { + textureInfo.textureSet = TextureSet::New(); + } + + uint32_t index = 0; + for(auto&& iter : pixelBuffers) + { + Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, iter.GetPixelFormat(), iter.GetWidth(), iter.GetHeight()); + + PixelData pixelData = Devel::PixelBuffer::Convert(iter); + texture.Upload(pixelData); + textureInfo.textureSet.SetTexture(index++, texture); + } + + pixelBuffers.clear(); + } + + // Update the load state. + // Note: This is regardless of success as we care about whether a + // load attempt is in progress or not. If unsuccessful, a broken + // image is still loaded. + textureInfo.loadState = LoadState::UPLOADED; +} + void TextureManager::NotifyObservers(TextureInfo& textureInfo, bool success) { TextureId textureId = textureInfo.textureId; @@ -1348,7 +1410,7 @@ void TextureManager::NotifyObservers(TextureInfo& textureInfo, bool success) if(info->animatedImageLoading) { - info->frameCount = info->animatedImageLoading.GetImageCount(); + info->frameCount = info->animatedImageLoading.GetImageCount(); info->frameInterval = info->animatedImageLoading.GetFrameInterval(info->frameIndex); info->animatedImageLoading.Reset(); } @@ -1594,7 +1656,8 @@ void TextureManager::AsyncLoadingHelper::Load(TextureId FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, - DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad) + DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, + bool loadYuvPlanes) { mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId)); if(DALI_UNLIKELY(url.IsBufferResource())) @@ -1604,7 +1667,7 @@ void TextureManager::AsyncLoadingHelper::Load(TextureId } else { - auto id = GetImplementation(mLoader).Load(url, desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad); + auto id = GetImplementation(mLoader).Load(url, desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, loadYuvPlanes); mLoadingInfoContainer.back().loadId = id; } } @@ -1638,10 +1701,10 @@ TextureManager::AsyncLoadingHelper::AsyncLoadingHelper( this, &AsyncLoadingHelper::AsyncLoadComplete); } -void TextureManager::AsyncLoadingHelper::AsyncLoadComplete(uint32_t id, - Devel::PixelBuffer pixelBuffer) +void TextureManager::AsyncLoadingHelper::AsyncLoadComplete(uint32_t id, + std::vector& pixelBuffers) { - mTextureManager.AsyncLoadComplete(mLoadingInfoContainer, id, pixelBuffer); + mTextureManager.AsyncLoadComplete(mLoadingInfoContainer, id, pixelBuffers); } Geometry TextureManager::GetRenderGeometry(TextureId textureId, uint32_t& frontElements, uint32_t& backElements) diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.h b/dali-toolkit/internal/visuals/texture-manager-impl.h index 4098dd8..40e4bbd 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.h +++ b/dali-toolkit/internal/visuals/texture-manager-impl.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -58,7 +58,7 @@ typedef IntrusivePtr ImageAtlasManagerPtr; class TextureManager : public ConnectionTracker { public: - typedef int32_t TextureId; ///< The TextureId type. This is used as a handle to refer to a particular Texture. + typedef int32_t TextureId; ///< The TextureId type. This is used as a handle to refer to a particular Texture. static constexpr int32_t INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error /** @@ -520,7 +520,8 @@ private: MultiplyOnLoad& preMultiplyOnLoad, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, - bool useCache); + bool useCache, + bool loadYuvPlanes); /** * @brief Get the current state of a texture @@ -553,7 +554,8 @@ private: bool orientationCorrection, bool preMultiplyOnLoad, Dali::AnimatedImageLoading animatedImageLoading, - uint32_t frameIndex) + uint32_t frameIndex, + bool loadYuvPlanes) : url(url), desiredSize(desiredSize), useSize(desiredSize), @@ -576,7 +578,8 @@ private: cropToMask(cropToMask), orientationCorrection(true), preMultiplyOnLoad(preMultiplyOnLoad), - preMultiplied(false) + preMultiplied(false), + loadYuvPlanes(loadYuvPlanes) { isAnimatedImageFormat = (animatedImageLoading) ? true : false; } @@ -615,6 +618,7 @@ private: bool preMultiplyOnLoad : 1; ///< true if the image's color should be multiplied by it's alpha bool preMultiplied : 1; ///< true if the image's color was multiplied by it's alpha bool isAnimatedImageFormat : 1; ///< true if the image is requested from animated image visual. + bool loadYuvPlanes : 1; ///< true if the image should be loaded as yuv planes }; /** @@ -706,7 +710,7 @@ private: * @param[in] id This is the async image loaders Id * @param[in] pixelBuffer The loaded image data */ - void AsyncLoadComplete(AsyncLoadingInfoContainerType& container, uint32_t id, Devel::PixelBuffer pixelBuffer); + void AsyncLoadComplete(AsyncLoadingInfoContainerType& container, uint32_t id, std::vector& pixelBuffer); /** * @brief Performs Post-Load steps including atlasing. @@ -714,7 +718,7 @@ private: * @param[in] pixelBuffer The image pixelBuffer * @return True if successful */ - void PostLoad(TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer); + void PostLoad(TextureManager::TextureInfo& textureInfo, std::vector& pixelBuffer); /** * Check if there is a texture waiting to be masked. If there @@ -739,6 +743,14 @@ private: void UploadTexture(Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo); /** + * Upload the texture specified in pixelBuffer to the appropriate location + * @param[in] pixelBuffer The image data to upload + * @param[in] textureInfo The texture info containing the location to + * store the data to. + */ + void UploadTextures(std::vector& pixelBuffers, TextureInfo& textureInfo); + + /** * Creates tiled geometry of for the texture which separates fully-opaque * tiles from ones which use transparency. * @param pixelBuffer @@ -856,7 +868,8 @@ private: FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, - DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad); + DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, + bool loadYuvPlanes); /** * @brief Apply mask @@ -894,7 +907,7 @@ private: * @param[in] id Loader id * @param[in] pixelBuffer Image data */ - void AsyncLoadComplete(uint32_t id, Devel::PixelBuffer pixelBuffer); + void AsyncLoadComplete(uint32_t id, std::vector& pixelBuffers); private: Toolkit::AsyncImageLoader mLoader; diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.h b/dali-toolkit/internal/visuals/visual-factory-cache.h index 3dbbb6f..ba008fd 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) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -90,6 +90,7 @@ public: IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING, IMAGE_SHADER_ATLAS_DEFAULT_WRAP, IMAGE_SHADER_ATLAS_CUSTOM_WRAP, + IMAGE_SHADER_YUV_TO_RGB, NATIVE_IMAGE_SHADER, NATIVE_IMAGE_SHADER_ROUNDED_CORNER, NATIVE_IMAGE_SHADER_BORDERLINE, @@ -324,12 +325,12 @@ private: struct BrokenImageInfo { BrokenImageInfo() - :visualType(), - url(""), - npatchId(NPatchData::INVALID_NPATCH_DATA_ID), - texture(), - width(0), - height(0) + : visualType(), + url(""), + npatchId(NPatchData::INVALID_NPATCH_DATA_ID), + texture(), + width(0), + height(0) { } @@ -338,20 +339,20 @@ private: } // Data - VisualUrl::Type visualType; - std::string url; - NPatchData::NPatchDataId npatchId; - Texture texture; - uint32_t width; - uint32_t height; + VisualUrl::Type visualType; + std::string url; + NPatchData::NPatchDataId npatchId; + Texture texture; + uint32_t width; + uint32_t height; }; Geometry mGeometry[GEOMETRY_TYPE_MAX + 1]; Shader mShader[SHADER_TYPE_MAX + 1]; - ImageAtlasManagerPtr mAtlasManager; - TextureManager mTextureManager; - NPatchLoader mNPatchLoader; + ImageAtlasManagerPtr mAtlasManager; + TextureManager mTextureManager; + NPatchLoader mNPatchLoader; SvgRasterizeThread* mSvgRasterizeThread; std::unique_ptr mVectorAnimationManager; diff --git a/dali-toolkit/public-api/controls/control.h b/dali-toolkit/public-api/controls/control.h index 7e6beff..360429c 100644 --- a/dali-toolkit/public-api/controls/control.h +++ b/dali-toolkit/public-api/controls/control.h @@ -153,8 +153,8 @@ public: DOWN, ///< Move keyboard focus towards the down direction @SINCE_1_0.0 PAGE_UP, ///< Move keyboard focus towards the previous page direction @SINCE_1_2.14 PAGE_DOWN, ///< Move keyboard focus towards the next page direction @SINCE_1_2.14 - FORWARD, ///< Move keyboard focus towards the forward direction @SINCE_2_1.10 - BACKWARD, ///< Move keyboard focus towards the backward direction @SINCE_2_1.10 + FORWARD, ///< Move keyboard focus towards the forward direction + BACKWARD, ///< Move keyboard focus towards the backward direction }; }; diff --git a/dali-toolkit/public-api/image-loader/async-image-loader.cpp b/dali-toolkit/public-api/image-loader/async-image-loader.cpp index 3cbfc60..97ebf62 100644 --- a/dali-toolkit/public-api/image-loader/async-image-loader.cpp +++ b/dali-toolkit/public-api/image-loader/async-image-loader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -59,12 +59,12 @@ AsyncImageLoader AsyncImageLoader::New() uint32_t AsyncImageLoader::Load(const std::string& url) { - return GetImplementation(*this).Load(Toolkit::Internal::VisualUrl(url), ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF); + return GetImplementation(*this).Load(Toolkit::Internal::VisualUrl(url), ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF, false); } uint32_t AsyncImageLoader::Load(const std::string& url, ImageDimensions dimensions) { - return GetImplementation(*this).Load(Toolkit::Internal::VisualUrl(url), dimensions, FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF); + return GetImplementation(*this).Load(Toolkit::Internal::VisualUrl(url), dimensions, FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF, false); } uint32_t AsyncImageLoader::Load(const std::string& url, @@ -73,7 +73,7 @@ uint32_t AsyncImageLoader::Load(const std::string& url, SamplingMode::Type samplingMode, bool orientationCorrection) { - return GetImplementation(*this).Load(Toolkit::Internal::VisualUrl(url), dimensions, fittingMode, samplingMode, orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF); + return GetImplementation(*this).Load(Toolkit::Internal::VisualUrl(url), dimensions, fittingMode, samplingMode, orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF, false); } bool AsyncImageLoader::Cancel(uint32_t loadingTaskId)