/*
- * Copyright (c) 2020 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.
* limitations under the License.
*/
-
// EXTERNAL HEADERS
-#include <dali/devel-api/addons/addon-base.h>
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/devel-api/addons/addon-base.h>
#include <dali/public-api/rendering/geometry.h>
#include <dali/public-api/rendering/renderer.h>
// INTERNAL HEADERS
// Needed to access the private class members
#define private public
+#include <dali-toolkit/internal/visuals/npatch/npatch-loader.h>
#include <dali-toolkit/internal/visuals/npatch/npatch-visual.h>
-#include <dali-toolkit/internal/visuals/npatch-loader.h>
#undef private
-
using Dali::Toolkit::Internal::TextureManager;
namespace Dali
{
namespace AddOns
{
-
struct DummyTiler
{
};
-void* CreateInstance( TextureManager* textureManager )
+void* CreateInstance(TextureManager* textureManager)
{
fprintf(stderr, "AddOn::CreateInstance( %p )\n", textureManager);
return new DummyTiler;
{
std::vector<std::string> gCallStack;
-static Geometry GetGeometryInternal(TextureManager::TextureId textureId, uint32_t& o0, uint32_t& o1 )
+static Geometry GetGeometryInternal(TextureManager::TextureId textureId, uint32_t& o0, uint32_t& o1)
{
- gCallStack.emplace_back( "GetGeometry" );
+ gCallStack.emplace_back("GetGeometry");
o0 = 10;
o1 = 5;
fprintf(stderr, "AddOn::GetGeometryInternal()\n");
return Dali::Geometry::New();
}
-static Geometry CreateGeometryInternal(TextureManager::TextureId textureId, const Devel::PixelBuffer& pixelBuffer )
+static Geometry CreateGeometryInternal(TextureManager::TextureId textureId, const Devel::PixelBuffer& pixelBuffer)
{
- gCallStack.emplace_back( "CreateGeometry" );
+ gCallStack.emplace_back("CreateGeometry");
fprintf(stderr, "AddOn::CreateGeometryInternal()\n");
return Dali::Geometry::New();
}
-static Geometry CreateGeometryMapInternal(const void* opacityMap,
+static Geometry CreateGeometryMapInternal(const void* opacityMap,
const Uint16Pair& gridSize,
- uint32_t *outElements)
+ uint32_t* outElements)
{
- gCallStack.emplace_back( "CreateGeometryGrid" );
+ gCallStack.emplace_back("CreateGeometryGrid");
outElements[0] = 2;
outElements[1] = 3;
return Dali::Geometry::New();
}
-static void* NPatchBuildInternal(const Devel::PixelBuffer& pixelBuffer, Toolkit::Internal::NPatchData* data )
+static void* NPatchBuildInternal(const Devel::PixelBuffer& pixelBuffer, Toolkit::Internal::NPatchData* data)
{
- gCallStack.emplace_back( "BuildNPatch" );
+ gCallStack.emplace_back("BuildNPatch");
fprintf(stderr, "AddOn::NPatchBuild()\n");
static char dummyData;
return &dummyData;
}
-static void NPatchDestroyInternal(void* object )
+static void NPatchDestroyInternal(void* object)
{
- gCallStack.emplace_back( "DestroyNPatch" );
+ gCallStack.emplace_back("DestroyNPatch");
fprintf(stderr, "AddOn::NPatchDestroy()\n");
}
-static void SubmitInternal(Renderer& renderer, const void* object )
+static void SubmitInternal(Renderer& renderer, const void* object)
{
- gCallStack.emplace_back( "SubmitRenderTask" );
+ gCallStack.emplace_back("SubmitRenderTask");
fprintf(stderr, "AddOn::SubmitInternal()\n");
}
-static std::vector<std::string> GetCallStack( bool clear )
+static std::vector<std::string> GetCallStack(bool clear)
{
auto retval = gCallStack;
if(clear)
return retval;
}
-
-}
-}
-}
+} // namespace GeometryTiler
+} // namespace AddOns
+} // namespace Dali
/**
* OverdrawingAddOn implementation
class TestRenderingAddOn : public Dali::AddOns::AddOnBase
{
public:
-
- void GetAddOnInfo( Dali::AddOnInfo& info ) override
+ void GetAddOnInfo(Dali::AddOnInfo& info) override
{
- info.type = Dali::AddOnType::GENERIC;
- info.name = "oo-rendering";
- info.version = Dali::DALI_ADDON_VERSION( 1, 0, 0 );
- info.next = nullptr;
+ info.type = Dali::AddOnType::GENERIC;
+ info.name = "oo-rendering";
+ info.version = Dali::DALI_ADDON_VERSION(1, 0, 0);
+ info.next = nullptr;
}
/**
Dali::AddOns::DispatchTable* GetGlobalDispatchTable() override
{
static Dali::AddOns::DispatchTable dispatchTable{};
- if( dispatchTable.Empty() )
+ if(dispatchTable.Empty())
{
dispatchTable["Initialize"] = Dali::AddOns::CreateInstance;
dispatchTable["CreateGeometry"] = Dali::AddOns::GeometryTiler::CreateGeometryInternal;
}
};
-REGISTER_ADDON_CLASS( TestRenderingAddOn );
+REGISTER_ADDON_CLASS(TestRenderingAddOn);
/*
- * Copyright (c) 2023 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.
*
*/
-#include <iostream>
#include <stdlib.h>
+#include <iostream>
#include <dali-toolkit-test-suite-utils.h>
#include <dali-toolkit/dali-toolkit.h>
#include <toolkit-event-thread-callback.h>
#include <toolkit-text-utils.h>
-#include <dali-toolkit/internal/visuals/image-visual-shader-feature-builder.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-feature-builder.h>
#include <../dali-toolkit/dali-toolkit-test-utils/dummy-control.h>
#include <dummy-visual.h>
#include <dali-toolkit/internal/texture-manager/texture-async-loading-helper.h>
#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
#include <dali-toolkit/internal/texture-manager/texture-upload-observer.h>
-#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/image/image-atlas-manager.h>
#include <dali-toolkit/internal/visuals/visual-factory-impl.h> ///< For VisualFactory's member TextureManager.
#include <dali-toolkit/public-api/image-loader/image-url.h>
#include <dali-toolkit/public-api/image-loader/image.h>
#include <dali-toolkit/devel-api/utility/npatch-utilities.h>
#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
-#include <dali-toolkit/internal/visuals/npatch-loader.h>
+#include <dali-toolkit/internal/visuals/npatch/npatch-loader.h>
#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali/integration-api/adaptor-framework/shader-precompiler.h>
#include <dali/integration-api/debug.h>
/*
-* Copyright (c) 2023 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.
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/visuals/npatch-data.h>
+#include <dali-toolkit/internal/visuals/npatch/npatch-data.h>
namespace Dali
{
${toolkit_src_dir}/visuals/gradient/linear-gradient.cpp
${toolkit_src_dir}/visuals/gradient/radial-gradient.cpp
${toolkit_src_dir}/visuals/animated-gradient/animated-gradient-visual.cpp
- ${toolkit_src_dir}/visuals/image-atlas-manager.cpp
+ ${toolkit_src_dir}/visuals/image/image-atlas-manager.cpp
${toolkit_src_dir}/visuals/image/image-visual.cpp
+ ${toolkit_src_dir}/visuals/image/image-visual-shader-debug.cpp
+ ${toolkit_src_dir}/visuals/image/image-visual-shader-factory.cpp
+ ${toolkit_src_dir}/visuals/image/image-visual-shader-feature-builder.cpp
${toolkit_src_dir}/visuals/mesh/mesh-visual.cpp
- ${toolkit_src_dir}/visuals/npatch-data.cpp
- ${toolkit_src_dir}/visuals/npatch-loader.cpp
+ ${toolkit_src_dir}/visuals/npatch/npatch-data.cpp
+ ${toolkit_src_dir}/visuals/npatch/npatch-loader.cpp
${toolkit_src_dir}/visuals/npatch/npatch-visual.cpp
${toolkit_src_dir}/visuals/primitive/primitive-visual.cpp
${toolkit_src_dir}/visuals/svg/svg-task.cpp
${toolkit_src_dir}/visuals/svg/svg-visual.cpp
- ${toolkit_src_dir}/visuals/text-visual-shader-factory.cpp
+ ${toolkit_src_dir}/visuals/text/text-visual-shader-factory.cpp
${toolkit_src_dir}/visuals/text/text-visual.cpp
${toolkit_src_dir}/visuals/transition-data-impl.cpp
- ${toolkit_src_dir}/visuals/image-visual-shader-debug.cpp
- ${toolkit_src_dir}/visuals/image-visual-shader-factory.cpp
- ${toolkit_src_dir}/visuals/image-visual-shader-feature-builder.cpp
${toolkit_src_dir}/visuals/visual-base-data-impl.cpp
${toolkit_src_dir}/visuals/visual-base-impl.cpp
${toolkit_src_dir}/visuals/visual-factory-cache.cpp
// INTERNAL HEADERS
#include <dali-toolkit/internal/texture-manager/texture-async-loading-helper.h>
#include <dali-toolkit/internal/texture-manager/texture-cache-manager.h>
-#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/image/image-atlas-manager.h>
#include <dali-toolkit/internal/visuals/rendering-addon.h>
namespace
#include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
#include <dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.h>
#include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.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/image/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-feature-builder.h>
#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
#include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
// INTERNAL HEADERS
-#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+#include <dali-toolkit/internal/visuals/image/image-atlas-manager.h> // For ImageAtlasManagerPtr
// EXTERNAL HEADERS
#include <dali/integration-api/adaptor-framework/adaptor.h>
// INTERNAL HEADERS
#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
-#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+#include <dali-toolkit/internal/visuals/image/image-atlas-manager.h> // For ImageAtlasManagerPtr
#include <dali/integration-api/adaptor-framework/adaptor.h>
#include <dali/integration-api/debug.h>
#include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
// INTERNAL HEADERS
-#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+#include <dali-toolkit/internal/visuals/image/image-atlas-manager.h> // For ImageAtlasManagerPtr
// EXTERNAL HEADERS
#include <dali/integration-api/adaptor-framework/adaptor.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-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/image/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-feature-builder.h>
#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
// INTERNAL INCLUDES
#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h>
#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
-#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-factory.h>
#ifdef TRACE_ENABLED
#include <chrono>
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "image-atlas-manager.h"
-
-// EXTERNAL HEADER
-#include <dali/devel-api/adaptor-framework/image-loading.h>
-
-// INTERNAL HEADERS
-#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-namespace
-{
-const uint32_t DEFAULT_ATLAS_SIZE(1024u); // this size can fit 8 by 8 images of average size 128*128
-const uint32_t MAX_ITEM_SIZE(512u);
-const uint32_t MAX_ITEM_AREA(MAX_ITEM_SIZE* MAX_ITEM_SIZE);
-} // namespace
-
-ImageAtlasManager::ImageAtlasManager()
-: mBrokenImageUrl("")
-{
-}
-
-ImageAtlasManager::~ImageAtlasManager()
-{
-}
-
-bool ImageAtlasManager::CheckAtlasAvailable(const VisualUrl& url, const ImageDimensions& size) const
-{
- ImageDimensions dimensions = size;
- ImageDimensions zero;
- if(size == zero)
- {
- dimensions = Dali::GetClosestImageSize(url.GetUrl());
- }
-
- // big image, atlasing is not applied
- if(static_cast<uint32_t>(dimensions.GetWidth()) * static_cast<uint32_t>(dimensions.GetHeight()) > MAX_ITEM_AREA || dimensions.GetWidth() > DEFAULT_ATLAS_SIZE || dimensions.GetHeight() > DEFAULT_ATLAS_SIZE)
- {
- return false;
- }
- return true;
-}
-
-TextureSet ImageAtlasManager::Add(Vector4& textureRect,
- const VisualUrl& url,
- ImageDimensions& size,
- FittingMode::Type fittingMode,
- bool orientationCorrection,
- AtlasUploadObserver* atlasUploadObserver)
-{
- ImageDimensions dimensions = size;
- ImageDimensions zero;
- if(size == zero)
- {
- dimensions = Dali::GetClosestImageSize(url.GetUrl());
- }
-
- // big image, atlasing is not applied
- if(static_cast<uint32_t>(dimensions.GetWidth()) * static_cast<uint32_t>(dimensions.GetHeight()) > MAX_ITEM_AREA || dimensions.GetWidth() > DEFAULT_ATLAS_SIZE || dimensions.GetHeight() > DEFAULT_ATLAS_SIZE)
- {
- return TextureSet();
- }
- size = dimensions;
-
- uint32_t i = 0;
- for(AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
- {
- if(GetImplementation(*iter).Upload(textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver))
- {
- return mTextureSetList[i];
- }
- i++;
- }
-
- CreateNewAtlas();
- GetImplementation(mAtlasList.back()).Upload(textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver);
- return mTextureSetList.back();
-}
-
-TextureSet ImageAtlasManager::Add(Vector4& textureRect,
- const EncodedImageBuffer& encodedImageBuffer,
- const ImageDimensions& size,
- FittingMode::Type fittingMode,
- bool orientationCorrection,
- AtlasUploadObserver* atlasUploadObserver)
-{
- // big image, atlasing is not applied
- if(static_cast<uint32_t>(size.GetWidth()) * static_cast<uint32_t>(size.GetHeight()) > MAX_ITEM_AREA || size.GetWidth() > DEFAULT_ATLAS_SIZE || size.GetHeight() > DEFAULT_ATLAS_SIZE)
- {
- return TextureSet();
- }
-
- uint32_t i = 0;
- for(AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
- {
- if(GetImplementation(*iter).Upload(textureRect, encodedImageBuffer, size, fittingMode, orientationCorrection, atlasUploadObserver))
- {
- return mTextureSetList[i];
- }
- i++;
- }
-
- CreateNewAtlas();
- GetImplementation(mAtlasList.back()).Upload(textureRect, encodedImageBuffer, size, fittingMode, orientationCorrection, atlasUploadObserver);
- return mTextureSetList.back();
-}
-
-TextureSet ImageAtlasManager::Add(Vector4& textureRect,
- PixelData pixelData)
-{
- // big buffer, atlasing is not applied
- if(static_cast<uint32_t>(pixelData.GetWidth()) * static_cast<uint32_t>(pixelData.GetHeight()) > MAX_ITEM_AREA || pixelData.GetWidth() > DEFAULT_ATLAS_SIZE || pixelData.GetHeight() > DEFAULT_ATLAS_SIZE)
- {
- return TextureSet();
- }
-
- uint32_t i = 0;
- for(AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
- {
- if((*iter).Upload(textureRect, pixelData))
- {
- return mTextureSetList[i];
- }
- i++;
- }
-
- CreateNewAtlas();
- mAtlasList.back().Upload(textureRect, pixelData);
- return mTextureSetList.back();
-}
-
-void ImageAtlasManager::Remove(TextureSet textureSet, const Vector4& textureRect)
-{
- uint32_t i = 0;
- for(TextureSetContainer::iterator iter = mTextureSetList.begin(); iter != mTextureSetList.end(); ++iter)
- {
- if((*iter) == textureSet)
- {
- mAtlasList[i].Remove(textureRect);
- return;
- }
- i++;
- }
-}
-
-void ImageAtlasManager::SetBrokenImage(const std::string& brokenImageUrl)
-{
- if(!brokenImageUrl.empty())
- {
- mBrokenImageUrl = brokenImageUrl;
- }
-}
-
-void ImageAtlasManager::CreateNewAtlas()
-{
- Toolkit::ImageAtlas newAtlas = Toolkit::ImageAtlas::New(DEFAULT_ATLAS_SIZE, DEFAULT_ATLAS_SIZE);
- if(!mBrokenImageUrl.empty())
- {
- newAtlas.SetBrokenImage(mBrokenImageUrl);
- }
- mAtlasList.push_back(newAtlas);
- TextureSet textureSet = TextureSet::New();
- textureSet.SetTexture(0u, newAtlas.GetAtlas());
- mTextureSetList.push_back(textureSet);
-}
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_IMAGE_ATLAS_MANAGER_H
-#define DALI_TOOLKIT_IMAGE_ATLAS_MANAGER_H
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
-#include <dali/public-api/common/vector-wrapper.h>
-#include <dali/public-api/object/ref-object.h>
-#include <dali/public-api/rendering/texture-set.h>
-#include <string>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
-#include <dali-toolkit/internal/visuals/visual-url.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-class AtlasUploadObserver;
-
-namespace Internal
-{
-/**
- * The manager for automatic image atlasing. Owned by VisualFactory
- */
-class ImageAtlasManager : public RefObject
-{
-public:
- typedef std::vector<Toolkit::ImageAtlas> AtlasContainer;
- typedef std::vector<TextureSet> TextureSetContainer;
-
-public:
- /**
- * Construtor
- *
- */
- ImageAtlasManager();
-
- /**
- * @brief Check whether the image of url could be Atlas or not.
- *
- * @param [in] url The URL of the resource image file to use.
- * @param [in] size The width and height to fit the loaded image to.
- * @return True if the image could be Atlas.
- */
- bool CheckAtlasAvailable(const VisualUrl& url, const ImageDimensions& size) const;
-
- /**
- * @brief Add an image to the atlas.
- *
- * @note To make the atlasing efficient, an valid size should be provided.
- * If size is not provided, then the image file will be opened to read the actual size for loading.
- *
- * SamplingMode::BOX_THEN_LINEAR is used to sampling pixels from the input image while fitting it to desired size.
- *
- * @param [out] textureRect The texture area of the resource image in the atlas.
- * @param [in] url The URL of the resource image file to use.
- * @param [in, out] size 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] orientationCorrection Reorient the image to respect any orientation metadata in its header.
- * @param [in] atlasUploadObserver The object to observe the uploading state inside ImageAtlas.
- * @return The texture set containing the image.
- */
- TextureSet Add(Vector4& textureRect,
- const VisualUrl& url,
- ImageDimensions& size,
- FittingMode::Type fittingMode = FittingMode::DEFAULT,
- bool orientationCorrection = true,
- AtlasUploadObserver* atlasUploadObserver = NULL);
-
- /**
- * @brief Add an image to the atlas.
- *
- * @note To make the atlasing efficient, an valid size should be provided.
- *
- * SamplingMode::BOX_THEN_LINEAR is used to sampling pixels from the input image while fitting it to desired size.
- *
- * @param [out] textureRect The texture area of the resource image in the atlas.
- * @param [in] encodedImageBuffer The encoded buffer of the resource image file to use.
- * @param [in] size 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] orientationCorrection Reorient the image to respect any orientation metadata in its header.
- * @param [in] atlasUploadObserver The object to observe the uploading state inside ImageAtlas.
- * @return The texture set containing the image.
- */
- TextureSet Add(Vector4& textureRect,
- const EncodedImageBuffer& encodedImageBuffer,
- const ImageDimensions& size,
- FittingMode::Type fittingMode = FittingMode::DEFAULT,
- bool orientationCorrection = true,
- AtlasUploadObserver* atlasUploadObserver = NULL);
-
- /**
- * @brief Add a pixel buffer to the atlas
- *
- * @param [out] textureRect The texture area of the resource image in the atlas.
- * @param [in] pixelData The pixel data.
- * @return The texture set containing the image.
- */
- TextureSet Add(Vector4& textureRect,
- PixelData pixelData);
-
- /**
- * Remove the image at the given rectangle from the texture set.
- *
- * @param [in] textureSet The texture set containing the atlas image.
- * @param [in] textureRect The texture area to be removed.
- */
- void Remove(TextureSet textureSet, const Vector4& textureRect);
-
- /**
- * @brief Set the broken image which is used to replace the image if loading fails.
- *
- * @param[in] brokenImageUrl The url of the broken image.
- */
- void SetBrokenImage(const std::string& brokenImageUrl);
-
- /**
- * @brief Get shader
- */
- Shader GetShader() const;
-
-private:
- /**
- * @brief Create a new atlas.
- *
- * This method is called when the newly added image or pixel buffer cannot fit into the current atlas list.
- */
- void CreateNewAtlas();
-
-protected:
- /**
- * Destructor
- */
- ~ImageAtlasManager() override;
-
- /**
- * Undefined copy constructor.
- */
- ImageAtlasManager(const ImageAtlasManager&);
-
- /**
- * Undefined assignment operator.
- */
- ImageAtlasManager& operator=(const ImageAtlasManager& rhs);
-
-private:
- AtlasContainer mAtlasList;
- TextureSetContainer mTextureSetList;
- std::string mBrokenImageUrl;
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_ATLAS_MANAGER_H
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/visuals/image-visual-shader-debug.h>
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/environment-variable.h>
-#include <dali/devel-api/adaptor-framework/style-monitor.h> ///< for load json file.
-#include <dali/public-api/common/vector-wrapper.h>
-
-#include <regex> ///< for redefine shader
-#include <string_view>
-
-#include <dali/integration-api/debug.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
-#include <dali-toolkit/devel-api/builder/json-parser.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-namespace
-{
-constexpr auto DALI_DEBUG_IMAGE_VISUAL_SHADER_ENV = "DALI_DEBUG_IMAGE_VISUAL_SHADER";
-
-bool DebugImageVisualShaderEnvironmentEnabled()
-{
- static bool enabled = false;
- static bool enabledSetted = false;
- if(!enabledSetted)
- {
- enabledSetted = true;
- auto debugEnabledString = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_ENV);
- enabled = debugEnabledString ? std::atoi(debugEnabledString) : false;
- }
- return enabled;
-}
-
-constexpr auto DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME_ENV = "DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME";
-constexpr auto DEFAULT_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME = "debug-image-visual-shader-script.json";
-
-const std::string& GetScriptFilename()
-{
- // Set the full path for the default script file.
- const static std::string styleDirPath{AssetManager::GetDaliStylePath()};
- static std::string mScriptFileName{};
-
- if(DALI_UNLIKELY(mScriptFileName.empty()))
- {
- // Use user's own script if exist.
- auto environmentScriptFilename = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME_ENV);
-
- mScriptFileName = environmentScriptFilename ? std::string(environmentScriptFilename) : styleDirPath + std::string(DEFAULT_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME);
-
- DALI_ASSERT_DEBUG(0 != mScriptFileName.length());
- }
-
- return mScriptFileName;
-}
-
-bool LoadJsonScript(std::string& stringOut)
-{
- auto styleMonitor = StyleMonitor::Get();
-
- // as toolkit is platform agnostic, it cannot load files from filesystem
- // ask style monitor to load the style sheet
- if(styleMonitor)
- {
- try
- {
- return styleMonitor.LoadThemeFile(GetScriptFilename(), stringOut);
- }
- catch(const std::exception& e)
- {
- DALI_LOG_ERROR("Something system exception throwed during load script file![%s]\n", GetScriptFilename().c_str());
- DALI_LOG_ERROR("Error message : [%s]\n", e.what());
- }
- catch(const Dali::DaliException& e)
- {
- DALI_LOG_ERROR("Something Dali exception throwed during load script file![%s]\n", GetScriptFilename().c_str());
- DALI_LOG_ERROR("Error message : [%s]\n", e.condition);
- }
- catch(...)
- {
- DALI_LOG_ERROR("Something unkown exception throwed during load script file![%s]\n", GetScriptFilename().c_str());
- }
- }
-
- return false;
-}
-// Json keywords what we will get information from json.
-constexpr std::string_view DEBUG_SCRIPT_VERSION_JSON_KEY = "version";
-
-constexpr std::string_view DEBUG_EXTRA_ATTRIBUTES_JSON_KEY = "extraAttributes";
-constexpr std::string_view DEBUG_EXTRA_VARYINGS_JSON_KEY = "extraVaryings";
-constexpr std::string_view DEBUG_EXTRA_UNIFORMS_JSON_KEY = "extraUniforms";
-constexpr std::string_view DEBUG_APPLY_VARYINGS_CODE_JSON_KEY = "applyVaryingsCode";
-
-constexpr std::string_view MINIMUM_DEBUG_COLOR_RATE_JSON_KEY = "minimumColorRate";
-constexpr std::string_view MAXIMUM_DEBUG_COLOR_RATE_JSON_KEY = "maximumColorRate";
-
-constexpr std::string_view DEBUG_RED_CHANNEL_CODE_JSON_KEY = "redChannelCodes";
-constexpr std::string_view DEBUG_GREEN_CHANNEL_CODE_JSON_KEY = "greenChannelCodes";
-constexpr std::string_view DEBUG_BLUE_CHANNEL_CODE_JSON_KEY = "blueChannelCodes";
-constexpr std::string_view DEBUG_TRIGGER_CODE_JSON_KEY = "triggerCode";
-constexpr std::string_view DEBUG_RATIO_CODE_JSON_KEY = "ratioCode";
-
-// Macro keywords what we will replace at vertex/fragment shader.
-constexpr std::string_view DEBUG_EXTRA_ATTRIBUTES_MACRO_KEY = "DEBUG_EXTRA_ATTRIBUTES";
-constexpr std::string_view DEBUG_EXTRA_VARYINGS_MACRO_KEY = "DEBUG_EXTRA_VARYINGS";
-constexpr std::string_view DEBUG_EXTRA_UNIFORMS_MACRO_KEY = "DEBUG_EXTRA_UNIFORMS";
-constexpr std::string_view DEBUG_APPLY_VARYINGS_CODE_MACRO_KEY = "DEBUG_APPLY_VARYING_CODE";
-
-constexpr std::string_view MINIMUM_DEBUG_COLOR_RATE_MACRO_KEY = "MINIMUM_DEBUG_COLOR_RATE";
-constexpr std::string_view MAXIMUM_DEBUG_COLOR_RATE_MACRO_KEY = "MAXIMUM_DEBUG_COLOR_RATE";
-
-constexpr std::string_view DEBUG_TRIGGER_RED_CODE_MACRO_KEY = "DEBUG_TRIGGER_RED_CODE";
-constexpr std::string_view DEBUG_TRIGGER_GREEN_CODE_MACRO_KEY = "DEBUG_TRIGGER_GREEN_CODE";
-constexpr std::string_view DEBUG_TRIGGER_BLUE_CODE_MACRO_KEY = "DEBUG_TRIGGER_BLUE_CODE";
-constexpr std::string_view DEBUG_RATIO_RED_CODE_MACRO_KEY = "DEBUG_RATIO_RED_CODE";
-constexpr std::string_view DEBUG_RATIO_GREEN_CODE_MACRO_KEY = "DEBUG_RATIO_GREEN_CODE";
-constexpr std::string_view DEBUG_RATIO_BLUE_CODE_MACRO_KEY = "DEBUG_RATIO_BLUE_CODE";
-
-// Default macro keywords when we fail to parse script.
-constexpr std::string_view DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE = "0.0";
-constexpr std::string_view DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE = "return false;";
-constexpr std::string_view DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE = "return 0.0;";
-constexpr std::string_view DEFAULT_DEBUG_APPLY_VARYINGS_CODE_MACRO_VALUE = "return;";
-
-constexpr std::string_view EMPTY_STRING = "";
-constexpr std::string_view VERTEX_SHADER_ATTRIBUTES_PREFIX = "INPUT";
-constexpr std::string_view VERTEX_SHADER_VARYINGS_PREFIX = "OUTPUT";
-constexpr std::string_view FRAGMENT_SHADER_VARYINGS_PREFIX = "INPUT";
-constexpr std::string_view UNIFORMS_PREFIX = "uniform";
-
-bool ParseScriptInfomation(Property::Map& vertexResult, Property::Map& fragmentResult)
-{
- std::string stringOut;
- if(!LoadJsonScript(stringOut))
- {
- DALI_LOG_ERROR("Fail to load script file [%s]\n", GetScriptFilename().c_str());
- return false;
- }
-
- Toolkit::JsonParser parser = Toolkit::JsonParser::New();
-
- if(!parser.Parse(stringOut))
- {
- std::ostringstream stream;
- if(parser.ParseError())
- {
- stream << "position: " << parser.GetErrorPosition() << ", line: " << parser.GetErrorLineNumber() << ", column: " << parser.GetErrorColumn() << ", description: " << parser.GetErrorDescription() << ".";
- }
- DALI_LOG_ERROR("Fail to parse json script\nError : %s\nJson : %s\n", stream.str().c_str(), stringOut.c_str());
- return false;
- }
-
- const auto* rootNode = parser.GetRoot();
- if(!rootNode)
- {
- DALI_LOG_ERROR("Fail to get root node\n");
- return false;
- }
-
- auto InsertScriptMap = [](Property::Map& result, const TreeNode* node, const std::string_view& jsonKey, const std::string_view& macroKey, const std::string_view& defaultValue, const std::string_view& prefixString) {
- std::ostringstream oss;
- oss.clear();
-
- if(node)
- {
- const auto* childNode = node->GetChild(jsonKey);
-
- if(childNode)
- {
- if(childNode->GetType() == TreeNode::FLOAT)
- {
- oss << childNode->GetFloat();
- }
- else if(childNode->GetType() == TreeNode::STRING)
- {
- if(!prefixString.empty())
- {
- oss << prefixString << " ";
- }
- oss << childNode->GetString();
- }
- else if(childNode->GetType() == TreeNode::ARRAY)
- {
- // Concat strings with line feed
- bool isFirst = true;
- for(auto iter = childNode->CBegin(), endIter = childNode->CEnd(); iter != endIter; ++iter)
- {
- if((*iter).second.GetType() == TreeNode::STRING)
- {
- if(isFirst)
- {
- isFirst = false;
- }
- else
- {
- oss << "\n";
- }
- if(!prefixString.empty())
- {
- oss << prefixString << " ";
- }
- oss << (*iter).second.GetString();
- }
- }
- }
- }
- }
-
- if(oss.str().empty() && !defaultValue.empty())
- {
- oss << defaultValue;
- }
-
- if(!oss.str().empty())
- {
- result.Insert(std::string(macroKey), oss.str());
- }
- };
-
- auto InsertChannelScriptMap = [&InsertScriptMap](Property::Map& result, const TreeNode* node, const std::string_view& channelJsonKey, const std::string_view& triggerMacroKey, const std::string_view& ratioMacroKey) {
- const auto* channelNode = node->GetChild(channelJsonKey);
- InsertScriptMap(result, channelNode, DEBUG_TRIGGER_CODE_JSON_KEY, triggerMacroKey, DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE, EMPTY_STRING);
- InsertScriptMap(result, channelNode, DEBUG_RATIO_CODE_JSON_KEY, ratioMacroKey, DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE, EMPTY_STRING);
- };
-
- // Get attribute value code
- InsertScriptMap(vertexResult, rootNode, DEBUG_EXTRA_ATTRIBUTES_JSON_KEY, DEBUG_EXTRA_ATTRIBUTES_MACRO_KEY, EMPTY_STRING, VERTEX_SHADER_ATTRIBUTES_PREFIX);
-
- // Get varying value code
- InsertScriptMap(vertexResult, rootNode, DEBUG_EXTRA_VARYINGS_JSON_KEY, DEBUG_EXTRA_VARYINGS_MACRO_KEY, EMPTY_STRING, VERTEX_SHADER_VARYINGS_PREFIX);
- InsertScriptMap(fragmentResult, rootNode, DEBUG_EXTRA_VARYINGS_JSON_KEY, DEBUG_EXTRA_VARYINGS_MACRO_KEY, EMPTY_STRING, FRAGMENT_SHADER_VARYINGS_PREFIX);
-
- // Get uniform value code
- InsertScriptMap(vertexResult, rootNode, DEBUG_EXTRA_UNIFORMS_JSON_KEY, DEBUG_EXTRA_UNIFORMS_MACRO_KEY, EMPTY_STRING, UNIFORMS_PREFIX);
- InsertScriptMap(fragmentResult, rootNode, DEBUG_EXTRA_UNIFORMS_JSON_KEY, DEBUG_EXTRA_UNIFORMS_MACRO_KEY, EMPTY_STRING, UNIFORMS_PREFIX);
-
- // Get apply varying code
- InsertScriptMap(vertexResult, rootNode, DEBUG_APPLY_VARYINGS_CODE_JSON_KEY, DEBUG_APPLY_VARYINGS_CODE_MACRO_KEY, DEFAULT_DEBUG_APPLY_VARYINGS_CODE_MACRO_VALUE, EMPTY_STRING);
-
- // Get color rate
- InsertScriptMap(fragmentResult, rootNode, MINIMUM_DEBUG_COLOR_RATE_JSON_KEY, MINIMUM_DEBUG_COLOR_RATE_MACRO_KEY, DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE, EMPTY_STRING);
- InsertScriptMap(fragmentResult, rootNode, MAXIMUM_DEBUG_COLOR_RATE_JSON_KEY, MAXIMUM_DEBUG_COLOR_RATE_MACRO_KEY, DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE, EMPTY_STRING);
-
- // Get each color ChannelCodes
- InsertChannelScriptMap(fragmentResult, rootNode, DEBUG_RED_CHANNEL_CODE_JSON_KEY, DEBUG_TRIGGER_RED_CODE_MACRO_KEY, DEBUG_RATIO_RED_CODE_MACRO_KEY);
- InsertChannelScriptMap(fragmentResult, rootNode, DEBUG_GREEN_CHANNEL_CODE_JSON_KEY, DEBUG_TRIGGER_GREEN_CODE_MACRO_KEY, DEBUG_RATIO_GREEN_CODE_MACRO_KEY);
- InsertChannelScriptMap(fragmentResult, rootNode, DEBUG_BLUE_CHANNEL_CODE_JSON_KEY, DEBUG_TRIGGER_BLUE_CODE_MACRO_KEY, DEBUG_RATIO_BLUE_CODE_MACRO_KEY);
-
- return true;
-}
-
-const std::vector<Property::Map>& GetScriptInfomation()
-{
- static std::vector<Property::Map> results;
-
- if(DALI_UNLIKELY(results.empty()))
- {
- results.resize(2);
-
- auto& vertexShaderResult = results[0];
- auto& fragmentShaderResult = results[1];
-
- if(!ParseScriptInfomation(vertexShaderResult, fragmentShaderResult))
- {
- // Use default script information if parse failed.
- vertexShaderResult.Clear();
- fragmentShaderResult.Clear();
-
- vertexShaderResult.Insert(std::string(DEBUG_APPLY_VARYINGS_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_APPLY_VARYINGS_CODE_MACRO_VALUE));
-
- fragmentShaderResult.Insert(std::string(MINIMUM_DEBUG_COLOR_RATE_MACRO_KEY), std::string(DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE));
- fragmentShaderResult.Insert(std::string(MAXIMUM_DEBUG_COLOR_RATE_MACRO_KEY), std::string(DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE));
- fragmentShaderResult.Insert(std::string(DEBUG_TRIGGER_RED_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE));
- fragmentShaderResult.Insert(std::string(DEBUG_TRIGGER_GREEN_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE));
- fragmentShaderResult.Insert(std::string(DEBUG_TRIGGER_BLUE_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE));
- fragmentShaderResult.Insert(std::string(DEBUG_RATIO_RED_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE));
- fragmentShaderResult.Insert(std::string(DEBUG_RATIO_GREEN_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE));
- fragmentShaderResult.Insert(std::string(DEBUG_RATIO_BLUE_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE));
- }
- }
-
- return results;
-}
-
-void RedefineMacro(std::string& shaderCode, std::string macro, std::string value)
-{
- std::string definition = "#define " + macro;
- std::size_t found = shaderCode.find(definition);
- DALI_ASSERT_ALWAYS(found != std::string::npos && "Macro keyword was not exist in shader code!");
-
- std::size_t insertionPoint = found + definition.length();
-
- // Automatically insert line-continuation character into value
- std::regex re("\n");
- std::sregex_token_iterator first{value.begin(), value.end(), re, -1}, last;
- for(auto i = first; i != last; ++i)
- {
- std::string line = std::string(" \\\n") + (*i).str();
- shaderCode.insert(insertionPoint, line);
- insertionPoint += line.length();
- }
-}
-
-} // namespace
-
-namespace ImageVisualShaderDebug
-{
-bool DebugImageVisualShaderEnabled()
-{
- return DebugImageVisualShaderEnvironmentEnabled();
-}
-
-void ApplyImageVisualShaderDebugScriptCode(std::string& vertexShader, std::string& fragmentShader)
-{
- const auto& resultMaps = GetScriptInfomation();
-
- for(std::size_t i = 0u; i < resultMaps[0].Count(); ++i)
- {
- auto key = resultMaps[0].GetKeyAt(i);
- const auto& value = resultMaps[0].GetValue(i);
-
- RedefineMacro(vertexShader, std::move(key.stringKey), value.Get<std::string>());
- }
-
- for(std::size_t i = 0u; i < resultMaps[1].Count(); ++i)
- {
- auto key = resultMaps[1].GetKeyAt(i);
- const auto& value = resultMaps[1].GetValue(i);
-
- RedefineMacro(fragmentShader, std::move(key.stringKey), value.Get<std::string>());
- }
-}
-} // namespace ImageVisualShaderDebug
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_IMAGE_VISUAL_SHADER_DEBUG_H
-#define DALI_TOOLKIT_IMAGE_VISUAL_SHADER_DEBUG_H
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// EXTERNAL INCLUDES
-#include <string>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-namespace ImageVisualShaderDebug
-{
-/**
- * @brief Check whether we need to use debug option for image visual.
- *
- * @return True if ImageVisualShader relative environment on. False otherwise.
- */
-bool DebugImageVisualShaderEnabled();
-
-/**
- * @brief Apply vertex / fragment shader use debug script.
- *
- * @param[in, out] vertexShader Vertex shader code to apply debug script.
- * @param[in, out] fragmentShader Fragment shader code to apply debug script.
- */
-void ApplyImageVisualShaderDebugScriptCode(std::string& vertexShader, std::string& fragmentShader);
-
-} // namespace ImageVisualShaderDebug
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_IMAGE_VISUAL_SHADER_DEBUG_H
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/rendering/texture-devel.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
-#include <dali-toolkit/internal/visuals/image-visual-shader-debug.h>
-#include <dali-toolkit/internal/visuals/visual-string-constants.h>
-#include <dali/integration-api/debug.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-namespace
-{
-const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
-
-constexpr int NATIVE_SHADER_TYPE_OFFSET = VisualFactoryCache::ShaderType::NATIVE_IMAGE_SHADER - VisualFactoryCache::ShaderType::IMAGE_SHADER;
-constexpr std::string_view Y_FLIP_MASK_TEXTURE = "uYFlipMaskTexture";
-constexpr float NOT_FLIP_MASK_TEXTURE = 0.0f;
-
-constexpr auto SHADER_TYPE_COUNT = 6u;
-
-constexpr std::string_view VertexPredefines[SHADER_TYPE_COUNT]{
- "", // VisualFactoryCache::IMAGE_SHADER,
- "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
- "", // VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
- "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
- "", // VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
- "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
-};
-constexpr std::string_view FragmentPredefines[SHADER_TYPE_COUNT]{
- "", // VisualFactoryCache::IMAGE_SHADER,
- "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
- "#define IS_REQUIRED_YUV_TO_RGB\n", // VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
- "#define IS_REQUIRED_ROUNDED_CORNER\n#define IS_REQUIRED_YUV_TO_RGB\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
- "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n", // VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
- "#define IS_REQUIRED_ROUNDED_CORNER\n#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
-};
-constexpr VisualFactoryCache::ShaderType ShaderTypePredefines[SHADER_TYPE_COUNT]{
- VisualFactoryCache::ShaderType::IMAGE_SHADER,
- VisualFactoryCache::ShaderType::IMAGE_SHADER_ROUNDED_CORNER,
- VisualFactoryCache::ShaderType::IMAGE_SHADER_YUV_TO_RGB,
- VisualFactoryCache::ShaderType::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
- VisualFactoryCache::ShaderType::IMAGE_SHADER_YUV_AND_RGB,
- VisualFactoryCache::ShaderType::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
-};
-} // unnamed namespace
-
-ImageVisualShaderFactory::ImageVisualShaderFactory()
-: mFragmentShaderNeedChange(ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED)
-{
-}
-
-ImageVisualShaderFactory::~ImageVisualShaderFactory()
-{
-}
-
-Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, ImageVisualShaderFeatureBuilder& featureBuilder)
-{
- Shader shader;
- VisualFactoryCache::ShaderType shaderType = featureBuilder.GetShaderType();
-
- if(featureBuilder.NeedToChangeFragmentShader() == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE &&
- (mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED ||
- mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE))
- {
- DALI_ASSERT_DEBUG((static_cast<int>(shaderType) >= static_cast<int>(VisualFactoryCache::IMAGE_SHADER)) &&
- (static_cast<int>(shaderType) <= static_cast<int>(VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP)) &&
- "Do not support native image shader for given feature!!");
- shaderType = static_cast<VisualFactoryCache::ShaderType>(static_cast<int>(shaderType) + NATIVE_SHADER_TYPE_OFFSET);
- }
-
- shader = factoryCache.GetShader(shaderType);
- if(shader)
- {
- return shader;
- }
-
- std::string vertexShaderPrefixList;
- std::string fragmentShaderPrefixList;
- featureBuilder.GetVertexShaderPrefixList(vertexShaderPrefixList);
- featureBuilder.GetFragmentShaderPrefixList(fragmentShaderPrefixList);
-
- if(Dali::Toolkit::Internal::ImageVisualShaderDebug::DebugImageVisualShaderEnabled())
- {
- vertexShaderPrefixList += "#define IS_REQUIRED_DEBUG_VISUAL_SHADER\n";
- fragmentShaderPrefixList += "#define IS_REQUIRED_DEBUG_VISUAL_SHADER\n";
- }
-
- 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(Dali::Toolkit::Internal::ImageVisualShaderDebug::DebugImageVisualShaderEnabled())
- {
- Dali::Toolkit::Internal::ImageVisualShaderDebug::ApplyImageVisualShaderDebugScriptCode(vertexShader, fragmentShader);
- }
-
- if(featureBuilder.NeedToChangeFragmentShader() == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE)
- {
- bool modified = DevelTexture::ApplyNativeFragmentShader(featureBuilder.GetTexture(), fragmentShader);
- if(mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE)
- {
- DALI_ASSERT_ALWAYS(modified && "NativeImageTexture need to change fragment shader. But DALI default image shader doesn't changed!");
- }
- else if(DALI_UNLIKELY(mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED))
- {
- mFragmentShaderNeedChange = (modified) ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
-
- if(mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE)
- {
- shaderType = static_cast<VisualFactoryCache::ShaderType>(static_cast<int>(shaderType) - NATIVE_SHADER_TYPE_OFFSET);
- shader = factoryCache.GetShader(shaderType);
- }
- }
- }
-
- if(shader)
- {
- return shader;
- }
-
- shader = factoryCache.GenerateAndSaveShader(shaderType, vertexShader, fragmentShader);
- shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
- if(featureBuilder.IsEnabledAlphaMaskingOnRendering())
- {
- shader.RegisterProperty(Y_FLIP_MASK_TEXTURE, NOT_FLIP_MASK_TEXTURE);
- }
-
- return shader;
-}
-
-std::string_view ImageVisualShaderFactory::GetVertexShaderSource()
-{
- // static string variable to cache complete vertex shader
- static std::string gVertexShader;
- if(gVertexShader.empty())
- {
- gVertexShader = Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data();
- }
-
- return gVertexShader;
-}
-
-std::string_view ImageVisualShaderFactory::GetFragmentShaderSource()
-{
- // static string variable to cache complete fragment shader (no atlas)
- static std::string gFragmentShaderNoAtlas;
- if(gFragmentShaderNoAtlas.empty())
- {
- gFragmentShaderNoAtlas = Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_FRAG.data();
- }
- return gFragmentShaderNoAtlas;
-}
-
-void ImageVisualShaderFactory::GetPreCompiledShader(RawShaderData& shaders)
-{
- std::vector<std::string_view> vertexPrefix;
- std::vector<std::string_view> fragmentPrefix;
- std::vector<std::string_view> shaderName;
- shaders.shaderCount = 0;
- int shaderCount = 0;
- for(uint32_t i = 0; i < SHADER_TYPE_COUNT; ++i)
- {
- vertexPrefix.push_back(VertexPredefines[i]);
- fragmentPrefix.push_back(FragmentPredefines[i]);
- shaderName.push_back(Scripting::GetLinearEnumerationName<VisualFactoryCache::ShaderType>(ShaderTypePredefines[i], VISUAL_SHADER_TYPE_TABLE, VISUAL_SHADER_TYPE_TABLE_COUNT));
- shaderCount++;
- }
-
- shaders.vertexPrefix = vertexPrefix;
- shaders.fragmentPrefix = fragmentPrefix;
- shaders.shaderName = shaderName;
- shaders.vertexShader = SHADER_IMAGE_VISUAL_SHADER_VERT;
- shaders.fragmentShader = SHADER_IMAGE_VISUAL_SHADER_FRAG;
- shaders.shaderCount = shaderCount;
-}
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
-#define DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
-
-/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// EXTERNAL INCLUDES
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
-#include <dali-toolkit/internal/visuals/image-visual-shader-feature-builder.h>
-#include <string_view>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-
-/**
- * ImageVisualShaderFactory is an object that provides and shares shaders between image visuals
- */
-class ImageVisualShaderFactory
-{
-public:
- /**
- * @brief Constructor
- */
- ImageVisualShaderFactory();
-
- /**
- * @brief Destructor
- */
- ~ImageVisualShaderFactory();
-
- /**
- * @brief Get the standard image rendering shader.
- * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
- * @param[in] featureBuilder Collection of current image shader's features
- * @return The standard image rendering shader with features.
- */
- Shader GetShader(VisualFactoryCache& factoryCache, ImageVisualShaderFeatureBuilder& featureBuilder);
-
- /**
- * @brief Request the default vertex shader source.
- * @return The default vertex shader source.
- */
- std::string_view GetVertexShaderSource();
-
- /**
- * @brief Request the default fragment shader source.
- * @return The default fragment shader source.
- */
- std::string_view GetFragmentShaderSource();
-
- /**
- * @brief Get the default shader source.
- * @param[in] shaders shaderList for precompile
- */
- void GetPreCompiledShader(RawShaderData& shaders);
-
-protected:
- /**
- * Undefined copy constructor.
- */
- ImageVisualShaderFactory(const ImageVisualShaderFactory&);
-
- /**
- * Undefined assignment operator.
- */
- ImageVisualShaderFactory& operator=(const ImageVisualShaderFactory& rhs);
-
-private:
- /**
- * @brief Cached information whether native image should change fragment shader.
- * Default it is ChangeFragmentShader::UNDECIDED.
- * If we have any chance to check native image source apply fragment shader,
- * this vaule will be changed one of these : ChangeFragmentShader::DONT_CHANGE or ChangeFragmentShader::NEED_CHANGE
- *
- * After result cached, this value will not be changed.
- *
- * If value is DONT_CHANGE, ImageVisualShaderFactory::GetShader never call ApplyNativeFragmentShader.
- * Else, ImageVisualShaderFactory::GetShader will call ApplyNativeFragmentShader if native image source texture come.
- */
- ImageVisualShaderFeature::ChangeFragmentShader::Type mFragmentShaderNeedChange : 3;
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
+++ /dev/null
-/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/visuals/image-visual-shader-feature-builder.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-namespace
-{
-// 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,
- COLOR_CONVERSION = 1 << 3,
-
- UNIFIED_YUV_AND_RGB = 1 << 2, // Special enum to trick unified YUV and RGB.
-};
-
-static constexpr auto SHADER_TYPE_COUNT = 16u;
-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_YUV_TO_RGB,
- VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
- VisualFactoryCache::IMAGE_SHADER_BORDERLINE_YUV_TO_RGB,
- VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_YUV_TO_RGB,
- VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
- VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
- VisualFactoryCache::IMAGE_SHADER_BORDERLINE_YUV_AND_RGB,
- VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_YUV_AND_RGB};
-} // unnamed namespace
-
-ImageVisualShaderFeatureBuilder::ImageVisualShaderFeatureBuilder()
-: mTextureAtlas(ImageVisualShaderFeature::TextureAtlas::DISABLED),
- mDefaultTextureWrapMode(ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY),
- mRoundedCorner(ImageVisualShaderFeature::RoundedCorner::DISABLED),
- mBorderline(ImageVisualShaderFeature::Borderline::DISABLED),
- mAlphaMaskingOnRendering(ImageVisualShaderFeature::AlphaMaskingOnRendering::DISABLED),
- mColorConversion(ImageVisualShaderFeature::ColorConversion::DONT_NEED),
- mTexture()
-{
-}
-
-ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::EnableTextureAtlas(bool enableTextureAtlas)
-{
- mTextureAtlas = (enableTextureAtlas ? ImageVisualShaderFeature::TextureAtlas::ENABLED : ImageVisualShaderFeature::TextureAtlas::DISABLED);
- return *this;
-}
-
-ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::ApplyDefaultTextureWrapMode(bool applyDefaultTextureWrapMode)
-{
- mDefaultTextureWrapMode = (applyDefaultTextureWrapMode ? ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY : ImageVisualShaderFeature::DefaultTextureWrapMode::DO_NOT_APPLY);
- return *this;
-}
-
-ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::EnableRoundedCorner(bool enableRoundedCorner)
-{
- mRoundedCorner = (enableRoundedCorner ? ImageVisualShaderFeature::RoundedCorner::ENABLED : ImageVisualShaderFeature::RoundedCorner::DISABLED);
- return *this;
-}
-
-ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::EnableBorderline(bool enableBorderline)
-{
- mBorderline = (enableBorderline ? ImageVisualShaderFeature::Borderline::ENABLED : ImageVisualShaderFeature::Borderline::DISABLED);
- return *this;
-}
-
-ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::SetTextureForFragmentShaderCheck(const Dali::Texture& texture)
-{
- mTexture = texture;
- return *this;
-}
-
-ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::EnableAlphaMaskingOnRendering(bool enableAlphaMaskingOnRendering)
-{
- mAlphaMaskingOnRendering = (enableAlphaMaskingOnRendering ? ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED : ImageVisualShaderFeature::AlphaMaskingOnRendering::DISABLED);
- return *this;
-}
-
-ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::EnableYuvToRgb(bool enableYuvToRgb, bool enableUnifiedYuvAndRgb)
-{
- mColorConversion = (enableUnifiedYuvAndRgb ? ImageVisualShaderFeature::ColorConversion::UNIFIED_YUV_AND_RGB : (enableYuvToRgb ? ImageVisualShaderFeature::ColorConversion::YUV_TO_RGB : ImageVisualShaderFeature::ColorConversion::DONT_NEED));
- return *this;
-}
-
-VisualFactoryCache::ShaderType ImageVisualShaderFeatureBuilder::GetShaderType()
-{
- VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::IMAGE_SHADER;
- if(mTextureAtlas == ImageVisualShaderFeature::TextureAtlas::ENABLED)
- {
- if(mDefaultTextureWrapMode == ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY)
- {
- shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP;
- }
- else
- {
- shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP;
- }
- }
- else
- {
- uint32_t shaderTypeFlag = static_cast<uint32_t>(ImageVisualRequireFlag::DEFAULT);
- if(mRoundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
- {
- shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::ROUNDED_CORNER);
- }
- if(mBorderline == ImageVisualShaderFeature::Borderline::ENABLED)
- {
- shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::BORDERLINE);
- }
- if(mAlphaMaskingOnRendering == ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED)
- {
- shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::ALPHA_MASKING);
- }
- else if(mColorConversion == 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);
- }
- else if(mColorConversion == ImageVisualShaderFeature::ColorConversion::UNIFIED_YUV_AND_RGB)
- {
- shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::COLOR_CONVERSION);
- shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::UNIFIED_YUV_AND_RGB);
- }
- shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
- }
-
- return shaderType;
-}
-
-ImageVisualShaderFeature::ChangeFragmentShader::Type ImageVisualShaderFeatureBuilder::NeedToChangeFragmentShader()
-{
- return (mTexture && DevelTexture::IsNative(mTexture))
- ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE
- : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
-}
-
-void ImageVisualShaderFeatureBuilder::GetVertexShaderPrefixList(std::string& vertexShaderPrefixList)
-{
- if(mTextureAtlas != ImageVisualShaderFeature::TextureAtlas::ENABLED)
- {
- if(mRoundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
- {
- vertexShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER\n";
- }
- if(mBorderline == ImageVisualShaderFeature::Borderline::ENABLED)
- {
- vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE\n";
- }
- if(mAlphaMaskingOnRendering == ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED)
- {
- vertexShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING\n";
- }
- }
-}
-
-void ImageVisualShaderFeatureBuilder::GetFragmentShaderPrefixList(std::string& fragmentShaderPrefixList)
-{
- if(mTextureAtlas == ImageVisualShaderFeature::TextureAtlas::ENABLED)
- {
- if(mDefaultTextureWrapMode == ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY)
- {
- fragmentShaderPrefixList += "#define ATLAS_DEFAULT_WARP\n";
- }
- else
- {
- fragmentShaderPrefixList += "#define ATLAS_CUSTOM_WARP\n";
- }
- }
- else
- {
- if(mRoundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
- {
- fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER\n";
- }
- if(mBorderline == ImageVisualShaderFeature::Borderline::ENABLED)
- {
- fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE\n";
- }
- if(mAlphaMaskingOnRendering == ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED)
- {
- fragmentShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING\n";
- }
- else if(mColorConversion == ImageVisualShaderFeature::ColorConversion::YUV_TO_RGB)
- {
- fragmentShaderPrefixList += "#define IS_REQUIRED_YUV_TO_RGB\n";
- }
- else if(mColorConversion == ImageVisualShaderFeature::ColorConversion::UNIFIED_YUV_AND_RGB)
- {
- fragmentShaderPrefixList += "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n";
- }
- }
-}
-
-Dali::Texture ImageVisualShaderFeatureBuilder::GetTexture()
-{
- return mTexture;
-}
-
-bool ImageVisualShaderFeatureBuilder::IsEnabledAlphaMaskingOnRendering() const
-{
- return mAlphaMaskingOnRendering == ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED;
-}
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FEATURE_BUILDER_H
-#define DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FEATURE_BUILDER_H
-
-/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/rendering/texture.h>
-#include <dali/devel-api/rendering/texture-devel.h>
-#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-/**
- * ImageVisualShaderFeature contains feature lists what image visual shader need to know.
- */
-namespace ImageVisualShaderFeature
-{
-namespace TextureAtlas
-{
-/**
- * @brief Whether use texture with atlas, or not
- */
-enum Type
-{
- DISABLED = 0, ///< Image visual doesn't use ATLAS
- ENABLED ///< Image visual uses ATLAS
-};
-} // namespace TextureAtlas
-
-namespace DefaultTextureWrapMode
-{
-/**
- * @brief Whether apply to texture wraping in default, or not
- */
-enum Type
-{
- APPLY = 0, ///< Image visual applies to wraping texture in default
- DO_NOT_APPLY ///< Image visual doesn't apply to wraping texture in default
-};
-} // namespace DefaultTextureWrapMode
-
-namespace RoundedCorner
-{
-/**
- * @brief Whether use rounded corner, or not
- */
-enum Type
-{
- DISABLED = 0, ///< Image visual doesn't use rounded corner
- ENABLED ///< Image visual uses rounded corner
-};
-} // namespace RoundedCorner
-
-namespace Borderline
-{
-/**
- * @brief Whether use borderline, or not
- */
-enum Type
-{
- DISABLED = 0, ///< Image visual doesn't use borderline
- ENABLED ///< Image visual uses borderline
-};
-} // namespace Borderline
-
-namespace ChangeFragmentShader
-{
-/**
- * @brief Whether native image change the default fragment shader, or not
- */
-enum Type
-{
- DONT_CHANGE = 0, ///< Native image doesn't change default fragment shader.
- NEED_CHANGE, ///< Native image changes default fragment shader. We need another shader cache.
- UNDECIDED, ///< Undecided.
-};
-} // namespace ChangeFragmentShader
-
-namespace AlphaMaskingOnRendering
-{
-/**
- * @brief Whether use runtime alpha masking in shader, or not
- */
-enum Type
-{
- DISABLED = 0, ///< Image visual doesn't use runtime alpha masking
- ENABLED ///< Image visual uses runtime alpha masking
-};
-} // 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
- UNIFIED_YUV_AND_RGB ///< Need to support both yuv conversion case and normal case.
-};
-} // namespace ColorConversion
-
-} // namespace ImageVisualShaderFeature
-
-/**
- * @brief Collection of current image visual feature. Only use for ImageVisualShaderFactory::GetShader()
- */
-class ImageVisualShaderFeatureBuilder
-{
-public:
- ImageVisualShaderFeatureBuilder();
-
- ImageVisualShaderFeatureBuilder& EnableTextureAtlas(bool enableTextureAtlas);
-
- ImageVisualShaderFeatureBuilder& ApplyDefaultTextureWrapMode(bool applyDefaultTextureWrapMode);
-
- ImageVisualShaderFeatureBuilder& EnableRoundedCorner(bool enableRoundedCorner);
-
- ImageVisualShaderFeatureBuilder& EnableBorderline(bool enableBorderline);
-
- ImageVisualShaderFeatureBuilder& SetTextureForFragmentShaderCheck(const Dali::Texture& texture);
-
- ImageVisualShaderFeatureBuilder& EnableAlphaMaskingOnRendering(bool enableAlphaMaskingOnRendering);
-
- ImageVisualShaderFeatureBuilder& EnableYuvToRgb(bool enableYuvToRgb, bool enableUnifiedYuvAndRgb = false);
-
- VisualFactoryCache::ShaderType GetShaderType();
-
- ImageVisualShaderFeature::ChangeFragmentShader::Type NeedToChangeFragmentShader();
-
- void GetVertexShaderPrefixList(std::string& vertexShaderPrefixList);
- void GetFragmentShaderPrefixList(std::string& fragmentShaderPrefixList);
-
- Dali::Texture GetTexture();
-
- bool IsEnabledAlphaMaskingOnRendering() const;
-
-private:
- ImageVisualShaderFeature::TextureAtlas::Type mTextureAtlas : 2; ///< Whether use texture with atlas, or not. default as TextureAtlas::DISABLED
- ImageVisualShaderFeature::DefaultTextureWrapMode::Type mDefaultTextureWrapMode : 2; ///< Whether apply to texture wraping in default, or not. default as DefaultTextureWrapMode::APPLY
- ImageVisualShaderFeature::RoundedCorner::Type mRoundedCorner : 2; ///< Whether use rounded corner, or not. default as RoundedCorner::DISABLED
- ImageVisualShaderFeature::Borderline::Type mBorderline : 2; ///< Whether use borderline, or not. default as Borderline::DISABLED
- ImageVisualShaderFeature::AlphaMaskingOnRendering::Type mAlphaMaskingOnRendering : 2; ///< Whether use runtime alpha masking, or not. default as AlphaMaskingOnRendering::DISABLED
- ImageVisualShaderFeature::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
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
--- /dev/null
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/visuals/image/image-atlas-manager.h>
+
+// EXTERNAL HEADER
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+const uint32_t DEFAULT_ATLAS_SIZE(1024u); // this size can fit 8 by 8 images of average size 128*128
+const uint32_t MAX_ITEM_SIZE(512u);
+const uint32_t MAX_ITEM_AREA(MAX_ITEM_SIZE* MAX_ITEM_SIZE);
+} // namespace
+
+ImageAtlasManager::ImageAtlasManager()
+: mBrokenImageUrl("")
+{
+}
+
+ImageAtlasManager::~ImageAtlasManager()
+{
+}
+
+bool ImageAtlasManager::CheckAtlasAvailable(const VisualUrl& url, const ImageDimensions& size) const
+{
+ ImageDimensions dimensions = size;
+ ImageDimensions zero;
+ if(size == zero)
+ {
+ dimensions = Dali::GetClosestImageSize(url.GetUrl());
+ }
+
+ // big image, atlasing is not applied
+ if(static_cast<uint32_t>(dimensions.GetWidth()) * static_cast<uint32_t>(dimensions.GetHeight()) > MAX_ITEM_AREA || dimensions.GetWidth() > DEFAULT_ATLAS_SIZE || dimensions.GetHeight() > DEFAULT_ATLAS_SIZE)
+ {
+ return false;
+ }
+ return true;
+}
+
+TextureSet ImageAtlasManager::Add(Vector4& textureRect,
+ const VisualUrl& url,
+ ImageDimensions& size,
+ FittingMode::Type fittingMode,
+ bool orientationCorrection,
+ AtlasUploadObserver* atlasUploadObserver)
+{
+ ImageDimensions dimensions = size;
+ ImageDimensions zero;
+ if(size == zero)
+ {
+ dimensions = Dali::GetClosestImageSize(url.GetUrl());
+ }
+
+ // big image, atlasing is not applied
+ if(static_cast<uint32_t>(dimensions.GetWidth()) * static_cast<uint32_t>(dimensions.GetHeight()) > MAX_ITEM_AREA || dimensions.GetWidth() > DEFAULT_ATLAS_SIZE || dimensions.GetHeight() > DEFAULT_ATLAS_SIZE)
+ {
+ return TextureSet();
+ }
+ size = dimensions;
+
+ uint32_t i = 0;
+ for(AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
+ {
+ if(GetImplementation(*iter).Upload(textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver))
+ {
+ return mTextureSetList[i];
+ }
+ i++;
+ }
+
+ CreateNewAtlas();
+ GetImplementation(mAtlasList.back()).Upload(textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver);
+ return mTextureSetList.back();
+}
+
+TextureSet ImageAtlasManager::Add(Vector4& textureRect,
+ const EncodedImageBuffer& encodedImageBuffer,
+ const ImageDimensions& size,
+ FittingMode::Type fittingMode,
+ bool orientationCorrection,
+ AtlasUploadObserver* atlasUploadObserver)
+{
+ // big image, atlasing is not applied
+ if(static_cast<uint32_t>(size.GetWidth()) * static_cast<uint32_t>(size.GetHeight()) > MAX_ITEM_AREA || size.GetWidth() > DEFAULT_ATLAS_SIZE || size.GetHeight() > DEFAULT_ATLAS_SIZE)
+ {
+ return TextureSet();
+ }
+
+ uint32_t i = 0;
+ for(AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
+ {
+ if(GetImplementation(*iter).Upload(textureRect, encodedImageBuffer, size, fittingMode, orientationCorrection, atlasUploadObserver))
+ {
+ return mTextureSetList[i];
+ }
+ i++;
+ }
+
+ CreateNewAtlas();
+ GetImplementation(mAtlasList.back()).Upload(textureRect, encodedImageBuffer, size, fittingMode, orientationCorrection, atlasUploadObserver);
+ return mTextureSetList.back();
+}
+
+TextureSet ImageAtlasManager::Add(Vector4& textureRect,
+ PixelData pixelData)
+{
+ // big buffer, atlasing is not applied
+ if(static_cast<uint32_t>(pixelData.GetWidth()) * static_cast<uint32_t>(pixelData.GetHeight()) > MAX_ITEM_AREA || pixelData.GetWidth() > DEFAULT_ATLAS_SIZE || pixelData.GetHeight() > DEFAULT_ATLAS_SIZE)
+ {
+ return TextureSet();
+ }
+
+ uint32_t i = 0;
+ for(AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
+ {
+ if((*iter).Upload(textureRect, pixelData))
+ {
+ return mTextureSetList[i];
+ }
+ i++;
+ }
+
+ CreateNewAtlas();
+ mAtlasList.back().Upload(textureRect, pixelData);
+ return mTextureSetList.back();
+}
+
+void ImageAtlasManager::Remove(TextureSet textureSet, const Vector4& textureRect)
+{
+ uint32_t i = 0;
+ for(TextureSetContainer::iterator iter = mTextureSetList.begin(); iter != mTextureSetList.end(); ++iter)
+ {
+ if((*iter) == textureSet)
+ {
+ mAtlasList[i].Remove(textureRect);
+ return;
+ }
+ i++;
+ }
+}
+
+void ImageAtlasManager::SetBrokenImage(const std::string& brokenImageUrl)
+{
+ if(!brokenImageUrl.empty())
+ {
+ mBrokenImageUrl = brokenImageUrl;
+ }
+}
+
+void ImageAtlasManager::CreateNewAtlas()
+{
+ Toolkit::ImageAtlas newAtlas = Toolkit::ImageAtlas::New(DEFAULT_ATLAS_SIZE, DEFAULT_ATLAS_SIZE);
+ if(!mBrokenImageUrl.empty())
+ {
+ newAtlas.SetBrokenImage(mBrokenImageUrl);
+ }
+ mAtlasList.push_back(newAtlas);
+ TextureSet textureSet = TextureSet::New();
+ textureSet.SetTexture(0u, newAtlas.GetAtlas());
+ mTextureSetList.push_back(textureSet);
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_IMAGE_ATLAS_MANAGER_H
+#define DALI_TOOLKIT_IMAGE_ATLAS_MANAGER_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+class AtlasUploadObserver;
+
+namespace Internal
+{
+/**
+ * The manager for automatic image atlasing. Owned by VisualFactory
+ */
+class ImageAtlasManager : public RefObject
+{
+public:
+ typedef std::vector<Toolkit::ImageAtlas> AtlasContainer;
+ typedef std::vector<TextureSet> TextureSetContainer;
+
+public:
+ /**
+ * Construtor
+ *
+ */
+ ImageAtlasManager();
+
+ /**
+ * @brief Check whether the image of url could be Atlas or not.
+ *
+ * @param [in] url The URL of the resource image file to use.
+ * @param [in] size The width and height to fit the loaded image to.
+ * @return True if the image could be Atlas.
+ */
+ bool CheckAtlasAvailable(const VisualUrl& url, const ImageDimensions& size) const;
+
+ /**
+ * @brief Add an image to the atlas.
+ *
+ * @note To make the atlasing efficient, an valid size should be provided.
+ * If size is not provided, then the image file will be opened to read the actual size for loading.
+ *
+ * SamplingMode::BOX_THEN_LINEAR is used to sampling pixels from the input image while fitting it to desired size.
+ *
+ * @param [out] textureRect The texture area of the resource image in the atlas.
+ * @param [in] url The URL of the resource image file to use.
+ * @param [in, out] size 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] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+ * @param [in] atlasUploadObserver The object to observe the uploading state inside ImageAtlas.
+ * @return The texture set containing the image.
+ */
+ TextureSet Add(Vector4& textureRect,
+ const VisualUrl& url,
+ ImageDimensions& size,
+ FittingMode::Type fittingMode = FittingMode::DEFAULT,
+ bool orientationCorrection = true,
+ AtlasUploadObserver* atlasUploadObserver = NULL);
+
+ /**
+ * @brief Add an image to the atlas.
+ *
+ * @note To make the atlasing efficient, an valid size should be provided.
+ *
+ * SamplingMode::BOX_THEN_LINEAR is used to sampling pixels from the input image while fitting it to desired size.
+ *
+ * @param [out] textureRect The texture area of the resource image in the atlas.
+ * @param [in] encodedImageBuffer The encoded buffer of the resource image file to use.
+ * @param [in] size 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] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+ * @param [in] atlasUploadObserver The object to observe the uploading state inside ImageAtlas.
+ * @return The texture set containing the image.
+ */
+ TextureSet Add(Vector4& textureRect,
+ const EncodedImageBuffer& encodedImageBuffer,
+ const ImageDimensions& size,
+ FittingMode::Type fittingMode = FittingMode::DEFAULT,
+ bool orientationCorrection = true,
+ AtlasUploadObserver* atlasUploadObserver = NULL);
+
+ /**
+ * @brief Add a pixel buffer to the atlas
+ *
+ * @param [out] textureRect The texture area of the resource image in the atlas.
+ * @param [in] pixelData The pixel data.
+ * @return The texture set containing the image.
+ */
+ TextureSet Add(Vector4& textureRect,
+ PixelData pixelData);
+
+ /**
+ * Remove the image at the given rectangle from the texture set.
+ *
+ * @param [in] textureSet The texture set containing the atlas image.
+ * @param [in] textureRect The texture area to be removed.
+ */
+ void Remove(TextureSet textureSet, const Vector4& textureRect);
+
+ /**
+ * @brief Set the broken image which is used to replace the image if loading fails.
+ *
+ * @param[in] brokenImageUrl The url of the broken image.
+ */
+ void SetBrokenImage(const std::string& brokenImageUrl);
+
+ /**
+ * @brief Get shader
+ */
+ Shader GetShader() const;
+
+private:
+ /**
+ * @brief Create a new atlas.
+ *
+ * This method is called when the newly added image or pixel buffer cannot fit into the current atlas list.
+ */
+ void CreateNewAtlas();
+
+protected:
+ /**
+ * Destructor
+ */
+ ~ImageAtlasManager() override;
+
+ /**
+ * Undefined copy constructor.
+ */
+ ImageAtlasManager(const ImageAtlasManager&);
+
+ /**
+ * Undefined assignment operator.
+ */
+ ImageAtlasManager& operator=(const ImageAtlasManager& rhs);
+
+private:
+ AtlasContainer mAtlasList;
+ TextureSetContainer mTextureSetList;
+ std::string mBrokenImageUrl;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ATLAS_MANAGER_H
--- /dev/null
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-debug.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
+#include <dali/devel-api/adaptor-framework/style-monitor.h> ///< for load json file.
+#include <dali/public-api/common/vector-wrapper.h>
+
+#include <regex> ///< for redefine shader
+#include <string_view>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/devel-api/builder/json-parser.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+constexpr auto DALI_DEBUG_IMAGE_VISUAL_SHADER_ENV = "DALI_DEBUG_IMAGE_VISUAL_SHADER";
+
+bool DebugImageVisualShaderEnvironmentEnabled()
+{
+ static bool enabled = false;
+ static bool enabledSetted = false;
+ if(!enabledSetted)
+ {
+ enabledSetted = true;
+ auto debugEnabledString = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_ENV);
+ enabled = debugEnabledString ? std::atoi(debugEnabledString) : false;
+ }
+ return enabled;
+}
+
+constexpr auto DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME_ENV = "DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME";
+constexpr auto DEFAULT_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME = "debug-image-visual-shader-script.json";
+
+const std::string& GetScriptFilename()
+{
+ // Set the full path for the default script file.
+ const static std::string styleDirPath{AssetManager::GetDaliStylePath()};
+ static std::string mScriptFileName{};
+
+ if(DALI_UNLIKELY(mScriptFileName.empty()))
+ {
+ // Use user's own script if exist.
+ auto environmentScriptFilename = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME_ENV);
+
+ mScriptFileName = environmentScriptFilename ? std::string(environmentScriptFilename) : styleDirPath + std::string(DEFAULT_DEBUG_IMAGE_VISUAL_SHADER_SCRIPT_FILE_NAME);
+
+ DALI_ASSERT_DEBUG(0 != mScriptFileName.length());
+ }
+
+ return mScriptFileName;
+}
+
+bool LoadJsonScript(std::string& stringOut)
+{
+ auto styleMonitor = StyleMonitor::Get();
+
+ // as toolkit is platform agnostic, it cannot load files from filesystem
+ // ask style monitor to load the style sheet
+ if(styleMonitor)
+ {
+ try
+ {
+ return styleMonitor.LoadThemeFile(GetScriptFilename(), stringOut);
+ }
+ catch(const std::exception& e)
+ {
+ DALI_LOG_ERROR("Something system exception throwed during load script file![%s]\n", GetScriptFilename().c_str());
+ DALI_LOG_ERROR("Error message : [%s]\n", e.what());
+ }
+ catch(const Dali::DaliException& e)
+ {
+ DALI_LOG_ERROR("Something Dali exception throwed during load script file![%s]\n", GetScriptFilename().c_str());
+ DALI_LOG_ERROR("Error message : [%s]\n", e.condition);
+ }
+ catch(...)
+ {
+ DALI_LOG_ERROR("Something unkown exception throwed during load script file![%s]\n", GetScriptFilename().c_str());
+ }
+ }
+
+ return false;
+}
+// Json keywords what we will get information from json.
+constexpr std::string_view DEBUG_SCRIPT_VERSION_JSON_KEY = "version";
+
+constexpr std::string_view DEBUG_EXTRA_ATTRIBUTES_JSON_KEY = "extraAttributes";
+constexpr std::string_view DEBUG_EXTRA_VARYINGS_JSON_KEY = "extraVaryings";
+constexpr std::string_view DEBUG_EXTRA_UNIFORMS_JSON_KEY = "extraUniforms";
+constexpr std::string_view DEBUG_APPLY_VARYINGS_CODE_JSON_KEY = "applyVaryingsCode";
+
+constexpr std::string_view MINIMUM_DEBUG_COLOR_RATE_JSON_KEY = "minimumColorRate";
+constexpr std::string_view MAXIMUM_DEBUG_COLOR_RATE_JSON_KEY = "maximumColorRate";
+
+constexpr std::string_view DEBUG_RED_CHANNEL_CODE_JSON_KEY = "redChannelCodes";
+constexpr std::string_view DEBUG_GREEN_CHANNEL_CODE_JSON_KEY = "greenChannelCodes";
+constexpr std::string_view DEBUG_BLUE_CHANNEL_CODE_JSON_KEY = "blueChannelCodes";
+constexpr std::string_view DEBUG_TRIGGER_CODE_JSON_KEY = "triggerCode";
+constexpr std::string_view DEBUG_RATIO_CODE_JSON_KEY = "ratioCode";
+
+// Macro keywords what we will replace at vertex/fragment shader.
+constexpr std::string_view DEBUG_EXTRA_ATTRIBUTES_MACRO_KEY = "DEBUG_EXTRA_ATTRIBUTES";
+constexpr std::string_view DEBUG_EXTRA_VARYINGS_MACRO_KEY = "DEBUG_EXTRA_VARYINGS";
+constexpr std::string_view DEBUG_EXTRA_UNIFORMS_MACRO_KEY = "DEBUG_EXTRA_UNIFORMS";
+constexpr std::string_view DEBUG_APPLY_VARYINGS_CODE_MACRO_KEY = "DEBUG_APPLY_VARYING_CODE";
+
+constexpr std::string_view MINIMUM_DEBUG_COLOR_RATE_MACRO_KEY = "MINIMUM_DEBUG_COLOR_RATE";
+constexpr std::string_view MAXIMUM_DEBUG_COLOR_RATE_MACRO_KEY = "MAXIMUM_DEBUG_COLOR_RATE";
+
+constexpr std::string_view DEBUG_TRIGGER_RED_CODE_MACRO_KEY = "DEBUG_TRIGGER_RED_CODE";
+constexpr std::string_view DEBUG_TRIGGER_GREEN_CODE_MACRO_KEY = "DEBUG_TRIGGER_GREEN_CODE";
+constexpr std::string_view DEBUG_TRIGGER_BLUE_CODE_MACRO_KEY = "DEBUG_TRIGGER_BLUE_CODE";
+constexpr std::string_view DEBUG_RATIO_RED_CODE_MACRO_KEY = "DEBUG_RATIO_RED_CODE";
+constexpr std::string_view DEBUG_RATIO_GREEN_CODE_MACRO_KEY = "DEBUG_RATIO_GREEN_CODE";
+constexpr std::string_view DEBUG_RATIO_BLUE_CODE_MACRO_KEY = "DEBUG_RATIO_BLUE_CODE";
+
+// Default macro keywords when we fail to parse script.
+constexpr std::string_view DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE = "0.0";
+constexpr std::string_view DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE = "return false;";
+constexpr std::string_view DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE = "return 0.0;";
+constexpr std::string_view DEFAULT_DEBUG_APPLY_VARYINGS_CODE_MACRO_VALUE = "return;";
+
+constexpr std::string_view EMPTY_STRING = "";
+constexpr std::string_view VERTEX_SHADER_ATTRIBUTES_PREFIX = "INPUT";
+constexpr std::string_view VERTEX_SHADER_VARYINGS_PREFIX = "OUTPUT";
+constexpr std::string_view FRAGMENT_SHADER_VARYINGS_PREFIX = "INPUT";
+constexpr std::string_view UNIFORMS_PREFIX = "uniform";
+
+bool ParseScriptInfomation(Property::Map& vertexResult, Property::Map& fragmentResult)
+{
+ std::string stringOut;
+ if(!LoadJsonScript(stringOut))
+ {
+ DALI_LOG_ERROR("Fail to load script file [%s]\n", GetScriptFilename().c_str());
+ return false;
+ }
+
+ Toolkit::JsonParser parser = Toolkit::JsonParser::New();
+
+ if(!parser.Parse(stringOut))
+ {
+ std::ostringstream stream;
+ if(parser.ParseError())
+ {
+ stream << "position: " << parser.GetErrorPosition() << ", line: " << parser.GetErrorLineNumber() << ", column: " << parser.GetErrorColumn() << ", description: " << parser.GetErrorDescription() << ".";
+ }
+ DALI_LOG_ERROR("Fail to parse json script\nError : %s\nJson : %s\n", stream.str().c_str(), stringOut.c_str());
+ return false;
+ }
+
+ const auto* rootNode = parser.GetRoot();
+ if(!rootNode)
+ {
+ DALI_LOG_ERROR("Fail to get root node\n");
+ return false;
+ }
+
+ auto InsertScriptMap = [](Property::Map& result, const TreeNode* node, const std::string_view& jsonKey, const std::string_view& macroKey, const std::string_view& defaultValue, const std::string_view& prefixString) {
+ std::ostringstream oss;
+ oss.clear();
+
+ if(node)
+ {
+ const auto* childNode = node->GetChild(jsonKey);
+
+ if(childNode)
+ {
+ if(childNode->GetType() == TreeNode::FLOAT)
+ {
+ oss << childNode->GetFloat();
+ }
+ else if(childNode->GetType() == TreeNode::STRING)
+ {
+ if(!prefixString.empty())
+ {
+ oss << prefixString << " ";
+ }
+ oss << childNode->GetString();
+ }
+ else if(childNode->GetType() == TreeNode::ARRAY)
+ {
+ // Concat strings with line feed
+ bool isFirst = true;
+ for(auto iter = childNode->CBegin(), endIter = childNode->CEnd(); iter != endIter; ++iter)
+ {
+ if((*iter).second.GetType() == TreeNode::STRING)
+ {
+ if(isFirst)
+ {
+ isFirst = false;
+ }
+ else
+ {
+ oss << "\n";
+ }
+ if(!prefixString.empty())
+ {
+ oss << prefixString << " ";
+ }
+ oss << (*iter).second.GetString();
+ }
+ }
+ }
+ }
+ }
+
+ if(oss.str().empty() && !defaultValue.empty())
+ {
+ oss << defaultValue;
+ }
+
+ if(!oss.str().empty())
+ {
+ result.Insert(std::string(macroKey), oss.str());
+ }
+ };
+
+ auto InsertChannelScriptMap = [&InsertScriptMap](Property::Map& result, const TreeNode* node, const std::string_view& channelJsonKey, const std::string_view& triggerMacroKey, const std::string_view& ratioMacroKey) {
+ const auto* channelNode = node->GetChild(channelJsonKey);
+ InsertScriptMap(result, channelNode, DEBUG_TRIGGER_CODE_JSON_KEY, triggerMacroKey, DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE, EMPTY_STRING);
+ InsertScriptMap(result, channelNode, DEBUG_RATIO_CODE_JSON_KEY, ratioMacroKey, DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE, EMPTY_STRING);
+ };
+
+ // Get attribute value code
+ InsertScriptMap(vertexResult, rootNode, DEBUG_EXTRA_ATTRIBUTES_JSON_KEY, DEBUG_EXTRA_ATTRIBUTES_MACRO_KEY, EMPTY_STRING, VERTEX_SHADER_ATTRIBUTES_PREFIX);
+
+ // Get varying value code
+ InsertScriptMap(vertexResult, rootNode, DEBUG_EXTRA_VARYINGS_JSON_KEY, DEBUG_EXTRA_VARYINGS_MACRO_KEY, EMPTY_STRING, VERTEX_SHADER_VARYINGS_PREFIX);
+ InsertScriptMap(fragmentResult, rootNode, DEBUG_EXTRA_VARYINGS_JSON_KEY, DEBUG_EXTRA_VARYINGS_MACRO_KEY, EMPTY_STRING, FRAGMENT_SHADER_VARYINGS_PREFIX);
+
+ // Get uniform value code
+ InsertScriptMap(vertexResult, rootNode, DEBUG_EXTRA_UNIFORMS_JSON_KEY, DEBUG_EXTRA_UNIFORMS_MACRO_KEY, EMPTY_STRING, UNIFORMS_PREFIX);
+ InsertScriptMap(fragmentResult, rootNode, DEBUG_EXTRA_UNIFORMS_JSON_KEY, DEBUG_EXTRA_UNIFORMS_MACRO_KEY, EMPTY_STRING, UNIFORMS_PREFIX);
+
+ // Get apply varying code
+ InsertScriptMap(vertexResult, rootNode, DEBUG_APPLY_VARYINGS_CODE_JSON_KEY, DEBUG_APPLY_VARYINGS_CODE_MACRO_KEY, DEFAULT_DEBUG_APPLY_VARYINGS_CODE_MACRO_VALUE, EMPTY_STRING);
+
+ // Get color rate
+ InsertScriptMap(fragmentResult, rootNode, MINIMUM_DEBUG_COLOR_RATE_JSON_KEY, MINIMUM_DEBUG_COLOR_RATE_MACRO_KEY, DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE, EMPTY_STRING);
+ InsertScriptMap(fragmentResult, rootNode, MAXIMUM_DEBUG_COLOR_RATE_JSON_KEY, MAXIMUM_DEBUG_COLOR_RATE_MACRO_KEY, DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE, EMPTY_STRING);
+
+ // Get each color ChannelCodes
+ InsertChannelScriptMap(fragmentResult, rootNode, DEBUG_RED_CHANNEL_CODE_JSON_KEY, DEBUG_TRIGGER_RED_CODE_MACRO_KEY, DEBUG_RATIO_RED_CODE_MACRO_KEY);
+ InsertChannelScriptMap(fragmentResult, rootNode, DEBUG_GREEN_CHANNEL_CODE_JSON_KEY, DEBUG_TRIGGER_GREEN_CODE_MACRO_KEY, DEBUG_RATIO_GREEN_CODE_MACRO_KEY);
+ InsertChannelScriptMap(fragmentResult, rootNode, DEBUG_BLUE_CHANNEL_CODE_JSON_KEY, DEBUG_TRIGGER_BLUE_CODE_MACRO_KEY, DEBUG_RATIO_BLUE_CODE_MACRO_KEY);
+
+ return true;
+}
+
+const std::vector<Property::Map>& GetScriptInfomation()
+{
+ static std::vector<Property::Map> results;
+
+ if(DALI_UNLIKELY(results.empty()))
+ {
+ results.resize(2);
+
+ auto& vertexShaderResult = results[0];
+ auto& fragmentShaderResult = results[1];
+
+ if(!ParseScriptInfomation(vertexShaderResult, fragmentShaderResult))
+ {
+ // Use default script information if parse failed.
+ vertexShaderResult.Clear();
+ fragmentShaderResult.Clear();
+
+ vertexShaderResult.Insert(std::string(DEBUG_APPLY_VARYINGS_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_APPLY_VARYINGS_CODE_MACRO_VALUE));
+
+ fragmentShaderResult.Insert(std::string(MINIMUM_DEBUG_COLOR_RATE_MACRO_KEY), std::string(DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE));
+ fragmentShaderResult.Insert(std::string(MAXIMUM_DEBUG_COLOR_RATE_MACRO_KEY), std::string(DEFAULT_DEBUG_COLOR_RATE_MACRO_VALUE));
+ fragmentShaderResult.Insert(std::string(DEBUG_TRIGGER_RED_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE));
+ fragmentShaderResult.Insert(std::string(DEBUG_TRIGGER_GREEN_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE));
+ fragmentShaderResult.Insert(std::string(DEBUG_TRIGGER_BLUE_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_TRIGGER_CODE_MACRO_VALUE));
+ fragmentShaderResult.Insert(std::string(DEBUG_RATIO_RED_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE));
+ fragmentShaderResult.Insert(std::string(DEBUG_RATIO_GREEN_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE));
+ fragmentShaderResult.Insert(std::string(DEBUG_RATIO_BLUE_CODE_MACRO_KEY), std::string(DEFAULT_DEBUG_RATIO_CODE_MACRO_VALUE));
+ }
+ }
+
+ return results;
+}
+
+void RedefineMacro(std::string& shaderCode, std::string macro, std::string value)
+{
+ std::string definition = "#define " + macro;
+ std::size_t found = shaderCode.find(definition);
+ DALI_ASSERT_ALWAYS(found != std::string::npos && "Macro keyword was not exist in shader code!");
+
+ std::size_t insertionPoint = found + definition.length();
+
+ // Automatically insert line-continuation character into value
+ std::regex re("\n");
+ std::sregex_token_iterator first{value.begin(), value.end(), re, -1}, last;
+ for(auto i = first; i != last; ++i)
+ {
+ std::string line = std::string(" \\\n") + (*i).str();
+ shaderCode.insert(insertionPoint, line);
+ insertionPoint += line.length();
+ }
+}
+
+} // namespace
+
+namespace ImageVisualShaderDebug
+{
+bool DebugImageVisualShaderEnabled()
+{
+ return DebugImageVisualShaderEnvironmentEnabled();
+}
+
+void ApplyImageVisualShaderDebugScriptCode(std::string& vertexShader, std::string& fragmentShader)
+{
+ const auto& resultMaps = GetScriptInfomation();
+
+ for(std::size_t i = 0u; i < resultMaps[0].Count(); ++i)
+ {
+ auto key = resultMaps[0].GetKeyAt(i);
+ const auto& value = resultMaps[0].GetValue(i);
+
+ RedefineMacro(vertexShader, std::move(key.stringKey), value.Get<std::string>());
+ }
+
+ for(std::size_t i = 0u; i < resultMaps[1].Count(); ++i)
+ {
+ auto key = resultMaps[1].GetKeyAt(i);
+ const auto& value = resultMaps[1].GetValue(i);
+
+ RedefineMacro(fragmentShader, std::move(key.stringKey), value.Get<std::string>());
+ }
+}
+} // namespace ImageVisualShaderDebug
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_IMAGE_VISUAL_SHADER_DEBUG_H
+#define DALI_TOOLKIT_IMAGE_VISUAL_SHADER_DEBUG_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace ImageVisualShaderDebug
+{
+/**
+ * @brief Check whether we need to use debug option for image visual.
+ *
+ * @return True if ImageVisualShader relative environment on. False otherwise.
+ */
+bool DebugImageVisualShaderEnabled();
+
+/**
+ * @brief Apply vertex / fragment shader use debug script.
+ *
+ * @param[in, out] vertexShader Vertex shader code to apply debug script.
+ * @param[in, out] fragmentShader Fragment shader code to apply debug script.
+ */
+void ApplyImageVisualShaderDebugScriptCode(std::string& vertexShader, std::string& fragmentShader);
+
+} // namespace ImageVisualShaderDebug
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_VISUAL_SHADER_DEBUG_H
--- /dev/null
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-factory.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/rendering/texture-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-debug.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+
+constexpr int NATIVE_SHADER_TYPE_OFFSET = VisualFactoryCache::ShaderType::NATIVE_IMAGE_SHADER - VisualFactoryCache::ShaderType::IMAGE_SHADER;
+constexpr std::string_view Y_FLIP_MASK_TEXTURE = "uYFlipMaskTexture";
+constexpr float NOT_FLIP_MASK_TEXTURE = 0.0f;
+
+constexpr auto SHADER_TYPE_COUNT = 6u;
+
+constexpr std::string_view VertexPredefines[SHADER_TYPE_COUNT]{
+ "", // VisualFactoryCache::IMAGE_SHADER,
+ "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
+ "", // VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
+ "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
+ "", // VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
+ "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
+};
+constexpr std::string_view FragmentPredefines[SHADER_TYPE_COUNT]{
+ "", // VisualFactoryCache::IMAGE_SHADER,
+ "#define IS_REQUIRED_ROUNDED_CORNER\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
+ "#define IS_REQUIRED_YUV_TO_RGB\n", // VisualFactoryCache::IMAGE_SHADER_YUV_TO_RGB,
+ "#define IS_REQUIRED_ROUNDED_CORNER\n#define IS_REQUIRED_YUV_TO_RGB\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
+ "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n", // VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
+ "#define IS_REQUIRED_ROUNDED_CORNER\n#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n", // VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
+};
+constexpr VisualFactoryCache::ShaderType ShaderTypePredefines[SHADER_TYPE_COUNT]{
+ VisualFactoryCache::ShaderType::IMAGE_SHADER,
+ VisualFactoryCache::ShaderType::IMAGE_SHADER_ROUNDED_CORNER,
+ VisualFactoryCache::ShaderType::IMAGE_SHADER_YUV_TO_RGB,
+ VisualFactoryCache::ShaderType::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
+ VisualFactoryCache::ShaderType::IMAGE_SHADER_YUV_AND_RGB,
+ VisualFactoryCache::ShaderType::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
+};
+} // unnamed namespace
+
+ImageVisualShaderFactory::ImageVisualShaderFactory()
+: mFragmentShaderNeedChange(ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED)
+{
+}
+
+ImageVisualShaderFactory::~ImageVisualShaderFactory()
+{
+}
+
+Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, ImageVisualShaderFeatureBuilder& featureBuilder)
+{
+ Shader shader;
+ VisualFactoryCache::ShaderType shaderType = featureBuilder.GetShaderType();
+
+ if(featureBuilder.NeedToChangeFragmentShader() == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE &&
+ (mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED ||
+ mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE))
+ {
+ DALI_ASSERT_DEBUG((static_cast<int>(shaderType) >= static_cast<int>(VisualFactoryCache::IMAGE_SHADER)) &&
+ (static_cast<int>(shaderType) <= static_cast<int>(VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP)) &&
+ "Do not support native image shader for given feature!!");
+ shaderType = static_cast<VisualFactoryCache::ShaderType>(static_cast<int>(shaderType) + NATIVE_SHADER_TYPE_OFFSET);
+ }
+
+ shader = factoryCache.GetShader(shaderType);
+ if(shader)
+ {
+ return shader;
+ }
+
+ std::string vertexShaderPrefixList;
+ std::string fragmentShaderPrefixList;
+ featureBuilder.GetVertexShaderPrefixList(vertexShaderPrefixList);
+ featureBuilder.GetFragmentShaderPrefixList(fragmentShaderPrefixList);
+
+ if(Dali::Toolkit::Internal::ImageVisualShaderDebug::DebugImageVisualShaderEnabled())
+ {
+ vertexShaderPrefixList += "#define IS_REQUIRED_DEBUG_VISUAL_SHADER\n";
+ fragmentShaderPrefixList += "#define IS_REQUIRED_DEBUG_VISUAL_SHADER\n";
+ }
+
+ 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(Dali::Toolkit::Internal::ImageVisualShaderDebug::DebugImageVisualShaderEnabled())
+ {
+ Dali::Toolkit::Internal::ImageVisualShaderDebug::ApplyImageVisualShaderDebugScriptCode(vertexShader, fragmentShader);
+ }
+
+ if(featureBuilder.NeedToChangeFragmentShader() == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE)
+ {
+ bool modified = DevelTexture::ApplyNativeFragmentShader(featureBuilder.GetTexture(), fragmentShader);
+ if(mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE)
+ {
+ DALI_ASSERT_ALWAYS(modified && "NativeImageTexture need to change fragment shader. But DALI default image shader doesn't changed!");
+ }
+ else if(DALI_UNLIKELY(mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::UNDECIDED))
+ {
+ mFragmentShaderNeedChange = (modified) ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
+
+ if(mFragmentShaderNeedChange == ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE)
+ {
+ shaderType = static_cast<VisualFactoryCache::ShaderType>(static_cast<int>(shaderType) - NATIVE_SHADER_TYPE_OFFSET);
+ shader = factoryCache.GetShader(shaderType);
+ }
+ }
+ }
+
+ if(shader)
+ {
+ return shader;
+ }
+
+ shader = factoryCache.GenerateAndSaveShader(shaderType, vertexShader, fragmentShader);
+ shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
+ if(featureBuilder.IsEnabledAlphaMaskingOnRendering())
+ {
+ shader.RegisterProperty(Y_FLIP_MASK_TEXTURE, NOT_FLIP_MASK_TEXTURE);
+ }
+
+ return shader;
+}
+
+std::string_view ImageVisualShaderFactory::GetVertexShaderSource()
+{
+ // static string variable to cache complete vertex shader
+ static std::string gVertexShader;
+ if(gVertexShader.empty())
+ {
+ gVertexShader = Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data();
+ }
+
+ return gVertexShader;
+}
+
+std::string_view ImageVisualShaderFactory::GetFragmentShaderSource()
+{
+ // static string variable to cache complete fragment shader (no atlas)
+ static std::string gFragmentShaderNoAtlas;
+ if(gFragmentShaderNoAtlas.empty())
+ {
+ gFragmentShaderNoAtlas = Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_FRAG.data();
+ }
+ return gFragmentShaderNoAtlas;
+}
+
+void ImageVisualShaderFactory::GetPreCompiledShader(RawShaderData& shaders)
+{
+ std::vector<std::string_view> vertexPrefix;
+ std::vector<std::string_view> fragmentPrefix;
+ std::vector<std::string_view> shaderName;
+ shaders.shaderCount = 0;
+ int shaderCount = 0;
+ for(uint32_t i = 0; i < SHADER_TYPE_COUNT; ++i)
+ {
+ vertexPrefix.push_back(VertexPredefines[i]);
+ fragmentPrefix.push_back(FragmentPredefines[i]);
+ shaderName.push_back(Scripting::GetLinearEnumerationName<VisualFactoryCache::ShaderType>(ShaderTypePredefines[i], VISUAL_SHADER_TYPE_TABLE, VISUAL_SHADER_TYPE_TABLE_COUNT));
+ shaderCount++;
+ }
+
+ shaders.vertexPrefix = vertexPrefix;
+ shaders.fragmentPrefix = fragmentPrefix;
+ shaders.shaderName = shaderName;
+ shaders.vertexShader = SHADER_IMAGE_VISUAL_SHADER_VERT;
+ shaders.fragmentShader = SHADER_IMAGE_VISUAL_SHADER_FRAG;
+ shaders.shaderCount = shaderCount;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
+#define DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/shader-precompiler.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-feature-builder.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <string_view>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+/**
+ * ImageVisualShaderFactory is an object that provides and shares shaders between image visuals
+ */
+class ImageVisualShaderFactory
+{
+public:
+ /**
+ * @brief Constructor
+ */
+ ImageVisualShaderFactory();
+
+ /**
+ * @brief Destructor
+ */
+ ~ImageVisualShaderFactory();
+
+ /**
+ * @brief Get the standard image rendering shader.
+ * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+ * @param[in] featureBuilder Collection of current image shader's features
+ * @return The standard image rendering shader with features.
+ */
+ Shader GetShader(VisualFactoryCache& factoryCache, ImageVisualShaderFeatureBuilder& featureBuilder);
+
+ /**
+ * @brief Request the default vertex shader source.
+ * @return The default vertex shader source.
+ */
+ std::string_view GetVertexShaderSource();
+
+ /**
+ * @brief Request the default fragment shader source.
+ * @return The default fragment shader source.
+ */
+ std::string_view GetFragmentShaderSource();
+
+ /**
+ * @brief Get the default shader source.
+ * @param[in] shaders shaderList for precompile
+ */
+ void GetPreCompiledShader(RawShaderData& shaders);
+
+protected:
+ /**
+ * Undefined copy constructor.
+ */
+ ImageVisualShaderFactory(const ImageVisualShaderFactory&);
+
+ /**
+ * Undefined assignment operator.
+ */
+ ImageVisualShaderFactory& operator=(const ImageVisualShaderFactory& rhs);
+
+private:
+ /**
+ * @brief Cached information whether native image should change fragment shader.
+ * Default it is ChangeFragmentShader::UNDECIDED.
+ * If we have any chance to check native image source apply fragment shader,
+ * this vaule will be changed one of these : ChangeFragmentShader::DONT_CHANGE or ChangeFragmentShader::NEED_CHANGE
+ *
+ * After result cached, this value will not be changed.
+ *
+ * If value is DONT_CHANGE, ImageVisualShaderFactory::GetShader never call ApplyNativeFragmentShader.
+ * Else, ImageVisualShaderFactory::GetShader will call ApplyNativeFragmentShader if native image source texture come.
+ */
+ ImageVisualShaderFeature::ChangeFragmentShader::Type mFragmentShaderNeedChange : 3;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
--- /dev/null
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-feature-builder.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+// 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,
+ COLOR_CONVERSION = 1 << 3,
+
+ UNIFIED_YUV_AND_RGB = 1 << 2, // Special enum to trick unified YUV and RGB.
+};
+
+static constexpr auto SHADER_TYPE_COUNT = 16u;
+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_YUV_TO_RGB,
+ VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_TO_RGB,
+ VisualFactoryCache::IMAGE_SHADER_BORDERLINE_YUV_TO_RGB,
+ VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_YUV_TO_RGB,
+ VisualFactoryCache::IMAGE_SHADER_YUV_AND_RGB,
+ VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_YUV_AND_RGB,
+ VisualFactoryCache::IMAGE_SHADER_BORDERLINE_YUV_AND_RGB,
+ VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_YUV_AND_RGB};
+} // unnamed namespace
+
+ImageVisualShaderFeatureBuilder::ImageVisualShaderFeatureBuilder()
+: mTextureAtlas(ImageVisualShaderFeature::TextureAtlas::DISABLED),
+ mDefaultTextureWrapMode(ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY),
+ mRoundedCorner(ImageVisualShaderFeature::RoundedCorner::DISABLED),
+ mBorderline(ImageVisualShaderFeature::Borderline::DISABLED),
+ mAlphaMaskingOnRendering(ImageVisualShaderFeature::AlphaMaskingOnRendering::DISABLED),
+ mColorConversion(ImageVisualShaderFeature::ColorConversion::DONT_NEED),
+ mTexture()
+{
+}
+
+ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::EnableTextureAtlas(bool enableTextureAtlas)
+{
+ mTextureAtlas = (enableTextureAtlas ? ImageVisualShaderFeature::TextureAtlas::ENABLED : ImageVisualShaderFeature::TextureAtlas::DISABLED);
+ return *this;
+}
+
+ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::ApplyDefaultTextureWrapMode(bool applyDefaultTextureWrapMode)
+{
+ mDefaultTextureWrapMode = (applyDefaultTextureWrapMode ? ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY : ImageVisualShaderFeature::DefaultTextureWrapMode::DO_NOT_APPLY);
+ return *this;
+}
+
+ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::EnableRoundedCorner(bool enableRoundedCorner)
+{
+ mRoundedCorner = (enableRoundedCorner ? ImageVisualShaderFeature::RoundedCorner::ENABLED : ImageVisualShaderFeature::RoundedCorner::DISABLED);
+ return *this;
+}
+
+ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::EnableBorderline(bool enableBorderline)
+{
+ mBorderline = (enableBorderline ? ImageVisualShaderFeature::Borderline::ENABLED : ImageVisualShaderFeature::Borderline::DISABLED);
+ return *this;
+}
+
+ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::SetTextureForFragmentShaderCheck(const Dali::Texture& texture)
+{
+ mTexture = texture;
+ return *this;
+}
+
+ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::EnableAlphaMaskingOnRendering(bool enableAlphaMaskingOnRendering)
+{
+ mAlphaMaskingOnRendering = (enableAlphaMaskingOnRendering ? ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED : ImageVisualShaderFeature::AlphaMaskingOnRendering::DISABLED);
+ return *this;
+}
+
+ImageVisualShaderFeatureBuilder& ImageVisualShaderFeatureBuilder::EnableYuvToRgb(bool enableYuvToRgb, bool enableUnifiedYuvAndRgb)
+{
+ mColorConversion = (enableUnifiedYuvAndRgb ? ImageVisualShaderFeature::ColorConversion::UNIFIED_YUV_AND_RGB : (enableYuvToRgb ? ImageVisualShaderFeature::ColorConversion::YUV_TO_RGB : ImageVisualShaderFeature::ColorConversion::DONT_NEED));
+ return *this;
+}
+
+VisualFactoryCache::ShaderType ImageVisualShaderFeatureBuilder::GetShaderType()
+{
+ VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::IMAGE_SHADER;
+ if(mTextureAtlas == ImageVisualShaderFeature::TextureAtlas::ENABLED)
+ {
+ if(mDefaultTextureWrapMode == ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY)
+ {
+ shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP;
+ }
+ else
+ {
+ shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP;
+ }
+ }
+ else
+ {
+ uint32_t shaderTypeFlag = static_cast<uint32_t>(ImageVisualRequireFlag::DEFAULT);
+ if(mRoundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
+ {
+ shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::ROUNDED_CORNER);
+ }
+ if(mBorderline == ImageVisualShaderFeature::Borderline::ENABLED)
+ {
+ shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::BORDERLINE);
+ }
+ if(mAlphaMaskingOnRendering == ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED)
+ {
+ shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::ALPHA_MASKING);
+ }
+ else if(mColorConversion == 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);
+ }
+ else if(mColorConversion == ImageVisualShaderFeature::ColorConversion::UNIFIED_YUV_AND_RGB)
+ {
+ shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::COLOR_CONVERSION);
+ shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::UNIFIED_YUV_AND_RGB);
+ }
+ shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
+ }
+
+ return shaderType;
+}
+
+ImageVisualShaderFeature::ChangeFragmentShader::Type ImageVisualShaderFeatureBuilder::NeedToChangeFragmentShader()
+{
+ return (mTexture && DevelTexture::IsNative(mTexture))
+ ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE
+ : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
+}
+
+void ImageVisualShaderFeatureBuilder::GetVertexShaderPrefixList(std::string& vertexShaderPrefixList)
+{
+ if(mTextureAtlas != ImageVisualShaderFeature::TextureAtlas::ENABLED)
+ {
+ if(mRoundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
+ {
+ vertexShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER\n";
+ }
+ if(mBorderline == ImageVisualShaderFeature::Borderline::ENABLED)
+ {
+ vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE\n";
+ }
+ if(mAlphaMaskingOnRendering == ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED)
+ {
+ vertexShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING\n";
+ }
+ }
+}
+
+void ImageVisualShaderFeatureBuilder::GetFragmentShaderPrefixList(std::string& fragmentShaderPrefixList)
+{
+ if(mTextureAtlas == ImageVisualShaderFeature::TextureAtlas::ENABLED)
+ {
+ if(mDefaultTextureWrapMode == ImageVisualShaderFeature::DefaultTextureWrapMode::APPLY)
+ {
+ fragmentShaderPrefixList += "#define ATLAS_DEFAULT_WARP\n";
+ }
+ else
+ {
+ fragmentShaderPrefixList += "#define ATLAS_CUSTOM_WARP\n";
+ }
+ }
+ else
+ {
+ if(mRoundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
+ {
+ fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER\n";
+ }
+ if(mBorderline == ImageVisualShaderFeature::Borderline::ENABLED)
+ {
+ fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE\n";
+ }
+ if(mAlphaMaskingOnRendering == ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED)
+ {
+ fragmentShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING\n";
+ }
+ else if(mColorConversion == ImageVisualShaderFeature::ColorConversion::YUV_TO_RGB)
+ {
+ fragmentShaderPrefixList += "#define IS_REQUIRED_YUV_TO_RGB\n";
+ }
+ else if(mColorConversion == ImageVisualShaderFeature::ColorConversion::UNIFIED_YUV_AND_RGB)
+ {
+ fragmentShaderPrefixList += "#define IS_REQUIRED_UNIFIED_YUV_AND_RGB\n";
+ }
+ }
+}
+
+Dali::Texture ImageVisualShaderFeatureBuilder::GetTexture()
+{
+ return mTexture;
+}
+
+bool ImageVisualShaderFeatureBuilder::IsEnabledAlphaMaskingOnRendering() const
+{
+ return mAlphaMaskingOnRendering == ImageVisualShaderFeature::AlphaMaskingOnRendering::ENABLED;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FEATURE_BUILDER_H
+#define DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FEATURE_BUILDER_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali/devel-api/rendering/texture-devel.h>
+#include <dali/public-api/rendering/texture.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+/**
+ * ImageVisualShaderFeature contains feature lists what image visual shader need to know.
+ */
+namespace ImageVisualShaderFeature
+{
+namespace TextureAtlas
+{
+/**
+ * @brief Whether use texture with atlas, or not
+ */
+enum Type
+{
+ DISABLED = 0, ///< Image visual doesn't use ATLAS
+ ENABLED ///< Image visual uses ATLAS
+};
+} // namespace TextureAtlas
+
+namespace DefaultTextureWrapMode
+{
+/**
+ * @brief Whether apply to texture wraping in default, or not
+ */
+enum Type
+{
+ APPLY = 0, ///< Image visual applies to wraping texture in default
+ DO_NOT_APPLY ///< Image visual doesn't apply to wraping texture in default
+};
+} // namespace DefaultTextureWrapMode
+
+namespace RoundedCorner
+{
+/**
+ * @brief Whether use rounded corner, or not
+ */
+enum Type
+{
+ DISABLED = 0, ///< Image visual doesn't use rounded corner
+ ENABLED ///< Image visual uses rounded corner
+};
+} // namespace RoundedCorner
+
+namespace Borderline
+{
+/**
+ * @brief Whether use borderline, or not
+ */
+enum Type
+{
+ DISABLED = 0, ///< Image visual doesn't use borderline
+ ENABLED ///< Image visual uses borderline
+};
+} // namespace Borderline
+
+namespace ChangeFragmentShader
+{
+/**
+ * @brief Whether native image change the default fragment shader, or not
+ */
+enum Type
+{
+ DONT_CHANGE = 0, ///< Native image doesn't change default fragment shader.
+ NEED_CHANGE, ///< Native image changes default fragment shader. We need another shader cache.
+ UNDECIDED, ///< Undecided.
+};
+} // namespace ChangeFragmentShader
+
+namespace AlphaMaskingOnRendering
+{
+/**
+ * @brief Whether use runtime alpha masking in shader, or not
+ */
+enum Type
+{
+ DISABLED = 0, ///< Image visual doesn't use runtime alpha masking
+ ENABLED ///< Image visual uses runtime alpha masking
+};
+} // 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
+ UNIFIED_YUV_AND_RGB ///< Need to support both yuv conversion case and normal case.
+};
+} // namespace ColorConversion
+
+} // namespace ImageVisualShaderFeature
+
+/**
+ * @brief Collection of current image visual feature. Only use for ImageVisualShaderFactory::GetShader()
+ */
+class ImageVisualShaderFeatureBuilder
+{
+public:
+ ImageVisualShaderFeatureBuilder();
+
+ ImageVisualShaderFeatureBuilder& EnableTextureAtlas(bool enableTextureAtlas);
+
+ ImageVisualShaderFeatureBuilder& ApplyDefaultTextureWrapMode(bool applyDefaultTextureWrapMode);
+
+ ImageVisualShaderFeatureBuilder& EnableRoundedCorner(bool enableRoundedCorner);
+
+ ImageVisualShaderFeatureBuilder& EnableBorderline(bool enableBorderline);
+
+ ImageVisualShaderFeatureBuilder& SetTextureForFragmentShaderCheck(const Dali::Texture& texture);
+
+ ImageVisualShaderFeatureBuilder& EnableAlphaMaskingOnRendering(bool enableAlphaMaskingOnRendering);
+
+ ImageVisualShaderFeatureBuilder& EnableYuvToRgb(bool enableYuvToRgb, bool enableUnifiedYuvAndRgb = false);
+
+ VisualFactoryCache::ShaderType GetShaderType();
+
+ ImageVisualShaderFeature::ChangeFragmentShader::Type NeedToChangeFragmentShader();
+
+ void GetVertexShaderPrefixList(std::string& vertexShaderPrefixList);
+ void GetFragmentShaderPrefixList(std::string& fragmentShaderPrefixList);
+
+ Dali::Texture GetTexture();
+
+ bool IsEnabledAlphaMaskingOnRendering() const;
+
+private:
+ ImageVisualShaderFeature::TextureAtlas::Type mTextureAtlas : 2; ///< Whether use texture with atlas, or not. default as TextureAtlas::DISABLED
+ ImageVisualShaderFeature::DefaultTextureWrapMode::Type mDefaultTextureWrapMode : 2; ///< Whether apply to texture wraping in default, or not. default as DefaultTextureWrapMode::APPLY
+ ImageVisualShaderFeature::RoundedCorner::Type mRoundedCorner : 2; ///< Whether use rounded corner, or not. default as RoundedCorner::DISABLED
+ ImageVisualShaderFeature::Borderline::Type mBorderline : 2; ///< Whether use borderline, or not. default as Borderline::DISABLED
+ ImageVisualShaderFeature::AlphaMaskingOnRendering::Type mAlphaMaskingOnRendering : 2; ///< Whether use runtime alpha masking, or not. default as AlphaMaskingOnRendering::DISABLED
+ ImageVisualShaderFeature::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
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
// INTERNAL HEADERS
#include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
#include <dali-toolkit/internal/texture-manager/texture-manager-impl.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/image/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-feature-builder.h>
#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
#include <dali-toolkit/internal/visuals/visual-base-impl.h>
#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+++ /dev/null
-/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/visuals/npatch-data.h>
-
-// INTERNAL HEADERS
-#include <dali-toolkit/internal/visuals/rendering-addon.h>
-
-// EXTERNAL HEADERS
-#include <dali/integration-api/debug.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-NPatchData::NPatchData()
-: mId(INVALID_NPATCH_DATA_ID),
- mUrl(),
- mTextureSet(),
- mHash(0),
- mCroppedWidth(0),
- mCroppedHeight(0),
- mBorder(0, 0, 0, 0),
- mLoadingState(LoadingState::NOT_STARTED),
- mRenderingMap{nullptr},
- mPreMultiplyOnLoad(false),
- mObserverNotifying(false)
-{
-}
-
-NPatchData::~NPatchData()
-{
- // If there is an opacity map, it has to be destroyed using addon call
- if(mRenderingMap)
- {
- RenderingAddOn::Get().DestroyNPatch(mRenderingMap);
- }
- mObserverList.Clear();
- mQueuedObservers.Clear();
-}
-
-void NPatchData::SetId(const NPatchDataId id)
-{
- mId = id;
-}
-
-NPatchData::NPatchDataId NPatchData::GetId() const
-{
- return mId;
-}
-
-void NPatchData::AddObserver(TextureUploadObserver* textureObserver)
-{
- if(textureObserver)
- {
- if(mObserverNotifying)
- {
- // Do not add it into observer list during observer notifying.
- mQueuedObservers.PushBack(textureObserver);
- }
- else
- {
- mObserverList.PushBack(textureObserver);
- }
- textureObserver->DestructionSignal().Connect(this, &NPatchData::ObserverDestroyed);
- }
-}
-
-void NPatchData::RemoveObserver(TextureUploadObserver* textureObserver)
-{
- if(textureObserver)
- {
- for(uint32_t index = 0; index < mObserverList.Count(); ++index)
- {
- if(textureObserver == mObserverList[index])
- {
- textureObserver->DestructionSignal().Disconnect(this, &NPatchData::ObserverDestroyed);
- mObserverList.Erase(mObserverList.begin() + index);
- break;
- }
- }
- }
-}
-
-uint32_t NPatchData::GetObserverCount() const
-{
- return mObserverList.Count();
-}
-
-void NPatchData::SetUrl(const VisualUrl& url)
-{
- mUrl = url;
-}
-
-VisualUrl NPatchData::GetUrl() const
-{
- return mUrl;
-}
-
-void NPatchData::SetTextures(const TextureSet textureSet)
-{
- mTextureSet = textureSet;
-}
-
-TextureSet NPatchData::GetTextures() const
-{
- return mTextureSet;
-}
-
-void NPatchData::SetStretchPixelsX(const NPatchUtility::StretchRanges stretchPixelsX)
-{
- mStretchPixelsX = stretchPixelsX;
-}
-
-void NPatchData::SetStretchPixelsY(const NPatchUtility::StretchRanges stretchPixelsY)
-{
- mStretchPixelsY = stretchPixelsY;
-}
-
-NPatchUtility::StretchRanges NPatchData::GetStretchPixelsX() const
-{
- return mStretchPixelsX;
-}
-
-NPatchUtility::StretchRanges NPatchData::GetStretchPixelsY() const
-{
- return mStretchPixelsY;
-}
-
-void NPatchData::SetHash(std::size_t hash)
-{
- mHash = hash;
-}
-
-std::size_t NPatchData::GetHash() const
-{
- return mHash;
-}
-
-void NPatchData::SetCroppedWidth(uint32_t croppedWidth)
-{
- mCroppedWidth = croppedWidth;
-}
-
-void NPatchData::SetCroppedHeight(uint32_t croppedHeight)
-{
- mCroppedHeight = croppedHeight;
-}
-
-uint32_t NPatchData::GetCroppedWidth() const
-{
- return mCroppedWidth;
-}
-
-uint32_t NPatchData::GetCroppedHeight() const
-{
- return mCroppedHeight;
-}
-
-void NPatchData::SetBorder(const Rect<int> border)
-{
- mBorder = border;
-}
-
-Rect<int> NPatchData::GetBorder() const
-{
- return mBorder;
-}
-
-void NPatchData::SetPreMultiplyOnLoad(bool preMultiplyOnLoad)
-{
- mPreMultiplyOnLoad = preMultiplyOnLoad;
-}
-
-bool NPatchData::IsPreMultiplied() const
-{
- return mPreMultiplyOnLoad;
-}
-
-void NPatchData::SetLoadingState(const LoadingState loadingState)
-{
- mLoadingState = loadingState;
-}
-
-NPatchData::LoadingState NPatchData::GetLoadingState() const
-{
- return mLoadingState;
-}
-
-void* NPatchData::GetRenderingMap() const
-{
- return mRenderingMap;
-}
-
-void NPatchData::SetLoadedNPatchData(Devel::PixelBuffer& pixelBuffer, bool preMultiplied)
-{
- if(mBorder == Rect<int>(0, 0, 0, 0))
- {
- NPatchUtility::ParseBorders(pixelBuffer, mStretchPixelsX, mStretchPixelsY);
-
- // Crop the image
- pixelBuffer.Crop(1, 1, pixelBuffer.GetWidth() - 2, pixelBuffer.GetHeight() - 2);
- }
- else
- {
- mStretchPixelsX.PushBack(Uint16Pair(mBorder.left, ((pixelBuffer.GetWidth() >= static_cast<unsigned int>(mBorder.right)) ? pixelBuffer.GetWidth() - mBorder.right : 0)));
- mStretchPixelsY.PushBack(Uint16Pair(mBorder.top, ((pixelBuffer.GetHeight() >= static_cast<unsigned int>(mBorder.bottom)) ? pixelBuffer.GetHeight() - mBorder.bottom : 0)));
- }
-
- mCroppedWidth = pixelBuffer.GetWidth();
- mCroppedHeight = pixelBuffer.GetHeight();
-
- // Create opacity map
- mRenderingMap = RenderingAddOn::Get().IsValid() ? RenderingAddOn::Get().BuildNPatch(pixelBuffer, this) : nullptr;
-
- PixelData pixels = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
-
- Texture texture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight());
- texture.Upload(pixels);
-
- mTextureSet = TextureSet::New();
- mTextureSet.SetTexture(0u, texture);
-
- mPreMultiplyOnLoad = preMultiplied;
-
- mLoadingState = LoadingState::LOAD_COMPLETE;
-}
-
-void NPatchData::NotifyObserver(TextureUploadObserver* observer, const bool& loadSuccess)
-{
- observer->LoadComplete(
- loadSuccess,
- TextureUploadObserver::TextureInformation(
- TextureUploadObserver::ReturnType::TEXTURE,
- static_cast<TextureManager::TextureId>(mId), ///< Note : until end of NPatchLoader::Load, npatch-visual don't know the id of data.
- mTextureSet,
- mUrl.GetUrl(),
- mPreMultiplyOnLoad));
-}
-
-void NPatchData::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
-{
- NPatchDataPtr self = this; // Keep reference until this API finished
-
- if(loadSuccess)
- {
- if(mLoadingState != LoadingState::LOAD_COMPLETE)
- {
- // If mLoadingState is LOAD_FAILED, just re-set (It can be happened when sync loading is failed, but async loading is succeeded).
- SetLoadedNPatchData(textureInformation.pixelBuffer, textureInformation.preMultiplied);
- }
- }
- else
- {
- if(mLoadingState == LoadingState::LOADING)
- {
- mLoadingState = LoadingState::LOAD_FAILED;
- }
- // If mLoadingState is already LOAD_COMPLETE, we can use uploaded texture (It can be happened when sync loading is succeeded, but async loading is failed).
- else if(mLoadingState == LoadingState::LOAD_COMPLETE)
- {
- loadSuccess = true;
- }
- }
-
- mObserverNotifying = true;
-
- // Reverse observer list that we can pop_back the observer.
- std::reverse(mObserverList.Begin(), mObserverList.End());
-
- while(mObserverList.Count() > 0u)
- {
- TextureUploadObserver* observer = *(mObserverList.End() - 1u);
- mObserverList.Erase(mObserverList.End() - 1u);
-
- observer->DestructionSignal().Disconnect(this, &NPatchData::ObserverDestroyed);
-
- NotifyObserver(observer, loadSuccess);
- }
-
- mObserverNotifying = false;
-
- // Swap observer list what we queued during notify observer.
- // If mQueuedObserver is not empty, it mean mLoadingState was LOAD_FAILED, and we try to re-load for this data.
- // (If mLoadingState was LOAD_COMPLETE, NotifyObserver will be called directly. @todo : Should we fix this logic, matched with texture manager?)
- // So LoadComplete will be called.
- mObserverList.Swap(mQueuedObservers);
-}
-
-void NPatchData::ObserverDestroyed(TextureUploadObserver* observer)
-{
- for(auto iter = mObserverList.Begin(); iter != mObserverList.End();)
- {
- if(observer == (*iter))
- {
- iter = mObserverList.Erase(iter);
- }
- else
- {
- ++iter;
- }
- }
- if(mObserverNotifying)
- {
- for(auto iter = mQueuedObservers.Begin(); iter != mQueuedObservers.End();)
- {
- if(observer == (*iter))
- {
- iter = mQueuedObservers.Erase(iter);
- }
- else
- {
- ++iter;
- }
- }
- }
-}
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_NPATCH_DATA_H
-#define DALI_TOOLKIT_NPATCH_DATA_H
-
-/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
-#include <dali/public-api/object/ref-object.h>
-#include <dali/public-api/rendering/texture-set.h>
-#include <string>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/utility/npatch-utilities.h>
-#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
-#include <dali-toolkit/internal/visuals/visual-url.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-class NPatchData;
-typedef IntrusivePtr<NPatchData> NPatchDataPtr;
-
-class NPatchData : public ConnectionTracker, public Dali::Toolkit::TextureUploadObserver, public Dali::RefObject
-{
-public:
- typedef int32_t NPatchDataId; ///< The NPatchDataId type. This is used as a handle to refer to a particular Npatch Data.
- static const NPatchDataId INVALID_NPATCH_DATA_ID = -1; ///< Used to represent a null TextureId or error
-
- /**
- * @brief Loading State of the NPatch image.
- */
- enum class LoadingState
- {
- NOT_STARTED = 0, ///< NPatch loading is not started yet.
- LOADING, ///< NPatch is on loading.
- LOAD_COMPLETE, ///< NPatch loading is completed successfully.
- LOAD_FAILED ///< NPatch loading is failed.
- };
-
-public:
- /**
- * Constructor
- */
- NPatchData();
-
- /**
- * Destructor, non-virtual as not a base class
- */
- ~NPatchData();
-
-public:
- /**
- * @brief Set cache data id.
- *
- * @param [in] id cache data id
- */
- void SetId(const NPatchDataId id);
-
- /**
- * @brief Retrieve cache data id
- *
- * @return cache data id.
- */
- NPatchDataId GetId() const;
-
- /**
- * @brief Add TextureUploadObserver that uses the image of this cache data.
- *
- * @param [in] textureObserver the TextureUploadObserver that uses the image of this cache data.
- */
- void AddObserver(TextureUploadObserver* textureObserver);
-
- /**
- * @brief Remove TextureUploadObserver.
- *
- * @param [in] textureObserver the TextureUploadObserver that will be removed in this cache data.
- */
- void RemoveObserver(TextureUploadObserver* textureObserver);
-
- /**
- * @brief Retrieve the number of observer.
- *
- * @return Return the number of observer.
- */
- uint32_t GetObserverCount() const;
-
- /**
- * @brief Set NPatch image url.
- *
- * @param [in] url NPatch image url
- */
- void SetUrl(const VisualUrl& url);
-
- /**
- * @brief Retrieve the image url.
- *
- * @return Return the image url.
- */
- VisualUrl GetUrl() const;
-
- /**
- * @brief Set texture set on the cache data
- *
- * @param [in] textureSet loaded texture set
- */
- void SetTextures(const TextureSet textureSet);
-
- /**
- * @brief Retrieve loaded texture set.
- *
- * @return Return loaded texture set.
- */
- TextureSet GetTextures() const;
-
- /**
- * @brief Set X directional stretchPixels
- *
- * @param [in] stretchPixelsX stretchPixels for X direction
- */
- void SetStretchPixelsX(const NPatchUtility::StretchRanges stretchPixelsX);
-
- /**
- * @brief Set Y directional stretchPixels
- *
- * @param [in] stretchPixelsY stretchPixels for Y direction
- */
- void SetStretchPixelsY(const NPatchUtility::StretchRanges stretchPixelsY);
-
- /**
- * @brief Retrieve stretchPixels for X direction.
- *
- * @return Return stretchPixels for X direction.
- */
- NPatchUtility::StretchRanges GetStretchPixelsX() const;
-
- /**
- * @brief Retrieve stretchPixels for Y direction.
- *
- * @return Return stretchPixels for Y direction.
- */
- NPatchUtility::StretchRanges GetStretchPixelsY() const;
-
- /**
- * @brief Set cache data hash.
- *
- * @param [in] hash cache hash
- */
- void SetHash(std::size_t hash);
-
- /**
- * @brief Retrieve hash value of the cache.
- *
- * @return Return hash value of the cache.
- */
- std::size_t GetHash() const;
-
- /**
- * @brief Set croppedWidth of NPatch
- *
- * @param [in] croppedWidth croppedWidth of NPatch
- */
- void SetCroppedWidth(uint32_t croppedWidth);
-
- /**
- * @brief Set croppedHeight of NPatch
- *
- * @param [in] croppedHeight croppedHeight of NPatch
- */
- void SetCroppedHeight(uint32_t croppedHeight);
-
- /**
- * @brief Retrieve croppedWidth of NPatch.
- *
- * @return Return croppedWidth of NPatch.
- */
- uint32_t GetCroppedWidth() const;
-
- /**
- * @brief Retrieve croppedHeight of NPatch.
- *
- * @return Return croppedHeight of NPatch.
- */
- uint32_t GetCroppedHeight() const;
-
- /**
- * @brief Set border of NPatch.
- *
- * @param [in] border border of NPatch
- */
- void SetBorder(const Rect<int> border);
-
- /**
- * @brief Retrieve border of NPatch.
- *
- * @return Return border of NPatch.
- */
- Rect<int> GetBorder() const;
-
- /**
- * @brief Set whether the loaded image is premultiplied or not
- *
- * @param [in] preMultiplyOnLoad whether the loaded image is premultiplied or not
- */
- void SetPreMultiplyOnLoad(bool preMultiplyOnLoad);
-
- /**
- * @brief Retrieve whether the loaded image is premultiplied or not.
- *
- * @return Return true if the image is premultiplied alpha.
- */
- bool IsPreMultiplied() const;
-
- /**
- * @brief Set current loading state.
- *
- * @param [in] loadingState current loading state
- */
- void SetLoadingState(const LoadingState loadingState);
-
- /**
- * @brief Retrieve current loading state.
- *
- * @return Return current loading state.
- */
- LoadingState GetLoadingState() const;
-
- /**
- * @brief Retrieve NPatch rendering data.
- *
- * @return Return NPatch rendering data.
- */
- void* GetRenderingMap() const;
-
- /**
- * @brief Set loaded pixel buffer for the cache data.
- *
- * @param [in] pixelBuffer loaded pixel buffer.
- * @param [in] preMultiplied whether the loaded image is premultiplied or not
- */
- void SetLoadedNPatchData(Devel::PixelBuffer& pixelBuffer, bool preMultiplied);
-
- /**
- * @brief Send LoadComplete notify with current setuped NPatchData
- *
- * @param [in] observer observer who will be got LoadComplete notify
- * @param [in] loadSuccess whether the image load success or not.
- */
- void NotifyObserver(TextureUploadObserver* observer, const bool& loadSuccess);
-
-private:
- /**
- * @copydoc TextureUploadObserver::LoadComplete
- *
- * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
- * This callback is the place to add the renderer as it would be called once the loading is finished.
- */
- void LoadComplete(bool loadSuccess, TextureInformation textureInformation) override;
-
- /**
- * This is called by the TextureUploadObserver when an observer is destroyed.
- * We use the callback to know when to remove an observer from our notify list.
- * @param[in] observer The observer that generated the callback
- */
- void ObserverDestroyed(TextureUploadObserver* observer);
-
-private:
- using ObserverListType = Dali::Vector<TextureUploadObserver*>;
-
- NPatchDataId mId;
- ObserverListType mObserverList; ///< Container used to store all observer clients of this Texture
- ObserverListType mQueuedObservers; ///< Container observers when user try to add during notify observers
-
- VisualUrl mUrl; ///< Url of the N-Patch
- TextureSet mTextureSet; ///< Texture containing the cropped image
- NPatchUtility::StretchRanges mStretchPixelsX; ///< X stretch pixels
- NPatchUtility::StretchRanges mStretchPixelsY; ///< Y stretch pixels
- std::size_t mHash; ///< Hash code for the Url
- uint32_t mCroppedWidth; ///< Width of the cropped middle part of N-patch
- uint32_t mCroppedHeight; ///< Height of the cropped middle part of N-patch
- Rect<int> mBorder; ///< The size of the border
- LoadingState mLoadingState; ///< True if the data loading is completed
- void* mRenderingMap; ///< NPatch rendering data
-
- bool mPreMultiplyOnLoad : 1; ///< Whether to multiply alpha into color channels on load
- bool mObserverNotifying : 1; ///< Whether this NPatchData notifying observers or not.
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_NPATCH_DATA_H
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/visuals/npatch-loader.h>
-
-// INTERNAL HEADERS
-#include <dali-toolkit/internal/visuals/rendering-addon.h>
-
-// EXTERNAL HEADERS
-#include <dali/devel-api/common/hash.h>
-#include <dali/integration-api/adaptor-framework/adaptor.h>
-#include <dali/integration-api/debug.h>
-#include <dali/integration-api/trace.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-namespace
-{
-constexpr auto INVALID_CACHE_INDEX = int32_t{-1}; ///< Invalid Cache index
-constexpr auto UNINITIALIZED_ID = int32_t{0}; ///< uninitialised id, use to initialize ids
-
-DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false);
-} // Anonymous namespace
-
-NPatchLoader::NPatchLoader()
-: mCurrentNPatchDataId(0),
- mRemoveProcessorRegistered(false)
-{
-}
-
-NPatchLoader::~NPatchLoader()
-{
- if(mRemoveProcessorRegistered && Adaptor::IsAvailable())
- {
- Adaptor::Get().UnregisterProcessorOnce(*this, true);
- mRemoveProcessorRegistered = false;
- }
-}
-
-NPatchData::NPatchDataId NPatchLoader::GenerateUniqueNPatchDataId()
-{
- // Skip invalid id generation.
- if(DALI_UNLIKELY(mCurrentNPatchDataId == NPatchData::INVALID_NPATCH_DATA_ID))
- {
- mCurrentNPatchDataId = 0;
- }
- return mCurrentNPatchDataId++;
-}
-
-NPatchData::NPatchDataId NPatchLoader::Load(TextureManager& textureManager, TextureUploadObserver* textureObserver, const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad, bool synchronousLoading)
-{
- NPatchDataPtr data = GetNPatchData(url, border, preMultiplyOnLoad);
-
- DALI_ASSERT_ALWAYS(data.Get() && "NPatchData creation failed!");
-
- if(data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
- {
- if(!synchronousLoading)
- {
- // NotifyObserver already done, so
- // data will not iterate observer list.
- // We need to call LoadComplete directly.
- data->NotifyObserver(textureObserver, true);
- }
- }
- else // if NOT_STARTED or LOADING or LOAD_FAILED, try to reload.
- {
- if(!synchronousLoading)
- {
- data->AddObserver(textureObserver);
- // If still LOADING and async, don't need to request reload. Fast return.
- if(data->GetLoadingState() == NPatchData::LoadingState::LOADING)
- {
- return data->GetId();
- }
- }
-
- data->SetLoadingState(NPatchData::LoadingState::LOADING);
-
- auto preMultiplyOnLoading = preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
- : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
-
- Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer(url, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, data.Get(), true, preMultiplyOnLoading);
-
- if(pixelBuffer)
- {
- preMultiplyOnLoad = (preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) ? true : false;
- data->SetLoadedNPatchData(pixelBuffer, preMultiplyOnLoad);
- }
- else if(synchronousLoading)
- {
- data->SetLoadingState(NPatchData::LoadingState::LOAD_FAILED);
- }
- }
- return data->GetId();
-}
-
-int32_t NPatchLoader::GetCacheIndexFromId(const NPatchData::NPatchDataId id)
-{
- const unsigned int size = mCache.size();
-
- for(unsigned int i = 0; i < size; ++i)
- {
- if(mCache[i].mData->GetId() == id)
- {
- return i;
- }
- }
-
- return INVALID_CACHE_INDEX;
-}
-
-bool NPatchLoader::GetNPatchData(const NPatchData::NPatchDataId id, NPatchDataPtr& data)
-{
- int32_t cacheIndex = GetCacheIndexFromId(id);
- if(cacheIndex != INVALID_CACHE_INDEX)
- {
- data = mCache[cacheIndex].mData;
- return true;
- }
- data = nullptr;
- return false;
-}
-
-void NPatchLoader::RequestRemove(NPatchData::NPatchDataId id, TextureUploadObserver* textureObserver)
-{
- // Remove observer first
- if(textureObserver)
- {
- int32_t cacheIndex = GetCacheIndexFromId(id);
- if(cacheIndex != INVALID_CACHE_INDEX)
- {
- NPatchInfo& info(mCache[cacheIndex]);
-
- info.mData->RemoveObserver(textureObserver);
- }
- }
-
- mRemoveQueue.push_back({id, nullptr});
-
- if(!mRemoveProcessorRegistered && Adaptor::IsAvailable())
- {
- mRemoveProcessorRegistered = true;
- Adaptor::Get().RegisterProcessorOnce(*this, true);
- }
-}
-
-void NPatchLoader::Remove(NPatchData::NPatchDataId id, TextureUploadObserver* textureObserver)
-{
- int32_t cacheIndex = GetCacheIndexFromId(id);
- if(cacheIndex == INVALID_CACHE_INDEX)
- {
- return;
- }
-
- NPatchInfo& info(mCache[cacheIndex]);
-
- info.mData->RemoveObserver(textureObserver);
-
- if(--info.mReferenceCount <= 0)
- {
- mCache.erase(mCache.begin() + cacheIndex);
- }
-}
-
-void NPatchLoader::Process(bool postProcessor)
-{
- DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_NPATCH_LOADER_PROCESS_REMOVE_QUEUE", [&](std::ostringstream& oss) {
- oss << "[" << mRemoveQueue.size() << "]";
- });
-
- mRemoveProcessorRegistered = false;
-
- for(auto& iter : mRemoveQueue)
- {
- Remove(iter.first, iter.second);
- }
-
- mRemoveQueue.clear();
-
- DALI_TRACE_END(gTraceFilter, "DALI_NPATCH_LOADER_PROCESS_REMOVE_QUEUE");
-}
-
-NPatchDataPtr NPatchLoader::GetNPatchData(const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad)
-{
- std::size_t hash = CalculateHash(url.GetUrl());
- std::vector<NPatchInfo>::size_type index = UNINITIALIZED_ID;
- const std::vector<NPatchInfo>::size_type count = mCache.size();
-
- NPatchInfo* infoPtr = nullptr;
-
- for(; index < count; ++index)
- {
- if(mCache[index].mData->GetHash() == hash)
- {
- // hash match, check url as well in case of hash collision
- if(mCache[index].mData->GetUrl().GetUrl() == url.GetUrl())
- {
- // Use cached data. Need to fast-out return.
- if(mCache[index].mData->GetBorder() == border)
- {
- mCache[index].mReferenceCount++;
- return mCache[index].mData;
- }
- else
- {
- if(mCache[index].mData->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
- {
- // If we only found LOAD_FAILED case, replace current data. We can reuse texture
- if(infoPtr == nullptr || infoPtr->mData->GetLoadingState() != NPatchData::LoadingState::LOAD_COMPLETE)
- {
- infoPtr = &mCache[index];
- }
- }
- // Still loading pixel buffer. We cannot reuse cached texture yet. Skip checking
- else if(mCache[index].mData->GetLoadingState() == NPatchData::LoadingState::LOADING)
- {
- continue;
- }
- // if LOAD_FAILED, reuse this cached NPatchData, and try to load again.
- else
- {
- if(infoPtr == nullptr)
- {
- infoPtr = &mCache[index];
- }
- }
- }
- }
- }
- }
-
- // If this is new image loading, make new cache data
- if(infoPtr == nullptr)
- {
- NPatchInfo info(new NPatchData());
- info.mData->SetId(GenerateUniqueNPatchDataId());
- info.mData->SetHash(hash);
- info.mData->SetUrl(url);
- info.mData->SetBorder(border);
- info.mData->SetPreMultiplyOnLoad(preMultiplyOnLoad);
-
- mCache.emplace_back(std::move(info));
- infoPtr = &mCache.back();
- }
- // Else if LOAD_COMPLETE, Same url but border is different - use the existing texture
- else if(infoPtr->mData->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
- {
- NPatchInfo info(new NPatchData());
-
- info.mData->SetId(GenerateUniqueNPatchDataId());
- info.mData->SetHash(hash);
- info.mData->SetUrl(url);
- info.mData->SetCroppedWidth(infoPtr->mData->GetCroppedWidth());
- info.mData->SetCroppedHeight(infoPtr->mData->GetCroppedHeight());
-
- info.mData->SetTextures(infoPtr->mData->GetTextures());
-
- NPatchUtility::StretchRanges stretchRangesX;
- stretchRangesX.PushBack(Uint16Pair(border.left, ((info.mData->GetCroppedWidth() >= static_cast<unsigned int>(border.right)) ? info.mData->GetCroppedHeight() - border.right : 0)));
-
- NPatchUtility::StretchRanges stretchRangesY;
- stretchRangesY.PushBack(Uint16Pair(border.top, ((info.mData->GetCroppedWidth() >= static_cast<unsigned int>(border.bottom)) ? info.mData->GetCroppedHeight() - border.bottom : 0)));
-
- info.mData->SetStretchPixelsX(stretchRangesX);
- info.mData->SetStretchPixelsY(stretchRangesY);
- info.mData->SetBorder(border);
-
- info.mData->SetPreMultiplyOnLoad(infoPtr->mData->IsPreMultiplied());
-
- info.mData->SetLoadingState(NPatchData::LoadingState::LOAD_COMPLETE);
-
- mCache.emplace_back(std::move(info));
- infoPtr = &mCache.back();
- }
- // Else, LOAD_FAILED. just increase reference so we can reuse it.
- else
- {
- infoPtr->mReferenceCount++;
- }
-
- DALI_ASSERT_ALWAYS(infoPtr && "NPatchInfo creation failed!");
-
- return infoPtr->mData;
-}
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_NPATCH_LOADER_H
-#define DALI_TOOLKIT_NPATCH_LOADER_H
-
-/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
-#include <dali/integration-api/processor-interface.h>
-#include <dali/public-api/rendering/texture-set.h>
-#include <string>
-#include <utility> // for std::pair
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/utility/npatch-utilities.h>
-#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
-#include <dali-toolkit/internal/visuals/npatch-data.h>
-#include <dali-toolkit/internal/visuals/visual-url.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-/**
- * The manager for loading Npatch textures.
- * It caches them internally for better performance; i.e. to avoid loading and
- * parsing the files over and over.
- *
- * Cache is not cleaned during app lifecycle as N patches take considerably
- * small space and there's not usually a lot of them. Usually N patches are specified in
- * toolkit default style and there is 1-2 per control that are shared across the whole application.
- */
-class NPatchLoader : public Integration::Processor
-{
-public:
- /**
- * Constructor
- */
- NPatchLoader();
-
- /**
- * Destructor, non-virtual as not a base class
- */
- ~NPatchLoader();
-
- /**
- * @brief Retrieve a texture matching the n-patch url.
- *
- * @param [in] textureManager that will be used to loading image
- * @param [in] textureObserver The NPatchVisual that requested loading.
- * @param [in] url to retrieve
- * @param [in] border The border size of the image
- * @param [in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
- * image has no alpha channel
- * @param [in] synchronousLoading True if the image will be loaded in synchronous time.
- * @return id of the texture.
- */
- NPatchData::NPatchDataId Load(TextureManager& textureManager, TextureUploadObserver* textureObserver, const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad, bool synchronousLoading);
-
- /**
- * @brief Retrieve N patch data matching to an id
- * @param [in] id of data
- * @param [out] data const pointer to the NPatchData
- * @return true if data matching to id was really found
- */
- bool GetNPatchData(const NPatchData::NPatchDataId id, NPatchDataPtr& data);
-
- /**
- * @brief Request remove a texture matching id.
- * Erase the observer from the observer list of cache if we need.
- *
- * @param [in] id cache data id
- * @param [in] textureObserver The NPatchVisual that requested loading.
- */
- void RequestRemove(NPatchData::NPatchDataId id, TextureUploadObserver* textureObserver);
-
-protected: // Implementation of Processor
- /**
- * @copydoc Dali::Integration::Processor::Process()
- */
- void Process(bool postProcessor) override;
-
- /**
- * @copydoc Dali::Integration::Processor::GetProcessorName()
- */
- std::string_view GetProcessorName() const override
- {
- return "NPatchLoader";
- }
-
-private:
- NPatchData::NPatchDataId GenerateUniqueNPatchDataId();
-
- int32_t GetCacheIndexFromId(const NPatchData::NPatchDataId id);
-
- /**
- * @brief Remove a texture matching id.
- * Erase the observer from the observer list of cache if we need.
- * This API decrease cached NPatchInfo reference.
- * If the NPatchInfo reference become 0, the textureSet will be reset.
- *
- * @param [in] id cache data id
- * @param [in] textureObserver The NPatchVisual that requested loading.
- */
- void Remove(NPatchData::NPatchDataId id, TextureUploadObserver* textureObserver);
-
-private:
- /**
- * @brief Information of NPatchData
- * It also hold ownership of NPatchData memory.
- */
- struct NPatchInfo
- {
- NPatchInfo(NPatchDataPtr data)
- : mData(data),
- mReferenceCount(1u)
- {
- }
- ~NPatchInfo()
- {
- }
- NPatchInfo(NPatchInfo&& info) noexcept // move constructor
- {
- mData = std::move(info.mData);
- mReferenceCount = info.mReferenceCount;
- info.mReferenceCount = 0u;
- }
- NPatchInfo& operator=(NPatchInfo&& info) noexcept // move operator
- {
- mData = std::move(info.mData);
- mReferenceCount = info.mReferenceCount;
- info.mReferenceCount = 0u;
- return *this;
- }
-
- NPatchInfo() = delete; // Do not use default constructor
- NPatchInfo(const NPatchInfo& info) = delete; // Do not use copy constructor
- NPatchInfo& operator=(const NPatchInfo& info) = delete; // Do not use copy assign
-
- NPatchDataPtr mData;
- std::int16_t mReferenceCount; ///< The number of N-patch visuals that use this data.
- };
-
- /**
- * @brief Get cached NPatchData by inputed url and border. If there is no cached data, create new one.
- * @note This API increase cached NPatchInfo reference.
- *
- * @param [in] url to retrieve
- * @param [in] border The border size of the image
- * @param [in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
- * image has no alpha channel
- * @return NPatchData pointer that Load function will used.
- */
- NPatchDataPtr GetNPatchData(const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad);
-
-protected:
- /**
- * Undefined copy constructor.
- */
- NPatchLoader(const NPatchLoader&);
-
- /**
- * Undefined assignment operator.
- */
- NPatchLoader& operator=(const NPatchLoader& rhs);
-
-private:
- NPatchData::NPatchDataId mCurrentNPatchDataId;
- std::vector<NPatchInfo> mCache;
-
- std::vector<std::pair<NPatchData::NPatchDataId, TextureUploadObserver*>> mRemoveQueue; ///< Queue of textures to remove at PostProcess. It will be cleared after PostProcess.
-
- bool mRemoveProcessorRegistered : 1; ///< Flag if remove processor registered or not.
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_NPATCH_LOADER_H
--- /dev/null
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/visuals/npatch/npatch-data.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/rendering-addon.h>
+
+// EXTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+NPatchData::NPatchData()
+: mId(INVALID_NPATCH_DATA_ID),
+ mUrl(),
+ mTextureSet(),
+ mHash(0),
+ mCroppedWidth(0),
+ mCroppedHeight(0),
+ mBorder(0, 0, 0, 0),
+ mLoadingState(LoadingState::NOT_STARTED),
+ mRenderingMap{nullptr},
+ mPreMultiplyOnLoad(false),
+ mObserverNotifying(false)
+{
+}
+
+NPatchData::~NPatchData()
+{
+ // If there is an opacity map, it has to be destroyed using addon call
+ if(mRenderingMap)
+ {
+ RenderingAddOn::Get().DestroyNPatch(mRenderingMap);
+ }
+ mObserverList.Clear();
+ mQueuedObservers.Clear();
+}
+
+void NPatchData::SetId(const NPatchDataId id)
+{
+ mId = id;
+}
+
+NPatchData::NPatchDataId NPatchData::GetId() const
+{
+ return mId;
+}
+
+void NPatchData::AddObserver(TextureUploadObserver* textureObserver)
+{
+ if(textureObserver)
+ {
+ if(mObserverNotifying)
+ {
+ // Do not add it into observer list during observer notifying.
+ mQueuedObservers.PushBack(textureObserver);
+ }
+ else
+ {
+ mObserverList.PushBack(textureObserver);
+ }
+ textureObserver->DestructionSignal().Connect(this, &NPatchData::ObserverDestroyed);
+ }
+}
+
+void NPatchData::RemoveObserver(TextureUploadObserver* textureObserver)
+{
+ if(textureObserver)
+ {
+ for(uint32_t index = 0; index < mObserverList.Count(); ++index)
+ {
+ if(textureObserver == mObserverList[index])
+ {
+ textureObserver->DestructionSignal().Disconnect(this, &NPatchData::ObserverDestroyed);
+ mObserverList.Erase(mObserverList.begin() + index);
+ break;
+ }
+ }
+ }
+}
+
+uint32_t NPatchData::GetObserverCount() const
+{
+ return mObserverList.Count();
+}
+
+void NPatchData::SetUrl(const VisualUrl& url)
+{
+ mUrl = url;
+}
+
+VisualUrl NPatchData::GetUrl() const
+{
+ return mUrl;
+}
+
+void NPatchData::SetTextures(const TextureSet textureSet)
+{
+ mTextureSet = textureSet;
+}
+
+TextureSet NPatchData::GetTextures() const
+{
+ return mTextureSet;
+}
+
+void NPatchData::SetStretchPixelsX(const NPatchUtility::StretchRanges stretchPixelsX)
+{
+ mStretchPixelsX = stretchPixelsX;
+}
+
+void NPatchData::SetStretchPixelsY(const NPatchUtility::StretchRanges stretchPixelsY)
+{
+ mStretchPixelsY = stretchPixelsY;
+}
+
+NPatchUtility::StretchRanges NPatchData::GetStretchPixelsX() const
+{
+ return mStretchPixelsX;
+}
+
+NPatchUtility::StretchRanges NPatchData::GetStretchPixelsY() const
+{
+ return mStretchPixelsY;
+}
+
+void NPatchData::SetHash(std::size_t hash)
+{
+ mHash = hash;
+}
+
+std::size_t NPatchData::GetHash() const
+{
+ return mHash;
+}
+
+void NPatchData::SetCroppedWidth(uint32_t croppedWidth)
+{
+ mCroppedWidth = croppedWidth;
+}
+
+void NPatchData::SetCroppedHeight(uint32_t croppedHeight)
+{
+ mCroppedHeight = croppedHeight;
+}
+
+uint32_t NPatchData::GetCroppedWidth() const
+{
+ return mCroppedWidth;
+}
+
+uint32_t NPatchData::GetCroppedHeight() const
+{
+ return mCroppedHeight;
+}
+
+void NPatchData::SetBorder(const Rect<int> border)
+{
+ mBorder = border;
+}
+
+Rect<int> NPatchData::GetBorder() const
+{
+ return mBorder;
+}
+
+void NPatchData::SetPreMultiplyOnLoad(bool preMultiplyOnLoad)
+{
+ mPreMultiplyOnLoad = preMultiplyOnLoad;
+}
+
+bool NPatchData::IsPreMultiplied() const
+{
+ return mPreMultiplyOnLoad;
+}
+
+void NPatchData::SetLoadingState(const LoadingState loadingState)
+{
+ mLoadingState = loadingState;
+}
+
+NPatchData::LoadingState NPatchData::GetLoadingState() const
+{
+ return mLoadingState;
+}
+
+void* NPatchData::GetRenderingMap() const
+{
+ return mRenderingMap;
+}
+
+void NPatchData::SetLoadedNPatchData(Devel::PixelBuffer& pixelBuffer, bool preMultiplied)
+{
+ if(mBorder == Rect<int>(0, 0, 0, 0))
+ {
+ NPatchUtility::ParseBorders(pixelBuffer, mStretchPixelsX, mStretchPixelsY);
+
+ // Crop the image
+ pixelBuffer.Crop(1, 1, pixelBuffer.GetWidth() - 2, pixelBuffer.GetHeight() - 2);
+ }
+ else
+ {
+ mStretchPixelsX.PushBack(Uint16Pair(mBorder.left, ((pixelBuffer.GetWidth() >= static_cast<unsigned int>(mBorder.right)) ? pixelBuffer.GetWidth() - mBorder.right : 0)));
+ mStretchPixelsY.PushBack(Uint16Pair(mBorder.top, ((pixelBuffer.GetHeight() >= static_cast<unsigned int>(mBorder.bottom)) ? pixelBuffer.GetHeight() - mBorder.bottom : 0)));
+ }
+
+ mCroppedWidth = pixelBuffer.GetWidth();
+ mCroppedHeight = pixelBuffer.GetHeight();
+
+ // Create opacity map
+ mRenderingMap = RenderingAddOn::Get().IsValid() ? RenderingAddOn::Get().BuildNPatch(pixelBuffer, this) : nullptr;
+
+ PixelData pixels = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+
+ Texture texture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight());
+ texture.Upload(pixels);
+
+ mTextureSet = TextureSet::New();
+ mTextureSet.SetTexture(0u, texture);
+
+ mPreMultiplyOnLoad = preMultiplied;
+
+ mLoadingState = LoadingState::LOAD_COMPLETE;
+}
+
+void NPatchData::NotifyObserver(TextureUploadObserver* observer, const bool& loadSuccess)
+{
+ observer->LoadComplete(
+ loadSuccess,
+ TextureUploadObserver::TextureInformation(
+ TextureUploadObserver::ReturnType::TEXTURE,
+ static_cast<TextureManager::TextureId>(mId), ///< Note : until end of NPatchLoader::Load, npatch-visual don't know the id of data.
+ mTextureSet,
+ mUrl.GetUrl(),
+ mPreMultiplyOnLoad));
+}
+
+void NPatchData::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
+{
+ NPatchDataPtr self = this; // Keep reference until this API finished
+
+ if(loadSuccess)
+ {
+ if(mLoadingState != LoadingState::LOAD_COMPLETE)
+ {
+ // If mLoadingState is LOAD_FAILED, just re-set (It can be happened when sync loading is failed, but async loading is succeeded).
+ SetLoadedNPatchData(textureInformation.pixelBuffer, textureInformation.preMultiplied);
+ }
+ }
+ else
+ {
+ if(mLoadingState == LoadingState::LOADING)
+ {
+ mLoadingState = LoadingState::LOAD_FAILED;
+ }
+ // If mLoadingState is already LOAD_COMPLETE, we can use uploaded texture (It can be happened when sync loading is succeeded, but async loading is failed).
+ else if(mLoadingState == LoadingState::LOAD_COMPLETE)
+ {
+ loadSuccess = true;
+ }
+ }
+
+ mObserverNotifying = true;
+
+ // Reverse observer list that we can pop_back the observer.
+ std::reverse(mObserverList.Begin(), mObserverList.End());
+
+ while(mObserverList.Count() > 0u)
+ {
+ TextureUploadObserver* observer = *(mObserverList.End() - 1u);
+ mObserverList.Erase(mObserverList.End() - 1u);
+
+ observer->DestructionSignal().Disconnect(this, &NPatchData::ObserverDestroyed);
+
+ NotifyObserver(observer, loadSuccess);
+ }
+
+ mObserverNotifying = false;
+
+ // Swap observer list what we queued during notify observer.
+ // If mQueuedObserver is not empty, it mean mLoadingState was LOAD_FAILED, and we try to re-load for this data.
+ // (If mLoadingState was LOAD_COMPLETE, NotifyObserver will be called directly. @todo : Should we fix this logic, matched with texture manager?)
+ // So LoadComplete will be called.
+ mObserverList.Swap(mQueuedObservers);
+}
+
+void NPatchData::ObserverDestroyed(TextureUploadObserver* observer)
+{
+ for(auto iter = mObserverList.Begin(); iter != mObserverList.End();)
+ {
+ if(observer == (*iter))
+ {
+ iter = mObserverList.Erase(iter);
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+ if(mObserverNotifying)
+ {
+ for(auto iter = mQueuedObservers.Begin(); iter != mQueuedObservers.End();)
+ {
+ if(observer == (*iter))
+ {
+ iter = mQueuedObservers.Erase(iter);
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+ }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_NPATCH_DATA_H
+#define DALI_TOOLKIT_NPATCH_DATA_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/utility/npatch-utilities.h>
+#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+class NPatchData;
+typedef IntrusivePtr<NPatchData> NPatchDataPtr;
+
+class NPatchData : public ConnectionTracker, public Dali::Toolkit::TextureUploadObserver, public Dali::RefObject
+{
+public:
+ typedef int32_t NPatchDataId; ///< The NPatchDataId type. This is used as a handle to refer to a particular Npatch Data.
+ static const NPatchDataId INVALID_NPATCH_DATA_ID = -1; ///< Used to represent a null TextureId or error
+
+ /**
+ * @brief Loading State of the NPatch image.
+ */
+ enum class LoadingState
+ {
+ NOT_STARTED = 0, ///< NPatch loading is not started yet.
+ LOADING, ///< NPatch is on loading.
+ LOAD_COMPLETE, ///< NPatch loading is completed successfully.
+ LOAD_FAILED ///< NPatch loading is failed.
+ };
+
+public:
+ /**
+ * Constructor
+ */
+ NPatchData();
+
+ /**
+ * Destructor, non-virtual as not a base class
+ */
+ ~NPatchData();
+
+public:
+ /**
+ * @brief Set cache data id.
+ *
+ * @param [in] id cache data id
+ */
+ void SetId(const NPatchDataId id);
+
+ /**
+ * @brief Retrieve cache data id
+ *
+ * @return cache data id.
+ */
+ NPatchDataId GetId() const;
+
+ /**
+ * @brief Add TextureUploadObserver that uses the image of this cache data.
+ *
+ * @param [in] textureObserver the TextureUploadObserver that uses the image of this cache data.
+ */
+ void AddObserver(TextureUploadObserver* textureObserver);
+
+ /**
+ * @brief Remove TextureUploadObserver.
+ *
+ * @param [in] textureObserver the TextureUploadObserver that will be removed in this cache data.
+ */
+ void RemoveObserver(TextureUploadObserver* textureObserver);
+
+ /**
+ * @brief Retrieve the number of observer.
+ *
+ * @return Return the number of observer.
+ */
+ uint32_t GetObserverCount() const;
+
+ /**
+ * @brief Set NPatch image url.
+ *
+ * @param [in] url NPatch image url
+ */
+ void SetUrl(const VisualUrl& url);
+
+ /**
+ * @brief Retrieve the image url.
+ *
+ * @return Return the image url.
+ */
+ VisualUrl GetUrl() const;
+
+ /**
+ * @brief Set texture set on the cache data
+ *
+ * @param [in] textureSet loaded texture set
+ */
+ void SetTextures(const TextureSet textureSet);
+
+ /**
+ * @brief Retrieve loaded texture set.
+ *
+ * @return Return loaded texture set.
+ */
+ TextureSet GetTextures() const;
+
+ /**
+ * @brief Set X directional stretchPixels
+ *
+ * @param [in] stretchPixelsX stretchPixels for X direction
+ */
+ void SetStretchPixelsX(const NPatchUtility::StretchRanges stretchPixelsX);
+
+ /**
+ * @brief Set Y directional stretchPixels
+ *
+ * @param [in] stretchPixelsY stretchPixels for Y direction
+ */
+ void SetStretchPixelsY(const NPatchUtility::StretchRanges stretchPixelsY);
+
+ /**
+ * @brief Retrieve stretchPixels for X direction.
+ *
+ * @return Return stretchPixels for X direction.
+ */
+ NPatchUtility::StretchRanges GetStretchPixelsX() const;
+
+ /**
+ * @brief Retrieve stretchPixels for Y direction.
+ *
+ * @return Return stretchPixels for Y direction.
+ */
+ NPatchUtility::StretchRanges GetStretchPixelsY() const;
+
+ /**
+ * @brief Set cache data hash.
+ *
+ * @param [in] hash cache hash
+ */
+ void SetHash(std::size_t hash);
+
+ /**
+ * @brief Retrieve hash value of the cache.
+ *
+ * @return Return hash value of the cache.
+ */
+ std::size_t GetHash() const;
+
+ /**
+ * @brief Set croppedWidth of NPatch
+ *
+ * @param [in] croppedWidth croppedWidth of NPatch
+ */
+ void SetCroppedWidth(uint32_t croppedWidth);
+
+ /**
+ * @brief Set croppedHeight of NPatch
+ *
+ * @param [in] croppedHeight croppedHeight of NPatch
+ */
+ void SetCroppedHeight(uint32_t croppedHeight);
+
+ /**
+ * @brief Retrieve croppedWidth of NPatch.
+ *
+ * @return Return croppedWidth of NPatch.
+ */
+ uint32_t GetCroppedWidth() const;
+
+ /**
+ * @brief Retrieve croppedHeight of NPatch.
+ *
+ * @return Return croppedHeight of NPatch.
+ */
+ uint32_t GetCroppedHeight() const;
+
+ /**
+ * @brief Set border of NPatch.
+ *
+ * @param [in] border border of NPatch
+ */
+ void SetBorder(const Rect<int> border);
+
+ /**
+ * @brief Retrieve border of NPatch.
+ *
+ * @return Return border of NPatch.
+ */
+ Rect<int> GetBorder() const;
+
+ /**
+ * @brief Set whether the loaded image is premultiplied or not
+ *
+ * @param [in] preMultiplyOnLoad whether the loaded image is premultiplied or not
+ */
+ void SetPreMultiplyOnLoad(bool preMultiplyOnLoad);
+
+ /**
+ * @brief Retrieve whether the loaded image is premultiplied or not.
+ *
+ * @return Return true if the image is premultiplied alpha.
+ */
+ bool IsPreMultiplied() const;
+
+ /**
+ * @brief Set current loading state.
+ *
+ * @param [in] loadingState current loading state
+ */
+ void SetLoadingState(const LoadingState loadingState);
+
+ /**
+ * @brief Retrieve current loading state.
+ *
+ * @return Return current loading state.
+ */
+ LoadingState GetLoadingState() const;
+
+ /**
+ * @brief Retrieve NPatch rendering data.
+ *
+ * @return Return NPatch rendering data.
+ */
+ void* GetRenderingMap() const;
+
+ /**
+ * @brief Set loaded pixel buffer for the cache data.
+ *
+ * @param [in] pixelBuffer loaded pixel buffer.
+ * @param [in] preMultiplied whether the loaded image is premultiplied or not
+ */
+ void SetLoadedNPatchData(Devel::PixelBuffer& pixelBuffer, bool preMultiplied);
+
+ /**
+ * @brief Send LoadComplete notify with current setuped NPatchData
+ *
+ * @param [in] observer observer who will be got LoadComplete notify
+ * @param [in] loadSuccess whether the image load success or not.
+ */
+ void NotifyObserver(TextureUploadObserver* observer, const bool& loadSuccess);
+
+private:
+ /**
+ * @copydoc TextureUploadObserver::LoadComplete
+ *
+ * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
+ * This callback is the place to add the renderer as it would be called once the loading is finished.
+ */
+ void LoadComplete(bool loadSuccess, TextureInformation textureInformation) override;
+
+ /**
+ * This is called by the TextureUploadObserver when an observer is destroyed.
+ * We use the callback to know when to remove an observer from our notify list.
+ * @param[in] observer The observer that generated the callback
+ */
+ void ObserverDestroyed(TextureUploadObserver* observer);
+
+private:
+ using ObserverListType = Dali::Vector<TextureUploadObserver*>;
+
+ NPatchDataId mId;
+ ObserverListType mObserverList; ///< Container used to store all observer clients of this Texture
+ ObserverListType mQueuedObservers; ///< Container observers when user try to add during notify observers
+
+ VisualUrl mUrl; ///< Url of the N-Patch
+ TextureSet mTextureSet; ///< Texture containing the cropped image
+ NPatchUtility::StretchRanges mStretchPixelsX; ///< X stretch pixels
+ NPatchUtility::StretchRanges mStretchPixelsY; ///< Y stretch pixels
+ std::size_t mHash; ///< Hash code for the Url
+ uint32_t mCroppedWidth; ///< Width of the cropped middle part of N-patch
+ uint32_t mCroppedHeight; ///< Height of the cropped middle part of N-patch
+ Rect<int> mBorder; ///< The size of the border
+ LoadingState mLoadingState; ///< True if the data loading is completed
+ void* mRenderingMap; ///< NPatch rendering data
+
+ bool mPreMultiplyOnLoad : 1; ///< Whether to multiply alpha into color channels on load
+ bool mObserverNotifying : 1; ///< Whether this NPatchData notifying observers or not.
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_NPATCH_DATA_H
--- /dev/null
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/visuals/npatch/npatch-loader.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/rendering-addon.h>
+
+// EXTERNAL HEADERS
+#include <dali/devel-api/common/hash.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+constexpr auto INVALID_CACHE_INDEX = int32_t{-1}; ///< Invalid Cache index
+constexpr auto UNINITIALIZED_ID = int32_t{0}; ///< uninitialised id, use to initialize ids
+
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false);
+} // Anonymous namespace
+
+NPatchLoader::NPatchLoader()
+: mCurrentNPatchDataId(0),
+ mRemoveProcessorRegistered(false)
+{
+}
+
+NPatchLoader::~NPatchLoader()
+{
+ if(mRemoveProcessorRegistered && Adaptor::IsAvailable())
+ {
+ Adaptor::Get().UnregisterProcessorOnce(*this, true);
+ mRemoveProcessorRegistered = false;
+ }
+}
+
+NPatchData::NPatchDataId NPatchLoader::GenerateUniqueNPatchDataId()
+{
+ // Skip invalid id generation.
+ if(DALI_UNLIKELY(mCurrentNPatchDataId == NPatchData::INVALID_NPATCH_DATA_ID))
+ {
+ mCurrentNPatchDataId = 0;
+ }
+ return mCurrentNPatchDataId++;
+}
+
+NPatchData::NPatchDataId NPatchLoader::Load(TextureManager& textureManager, TextureUploadObserver* textureObserver, const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad, bool synchronousLoading)
+{
+ NPatchDataPtr data = GetNPatchData(url, border, preMultiplyOnLoad);
+
+ DALI_ASSERT_ALWAYS(data.Get() && "NPatchData creation failed!");
+
+ if(data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+ {
+ if(!synchronousLoading)
+ {
+ // NotifyObserver already done, so
+ // data will not iterate observer list.
+ // We need to call LoadComplete directly.
+ data->NotifyObserver(textureObserver, true);
+ }
+ }
+ else // if NOT_STARTED or LOADING or LOAD_FAILED, try to reload.
+ {
+ if(!synchronousLoading)
+ {
+ data->AddObserver(textureObserver);
+ // If still LOADING and async, don't need to request reload. Fast return.
+ if(data->GetLoadingState() == NPatchData::LoadingState::LOADING)
+ {
+ return data->GetId();
+ }
+ }
+
+ data->SetLoadingState(NPatchData::LoadingState::LOADING);
+
+ auto preMultiplyOnLoading = preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
+ : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+ Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer(url, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, data.Get(), true, preMultiplyOnLoading);
+
+ if(pixelBuffer)
+ {
+ preMultiplyOnLoad = (preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) ? true : false;
+ data->SetLoadedNPatchData(pixelBuffer, preMultiplyOnLoad);
+ }
+ else if(synchronousLoading)
+ {
+ data->SetLoadingState(NPatchData::LoadingState::LOAD_FAILED);
+ }
+ }
+ return data->GetId();
+}
+
+int32_t NPatchLoader::GetCacheIndexFromId(const NPatchData::NPatchDataId id)
+{
+ const unsigned int size = mCache.size();
+
+ for(unsigned int i = 0; i < size; ++i)
+ {
+ if(mCache[i].mData->GetId() == id)
+ {
+ return i;
+ }
+ }
+
+ return INVALID_CACHE_INDEX;
+}
+
+bool NPatchLoader::GetNPatchData(const NPatchData::NPatchDataId id, NPatchDataPtr& data)
+{
+ int32_t cacheIndex = GetCacheIndexFromId(id);
+ if(cacheIndex != INVALID_CACHE_INDEX)
+ {
+ data = mCache[cacheIndex].mData;
+ return true;
+ }
+ data = nullptr;
+ return false;
+}
+
+void NPatchLoader::RequestRemove(NPatchData::NPatchDataId id, TextureUploadObserver* textureObserver)
+{
+ // Remove observer first
+ if(textureObserver)
+ {
+ int32_t cacheIndex = GetCacheIndexFromId(id);
+ if(cacheIndex != INVALID_CACHE_INDEX)
+ {
+ NPatchInfo& info(mCache[cacheIndex]);
+
+ info.mData->RemoveObserver(textureObserver);
+ }
+ }
+
+ mRemoveQueue.push_back({id, nullptr});
+
+ if(!mRemoveProcessorRegistered && Adaptor::IsAvailable())
+ {
+ mRemoveProcessorRegistered = true;
+ Adaptor::Get().RegisterProcessorOnce(*this, true);
+ }
+}
+
+void NPatchLoader::Remove(NPatchData::NPatchDataId id, TextureUploadObserver* textureObserver)
+{
+ int32_t cacheIndex = GetCacheIndexFromId(id);
+ if(cacheIndex == INVALID_CACHE_INDEX)
+ {
+ return;
+ }
+
+ NPatchInfo& info(mCache[cacheIndex]);
+
+ info.mData->RemoveObserver(textureObserver);
+
+ if(--info.mReferenceCount <= 0)
+ {
+ mCache.erase(mCache.begin() + cacheIndex);
+ }
+}
+
+void NPatchLoader::Process(bool postProcessor)
+{
+ DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_NPATCH_LOADER_PROCESS_REMOVE_QUEUE", [&](std::ostringstream& oss) {
+ oss << "[" << mRemoveQueue.size() << "]";
+ });
+
+ mRemoveProcessorRegistered = false;
+
+ for(auto& iter : mRemoveQueue)
+ {
+ Remove(iter.first, iter.second);
+ }
+
+ mRemoveQueue.clear();
+
+ DALI_TRACE_END(gTraceFilter, "DALI_NPATCH_LOADER_PROCESS_REMOVE_QUEUE");
+}
+
+NPatchDataPtr NPatchLoader::GetNPatchData(const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad)
+{
+ std::size_t hash = CalculateHash(url.GetUrl());
+ std::vector<NPatchInfo>::size_type index = UNINITIALIZED_ID;
+ const std::vector<NPatchInfo>::size_type count = mCache.size();
+
+ NPatchInfo* infoPtr = nullptr;
+
+ for(; index < count; ++index)
+ {
+ if(mCache[index].mData->GetHash() == hash)
+ {
+ // hash match, check url as well in case of hash collision
+ if(mCache[index].mData->GetUrl().GetUrl() == url.GetUrl())
+ {
+ // Use cached data. Need to fast-out return.
+ if(mCache[index].mData->GetBorder() == border)
+ {
+ mCache[index].mReferenceCount++;
+ return mCache[index].mData;
+ }
+ else
+ {
+ if(mCache[index].mData->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+ {
+ // If we only found LOAD_FAILED case, replace current data. We can reuse texture
+ if(infoPtr == nullptr || infoPtr->mData->GetLoadingState() != NPatchData::LoadingState::LOAD_COMPLETE)
+ {
+ infoPtr = &mCache[index];
+ }
+ }
+ // Still loading pixel buffer. We cannot reuse cached texture yet. Skip checking
+ else if(mCache[index].mData->GetLoadingState() == NPatchData::LoadingState::LOADING)
+ {
+ continue;
+ }
+ // if LOAD_FAILED, reuse this cached NPatchData, and try to load again.
+ else
+ {
+ if(infoPtr == nullptr)
+ {
+ infoPtr = &mCache[index];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // If this is new image loading, make new cache data
+ if(infoPtr == nullptr)
+ {
+ NPatchInfo info(new NPatchData());
+ info.mData->SetId(GenerateUniqueNPatchDataId());
+ info.mData->SetHash(hash);
+ info.mData->SetUrl(url);
+ info.mData->SetBorder(border);
+ info.mData->SetPreMultiplyOnLoad(preMultiplyOnLoad);
+
+ mCache.emplace_back(std::move(info));
+ infoPtr = &mCache.back();
+ }
+ // Else if LOAD_COMPLETE, Same url but border is different - use the existing texture
+ else if(infoPtr->mData->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+ {
+ NPatchInfo info(new NPatchData());
+
+ info.mData->SetId(GenerateUniqueNPatchDataId());
+ info.mData->SetHash(hash);
+ info.mData->SetUrl(url);
+ info.mData->SetCroppedWidth(infoPtr->mData->GetCroppedWidth());
+ info.mData->SetCroppedHeight(infoPtr->mData->GetCroppedHeight());
+
+ info.mData->SetTextures(infoPtr->mData->GetTextures());
+
+ NPatchUtility::StretchRanges stretchRangesX;
+ stretchRangesX.PushBack(Uint16Pair(border.left, ((info.mData->GetCroppedWidth() >= static_cast<unsigned int>(border.right)) ? info.mData->GetCroppedHeight() - border.right : 0)));
+
+ NPatchUtility::StretchRanges stretchRangesY;
+ stretchRangesY.PushBack(Uint16Pair(border.top, ((info.mData->GetCroppedWidth() >= static_cast<unsigned int>(border.bottom)) ? info.mData->GetCroppedHeight() - border.bottom : 0)));
+
+ info.mData->SetStretchPixelsX(stretchRangesX);
+ info.mData->SetStretchPixelsY(stretchRangesY);
+ info.mData->SetBorder(border);
+
+ info.mData->SetPreMultiplyOnLoad(infoPtr->mData->IsPreMultiplied());
+
+ info.mData->SetLoadingState(NPatchData::LoadingState::LOAD_COMPLETE);
+
+ mCache.emplace_back(std::move(info));
+ infoPtr = &mCache.back();
+ }
+ // Else, LOAD_FAILED. just increase reference so we can reuse it.
+ else
+ {
+ infoPtr->mReferenceCount++;
+ }
+
+ DALI_ASSERT_ALWAYS(infoPtr && "NPatchInfo creation failed!");
+
+ return infoPtr->mData;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_NPATCH_LOADER_H
+#define DALI_TOOLKIT_NPATCH_LOADER_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/integration-api/processor-interface.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <string>
+#include <utility> // for std::pair
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/utility/npatch-utilities.h>
+#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
+#include <dali-toolkit/internal/visuals/npatch/npatch-data.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+/**
+ * The manager for loading Npatch textures.
+ * It caches them internally for better performance; i.e. to avoid loading and
+ * parsing the files over and over.
+ *
+ * Cache is not cleaned during app lifecycle as N patches take considerably
+ * small space and there's not usually a lot of them. Usually N patches are specified in
+ * toolkit default style and there is 1-2 per control that are shared across the whole application.
+ */
+class NPatchLoader : public Integration::Processor
+{
+public:
+ /**
+ * Constructor
+ */
+ NPatchLoader();
+
+ /**
+ * Destructor, non-virtual as not a base class
+ */
+ ~NPatchLoader();
+
+ /**
+ * @brief Retrieve a texture matching the n-patch url.
+ *
+ * @param [in] textureManager that will be used to loading image
+ * @param [in] textureObserver The NPatchVisual that requested loading.
+ * @param [in] url to retrieve
+ * @param [in] border The border size of the image
+ * @param [in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
+ * image has no alpha channel
+ * @param [in] synchronousLoading True if the image will be loaded in synchronous time.
+ * @return id of the texture.
+ */
+ NPatchData::NPatchDataId Load(TextureManager& textureManager, TextureUploadObserver* textureObserver, const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad, bool synchronousLoading);
+
+ /**
+ * @brief Retrieve N patch data matching to an id
+ * @param [in] id of data
+ * @param [out] data const pointer to the NPatchData
+ * @return true if data matching to id was really found
+ */
+ bool GetNPatchData(const NPatchData::NPatchDataId id, NPatchDataPtr& data);
+
+ /**
+ * @brief Request remove a texture matching id.
+ * Erase the observer from the observer list of cache if we need.
+ *
+ * @param [in] id cache data id
+ * @param [in] textureObserver The NPatchVisual that requested loading.
+ */
+ void RequestRemove(NPatchData::NPatchDataId id, TextureUploadObserver* textureObserver);
+
+protected: // Implementation of Processor
+ /**
+ * @copydoc Dali::Integration::Processor::Process()
+ */
+ void Process(bool postProcessor) override;
+
+ /**
+ * @copydoc Dali::Integration::Processor::GetProcessorName()
+ */
+ std::string_view GetProcessorName() const override
+ {
+ return "NPatchLoader";
+ }
+
+private:
+ NPatchData::NPatchDataId GenerateUniqueNPatchDataId();
+
+ int32_t GetCacheIndexFromId(const NPatchData::NPatchDataId id);
+
+ /**
+ * @brief Remove a texture matching id.
+ * Erase the observer from the observer list of cache if we need.
+ * This API decrease cached NPatchInfo reference.
+ * If the NPatchInfo reference become 0, the textureSet will be reset.
+ *
+ * @param [in] id cache data id
+ * @param [in] textureObserver The NPatchVisual that requested loading.
+ */
+ void Remove(NPatchData::NPatchDataId id, TextureUploadObserver* textureObserver);
+
+private:
+ /**
+ * @brief Information of NPatchData
+ * It also hold ownership of NPatchData memory.
+ */
+ struct NPatchInfo
+ {
+ NPatchInfo(NPatchDataPtr data)
+ : mData(data),
+ mReferenceCount(1u)
+ {
+ }
+ ~NPatchInfo()
+ {
+ }
+ NPatchInfo(NPatchInfo&& info) noexcept // move constructor
+ {
+ mData = std::move(info.mData);
+ mReferenceCount = info.mReferenceCount;
+ info.mReferenceCount = 0u;
+ }
+ NPatchInfo& operator=(NPatchInfo&& info) noexcept // move operator
+ {
+ mData = std::move(info.mData);
+ mReferenceCount = info.mReferenceCount;
+ info.mReferenceCount = 0u;
+ return *this;
+ }
+
+ NPatchInfo() = delete; // Do not use default constructor
+ NPatchInfo(const NPatchInfo& info) = delete; // Do not use copy constructor
+ NPatchInfo& operator=(const NPatchInfo& info) = delete; // Do not use copy assign
+
+ NPatchDataPtr mData;
+ std::int16_t mReferenceCount; ///< The number of N-patch visuals that use this data.
+ };
+
+ /**
+ * @brief Get cached NPatchData by inputed url and border. If there is no cached data, create new one.
+ * @note This API increase cached NPatchInfo reference.
+ *
+ * @param [in] url to retrieve
+ * @param [in] border The border size of the image
+ * @param [in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
+ * image has no alpha channel
+ * @return NPatchData pointer that Load function will used.
+ */
+ NPatchDataPtr GetNPatchData(const VisualUrl& url, const Rect<int>& border, bool& preMultiplyOnLoad);
+
+protected:
+ /**
+ * Undefined copy constructor.
+ */
+ NPatchLoader(const NPatchLoader&);
+
+ /**
+ * Undefined assignment operator.
+ */
+ NPatchLoader& operator=(const NPatchLoader& rhs);
+
+private:
+ NPatchData::NPatchDataId mCurrentNPatchDataId;
+ std::vector<NPatchInfo> mCache;
+
+ std::vector<std::pair<NPatchData::NPatchDataId, TextureUploadObserver*>> mRemoveQueue; ///< Queue of textures to remove at PostProcess. It will be cleared after PostProcess.
+
+ bool mRemoveProcessorRegistered : 1; ///< Flag if remove processor registered or not.
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_NPATCH_LOADER_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/image/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-feature-builder.h>
+#include <dali-toolkit/internal/visuals/npatch/npatch-loader.h>
#include <dali-toolkit/internal/visuals/rendering-addon.h>
#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
#include <dali-toolkit/internal/visuals/visual-base-impl.h>
#include <dali-toolkit/internal/visuals/svg/svg-visual.h>
// INTERNAL INCLUDES
-#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/image/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-feature-builder.h>
#include <dali-toolkit/internal/visuals/svg/svg-task.h>
#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/visuals/text-visual-shader-factory.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
-#include <dali-toolkit/internal/visuals/visual-string-constants.h>
-#include <dali/integration-api/debug.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-namespace
-{
-// enum of required list when we select shader
-enum class TextVisualRequireFlag : uint32_t
-{
- DEFAULT = 0,
- STYLES = 1 << 0,
- OVERLAY = 1 << 1,
- EMOJI = 1 << 2,
- MULTI_COLOR = 1 << 3,
-};
-
-const VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[] =
- {
- VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT,
- VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE,
- VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_OVERLAY,
- VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_OVERLAY,
- VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI,
- VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI,
- VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_OVERLAY_AND_EMOJI,
- VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_OVERLAY_AND_EMOJI,
- VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT,
- VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE,
- VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_OVERLAY,
- VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE_AND_OVERLAY,
-};
-
-static constexpr auto SHADER_TYPE_COUNT = 1u;
-constexpr std::string_view VertexPredefines[SHADER_TYPE_COUNT]{
- "", // VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT
-};
-constexpr std::string_view FragmentPredefines[SHADER_TYPE_COUNT]{
- "", // VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT
-};
-constexpr VisualFactoryCache::ShaderType ShaderTypePredefines[SHADER_TYPE_COUNT]{
- VisualFactoryCache::ShaderType::TEXT_SHADER_SINGLE_COLOR_TEXT,
-};
-
-} // unnamed namespace
-
-namespace TextVisualShaderFeature
-{
-FeatureBuilder& FeatureBuilder::EnableMultiColor(bool enableMultiColor)
-{
- mTextMultiColor = enableMultiColor ? TextMultiColor::MULTI_COLOR_TEXT : TextMultiColor::SINGLE_COLOR_TEXT;
- return *this;
-}
-FeatureBuilder& FeatureBuilder::EnableEmoji(bool enableEmoji)
-{
- mTextEmoji = enableEmoji ? TextEmoji::HAS_EMOJI : TextEmoji::NO_EMOJI;
- return *this;
-}
-FeatureBuilder& FeatureBuilder::EnableStyle(bool enableStyle)
-{
- mTextStyle = enableStyle ? TextStyle::HAS_STYLES : TextStyle::NO_STYLES;
- return *this;
-}
-FeatureBuilder& FeatureBuilder::EnableOverlay(bool enableOverlay)
-{
- mTextOverlay = enableOverlay ? TextOverlay::HAS_OVERLAY : TextOverlay::NO_OVERLAY;
- return *this;
-}
-} // namespace TextVisualShaderFeature
-
-TextVisualShaderFactory::TextVisualShaderFactory()
-{
-}
-
-TextVisualShaderFactory::~TextVisualShaderFactory()
-{
-}
-
-Shader TextVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, const TextVisualShaderFeature::FeatureBuilder& featureBuilder)
-{
- Shader shader;
- uint32_t shaderTypeFlag = static_cast<uint32_t>(TextVisualRequireFlag::DEFAULT);
- VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT;
-
- const auto& multiColor = featureBuilder.mTextMultiColor;
- const auto& emoji = featureBuilder.mTextEmoji;
- const auto& style = featureBuilder.mTextStyle;
- const auto& overlay = featureBuilder.mTextOverlay;
-
- if(style == TextVisualShaderFeature::TextStyle::HAS_STYLES)
- {
- shaderTypeFlag |= static_cast<uint32_t>(TextVisualRequireFlag::STYLES);
- }
- if(overlay == TextVisualShaderFeature::TextOverlay::HAS_OVERLAY)
- {
- shaderTypeFlag |= static_cast<uint32_t>(TextVisualRequireFlag::OVERLAY);
- }
- // multi color can also render emoji. If multi color text, dont consider emoji
- if(multiColor != TextVisualShaderFeature::TextMultiColor::MULTI_COLOR_TEXT && emoji == TextVisualShaderFeature::TextEmoji::HAS_EMOJI)
- {
- shaderTypeFlag |= static_cast<uint32_t>(TextVisualRequireFlag::EMOJI);
- }
- if(multiColor == TextVisualShaderFeature::TextMultiColor::MULTI_COLOR_TEXT)
- {
- shaderTypeFlag |= static_cast<uint32_t>(TextVisualRequireFlag::MULTI_COLOR);
- }
-
- shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
- shader = factoryCache.GetShader(shaderType);
-
- if(!shader)
- {
- std::string vertexShaderPrefixList;
- std::string fragmentShaderPrefixList;
-
- if(style == TextVisualShaderFeature::TextStyle::HAS_STYLES)
- {
- fragmentShaderPrefixList += "#define IS_REQUIRED_STYLE\n";
- }
- if(overlay == TextVisualShaderFeature::TextOverlay::HAS_OVERLAY)
- {
- fragmentShaderPrefixList += "#define IS_REQUIRED_OVERLAY\n";
- }
- // multi color can also render emoji. If multi color text, dont consider emoji
- if(multiColor != TextVisualShaderFeature::TextMultiColor::MULTI_COLOR_TEXT && emoji == TextVisualShaderFeature::TextEmoji::HAS_EMOJI)
- {
- fragmentShaderPrefixList += "#define IS_REQUIRED_EMOJI\n";
- }
- if(multiColor == TextVisualShaderFeature::TextMultiColor::MULTI_COLOR_TEXT)
- {
- fragmentShaderPrefixList += "#define IS_REQUIRED_MULTI_COLOR\n";
- }
-
- std::string vertexShader = std::string(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_TEXT_VISUAL_SHADER_VERT.data());
- std::string fragmentShader = std::string(Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_TEXT_VISUAL_SHADER_FRAG.data());
-
- shader = factoryCache.GenerateAndSaveShader(shaderType, vertexShader, fragmentShader);
- }
- return shader;
-}
-
-void TextVisualShaderFactory::GetPreCompiledShader(RawShaderData& shaders)
-{
- std::vector<std::string_view> vertexPrefix;
- std::vector<std::string_view> fragmentPrefix;
- std::vector<std::string_view> shaderName;
- int shaderCount = 0;
- for(uint32_t i = 0; i < SHADER_TYPE_COUNT; ++i)
- {
- vertexPrefix.push_back(VertexPredefines[i]);
- fragmentPrefix.push_back(FragmentPredefines[i]);
- shaderName.push_back(Scripting::GetLinearEnumerationName<VisualFactoryCache::ShaderType>(ShaderTypePredefines[i], VISUAL_SHADER_TYPE_TABLE, VISUAL_SHADER_TYPE_TABLE_COUNT));
- shaderCount++;
- }
-
- shaders.vertexPrefix = vertexPrefix;
- shaders.fragmentPrefix = fragmentPrefix;
- shaders.shaderName = shaderName;
- shaders.vertexShader = SHADER_TEXT_VISUAL_SHADER_VERT;
- shaders.fragmentShader = SHADER_TEXT_VISUAL_SHADER_FRAG;
- shaders.shaderCount = shaderCount;
-}
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_TEXT_VISUAL_SHADER_FACTORY_H
-#define DALI_TOOLKIT_TEXT_VISUAL_SHADER_FACTORY_H
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// EXTERNAL INCLUDES
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
-#include <string_view>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-/**
- * TextVisualShaderFeature contains feature lists what text visual shader need to know.
- */
-namespace TextVisualShaderFeature
-{
-namespace TextMultiColor
-{
-/**
- * @brief Whether text contains single color or not.
- */
-enum Type
-{
- SINGLE_COLOR_TEXT = 0, ///< The text contains single color only.
- MULTI_COLOR_TEXT ///< The text contains multiple colors.
-};
-} // namespace TextMultiColor
-
-namespace TextEmoji
-{
-/**
- * @brief Whether text contains emoji or not.
- */
-enum Type
-{
- NO_EMOJI = 0, ///< The text contains no emoji.
- HAS_EMOJI ///< The text contains emoji.
-};
-} // namespace TextEmoji
-
-namespace TextStyle
-{
-/**
- * @brief Whether text contains styles (like shadow or background color) or not.
- */
-enum Type
-{
- NO_STYLES = 0, ///< The text contains contains no styles.
- HAS_STYLES ///< The text contains contains styles.
-};
-} // namespace TextStyle
-
-namespace TextOverlay
-{
-/**
- * @brief Whether text contains overlay styles (like markdown) or not.
- */
-enum Type
-{
- NO_OVERLAY = 0, ///< The text contains contains no overlay.
- HAS_OVERLAY ///< The text contains contains overlay.
-};
-} // namespace TextOverlay
-
-/**
- * @brief Collection of current text visual feature.
- */
-struct FeatureBuilder
-{
- FeatureBuilder()
- : mTextMultiColor(TextMultiColor::SINGLE_COLOR_TEXT),
- mTextEmoji(TextEmoji::NO_EMOJI),
- mTextStyle(TextStyle::NO_STYLES),
- mTextOverlay(TextOverlay::NO_OVERLAY)
- {
- }
-
- FeatureBuilder& EnableMultiColor(bool enableMultiColor);
- FeatureBuilder& EnableEmoji(bool enableEmoji);
- FeatureBuilder& EnableStyle(bool enableStyle);
- FeatureBuilder& EnableOverlay(bool enableOverlay);
-
- bool IsEnabledMultiColor() const
- {
- return mTextMultiColor == TextMultiColor::MULTI_COLOR_TEXT;
- }
- bool IsEnabledEmoji() const
- {
- return mTextEmoji == TextEmoji::HAS_EMOJI;
- }
- bool IsEnabledStyle() const
- {
- return mTextStyle == TextStyle::HAS_STYLES;
- }
- bool IsEnabledOverlay() const
- {
- return mTextOverlay == TextOverlay::HAS_OVERLAY;
- }
-
- TextMultiColor::Type mTextMultiColor : 2; ///< Whether text has multiple color, or not. default as TextMultiColor::SINGLE_COLOR_TEXT
- TextEmoji::Type mTextEmoji : 2; ///< Whether text has emoji, or not. default as TextEmoji::NO_EMOJI
- TextStyle::Type mTextStyle : 2; ///< Whether text has style, or not. default as TextStyle::NO_STYLES
- TextOverlay::Type mTextOverlay : 2; ///< Whether text has overlay style, or not. default as TextOverlay::NO_OVERLAY
-};
-
-} // namespace TextVisualShaderFeature
-
-/**
- * TextVisualShaderFactory is an object that provides and shares shaders for text visuals
- */
-class TextVisualShaderFactory
-{
-public:
- /**
- * @brief Constructor
- */
- TextVisualShaderFactory();
-
- /**
- * @brief Destructor
- */
- ~TextVisualShaderFactory();
-
- /**
- * @brief Get the standard text rendering shader.
- * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
- * @param[in] featureBuilder Collection of current text shader's features
- * @return The standard text rendering shader with features.
- */
- Shader GetShader(VisualFactoryCache& factoryCache, const TextVisualShaderFeature::FeatureBuilder& featureBuilder);
-
- /**
- * @brief Get the default shader source.
- * @param[in] shaders shaderList for precompile
- */
- void GetPreCompiledShader(RawShaderData& shaders);
-
-protected:
- /**
- * Undefined copy constructor.
- */
- TextVisualShaderFactory(const TextVisualShaderFactory&);
-
- /**
- * Undefined assignment operator.
- */
- TextVisualShaderFactory& operator=(const TextVisualShaderFactory& rhs);
-
-private:
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_TEXT_VISUAL_SHADER_FACTORY_H
--- /dev/null
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/visuals/text/text-visual-shader-factory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+// enum of required list when we select shader
+enum class TextVisualRequireFlag : uint32_t
+{
+ DEFAULT = 0,
+ STYLES = 1 << 0,
+ OVERLAY = 1 << 1,
+ EMOJI = 1 << 2,
+ MULTI_COLOR = 1 << 3,
+};
+
+const VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[] =
+ {
+ VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT,
+ VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE,
+ VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_OVERLAY,
+ VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_OVERLAY,
+ VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI,
+ VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI,
+ VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_OVERLAY_AND_EMOJI,
+ VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_OVERLAY_AND_EMOJI,
+ VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT,
+ VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE,
+ VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_OVERLAY,
+ VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE_AND_OVERLAY,
+};
+
+static constexpr auto SHADER_TYPE_COUNT = 1u;
+constexpr std::string_view VertexPredefines[SHADER_TYPE_COUNT]{
+ "", // VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT
+};
+constexpr std::string_view FragmentPredefines[SHADER_TYPE_COUNT]{
+ "", // VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT
+};
+constexpr VisualFactoryCache::ShaderType ShaderTypePredefines[SHADER_TYPE_COUNT]{
+ VisualFactoryCache::ShaderType::TEXT_SHADER_SINGLE_COLOR_TEXT,
+};
+
+} // unnamed namespace
+
+namespace TextVisualShaderFeature
+{
+FeatureBuilder& FeatureBuilder::EnableMultiColor(bool enableMultiColor)
+{
+ mTextMultiColor = enableMultiColor ? TextMultiColor::MULTI_COLOR_TEXT : TextMultiColor::SINGLE_COLOR_TEXT;
+ return *this;
+}
+FeatureBuilder& FeatureBuilder::EnableEmoji(bool enableEmoji)
+{
+ mTextEmoji = enableEmoji ? TextEmoji::HAS_EMOJI : TextEmoji::NO_EMOJI;
+ return *this;
+}
+FeatureBuilder& FeatureBuilder::EnableStyle(bool enableStyle)
+{
+ mTextStyle = enableStyle ? TextStyle::HAS_STYLES : TextStyle::NO_STYLES;
+ return *this;
+}
+FeatureBuilder& FeatureBuilder::EnableOverlay(bool enableOverlay)
+{
+ mTextOverlay = enableOverlay ? TextOverlay::HAS_OVERLAY : TextOverlay::NO_OVERLAY;
+ return *this;
+}
+} // namespace TextVisualShaderFeature
+
+TextVisualShaderFactory::TextVisualShaderFactory()
+{
+}
+
+TextVisualShaderFactory::~TextVisualShaderFactory()
+{
+}
+
+Shader TextVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, const TextVisualShaderFeature::FeatureBuilder& featureBuilder)
+{
+ Shader shader;
+ uint32_t shaderTypeFlag = static_cast<uint32_t>(TextVisualRequireFlag::DEFAULT);
+ VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT;
+
+ const auto& multiColor = featureBuilder.mTextMultiColor;
+ const auto& emoji = featureBuilder.mTextEmoji;
+ const auto& style = featureBuilder.mTextStyle;
+ const auto& overlay = featureBuilder.mTextOverlay;
+
+ if(style == TextVisualShaderFeature::TextStyle::HAS_STYLES)
+ {
+ shaderTypeFlag |= static_cast<uint32_t>(TextVisualRequireFlag::STYLES);
+ }
+ if(overlay == TextVisualShaderFeature::TextOverlay::HAS_OVERLAY)
+ {
+ shaderTypeFlag |= static_cast<uint32_t>(TextVisualRequireFlag::OVERLAY);
+ }
+ // multi color can also render emoji. If multi color text, dont consider emoji
+ if(multiColor != TextVisualShaderFeature::TextMultiColor::MULTI_COLOR_TEXT && emoji == TextVisualShaderFeature::TextEmoji::HAS_EMOJI)
+ {
+ shaderTypeFlag |= static_cast<uint32_t>(TextVisualRequireFlag::EMOJI);
+ }
+ if(multiColor == TextVisualShaderFeature::TextMultiColor::MULTI_COLOR_TEXT)
+ {
+ shaderTypeFlag |= static_cast<uint32_t>(TextVisualRequireFlag::MULTI_COLOR);
+ }
+
+ shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
+ shader = factoryCache.GetShader(shaderType);
+
+ if(!shader)
+ {
+ std::string vertexShaderPrefixList;
+ std::string fragmentShaderPrefixList;
+
+ if(style == TextVisualShaderFeature::TextStyle::HAS_STYLES)
+ {
+ fragmentShaderPrefixList += "#define IS_REQUIRED_STYLE\n";
+ }
+ if(overlay == TextVisualShaderFeature::TextOverlay::HAS_OVERLAY)
+ {
+ fragmentShaderPrefixList += "#define IS_REQUIRED_OVERLAY\n";
+ }
+ // multi color can also render emoji. If multi color text, dont consider emoji
+ if(multiColor != TextVisualShaderFeature::TextMultiColor::MULTI_COLOR_TEXT && emoji == TextVisualShaderFeature::TextEmoji::HAS_EMOJI)
+ {
+ fragmentShaderPrefixList += "#define IS_REQUIRED_EMOJI\n";
+ }
+ if(multiColor == TextVisualShaderFeature::TextMultiColor::MULTI_COLOR_TEXT)
+ {
+ fragmentShaderPrefixList += "#define IS_REQUIRED_MULTI_COLOR\n";
+ }
+
+ std::string vertexShader = std::string(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_TEXT_VISUAL_SHADER_VERT.data());
+ std::string fragmentShader = std::string(Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_TEXT_VISUAL_SHADER_FRAG.data());
+
+ shader = factoryCache.GenerateAndSaveShader(shaderType, vertexShader, fragmentShader);
+ }
+ return shader;
+}
+
+void TextVisualShaderFactory::GetPreCompiledShader(RawShaderData& shaders)
+{
+ std::vector<std::string_view> vertexPrefix;
+ std::vector<std::string_view> fragmentPrefix;
+ std::vector<std::string_view> shaderName;
+ int shaderCount = 0;
+ for(uint32_t i = 0; i < SHADER_TYPE_COUNT; ++i)
+ {
+ vertexPrefix.push_back(VertexPredefines[i]);
+ fragmentPrefix.push_back(FragmentPredefines[i]);
+ shaderName.push_back(Scripting::GetLinearEnumerationName<VisualFactoryCache::ShaderType>(ShaderTypePredefines[i], VISUAL_SHADER_TYPE_TABLE, VISUAL_SHADER_TYPE_TABLE_COUNT));
+ shaderCount++;
+ }
+
+ shaders.vertexPrefix = vertexPrefix;
+ shaders.fragmentPrefix = fragmentPrefix;
+ shaders.shaderName = shaderName;
+ shaders.vertexShader = SHADER_TEXT_VISUAL_SHADER_VERT;
+ shaders.fragmentShader = SHADER_TEXT_VISUAL_SHADER_FRAG;
+ shaders.shaderCount = shaderCount;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_VISUAL_SHADER_FACTORY_H
+#define DALI_TOOLKIT_TEXT_VISUAL_SHADER_FACTORY_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/shader-precompiler.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <string_view>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+/**
+ * TextVisualShaderFeature contains feature lists what text visual shader need to know.
+ */
+namespace TextVisualShaderFeature
+{
+namespace TextMultiColor
+{
+/**
+ * @brief Whether text contains single color or not.
+ */
+enum Type
+{
+ SINGLE_COLOR_TEXT = 0, ///< The text contains single color only.
+ MULTI_COLOR_TEXT ///< The text contains multiple colors.
+};
+} // namespace TextMultiColor
+
+namespace TextEmoji
+{
+/**
+ * @brief Whether text contains emoji or not.
+ */
+enum Type
+{
+ NO_EMOJI = 0, ///< The text contains no emoji.
+ HAS_EMOJI ///< The text contains emoji.
+};
+} // namespace TextEmoji
+
+namespace TextStyle
+{
+/**
+ * @brief Whether text contains styles (like shadow or background color) or not.
+ */
+enum Type
+{
+ NO_STYLES = 0, ///< The text contains contains no styles.
+ HAS_STYLES ///< The text contains contains styles.
+};
+} // namespace TextStyle
+
+namespace TextOverlay
+{
+/**
+ * @brief Whether text contains overlay styles (like markdown) or not.
+ */
+enum Type
+{
+ NO_OVERLAY = 0, ///< The text contains contains no overlay.
+ HAS_OVERLAY ///< The text contains contains overlay.
+};
+} // namespace TextOverlay
+
+/**
+ * @brief Collection of current text visual feature.
+ */
+struct FeatureBuilder
+{
+ FeatureBuilder()
+ : mTextMultiColor(TextMultiColor::SINGLE_COLOR_TEXT),
+ mTextEmoji(TextEmoji::NO_EMOJI),
+ mTextStyle(TextStyle::NO_STYLES),
+ mTextOverlay(TextOverlay::NO_OVERLAY)
+ {
+ }
+
+ FeatureBuilder& EnableMultiColor(bool enableMultiColor);
+ FeatureBuilder& EnableEmoji(bool enableEmoji);
+ FeatureBuilder& EnableStyle(bool enableStyle);
+ FeatureBuilder& EnableOverlay(bool enableOverlay);
+
+ bool IsEnabledMultiColor() const
+ {
+ return mTextMultiColor == TextMultiColor::MULTI_COLOR_TEXT;
+ }
+ bool IsEnabledEmoji() const
+ {
+ return mTextEmoji == TextEmoji::HAS_EMOJI;
+ }
+ bool IsEnabledStyle() const
+ {
+ return mTextStyle == TextStyle::HAS_STYLES;
+ }
+ bool IsEnabledOverlay() const
+ {
+ return mTextOverlay == TextOverlay::HAS_OVERLAY;
+ }
+
+ TextMultiColor::Type mTextMultiColor : 2; ///< Whether text has multiple color, or not. default as TextMultiColor::SINGLE_COLOR_TEXT
+ TextEmoji::Type mTextEmoji : 2; ///< Whether text has emoji, or not. default as TextEmoji::NO_EMOJI
+ TextStyle::Type mTextStyle : 2; ///< Whether text has style, or not. default as TextStyle::NO_STYLES
+ TextOverlay::Type mTextOverlay : 2; ///< Whether text has overlay style, or not. default as TextOverlay::NO_OVERLAY
+};
+
+} // namespace TextVisualShaderFeature
+
+/**
+ * TextVisualShaderFactory is an object that provides and shares shaders for text visuals
+ */
+class TextVisualShaderFactory
+{
+public:
+ /**
+ * @brief Constructor
+ */
+ TextVisualShaderFactory();
+
+ /**
+ * @brief Destructor
+ */
+ ~TextVisualShaderFactory();
+
+ /**
+ * @brief Get the standard text rendering shader.
+ * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+ * @param[in] featureBuilder Collection of current text shader's features
+ * @return The standard text rendering shader with features.
+ */
+ Shader GetShader(VisualFactoryCache& factoryCache, const TextVisualShaderFeature::FeatureBuilder& featureBuilder);
+
+ /**
+ * @brief Get the default shader source.
+ * @param[in] shaders shaderList for precompile
+ */
+ void GetPreCompiledShader(RawShaderData& shaders);
+
+protected:
+ /**
+ * Undefined copy constructor.
+ */
+ TextVisualShaderFactory(const TextVisualShaderFactory&);
+
+ /**
+ * Undefined assignment operator.
+ */
+ TextVisualShaderFactory& operator=(const TextVisualShaderFactory& rhs);
+
+private:
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_VISUAL_SHADER_FACTORY_H
#include <dali-toolkit/internal/text/text-effects-style.h>
#include <dali-toolkit/internal/text/text-enumerations-impl.h>
#include <dali-toolkit/internal/text/text-font-style.h>
-#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/image/image-atlas-manager.h>
#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
#include <dali-toolkit/internal/visuals/visual-base-impl.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
mImpl->mRenderer = VisualRenderer::New(geometry, shader);
mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
mTextRequireRenderPropertyIndex = mImpl->mRenderer.RegisterUniqueProperty("requireRender", mTextRequireRender);
- mHasMultipleTextColorsIndex = mImpl->mRenderer.RegisterUniqueProperty("uHasMultipleTextColors", static_cast<float>(false));
+ mHasMultipleTextColorsIndex = mImpl->mRenderer.RegisterUniqueProperty("uHasMultipleTextColors", static_cast<float>(false));
}
void TextVisual::DoSetProperties(const Property::Map& propertyMap)
const bool isWidthRelative = fabsf(mImpl->mTransform.mOffsetSizeMode.z) < Math::MACHINE_EPSILON_1000;
const bool isHeightRelative = fabsf(mImpl->mTransform.mOffsetSizeMode.w) < Math::MACHINE_EPSILON_1000;
- const float controlWidth = mImpl->mControlSize.width;
+ const float controlWidth = mImpl->mControlSize.width;
const float controlHeight = mImpl->mControlSize.height;
// Round the size and offset to avoid pixel alignement issues.
shadowEnabled = true;
}
- const bool outlineEnabled = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
- const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled();
- const bool markupOrSpannedText = mController->IsMarkupProcessorEnabled() || mController->GetTextModel()->IsSpannedTextPlaced();
- const bool markupUnderlineEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupUnderlineSet();
- const bool markupStrikethroughEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupStrikethroughSet();
- const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled() || markupUnderlineEnabled;
- const bool strikethroughEnabled = mController->GetTextModel()->IsStrikethroughEnabled() || markupStrikethroughEnabled;
- const bool backgroundMarkupSet = mController->GetTextModel()->IsMarkupBackgroundColorSet();
- const bool cutoutEnabled = mController->IsTextCutout();
- const bool backgroundWithCutoutEnabled = mController->GetTextModel()->IsBackgroundWithCutoutEnabled();
- const bool styleEnabled = (shadowEnabled || outlineEnabled || backgroundEnabled || markupOrSpannedText || backgroundMarkupSet || cutoutEnabled || backgroundWithCutoutEnabled);
- const bool isOverlayStyle = underlineEnabled || strikethroughEnabled;
+ const bool outlineEnabled = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
+ const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled();
+ const bool markupOrSpannedText = mController->IsMarkupProcessorEnabled() || mController->GetTextModel()->IsSpannedTextPlaced();
+ const bool markupUnderlineEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupUnderlineSet();
+ const bool markupStrikethroughEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupStrikethroughSet();
+ const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled() || markupUnderlineEnabled;
+ const bool strikethroughEnabled = mController->GetTextModel()->IsStrikethroughEnabled() || markupStrikethroughEnabled;
+ const bool backgroundMarkupSet = mController->GetTextModel()->IsMarkupBackgroundColorSet();
+ const bool cutoutEnabled = mController->IsTextCutout();
+ const bool backgroundWithCutoutEnabled = mController->GetTextModel()->IsBackgroundWithCutoutEnabled();
+ const bool styleEnabled = (shadowEnabled || outlineEnabled || backgroundEnabled || markupOrSpannedText || backgroundMarkupSet || cutoutEnabled || backgroundWithCutoutEnabled);
+ const bool isOverlayStyle = underlineEnabled || strikethroughEnabled;
// if background with cutout is enabled, This text visual must render the entire control size.
if(cutoutEnabled)
{
- relayoutSize = Vector2(controlWidth, controlHeight);
- mImpl->mTransform.mSize.width = controlWidth;
+ relayoutSize = Vector2(controlWidth, controlHeight);
+ mImpl->mTransform.mSize.width = controlWidth;
mImpl->mTransform.mSize.height = controlHeight;
- mImpl->mTransform.mOffset.x = 0;
- mImpl->mTransform.mOffset.y = 0;
+ mImpl->mTransform.mOffset.x = 0;
+ mImpl->mTransform.mOffset.y = 0;
}
AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle);
Pixel::Format textPixelFormat = (mTextShaderFeatureCache.IsEnabledEmoji() || mTextShaderFeatureCache.IsEnabledMultiColor() || cutoutEnabled) ? Pixel::RGBA8888 : Pixel::L8;
// Check the text direction
- Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection();
- uint32_t textureSetIndex = 0u;
+ Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection();
+ uint32_t textureSetIndex = 0u;
// Create a texture for the text without any styles
Devel::PixelBuffer cutoutData;
- float cutoutAlpha = mController->GetTextModel()->GetDefaultColor().a;
+ float cutoutAlpha = mController->GetTextModel()->GetDefaultColor().a;
if(cutoutEnabled)
{
cutoutData = mTypesetter->RenderWithPixelBuffer(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
// Make transparent buffer.
// If the cutout is enabled, a separate texture is not used for the text.
- Devel::PixelBuffer buffer = mTypesetter->CreateFullBackgroundBuffer(1, 1, Vector4(0.f, 0.f ,0.f ,0.f));
- PixelData data = Devel::PixelBuffer::Convert(buffer);
+ Devel::PixelBuffer buffer = mTypesetter->CreateFullBackgroundBuffer(1, 1, Vector4(0.f, 0.f, 0.f, 0.f));
+ PixelData data = Devel::PixelBuffer::Convert(buffer);
AddTexture(textureSet, data, sampler, textureSetIndex);
++textureSetIndex;
}
++textureSetIndex;
}
-
if(mTextShaderFeatureCache.IsEnabledStyle())
{
// Create RGBA texture for all the text styles that render in the background (without the text itself)
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/controller/text-controller.h>
#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
-#include <dali-toolkit/internal/visuals/text-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/text/text-visual-shader-factory.h>
#include <dali-toolkit/internal/visuals/visual-base-impl.h>
namespace Dali
#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h>
#include <dali-toolkit/internal/visuals/color/color-visual.h>
-#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/image/image-atlas-manager.h>
#include <dali-toolkit/internal/visuals/svg/svg-visual.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
*/
// EXTERNAL INCLUDES
-#include <dali/devel-api/common/owner-container.h>
-#include <dali/integration-api/adaptor-framework/shader-precompiler.h>
#include <dali/public-api/math/uint-16-pair.h>
#include <dali/public-api/object/ref-object.h>
#include <dali/public-api/rendering/geometry.h>
// INTERNAL INCLUDES
#include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
-#include <dali-toolkit/internal/visuals/npatch-loader.h>
+#include <dali-toolkit/internal/visuals/npatch/npatch-loader.h>
#include <dali/devel-api/rendering/renderer-devel.h>
namespace Dali
#include <dali-toolkit/internal/visuals/border/border-visual.h>
#include <dali-toolkit/internal/visuals/color/color-visual.h>
#include <dali-toolkit/internal/visuals/gradient/gradient-visual.h>
-#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/image/image-visual-shader-factory.h>
#include <dali-toolkit/internal/visuals/image/image-visual.h>
#include <dali-toolkit/internal/visuals/mesh/mesh-visual.h>
#include <dali-toolkit/internal/visuals/npatch/npatch-visual.h>
#include <dali-toolkit/internal/visuals/primitive/primitive-visual.h>
#include <dali-toolkit/internal/visuals/svg/svg-visual.h>
-#include <dali-toolkit/internal/visuals/text-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/text/text-visual-shader-factory.h>
#include <dali-toolkit/internal/visuals/text/text-visual.h>
#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>