/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
*/
// CLASS HEADER
-#include "npatch-visual.h"
+#include <dali-toolkit/internal/visuals/npatch/npatch-visual.h>
// EXTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali-toolkit/devel-api/utility/npatch-helper.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/image-visual-shader-feature-builder.h>
#include <dali-toolkit/internal/visuals/npatch-loader.h>
#include <dali-toolkit/internal/visuals/rendering-addon.h>
#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
TextureManager& textureManager = mFactoryCache.GetTextureManager();
bool synchronousLoading = mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
- if(mId == NPatchData::INVALID_NPATCH_DATA_ID && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()))
+ if(mId == NPatchData::INVALID_NPATCH_DATA_ID)
{
bool preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader ? true : false;
mId = mLoader.Load(textureManager, this, mImageUrl, mBorder, preMultiplyOnLoad, synchronousLoading);
- const NPatchData* data;
+ NPatchDataPtr data;
if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
{
EnablePreMultipliedAlpha(data->IsPreMultiplied());
}
}
- if(!mAuxiliaryPixelBuffer && mAuxiliaryUrl.IsValid() && (mAuxiliaryUrl.IsLocalResource() || mAuxiliaryUrl.IsBufferResource()))
+ if(mAuxiliaryTextureId == TextureManager::INVALID_TEXTURE_ID && mAuxiliaryUrl.IsValid())
{
+ auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader
+ ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
+ : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+ TextureManager::MaskingDataPointer maskingDataPtr = nullptr;
+ ImageAtlasManagerPtr imageAtlasManagerPtr = nullptr;
+
+ bool atlasing = false;
+ auto atlasRect = Vector4::ZERO;
+ auto atlasRectSize = Dali::ImageDimensions();
+
+ bool loadingStatus = false;
+
// Load the auxiliary image
- auto preMultiplyOnLoading = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- mAuxiliaryPixelBuffer = textureManager.LoadPixelBuffer(mAuxiliaryUrl, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, this, true, preMultiplyOnLoading);
+ mAuxiliaryTextureSet = textureManager.LoadTexture(mAuxiliaryUrl, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, maskingDataPtr, synchronousLoading, mAuxiliaryTextureId, atlasRect, atlasRectSize, atlasing, loadingStatus, this, nullptr, imageAtlasManagerPtr, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad);
+
+ // If synchronousLoading is true, we can check the auxiliaryResource's status now.
+ if(synchronousLoading)
+ {
+ mAuxiliaryResourceStatus = (mAuxiliaryTextureSet && mAuxiliaryTextureSet.GetTextureCount() > 0u) ? Toolkit::Visual::ResourceStatus::READY : Toolkit::Visual::ResourceStatus::FAILED;
+ }
}
}
naturalSize.y = 0u;
// load now if not already loaded
- const NPatchData* data;
+ NPatchDataPtr data;
if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() != NPatchData::LoadingState::LOADING)
{
naturalSize.x = data->GetCroppedWidth();
}
}
- if(mAuxiliaryPixelBuffer)
+ if(mAuxiliaryTextureSet && mAuxiliaryTextureSet.GetTextureCount() > 0u)
{
- naturalSize.x = std::max(naturalSize.x, float(mAuxiliaryPixelBuffer.GetWidth()));
- naturalSize.y = std::max(naturalSize.y, float(mAuxiliaryPixelBuffer.GetHeight()));
+ naturalSize.x = std::max(naturalSize.x, float(mAuxiliaryTextureSet.GetTexture(0u).GetWidth()));
+ naturalSize.y = std::max(naturalSize.y, float(mAuxiliaryTextureSet.GetTexture(0u).GetHeight()));
}
}
// load when first go on stage
LoadImages();
- const NPatchData* data;
- if(mLoader.GetNPatchData(mId, data))
- {
- Geometry geometry = CreateGeometry();
- Shader shader = CreateShader();
-
- mImpl->mRenderer.SetGeometry(geometry);
- mImpl->mRenderer.SetShader(shader);
+ // Set mPlacementActor now, because some case, LoadImages can use this information in LoadComplete API.
+ // at this case, we try to SetResouce to mPlaceActor twice. so, we should avoid that case.
+ mPlacementActor = actor;
- mPlacementActor = actor;
- if(data->GetLoadingState() != NPatchData::LoadingState::LOADING)
+ NPatchDataPtr data;
+ if(mImpl->mRenderer && mLoader.GetNPatchData(mId, data) && data->GetLoadingState() != NPatchData::LoadingState::LOADING)
+ {
+ // If mAuxiliaryUrl need to be loaded, we should wait it until LoadComplete called.
+ if(!mAuxiliaryUrl.IsValid() || mAuxiliaryResourceStatus != Toolkit::Visual::ResourceStatus::PREPARING)
{
- if(RenderingAddOn::Get().IsValid())
- {
- RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap());
- }
-
- ApplyTextureAndUniforms();
- actor.AddRenderer(mImpl->mRenderer);
- mPlacementActor.Reset();
-
- // npatch loaded and ready to display
- ResourceReady(Toolkit::Visual::ResourceStatus::READY);
+ SetResource();
}
}
}
void NPatchVisual::DoSetOffScene(Actor& actor)
{
- if((mId != NPatchData::INVALID_NPATCH_DATA_ID) && mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
+ if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
{
- mLoader.Remove(mId, this);
- mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
- mId = NPatchData::INVALID_NPATCH_DATA_ID;
+ if(mId != NPatchData::INVALID_NPATCH_DATA_ID)
+ {
+ mLoader.RequestRemove(mId, this);
+ mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
+ mId = NPatchData::INVALID_NPATCH_DATA_ID;
+ }
+ if(mAuxiliaryTextureId != TextureManager::INVALID_TEXTURE_ID)
+ {
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+ textureManager.RequestRemove(mAuxiliaryTextureId, this);
+ mAuxiliaryTextureId = TextureManager::INVALID_TEXTURE_ID;
+ mAuxiliaryResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
+ mAuxiliaryTextureSet.Reset();
+ }
}
actor.RemoveRenderer(mImpl->mRenderer);
mImageUrl(),
mAuxiliaryUrl(),
mId(NPatchData::INVALID_NPATCH_DATA_ID),
+ mAuxiliaryTextureSet(),
+ mAuxiliaryTextureId(TextureManager::INVALID_TEXTURE_ID),
+ mAuxiliaryResourceStatus(Toolkit::Visual::ResourceStatus::PREPARING),
mBorderOnly(false),
mBorder(),
mAuxiliaryImageAlpha(0.0f),
NPatchVisual::~NPatchVisual()
{
- if(Stage::IsInstalled() && (mId != NPatchData::INVALID_NPATCH_DATA_ID) && (mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER))
+ if(Stage::IsInstalled())
{
- mLoader.Remove(mId, this);
- mId = NPatchData::INVALID_NPATCH_DATA_ID;
+ if(mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER)
+ {
+ if(mId != NPatchData::INVALID_NPATCH_DATA_ID)
+ {
+ mLoader.RequestRemove(mId, this);
+ mId = NPatchData::INVALID_NPATCH_DATA_ID;
+ }
+ if(mAuxiliaryTextureId != TextureManager::INVALID_TEXTURE_ID)
+ {
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+
+ textureManager.RequestRemove(mAuxiliaryTextureId, this);
+ mAuxiliaryTextureId = TextureManager::INVALID_TEXTURE_ID;
+ mAuxiliaryTextureSet.Reset();
+ }
+ }
}
}
void NPatchVisual::OnInitialize()
{
// Get basic geometry and shader
- Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
- Shader shader = mImageVisualShaderFactory.GetShader(
+ Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
+ auto imageVisualShaderFeatureBuilder = ImageVisualShaderFeatureBuilder();
+ Shader shader = mImageVisualShaderFactory.GetShader(
mFactoryCache,
- ImageVisualShaderFeature::FeatureBuilder());
+ imageVisualShaderFeatureBuilder);
mImpl->mRenderer = VisualRenderer::New(geometry, shader);
mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
Geometry NPatchVisual::CreateGeometry()
{
- Geometry geometry;
- const NPatchData* data;
+ Geometry geometry;
+ NPatchDataPtr data;
if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
{
if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
Shader NPatchVisual::CreateShader()
{
- Shader shader;
- const NPatchData* data;
+ Shader shader;
+ NPatchDataPtr data;
// 0 is either no data (load failed?) or no stretch regions on image
// for both cases we use the default shader
NPatchUtility::StretchRanges::SizeType xStretchCount = 0;
NPatchUtility::StretchRanges::SizeType yStretchCount = 0;
- auto fragmentShader = mAuxiliaryPixelBuffer ? SHADER_NPATCH_VISUAL_MASK_SHADER_FRAG
- : SHADER_NPATCH_VISUAL_SHADER_FRAG;
- auto shaderType = mAuxiliaryPixelBuffer ? VisualFactoryCache::NINE_PATCH_MASK_SHADER
- : VisualFactoryCache::NINE_PATCH_SHADER;
+ auto fragmentShader = mAuxiliaryResourceStatus == Toolkit::Visual::ResourceStatus::READY ? SHADER_NPATCH_VISUAL_MASK_SHADER_FRAG
+ : SHADER_NPATCH_VISUAL_SHADER_FRAG;
+ auto shaderType = mAuxiliaryResourceStatus == Toolkit::Visual::ResourceStatus::READY ? VisualFactoryCache::NINE_PATCH_MASK_SHADER
+ : VisualFactoryCache::NINE_PATCH_SHADER;
// ask loader for the regions
if(mLoader.GetNPatchData(mId, data))
shader = mFactoryCache.GetShader(shaderType);
if(DALI_UNLIKELY(!shader))
{
- shader = Shader::New(SHADER_NPATCH_VISUAL_3X3_SHADER_VERT, fragmentShader);
- // Only cache vanilla 9 patch shaders
- mFactoryCache.SaveShader(shaderType, shader);
+ shader = mFactoryCache.GenerateAndSaveShader(shaderType, SHADER_NPATCH_VISUAL_3X3_SHADER_VERT, fragmentShader);
}
}
else if(xStretchCount > 0 || yStretchCount > 0)
{
+ std::stringstream shaderName;
+ shaderName << "N_PATCH_" << xStretchCount << "x" << yStretchCount;
+
std::stringstream vertexShader;
vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
<< "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
<< SHADER_NPATCH_VISUAL_SHADER_VERT;
- shader = Shader::New(vertexShader.str(), fragmentShader);
+ shader = Shader::New(vertexShader.str(), fragmentShader, Dali::Shader::Hint::NONE, shaderName.str());
}
}
else
}
else if(xStretchCount > 0 || yStretchCount > 0)
{
+ std::stringstream shaderName;
+ shaderName << "N_PATCH_" << xStretchCount << "x" << yStretchCount;
+
std::stringstream vertexShader;
vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
<< "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
<< SHADER_NPATCH_VISUAL_SHADER_VERT;
- shader = Shader::New(vertexShader.str(), fragmentShader, hints);
+ shader = Shader::New(vertexShader.str(), fragmentShader, hints, shaderName.str());
}
}
void NPatchVisual::ApplyTextureAndUniforms()
{
- const NPatchData* data;
- TextureSet textureSet;
+ NPatchDataPtr data;
+ TextureSet textureSet;
if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
{
textureSet = data->GetTextures();
- NPatchHelper::ApplyTextureAndUniforms(mImpl->mRenderer, data);
+ NPatchHelper::ApplyTextureAndUniforms(mImpl->mRenderer, data.Get());
+
+ if(mAuxiliaryResourceStatus == Toolkit::Visual::ResourceStatus::READY)
+ {
+ DALI_ASSERT_ALWAYS(mAuxiliaryTextureId != TextureManager::INVALID_TEXTURE_ID);
+ DALI_ASSERT_ALWAYS(mAuxiliaryTextureSet && mAuxiliaryTextureSet.GetTextureCount() > 0u);
+
+ // TODO : This code exist due to the texture cache manager hold TextureSet, not Texture.
+ // If we call textureSet.SetTexture(1, texture) directly, the cached TextureSet also be changed.
+ // We should make pass utc-Dali-VisualFactory.cpp UtcDaliNPatchVisualAuxiliaryImage02().
+ TextureSet tempTextureSet = TextureSet::New();
+ tempTextureSet.SetTexture(1, mAuxiliaryTextureSet.GetTexture(0));
+ tempTextureSet.SetTexture(0, textureSet.GetTexture(0));
+ textureSet = tempTextureSet;
+
+ mImpl->mRenderer.RegisterProperty(DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA,
+ AUXILIARY_IMAGE_ALPHA_NAME,
+ mAuxiliaryImageAlpha);
+ }
+ mImpl->mRenderer.SetTextures(textureSet);
}
else
{
DALI_LOG_ERROR("The N patch image '%s' is not a valid N patch image\n", mImageUrl.GetUrl().c_str());
- textureSet = TextureSet::New();
-
Actor actor = mPlacementActor.GetHandle();
Vector2 imageSize = Vector2::ZERO;
if(actor)
{
imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
}
- mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
+ mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize, false);
}
- if(mAuxiliaryPixelBuffer)
- {
- // If the auxiliary image is smaller than the un-stretched NPatch, use CPU resizing to enlarge it to the
- // same size as the unstretched NPatch. This will give slightly higher quality results than just relying
- // on GL interpolation alone.
- if(mAuxiliaryPixelBuffer.GetWidth() < data->GetCroppedWidth() &&
- mAuxiliaryPixelBuffer.GetHeight() < data->GetCroppedHeight())
- {
- mAuxiliaryPixelBuffer.Resize(data->GetCroppedWidth(), data->GetCroppedHeight());
- }
-
- // Note, this resets mAuxiliaryPixelBuffer handle
- auto auxiliaryPixelData = Devel::PixelBuffer::Convert(mAuxiliaryPixelBuffer);
-
- auto texture = Texture::New(TextureType::TEXTURE_2D,
- auxiliaryPixelData.GetPixelFormat(),
- auxiliaryPixelData.GetWidth(),
- auxiliaryPixelData.GetHeight());
- texture.Upload(auxiliaryPixelData);
- textureSet.SetTexture(1, texture);
- mImpl->mRenderer.RegisterProperty(DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA,
- AUXILIARY_IMAGE_ALPHA_NAME,
- mAuxiliaryImageAlpha);
- }
- mImpl->mRenderer.SetTextures(textureSet);
-
// Register transform properties
mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
}
void NPatchVisual::SetResource()
{
- const NPatchData* data;
+ NPatchDataPtr data;
if(mImpl->mRenderer && mLoader.GetNPatchData(mId, data))
{
Geometry geometry = CreateGeometry();
mImpl->mRenderer.SetGeometry(geometry);
mImpl->mRenderer.SetShader(shader);
+ if(RenderingAddOn::Get().IsValid())
+ {
+ RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap());
+ }
Actor actor = mPlacementActor.GetHandle();
if(actor)
{
ApplyTextureAndUniforms();
actor.AddRenderer(mImpl->mRenderer);
mPlacementActor.Reset();
+ }
- // npatch loaded and ready to display
+ // npatch loaded and ready to display
+ if(data->GetLoadingState() != NPatchData::LoadingState::LOAD_COMPLETE)
+ {
+ ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
+ }
+ else
+ {
ResourceReady(Toolkit::Visual::ResourceStatus::READY);
}
}
void NPatchVisual::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
{
- if(textureInformation.returnType == TextureUploadObserver::ReturnType::TEXTURE)
+ if(textureInformation.url.length() > 0) // For the Url.
{
- EnablePreMultipliedAlpha(textureInformation.preMultiplied);
- if(!loadSuccess)
+ if(DALI_UNLIKELY(mId == NPatchData::INVALID_NPATCH_DATA_ID))
{
- // Image loaded and ready to display
- ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
+ // Special case when mLoader.Load call LoadComplete function before mId setup.
+ // We can overwrite mId.
+ mId = static_cast<NPatchData::NPatchDataId>(textureInformation.textureId);
}
-
- if(mAuxiliaryPixelBuffer || !mAuxiliaryUrl.IsValid())
+ if(loadSuccess)
{
- SetResource();
+ EnablePreMultipliedAlpha(textureInformation.preMultiplied);
}
}
- else // for the ReturnType::PIXEL_BUFFER
+ else // For the AuxiliaryUrl
{
- if(loadSuccess && textureInformation.url == mAuxiliaryUrl.GetUrl())
+ if(DALI_UNLIKELY(mAuxiliaryTextureId == TextureManager::INVALID_TEXTURE_ID))
{
- mAuxiliaryPixelBuffer = textureInformation.pixelBuffer;
- SetResource();
+ // Special case when TextureManager.LoadTexture call LoadComplete function before mAuxiliaryTextureId setup.
+ // We can overwrite mAuxiliaryTextureId.
+ mAuxiliaryTextureId = textureInformation.textureId;
+ }
+ if(loadSuccess)
+ {
+ mAuxiliaryTextureSet = textureInformation.textureSet;
+ mAuxiliaryResourceStatus = Toolkit::Visual::ResourceStatus::READY;
}
else
{
- // Image loaded and ready to display
- ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
+ mAuxiliaryResourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
+ }
+ }
+
+ // If auxiliaryUrl didn't required OR auxiliaryUrl load done.
+ if(!mAuxiliaryUrl.IsValid() || mAuxiliaryResourceStatus != Toolkit::Visual::ResourceStatus::PREPARING)
+ {
+ NPatchDataPtr data;
+ // and.. If Url loading done.
+ if(mImpl->mRenderer && mLoader.GetNPatchData(mId, data) && data->GetLoadingState() != NPatchData::LoadingState::LOADING)
+ {
+ SetResource();
}
}
}