Fix resource ready state
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / image / image-visual.cpp
index 6f3231d..3a91784 100644 (file)
@@ -23,6 +23,8 @@
 #include <dali/public-api/actors/layer.h>
 #include <dali/devel-api/common/stage.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/devel-api/rendering/texture-devel.h>
 #include <dali/devel-api/scripting/enum-helper.h>
 #include <dali/devel-api/scripting/scripting.h>
 #include <dali/integration-api/debug.h>
@@ -40,7 +42,6 @@
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
 #include <dali-toolkit/internal/visuals/visual-url.h>
 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
-#include <dali/devel-api/rendering/renderer-devel.h>
 
 namespace Dali
 {
@@ -142,32 +143,32 @@ ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache,
   return new ImageVisual( factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode );
 }
 
-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() );
 }
@@ -512,52 +513,31 @@ void ImageVisual::GetNaturalSize( Vector2& naturalSize )
 void ImageVisual::CreateRenderer( TextureSet& textureSet )
 {
   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 opaqueElementsCount {0u};
-    uint32_t transparentElementsCount {0u};
-    geometry = textureManager.GetRenderGeometry(mTextureId, opaqueElementsCount, transparentElementsCount);
-    if(!opaqueElementsCount && !transparentElementsCount)
-    {
-      geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
-    }
+    uint32_t firstElementCount {0u};
+    uint32_t secondElementCount {0u};
+    geometry = textureManager.GetRenderGeometry(mTextureId, firstElementCount, secondElementCount);
 
-    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() )
-    {
-      // Use custom hints
-      shader = Shader::New( mImageVisualShaderFactory.GetVertexShaderSource(), mImageVisualShaderFactory.GetFragmentShaderSource(), mImpl->mCustomShader->mHints );
-      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
-    }
-    else
+    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 );
+  Shader shader = GetShader();
 
+  // Create the renderer
   mImpl->mRenderer = Renderer::New( geometry, shader );
+
   if( textureSet )
   {
     mImpl->mRenderer.SetTextures( textureSet );
@@ -570,6 +550,7 @@ void ImageVisual::CreateRenderer( TextureSet& textureSet )
   EnablePreMultipliedAlpha( IsPreMultipliedAlphaEnabled() );
 }
 
+
 void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection,
                                TextureManager::ReloadPolicy forceReload )
 {
@@ -589,16 +570,29 @@ void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& t
     ? 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;
+    }
+
     EnablePreMultipliedAlpha( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD );
   }
+  else if(synchronousLoading)
+  {
+    // Synchronous loading is failed
+    mLoadState = TextureManager::LoadState::LOAD_FAILED;
+  }
 
   if( atlasing ) // Flag needs to be set before creating renderer
   {
@@ -685,7 +679,7 @@ void ImageVisual::DoSetOnScene( Actor& actor )
     mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
   }
 
-  if( mLoading == false )
+  if(mLoadState == TextureManager::LoadState::LOAD_FINISHED)
   {
     actor.AddRenderer( mImpl->mRenderer );
     mPlacementActor.Reset();
@@ -693,6 +687,19 @@ void ImageVisual::DoSetOnScene( Actor& actor )
     // Image loaded and ready to display
     ResourceReady( Toolkit::Visual::ResourceStatus::READY );
   }
+  else if(mLoadState == TextureManager::LoadState::LOAD_FAILED)
+  {
+    Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
+
+    mTextures = TextureSet::New();
+    mTextures.SetTexture(0u, brokenImage);
+    mImpl->mRenderer.SetTextures(mTextures);
+
+    actor.AddRenderer(mImpl->mRenderer);
+    mPlacementActor.Reset();
+
+    ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
+  }
 }
 
 void ImageVisual::DoSetOffScene( Actor& actor )
@@ -705,9 +712,10 @@ void ImageVisual::DoSetOffScene( Actor& actor )
   {
     RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
     mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
+
+    mLoadState = TextureManager::LoadState::NOT_STARTED;
   }
 
-  mLoading = false;
   mImpl->mRenderer.Reset();
   mPlacementActor.Reset();
 }
@@ -788,6 +796,15 @@ bool ImageVisual::IsResourceReady() const
            mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED );
 }
 
+void ImageVisual::UpdateShader()
+{
+  if(mImpl->mRenderer)
+  {
+    Shader shader = GetShader();
+    mImpl->mRenderer.SetShader(shader);
+  }
+}
+
 // From existing atlas manager
 void ImageVisual::UploadCompleted()
 {
@@ -801,9 +818,10 @@ void ImageVisual::UploadCompleted()
     // 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;
+  mLoadState = TextureManager::LoadState::LOAD_FINISHED;
 }
 
 // From Texture Manager
@@ -854,37 +872,39 @@ void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, Textur
   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 opaqueElements{0u};
-    uint32_t transparentElements{0u};
-    auto geometry = mFactoryCache.GetTextureManager().GetRenderGeometry(mTextureId, opaqueElements, transparentElements);
+    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 (opaqueElements)
+      if (firstElementCount)
       {
         drawCommand.firstIndex = 0;
-        drawCommand.elementCount = opaqueElements;
-        drawCommand.queue = 0;
+        drawCommand.elementCount = firstElementCount;
+        drawCommand.queue = DevelRenderer::RENDER_QUEUE_OPAQUE;
         DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand);
       }
 
-      if (transparentElements)
+      if (secondElementCount)
       {
-        drawCommand.firstIndex = opaqueElements;
-        drawCommand.elementCount = transparentElements;
-        drawCommand.queue = 1;
+        drawCommand.firstIndex = firstElementCount;
+        drawCommand.elementCount = secondElementCount;
+        drawCommand.queue = DevelRenderer::RENDER_QUEUE_TRANSPARENT;
         DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand);
       }
     }
@@ -892,7 +912,6 @@ void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, Textur
 
   // Signal to observers ( control ) that resources are ready. Must be all resources.
   ResourceReady( resourceStatus );
-  mLoading = false;
 }
 
 void ImageVisual::RemoveTexture()
@@ -922,6 +941,76 @@ void ImageVisual::RemoveTexture()
   }
 }
 
+Shader ImageVisual::GetShader()
+{
+  Shader shader;
+
+  std::string_view vertexShaderView;
+  bool usesWholeTexture = true;
+  if(mImpl->mCustomShader && !mImpl->mCustomShader->mVertexShader.empty())
+  {
+    vertexShaderView = mImpl->mCustomShader->mVertexShader;
+    usesWholeTexture = false; // Impossible to tell.
+  }
+  else
+  {
+    vertexShaderView = mImageVisualShaderFactory.GetVertexShaderSource();
+  }
+
+  std::string_view fragmentShaderView;
+  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
+  bool modifiedFragmentShader = false;
+  std::string fragmentShaderString;
+  if(mTextures && DevelTexture::IsNative(mTextures.GetTexture(0)))
+  {
+    Texture nativeTexture = mTextures.GetTexture(0);
+    fragmentShaderString   = std::string(fragmentShaderView);
+    modifiedFragmentShader = DevelTexture::ApplyNativeFragmentShader(nativeTexture, fragmentShaderString);
+    fragmentShaderView     = fragmentShaderString;
+  }
+
+  const bool useStandardShader = !mImpl->mCustomShader && !modifiedFragmentShader;
+  if(useStandardShader)
+  {
+    // Create and cache the standard shader
+    shader = mImageVisualShaderFactory.GetShader(
+      mFactoryCache,
+      mImpl->mFlags & Impl::IS_ATLASING_APPLIED,
+      mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE,
+      IsRoundedCornerRequired() );
+  }
+  else if(mImpl->mCustomShader)
+  {
+    shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints);
+  }
+  else
+  {
+    shader = Shader::New(vertexShaderView, fragmentShaderView);
+  }
+
+  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
 
 } // namespace Toolkit