Avoid shader string copy when possible.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / image / image-visual.cpp
index 16038b4..0cd4c1b 100644 (file)
 // EXTERNAL HEADERS
 #include <cstring> // for strlen()
 #include <dali/public-api/actors/layer.h>
-#include <dali/public-api/common/stage.h>
-#include <dali/devel-api/images/texture-set-image.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>
@@ -498,7 +499,7 @@ void ImageVisual::GetNaturalSize( Vector2& naturalSize )
       }
       else
       {
-        Image brokenImage = mFactoryCache.GetBrokenVisualImage();
+        Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
 
         naturalSize.x = brokenImage.GetWidth();
         naturalSize.y = brokenImage.GetWidth();
@@ -512,44 +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, 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() )
+    TextureManager& textureManager = mFactoryCache.GetTextureManager();
+
+    uint32_t firstElementCount {0u};
+    uint32_t secondElementCount {0u};
+    geometry = textureManager.GetRenderGeometry(mTextureId, firstElementCount, secondElementCount);
+
+    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 );
+  Shader shader = GetShader();
 
+  // Create the renderer
   mImpl->mRenderer = Renderer::New( geometry, shader );
+
   if( textureSet )
   {
     mImpl->mRenderer.SetTextures( textureSet );
@@ -562,6 +550,7 @@ void ImageVisual::CreateRenderer( TextureSet& textureSet )
   EnablePreMultipliedAlpha( IsPreMultipliedAlphaEnabled() );
 }
 
+
 void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection,
                                TextureManager::ReloadPolicy forceReload )
 {
@@ -610,13 +599,27 @@ bool ImageVisual::AttemptAtlasing()
 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 );
@@ -637,7 +640,7 @@ void ImageVisual::InitializeRenderer()
   }
 }
 
-void ImageVisual::DoSetOnStage( Actor& actor )
+void ImageVisual::DoSetOnScene( Actor& actor )
 {
   if( mImageUrl.IsValid() )
   {
@@ -673,9 +676,9 @@ void ImageVisual::DoSetOnStage( Actor& actor )
   }
 }
 
-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);
@@ -766,6 +769,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()
 {
@@ -806,24 +818,20 @@ void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, Textur
       mPlacementActor.Reset();
     }
 
-    if( loadingSuccess )
+    if( !loadingSuccess )
     {
-      Sampler sampler = Sampler::New();
-      sampler.SetWrapMode(  mWrapModeU, mWrapModeV  );
-      textureSet.SetSampler( 0u, sampler );
-      mImpl->mRenderer.SetTextures(textureSet);
-    }
-    else
-    {
-      Image brokenImage = mFactoryCache.GetBrokenVisualImage();
+      Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
 
       textureSet = TextureSet::New();
+      textureSet.SetTexture(0u, brokenImage);
       mImpl->mRenderer.SetTextures( textureSet );
-      TextureSetImage( textureSet, 0u, brokenImage );
-      Sampler sampler = Sampler::New();
-      sampler.SetWrapMode(  mWrapModeU, mWrapModeV  );
-      textureSet.SetSampler( 0u, sampler );
     }
+
+    Sampler sampler = Sampler::New();
+    sampler.SetWrapMode(  mWrapModeU, mWrapModeV  );
+    textureSet.SetSampler( 0u, sampler );
+    mImpl->mRenderer.SetTextures(textureSet);
+
   }
 
   // Storing TextureSet needed when renderer staged.
@@ -841,6 +849,37 @@ void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, Textur
   {
     resourceStatus = Toolkit::Visual::ResourceStatus::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;
@@ -873,6 +912,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