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=44c9fac851bc3d770aa871ee104bc344eb176d6e;hp=b8abd9b2e1c9fff4ab14b09c50b96b681133e880;hb=ba1c6fea08ea39ca92356ae4b39a952919398e7e;hpb=9637b6f3d8d77b6ccb1cff1e0ec5a0d37e82b2ea diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index b8abd9b..44c9fac 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) 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. @@ -19,98 +19,99 @@ #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 +#include namespace Dali { - namespace Toolkit { - namespace Internal { - namespace { +const int CUSTOM_PROPERTY_COUNT(12); // ltr, wrap, pixel area, atlas, pixalign, crop to mask, mask texture ratio + border/corner // 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 ) +constexpr uint32_t TEXTURE_COUNT_FOR_GPU_ALPHA_MASK = 2u; + +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; @@ -118,183 +119,205 @@ 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); + } + } + + 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.Remove( mMaskingData->mAlphaMaskId, this ); + textureManager.RemoveEncodedImageBuffer(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); + } + else if(keyValue.first == IMAGE_SAMPLING_MODE) { - DoSetProperty( Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second); } - else if( keyValue.first == IMAGE_SAMPLING_MODE ) + else if(keyValue.first == IMAGE_DESIRED_WIDTH) { - DoSetProperty( Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second); } - else if( keyValue.first == IMAGE_DESIRED_WIDTH ) + else if(keyValue.first == IMAGE_DESIRED_HEIGHT) { - DoSetProperty( Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second); } - else if( keyValue.first == IMAGE_DESIRED_HEIGHT ) + else if(keyValue.first == PIXEL_AREA_UNIFORM_NAME) { - DoSetProperty( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second); } - else if( keyValue.first == PIXEL_AREA_UNIFORM_NAME ) + else if(keyValue.first == IMAGE_WRAP_MODE_U) { - DoSetProperty( Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second); } - else if( keyValue.first == IMAGE_WRAP_MODE_U ) + else if(keyValue.first == IMAGE_WRAP_MODE_V) { - DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second); } - else if( keyValue.first == IMAGE_WRAP_MODE_V ) + else if(keyValue.first == SYNCHRONOUS_LOADING) { - DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second); } - else if( keyValue.first == SYNCHRONOUS_LOADING ) + else if(keyValue.first == IMAGE_ATLASING) { - DoSetProperty( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::ATLASING, keyValue.second); } - else if( keyValue.first == IMAGE_ATLASING ) + else if(keyValue.first == ALPHA_MASK_URL) { - DoSetProperty( Toolkit::ImageVisual::Property::ATLASING, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second); } - else if( keyValue.first == ALPHA_MASK_URL ) + else if(keyValue.first == MASK_CONTENT_SCALE_NAME) { - DoSetProperty( Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second); } - else if( keyValue.first == MASK_CONTENT_SCALE_NAME ) + else if(keyValue.first == CROP_TO_MASK_NAME) { - DoSetProperty( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second ); + DoSetProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second); } - else if( keyValue.first == CROP_TO_MASK_NAME ) + else if(keyValue.first == MASKING_TYPE_NAME) { - DoSetProperty( Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second ); + DoSetProperty(Toolkit::DevelImageVisual::Property::MASKING_TYPE, 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; + mImpl->mFlags |= Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; } else { - mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; + mImpl->mFlags &= ~Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; } } else @@ -307,9 +330,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 { @@ -321,9 +344,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 { @@ -335,51 +358,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; @@ -390,7 +413,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; @@ -400,8 +423,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; @@ -409,25 +432,36 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v break; } + case Toolkit::DevelImageVisual::Property::MASKING_TYPE: + { + int maskingType = 0; + if(value.Get(maskingType)) + { + AllocateMaskData(); + mMaskingData->mPreappliedMasking = Toolkit::DevelImageVisual::MaskingType::Type(maskingType) == Toolkit::DevelImageVisual::MaskingType::MASKING_ON_LOADING ? true : false; + } + break; + } + 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; } @@ -438,23 +472,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 & Visual::Base::Impl::IS_ATLASING_APPLIED) { naturalSize.x = mAtlasRectSize.GetWidth(); naturalSize.y = mAtlasRectSize.GetHeight(); @@ -462,46 +496,50 @@ void ImageVisual::GetNaturalSize( Vector2& naturalSize ) } auto textureSet = mImpl->mRenderer.GetTextures(); - if( textureSet ) + if(textureSet && textureSet.GetTextureCount()) { - auto texture = textureSet.GetTexture(0); - if( texture ) + if(mTextureSize != Vector2::ZERO) { - naturalSize.x = texture.GetWidth(); - naturalSize.y = texture.GetHeight(); + naturalSize = mTextureSize; return; } } } - 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(); - - naturalSize.x = brokenImage.GetWidth(); - naturalSize.y = brokenImage.GetWidth(); + 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(); } return; } @@ -509,110 +547,110 @@ 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, mImpl->mCustomShader->mGridSize); + } + else // Get any geometry associated with the texture { TextureManager& textureManager = mFactoryCache.GetTextureManager(); - uint32_t firstElementCount {0u}; - uint32_t secondElementCount {0u}; + uint32_t firstElementCount{0u}; + uint32_t secondElementCount{0u}; geometry = textureManager.GetRenderGeometry(mTextureId, firstElementCount, secondElementCount); - if(!firstElementCount && !secondElementCount) - { - 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() ); - } - else - { - geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize ); - if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() ) + if(!firstElementCount && !secondElementCount) // Otherwise use quad { - // Use custom hints - shader = Shader::New( mImageVisualShaderFactory.GetVertexShaderSource(), mImageVisualShaderFactory.GetFragmentShaderSource(), mImpl->mCustomShader->mHints ); - shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT ); - } - else - { - 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 = VisualRenderer::New(geometry, shader); + mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT); //Register transform properties - mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); + mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT); - EnablePreMultipliedAlpha( IsPreMultipliedAlphaEnabled() ); + EnablePreMultipliedAlpha(IsPreMultipliedAlphaEnabled()); + + if(mMaskingData) + { + mImpl->mRenderer.RegisterProperty(CROP_TO_MASK_NAME, static_cast(mMaskingData->mCropToMask)); + } } -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; + mImpl->mFlags |= Visual::Base::Impl::IS_ATLASING_APPLIED; } else { - mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED; + mImpl->mFlags &= ~Visual::Base::Impl::IS_ATLASING_APPLIED; } } bool ImageVisual::AttemptAtlasing() { - return ( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL && mAttemptAtlasing ); + return (!mImpl->mCustomShader && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()) && mAttemptAtlasing); } void ImageVisual::InitializeRenderer() @@ -628,45 +666,53 @@ void ImageVisual::InitializeRenderer() // - 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 ) + if(!mTextures) { - if( mTextureId == TextureManager::INVALID_TEXTURE_ID ) + if(mTextureId == TextureManager::INVALID_TEXTURE_ID) { - LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, - TextureManager::ReloadPolicy::CACHED ); + LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::CACHED); } else { - mTextures = mFactoryCache.GetTextureManager().GetTextureSet( mTextureId ); + 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); + ComputeTextureSize(); + CheckMaskTexture(); + 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::DoSetOnScene( Actor& actor ) +void ImageVisual::DoSetOnScene(Actor& actor) { - if( mImageUrl.IsValid() ) + if(mImageUrl.IsValid()) { InitializeRenderer(); } - if( !mImpl->mRenderer ) + if(!mImpl->mRenderer) { return; } @@ -674,101 +720,118 @@ void ImageVisual::DoSetOnScene( 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::DoSetOffScene( Actor& actor ) +void ImageVisual::DoSetOffScene(Actor& actor) { // 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); + ComputeTextureSize(); + + 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(Toolkit::ImageVisual::Property::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::DevelImageVisual::Property::MASKING_TYPE, mMaskingData->mPreappliedMasking ? DevelImageVisual::MaskingType::MASKING_ON_LOADING : DevelImageVisual::MaskingType::MASKING_ON_RENDERING); } - 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 actionId, const Dali::Property::Value& attributes) { // Check if action is valid for this visual type and perform action if possible - switch ( actionName ) + switch(actionId) { case DevelImageVisual::Action::RELOAD: { auto attemptAtlasing = AttemptAtlasing(); - LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, - TextureManager::ReloadPolicy::FORCED ); + LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::FORCED); break; } } @@ -776,16 +839,19 @@ 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.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT); } } -bool ImageVisual::IsResourceReady() const +void ImageVisual::UpdateShader() { - return ( mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY || - mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED ); + if(mImpl->mRenderer) + { + Shader shader = GenerateShader(); + mImpl->mRenderer.SetShader(shader); + } } // From existing atlas manager @@ -794,130 +860,294 @@ 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::LoadComplete(bool loadingSuccess, TextureInformation textureInformation) { Toolkit::Visual::ResourceStatus resourceStatus; - if( mImpl->mRenderer ) + if(mImpl->mRenderer) { - if( usingAtlas ) + if(textureInformation.useAtlasing) { - mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect ); + mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect); } - EnablePreMultipliedAlpha( preMultiplied ); + EnablePreMultipliedAlpha(textureInformation.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); + textureInformation.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); + textureInformation.textureSet.SetSampler(0u, sampler); + mImpl->mRenderer.SetTextures(textureInformation.textureSet); + ComputeTextureSize(); + CheckMaskTexture(); } - 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; + mTextures = textureInformation.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 ) + if(loadingSuccess) { uint32_t firstElementCount{0u}; uint32_t secondElementCount{0u}; - auto geometry = mFactoryCache.GetTextureManager().GetRenderGeometry(mTextureId, firstElementCount, secondElementCount); - if (mImpl->mRenderer && geometry) + 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) + if(firstElementCount) { - drawCommand.firstIndex = 0; + drawCommand.firstIndex = 0; drawCommand.elementCount = firstElementCount; - drawCommand.queue = DevelRenderer::RENDER_QUEUE_OPAQUE; + drawCommand.queue = DevelRenderer::RENDER_QUEUE_OPAQUE; DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand); } - if (secondElementCount) + if(secondElementCount) { - drawCommand.firstIndex = firstElementCount; + drawCommand.firstIndex = firstElementCount; drawCommand.elementCount = secondElementCount; - drawCommand.queue = DevelRenderer::RENDER_QUEUE_TRANSPARENT; + 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); + } + } +} + +void ImageVisual::ComputeTextureSize() +{ + if(mImpl->mRenderer) + { + auto textureSet = mImpl->mRenderer.GetTextures(); + if(textureSet && textureSet.GetTextureCount()) + { + auto texture = textureSet.GetTexture(0); + if(texture) + { + mTextureSize.x = texture.GetWidth(); + mTextureSize.y = texture.GetHeight(); + if(textureSet.GetTextureCount() > 1u && mMaskingData && !mMaskingData->mPreappliedMasking && mMaskingData->mCropToMask) + { + Texture maskTexture = textureSet.GetTexture(1); + if(maskTexture) + { + mTextureSize.x = std::min(static_cast(mTextureSize.x * mMaskingData->mContentScaleFactor), maskTexture.GetWidth()); + mTextureSize.y = std::min(static_cast(mTextureSize.y * mMaskingData->mContentScaleFactor), maskTexture.GetHeight()); + } + } + } + } + } +} + +Vector2 ImageVisual::ComputeMaskTextureRatio() +{ + Vector2 maskTextureRatio; + if(mImpl->mRenderer) + { + auto textureSet = mImpl->mRenderer.GetTextures(); + if(textureSet && textureSet.GetTextureCount()) + { + auto texture = textureSet.GetTexture(0); + if(texture) + { + if(textureSet.GetTextureCount() > 1u && mMaskingData && !mMaskingData->mPreappliedMasking && mMaskingData->mCropToMask) + { + Texture maskTexture = textureSet.GetTexture(1); + if(maskTexture) + { + float textureWidth = std::max(static_cast(texture.GetWidth() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1); + float textureHeight = std::max(static_cast(texture.GetHeight() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1); + maskTextureRatio = Vector2(std::min(static_cast(maskTexture.GetWidth()), textureWidth) / textureWidth, + std::min(static_cast(maskTexture.GetHeight()), textureHeight) / textureHeight); + } + } + } + } + } + return maskTextureRatio; +} + +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) + { + bool requiredAlphaMaskingOnRendering = (mMaskingData && !mMaskingData->mMaskImageLoadingFailed) ? !mMaskingData->mPreappliedMasking : false; + // Create and cache the standard shader + shader = mImageVisualShaderFactory.GetShader( + mFactoryCache, + ImageVisualShaderFeature::FeatureBuilder() + .EnableTextureAtlas(mImpl->mFlags & Visual::Base::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()) + .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering)); + } + 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) + { + 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; +} + +void ImageVisual::CheckMaskTexture() +{ + if(mMaskingData && !mMaskingData->mPreappliedMasking) + { + bool maskLoadFailed = true; + TextureSet textures = mImpl->mRenderer.GetTextures(); + if(textures && textures.GetTextureCount() >= TEXTURE_COUNT_FOR_GPU_ALPHA_MASK) + { + if(mMaskingData->mCropToMask) + { + mImpl->mRenderer.RegisterProperty(MASK_TEXTURE_RATIO_NAME, ComputeMaskTextureRatio()); + } + maskLoadFailed = false; + } + + if(mMaskingData->mMaskImageLoadingFailed != maskLoadFailed) { - mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect ); + mMaskingData->mMaskImageLoadingFailed = maskLoadFailed; + UpdateShader(); } } }