#include <dali/devel-api/scripting/scripting.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
-#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
#include <dali/public-api/rendering/renderer.h>
#include <test-native-image.h>
END_TEST;
}
+
int UtcDaliImageViewSyncLoading02(void)
{
ToolkitTestApplication application;
END_TEST;
}
-int UtcDaliImageViewAddedTexture(void)
-{
- ToolkitTestApplication application;
-
- tet_infoline("ImageView Testing image view with texture provided manager url");
-
- ImageView imageView = ImageView::New();
-
- // empty texture is ok, though pointless from app point of view
- TextureSet empty;
- std::string url = TextureManager::AddTexture(empty);
- DALI_TEST_CHECK(url.size() > 0u);
-
- Property::Map propertyMap;
- propertyMap[ImageVisual::Property::URL] = url;
- imageView.SetProperty(ImageView::Property::IMAGE, propertyMap);
-
- Stage::GetCurrent().Add( imageView );
- application.SendNotification();
- application.Render();
-
- END_TEST;
-}
-
int UtcDaliImageViewSizeWithBackground(void)
{
ToolkitTestApplication application;
devel_api_image_loader_header_files = \
$(devel_api_src_dir)/image-loader/async-image-loader-devel.h \
$(devel_api_src_dir)/image-loader/atlas-upload-observer.h \
- $(devel_api_src_dir)/image-loader/image-atlas.h \
- $(devel_api_src_dir)/image-loader/texture-manager.h
+ $(devel_api_src_dir)/image-loader/image-atlas.h
devel_api_scripting_header_files = \
$(devel_api_src_dir)/scripting/script.h \
mWrapModeU( WrapMode::DEFAULT ),
mWrapModeV( WrapMode::DEFAULT ),
mAttemptAtlasing( false ),
- mLoadingStatus( false )
+ mTextureLoading( false )
{
}
mWrapModeU( WrapMode::DEFAULT ),
mWrapModeV( WrapMode::DEFAULT ),
mAttemptAtlasing( false ),
- mLoadingStatus( false )
+ mTextureLoading( false )
{
}
ImageVisual::~ImageVisual()
{
- if( mMaskingData && Stage::IsInstalled() )
- {
- // TextureManager could have been deleted before the actor that contains this
- // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage
- // is still valid before accessing texture manager.
- if( mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID )
- {
- TextureManager& textureManager = mFactoryCache.GetTextureManager();
- textureManager.Remove( mMaskingData->mAlphaMaskId );
- }
- }
delete mMaskingData;
}
}
}
}
+
}
void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& value )
{
AllocateMaskData();
// Immediately trigger the alpha mask loading (it may just get a cached value)
- mMaskingData->mAlphaMaskUrl = alphaUrl;
- TextureManager& textureManager = mFactoryCache.GetTextureManager();
- mMaskingData->mAlphaMaskId = textureManager.RequestMaskLoad( alphaUrl );
+ mMaskingData->SetImage( alphaUrl );
}
break;
}
{
if( mMaskingData == NULL )
{
- mMaskingData = new TextureManager::MaskingData();
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+ mMaskingData = new MaskingData(textureManager);
}
}
return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
}
-/*
-( VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode,
- ImageVisual::MaskingData* maskInfo, bool synchronousLoading,
- TextureManager::TextureId textureId, Vector4& textureRect, bool& atlasingStatus, bool& loadingStatus
- */
+TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, bool synchronousLoading, bool attemptAtlasing )
+{
+ TextureSet textureSet;
+
+ mTextureLoading = false;
+ textureRect = FULL_TEXTURE_RECT;
+
+ if( synchronousLoading )
+ {
+ PixelData data;
+ if( mImageUrl.IsValid() )
+ {
+ // if sync loading is required, the loading should immediately when actor is on stage
+ Devel::PixelBuffer pixelBuffer = LoadImageFromFile( mImageUrl.GetUrl(), mDesiredSize, mFittingMode, mSamplingMode );
+
+ if( pixelBuffer )
+ {
+ data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+ }
+ }
+ if( !data )
+ {
+ // use broken image
+ textureSet = TextureSet::New();
+ TextureSetImage( textureSet, 0u, VisualFactoryCache::GetBrokenVisualImage() );
+ }
+ else
+ {
+ if( attemptAtlasing )
+ {
+ textureSet = mFactoryCache.GetAtlasManager()->Add( textureRect, data );
+ mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+ }
+ if( !textureSet ) // big image, no atlasing or atlasing failed
+ {
+ mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+ Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(),
+ data.GetWidth(), data.GetHeight() );
+ texture.Upload( data );
+ textureSet = TextureSet::New();
+ textureSet.SetTexture( 0u, texture );
+ }
+ }
+ }
+ else
+ {
+ mTextureLoading = true;
+ if( attemptAtlasing )
+ {
+ textureSet = mFactoryCache.GetAtlasManager()->Add( textureRect, mImageUrl.GetUrl(), mDesiredSize, mFittingMode, true, this );
+ mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+ }
+ if( !textureSet ) // big image, no atlasing or atlasing failed
+ {
+ mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+ if( mMaskingData == NULL )
+ {
+ mTextureId = textureManager.RequestLoad( mImageUrl, mDesiredSize, mFittingMode,
+ mSamplingMode, TextureManager::NO_ATLAS, this );
+ }
+ else
+ {
+ mTextureId = textureManager.RequestLoad( mImageUrl,
+ mMaskingData->mAlphaMaskId,
+ mMaskingData->mContentScaleFactor,
+ mDesiredSize,
+ mFittingMode, mSamplingMode,
+ TextureManager::NO_ATLAS,
+ mMaskingData->mCropToMask,
+ this );
+ }
+
+ TextureManager::LoadState loadState = textureManager.GetTextureState( mTextureId );
+ mTextureLoading = ( loadState == TextureManager::LOADING );
+
+ if( loadState == TextureManager::UPLOADED )
+ {
+ // UploadComplete has already been called - keep the same texture set
+ textureSet = textureManager.GetTextureSet(mTextureId);
+ }
+ }
+ }
+
+ if( ! (mImpl->mFlags & Impl::IS_ATLASING_APPLIED) && textureSet )
+ {
+ Sampler sampler = Sampler::New();
+ sampler.SetWrapMode( mWrapModeU, mWrapModeV );
+ textureSet.SetSampler( 0u, sampler );
+ }
+
+ return textureSet;
+}
+
void ImageVisual::InitializeRenderer()
{
mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
- TextureManager& textureManager = mFactoryCache.GetTextureManager();
-
if( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL )
{
bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
Vector4 atlasRect;
-
- auto attemptAtlasing = mAttemptAtlasing;
-
// texture set has to be created first as we need to know if atlasing succeeded or not
// when selecting the shader
- TextureSet textures =
- textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
- mMaskingData, IsSynchronousResourceLoading(), mTextureId,
- atlasRect, attemptAtlasing, mLoadingStatus, mWrapModeU,
- mWrapModeV, this, this, mFactoryCache.GetAtlasManager());
- if(attemptAtlasing)
- {
- mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
- }
+ TextureSet textures = CreateTextureSet( atlasRect, IsSynchronousResourceLoading(), mAttemptAtlasing );
CreateRenderer( textures );
if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED ) // the texture is packed inside atlas
{
mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
- if( !defaultWrapMode ) // custom wrap mode
+ if( !defaultWrapMode ) // custom wrap mode, renderer is not cached.
{
Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE);
wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) );
}
else
{
- auto attemptAtlasing = false;
// for custom shader or remote image, atlas is not applied
Vector4 atlasRect; // ignored in this case
- TextureSet textures =
- textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
- mMaskingData, IsSynchronousResourceLoading(), mTextureId,
- atlasRect, attemptAtlasing, mLoadingStatus, mWrapModeU, mWrapModeV, this,
- nullptr, nullptr); // no atlasing
- DALI_ASSERT_DEBUG(attemptAtlasing == false);
+ TextureSet textures = CreateTextureSet( atlasRect, IsSynchronousResourceLoading(), false );
CreateRenderer( textures );
}
}
void ImageVisual::InitializeRenderer( const Image& image )
{
+ // don't reuse CreateTextureSet
TextureSet textures = TextureSet::New();
NativeImage nativeImage = NativeImage::DownCast( image );
mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
}
- if( mLoadingStatus == false )
+ if( mTextureLoading == false )
{
actor.AddRenderer( mImpl->mRenderer );
mPlacementActor.Reset();
RemoveTexture( mImageUrl.GetUrl() );
mImage.Reset();
}
- mLoadingStatus = false;
+ mTextureLoading = false;
mImpl->mRenderer.Reset();
mPlacementActor.Reset();
}
// reset the weak handle so that the renderer only get added to actor once
mPlacementActor.Reset();
}
- mLoadingStatus = false;
+ mTextureLoading = false;
}
// From Texture Manager
ResourceReady();
}
}
- mLoadingStatus = false;
+ mTextureLoading = false;
}
void ImageVisual::RemoveTexture(const std::string& url)
}
}
+
+ImageVisual::MaskingData::MaskingData( TextureManager& textureManager )
+: mTextureManager( textureManager ),
+ mAlphaMaskUrl(),
+ mAlphaMaskId( TextureManager::INVALID_TEXTURE_ID ),
+ mContentScaleFactor( 1.0f ),
+ mCropToMask( true )
+{
+}
+
+ImageVisual::MaskingData::~MaskingData()
+{
+ if( Stage::IsInstalled() )
+ {
+ // TextureManager could have been deleted before the actor that contains this
+ // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage
+ // is still valid before accessing texture manager.
+ if( mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID )
+ {
+ mTextureManager.Remove( mAlphaMaskId );
+ }
+ }
+}
+
+void ImageVisual::MaskingData::SetImage( const std::string& maskUrl )
+{
+ mAlphaMaskUrl = maskUrl;
+ mAlphaMaskId = mTextureManager.RequestMaskLoad( mAlphaMaskUrl );
+}
+
} // namespace Internal
} // namespace Toolkit
void DoSetProperty( Property::Index index, const Property::Value& value );
private:
+ struct MaskingData
+ {
+ MaskingData( TextureManager& textureManager );
+ ~MaskingData();
+ void SetImage( const std::string& url );
+
+ TextureManager& mTextureManager;
+ VisualUrl mAlphaMaskUrl;
+ TextureManager::TextureId mAlphaMaskId;
+ float mContentScaleFactor;
+ bool mCropToMask;
+ };
Image mImage;
Vector4 mPixelArea;
WeakHandle<Actor> mPlacementActor;
VisualUrl mImageUrl;
- TextureManager::MaskingData* mMaskingData;
+ MaskingData* mMaskingData;
Dali::ImageDimensions mDesiredSize;
TextureManager::TextureId mTextureId;
Dali::SamplingMode::Type mSamplingMode:4;
Dali::WrapMode::Type mWrapModeU:3;
Dali::WrapMode::Type mWrapModeV:3;
- bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture
- bool mLoadingStatus; ///< True if the texture is being loaded asynchronously, or false when it has loaded.
+ bool mAttemptAtlasing:1; ///< If true will attempt atlasing, otherwise create unique texture
+ bool mTextureLoading:1; ///< True if the texture is being loaded asynchronously, or false when it has loaded.
};
// EXTERNAL HEADERS
#include <cstdlib>
#include <string>
-#include <dali/public-api/math/vector4.h>
#include <dali/devel-api/adaptor-framework/environment-variable.h>
-#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali/devel-api/common/hash.h>
#include <dali/devel-api/images/texture-set-image.h>
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
// INTERNAL HEADERS
#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
#include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
-#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
namespace
{
} // Anonymous namespace
-TextureManager::MaskingData::MaskingData()
-: mAlphaMaskUrl(),
- mAlphaMaskId( INVALID_TEXTURE_ID ),
- mContentScaleFactor( 1.0f ),
- mCropToMask( true )
-{
-}
TextureManager::TextureManager()
: mAsyncLocalLoaders( GetNumberOfLocalLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ),
{
}
-TextureSet TextureManager::LoadTexture(
- VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode,
- Dali::SamplingMode::Type samplingMode, const MaskingDataPointer& maskInfo,
- bool synchronousLoading, TextureManager::TextureId& textureId, Vector4& textureRect,
- bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU,
- Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver,
- AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager)
-{
- TextureSet textureSet;
-
- loadingStatus = false;
- textureRect = FULL_ATLAS_RECT;
-
- if( VisualUrl::TEXTURE == url.GetProtocolType())
- {
- std::string location = url.GetLocation();
- if( location.size() > 0u )
- {
- TextureId id = std::stoi( location );
- for( auto&& elem : mExternalTextures )
- {
- if( elem.textureId == id )
- {
- return elem.textureSet;
- }
- }
- }
- }
- else if( synchronousLoading )
- {
- PixelData data;
- if( url.IsValid() )
- {
- // if sync loading is required, the loading should immediately when actor is on stage
- Devel::PixelBuffer pixelBuffer = LoadImageFromFile( url.GetUrl(), desiredSize, fittingMode, samplingMode );
- if( pixelBuffer )
- {
- data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
- }
- }
- if( !data )
- {
- // use broken image
- textureSet = TextureSet::New();
- Devel::PixelBuffer pixelBuffer = LoadImageFromFile( BROKEN_IMAGE_URL );
- if( pixelBuffer )
- {
- data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
- }
- Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(),
- data.GetWidth(), data.GetHeight() );
- texture.Upload( data );
- textureSet = TextureSet::New();
- textureSet.SetTexture( 0u, texture );
- }
- else
- {
- if( atlasingStatus ) // attempt atlasing
- {
- textureSet = imageAtlasManager->Add( textureRect, data );
- }
- if( !textureSet ) // big image, no atlasing or atlasing failed
- {
- atlasingStatus = false;
- Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(),
- data.GetWidth(), data.GetHeight() );
- texture.Upload( data );
- textureSet = TextureSet::New();
- textureSet.SetTexture( 0u, texture );
- }
- }
- }
- else
- {
- loadingStatus = true;
- if( atlasingStatus )
- {
- textureSet = imageAtlasManager->Add( textureRect, url.GetUrl(), desiredSize, fittingMode, true, atlasObserver );
- }
- if( !textureSet ) // big image, no atlasing or atlasing failed
- {
- atlasingStatus = false;
- if( !maskInfo )
- {
- textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, textureObserver );
- }
- else
- {
- textureId = RequestLoad( url,
- maskInfo->mAlphaMaskId,
- maskInfo->mContentScaleFactor,
- desiredSize,
- fittingMode, samplingMode,
- TextureManager::NO_ATLAS,
- maskInfo->mCropToMask,
- textureObserver );
- }
-
- TextureManager::LoadState loadState = GetTextureState( textureId );
- loadingStatus = ( loadState == TextureManager::LOADING );
-
- if( loadState == TextureManager::UPLOADED )
- {
- // UploadComplete has already been called - keep the same texture set
- textureSet = GetTextureSet( textureId );
- }
- }
- }
-
- if( ! atlasingStatus && textureSet )
- {
- Sampler sampler = Sampler::New();
- sampler.SetWrapMode( wrapModeU, wrapModeV );
- textureSet.SetSampler( 0u, sampler );
- }
-
- return textureSet;
-}
-
TextureManager::TextureId TextureManager::RequestLoad(
const VisualUrl& url,
const ImageDimensions desiredSize,
return RequestLoadInternal( maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, KEEP_PIXEL_BUFFER, NULL );
}
+
TextureManager::TextureId TextureManager::RequestLoadInternal(
const VisualUrl& url,
TextureId maskTextureId,
}
}
+TextureManager::~TextureManager()
+{
+}
+
TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureManager)
: AsyncLoadingHelper(Toolkit::AsyncImageLoader::New(), textureManager,
AsyncLoadingInfoContainerType())
namespace Internal
{
-class ImageAtlasManager;
-typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
/**
* The TextureManager provides a common Image loading API for Visuals.
public:
- struct MaskingData
- {
- MaskingData();
- ~MaskingData() = default;
-
- VisualUrl mAlphaMaskUrl;
- TextureManager::TextureId mAlphaMaskId;
- float mContentScaleFactor;
- bool mCropToMask;
- };
-
/**
* Constructor.
*/
/**
* Destructor.
*/
- ~TextureManager() = default;
+ ~TextureManager();
// TextureManager Main API:
- TextureSet LoadTexture(VisualUrl& url, Dali::ImageDimensions desiredSize,
- Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode,
- MaskingData* maskInfo, bool synchronousLoading,
- TextureManager::TextureId& textureId, Vector4& textureRect,
- bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU,
- Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver,
- AtlasUploadObserver* atlasObserver,
- ImageAtlasManagerPtr imageAtlasManager);
-
/**
* @brief Requests an image load of the given URL.
*
unsigned short loadId; ///< The load Id used by the async loader to reference this load
};
+ /**
+ * @brief This struct is used within a container to manage atlas creation and destruction.
+ */
+ struct AtlasInfo
+ {
+ AtlasInfo( Toolkit::ImageAtlas atlas, TextureSet textureSet )
+ : atlas( atlas ),
+ textureSet( textureSet )
+ {
+ }
+
+ Toolkit::ImageAtlas atlas; ///< The ImageAtlas object
+ TextureSet textureSet; ///< The TextureSet is kept in the struct to allow fast lookup of TextureSet to Atlas
+ };
+
// Private typedefs:
typedef std::deque<AsyncLoadingInfo> AsyncLoadingInfoContainerType; ///< The container type used to manage Asynchronous loads in progress
+ typedef std::vector<AtlasInfo> AtlasInfoContainerType; ///< The container type used to manage Atlas creation and destruction
typedef std::vector<TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
/**
private: // Member Variables:
+ AtlasInfoContainerType mAtlasContainer; ///< Used to manage Atlas creation and destruction
TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
RoundRobinContainerView< AsyncLoadingHelper > mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads
RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads