X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Fimage%2Fimage-visual.cpp;h=650c5086e0e75de3bb66d8b67dfff05bcaaf7ac7;hp=9823a9271342eb22af23c98793ee4f88dda86698;hb=e0c063be9e7ecde0e5665079289489d456828abf;hpb=2b051f9220d4e28225a57d5dabc98e093357cad6 diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index 9823a92..650c508 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,97 +19,95 @@ #include // EXTERNAL HEADERS -#include // for strlen() -#include -#include #include +#include +#include +#include #include #include #include +#include +#include // for strlen() // INTERNAL HEADERS -#include -#include #include -#include -#include -#include -#include -#include #include +#include +#include #include +#include +#include +#include +#include #include -#include +#include +#include namespace Dali { - namespace Toolkit { - namespace Internal { - namespace { - // fitting modes -DALI_ENUM_TO_STRING_TABLE_BEGIN( FITTING_MODE ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, SHRINK_TO_FIT ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, SCALE_TO_FILL ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, FIT_WIDTH ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, FIT_HEIGHT ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, DEFAULT ) -DALI_ENUM_TO_STRING_TABLE_END( FITTING_MODE ) +DALI_ENUM_TO_STRING_TABLE_BEGIN(FITTING_MODE) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SHRINK_TO_FIT) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SCALE_TO_FILL) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_WIDTH) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_HEIGHT) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, DEFAULT) +DALI_ENUM_TO_STRING_TABLE_END(FITTING_MODE) // sampling modes -DALI_ENUM_TO_STRING_TABLE_BEGIN( SAMPLING_MODE ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, BOX ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, NEAREST ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, LINEAR ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, BOX_THEN_NEAREST ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, BOX_THEN_LINEAR ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, NO_FILTER ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, DONT_CARE ) -DALI_ENUM_TO_STRING_TABLE_END( SAMPLING_MODE ) +DALI_ENUM_TO_STRING_TABLE_BEGIN(SAMPLING_MODE) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NEAREST) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, LINEAR) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_NEAREST) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_LINEAR) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NO_FILTER) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, DONT_CARE) +DALI_ENUM_TO_STRING_TABLE_END(SAMPLING_MODE) // wrap modes -DALI_ENUM_TO_STRING_TABLE_BEGIN( WRAP_MODE ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, DEFAULT ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, CLAMP_TO_EDGE ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, REPEAT ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, MIRRORED_REPEAT ) -DALI_ENUM_TO_STRING_TABLE_END( WRAP_MODE ) +DALI_ENUM_TO_STRING_TABLE_BEGIN(WRAP_MODE) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, DEFAULT) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, CLAMP_TO_EDGE) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, REPEAT) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, MIRRORED_REPEAT) +DALI_ENUM_TO_STRING_TABLE_END(WRAP_MODE) // load policies -DALI_ENUM_TO_STRING_TABLE_BEGIN( LOAD_POLICY ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::ImageVisual::LoadPolicy, IMMEDIATE ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::ImageVisual::LoadPolicy, ATTACHED ) -DALI_ENUM_TO_STRING_TABLE_END( LOAD_POLICY ) +DALI_ENUM_TO_STRING_TABLE_BEGIN(LOAD_POLICY) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, IMMEDIATE) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, ATTACHED) +DALI_ENUM_TO_STRING_TABLE_END(LOAD_POLICY) // release policies -DALI_ENUM_TO_STRING_TABLE_BEGIN( RELEASE_POLICY ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::ImageVisual::ReleasePolicy, DETACHED ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::ImageVisual::ReleasePolicy, DESTROYED ) -DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::ImageVisual::ReleasePolicy, NEVER ) -DALI_ENUM_TO_STRING_TABLE_END( RELEASE_POLICY ) +DALI_ENUM_TO_STRING_TABLE_BEGIN(RELEASE_POLICY) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DETACHED) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DESTROYED) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, NEVER) +DALI_ENUM_TO_STRING_TABLE_END(RELEASE_POLICY) const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f); -const float PIXEL_ALIGN_ON = 1.0f; +const float PIXEL_ALIGN_ON = 1.0f; const float PIXEL_ALIGN_OFF = 0.0f; -Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridSize ) +Geometry CreateGeometry(VisualFactoryCache& factoryCache, ImageDimensions gridSize) { Geometry geometry; - if( gridSize == ImageDimensions( 1, 1 ) ) + if(gridSize == ImageDimensions(1, 1)) { - geometry = factoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY ); + geometry = factoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY); } else { - geometry = VisualFactoryCache::CreateGridGeometry( gridSize ); + geometry = VisualFactoryCache::CreateGridGeometry(gridSize); } return geometry; @@ -117,177 +115,195 @@ Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridS } // unnamed namespace - -ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache, - ImageVisualShaderFactory& shaderFactory, - const VisualUrl& imageUrl, - const Property::Map& properties, - ImageDimensions size, - FittingMode::Type fittingMode, - Dali::SamplingMode::Type samplingMode ) +ImageVisualPtr ImageVisual::New(VisualFactoryCache& factoryCache, + ImageVisualShaderFactory& shaderFactory, + const VisualUrl& imageUrl, + const Property::Map& properties, + ImageDimensions size, + FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode) { - ImageVisualPtr imageVisualPtr( new ImageVisual( factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode ) ); - imageVisualPtr->SetProperties( properties ); + ImageVisualPtr imageVisualPtr(new ImageVisual(factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode)); + imageVisualPtr->SetProperties(properties); + imageVisualPtr->Initialize(); return imageVisualPtr; } -ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache, - ImageVisualShaderFactory& shaderFactory, - const VisualUrl& imageUrl, - ImageDimensions size, - FittingMode::Type fittingMode, - Dali::SamplingMode::Type samplingMode ) +ImageVisualPtr ImageVisual::New(VisualFactoryCache& factoryCache, + ImageVisualShaderFactory& shaderFactory, + const VisualUrl& imageUrl, + ImageDimensions size, + FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode) { - return new ImageVisual( factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode ); + ImageVisualPtr imageVisualPtr(new ImageVisual(factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode)); + imageVisualPtr->Initialize(); + return imageVisualPtr; } -ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, - ImageVisualShaderFactory& shaderFactory, - const VisualUrl& imageUrl, - ImageDimensions size, - FittingMode::Type fittingMode, - Dali::SamplingMode::Type samplingMode ) -: Visual::Base( factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::IMAGE ), - mPixelArea( FULL_TEXTURE_RECT ), +ImageVisual::ImageVisual(VisualFactoryCache& factoryCache, + ImageVisualShaderFactory& shaderFactory, + const VisualUrl& imageUrl, + ImageDimensions size, + FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode) +: Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::IMAGE), + mPixelArea(FULL_TEXTURE_RECT), mPlacementActor(), - mImageUrl( imageUrl ), - mMaskingData( ), - mDesiredSize( size ), - mTextureId( TextureManager::INVALID_TEXTURE_ID ), + mImageUrl(imageUrl), + mMaskingData(), + mDesiredSize(size), + mTextureId(TextureManager::INVALID_TEXTURE_ID), mTextures(), - mImageVisualShaderFactory( shaderFactory ), - mFittingMode( fittingMode ), - mSamplingMode( samplingMode ), - mWrapModeU( WrapMode::DEFAULT ), - mWrapModeV( WrapMode::DEFAULT ), - mLoadPolicy( Toolkit::ImageVisual::LoadPolicy::ATTACHED ), - mReleasePolicy( Toolkit::ImageVisual::ReleasePolicy::DETACHED ), - mAtlasRect( 0.0f, 0.0f, 0.0f, 0.0f ), - mAtlasRectSize( 0, 0 ), - mAttemptAtlasing( false ), - mLoading( false ), - mOrientationCorrection( true ) + mImageVisualShaderFactory(shaderFactory), + mFittingMode(fittingMode), + mSamplingMode(samplingMode), + mWrapModeU(WrapMode::DEFAULT), + mWrapModeV(WrapMode::DEFAULT), + mLoadPolicy(Toolkit::ImageVisual::LoadPolicy::ATTACHED), + mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED), + mAtlasRect(0.0f, 0.0f, 0.0f, 0.0f), + mAtlasRectSize(0, 0), + mLoadState(TextureManager::LoadState::NOT_STARTED), + mAttemptAtlasing(false), + mOrientationCorrection(true) { - EnablePreMultipliedAlpha( mFactoryCache.GetPreMultiplyOnLoad() ); + EnablePreMultipliedAlpha(mFactoryCache.GetPreMultiplyOnLoad()); } ImageVisual::~ImageVisual() { - if( Stage::IsInstalled() ) + if(Stage::IsInstalled()) { - if( mMaskingData ) + if(mMaskingData) { // 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 ) + if(mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID) { TextureManager& textureManager = mFactoryCache.GetTextureManager(); - textureManager.Remove( mMaskingData->mAlphaMaskId, this ); + textureManager.Remove(mMaskingData->mAlphaMaskId, this); + } + } + + if(mImageUrl.IsValid()) + { + // Decrease reference count of External Resources : + // EncodedImageBuffer or ExternalTextures. + // Ensure the stage is still valid before accessing texture manager. + if(mImageUrl.GetProtocolType() == VisualUrl::TEXTURE) + { + TextureManager& textureManager = mFactoryCache.GetTextureManager(); + textureManager.RemoveExternalTexture(mImageUrl.GetUrl()); + } + else if(mImageUrl.IsBufferResource()) + { + TextureManager& textureManager = mFactoryCache.GetTextureManager(); + textureManager.RemoveExternalEncodedImageBuffer(mImageUrl.GetUrl()); } } // ImageVisual destroyed so remove texture unless ReleasePolicy is set to never release - if( ( mTextureId != TextureManager::INVALID_TEXTURE_ID ) && ( mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER ) ) + if((mTextureId != TextureManager::INVALID_TEXTURE_ID) && (mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER)) { RemoveTexture(); } } } -void ImageVisual::DoSetProperties( const Property::Map& propertyMap ) +void ImageVisual::DoSetProperties(const Property::Map& propertyMap) { // Url is already received in constructor - for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter ) + for(Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter) { - KeyValuePair keyValue = propertyMap.GetKeyValue( iter ); - if( keyValue.first.type == Property::Key::INDEX ) + KeyValuePair keyValue = propertyMap.GetKeyValue(iter); + if(keyValue.first.type == Property::Key::INDEX) { - DoSetProperty( keyValue.first.indexKey, keyValue.second ); + DoSetProperty(keyValue.first.indexKey, keyValue.second); } else { - if( keyValue.first == IMAGE_FITTING_MODE ) + if(keyValue.first == IMAGE_FITTING_MODE) { - DoSetProperty( Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second); } - else if( keyValue.first == IMAGE_SAMPLING_MODE ) + else if(keyValue.first == IMAGE_SAMPLING_MODE) { - DoSetProperty( Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second); } - else if( keyValue.first == IMAGE_DESIRED_WIDTH ) + else if(keyValue.first == IMAGE_DESIRED_WIDTH) { - DoSetProperty( Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second); } - else if( keyValue.first == IMAGE_DESIRED_HEIGHT ) + else if(keyValue.first == IMAGE_DESIRED_HEIGHT) { - DoSetProperty( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second); } - else if( keyValue.first == PIXEL_AREA_UNIFORM_NAME ) + else if(keyValue.first == PIXEL_AREA_UNIFORM_NAME) { - DoSetProperty( Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second); } - else if( keyValue.first == IMAGE_WRAP_MODE_U ) + else if(keyValue.first == IMAGE_WRAP_MODE_U) { - DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second); } - else if( keyValue.first == IMAGE_WRAP_MODE_V ) + else if(keyValue.first == IMAGE_WRAP_MODE_V) { - DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second); } - else if( keyValue.first == SYNCHRONOUS_LOADING ) + else if(keyValue.first == SYNCHRONOUS_LOADING) { - DoSetProperty( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second); } - else if( keyValue.first == IMAGE_ATLASING ) + else if(keyValue.first == IMAGE_ATLASING) { - DoSetProperty( Toolkit::ImageVisual::Property::ATLASING, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::ATLASING, keyValue.second); } - else if( keyValue.first == ALPHA_MASK_URL ) + else if(keyValue.first == ALPHA_MASK_URL) { - DoSetProperty( Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second); } - else if( keyValue.first == MASK_CONTENT_SCALE_NAME ) + else if(keyValue.first == MASK_CONTENT_SCALE_NAME) { - DoSetProperty( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second); } - else if( keyValue.first == CROP_TO_MASK_NAME ) + else if(keyValue.first == CROP_TO_MASK_NAME) { - DoSetProperty( Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second); } - else if ( keyValue.first == LOAD_POLICY_NAME ) + else if(keyValue.first == LOAD_POLICY_NAME) { - DoSetProperty( Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second); } - else if( keyValue.first == RELEASE_POLICY_NAME ) + else if(keyValue.first == RELEASE_POLICY_NAME) { - DoSetProperty( Toolkit::ImageVisual::Property::RELEASE_POLICY, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::RELEASE_POLICY, keyValue.second); } - else if( keyValue.first == ORIENTATION_CORRECTION_NAME ) + else if(keyValue.first == ORIENTATION_CORRECTION_NAME) { - DoSetProperty( Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, keyValue.second); } } } // Load image immediately if LOAD_POLICY requires it - if ( mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::IMMEDIATE ) + if(mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::IMMEDIATE) { auto attemptAtlasing = AttemptAtlasing(); - LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, - TextureManager::ReloadPolicy::CACHED ); + LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::CACHED); } } -void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& value ) +void ImageVisual::DoSetProperty(Property::Index index, const Property::Value& value) { - switch( index ) + switch(index) { case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING: { bool sync = false; - if( value.Get( sync ) ) + if(value.Get(sync)) { - if( sync ) + if(sync) { mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; } @@ -306,9 +322,9 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v case Toolkit::ImageVisual::Property::DESIRED_WIDTH: { float desiredWidth = 0.0f; - if( value.Get( desiredWidth ) ) + if(value.Get(desiredWidth)) { - mDesiredSize.SetWidth( desiredWidth ); + mDesiredSize.SetWidth(desiredWidth); } else { @@ -320,9 +336,9 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v case Toolkit::ImageVisual::Property::DESIRED_HEIGHT: { float desiredHeight = 0.0f; - if( value.Get( desiredHeight ) ) + if(value.Get(desiredHeight)) { - mDesiredSize.SetHeight( desiredHeight ); + mDesiredSize.SetHeight(desiredHeight); } else { @@ -334,51 +350,51 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v case Toolkit::ImageVisual::Property::FITTING_MODE: { int fittingMode = 0; - Scripting::GetEnumerationProperty( value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode ); - mFittingMode = Dali::FittingMode::Type( fittingMode ); + Scripting::GetEnumerationProperty(value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode); + mFittingMode = Dali::FittingMode::Type(fittingMode); break; } case Toolkit::ImageVisual::Property::SAMPLING_MODE: { int samplingMode = 0; - Scripting::GetEnumerationProperty( value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode ); - mSamplingMode = Dali::SamplingMode::Type( samplingMode ); + Scripting::GetEnumerationProperty(value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode); + mSamplingMode = Dali::SamplingMode::Type(samplingMode); break; } case Toolkit::ImageVisual::Property::PIXEL_AREA: { - value.Get( mPixelArea ); + value.Get(mPixelArea); break; } case Toolkit::ImageVisual::Property::WRAP_MODE_U: { int wrapMode = 0; - Scripting::GetEnumerationProperty( value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode ); - mWrapModeU = Dali::WrapMode::Type( wrapMode ); + Scripting::GetEnumerationProperty(value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode); + mWrapModeU = Dali::WrapMode::Type(wrapMode); break; } case Toolkit::ImageVisual::Property::WRAP_MODE_V: { int wrapMode = 0; - Scripting::GetEnumerationProperty( value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode ); - mWrapModeV = Dali::WrapMode::Type( wrapMode ); + Scripting::GetEnumerationProperty(value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode); + mWrapModeV = Dali::WrapMode::Type(wrapMode); break; } case Toolkit::ImageVisual::Property::ATLASING: { - value.Get( mAttemptAtlasing ); + value.Get(mAttemptAtlasing); break; } case Toolkit::ImageVisual::Property::ALPHA_MASK_URL: { std::string alphaUrl = ""; - if( value.Get( alphaUrl ) ) + if(value.Get(alphaUrl)) { AllocateMaskData(); mMaskingData->mAlphaMaskUrl = alphaUrl; @@ -389,7 +405,7 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v case Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE: { float scale = 1.0f; - if( value.Get( scale ) ) + if(value.Get(scale)) { AllocateMaskData(); mMaskingData->mContentScaleFactor = scale; @@ -399,8 +415,8 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v case Toolkit::ImageVisual::Property::CROP_TO_MASK: { - bool crop=false; - if( value.Get( crop ) ) + bool crop = false; + if(value.Get(crop)) { AllocateMaskData(); mMaskingData->mCropToMask = crop; @@ -411,22 +427,22 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v case Toolkit::ImageVisual::Property::RELEASE_POLICY: { int releasePolicy = 0; - Scripting::GetEnumerationProperty( value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy ); - mReleasePolicy = Toolkit::ImageVisual::ReleasePolicy::Type( releasePolicy ); + Scripting::GetEnumerationProperty(value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy); + mReleasePolicy = Toolkit::ImageVisual::ReleasePolicy::Type(releasePolicy); break; } case Toolkit::ImageVisual::Property::LOAD_POLICY: { int loadPolicy = 0; - Scripting::GetEnumerationProperty( value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy ); - mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type( loadPolicy ); + Scripting::GetEnumerationProperty(value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy); + mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type(loadPolicy); break; } case Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION: { - bool orientationCorrection( mOrientationCorrection ); - if( value.Get( orientationCorrection ) ) + bool orientationCorrection(mOrientationCorrection); + if(value.Get(orientationCorrection)) { mOrientationCorrection = orientationCorrection; } @@ -437,23 +453,23 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v void ImageVisual::AllocateMaskData() { - if( !mMaskingData ) + if(!mMaskingData) { mMaskingData.reset(new TextureManager::MaskingData()); } } -void ImageVisual::GetNaturalSize( Vector2& naturalSize ) +void ImageVisual::GetNaturalSize(Vector2& naturalSize) { - if( mDesiredSize.GetWidth()>0 && mDesiredSize.GetHeight()>0) + if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0) { naturalSize.x = mDesiredSize.GetWidth(); naturalSize.y = mDesiredSize.GetHeight(); return; } - else if( mImpl->mRenderer ) // Check if we have a loaded image + else if(mImpl->mRenderer) // Check if we have a loaded image { - if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED ) + if(mImpl->mFlags & Impl::IS_ATLASING_APPLIED) { naturalSize.x = mAtlasRectSize.GetWidth(); naturalSize.y = mAtlasRectSize.GetHeight(); @@ -461,10 +477,10 @@ void ImageVisual::GetNaturalSize( Vector2& naturalSize ) } auto textureSet = mImpl->mRenderer.GetTextures(); - if( textureSet ) + if(textureSet) { auto texture = textureSet.GetTexture(0); - if( texture ) + if(texture) { naturalSize.x = texture.GetWidth(); naturalSize.y = texture.GetHeight(); @@ -473,32 +489,38 @@ void ImageVisual::GetNaturalSize( Vector2& naturalSize ) } } - if( mMaskingData != NULL && mMaskingData->mAlphaMaskUrl.IsValid() && - mMaskingData->mCropToMask ) + if(mMaskingData != NULL && mMaskingData->mAlphaMaskUrl.IsValid() && + mMaskingData->mCropToMask) { - ImageDimensions dimensions = Dali::GetClosestImageSize( mMaskingData->mAlphaMaskUrl.GetUrl() ); - if( dimensions != ImageDimensions( 0, 0 ) ) + ImageDimensions dimensions = Dali::GetClosestImageSize(mMaskingData->mAlphaMaskUrl.GetUrl()); + if(dimensions != ImageDimensions(0, 0)) { naturalSize.x = dimensions.GetWidth(); naturalSize.y = dimensions.GetHeight(); } return; } - else if( mImageUrl.IsValid() ) + else if(mImageUrl.IsValid()) { - if( mImageUrl.GetProtocolType() == VisualUrl::LOCAL ) + if(mImageUrl.GetProtocolType() == VisualUrl::LOCAL) { - ImageDimensions dimensions = Dali::GetClosestImageSize( mImageUrl.GetUrl() ); + ImageDimensions dimensions = Dali::GetClosestImageSize(mImageUrl.GetUrl()); - if( dimensions != ImageDimensions( 0, 0 ) ) + if(dimensions != ImageDimensions(0, 0)) { naturalSize.x = dimensions.GetWidth(); naturalSize.y = dimensions.GetHeight(); } else { - Texture brokenImage = mFactoryCache.GetBrokenVisualImage(); - + Actor actor = mPlacementActor.GetHandle(); + Vector2 imageSize = Vector2::ZERO; + if(actor) + { + imageSize = actor.GetProperty(Actor::Property::SIZE).Get(); + } + mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize); + Texture brokenImage = mImpl->mRenderer.GetTextures().GetTexture(0); naturalSize.x = brokenImage.GetWidth(); naturalSize.y = brokenImage.GetWidth(); } @@ -508,90 +530,92 @@ void ImageVisual::GetNaturalSize( Vector2& naturalSize ) naturalSize = Vector2::ZERO; } -void ImageVisual::CreateRenderer( TextureSet& textureSet ) +void ImageVisual::OnInitialize() { Geometry geometry; - Shader shader; - if( !mImpl->mCustomShader ) + // Get the geometry + if(mImpl->mCustomShader) { - geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) ); - - shader = mImageVisualShaderFactory.GetShader( mFactoryCache, - mImpl->mFlags & Impl::IS_ATLASING_APPLIED, - mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE, - IsRoundedCornerRequired() ); + geometry = CreateGeometry(mFactoryCache, mImpl->mCustomShader->mGridSize); } - else + else // Get any geometry associated with the texture { - geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize ); - if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() ) - { - // Use custom hints - shader = Shader::New( mImageVisualShaderFactory.GetVertexShaderSource(), mImageVisualShaderFactory.GetFragmentShaderSource(), mImpl->mCustomShader->mHints ); - shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT ); - } - else + TextureManager& textureManager = mFactoryCache.GetTextureManager(); + + uint32_t firstElementCount{0u}; + uint32_t secondElementCount{0u}; + geometry = textureManager.GetRenderGeometry(mTextureId, firstElementCount, secondElementCount); + + if(!firstElementCount && !secondElementCount) // Otherwise use quad { - shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource() : mImpl->mCustomShader->mVertexShader, - mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource() : mImpl->mCustomShader->mFragmentShader, - mImpl->mCustomShader->mHints ); - if( mImpl->mCustomShader->mVertexShader.empty() ) - { - shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT ); - } + geometry = CreateGeometry(mFactoryCache, ImageDimensions(1, 1)); } } - // Set pixel align off as default. - // ToDo: Pixel align causes issues such as rattling image animation. - // We should trun it off until issues are resolved - shader.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF ); - - mImpl->mRenderer = Renderer::New( geometry, shader ); - if( textureSet ) + // Increase reference count of External Resources : + // EncodedImageBuffer or ExternalTextures. + // Reference count will be decreased at destructor of the visual. + if(mImageUrl.IsValid() && (mImageUrl.IsBufferResource() || mImageUrl.GetProtocolType() == VisualUrl::TEXTURE)) { - mImpl->mRenderer.SetTextures( textureSet ); + TextureManager& textureManager = mFactoryCache.GetTextureManager(); + textureManager.UseExternalResource(mImageUrl.GetUrl()); } - // else still waiting for texture load to finish. + + Shader shader = GenerateShader(); + + // Create the renderer + mImpl->mRenderer = Renderer::New(geometry, shader); //Register transform properties - mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); + mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT); - EnablePreMultipliedAlpha( IsPreMultipliedAlphaEnabled() ); + EnablePreMultipliedAlpha(IsPreMultipliedAlphaEnabled()); } -void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection, - TextureManager::ReloadPolicy forceReload ) +void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection, TextureManager::ReloadPolicy forceReload) { TextureManager& textureManager = mFactoryCache.GetTextureManager(); - ImageAtlasManagerPtr atlasManager = nullptr; + ImageAtlasManagerPtr atlasManager = nullptr; AtlasUploadObserver* atlasUploadObserver = nullptr; - auto textureObserver = this; + auto textureObserver = this; - if( atlasing ) + if(atlasing) { - atlasManager = mFactoryCache.GetAtlasManager(); + atlasManager = mFactoryCache.GetAtlasManager(); atlasUploadObserver = this; } auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader - ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD - : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD + : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; - textures = textureManager.LoadTexture( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, - mMaskingData, IsSynchronousLoadingRequired(), mTextureId, - atlasRect, mAtlasRectSize, atlasing, mLoading, mWrapModeU, - mWrapModeV, textureObserver, atlasUploadObserver, atlasManager, - mOrientationCorrection, forceReload, preMultiplyOnLoad); + bool synchronousLoading = IsSynchronousLoadingRequired(); + bool loadingStatus; + + textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mTextureId, atlasRect, mAtlasRectSize, atlasing, loadingStatus, mWrapModeU, mWrapModeV, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection, forceReload, preMultiplyOnLoad); + + if(textures) + { + if(loadingStatus) + { + mLoadState = TextureManager::LoadState::LOADING; + } + else + { + mLoadState = TextureManager::LoadState::LOAD_FINISHED; + } - if( textures ) + EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD); + } + else if(synchronousLoading) { - EnablePreMultipliedAlpha( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ); + // Synchronous loading is failed + mLoadState = TextureManager::LoadState::LOAD_FAILED; } - if( atlasing ) // Flag needs to be set before creating renderer + if(atlasing) // Flag needs to be set before creating renderer { mImpl->mFlags |= Impl::IS_ATLASING_APPLIED; } @@ -603,47 +627,67 @@ void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& t bool ImageVisual::AttemptAtlasing() { - return ( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL && mAttemptAtlasing ); + return (!mImpl->mCustomShader && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()) && mAttemptAtlasing); } void ImageVisual::InitializeRenderer() { auto attemptAtlasing = AttemptAtlasing(); - // texture set has to be created first as we need to know if atlasing succeeded or not - // when selecting the shader - if( mTextureId == TextureManager::INVALID_TEXTURE_ID && ! mTextures ) // Only load the texture once + // Load Texture if mTextures is empty. + // mTextures is already set, the mTexture can be used to create Renderer. + // There are two cases mTextures is empty. + // 1. mTextureId == TextureManager::INVALID_TEXTURE_ID + // - Visual is on stage with LoadPolicy::ATTACHED + // 2. mTextureId != TextureManager::INVALID_TEXTURE_ID + // - If ReleasePolicy is DESTROYED, InitializeRenderer called every on stage called. + // - Then every resources those contained in Visual are Reset but mTextureId is remained when the Off stage time, + // - So, mTextures needed to be get from texture manager to created resources like mImpl->mRenderer. + if(!mTextures) { - LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, - TextureManager::ReloadPolicy::CACHED ); + if(mTextureId == TextureManager::INVALID_TEXTURE_ID) + { + LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::CACHED); + } + else + { + mTextures = mFactoryCache.GetTextureManager().GetTextureSet(mTextureId); + } } - CreateRenderer( mTextures ); - mTextures.Reset(); // Visual should not keep a handle to the texture after this point. + if(mTextures) + { + mImpl->mRenderer.SetTextures(mTextures); + if(DevelTexture::IsNative(mTextures.GetTexture(0))) + { + UpdateShader(); + } + mTextures.Reset(); // Visual should not keep a handle to the texture after this point. + } - if( attemptAtlasing ) // the texture is packed inside atlas + if(attemptAtlasing) // the texture is packed inside atlas { - mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect ); + mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect); bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE; - if( !defaultWrapMode ) // custom wrap mode + if(!defaultWrapMode) // custom wrap mode { - Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE); - wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) ); - mImpl->mRenderer.RegisterProperty( WRAP_MODE_UNIFORM_NAME, wrapMode ); + Vector2 wrapMode(mWrapModeU - WrapMode::CLAMP_TO_EDGE, mWrapModeV - WrapMode::CLAMP_TO_EDGE); + wrapMode.Clamp(Vector2::ZERO, Vector2(2.f, 2.f)); + mImpl->mRenderer.RegisterProperty(WRAP_MODE_UNIFORM_NAME, wrapMode); } } } -void ImageVisual::DoSetOnStage( Actor& actor ) +void ImageVisual::DoSetOnScene(Actor& actor) { - if( mImageUrl.IsValid() ) + if(mImageUrl.IsValid()) { InitializeRenderer(); } - if( !mImpl->mRenderer ) + if(!mImpl->mRenderer) { return; } @@ -651,101 +695,116 @@ void ImageVisual::DoSetOnStage( Actor& actor ) mPlacementActor = actor; // Search the Actor tree to find if Layer UI behaviour set. Layer layer = actor.GetLayer(); - if( layer && layer.GetProperty( Layer::Property::BEHAVIOR ) == Layer::LAYER_3D ) + if(layer && layer.GetProperty(Layer::Property::BEHAVIOR) == Layer::LAYER_3D) { - // Layer 3D set, do not align pixels - mImpl->mRenderer.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF ); + // Layer 3D set, do not align pixels + mImpl->mRenderer.RegisterProperty(PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF); } - if( mPixelArea != FULL_TEXTURE_RECT ) + if(mPixelArea != FULL_TEXTURE_RECT) { - mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea ); + mImpl->mRenderer.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, mPixelArea); } - if( mLoading == false ) + if(mLoadState == TextureManager::LoadState::LOAD_FINISHED) { - actor.AddRenderer( mImpl->mRenderer ); + actor.AddRenderer(mImpl->mRenderer); mPlacementActor.Reset(); // Image loaded and ready to display - ResourceReady( Toolkit::Visual::ResourceStatus::READY ); + ResourceReady(Toolkit::Visual::ResourceStatus::READY); + } + else if(mLoadState == TextureManager::LoadState::LOAD_FAILED) + { + Vector2 imageSize = Vector2::ZERO; + if(actor) + { + imageSize = actor.GetProperty(Actor::Property::SIZE).Get(); + } + mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize); + actor.AddRenderer(mImpl->mRenderer); + mPlacementActor.Reset(); + + ResourceReady(Toolkit::Visual::ResourceStatus::FAILED); } } -void ImageVisual::DoSetOffStage( Actor& actor ) +void ImageVisual::DoSetOffScene(Actor& actor) { - // Visual::Base::SetOffStage only calls DoSetOffStage if mRenderer exists (is on onstage) + // Visual::Base::SetOffScene only calls DoSetOffScene if mRenderer exists (is on onstage) - // Image release is dependent on the ReleasePolicy, renderer is destroyed. - actor.RemoveRenderer( mImpl->mRenderer); - if( mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED ) + // Image release is dependent on the ReleasePolicy, renderer is removed. + actor.RemoveRenderer(mImpl->mRenderer); + if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED) { RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING; + + TextureSet textureSet = TextureSet::New(); + mImpl->mRenderer.SetTextures(textureSet); + + mLoadState = TextureManager::LoadState::NOT_STARTED; } - mLoading = false; - mImpl->mRenderer.Reset(); mPlacementActor.Reset(); } -void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const +void ImageVisual::DoCreatePropertyMap(Property::Map& map) const { map.Clear(); - map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE ); + map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE); bool sync = IsSynchronousLoadingRequired(); - map.Insert( SYNCHRONOUS_LOADING, sync ); - if( mImageUrl.IsValid() ) + map.Insert(SYNCHRONOUS_LOADING, sync); + if(mImageUrl.IsValid()) { - map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() ); - map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() ); - map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() ); + map.Insert(Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl()); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth()); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight()); } - map.Insert( Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode ); - map.Insert( Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode ); + map.Insert(Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode); + map.Insert(Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode); - map.Insert( Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea ); - map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU ); - map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV ); + map.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea); + map.Insert(Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU); + map.Insert(Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV); - map.Insert( Toolkit::ImageVisual::Property::ATLASING, mAttemptAtlasing ); + map.Insert(Toolkit::ImageVisual::Property::ATLASING, mAttemptAtlasing); - if( mMaskingData != NULL ) + if(mMaskingData != NULL) { - map.Insert( Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl() ); - map.Insert( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor ); - map.Insert( Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask ); + map.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl()); + map.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor); + map.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask); } - map.Insert( Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy ); - map.Insert( Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy ); - map.Insert( Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, mOrientationCorrection ); + map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy); + map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy); + map.Insert(Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, mOrientationCorrection); } -void ImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const +void ImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const { map.Clear(); - map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE ); - if( mImageUrl.IsValid() ) + map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE); + if(mImageUrl.IsValid()) { - map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() ); - map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() ); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth()); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight()); } } -void ImageVisual::OnDoAction( const Dali::Property::Index actionName, const Dali::Property::Value& attributes ) +void ImageVisual::OnDoAction(const Dali::Property::Index actionName, const Dali::Property::Value& attributes) { // Check if action is valid for this visual type and perform action if possible - switch ( actionName ) + switch(actionName) { case DevelImageVisual::Action::RELOAD: { auto attemptAtlasing = AttemptAtlasing(); - LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, - TextureManager::ReloadPolicy::FORCED ); + LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::FORCED); break; } } @@ -753,16 +812,25 @@ void ImageVisual::OnDoAction( const Dali::Property::Index actionName, const Dali void ImageVisual::OnSetTransform() { - if( mImpl->mRenderer ) + if(mImpl->mRenderer) { - mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); + mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT); } } bool ImageVisual::IsResourceReady() const { - return ( mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY || - mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED ); + return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY || + mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED); +} + +void ImageVisual::UpdateShader() +{ + if(mImpl->mRenderer) + { + Shader shader = GenerateShader(); + mImpl->mRenderer.SetShader(shader); + } } // From existing atlas manager @@ -771,101 +839,216 @@ void ImageVisual::UploadCompleted() // Texture has been uploaded. If weak handle is holding a placement actor, // it is the time to add the renderer to actor. Actor actor = mPlacementActor.GetHandle(); - if( actor ) + if(actor) { - mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect ); - actor.AddRenderer( mImpl->mRenderer ); + mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect); + actor.AddRenderer(mImpl->mRenderer); // reset the weak handle so that the renderer only get added to actor once mPlacementActor.Reset(); } + // Image loaded - ResourceReady( Toolkit::Visual::ResourceStatus::READY ); - mLoading = false; + ResourceReady(Toolkit::Visual::ResourceStatus::READY); + mLoadState = TextureManager::LoadState::LOAD_FINISHED; } // From Texture Manager -void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, TextureSet textureSet, bool usingAtlas, - const Vector4& atlasRectangle, bool preMultiplied ) +void ImageVisual::UploadComplete(bool loadingSuccess, int32_t textureId, TextureSet textureSet, bool usingAtlas, const Vector4& atlasRectangle, bool preMultiplied) { Toolkit::Visual::ResourceStatus resourceStatus; - if( mImpl->mRenderer ) + if(mImpl->mRenderer) { - if( usingAtlas ) + if(usingAtlas) { - mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect ); + mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect); } - EnablePreMultipliedAlpha( preMultiplied ); + EnablePreMultipliedAlpha(preMultiplied); Actor actor = mPlacementActor.GetHandle(); - if( actor ) + if(!loadingSuccess) { - actor.AddRenderer( mImpl->mRenderer ); - // reset the weak handle so that the renderer only get added to actor once - mPlacementActor.Reset(); + Vector2 imageSize = Vector2::ZERO; + if(actor) + { + imageSize = actor.GetProperty(Actor::Property::SIZE).Get(); + } + mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize); + textureSet = mImpl->mRenderer.GetTextures(); } - - if( !loadingSuccess ) + else { - Texture brokenImage = mFactoryCache.GetBrokenVisualImage(); - - textureSet = TextureSet::New(); - textureSet.SetTexture(0u, brokenImage); - mImpl->mRenderer.SetTextures( textureSet ); + Sampler sampler = Sampler::New(); + sampler.SetWrapMode(mWrapModeU, mWrapModeV); + textureSet.SetSampler(0u, sampler); + mImpl->mRenderer.SetTextures(textureSet); } - Sampler sampler = Sampler::New(); - sampler.SetWrapMode( mWrapModeU, mWrapModeV ); - textureSet.SetSampler( 0u, sampler ); - mImpl->mRenderer.SetTextures(textureSet); - + if(actor) + { + actor.AddRenderer(mImpl->mRenderer); + // reset the weak handle so that the renderer only get added to actor once + mPlacementActor.Reset(); + } } // Storing TextureSet needed when renderer staged. - if( ! mImpl->mRenderer ) + if(!mImpl->mRenderer) { mTextures = textureSet; } // Image loaded, set status regardless of staged status. - if( loadingSuccess ) + if(loadingSuccess) { resourceStatus = Toolkit::Visual::ResourceStatus::READY; + mLoadState = TextureManager::LoadState::LOAD_FINISHED; } else { resourceStatus = Toolkit::Visual::ResourceStatus::FAILED; + mLoadState = TextureManager::LoadState::LOAD_FAILED; } + + // use geometry if needed + if(loadingSuccess) + { + uint32_t firstElementCount{0u}; + uint32_t secondElementCount{0u}; + auto geometry = mFactoryCache.GetTextureManager().GetRenderGeometry(mTextureId, firstElementCount, secondElementCount); + if(mImpl->mRenderer && geometry) + { + mImpl->mRenderer.SetGeometry(geometry); + Dali::DevelRenderer::DrawCommand drawCommand{}; + drawCommand.drawType = DevelRenderer::DrawType::INDEXED; + + if(firstElementCount) + { + drawCommand.firstIndex = 0; + drawCommand.elementCount = firstElementCount; + drawCommand.queue = DevelRenderer::RENDER_QUEUE_OPAQUE; + DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand); + } + + if(secondElementCount) + { + drawCommand.firstIndex = firstElementCount; + drawCommand.elementCount = secondElementCount; + drawCommand.queue = DevelRenderer::RENDER_QUEUE_TRANSPARENT; + DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand); + } + } + } + // Signal to observers ( control ) that resources are ready. Must be all resources. - ResourceReady( resourceStatus ); - mLoading = false; + ResourceReady(resourceStatus); } void ImageVisual::RemoveTexture() { - if( mTextureId != TextureManager::INVALID_TEXTURE_ID ) + if(mTextureId != TextureManager::INVALID_TEXTURE_ID) { - mFactoryCache.GetTextureManager().Remove( mTextureId, this ); + mFactoryCache.GetTextureManager().Remove(mTextureId, this); mTextureId = TextureManager::INVALID_TEXTURE_ID; } else { - Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f ); - Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME ); - if( index != Property::INVALID_INDEX ) + Vector4 atlasRect(0.f, 0.f, 1.f, 1.f); + Property::Index index = mImpl->mRenderer.GetPropertyIndex(ATLAS_RECT_UNIFORM_NAME); + if(index != Property::INVALID_INDEX) { - Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index ); - atlasRectValue.Get( atlasRect ); + Property::Value atlasRectValue = mImpl->mRenderer.GetProperty(index); + atlasRectValue.Get(atlasRect); } TextureSet textureSet = mImpl->mRenderer.GetTextures(); - mImpl->mRenderer.Reset(); - if( index != Property::INVALID_INDEX ) + if(index != Property::INVALID_INDEX) + { + mFactoryCache.GetAtlasManager()->Remove(textureSet, atlasRect); + } + } +} + +Shader ImageVisual::GenerateShader() const +{ + Shader shader; + + bool usesWholeTexture = true; + const bool useStandardShader = !mImpl->mCustomShader; + const bool useNativeImage = (mTextures && DevelTexture::IsNative(mTextures.GetTexture(0))); + + if(useStandardShader) + { + // Create and cache the standard shader + shader = mImageVisualShaderFactory.GetShader( + mFactoryCache, + ImageVisualShaderFeature::FeatureBuilder() + .EnableTextureAtlas(mImpl->mFlags & Impl::IS_ATLASING_APPLIED && !useNativeImage) + .ApplyDefaultTextureWrapMode(mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE) + .EnableRoundedCorner(IsRoundedCornerRequired()) + .EnableBorderline(IsBorderlineRequired()) + .SetTextureForFragmentShaderCheck(useNativeImage ? mTextures.GetTexture(0) : Dali::Texture()) + ); + } + else + { + std::string_view vertexShaderView; + std::string_view fragmentShaderView; + + if(mImpl->mCustomShader && !mImpl->mCustomShader->mVertexShader.empty()) + { + vertexShaderView = mImpl->mCustomShader->mVertexShader; + usesWholeTexture = false; // Impossible to tell. + } + else + { + vertexShaderView = mImageVisualShaderFactory.GetVertexShaderSource(); + } + + if(mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty()) + { + fragmentShaderView = mImpl->mCustomShader->mFragmentShader; + } + else + { + fragmentShaderView = mImageVisualShaderFactory.GetFragmentShaderSource(); + } + + // If the texture is native, we may need to change prefix and sampler in + // the fragment shader + if(useNativeImage) { - mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect ); + bool modifiedFragmentShader = false; + Texture nativeTexture = mTextures.GetTexture(0); + std::string fragmentShaderString = std::string(fragmentShaderView); + + modifiedFragmentShader = DevelTexture::ApplyNativeFragmentShader(nativeTexture, fragmentShaderString); + if(modifiedFragmentShader) + { + fragmentShaderView = fragmentShaderString; + } + + // Create shader here cause fragmentShaderString scope issue + shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints); + } + else + { + shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints); } } + + if(usesWholeTexture) + { + shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT); + } + + // Set pixel align off as default. + // ToDo: Pixel align causes issues such as rattling image animation. + // We should trun it off until issues are resolved + shader.RegisterProperty(PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF); + + return shader; } } // namespace Internal