true, ///< orientationCorrection
preMultiply);
- textureManager.AsyncLoadComplete(textureId, pixelBuffer);
- textureManager.AsyncLoadComplete(maskInfo->mAlphaMaskId, Dali::Devel::PixelBuffer());
+ std::vector<Devel::PixelBuffer> pixelBuffers;
+ pixelBuffers.push_back(pixelBuffer);
+ textureManager.AsyncLoadComplete(textureId, pixelBuffers);
+ std::vector<Devel::PixelBuffer> maskBuffers;
+ textureManager.AsyncLoadComplete(maskInfo->mAlphaMaskId, maskBuffers);
textureManager.Remove(maskInfo->mAlphaMaskId, nullptr);
textureManager.Remove(textureId, &observer);
}
// ApplyMask event come back, and do nothing.
// CAPTION : HARD-CODING.
{
- textureManager.AsyncLoadComplete(textureId1, Dali::Devel::PixelBuffer());
+ std::vector<Devel::PixelBuffer> pixelBuffers;
+ textureManager.AsyncLoadComplete(textureId1, pixelBuffers);
textureManager.Remove(maskInfo->mAlphaMaskId, nullptr);
}
// CAPTION : HARD-CODING.
{
- textureManager.AsyncLoadComplete(textureId2, Dali::Devel::PixelBuffer());
+ std::vector<Devel::PixelBuffer> pixelBuffers;
+ textureManager.AsyncLoadComplete(textureId2, pixelBuffers);
textureManager.Remove(textureId2, &observer2);
}
DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
END_TEST;
-}
\ No newline at end of file
+}
// EXTERNAL INCLUDE
#include <cstddef>
+#include <string>
namespace Dali
{
-
namespace EnvironmentVariable
{
-
namespace
{
-const char * gReturnValue = NULL;
-}
+const char* gReturnValue = NULL;
+std::string gEnvironmentVariableName;
+std::string gEnvironmentVariableValue;
+} // namespace
-const char * GetEnvironmentVariable( const char * variable )
+const char* GetEnvironmentVariable(const char* variable)
{
+ if(gEnvironmentVariableName == variable)
+ {
+ return gEnvironmentVariableValue.c_str();
+ }
return gReturnValue;
}
-void SetTestingEnvironmentVariable( bool testing)
+void SetTestingEnvironmentVariable(bool testing)
{
- if( testing )
+ if(testing)
{
gReturnValue = "1";
}
}
}
+void SetTestEnvironmentVariable(const char* variable, const char* value)
+{
+ gEnvironmentVariableName = variable;
+ gEnvironmentVariableValue = value;
+}
+
} // namespace EnvironmentVariable
} // namespace Dali
#define DALI_TOOLKIT_ENVIRONMENT_VARIABLE_H
/*
- * Copyright (c) 2019 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.
namespace Dali
{
-
namespace EnvironmentVariable
{
+const char* GetEnvironmentVariable(const char* variable);
-const char * GetEnvironmentVariable( const char * variable );
+void SetTestingEnvironmentVariable(bool);
-void SetTestingEnvironmentVariable( bool );
+void SetTestEnvironmentVariable(const char* variable, const char* value);
} // namespace EnvironmentVariable
} // namespace Dali
-
#endif // DALI_TOOLKIT_ENVIRONMENT_VARIABLE_H
#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-environment-variable.h>
#include <toolkit-event-thread-callback.h>
#include <toolkit-timer.h>
const char* TEST_REMOTE_INVALID_FILE_NAME = "https://www.tizen.org/invalid.png";
const char* TEST_MASK_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/mask.png";
const char* TEST_ROTATED_IMAGE = TEST_RESOURCE_DIR "/keyboard-Landscape.jpg";
+const char* TEST_YUV420_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1-yuv420.jpg";
+
+constexpr auto LOAD_IMAGE_YUV_PLANES_ENV = "DALI_LOAD_IMAGE_YUV_PLANES_ENV";
bool gResourceReadySignalFired = false;
std::vector<int> gReadyIds = {};
application.Render();
DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
- Renderer renderer = actor.GetRendererAt(0u);
+ Renderer renderer = actor.GetRendererAt(0u);
TextureSet textures = renderer.GetTextures();
DALI_TEST_CHECK(textures);
DALI_TEST_EQUALS(textures.GetTextureCount(), 2u, TEST_LOCATION);
application.Render();
DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
- Renderer renderer = actor.GetRendererAt(0u);
+ Renderer renderer = actor.GetRendererAt(0u);
TextureSet textures = renderer.GetTextures();
DALI_TEST_CHECK(textures);
DALI_TEST_EQUALS(textures.GetTextureCount(), 1u, TEST_LOCATION);
application.Render();
DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
- Renderer renderer = actor.GetRendererAt(0u);
+ Renderer renderer = actor.GetRendererAt(0u);
TextureSet textures = renderer.GetTextures();
DALI_TEST_CHECK(textures);
DALI_TEST_EQUALS(textures.GetTextureCount(), 2u, TEST_LOCATION);
END_TEST;
}
+
+int UtcDaliImageVisualLoadImagePlanes01(void)
+{
+ EnvironmentVariable::SetTestEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV, "1");
+
+ ToolkitTestApplication application;
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK(factory);
+
+ Property::Map propertyMap;
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+ propertyMap.Insert(ImageVisual::Property::URL, TEST_YUV420_IMAGE_FILE_NAME);
+
+ Visual::Base visual = factory.CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+ actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 3, TEST_LOCATION);
+
+ Renderer renderer = actor.GetRendererAt(0);
+ auto preMultipliedAlpha = renderer.GetProperty<bool>(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA);
+ DALI_TEST_EQUALS(preMultipliedAlpha, false, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliImageVisualLoadImagePlanes02(void)
+{
+ EnvironmentVariable::SetTestEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV, "1");
+
+ ToolkitTestApplication application;
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK(factory);
+
+ // Alpha masking case - not support yuv planes
+ Property::Map propertyMap;
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+ propertyMap.Insert(ImageVisual::Property::URL, TEST_YUV420_IMAGE_FILE_NAME);
+ propertyMap.Insert(ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME);
+
+ Visual::Base visual = factory.CreateVisual(propertyMap);
+ DALI_TEST_CHECK(visual);
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+ actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 1, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliImageVisualLoadImagePlanes03(void)
+{
+ EnvironmentVariable::SetTestEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV, "1");
+
+ ToolkitTestApplication application;
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK(factory);
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ Property::Map propertyMap;
+ propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+ propertyMap.Insert(ImageVisual::Property::URL, TEST_YUV420_IMAGE_FILE_NAME);
+ propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, 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));
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 3, TEST_LOCATION);
+
+ END_TEST;
+}
/*
- * 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.
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,
#endif
uniform sampler2D sTexture;
+#ifdef IS_REQUIRED_YUV_TO_RGB
+uniform sampler2D sTextureU;
+uniform sampler2D sTextureV;
+#endif
#ifdef IS_REQUIRED_ALPHA_MASKING
uniform sampler2D sMaskTexture;
}
#endif
+#ifdef 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()
{
#ifdef ATLAS_DEFAULT_WARP
mediump vec2 texCoord = vTexCoord;
#endif
+#ifdef 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
#ifdef IS_REQUIRED_ALPHA_MASKING
mediump float maskAlpha = TEXTURE(sMaskTexture, vMaskTexCoord).a;
FittingMode::Type fittingMode,
SamplingMode::Type samplingMode,
bool orientationCorrection,
- DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
+ DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
+ bool loadPlanes)
{
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, loadPlanes));
return mLoadTaskId;
}
{
if(mPixelBufferLoadedSignal.GetConnectionCount() > 0)
{
- std::vector<Devel::PixelBuffer> pixelBuffers{next->pixelBuffer};
- mPixelBufferLoadedSignal.Emit(next->id, pixelBuffers);
+ mPixelBufferLoadedSignal.Emit(next->id, next->pixelBuffers);
}
else if(mLoadedSignal.GetConnectionCount() > 0)
{
PixelData pixelData;
- if(next->pixelBuffer)
+ if(!next->pixelBuffers.empty())
{
- pixelData = Devel::PixelBuffer::Convert(next->pixelBuffer);
+ pixelData = Devel::PixelBuffer::Convert(next->pixelBuffers[0]);
}
mLoadedSignal.Emit(next->id, pixelData);
}
#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.
DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
/**
- * @copydoc Toolkit::AsyncImageLoader::Load( const std::string&, ImageDimensions, FittingMode::Type, SamplingMode::Type, bool , DevelAsyncImageLoader::PreMultiplyOnLoad )
+ * @brief Starts an image loading task.
+ * @param[in] url The URL of the image file to load
+ * @param[in] dimensions The width and height to fit the loaded image to
+ * @param[in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter
+ * @param[in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size
+ * @param[in] orientationCorrection Reorient the image to respect any orientation metadata in its header
+ * @param[in] preMultiplyOnLoad ON if the image color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+ * @param[in] loadPlanes true to load image planes or false to load bitmap image.
+ * @return The loading task id
*/
uint32_t Load(const VisualUrl& url,
ImageDimensions dimensions,
FittingMode::Type fittingMode,
SamplingMode::Type samplingMode,
bool orientationCorrection,
- DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+ DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
+ bool loadPlanes);
/**
* @brief Starts an image loading task by encoded image buffer.
uint32_t packPositionY = 0;
if(mPacker.Pack(dimensions.GetWidth(), dimensions.GetHeight(), packPositionX, packPositionY))
{
- uint32_t loadId = GetImplementation(mAsyncLoader).Load(url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF);
+ uint32_t 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<float>(packPositionX) + 0.5f) / mWidth; // left
/*
- * 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.
#include "image-load-thread.h"
// EXTERNAL INCLUDES
-#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali/devel-api/adaptor-framework/thread-settings.h>
#include <dali/integration-api/adaptor-framework/adaptor.h>
#include <dali/integration-api/debug.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
namespace Dali
{
namespace Internal
{
LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
-: pixelBuffer(),
- url(),
+: url(),
encodedImageBuffer(),
id(id),
dimensions(),
fittingMode(),
samplingMode(),
- orientationCorrection(),
preMultiplyOnLoad(preMultiplyOnLoad),
- isMaskTask(false),
maskPixelBuffer(),
contentScale(1.0f),
- cropToMask(false),
animatedImageLoading(animatedImageLoading),
- frameIndex(frameIndex)
+ frameIndex(frameIndex),
+ orientationCorrection(),
+ isMaskTask(false),
+ cropToMask(false),
+ loadPlanes(false)
{
}
-LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
-: pixelBuffer(),
- url(url),
+LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, bool loadPlanes)
+: url(url),
encodedImageBuffer(),
id(id),
dimensions(dimensions),
fittingMode(fittingMode),
samplingMode(samplingMode),
- orientationCorrection(orientationCorrection),
preMultiplyOnLoad(preMultiplyOnLoad),
- isMaskTask(false),
maskPixelBuffer(),
contentScale(1.0f),
- cropToMask(false),
animatedImageLoading(),
- frameIndex(0u)
+ frameIndex(0u),
+ orientationCorrection(orientationCorrection),
+ isMaskTask(false),
+ cropToMask(false),
+ loadPlanes(loadPlanes)
{
}
LoadingTask::LoadingTask(uint32_t id, const EncodedImageBuffer& encodedImageBuffer, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
-: pixelBuffer(),
- url(),
+: url(),
encodedImageBuffer(encodedImageBuffer),
id(id),
dimensions(dimensions),
fittingMode(fittingMode),
samplingMode(samplingMode),
- orientationCorrection(orientationCorrection),
preMultiplyOnLoad(preMultiplyOnLoad),
- isMaskTask(false),
maskPixelBuffer(),
contentScale(1.0f),
- cropToMask(false),
animatedImageLoading(),
- frameIndex(0u)
+ frameIndex(0u),
+ orientationCorrection(orientationCorrection),
+ isMaskTask(false),
+ cropToMask(false),
+ loadPlanes(false)
{
}
LoadingTask::LoadingTask(uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::PixelBuffer maskPixelBuffer, float contentScale, bool cropToMask, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
-: pixelBuffer(pixelBuffer),
- url(""),
+: url(""),
encodedImageBuffer(),
id(id),
dimensions(),
fittingMode(),
samplingMode(),
- orientationCorrection(),
preMultiplyOnLoad(preMultiplyOnLoad),
- isMaskTask(true),
maskPixelBuffer(maskPixelBuffer),
contentScale(contentScale),
- cropToMask(cropToMask),
animatedImageLoading(),
- frameIndex(0u)
+ frameIndex(0u),
+ orientationCorrection(),
+ isMaskTask(true),
+ cropToMask(cropToMask),
+ loadPlanes(false)
{
+ pixelBuffers.push_back(pixelBuffer);
}
void LoadingTask::Load()
{
+ Devel::PixelBuffer pixelBuffer;
if(animatedImageLoading)
{
pixelBuffer = animatedImageLoading.LoadFrame(frameIndex);
}
else if(url.IsValid() && url.IsLocalResource())
{
- pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection);
+ if(loadPlanes)
+ {
+ Dali::LoadImagePlanesFromFile(url.GetUrl(), pixelBuffers, dimensions, fittingMode, samplingMode, orientationCorrection);
+ }
+ else
+ {
+ pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection);
+ }
}
else if(url.IsValid())
{
pixelBuffer = Dali::DownloadImageSynchronously(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection);
}
- if(!pixelBuffer)
+ if(pixelBuffer)
+ {
+ pixelBuffers.push_back(pixelBuffer);
+ }
+
+ if(pixelBuffers.empty())
{
DALI_LOG_ERROR("LoadingTask::Load: Loading is failed: %s\n", url.GetUrl().c_str());
}
void LoadingTask::ApplyMask()
{
- pixelBuffer.ApplyMask(maskPixelBuffer, contentScale, cropToMask);
+ if(!pixelBuffers.empty())
+ {
+ pixelBuffers[0].ApplyMask(maskPixelBuffer, contentScale, cropToMask);
+ }
}
void LoadingTask::MultiplyAlpha()
{
- if(pixelBuffer && Pixel::HasAlpha(pixelBuffer.GetPixelFormat()))
+ if(!pixelBuffers.empty() && Pixel::HasAlpha(pixelBuffers[0].GetPixelFormat()))
{
if(preMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON)
{
- pixelBuffer.MultiplyColorByAlpha();
+ pixelBuffers[0].MultiplyColorByAlpha();
}
}
}
#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.
#include <dali/devel-api/threading/mutex.h>
#include <dali/devel-api/threading/thread.h>
#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/images/image-operations.h>
#include <dali/public-api/object/ref-object.h>
-#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
namespace Dali
{
* @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
* @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
* @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+ * @param [in] loadPlanes true to load image planes or false to load bitmap image.
*/
LoadingTask(uint32_t id,
const VisualUrl& url,
FittingMode::Type fittingMode,
SamplingMode::Type samplingMode,
bool orientationCorrection,
- DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+ DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
+ bool loadPlanes);
/**
* Constructor.
LoadingTask& operator=(const LoadingTask& queue);
public:
- Devel::PixelBuffer pixelBuffer; ///< pixelBuffer handle after successful load
- ///< or pixelBuffer to be masked image in the mask task
- VisualUrl url; ///< url of the image to load
- EncodedImageBuffer encodedImageBuffer; ///< encoded buffer of the image to load
- uint32_t id; ///< The unique id associated with this task.
- ImageDimensions dimensions; ///< dimensions to load
- FittingMode::Type fittingMode; ///< fitting options
- SamplingMode::Type samplingMode; ///< sampling options
- bool orientationCorrection : 1; ///< if orientation correction is needed
- DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad; //< if the image's color should be multiplied by it's alpha
-
- bool isMaskTask; ///< whether this task is for mask or not
+ std::vector<Devel::PixelBuffer> pixelBuffers{}; ///< pixelBuffer handle after successful load
+ ///< or pixelBuffer to be masked image in the mask task
+ VisualUrl url; ///< url of the image to load
+ EncodedImageBuffer encodedImageBuffer; ///< encoded buffer of the image to load
+ uint32_t id; ///< The unique id associated with this task.
+ ImageDimensions dimensions; ///< dimensions to load
+ FittingMode::Type fittingMode; ///< fitting options
+ SamplingMode::Type samplingMode; ///< sampling options
+ DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad; ///< if the image's color should be multiplied by it's alpha
+
Devel::PixelBuffer maskPixelBuffer; ///< pixelBuffer of mask image
float contentScale; ///< The factor to scale the content
- bool cropToMask; ///< Whether to crop the content to the mask size
Dali::AnimatedImageLoading animatedImageLoading;
uint32_t frameIndex;
+
+ bool orientationCorrection : 1; ///< if orientation correction is needed
+ bool isMaskTask : 1; ///< whether this task is for mask or not
+ bool cropToMask : 1; ///< Whether to crop the content to the mask size
+ bool loadPlanes : 1; ///< Whether to load image planes
};
/**
const Dali::FittingMode::Type& fittingMode,
const Dali::SamplingMode::Type& samplingMode,
const bool& orientationCorrection,
- const DevelAsyncImageLoader::PreMultiplyOnLoad& preMultiplyOnLoad)
+ const DevelAsyncImageLoader::PreMultiplyOnLoad& preMultiplyOnLoad,
+ const bool& loadYuvPlanes)
{
mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId));
if(DALI_UNLIKELY(url.IsBufferResource()))
}
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;
}
}
if(loadingInfo.loadId == id)
{
// Call TextureManager::AsyncLoadComplete
- mTextureManager.AsyncLoadComplete(loadingInfo.textureId, pixelBuffers[0]);
+ mTextureManager.AsyncLoadComplete(loadingInfo.textureId, pixelBuffers);
}
mLoadingInfoContainer.pop_front();
* @param[in] orientationCorrection Whether to use image metadata to rotate or flip the image,
* e.g., from portrait to landscape
* @param[in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+ * @param[in] loadYuvPlanes True if the image should be loaded as yuv planes
*/
void Load(const TextureManager::TextureId& textureId,
const VisualUrl& url,
const Dali::FittingMode::Type& fittingMode,
const Dali::SamplingMode::Type& samplingMode,
const bool& orientationCorrection,
- const DevelAsyncImageLoader::PreMultiplyOnLoad& preMultiplyOnLoad);
+ const DevelAsyncImageLoader::PreMultiplyOnLoad& preMultiplyOnLoad,
+ const bool& loadYuvPlanes);
/**
* @brief Apply mask
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_ENV";
size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue)
{
return GetNumberOfThreads(NUMBER_OF_REMOTE_LOADER_THREADS_ENV, DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS);
}
+bool NeedToLoadYuvPlanes()
+{
+ auto loadYuvPlanesString = Dali::EnvironmentVariable::GetEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV);
+ bool loadYuvPlanes = loadYuvPlanesString ? std::atoi(loadYuvPlanesString) : false;
+ return loadYuvPlanes;
+}
} // namespace
namespace Dali
mLifecycleObservers(),
mLoadQueue(),
mRemoveQueue(),
- mQueueLoadFlag(false)
+ mQueueLoadFlag(false),
+ mLoadYuvPlanes(NeedToLoadYuvPlanes())
{
// Initialize the AddOn
RenderingAddOn::Get();
: false;
if(synchronousAtlasAvaliable)
{
- Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection);
+ std::vector<Devel::PixelBuffer> pixelBuffers;
+ LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection, false, pixelBuffers);
- if(pixelBuffer && maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
+ if(!pixelBuffers.empty() && maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
{
- Devel::PixelBuffer maskPixelBuffer = LoadImageSynchronously(maskInfo->mAlphaMaskUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true);
- if(maskPixelBuffer)
+ std::vector<Devel::PixelBuffer> maskPixelBuffers;
+ LoadImageSynchronously(maskInfo->mAlphaMaskUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true, false, maskPixelBuffers);
+ if(!maskPixelBuffers.empty())
{
- pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
+ pixelBuffers[0].ApplyMask(maskPixelBuffers[0], maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
}
}
PixelData data;
- if(pixelBuffer)
+ if(!pixelBuffers.empty())
{
- PreMultiply(pixelBuffer, preMultiplyOnLoad);
- data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+ PreMultiply(pixelBuffers[0], preMultiplyOnLoad);
+ data = Devel::PixelBuffer::Convert(pixelBuffers[0]); // takes ownership of buffer
if(data)
{
const std::uint32_t& frameIndex,
const bool& synchronousLoading)
{
- TextureHash textureHash = INITIAL_HASH_NUMBER;
- TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX;
+ TextureHash textureHash = INITIAL_HASH_NUMBER;
+ TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX;
+ bool loadYuvPlanes = (mLoadYuvPlanes && maskTextureId == INVALID_TEXTURE_ID && storageType == StorageType::UPLOAD_TO_TEXTURE);
+
if(storageType != StorageType::RETURN_PIXEL_BUFFER)
{
textureHash = mTextureCacheManager.GenerateHash(url, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask, frameIndex);
bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
// Cache new texutre, and get cacheIndex.
- cacheIndex = mTextureCacheManager.AppendCache(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex));
+ cacheIndex = mTextureCacheManager.AppendCache(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex, loadYuvPlanes));
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d, frameindex=%d premultiply=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, frameIndex, preMultiply);
}
if(!(textureInfo.loadState == TextureManager::LoadState::UPLOADED ||
textureInfo.loadState == TextureManager::LoadState::LOAD_FINISHED))
{
- Devel::PixelBuffer pixelBuffer = LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection);
+ std::vector<Devel::PixelBuffer> pixelBuffers;
+ LoadImageSynchronously(url, desiredSize, fittingMode, samplingMode, orientationCorrection, loadYuvPlanes, pixelBuffers);
- if(!pixelBuffer)
+ if(pixelBuffers.empty())
{
// If pixelBuffer loading is failed in synchronously, call Remove() method.
Remove(textureId, nullptr);
if(storageType == StorageType::KEEP_PIXEL_BUFFER) // For the mask image loading.
{
- textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data
+ textureInfo.pixelBuffer = pixelBuffers[0]; // Store the pixel data
textureInfo.loadState = LoadState::LOAD_FINISHED;
}
else // For the image loading.
Devel::PixelBuffer maskPixelBuffer = mTextureCacheManager[maskCacheIndex].pixelBuffer;
if(maskPixelBuffer)
{
- pixelBuffer.ApplyMask(maskPixelBuffer, contentScale, cropToMask);
+ pixelBuffers[0].ApplyMask(maskPixelBuffer, contentScale, cropToMask);
}
else
{
DALI_LOG_ERROR("Mask image is not stored in cache.\n");
}
}
- PreMultiply(pixelBuffer, preMultiplyOnLoad);
+ PreMultiply(pixelBuffers[0], preMultiplyOnLoad);
// Upload texture
- UploadTexture(pixelBuffer, textureInfo);
+ UploadTextures(pixelBuffers, textureInfo);
if(maskTexture && textureInfo.textureSet)
{
textureInfo.textureSet.SetTexture(1u, maskTexture);
}
}
-Devel::PixelBuffer TextureManager::LoadImageSynchronously(
- const VisualUrl& url,
- const Dali::ImageDimensions& desiredSize,
- const Dali::FittingMode::Type& fittingMode,
- const Dali::SamplingMode::Type& samplingMode,
- const bool& orientationCorrection)
+void TextureManager::LoadImageSynchronously(
+ const VisualUrl& url,
+ const Dali::ImageDimensions& desiredSize,
+ const Dali::FittingMode::Type& fittingMode,
+ const Dali::SamplingMode::Type& samplingMode,
+ const bool& orientationCorrection,
+ const bool& loadYuvPlanes,
+ std::vector<Devel::PixelBuffer>& pixelBuffers)
{
Devel::PixelBuffer pixelBuffer;
if(url.IsBufferResource())
}
else
{
- pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection);
+ if(loadYuvPlanes)
+ {
+ Dali::LoadImagePlanesFromFile(url.GetUrl(), pixelBuffers, desiredSize, fittingMode, samplingMode, orientationCorrection);
+ }
+ else
+ {
+ pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection);
+ }
+ }
+
+ if(pixelBuffer)
+ {
+ pixelBuffers.push_back(pixelBuffer);
}
- return pixelBuffer;
}
void TextureManager::AddObserver(TextureManager::LifecycleObserver& observer)
}
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);
}
}
-void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureId, Devel::PixelBuffer pixelBuffer)
+void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureId, std::vector<Devel::PixelBuffer>& pixelBuffers)
{
TextureCacheIndex cacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d CacheIndex:%d )\n", textureId, cacheIndex.GetIndex());
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
{
}
}
-void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer)
+void TextureManager::PostLoad(TextureManager::TextureInfo& textureInfo, std::vector<Devel::PixelBuffer>& pixelBuffers)
{
// Was the load successful?
- if(pixelBuffer && (pixelBuffer.GetWidth() != 0) && (pixelBuffer.GetHeight() != 0))
+ if(!pixelBuffers.empty())
{
- // No atlas support for now
- textureInfo.useAtlas = 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.
- // note, If the texture is already uploaded synchronously during loading,
- // we don't need to apply mask.
- if(textureInfo.loadState != LoadState::UPLOADED &&
- textureInfo.maskTextureId != INVALID_TEXTURE_ID)
+ Devel::PixelBuffer pixelBuffer = pixelBuffers[0];
+ if(pixelBuffer && (pixelBuffer.GetWidth() != 0) && (pixelBuffer.GetHeight() != 0))
{
- if(textureInfo.loadState == LoadState::MASK_APPLYING)
- {
- textureInfo.loadState = LoadState::MASK_APPLIED;
- UploadTexture(pixelBuffer, textureInfo);
- NotifyObservers(textureInfo, true);
- }
- else
+ // No atlas support for now
+ textureInfo.useAtlas = UseAtlas::NO_ATLAS;
+ textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied();
+
+ if(textureInfo.storageType == StorageType::UPLOAD_TO_TEXTURE)
{
- LoadState maskLoadState = mTextureCacheManager.GetTextureStateInternal(textureInfo.maskTextureId);
- textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily
- if(maskLoadState == LoadState::LOADING)
- {
- textureInfo.loadState = LoadState::WAITING_FOR_MASK;
- }
- else if(maskLoadState == LoadState::LOAD_FINISHED || maskLoadState == LoadState::UPLOADED)
+ // 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.
+ // note, If the texture is already uploaded synchronously during loading,
+ // we don't need to apply mask.
+ if(textureInfo.loadState != LoadState::UPLOADED &&
+ textureInfo.maskTextureId != INVALID_TEXTURE_ID)
{
- // Send New Task to Thread
- TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureInfo.maskTextureId);
- if(maskCacheIndex != INVALID_CACHE_INDEX)
+ if(textureInfo.loadState == LoadState::MASK_APPLYING)
+ {
+ textureInfo.loadState = LoadState::MASK_APPLIED;
+ UploadTexture(pixelBuffer, textureInfo);
+ NotifyObservers(textureInfo, true);
+ }
+ else
{
- TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]);
- if(maskTextureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER)
+ LoadState maskLoadState = mTextureCacheManager.GetTextureStateInternal(textureInfo.maskTextureId);
+ textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily
+ if(maskLoadState == LoadState::LOADING)
{
- // Send New Task to Thread
- ApplyMask(textureInfo, textureInfo.maskTextureId);
+ textureInfo.loadState = LoadState::WAITING_FOR_MASK;
}
- else if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE)
+ else if(maskLoadState == LoadState::LOAD_FINISHED || maskLoadState == LoadState::UPLOADED)
{
- // Upload image texture. textureInfo.loadState will be UPLOADED.
- UploadTexture(textureInfo.pixelBuffer, textureInfo);
- if(maskTextureInfo.textureSet.GetTextureCount() > 0u)
+ // Send New Task to Thread
+ TextureCacheIndex maskCacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureInfo.maskTextureId);
+ if(maskCacheIndex != INVALID_CACHE_INDEX)
{
- Texture maskTexture = maskTextureInfo.textureSet.GetTexture(0u);
- textureInfo.textureSet.SetTexture(1u, maskTexture);
+ TextureInfo& maskTextureInfo(mTextureCacheManager[maskCacheIndex]);
+ if(maskTextureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER)
+ {
+ // Send New Task to Thread
+ ApplyMask(textureInfo, textureInfo.maskTextureId);
+ }
+ else if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE)
+ {
+ // 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.
+ }
+ else // maskLoadState == LoadState::LOAD_FAILED
+ {
+ // Url texture load success, But alpha mask texture load failed. Run as normal image upload.
+ DALI_LOG_ERROR("Alpha mask image loading failed! Image will not be masked\n");
+ UploadTexture(pixelBuffer, textureInfo);
NotifyObservers(textureInfo, true);
}
}
}
- else // maskLoadState == LoadState::LOAD_FAILED
+ else
{
- // Url texture load success, But alpha mask texture load failed. Run as normal image upload.
- DALI_LOG_ERROR("Alpha mask image loading failed! Image will not be masked\n");
UploadTexture(pixelBuffer, textureInfo);
NotifyObservers(textureInfo, true);
}
}
- }
- else
- {
- UploadTexture(pixelBuffer, textureInfo);
- NotifyObservers(textureInfo, true);
+ else
+ {
+ 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 = UseAtlas::NO_ATLAS;
+ textureInfo.preMultiplied = false;
- 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);
- }
+ UploadTextures(pixelBuffers, textureInfo);
+ NotifyObservers(textureInfo, true);
}
}
else
textureInfo.loadState = LoadState::UPLOADED;
}
+void TextureManager::UploadTextures(std::vector<Devel::PixelBuffer>& pixelBuffers, TextureManager::TextureInfo& textureInfo)
+{
+ if(!pixelBuffers.empty() && textureInfo.loadState != LoadState::UPLOADED && textureInfo.useAtlas != UseAtlas::USE_ATLAS)
+ {
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, " TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId);
+
+ // Check if this pixelBuffer is premultiplied
+ textureInfo.preMultiplied = pixelBuffers[0].IsAlphaPreMultiplied();
+
+ 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&& pixelBuffer : pixelBuffers)
+ {
+ Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight());
+
+ PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer);
+ 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(TextureManager::TextureInfo& textureInfo, const bool& success)
{
TextureId textureId = textureInfo.textureId;
* @param[in] samplingMode The SamplingMode to use
* @param[in] orientationCorrection Whether to use image metadata to rotate or flip the image,
* e.g., from portrait to landscape
+ * @param[in] loadYuvPlanes True if the image should be loaded as yuv planes
+ * @param[out] pixelBuffers The image pixelBuffer
* @return PixelBuffer of loaded image.
*/
- Devel::PixelBuffer LoadImageSynchronously(
- const VisualUrl& url,
- const Dali::ImageDimensions& desiredSize,
- const Dali::FittingMode::Type& fittingMode,
- const Dali::SamplingMode::Type& samplingMode,
- const bool& orientationCorrection);
+ void LoadImageSynchronously(
+ const VisualUrl& url,
+ const Dali::ImageDimensions& desiredSize,
+ const Dali::FittingMode::Type& fittingMode,
+ const Dali::SamplingMode::Type& samplingMode,
+ const bool& orientationCorrection,
+ const bool& loadYuvPlanes,
+ std::vector<Devel::PixelBuffer>& pixelBuffers);
private:
// Load and queue
/**
* @brief Performs Post-Load steps including atlasing.
- * @param[in] textureInfo The struct associated with this Texture
- * @param[in] pixelBuffer The image pixelBuffer
+ * @param[in] textureInfo The struct associated with this Texture
+ * @param[in] pixelBuffers The image pixelBuffer
* @return True if successful
*/
- void PostLoad(TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer);
+ void PostLoad(TextureManager::TextureInfo& textureInfo, std::vector<Devel::PixelBuffer>& pixelBuffers);
/**
* Check if there is a texture waiting to be masked. If there
*/
void UploadTexture(Devel::PixelBuffer& pixelBuffer, TextureManager::TextureInfo& textureInfo);
+ /**
+ * Upload the texture specified in pixelBuffer to the appropriate location
+ * @param[in] pixelBuffers The image data to upload
+ * @param[in] textureInfo The texture info containing the location to store the data to.
+ */
+ void UploadTextures(std::vector<Devel::PixelBuffer>& pixelBuffers, TextureManager::TextureInfo& textureInfo);
+
/**
* Notify the current observers that the texture upload is complete,
* then remove the observers from the list.
/**
* @brief Common method to handle loading completion.
* TextureAsyncLoadingHelper will call this API After async loading finished.
- * @param[in] textureId The ID of the texture load complete.
- * @param[in] pixelBuffer The loaded image data
+ * @param[in] textureId The ID of the texture load complete.
+ * @param[in] pixelBuffers The loaded image data
*/
- void AsyncLoadComplete(const TextureManager::TextureId& textureId, Devel::PixelBuffer pixelBuffer);
+ void AsyncLoadComplete(const TextureManager::TextureId& textureId, std::vector<Devel::PixelBuffer>& pixelBuffers);
private:
/**
Dali::Vector<LoadQueueElement> mLoadQueue; ///< Queue of textures to load after NotifyObservers
Dali::Vector<TextureManager::TextureId> mRemoveQueue; ///< Queue of textures to remove after NotifyObservers
bool mQueueLoadFlag; ///< Flag that causes Load Textures to be queued.
+ bool mLoadYuvPlanes; ///< A global flag to specify if the image should be loaded as yuv planes
};
} // namespace Internal
const bool& orientationCorrection,
const bool& preMultiplyOnLoad,
const Dali::AnimatedImageLoading& animatedImageLoading,
- const std::uint32_t& frameIndex)
+ const std::uint32_t& frameIndex,
+ const bool& loadYuvPlanes)
: url(url),
desiredSize(desiredSize),
useSize(desiredSize),
cropToMask(cropToMask),
orientationCorrection(true),
preMultiplyOnLoad(preMultiplyOnLoad),
- preMultiplied(false)
+ preMultiplied(false),
+ loadYuvPlanes(loadYuvPlanes)
{
isAnimatedImageFormat = (animatedImageLoading) ? true : false;
}
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
};
} // namespace TextureManagerType
// 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,
+ COLOR_CONVERSION = 1 << 3,
};
-static constexpr auto SHADER_TYPE_COUNT = 8u;
+static constexpr auto SHADER_TYPE_COUNT = 12u;
VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[SHADER_TYPE_COUNT] =
{
VisualFactoryCache::IMAGE_SHADER,
VisualFactoryCache::IMAGE_SHADER_MASKING,
VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_MASKING,
VisualFactoryCache::IMAGE_SHADER_BORDERLINE_MASKING,
- VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING};
-
+ VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING,
+ 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};
} // unnamed namespace
namespace ImageVisualShaderFeature
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::EnableAlphaMaskingOnRendering(bool enableAlphaMaskingOnRendering)
{
mAlphaMaskingOnRendering = (enableAlphaMaskingOnRendering ? AlphaMaskingOnRendering::ENABLED : AlphaMaskingOnRendering::DISABLED);
return *this;
}
+
+FeatureBuilder& FeatureBuilder::EnableYuvToRgb(bool enableYuvToRgb)
+{
+ mColorConversion = (enableYuvToRgb ? ColorConversion::YUV_TO_RGB : ColorConversion::DONT_NEED);
+ return *this;
+}
} // namespace ImageVisualShaderFeature
ImageVisualShaderFactory::ImageVisualShaderFactory()
const auto& roundedCorner = featureBuilder.mRoundedCorner;
const auto& borderline = featureBuilder.mBorderline;
const auto& alphaMaskingOnRendering = featureBuilder.mAlphaMaskingOnRendering;
+ const auto& colorConversion = featureBuilder.mColorConversion;
const auto& changeFragmentShader = (featureBuilder.mTexture && DevelTexture::IsNative(featureBuilder.mTexture))
- ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE
- : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
+ ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE
+ : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
if(atlasing == ImageVisualShaderFeature::TextureAtlas::ENABLED)
{
{
shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::ALPHA_MASKING);
}
+ else if(colorConversion == ImageVisualShaderFeature::ColorConversion::YUV_TO_RGB) // Not support gpu masking and color conversion at the same time now
+ {
+ shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::COLOR_CONVERSION);
+ }
shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
}
vertexShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING\n";
fragmentShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING\n";
}
+ else if(colorConversion == ImageVisualShaderFeature::ColorConversion::YUV_TO_RGB)
+ {
+ fragmentShaderPrefixList += "#define IS_REQUIRED_YUV_TO_RGB\n";
+ }
}
std::string vertexShader = std::string(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_VERT.data());
#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.
{
namespace Internal
{
-
/**
* ImageVisualShaderFeature contains feature lists what image visual shader need to know.
*/
};
} // namespace AlphaMaskingOnRendering
+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()
*/
mRoundedCorner(RoundedCorner::DISABLED),
mBorderline(Borderline::DISABLED),
mAlphaMaskingOnRendering(AlphaMaskingOnRendering::DISABLED),
+ mColorConversion(ColorConversion::DONT_NEED),
mTexture()
{
}
FeatureBuilder& EnableBorderline(bool enableBorderline);
FeatureBuilder& SetTextureForFragmentShaderCheck(const Dali::Texture& texture);
FeatureBuilder& EnableAlphaMaskingOnRendering(bool enableAlphaMaskingOnRendering);
+ 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
AlphaMaskingOnRendering::Type mAlphaMaskingOnRendering : 2; ///< Whether use runtime alpha masking, or not. default as AlphaMaskingOnRendering::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
};
class ImageVisualShaderFactory
{
public:
-
/**
* @brief Constructor
*/
ImageVisualShaderFactory& operator=(const ImageVisualShaderFactory& rhs);
private:
-
/**
* @brief Cached information whether native image should change fragment shader.
* Default it is ChangeFragmentShader::UNDECIDED.
mImpl->mRenderer.SetTextures(mTextures);
ComputeTextureSize();
CheckMaskTexture();
- if(DevelTexture::IsNative(mTextures.GetTexture(0)))
+
+ bool needToUpdateShader = DevelTexture::IsNative(mTextures.GetTexture(0));
+ if(mTextures.GetTextureCount() == 3)
+ {
+ //TODO: need to check pixel format yuv. Now we can't get the format of the texture.
+ mNeedYuvToRgb = true;
+ needToUpdateShader = true;
+ }
+ if(needToUpdateShader)
{
UpdateShader();
}
mImpl->mRenderer.SetTextures(textureInformation.textureSet);
ComputeTextureSize();
CheckMaskTexture();
+
+ if(textureInformation.textureSet.GetTextureCount() == 3)
+ {
+ //TODO: need to check pixel format yuv. Now we can't get the format of the texture.
+ mNeedYuvToRgb = true;
+ UpdateShader();
+ }
}
if(actor)
.EnableRoundedCorner(IsRoundedCornerRequired())
.EnableBorderline(IsBorderlineRequired())
.SetTextureForFragmentShaderCheck(useNativeImage ? mTextures.GetTexture(0) : Dali::Texture())
- .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering));
+ .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering)
+ .EnableYuvToRgb(mNeedYuvToRgb));
}
else
{
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
ConditionalWait::ScopedLock lock(mConditionalWait);
if(!mRasterizeTasks.empty())
{
- for(std::vector<SvgTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it)
+ for(std::vector<SvgTaskPtr>::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt;)
{
if((*it) && (*it)->GetSvgVisual() == visual)
{
- mRasterizeTasks.erase(it);
+ it = mRasterizeTasks.erase(it);
+ }
+ else
+ {
+ it++;
}
}
}
IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING,
IMAGE_SHADER_ATLAS_DEFAULT_WRAP,
IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
+ IMAGE_SHADER_YUV_TO_RGB,
+ IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
+ IMAGE_SHADER_BORDERLINE_YUV_TO_RGB,
+ IMAGE_SHADER_ROUNDED_BORDERLINE_YUV_TO_RGB,
NATIVE_IMAGE_SHADER,
NATIVE_IMAGE_SHADER_ROUNDED_CORNER,
NATIVE_IMAGE_SHADER_BORDERLINE,
/*
- * 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.
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,
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)