[dali_2.2.39] Merge branch 'devel/master' 95/297195/1
authorRichard Huang <r.huang@samsung.com>
Fri, 11 Aug 2023 09:57:04 +0000 (10:57 +0100)
committerRichard Huang <r.huang@samsung.com>
Fri, 11 Aug 2023 09:57:04 +0000 (10:57 +0100)
Change-Id: I285b74aac27fa7b4a755899fa6c3a21012cf0ce0

42 files changed:
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-ParticleSystem.cpp
dali-physics/third-party/bullet3/CMakeLists.txt
dali-toolkit/devel-api/visuals/image-visual-properties-devel.h
dali-toolkit/internal/controls/gl-view/gl-view-render-thread.cpp
dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h
dali-toolkit/internal/file.list
dali-toolkit/internal/image-loader/fast-track-loading-task.cpp [new file with mode: 0644]
dali-toolkit/internal/image-loader/fast-track-loading-task.h [new file with mode: 0644]
dali-toolkit/internal/image-loader/loading-task.cpp
dali-toolkit/internal/particle-system/particle-emitter-impl.cpp
dali-toolkit/internal/particle-system/particle-emitter-impl.h
dali-toolkit/internal/particle-system/particle-renderer-impl.cpp
dali-toolkit/internal/particle-system/particle-renderer-impl.h
dali-toolkit/internal/text/controller/text-controller-impl-model-updater.cpp
dali-toolkit/internal/text/shaper.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.h
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/svg/svg-task.cpp
dali-toolkit/internal/visuals/svg/svg-visual.cpp
dali-toolkit/internal/visuals/visual-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/public-api/particle-system/particle-emitter.cpp
dali-toolkit/public-api/particle-system/particle-emitter.h
dali-toolkit/public-api/particle-system/particle-list.cpp
dali-toolkit/public-api/particle-system/particle-list.h
dali-toolkit/public-api/particle-system/particle-modifier.cpp
dali-toolkit/public-api/particle-system/particle-modifier.h
dali-toolkit/public-api/particle-system/particle-renderer.cpp
dali-toolkit/public-api/particle-system/particle-renderer.h
packaging/dali-toolkit.spec

index 1ddb118..f11bfbf 100755 (executable)
@@ -112,6 +112,7 @@ SET(TEST_HARNESS_SOURCES
   dali-toolkit-test-utils/toolkit-physical-keyboard.cpp
   dali-toolkit-test-utils/toolkit-style-monitor.cpp
   dali-toolkit-test-utils/toolkit-test-application.cpp
+  dali-toolkit-test-utils/toolkit-texture-upload-manager.cpp
   dali-toolkit-test-utils/toolkit-timer.cpp
   dali-toolkit-test-utils/toolkit-trigger-event-factory.cpp
   dali-toolkit-test-utils/toolkit-tts-player.cpp
index 4bac7a6..527b9f4 100644 (file)
@@ -1409,4 +1409,71 @@ bool TestGraphicsController::GetProgramParameter(Graphics::Program& program, uin
   return graphicsProgram->GetParameter(parameterId, outData);
 }
 
+Graphics::Texture* TestGraphicsController::CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo)
+{
+  Graphics::Texture*                     ret = nullptr;
+  Graphics::UniquePtr<Graphics::Texture> texture;
+  TraceCallStack::NamedParams            namedParams;
+  namedParams["resourceId"] << resourceId;
+
+  auto iter = mTextureUploadBindMapper.find(resourceId);
+  DALI_ASSERT_ALWAYS(iter == mTextureUploadBindMapper.end());
+
+  // Create new graphics texture.
+  texture = CreateTexture(createInfo, std::move(texture));
+  ret     = texture.get();
+
+  mTextureUploadBindMapper.insert(std::make_pair(resourceId, std::move(texture)));
+
+  mCallStack.PushCall("CreateTextureByResourceId", "", namedParams);
+  return ret;
+}
+
+void TestGraphicsController::DiscardTextureFromResourceId(uint32_t resourceId)
+{
+  TraceCallStack::NamedParams namedParams;
+  namedParams["resourceId"] << resourceId;
+
+  mTextureUploadBindMapper.erase(resourceId);
+
+  mCallStack.PushCall("DiscardTextureFromResourceId", "", namedParams);
+}
+
+Graphics::Texture* TestGraphicsController::GetTextureFromResourceId(uint32_t resourceId)
+{
+  TraceCallStack::NamedParams namedParams;
+  namedParams["resourceId"] << resourceId;
+
+  Graphics::Texture* ret = nullptr;
+
+  auto iter = mTextureUploadBindMapper.find(resourceId);
+  if(iter != mTextureUploadBindMapper.end())
+  {
+    ret = iter->second.get();
+  }
+
+  mCallStack.PushCall("GetTextureFromResourceId", "", namedParams);
+
+  return ret;
+}
+
+Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId)
+{
+  TraceCallStack::NamedParams namedParams;
+  namedParams["resourceId"] << resourceId;
+
+  Graphics::UniquePtr<Graphics::Texture> texture;
+
+  auto iter = mTextureUploadBindMapper.find(resourceId);
+  if(iter != mTextureUploadBindMapper.end())
+  {
+    texture = std::move(iter->second);
+    mTextureUploadBindMapper.erase(iter);
+  }
+
+  mCallStack.PushCall("ReleaseTextureFromResourceId", "", namedParams);
+
+  return texture;
+}
+
 } // namespace Dali
index ade48d7..9540c3e 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <dali/graphics-api/graphics-controller.h>
+#include <unordered_map>
 #include "test-gl-abstraction.h"
 #include "test-gl-context-helper-abstraction.h"
 #include "test-graphics-command-buffer.h"
@@ -375,6 +376,53 @@ public:
    */
   bool PipelineEquals(const Graphics::Pipeline& pipeline0, const Graphics::Pipeline& pipeline1) const override;
 
+  /**
+   * @brief Retrieves program parameters
+   *
+   * This function can be used to retrieve data from internal implementation
+   *
+   * @param[in] program Valid program object
+   * @param[in] parameterId Integer parameter id
+   * @param[out] outData Pointer to output memory
+   * @return True on success
+   */
+  bool GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) override;
+
+public: // ResourceId relative API.
+  /**
+   * @brief Create Graphics::Texture as resourceId.
+   * The ownership of Graphics::Texture will be hold on this controller.
+   * @note If some Graphics::Texture already created before, assert.
+   * @post DiscardTextureFromResourceId() or ReleaseTextureFromResourceId() should be called when we don't use resourceId texture anymore.
+   *
+   * @param[in] resourceId The unique id of resouces.
+   * @return Pointer of Graphics::Texture, or nullptr if we fail to create.
+   */
+  Graphics::Texture* CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo) override;
+
+  /**
+   * @brief Discard Graphics::Texture as resourceId.
+   *
+   * @param[in] resourceId The unique id of resouces.
+   */
+  void DiscardTextureFromResourceId(uint32_t resourceId) override;
+
+  /**
+   * @brief Get the Graphics::Texture as resourceId.
+   *
+   * @param[in] resourceId The unique id of resouces.
+   * @return Pointer of Graphics::Texture, or nullptr if there is no valid objects.
+   */
+  Graphics::Texture* GetTextureFromResourceId(uint32_t resourceId) override;
+
+  /**
+   * @brief Get the ownership of Graphics::Texture as resourceId.
+   *
+   * @param[in] resourceId The unique id of resouces.
+   * @return Pointer of Graphics::Texture.
+   */
+  Graphics::UniquePtr<Graphics::Texture> ReleaseTextureFromResourceId(uint32_t resourceId) override;
+
 public: // Test Functions
   void SetVertexFormats(Property::Array& vfs)
   {
@@ -396,18 +444,6 @@ public: // Test Functions
     mSubmitStack.clear();
   }
 
-  /**
-   * @brief Retrieves program parameters
-   *
-   * This function can be used to retrieve data from internal implementation
-   *
-   * @param[in] program Valid program object
-   * @param[in] parameterId Integer parameter id
-   * @param[out] outData Pointer to output memory
-   * @return True on success
-   */
-  bool GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) override;
-
   void ProcessCommandBuffer(TestGraphicsCommandBuffer& commandBuffer);
 
   void BindPipeline(TestGraphicsPipeline* pipeline);
@@ -436,6 +472,8 @@ public:
 
   std::vector<TestGraphicsBuffer*> mAllocatedBuffers;
 
+  std::unordered_map<uint32_t, Graphics::UniquePtr<Graphics::Texture>> mTextureUploadBindMapper;
+
   struct PipelineCache
   {
   };
index 8f3095f..ca52b18 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
 #include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/integration-api/adaptor-framework/scene-holder.h>
 
-#include <toolkit-scene-holder-impl.h>
-#include <toolkit-adaptor-impl.h>
 #include <dali/integration-api/debug.h>
 #include <dali/integration-api/scene.h>
 #include <test-application.h>
+#include <toolkit-adaptor-impl.h>
+#include <toolkit-scene-holder-impl.h>
 #include <toolkit-test-application.h>
 
 namespace Dali
 {
-
 namespace Internal
 {
 namespace Adaptor
 {
-
 ///////////////////////////////////////////////////////////////////////////////
 //
 // Dali::Internal::Adaptor::Adaptor Stub
@@ -49,14 +47,14 @@ Dali::Adaptor* gAdaptor = nullptr;
 
 Dali::Adaptor& Adaptor::New()
 {
-  DALI_ASSERT_ALWAYS( ! gAdaptor );
+  DALI_ASSERT_ALWAYS(!gAdaptor);
   gAdaptor = new Dali::Adaptor;
   return *gAdaptor;
 }
 
 Dali::Adaptor& Adaptor::Get()
 {
-  DALI_ASSERT_ALWAYS( gAdaptor );
+  DALI_ASSERT_ALWAYS(gAdaptor);
   return *gAdaptor;
 }
 
@@ -69,33 +67,32 @@ Adaptor::~Adaptor()
   gAdaptor = nullptr;
 }
 
-void Adaptor::Start( Dali::Window window )
+void Adaptor::Start(Dali::Window window)
 {
-  AddWindow( &GetImplementation( window ) );
+  AddWindow(&GetImplementation(window));
 }
 
-Integration::Scene Adaptor::GetScene( Dali::Window window )
+Integration::Scene Adaptor::GetScene(Dali::Window window)
 {
   return window.GetScene();
 }
 
-bool Adaptor::AddIdle( CallbackBase* callback, bool hasReturnValue )
+bool Adaptor::AddIdle(CallbackBase* callback, bool hasReturnValue)
 {
-  mCallbacks.PushBack( callback );
+  mCallbacks.PushBack(callback);
   return true;
 }
 
-void Adaptor::RemoveIdle( CallbackBase* callback )
+void Adaptor::RemoveIdle(CallbackBase* callback)
 {
-  mCallbacks.Erase( std::find_if( mCallbacks.Begin(), mCallbacks.End(),
-                                  [ &callback ] ( CallbackBase* current ) { return callback == current; } ) );
+  mCallbacks.Erase(std::find_if(mCallbacks.Begin(), mCallbacks.End(), [&callback](CallbackBase* current) { return callback == current; }));
 }
 
 void Adaptor::RunIdles()
 {
-  for( auto& callback : mCallbacks )
+  for(auto& callback : mCallbacks)
   {
-    CallbackBase::Execute( *callback );
+    CallbackBase::Execute(*callback);
   }
 
   mCallbacks.Clear();
@@ -103,22 +100,22 @@ void Adaptor::RunIdles()
 
 Dali::RenderSurfaceInterface& Adaptor::GetSurface()
 {
-  DALI_ASSERT_ALWAYS( ! mWindows.empty() );
+  DALI_ASSERT_ALWAYS(!mWindows.empty());
 
-  return reinterpret_cast < Dali::RenderSurfaceInterface& >( mWindows.front()->GetRenderSurface() );
+  return reinterpret_cast<Dali::RenderSurfaceInterface&>(mWindows.front()->GetRenderSurface());
 }
 
 Dali::WindowContainer Adaptor::GetWindows()
 {
   Dali::WindowContainer windows;
 
-  for ( auto iter = mWindows.begin(); iter != mWindows.end(); ++iter )
+  for(auto iter = mWindows.begin(); iter != mWindows.end(); ++iter)
   {
     // Downcast to Dali::Window
-    Dali::Window window( dynamic_cast<Dali::Internal::Adaptor::Window*>( *iter ) );
-    if ( window )
+    Dali::Window window(dynamic_cast<Dali::Internal::Adaptor::Window*>(*iter));
+    if(window)
     {
-      windows.push_back( window );
+      windows.push_back(window);
     }
   }
 
@@ -129,21 +126,21 @@ Dali::SceneHolderList Adaptor::GetSceneHolders()
 {
   Dali::SceneHolderList sceneHolderList;
 
-  for( auto iter = mWindows.begin(); iter != mWindows.end(); ++iter )
+  for(auto iter = mWindows.begin(); iter != mWindows.end(); ++iter)
   {
-    sceneHolderList.push_back( Dali::Integration::SceneHolder( *iter ) );
+    sceneHolderList.push_back(Dali::Integration::SceneHolder(*iter));
   }
 
   return sceneHolderList;
 }
 
-Dali::Internal::Adaptor::SceneHolder* Adaptor::GetWindow( Dali::Actor& actor )
+Dali::Internal::Adaptor::SceneHolder* Adaptor::GetWindow(Dali::Actor& actor)
 {
-  Dali::Integration::Scene scene = Dali::Integration::Scene::Get( actor );
+  Dali::Integration::Scene scene = Dali::Integration::Scene::Get(actor);
 
-  for( auto window : mWindows )
+  for(auto window : mWindows)
   {
-    if ( scene == window->GetScene() )
+    if(scene == window->GetScene())
     {
       return window;
     }
@@ -152,39 +149,39 @@ Dali::Internal::Adaptor::SceneHolder* Adaptor::GetWindow( Dali::Actor& actor )
   return nullptr;
 }
 
-void Adaptor::AddWindow( Internal::Adaptor::SceneHolder* window )
+void Adaptor::AddWindow(Internal::Adaptor::SceneHolder* window)
 {
-  if ( window )
+  if(window)
   {
-    mWindows.push_back( window );
+    mWindows.push_back(window);
 
-    Dali::Integration::SceneHolder newWindow( window );
-    mWindowCreatedSignal.Emit( newWindow );
+    Dali::Integration::SceneHolder newWindow(window);
+    mWindowCreatedSignal.Emit(newWindow);
   }
 }
 
-void Adaptor::RemoveWindow( Internal::Adaptor::SceneHolder* window )
+void Adaptor::RemoveWindow(Internal::Adaptor::SceneHolder* window)
 {
-  auto iter = std::find( mWindows.begin(), mWindows.end(), window );
-  if( iter != mWindows.end() )
+  auto iter = std::find(mWindows.begin(), mWindows.end(), window);
+  if(iter != mWindows.end())
   {
-    mWindows.erase( iter );
+    mWindows.erase(iter);
   }
 }
 
-void Adaptor::RegisterProcessor( Integration::Processor& processor, bool postProcessor )
+void Adaptor::RegisterProcessor(Integration::Processor& processor, bool postProcessor)
 {
   Integration::Core& core = mTestApplication->GetCore();
-  core.RegisterProcessor( processor, postProcessor );
+  core.RegisterProcessor(processor, postProcessor);
 }
 
-void Adaptor::UnregisterProcessor( Integration::Processor& processor, bool postProcessor )
+void Adaptor::UnregisterProcessor(Integration::Processor& processor, bool postProcessor)
 {
   Integration::Core& core = mTestApplication->GetCore();
-  core.UnregisterProcessor( processor, postProcessor );
+  core.UnregisterProcessor(processor, postProcessor);
 }
 
-void Adaptor::SetApplication( Dali::TestApplication& testApplication )
+void Adaptor::SetApplication(Dali::TestApplication& testApplication)
 {
   mTestApplication = &testApplication;
 }
@@ -214,7 +211,7 @@ Dali::Adaptor::WindowCreatedSignalType& Adaptor::WindowCreatedSignal()
 ///////////////////////////////////////////////////////////////////////////////
 
 Adaptor::Adaptor()
-: mImpl( new Internal::Adaptor::Adaptor )
+: mImpl(new Internal::Adaptor::Adaptor)
 {
 }
 
@@ -240,21 +237,21 @@ void Adaptor::Stop()
 {
 }
 
-bool Adaptor::AddIdle( CallbackBase* callback, bool hasReturnValue )
+bool Adaptor::AddIdle(CallbackBase* callback, bool hasReturnValue)
 {
-  return mImpl->AddIdle( callback, hasReturnValue );
+  return mImpl->AddIdle(callback, hasReturnValue);
 }
 
-void Adaptor::RemoveIdle( CallbackBase* callback )
+void Adaptor::RemoveIdle(CallbackBase* callback)
 {
-  mImpl->RemoveIdle( callback );
+  mImpl->RemoveIdle(callback);
 }
 
-void Adaptor::ReplaceSurface( Window window, Dali::RenderSurfaceInterface& surface )
+void Adaptor::ReplaceSurface(Window window, Dali::RenderSurfaceInterface& surface)
 {
 }
 
-void Adaptor::ReplaceSurface( Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface& surface )
+void Adaptor::ReplaceSurface(Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface& surface)
 {
 }
 
@@ -294,7 +291,7 @@ Any Adaptor::GetNativeWindowHandle()
   return window;
 }
 
-Any Adaptor::GetNativeWindowHandle( Actor actor )
+Any Adaptor::GetNativeWindowHandle(Actor actor)
 {
   return GetNativeWindowHandle();
 }
@@ -303,7 +300,7 @@ void Adaptor::ReleaseSurfaceLock()
 {
 }
 
-void Adaptor::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
+void Adaptor::SetRenderRefreshRate(unsigned int numberOfVSyncsPerRender)
 {
 }
 
@@ -325,15 +322,15 @@ void Adaptor::NotifyLanguageChanged()
 {
 }
 
-void Adaptor::FeedTouchPoint( TouchPoint& point, int timeStamp )
+void Adaptor::FeedTouchPoint(TouchPoint& point, int timeStamp)
 {
 }
 
-void Adaptor::FeedWheelEvent( WheelEvent& wheelEvent )
+void Adaptor::FeedWheelEvent(WheelEvent& wheelEvent)
 {
 }
 
-void Adaptor::FeedKeyEvent( KeyEvent& keyEvent )
+void Adaptor::FeedKeyEvent(KeyEvent& keyEvent)
 {
 }
 
@@ -358,24 +355,51 @@ public:
   }
 };
 
-LogFactory* gLogFactory = NULL;
+LogFactory*                gLogFactory = NULL;
 const LogFactoryInterface& Adaptor::GetLogFactory()
 {
-  if( gLogFactory == NULL )
+  if(gLogFactory == NULL)
   {
     gLogFactory = new LogFactory;
   }
   return *gLogFactory;
 }
 
-void Adaptor::RegisterProcessor( Integration::Processor& processor, bool postProcessor)
+class TraceFactory : public TraceFactoryInterface
+{
+public:
+  virtual void InstallTraceFunction() const
+  {
+    Dali::Integration::Trace::LogContextFunction logContextFunction(&TestApplication::LogContext);
+    Dali::Integration::Trace::InstallLogContextFunction(logContextFunction);
+  }
+
+  TraceFactory()
+  {
+  }
+  virtual ~TraceFactory()
+  {
+  }
+};
+
+TraceFactory*                gTraceFactory = NULL;
+const TraceFactoryInterface& Adaptor::GetTraceFactory()
+{
+  if(gTraceFactory == NULL)
+  {
+    gTraceFactory = new TraceFactory;
+  }
+  return *gTraceFactory;
+}
+
+void Adaptor::RegisterProcessor(Integration::Processor& processor, bool postProcessor)
 {
-  mImpl->RegisterProcessor( processor, postProcessor );
+  mImpl->RegisterProcessor(processor, postProcessor);
 }
 
-void Adaptor::UnregisterProcessor( Integration::Processor& processor, bool postProcessor)
+void Adaptor::UnregisterProcessor(Integration::Processor& processor, bool postProcessor)
 {
-  mImpl->UnregisterProcessor( processor, postProcessor );
+  mImpl->UnregisterProcessor(processor, postProcessor);
 }
 
 } // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.cpp
new file mode 100644 (file)
index 0000000..f1c336c
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <toolkit-texture-upload-manager.h>
+
+// EXTERNAL INCLUDE
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+#include <dali/graphics-api/graphics-controller.h>
+#include <dali/integration-api/pixel-data-integ.h>
+#include <dali/integration-api/texture-integ.h>
+
+// INTERNAL INCLUDE
+#include <test-graphics-controller.h>
+#include <toolkit-application.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class TextureUploadManager : public Dali::BaseObject
+{
+public:
+  using ResourceId = Dali::Devel::TextureUploadManager::ResourceId;
+
+public:
+  static Dali::Devel::TextureUploadManager Get();
+  TextureUploadManager();
+  ~TextureUploadManager() = default;
+
+  Dali::Texture GenerateTexture2D();
+
+public: // Update thread called method
+  bool ResourceUpload();
+
+  void InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController);
+
+private:                                                             // Update thread called method
+  using UploadRequestItem  = std::pair<ResourceId, Dali::PixelData>; ///< TODO : PixelData? PixelBuffer?
+  using RequestUploadQueue = std::vector<UploadRequestItem>;
+
+  bool ProcessUploadQueue(RequestUploadQueue&& queue);
+
+public: // Worker thread called method
+  /**
+   * @copydoc Dali::Devel::TextureUploadManager::RequestUpload()
+   */
+  void RequestUpload(ResourceId id, Dali::PixelData pixelData);
+
+private:
+  Dali::Graphics::Controller* mGraphicsController;
+  RequestUploadQueue          mRequestUploadQueue{};
+
+public:
+  ResourceId gUniqueResourceId{0u};
+};
+
+inline Internal::Adaptor::TextureUploadManager& GetImplementation(Dali::Devel::TextureUploadManager& obj)
+{
+  DALI_ASSERT_ALWAYS(obj && "TextureUploadManager is empty");
+
+  Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::TextureUploadManager&>(handle);
+}
+
+inline const Internal::Adaptor::TextureUploadManager& GetImplementation(const Dali::Devel::TextureUploadManager& obj)
+{
+  DALI_ASSERT_ALWAYS(obj && "TextureUploadManager is empty");
+
+  const Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::TextureUploadManager&>(handle);
+}
+
+/********************************************************************************/
+/*********************************  INTERNAL CLASS  *****************************/
+/********************************************************************************/
+
+namespace
+{
+Devel::TextureUploadManager gTextureUploadManager;
+} // namespace
+
+Devel::TextureUploadManager TextureUploadManager::Get()
+{
+  if(!gTextureUploadManager)
+  {
+    gTextureUploadManager = Devel::TextureUploadManager(new TextureUploadManager());
+  }
+  return gTextureUploadManager;
+}
+
+TextureUploadManager::TextureUploadManager()
+: mGraphicsController{nullptr}
+{
+}
+
+Dali::Texture TextureUploadManager::GenerateTexture2D()
+{
+  ResourceId resourceId = ++gUniqueResourceId;
+
+  Dali::Texture ret = Dali::Integration::NewTextureWithResourceId(Dali::TextureType::TEXTURE_2D, resourceId);
+
+  return ret;
+}
+
+// Called by update thread
+
+bool TextureUploadManager::ResourceUpload()
+{
+  DALI_ASSERT_DEBUG(mGraphicsController && "GraphicsController is not prepared!");
+
+  // Upload.
+  bool uploaded = ProcessUploadQueue(std::move(mRequestUploadQueue));
+  mRequestUploadQueue.clear();
+
+  return uploaded;
+}
+
+void TextureUploadManager::InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController)
+{
+  mGraphicsController = &graphicsController;
+}
+
+bool TextureUploadManager::ProcessUploadQueue(RequestUploadQueue&& queue)
+{
+  bool uploaded = false;
+
+  if(!queue.empty())
+  {
+    for(auto& requests : queue)
+    {
+      auto& resourceId = requests.first;
+      auto& pixelData  = requests.second;
+
+      Graphics::Texture* graphicsTexture = nullptr;
+
+      // TODO : Could we detect TEXTURE_2D or TEXTURE_CUBE case in future?
+      {
+        // We always need to create new one
+        auto createInfo = Graphics::TextureCreateInfo();
+        createInfo
+          .SetTextureType(Dali::Graphics::ConvertTextureType(Dali::TextureType::TEXTURE_2D))
+          .SetUsageFlags(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE))
+          .SetFormat(Dali::Graphics::ConvertPixelFormat(pixelData.GetPixelFormat()))
+          .SetSize({pixelData.GetWidth(), pixelData.GetHeight()})
+          .SetLayout(Graphics::TextureLayout::LINEAR)
+          .SetData(nullptr)
+          .SetDataSize(0u)
+          .SetNativeImage(nullptr)
+          .SetMipMapFlag(Graphics::TextureMipMapFlag::DISABLED);
+
+        graphicsTexture = mGraphicsController->CreateTextureByResourceId(resourceId, createInfo);
+      }
+
+      if(graphicsTexture)
+      {
+        Graphics::TextureUpdateInfo info{};
+
+        info.dstTexture   = graphicsTexture;
+        info.dstOffset2D  = {0u, 0u};
+        info.layer        = 0u;
+        info.level        = 0u;
+        info.srcReference = 0;
+        info.srcExtent2D  = {pixelData.GetWidth(), pixelData.GetHeight()};
+        info.srcOffset    = 0;
+        info.srcSize      = Dali::Integration::GetPixelDataBuffer(pixelData).bufferSize;
+        info.srcStride    = pixelData.GetStride();
+        info.srcFormat    = Dali::Graphics::ConvertPixelFormat(pixelData.GetPixelFormat());
+
+        Graphics::TextureUpdateSourceInfo updateSourceInfo{};
+        updateSourceInfo.sourceType                = Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA;
+        updateSourceInfo.pixelDataSource.pixelData = pixelData;
+
+        mGraphicsController->UpdateTextures({info}, {updateSourceInfo});
+
+        uploaded = true;
+      }
+      else
+      {
+        // Invalidate resouce id! ignore.
+      }
+    }
+
+    if(uploaded)
+    {
+      // Flush here
+      Graphics::SubmitInfo submitInfo;
+      submitInfo.cmdBuffer.clear(); // Only flush
+      submitInfo.flags = 0 | Graphics::SubmitFlagBits::FLUSH;
+      mGraphicsController->SubmitCommandBuffers(submitInfo);
+    }
+  }
+
+  return uploaded;
+}
+
+// Called by worker thread
+
+void TextureUploadManager::RequestUpload(Dali::Devel::TextureUploadManager::ResourceId resourceId, Dali::PixelData pixelData)
+{
+  mRequestUploadQueue.push_back(std::move(UploadRequestItem(resourceId, pixelData)));
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+/********************************************************************************/
+/*********************************  PUBLIC CLASS  *******************************/
+/********************************************************************************/
+
+namespace Devel
+{
+// Called by main thread
+
+TextureUploadManager::TextureUploadManager() = default;
+
+TextureUploadManager::~TextureUploadManager() = default;
+
+TextureUploadManager TextureUploadManager::Get()
+{
+  return Internal::Adaptor::TextureUploadManager::Get();
+}
+
+Dali::Texture TextureUploadManager::GenerateTexture2D()
+{
+  return Internal::Adaptor::GetImplementation(*this).GenerateTexture2D();
+}
+
+TextureUploadManager::TextureUploadManager(Internal::Adaptor::TextureUploadManager* impl)
+: BaseHandle(impl)
+{
+}
+
+// Called by update thread
+
+bool TextureUploadManager::ResourceUpload()
+{
+  return Internal::Adaptor::GetImplementation(*this).ResourceUpload();
+}
+
+// Called by worker thread
+
+void TextureUploadManager::RequestUpload(ResourceId resourceId, PixelData pixelData)
+{
+  Internal::Adaptor::GetImplementation(*this).RequestUpload(resourceId, pixelData);
+}
+
+} // namespace Devel
+
+} // namespace Dali
+
+namespace Test
+{
+namespace TextureUploadManager
+{
+void InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController)
+{
+  auto textureUploadManager = Dali::Devel::TextureUploadManager::Get();
+  Internal::Adaptor::GetImplementation(textureUploadManager).InitalizeGraphicsController(graphicsController);
+}
+} // namespace TextureUploadManager
+} // namespace Test
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.h
new file mode 100644 (file)
index 0000000..18585fd
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef DALI_TOOLKIT_TOOLKIT_TEXTURE_UPLOAD_MANAGER_H
+#define DALI_TOOLKIT_TOOLKIT_TEXTURE_UPLOAD_MANAGER_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+
+namespace Dali
+{
+namespace Graphics DALI_INTERNAL
+{
+class Controller;
+} // namespace DALI_INTERNAL
+} // namespace Dali
+
+namespace Test
+{
+namespace TextureUploadManager
+{
+void InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController);
+}
+} // namespace Test
+
+#endif // DALI_TOOLKIT_TOOLKIT_TEXTURE_UPLOAD_MANAGER_H
index 9583e09..4b5e546 100644 (file)
 #include <iostream>
 #include <vector>
 
+#include <unistd.h>
+#include <thread>
+
 #include <dali-toolkit-test-suite-utils.h>
 
 #include <toolkit-environment-variable.h>
 #include <toolkit-event-thread-callback.h>
+#include <toolkit-texture-upload-manager.h>
 #include <toolkit-timer.h>
 
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali-toolkit/devel-api/image-loader/texture-manager.h>
 #include <dali-toolkit/devel-api/visual-factory/transition-data.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 #include <dali-toolkit/public-api/image-loader/image-url.h>
 #include <dali-toolkit/public-api/image-loader/image.h>
 
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+
 #include "dummy-control.h"
 #include "test-encoded-image-buffer.h"
 #include "test-native-image-source.h"
@@ -3550,3 +3557,315 @@ int UtcDaliImageVisualLoadImagePlanes03(void)
 
   END_TEST;
 }
+
+int UtcDaliImageVisualLoadFastTrackImage01(void)
+{
+  tet_infoline("Test worker thread uploading with Local URL");
+  ToolkitTestApplication application;
+
+  Test::TextureUploadManager::InitalizeGraphicsController(application.GetGraphicsController());
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  // Pair of filename - expect GenTextures count.
+  std::vector<std::pair<std::string, int>> testCases = {
+    {TEST_IMAGE_FILE_NAME, 1},
+    {TEST_REMOTE_IMAGE_FILE_NAME, 1},
+    {TEST_INVALID_FILE_NAME, 0},
+  };
+
+  for(auto&& tc : testCases)
+  {
+    auto& filename    = tc.first;
+    auto& expectValue = tc.second;
+
+    tet_printf("Test %s\n", filename.c_str());
+
+    Property::Map propertyMap;
+    propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+    propertyMap.Insert(ImageVisual::Property::URL, filename.c_str());
+    propertyMap.Insert(DevelImageVisual::Property::FAST_TRACK_UPLOADING, true);
+
+    Visual::Base visual = factory.CreateVisual(propertyMap);
+    DALI_TEST_CHECK(visual);
+
+    DummyControl      actor     = DummyControl::New();
+    DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+    dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+    actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
+
+    TestGlAbstraction& gl           = application.GetGlAbstraction();
+    TraceCallStack&    textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    application.GetScene().Add(actor);
+
+    application.SendNotification();
+    application.Render();
+
+    // EventThread without callback
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 30, false), true, TEST_LOCATION);
+
+    DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION);
+
+    {
+      // TODO : There is no way to flush TextureUploadManager in test-application's Render() now.
+      // How can we make it? Should it be integration-api?
+      auto textureUploadManager = Dali::Devel::TextureUploadManager::Get();
+      DALI_TEST_EQUALS(textureUploadManager.ResourceUpload(), expectValue > 0, TEST_LOCATION);
+    }
+    // Render only without SendNotification(). And check whether glTexImage2D called or not.
+    application.Render();
+
+    DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), expectValue, TEST_LOCATION);
+
+    application.SendNotification();
+    application.Render();
+
+    textureTrace.Reset();
+  }
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadFastTrackImage02(void)
+{
+  tet_infoline("Test worker thread uploading with Local URL");
+  ToolkitTestApplication application;
+
+  Test::TextureUploadManager::InitalizeGraphicsController(application.GetGraphicsController());
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  {
+    auto filename    = std::string(TEST_IMAGE_FILE_NAME);
+    auto expectValue = 1;
+
+    tet_printf("Test %s\n", filename.c_str());
+
+    Property::Map propertyMap;
+    propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+    propertyMap.Insert(ImageVisual::Property::URL, filename.c_str());
+    propertyMap.Insert("fastTrackUploading", true);
+
+    Visual::Base visual = factory.CreateVisual(propertyMap);
+    DALI_TEST_CHECK(visual);
+
+    DummyControl      actor     = DummyControl::New();
+    DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+    dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+    actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
+
+    TestGlAbstraction& gl           = application.GetGlAbstraction();
+    TraceCallStack&    textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    application.GetScene().Add(actor);
+
+    application.SendNotification();
+    application.Render();
+
+    // EventThread without callback
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 30, false), true, TEST_LOCATION);
+
+    DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION);
+
+    {
+      // TODO : There is no way to flush TextureUploadManager in test-application's Render() now.
+      // How can we make it? Should it be integration-api?
+      auto textureUploadManager = Dali::Devel::TextureUploadManager::Get();
+      DALI_TEST_EQUALS(textureUploadManager.ResourceUpload(), expectValue > 0, TEST_LOCATION);
+    }
+    // Render only without SendNotification(). And check whether glTexImage2D called or not.
+    application.Render();
+
+    DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), expectValue, TEST_LOCATION);
+
+    application.SendNotification();
+    application.Render();
+
+    textureTrace.Reset();
+  }
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadFastTrackImageResourceReady(void)
+{
+  tet_infoline("Test worker thread uploading with Local URL");
+  ToolkitTestApplication application;
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  propertyMap.Insert(DevelImageVisual::Property::FAST_TRACK_UPLOADING, true);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK(visual);
+
+  DummyControl      actor     = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  // EventThread with callback
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  // Check resource ready comes after
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadFastTrackImageReload(void)
+{
+  tet_infoline("Test worker thread uploading with Local URL");
+  ToolkitTestApplication application;
+
+  Test::TextureUploadManager::InitalizeGraphicsController(application.GetGraphicsController());
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  propertyMap.Insert(DevelImageVisual::Property::FAST_TRACK_UPLOADING, true);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK(visual);
+
+  DummyControl      actor     = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  // EventThread without callback
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 30, false), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION);
+
+  {
+    // TODO : There is no way to flush TextureUploadManager in test-application's Render() now.
+    // How can we make it? Should it be integration-api?
+    auto textureUploadManager = Dali::Devel::TextureUploadManager::Get();
+    DALI_TEST_EQUALS(textureUploadManager.ResourceUpload(), true, TEST_LOCATION);
+  }
+  // Render only without SendNotification(). And check whether glTexImage2D called or not.
+  application.Render();
+
+  DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 1, TEST_LOCATION);
+
+  // Reload
+  Property::Map attributes;
+  DevelControl::DoAction(actor, Control::CONTROL_PROPERTY_END_INDEX + 1, DevelImageVisual::Action::RELOAD, attributes);
+
+  // EventThread with callback
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  // Check resource ready comes after
+  application.SendNotification();
+  application.Render();
+
+  // Check whether renderer count is 1 or not.
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadFastTrackImagePlanes01(void)
+{
+#if 0 //< Do not open this UTC yet.
+  EnvironmentVariable::SetTestEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV, "1");
+  EnvironmentVariable::SetTestEnvironmentVariable(ENABLE_DECODE_JPEG_TO_YUV_420_ENV, "1");
+
+  ToolkitTestApplication application;
+
+  Test::TextureUploadManager::InitalizeGraphicsController(application.GetGraphicsController());
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_YUV420_IMAGE_FILE_NAME);
+  propertyMap.Insert(DevelImageVisual::Property::FAST_TRACK_UPLOADING, true);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK(visual);
+
+  DummyControl      actor     = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  // EventThread without callback
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 30, false), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION);
+
+  {
+    // TODO : There is no way to flush TextureUploadManager in test-application's Render() now.
+    // How can we make it? Should it be integration-api?
+    auto textureUploadManager = Dali::Devel::TextureUploadManager::Get();
+    textureUploadManager.ResourceUpload();
+    application.Render();
+  }
+  // Render only without SendNotification(). And check whether glTexImage2D called or not.
+  application.Render();
+
+  DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 3, TEST_LOCATION);
+
+  // Event thread don't know the result yet.
+  DALI_TEST_EQUALS(actor.IsResourceReady(), false, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  // Check resource ready comes after
+  application.SendNotification();
+
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION);
+
+#else
+  DALI_TEST_CHECK(true);
+#endif
+  END_TEST;
+}
\ No newline at end of file
index 54ad18b..eb7ba1d 100644 (file)
@@ -320,6 +320,109 @@ int UtcDaliParticleSystemEmitterNew(void)
   END_TEST;
 }
 
+int UtcDaliParticleSystemEmitterNew2(void)
+{
+  // create particle emitter
+  auto emitter = ParticleEmitter::New();
+
+  bool result = (emitter != nullptr);
+  DALI_TEST_EQUALS(result, true, TEST_LOCATION);
+
+  // Create test source
+  auto source = ParticleSource::New<TestSource>(&emitter);
+
+  // Create test renderer
+  auto renderer = ParticleRenderer::New();
+
+  // Create modifier
+  auto modifier = ParticleModifier::New<TestModifier>();
+
+  // Create domain
+  auto domain = ParticleDomain::New();
+
+  // Test emitter readiness
+  auto ready = emitter.GetStatus();
+
+  // Emitter should return status incomplete
+  DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
+
+  // Attach all components to the emitter
+  emitter.SetSource(source);
+  emitter.SetRenderer(renderer);
+  emitter.AddModifier(modifier);
+  emitter.SetDomain(domain);
+
+  // test blending mode
+  DALI_TEST_EQUALS(renderer.GetBlendingMode(), Dali::Toolkit::ParticleSystem::BlendingMode::DEFAULT, TEST_LOCATION);
+
+  emitter.SetParticleCount(10000);
+  DALI_TEST_EQUALS(emitter.GetParticleCount(), 10000, TEST_LOCATION);
+
+  auto m = emitter.GetModifierAt(0);
+  DALI_TEST_EQUALS(m != nullptr, true, TEST_LOCATION);
+
+  m.GetModifierCallback();
+
+  // test status again (domain is optional);
+  ready = emitter.GetStatus();
+
+  // Emitter should return status incomplete
+  DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliParticleSystemEmitterDefaultStreams(void)
+{
+  // create particle emitter
+  auto emitter = ParticleEmitter::New();
+
+  bool result = (emitter != nullptr);
+  DALI_TEST_EQUALS(result, true, TEST_LOCATION);
+
+  // Create test source
+  auto source = ParticleSource::New<TestSource>(&emitter);
+
+  // Create test renderer
+  auto renderer = ParticleRenderer::New();
+
+  // Create modifier
+  auto modifier = ParticleModifier::New<TestModifier>();
+
+  // Create domain
+  auto domain = ParticleDomain::New();
+
+  // Test emitter readiness
+  auto ready = emitter.GetStatus();
+
+  // Emitter should return status incomplete
+  DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
+
+  // Attach all components to the emitter
+  emitter.SetSource(source);
+  emitter.SetRenderer(renderer);
+  emitter.AddModifier(modifier);
+  emitter.SetDomain(domain);
+
+  auto                  particleList   = emitter.GetParticleList();
+  std::vector<uint32_t> expectedValues = {
+    ParticleStream::POSITION_STREAM_BIT, 0, ParticleStream::COLOR_STREAM_BIT, 3, ParticleStream::VELOCITY_STREAM_BIT, 2, ParticleStream::SCALE_STREAM_BIT, 1, ParticleStream::LIFETIME_STREAM_BIT, 4, ParticleStream::LIFETIME_BASE_STREAM_BIT, 5};
+
+  for(auto i = 0u; i < expectedValues.size(); i += 2)
+  {
+    auto index = particleList.GetDefaultStreamIndex(expectedValues[i]);
+    DALI_TEST_EQUALS(index, expectedValues[i + 1], TEST_LOCATION);
+  }
+
+  // test status again (domain is optional);
+  ready = emitter.GetStatus();
+
+  // Emitter should return status incomplete
+  DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliParticleSystemEmitterModifierStack(void)
 {
   // create particle emitter
index b504089..53a54e6 100644 (file)
@@ -110,6 +110,7 @@ if(ENABLE_PKG_CONFIGURE)
     if( NOT LIB_DIR )
         set( LIB_DIR ${prefix}/lib )
     endif()
+    set(DEV_INCLUDE_PATH ${prefix}/include/bullet)
 
     set(bullet_pkg_cfg_file bullet3.pc)
     configure_file(${CMAKE_CURRENT_LIST_DIR}/${bullet_pkg_cfg_file}.cmake ${bullet_pkg_cfg_file} @ONLY)
@@ -158,4 +159,4 @@ if(INSTALL_CMAKE_MODULES)
     include(\${CMAKE_CURRENT_LIST_DIR}/bullet3-targets.cmake)
   ")
   install(FILES ${CMAKE_CURRENT_BINARY_DIR}/bullet3-config.cmake DESTINATION share/bullet3)
-endif()
\ No newline at end of file
+endif()
index 3c0e7d6..35dc49d 100644 (file)
@@ -158,6 +158,23 @@ enum Type
   MASKING_TYPE = ORIENTATION_CORRECTION + 12,
 
   /**
+   * @brief If true, uploads texture before ResourceReady signal is emitted. Otherwise uploads after texture load is completed.
+   * @details Name "fastTrackUploading", type Property::BOOLEAN
+   * If true, the upload happens without event-thread dependency, but the following need to be considered:
+   *  - Texture size is not valid until upload is fully complete.
+   *  - Texture cannot be cached (a new image is uploaded every time).
+   *  - Seamless visual change is not supported.
+   *  - The following, if set are also not supported and will be ignored:
+   *    - Alpha masking
+   *    - Synchronous loading
+   *    - Reload action
+   *    - Atlas loading
+   *    - Custom shader
+   * @note Used by the ImageVisual. The default is false.
+   */
+  FAST_TRACK_UPLOADING = ORIENTATION_CORRECTION + 13,
+
+  /**
    * @brief Whether to enable broken image in image visual.
    * Some of visual don't need to show broken image(ex. placeholder)
    * Disable broken image for these visuals.
index 3e84cfd..391dd34 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -43,6 +43,7 @@ constexpr uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_
 
 GlViewRenderThread::GlViewRenderThread(Dali::NativeImageSourceQueuePtr queue)
 : mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+  mTraceFactory(Dali::Adaptor::Get().GetTraceFactory()),
   mSurfaceSize(1, 1),
   mNativeImageSurface(),
   mNativeImageQueue(queue),
@@ -154,6 +155,7 @@ void GlViewRenderThread::Run()
 {
   Dali::SetThreadName("GlViewRenderer");
   mLogFactory.InstallLogFunction();
+  mTraceFactory.InstallTraceFunction();
 
   int renderFrameResult = 0;
 
index 753526e..cc5f45a 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_GL_VIEW_THREAD_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -25,6 +25,7 @@
 #include <dali/devel-api/threading/thread.h>
 #include <dali/integration-api/adaptor-framework/log-factory-interface.h>
 #include <dali/integration-api/adaptor-framework/native-image-surface.h>
+#include <dali/integration-api/adaptor-framework/trace-factory-interface.h>
 #include <dali/public-api/math/vector2.h>
 #include <dali/public-api/signals/callback.h>
 
@@ -145,11 +146,13 @@ private:
   void SleepUntil(uint64_t timeInNanoseconds);
 
 private:
-  const Dali::LogFactoryInterface& mLogFactory;
-  Dali::Vector2                    mSurfaceSize; ///< The size of mNativeImageQueue
-  Dali::NativeImageSurfacePtr      mNativeImageSurface;
-  Dali::NativeImageSourceQueuePtr  mNativeImageQueue;
-  Semaphore<>                      mSurfaceSemaphore; ///< The semaphore to avoid race condition to the render target
+  const Dali::LogFactoryInterface&   mLogFactory;
+  const Dali::TraceFactoryInterface& mTraceFactory;
+
+  Dali::Vector2                   mSurfaceSize; ///< The size of mNativeImageQueue
+  Dali::NativeImageSurfacePtr     mNativeImageSurface;
+  Dali::NativeImageSourceQueuePtr mNativeImageQueue;
+  Semaphore<>                     mSurfaceSemaphore; ///< The semaphore to avoid race condition to the render target
 
   std::unique_ptr<CallbackBase> mGlInitCallback;
   std::unique_ptr<CallbackBase> mGlRenderFrameCallback;
index 3ac6c81..9933e1a 100644 (file)
@@ -141,6 +141,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/filters/spread-filter.cpp
    ${toolkit_src_dir}/image-loader/async-image-loader-impl.cpp
    ${toolkit_src_dir}/image-loader/atlas-packer.cpp
+   ${toolkit_src_dir}/image-loader/fast-track-loading-task.cpp
    ${toolkit_src_dir}/image-loader/image-atlas-impl.cpp
    ${toolkit_src_dir}/image-loader/loading-task.cpp
    ${toolkit_src_dir}/image-loader/image-url-impl.cpp
diff --git a/dali-toolkit/internal/image-loader/fast-track-loading-task.cpp b/dali-toolkit/internal/image-loader/fast-track-loading-task.cpp
new file mode 100644 (file)
index 0000000..cd97cc2
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/image-loader/fast-track-loading-task.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/texture-integ.h>
+#include <dali/integration-api/trace.h>
+
+#ifdef TRACE_ENABLED
+#include <sstream>
+#endif
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false);
+}
+
+FastTrackLoadingTask::FastTrackLoadingTask(const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
+: AsyncTask(MakeCallback(this, &FastTrackLoadingTask::OnComplete), url.GetProtocolType() == VisualUrl::ProtocolType::REMOTE ? AsyncTask::PriorityType::LOW : AsyncTask::PriorityType::HIGH),
+  mUrl(url),
+  mTexture(),
+  mDimensions(dimensions),
+  mFittingMode(fittingMode),
+  mSamplingMode(samplingMode),
+  mPreMultiplyOnLoad(preMultiplyOnLoad),
+  mCallback(),
+  mTextureUploadManager(Dali::Devel::TextureUploadManager::Get()),
+  mImageWidth(0u),
+  mImageHeight(0u),
+  mImageFormat(Pixel::INVALID),
+  mPixelData(),
+  mResourceId(0u),
+  mOrientationCorrection(orientationCorrection),
+  mLoadSuccess(false),
+  mPremultiplied(false)
+{
+  mCallback = std::unique_ptr<CallbackBase>(callback);
+  PrepareTexture();
+}
+
+FastTrackLoadingTask::~FastTrackLoadingTask()
+{
+}
+
+void FastTrackLoadingTask::PrepareTexture()
+{
+  mTexture    = mTextureUploadManager.GenerateTexture2D();
+  mResourceId = Integration::GetTextureResourceId(mTexture);
+}
+
+void FastTrackLoadingTask::OnComplete(AsyncTaskPtr task)
+{
+  if(mLoadSuccess)
+  {
+    Dali::Integration::SetTextureSize(mTexture, Dali::ImageDimensions(mImageWidth, mImageHeight));
+    Dali::Integration::SetTexturePixelFormat(mTexture, mImageFormat);
+  }
+  if(mCallback)
+  {
+    CallbackBase::Execute(*mCallback, FastTrackLoadingTaskPtr(reinterpret_cast<FastTrackLoadingTask*>(task.Get())));
+  }
+}
+
+// Called by worker thread
+
+void FastTrackLoadingTask::Process()
+{
+  Load();
+  UploadToTexture();
+}
+
+bool FastTrackLoadingTask::IsReady()
+{
+  return true;
+}
+
+void FastTrackLoadingTask::Load()
+{
+#ifdef TRACE_ENABLED
+  if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+  {
+    std::ostringstream oss;
+    oss << "[url:" << mUrl.GetUrl() << "]";
+    DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_IMAGE_FAST_TRACK_UPLOADING_TASK", oss.str().c_str());
+  }
+#endif
+
+  Devel::PixelBuffer              pixelBuffer;
+  std::vector<Devel::PixelBuffer> pixelBuffers;
+
+  if(mUrl.IsValid() && mUrl.IsLocalResource())
+  {
+    // TODO : We need to consider YUV case in future.
+    //Dali::LoadImagePlanesFromFile(mUrl.GetUrl(), pixelBuffers, mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
+
+    pixelBuffer = Dali::LoadImageFromFile(mUrl.GetUrl(), mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
+  }
+  else if(mUrl.IsValid())
+  {
+    pixelBuffer = Dali::DownloadImageSynchronously(mUrl.GetUrl(), mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection);
+  }
+
+  if(pixelBuffer)
+  {
+    pixelBuffers.push_back(pixelBuffer);
+  }
+
+  if(pixelBuffers.empty())
+  {
+    DALI_LOG_ERROR("FastTrackLoadingTask::Load: Loading is failed: ResourceId : %d, url : [%s]\n", mResourceId, mUrl.GetUrl().c_str());
+  }
+  else
+  {
+    if(pixelBuffers.size() == 1u)
+    {
+      mLoadSuccess = true;
+      MultiplyAlpha(pixelBuffers[0]);
+      mPixelData = Dali::Devel::PixelBuffer::Convert(pixelBuffers[0]);
+    }
+    else
+    {
+      DALI_LOG_ERROR("FastTrackLoadingTask::Load: ??? Undefined case. PixelBuffers.size() : %zu : ResourceId : %d, url : [%s]\n", pixelBuffers.size(), mResourceId, mUrl.GetUrl().c_str());
+    }
+  }
+
+#ifdef TRACE_ENABLED
+  if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+  {
+    std::ostringstream oss;
+    oss << "[";
+    oss << "pixelBuffers: " << pixelBuffers.size() << " ";
+    if(!pixelBuffers.empty())
+    {
+      oss << "premult:" << mPremultiplied << " ";
+    }
+    oss << "url:" << mUrl.GetUrl() << "]";
+    DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_IMAGE_FAST_TRACK_UPLOADING_TASK", oss.str().c_str());
+  }
+#endif
+}
+
+void FastTrackLoadingTask::MultiplyAlpha(Dali::Devel::PixelBuffer pixelBuffer)
+{
+  if(mPreMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON && Pixel::HasAlpha(pixelBuffer.GetPixelFormat()))
+  {
+    pixelBuffer.MultiplyColorByAlpha();
+    mPremultiplied = pixelBuffer.IsAlphaPreMultiplied();
+  }
+}
+
+void FastTrackLoadingTask::UploadToTexture()
+{
+  if(mLoadSuccess)
+  {
+    mImageWidth  = mPixelData.GetWidth();
+    mImageHeight = mPixelData.GetHeight();
+    mImageFormat = mPixelData.GetPixelFormat();
+
+    mTextureUploadManager.RequestUpload(mResourceId, mPixelData);
+  }
+
+  mPixelData.Reset();
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/image-loader/fast-track-loading-task.h b/dali-toolkit/internal/image-loader/fast-track-loading-task.h
new file mode 100644 (file)
index 0000000..0458352
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef DALI_TOOLKIT_FAST_TRACK_IMAGE_LOADING_TASK_H
+#define DALI_TOOLKIT_FAST_TRACK_IMAGE_LOADING_TASK_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
+#include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
+#include <dali/public-api/rendering/texture.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+class FastTrackLoadingTask;
+using FastTrackLoadingTaskPtr = IntrusivePtr<FastTrackLoadingTask>;
+
+/**
+ * @brief The task of loading image and uploading texture on fast track.
+ * It is available that upload the loaded image data on texture at image loader threads.
+ */
+class FastTrackLoadingTask : public AsyncTask
+{
+public:
+  /**
+   * @brief Constructor.
+   */
+  FastTrackLoadingTask(const VisualUrl&                         url,
+                       ImageDimensions                          dimensions,
+                       FittingMode::Type                        fittingMode,
+                       SamplingMode::Type                       samplingMode,
+                       bool                                     orientationCorrection,
+                       DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
+                       CallbackBase*                            callback);
+
+  /**
+   * @brief Destructor.
+   */
+  ~FastTrackLoadingTask() override;
+
+  /**
+   * @brief Process the task accodring to the type
+   */
+  void Process() override;
+
+  /**
+   * @brief Whether the task is ready to process.
+   * @return True if the task is ready to process.
+   */
+  bool IsReady() override;
+
+private:
+  // Undefined
+  FastTrackLoadingTask(const FastTrackLoadingTask& queue) = delete;
+  FastTrackLoadingTask& operator=(const FastTrackLoadingTask& queue) = delete;
+
+  /**
+   * @brief Create textures for this task.
+   * @note This should be called in construct timing.
+   */
+  void PrepareTexture();
+
+  /**
+   * @brief Load the image.
+   */
+  void Load();
+
+  /**
+   * @brief Multiply alpha if required.
+   *
+   * @param[in,out] pixelBuffer target pixel buffer that need to be multiplied alpha.
+   */
+  void MultiplyAlpha(Dali::Devel::PixelBuffer pixelBuffer);
+
+  /**
+   * @brief Upload loaded pixelBuffer into texture
+   */
+  void UploadToTexture();
+
+private:
+  /**
+   * @brief Complete callback.
+   *
+   * @param[in] task The pointer of task who call this callback.
+   */
+  void OnComplete(AsyncTaskPtr task);
+
+public:
+  VisualUrl     mUrl;     ///< url of the image to load.
+  Dali::Texture mTexture; ///< texture for regular image.
+
+private:
+  ImageDimensions                          mDimensions;   ///< dimensions to load
+  FittingMode::Type                        mFittingMode;  ///< fitting options
+  SamplingMode::Type                       mSamplingMode; ///< sampling options
+  DevelAsyncImageLoader::PreMultiplyOnLoad mPreMultiplyOnLoad;
+  std::unique_ptr<CallbackBase>            mCallback;
+
+  // Texture Upload relative API
+  Dali::Devel::TextureUploadManager mTextureUploadManager;
+
+  // Note : mPixelData is invalid after upload requested. We should keep image size informations.
+  uint32_t      mImageWidth;
+  uint32_t      mImageHeight;
+  Pixel::Format mImageFormat;
+
+  Dali::PixelData mPixelData;
+
+  uint32_t mResourceId;
+
+  bool mOrientationCorrection : 1; ///< If orientation correction is needed
+
+public:
+  bool mLoadSuccess : 1;   ///< Whether image load successed or not.
+  bool mPremultiplied : 1; ///< True if the image's color was multiplied by it's alpha
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_FAST_TRACK_IMAGE_LOADING_TASK_H
index e81b16f..a1fcd63 100644 (file)
  */
 
 // CLASS HEADER
-#include "loading-task.h"
+#include <dali-toolkit/internal/image-loader/loading-task.h>
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/devel-api/adaptor-framework/thread-settings.h>
 #include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 #include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
 
+#ifdef TRACE_ENABLED
+#include <sstream>
+#endif
+
 namespace Dali
 {
 namespace Toolkit
 {
 namespace Internal
 {
+namespace
+{
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false);
+}
+
 LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
 : AsyncTask(callback),
   url(),
@@ -148,6 +158,15 @@ LoadingTask::~LoadingTask()
 
 void LoadingTask::Process()
 {
+#ifdef TRACE_ENABLED
+  if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+  {
+    std::ostringstream oss;
+    oss << "[url:" << (!!(animatedImageLoading) ? animatedImageLoading.GetUrl() : url.GetUrl()) << "]";
+    DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_IMAGE_LOADING_TASK", oss.str().c_str());
+  }
+#endif
+
   isReady = false;
   if(!isMaskTask)
   {
@@ -159,6 +178,23 @@ void LoadingTask::Process()
   }
   MultiplyAlpha();
   isReady = true;
+
+#ifdef TRACE_ENABLED
+  if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+  {
+    std::ostringstream oss;
+    oss << "[";
+    oss << "masking:" << isMaskTask << " ";
+    oss << "index: " << frameIndex << " ";
+    oss << "pixelBuffers: " << pixelBuffers.size() << " ";
+    if(!pixelBuffers.empty())
+    {
+      oss << "premult:" << pixelBuffers[0].IsAlphaPreMultiplied() << " ";
+    }
+    oss << "url:" << (!!(animatedImageLoading) ? animatedImageLoading.GetUrl() : url.GetUrl()) << "]";
+    DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_IMAGE_LOADING_TASK", oss.str().c_str());
+  }
+#endif
 }
 
 bool LoadingTask::IsReady()
index 80d5700..150d857 100644 (file)
@@ -89,13 +89,21 @@ void ParticleEmitter::SetRenderer(const ParticleSystem::ParticleRenderer& render
 
 void ParticleEmitter::SetParticleCount(uint32_t maxParticleCount)
 {
-  // Default particle list has no data streams, it will replace old list
-  mParticleList = ParticleSystem::ParticleList::New(maxParticleCount,
-                                                    ParticleStream::POSITION_STREAM_BIT |
-                                                      ParticleStream::COLOR_STREAM_BIT |
-                                                      ParticleStream::VELOCITY_STREAM_BIT |
-                                                      ParticleStream::SCALE_STREAM_BIT |
-                                                      ParticleStream::LIFETIME_STREAM_BIT);
+  if(!mParticleList || maxParticleCount != GetImplementation(mParticleList).GetParticleCount())
+  {
+    // Default particle list has no data streams, it will replace old list
+    mParticleList = ParticleSystem::ParticleList::New(maxParticleCount,
+                                                      ParticleStream::POSITION_STREAM_BIT |
+                                                        ParticleStream::COLOR_STREAM_BIT |
+                                                        ParticleStream::VELOCITY_STREAM_BIT |
+                                                        ParticleStream::SCALE_STREAM_BIT |
+                                                        ParticleStream::LIFETIME_STREAM_BIT);
+  }
+}
+
+uint32_t ParticleEmitter::GetParticleCount()
+{
+  return GetImplementation(mParticleList).GetParticleCount();
 }
 
 ParticleSystem::ParticleList& ParticleEmitter::GetParticleList()
index 4b09f2b..8b2459e 100644 (file)
@@ -79,6 +79,8 @@ public:
 
   void SetParticleCount(uint32_t maxParticleCount);
 
+  uint32_t GetParticleCount();
+
   ParticleSystem::ParticleList& GetParticleList();
 
   uint32_t AddModifier(const ParticleSystem::ParticleModifier& modifier);
index 87eefa5..123fa66 100644 (file)
@@ -49,6 +49,11 @@ void ParticleRenderer::SetBlendingMode(BlendingMode blendingMode)
   mBlendingMode = blendingMode;
 }
 
+BlendingMode ParticleRenderer::GetBlendingMode() const
+{
+  return mBlendingMode;
+}
+
 void ParticleRenderer::CreateShader()
 {
   // Create shader dynamically
index 59bee33..bad792c 100644 (file)
@@ -60,6 +60,8 @@ public:
 
   void SetBlendingMode(BlendingMode blendingMode);
 
+  BlendingMode GetBlendingMode() const;
+
   bool Initialize();
 
   void PrepareToDie();
index 01e9157..958d663 100644 (file)
@@ -19,6 +19,7 @@
 #include <dali-toolkit/internal/text/controller/text-controller-impl-model-updater.h>
 
 // EXTERNAL INCLUDES
+#include <chrono>
 #include <dali/integration-api/debug.h>
 #include <dali/integration-api/trace.h>
 #include <dali/public-api/math/math-utils.h>
@@ -43,6 +44,18 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT
 
 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false);
 
+#if defined(TRACE_ENABLED)
+uint32_t GetMilliSeconds()
+{
+  // Get the time of a monotonic clock since its epoch.
+  auto epoch = std::chrono::steady_clock::now().time_since_epoch();
+
+  auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
+
+  return static_cast<uint32_t>(duration.count());
+}
+#endif
+
 // The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
 // based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
 constexpr float         BRIGHTNESS_THRESHOLD = 0.179f;
@@ -327,6 +340,20 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
   newParagraphGlyphs.Reserve(numberOfParagraphs);
 
   const Length currentNumberOfGlyphs = glyphs.Count();
+
+#if defined(TRACE_ENABLED)
+  uint32_t logThreshold = TextAbstraction::FontClient::GetPerformanceLogThresholdTime();
+  bool     logEnabled   = TextAbstraction::FontClient::IsPerformanceLogEnabled();
+
+  uint32_t timeStamps[6];
+  uint32_t timeStampIndex = 0;
+
+  if(logEnabled)
+  {
+    timeStamps[timeStampIndex++] = GetMilliSeconds();
+  }
+#endif
+
   if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
   {
     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
@@ -350,6 +377,13 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
     updated = true;
   }
 
+#if defined(TRACE_ENABLED)
+  if(logEnabled)
+  {
+    timeStamps[timeStampIndex++] = GetMilliSeconds();
+  }
+#endif
+
   const Length numberOfGlyphs = static_cast<Length>(glyphs.Count()) - currentNumberOfGlyphs;
 
   if(Controller::NO_OPERATION != (Controller::GET_GLYPH_METRICS & operations))
@@ -370,6 +404,13 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
     updated = true;
   }
 
+#if defined(TRACE_ENABLED)
+  if(logEnabled)
+  {
+    timeStamps[timeStampIndex++] = GetMilliSeconds();
+  }
+#endif
+
   if((nullptr != impl.mEventData) &&
      impl.mEventData->mPreEditFlag &&
      (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count()))
@@ -564,6 +605,13 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
     updated = true;
   }
 
+#if defined(TRACE_ENABLED)
+  if(logEnabled)
+  {
+    timeStamps[timeStampIndex++] = GetMilliSeconds();
+  }
+#endif
+
   if(Controller::NO_OPERATION != (Controller::COLOR & operations))
   {
     // Set the color runs in glyphs.
@@ -589,6 +637,13 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
     updated = true;
   }
 
+#if defined(TRACE_ENABLED)
+  if(logEnabled)
+  {
+    timeStamps[timeStampIndex++] = GetMilliSeconds();
+  }
+#endif
+
   if((Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations)) &&
      !((nullptr != impl.mEventData) &&
        impl.mEventData->mPreEditFlag &&
@@ -608,6 +663,26 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
     updated = true;
   }
 
+#if defined(TRACE_ENABLED)
+  if(logEnabled)
+  {
+    timeStamps[timeStampIndex++] = GetMilliSeconds();
+    uint32_t timeShape   = timeStamps[1] - timeStamps[0];
+    uint32_t timeGlyph   = timeStamps[2] - timeStamps[1];
+    uint32_t timePreedit = timeStamps[3] - timeStamps[2];
+    uint32_t timeColor   = timeStamps[4] - timeStamps[3];
+    uint32_t timeCopy    = timeStamps[5] - timeStamps[4];
+
+    if(timeStamps[5] - timeStamps[0] > logThreshold)
+    {
+      std::string currentText;
+      Utf32ToUtf8(impl.mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
+      DALI_LOG_DEBUG_INFO("DALI_TEXT_MODEL_UPDATE shape:%u ms, glyph:%u ms, preedit:%u ms, color:%u ms, copy:%u ms\n", timeShape, timeGlyph, timePreedit, timeColor, timeCopy);
+      DALI_LOG_DEBUG_INFO("DALI_TEXT_MODEL_UPDATE chars:%d, text:%s\n", numberOfCharacters, currentText.c_str());
+    }
+  }
+#endif
+
   // The estimated number of lines. Used to avoid reallocations when layouting.
   impl.mTextUpdateInfo.mEstimatedNumberOfLines = std::max(impl.mModel->mVisualModel->mLines.Count(), impl.mModel->mLogicalModel->mParagraphInfo.Count());
 
index 9d9fc1b..5fbabd4 100644 (file)
 #include <dali-toolkit/internal/text/shaper.h>
 
 // EXTERNAL INCLUDES
+#include <chrono>
+#include <dali/devel-api/text-abstraction/font-client.h>
 #include <dali/devel-api/text-abstraction/shaping.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 
 namespace Dali
 {
@@ -27,12 +31,26 @@ namespace Toolkit
 {
 namespace Text
 {
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false);
+
 CharacterIndex min(CharacterIndex index0,
                    CharacterIndex index1)
 {
   return (index0 < index1) ? index0 : index1;
 }
 
+#if defined(TRACE_ENABLED)
+uint32_t GetMilliSeconds()
+{
+  // Get the time of a monotonic clock since its epoch.
+  auto epoch = std::chrono::steady_clock::now().time_since_epoch();
+
+  auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
+
+  return static_cast<uint32_t>(duration.count());
+}
+#endif
+
 void ShapeText(const Vector<Character>&     text,
                const Vector<LineBreakInfo>& lineBreakInfo,
                const Vector<ScriptRun>&     scripts,
@@ -51,6 +69,15 @@ void ShapeText(const Vector<Character>&     text,
     return;
   }
 
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_SHAPE_TEXT");
+
+#if defined(TRACE_ENABLED)
+  uint32_t sumPre = 0, sumShape = 0, sumPost = 0;
+
+  uint32_t logThreshold = TextAbstraction::FontClient::GetPerformanceLogThresholdTime();
+  bool     logEnabled   = TextAbstraction::FontClient::IsPerformanceLogEnabled();
+#endif
+
 #ifdef DEBUG_ENABLED
   const Length numberOfFontRuns        = fonts.Count();
   const Length numberOfScriptRuns      = scripts.Count();
@@ -132,6 +159,16 @@ void ShapeText(const Vector<Character>&     text,
   const CharacterIndex lastCharacter = startCharacterIndex + numberOfCharacters;
   for(previousIndex = startCharacterIndex; previousIndex < lastCharacter;)
   {
+#if defined(TRACE_ENABLED)
+    uint32_t timeStamps[4];
+    uint32_t timeStampIndex = 0;
+
+    if(logEnabled)
+    {
+      timeStamps[timeStampIndex++] = GetMilliSeconds();
+    }
+#endif
+
     // Get the font id and the script.
     const FontRun&   fontRun   = *fontRunIt;
     const ScriptRun& scriptRun = *scriptRunIt;
@@ -164,12 +201,26 @@ void ShapeText(const Vector<Character>&     text,
       }
     }
 
+#if defined(TRACE_ENABLED)
+    if(logEnabled)
+    {
+      timeStamps[timeStampIndex++] = GetMilliSeconds();
+    }
+#endif
+
     // Shape the text for the current chunk.
     const Length numberOfGlyphs = shaping.Shape(textBuffer + previousIndex,
                                                 (currentIndex - previousIndex), // The number of characters to shape.
                                                 currentFontId,
                                                 currentScript);
 
+#if defined(TRACE_ENABLED)
+    if(logEnabled)
+    {
+      timeStamps[timeStampIndex++] = GetMilliSeconds();
+    }
+#endif
+
     // Retrieve the glyphs and the glyph to character conversion map.
     Vector<GlyphInfo>      tmpGlyphs;
     Vector<CharacterIndex> tmpGlyphToCharacterMap;
@@ -224,6 +275,16 @@ void ShapeText(const Vector<Character>&     text,
 
     // Update the previous index.
     previousIndex = currentIndex;
+
+#if defined(TRACE_ENABLED)
+    if(logEnabled)
+    {
+      timeStamps[timeStampIndex++] = GetMilliSeconds();
+      sumPre   += timeStamps[1] - timeStamps[0];
+      sumShape += timeStamps[2] - timeStamps[1];
+      sumPost  += timeStamps[3] - timeStamps[2];
+    }
+#endif
   }
 
   // Update indices.
@@ -252,6 +313,16 @@ void ShapeText(const Vector<Character>&     text,
   // Resize the vectors to set the right number of items.
   glyphs.Resize(totalNumberOfGlyphs);
   glyphToCharacterMap.Resize(totalNumberOfGlyphs);
+
+#if defined(TRACE_ENABLED)
+  if(logEnabled)
+  {
+    if(sumPre + sumShape + sumPost > logThreshold)
+    {
+      DALI_LOG_DEBUG_INFO("DALI_TEXT_SHAPE_TEXT updated:%u/%u, pre:%u ms, shape:%u ms, post:%u ms\n", numberOfNewGlyphs, totalNumberOfGlyphs, sumPre, sumShape, sumPost);
+    }
+  }
+#endif
 }
 
 } // namespace Text
index b1e9bea..c19a440 100644 (file)
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 #include <dali/public-api/math/math-utils.h>
 #include <dali/public-api/object/property-array.h>
 
 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
 
+#ifdef TRACE_ENABLED
+#include <sstream>
+#endif
+
 namespace Dali
 {
 namespace Toolkit
@@ -43,6 +48,8 @@ constexpr auto MICROSECONDS_PER_SECOND(1e+6);
 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
 #endif
 
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false);
+
 } // unnamed namespace
 
 VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache)
@@ -136,6 +143,8 @@ bool VectorAnimationTask::IsAnimating()
 
 bool VectorAnimationTask::Load(bool synchronousLoading)
 {
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_LOTTIE_LOADING_TASK");
+
   if(!mVectorRenderer.Load(mUrl))
   {
     DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mUrl.c_str());
@@ -452,6 +461,8 @@ bool VectorAnimationTask::Rasterize()
     return false;
   }
 
+  DALI_TRACE_BEGIN(gTraceFilter, "DALI_LOTTIE_RASTERIZE_TASK");
+
   ApplyAnimationData();
 
   if(mPlayState == PlayState::PLAYING && mUpdateFrameNumber)
@@ -559,6 +570,18 @@ bool VectorAnimationTask::Rasterize()
     mKeepAnimation = true;
   }
 
+#ifdef TRACE_ENABLED
+  if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+  {
+    std::ostringstream oss;
+    oss << "[size: " << mWidth << " x " << mHeight << ", ";
+    oss << "frame: " << mCurrentFrame << ", ";
+    oss << "loop: " << mCurrentLoop << ", ";
+    oss << "state : " << mPlayState << "]";
+    DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_LOTTIE_RASTERIZE_TASK", oss.str().c_str());
+  }
+#endif
+
   return true;
 }
 
index 9d2cfbe..66a9f14 100644 (file)
@@ -47,7 +47,8 @@ VectorAnimationThread::VectorAnimationThread()
   mConditionalWait(),
   mNeedToSleep(false),
   mDestroyThread(false),
-  mLogFactory(Dali::Adaptor::Get().GetLogFactory())
+  mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+  mTraceFactory(Dali::Adaptor::Get().GetTraceFactory())
 {
   mAsyncTaskManager = Dali::AsyncTaskManager::Get();
   mSleepThread.Start();
@@ -176,6 +177,7 @@ void VectorAnimationThread::Run()
 {
   SetThreadName("VectorAnimationThread");
   mLogFactory.InstallLogFunction();
+  mTraceFactory.InstallTraceFunction();
 
   while(!mDestroyThread)
   {
@@ -289,6 +291,7 @@ VectorAnimationThread::SleepThread::SleepThread(CallbackBase* callback)
   mAwakeCallback(std::unique_ptr<CallbackBase>(callback)),
   mSleepTimePoint(),
   mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+  mTraceFactory(Dali::Adaptor::Get().GetTraceFactory()),
   mNeedToSleep(false),
   mDestroyThread(false)
 {
@@ -318,6 +321,7 @@ void VectorAnimationThread::SleepThread::Run()
 {
   SetThreadName("VectorSleepThread");
   mLogFactory.InstallLogFunction();
+  mTraceFactory.InstallTraceFunction();
 
   while(!mDestroyThread)
   {
index 14aa6c9..07537c5 100644 (file)
@@ -21,6 +21,7 @@
 #include <dali/devel-api/threading/conditional-wait.h>
 #include <dali/devel-api/threading/thread.h>
 #include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+#include <dali/integration-api/adaptor-framework/trace-factory-interface.h>
 #include <dali/public-api/adaptor-framework/round-robin-container-view.h>
 #include <dali/public-api/signals/connection-tracker.h>
 #include <memory>
@@ -145,6 +146,7 @@ private:
     std::unique_ptr<CallbackBase>                      mAwakeCallback;
     std::chrono::time_point<std::chrono::steady_clock> mSleepTimePoint;
     const Dali::LogFactoryInterface&                   mLogFactory;
+    const Dali::TraceFactoryInterface&                 mTraceFactory;
     bool                                               mNeedToSleep;
     bool                                               mDestroyThread;
   };
@@ -168,6 +170,7 @@ private:
   bool                                 mDestroyThread;
   bool                                 mEventTriggered{false};
   const Dali::LogFactoryInterface&     mLogFactory;
+  const Dali::TraceFactoryInterface&   mTraceFactory;
   Dali::AsyncTaskManager               mAsyncTaskManager;
 };
 
index 18cf2b4..5b2aff8 100644 (file)
@@ -27,6 +27,7 @@
 #include <dali/devel-api/scripting/scripting.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/actors/layer.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
 #include <dali/public-api/rendering/decorated-visual-renderer.h>
 #include <cstring> // for strlen()
 
@@ -200,6 +201,8 @@ ImageVisual::~ImageVisual()
     {
       RemoveTexture();
     }
+
+    ResetFastTrackLoadingTask();
   }
 }
 
@@ -283,6 +286,10 @@ void ImageVisual::DoSetProperties(const Property::Map& propertyMap)
       {
         DoSetProperty(Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, keyValue.second);
       }
+      else if(keyValue.first == FAST_TRACK_UPLOADING_NAME)
+      {
+        DoSetProperty(Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING, keyValue.second);
+      }
     }
   }
   // Load image immediately if LOAD_POLICY requires it
@@ -477,6 +484,16 @@ void ImageVisual::DoSetProperty(Property::Index index, const Property::Value& va
       }
       break;
     }
+
+    case Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING:
+    {
+      bool fastTrackUploading = false;
+      if(value.Get(fastTrackUploading))
+      {
+        mUseFastTrackUploading = fastTrackUploading;
+      }
+      break;
+    }
   }
 }
 
@@ -634,9 +651,76 @@ void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& te
                              : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
 
   bool synchronousLoading = IsSynchronousLoadingRequired();
-  bool loadingStatus;
+  bool loadingStatus      = false;
+
+  // Remove previous loading task.
+  ResetFastTrackLoadingTask();
+
+  // Rare case. If someone call LoadTexture during fast track loading task running, (Ex : Action::RELOAD)
+  // we should remove previously added renderer now.
+  if(mRendererAdded)
+  {
+    Actor actor = mPlacementActor.GetHandle();
+    if(actor)
+    {
+      actor.RemoveRenderer(mImpl->mRenderer);
+      mRendererAdded = false;
+    }
+  }
+
+  /**
+   * @brief Check whether FastTrackUploading is avaliable or not.
+   * @return True if we can use fast track uploading feature. False otherwise.
+   */
+  auto IsFastTrackUploadingAvailable = [&]() {
+    if(mUseFastTrackUploading &&
+       mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::ATTACHED &&
+       mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED &&
+       forceReload == TextureManager::ReloadPolicy::CACHED &&
+       (mImageUrl.GetProtocolType() == VisualUrl::LOCAL || mImageUrl.GetProtocolType() == VisualUrl::REMOTE) &&
+       !synchronousLoading &&
+       !atlasing &&
+       !mImpl->mCustomShader &&
+       !(mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid()))
+    {
+      return true;
+    }
+    else if(mUseFastTrackUploading)
+    {
+      DALI_LOG_DEBUG_INFO("FastTrack : Fail to load fast track. mUrl : [%s]%s%s%s%s%s%s%s%s\n",
+                          mImageUrl.GetUrl().c_str(),
+                          (mLoadPolicy != Toolkit::ImageVisual::LoadPolicy::ATTACHED) ? "/ mLoadPolicy != ATTACHED" : "",
+                          (mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::DETACHED) ? "/ mReleasePolicy != DETACHED" : "",
+                          (forceReload != TextureManager::ReloadPolicy::CACHED) ? "/ forceReload != CACHED" : "",
+                          (!(mImageUrl.GetProtocolType() == VisualUrl::LOCAL || mImageUrl.GetProtocolType() == VisualUrl::REMOTE)) ? "/ url is not image" : "",
+                          (synchronousLoading) ? "/ synchronousLoading" : "",
+                          (atlasing) ? "/ atlasing" : "",
+                          (mImpl->mCustomShader) ? "/ use customs shader" : "",
+                          (mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid()) ? "/ use masking url" : "");
+    }
+    return false;
+  };
+
+  if(IsFastTrackUploadingAvailable())
+  {
+    // Enable PremultipliedAlpha first.
+    EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
+
+    // Set new TextureSet with fast track loading task
+    mFastTrackLoadingTask = new FastTrackLoadingTask(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mOrientationCorrection, preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF, MakeCallback(this, &ImageVisual::FastLoadComplete));
+
+    TextureSet textureSet = TextureSet::New();
+    textureSet.SetTexture(0u, mFastTrackLoadingTask->mTexture);
+    mImpl->mRenderer.SetTextures(textureSet);
 
-  textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mTextureId, atlasRect, mAtlasRectSize, atlasing, loadingStatus, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection, forceReload, preMultiplyOnLoad);
+    Dali::AsyncTaskManager::Get().AddTask(mFastTrackLoadingTask);
+
+    mLoadState = TextureManager::LoadState::LOADING;
+  }
+  else
+  {
+    textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mTextureId, atlasRect, mAtlasRectSize, atlasing, loadingStatus, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection, forceReload, preMultiplyOnLoad);
+  }
 
   if(textures)
   {
@@ -770,6 +854,7 @@ void ImageVisual::DoSetOnScene(Actor& actor)
   if(mLoadState == TextureManager::LoadState::LOAD_FINISHED)
   {
     actor.AddRenderer(mImpl->mRenderer);
+    mRendererAdded = true;
     mPlacementActor.Reset();
 
     // Image loaded and ready to display
@@ -780,6 +865,14 @@ void ImageVisual::DoSetOnScene(Actor& actor)
     ShowBrokenImage();
     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
   }
+  else
+  {
+    if(mFastTrackLoadingTask)
+    {
+      actor.AddRenderer(mImpl->mRenderer);
+      mRendererAdded = true;
+    }
+  }
 }
 
 void ImageVisual::DoSetOffScene(Actor& actor)
@@ -788,6 +881,8 @@ void ImageVisual::DoSetOffScene(Actor& actor)
 
   // Image release is dependent on the ReleasePolicy, renderer is removed.
   actor.RemoveRenderer(mImpl->mRenderer);
+  mRendererAdded = false;
+
   if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
   {
     ResetRenderer();
@@ -830,6 +925,8 @@ void ImageVisual::DoCreatePropertyMap(Property::Map& map) const
   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::DevelImageVisual::Property::FAST_TRACK_UPLOADING, mUseFastTrackUploading);
 }
 
 void ImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
@@ -885,6 +982,7 @@ void ImageVisual::UploadCompleted()
   {
     mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect);
     actor.AddRenderer(mImpl->mRenderer);
+    mRendererAdded = true;
     // reset the weak handle so that the renderer only get added to actor once
     mPlacementActor.Reset();
   }
@@ -894,6 +992,39 @@ void ImageVisual::UploadCompleted()
   mLoadState = TextureManager::LoadState::LOAD_FINISHED;
 }
 
+// From FastTrackLoadingTask
+void ImageVisual::FastLoadComplete(FastTrackLoadingTaskPtr task)
+{
+  Toolkit::Visual::ResourceStatus resourceStatus;
+
+  DALI_ASSERT_ALWAYS(mFastTrackLoadingTask == task && "Task was not canceled successfully!");
+  DALI_ASSERT_ALWAYS(mRendererAdded && "Some FastTrack logic missed!");
+
+  Actor actor = mPlacementActor.GetHandle();
+
+  if(mFastTrackLoadingTask && mFastTrackLoadingTask->mLoadSuccess)
+  {
+    resourceStatus = Toolkit::Visual::ResourceStatus::READY;
+    mLoadState     = TextureManager::LoadState::LOAD_FINISHED;
+
+    // Change premultiplied alpha flag after change renderer.
+    EnablePreMultipliedAlpha(mFastTrackLoadingTask->mPremultiplied);
+  }
+  else
+  {
+    resourceStatus    = Toolkit::Visual::ResourceStatus::FAILED;
+    mLoadState        = TextureManager::LoadState::LOAD_FAILED;
+
+    // Change renderer as broken.
+    ShowBrokenImage();
+  }
+
+  mFastTrackLoadingTask.Reset();
+
+  // Signal to observers ( control ) that resources are ready. Must be all resources.
+  ResourceReady(resourceStatus);
+}
+
 // From Texture Manager
 void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureInformation)
 {
@@ -938,6 +1069,7 @@ void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureIn
       if(actor)
       {
         actor.AddRenderer(mImpl->mRenderer);
+        mRendererAdded = true;
         // reset the weak handle so that the renderer only get added to actor once
         mPlacementActor.Reset();
       }
@@ -1005,6 +1137,8 @@ void ImageVisual::RemoveTexture()
   }
   else
   {
+    ResetFastTrackLoadingTask();
+
     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)
@@ -1200,21 +1334,46 @@ void ImageVisual::ShowBrokenImage()
     {
       imageSize           = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
       mPlacementActorSize = imageSize;
+
+      if(mRendererAdded)
+      {
+        actor.RemoveRenderer(mImpl->mRenderer);
+        mRendererAdded = false;
+      }
     }
 
     mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
     if(actor)
     {
       actor.AddRenderer(mImpl->mRenderer);
+      mRendererAdded = true;
       mPlacementActor.Reset();
     }
   }
   else
   {
+    if(mRendererAdded)
+    {
+      Actor actor = mPlacementActor.GetHandle();
+      if(actor)
+      {
+        actor.RemoveRenderer(mImpl->mRenderer);
+        mRendererAdded = false;
+      }
+    }
     ResetRenderer();
   }
 }
 
+void ImageVisual::ResetFastTrackLoadingTask()
+{
+  if(mFastTrackLoadingTask)
+  {
+    Dali::AsyncTaskManager::Get().RemoveTask(mFastTrackLoadingTask);
+    mFastTrackLoadingTask.Reset();
+  }
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 1bd414b..925cdad 100644 (file)
 #include <dali/public-api/common/intrusive-ptr.h>
 #include <dali/public-api/images/image-operations.h>
 #include <dali/public-api/object/weak-handle.h>
+#include <dali/public-api/rendering/visual-renderer.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/image-loader/atlas-upload-observer.h>
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/internal/image-loader/fast-track-loading-task.h>
 #include <dali-toolkit/internal/texture-manager/texture-upload-observer.h>
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
 #include <dali-toolkit/internal/visuals/visual-url.h>
@@ -250,6 +252,13 @@ public:
    */
   void LoadComplete(bool success, TextureInformation textureInformation) override;
 
+  /**
+   * @brief Test callback for FastTrackLoadingTask
+   *
+   * @param[in] task The pointer of task who call this callback.
+   */
+  void FastLoadComplete(FastTrackLoadingTaskPtr task);
+
 private:
   /**
    * Allocate the mask data when a masking property is defined in the property map
@@ -333,6 +342,11 @@ private:
    */
   void ShowBrokenImage();
 
+  /**
+   * @brief Remove current added fast track upload task.
+   */
+  void ResetFastTrackLoadingTask();
+
 private:
   Vector4                            mPixelArea;
   WeakHandle<Actor>                  mPlacementActor;
@@ -345,6 +359,8 @@ private:
   Vector2                   mTextureSize;
   Vector2                   mPlacementActorSize;
 
+  FastTrackLoadingTaskPtr mFastTrackLoadingTask; ///< For fast track uploading.
+
   ImageVisualShaderFactory& mImageVisualShaderFactory;
 
   Dali::FittingMode::Type                         mFittingMode : 3;
@@ -355,11 +371,13 @@ private:
   Dali::Toolkit::ImageVisual::ReleasePolicy::Type mReleasePolicy;
   Vector4                                         mAtlasRect;
   Dali::ImageDimensions                           mAtlasRectSize;
-  TextureManager::LoadState                       mLoadState;             ///< The texture loading state
-  bool                                            mAttemptAtlasing;       ///< If true will attempt atlasing, otherwise create unique texture
-  bool                                            mOrientationCorrection; ///< true if the image will have it's orientation corrected.
-  bool                                            mNeedYuvToRgb{false};   ///< true if we need to convert yuv to rgb.
-  bool                                            mEnableBrokenImage;
+  TextureManager::LoadState                       mLoadState;                    ///< The texture loading state
+  bool                                            mAttemptAtlasing;              ///< If true will attempt atlasing, otherwise create unique texture
+  bool                                            mOrientationCorrection;        ///< true if the image will have it's orientation corrected.
+  bool                                            mNeedYuvToRgb{false};          ///< true if we need to convert yuv to rgb.
+  bool                                            mEnableBrokenImage{true};      ///< true if enable broken image.
+  bool                                            mUseFastTrackUploading{false}; ///< True if we use fast tack feature.
+  bool                                            mRendererAdded{false};         ///< True if renderer added into actor.
 };
 
 } // namespace Internal
index 172eab6..d36eeb1 100644 (file)
@@ -74,7 +74,7 @@ void NPatchVisual::LoadImages()
   TextureManager& textureManager     = mFactoryCache.GetTextureManager();
   bool            synchronousLoading = mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
 
-  if(mId == NPatchData::INVALID_NPATCH_DATA_ID && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()))
+  if(mId == NPatchData::INVALID_NPATCH_DATA_ID)
   {
     bool preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader ? true : false;
     mId                    = mLoader.Load(textureManager, this, mImageUrl, mBorder, preMultiplyOnLoad, synchronousLoading);
@@ -86,7 +86,7 @@ void NPatchVisual::LoadImages()
     }
   }
 
-  if(mAuxiliaryTextureId == TextureManager::INVALID_TEXTURE_ID && mAuxiliaryUrl.IsValid() && (mAuxiliaryUrl.IsLocalResource() || mAuxiliaryUrl.IsBufferResource()))
+  if(mAuxiliaryTextureId == TextureManager::INVALID_TEXTURE_ID && mAuxiliaryUrl.IsValid())
   {
     auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader
                                ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
index 7b8ef29..bcd0f91 100644 (file)
 #include <dali/devel-api/adaptor-framework/file-loader.h>
 #include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
 
+#ifdef TRACE_ENABLED
+#include <sstream>
+#endif
+
 namespace Dali
 {
 namespace Toolkit
 {
 namespace Internal
 {
+namespace
+{
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false);
+}
+
 SvgTask::SvgTask(VectorImageRenderer vectorRenderer, CallbackBase* callback, AsyncTask::PriorityType priorityType)
 : AsyncTask(callback, priorityType),
   mVectorRenderer(vectorRenderer),
@@ -74,6 +84,8 @@ void SvgLoadingTask::Process()
     return;
   }
 
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_SVG_LOADING_TASK");
+
   Dali::Vector<uint8_t> buffer;
 
   if(!mUrl.IsLocalResource())
@@ -128,15 +140,26 @@ void SvgRasterizingTask::Process()
     return;
   }
 
+#ifdef TRACE_ENABLED
+  if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+  {
+    std::ostringstream oss;
+    oss << "[size: " << mWidth << " x " << mHeight << "]";
+    DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_SVG_RASTERIZE_TASK", oss.str().c_str());
+  }
+#endif
+
   Devel::PixelBuffer pixelBuffer = mVectorRenderer.Rasterize(mWidth, mHeight);
   if(!pixelBuffer)
   {
     DALI_LOG_ERROR("Rasterize is failed!\n");
+    DALI_TRACE_END(gTraceFilter, "DALI_SVG_RASTERIZE_TASK");
     return;
   }
 
   mPixelData    = Devel::PixelBuffer::Convert(pixelBuffer);
   mHasSucceeded = true;
+  DALI_TRACE_END(gTraceFilter, "DALI_SVG_RASTERIZE_TASK");
 }
 
 bool SvgRasterizingTask::IsReady()
index 2a1b09f..8f9919d 100644 (file)
@@ -234,12 +234,7 @@ void SvgVisual::DoSetOnScene(Actor& actor)
 
 void SvgVisual::DoSetOffScene(Actor& actor)
 {
-  // Remove loading & rasterizing task
-  if(mLoadingTask)
-  {
-    Dali::AsyncTaskManager::Get().RemoveTask(mLoadingTask);
-    mLoadingTask.Reset();
-  }
+  // Remove rasterizing task
   if(mRasterizingTask)
   {
     Dali::AsyncTaskManager::Get().RemoveTask(mRasterizingTask);
index ec888ce..0ffa198 100644 (file)
@@ -123,6 +123,7 @@ const char* const ALPHA_MASK_URL("alphaMaskUrl");
 const char* const REDRAW_IN_SCALING_DOWN_NAME("redrawInScalingDown");
 const char* const MASKING_TYPE_NAME("maskingType");
 const char* const MASK_TEXTURE_RATIO_NAME("maskTextureRatio");
+const char* const FAST_TRACK_UPLOADING_NAME("fastTrackUploading");
 const char* const ENABLE_BROKEN_IMAGE("enableBrokenImage");
 
 // Text visual
index 29d75a9..ff492ec 100644 (file)
@@ -107,6 +107,7 @@ extern const char* const ALPHA_MASK_URL;
 extern const char* const REDRAW_IN_SCALING_DOWN_NAME;
 extern const char* const MASKING_TYPE_NAME;
 extern const char* const MASK_TEXTURE_RATIO_NAME;
+extern const char* const FAST_TRACK_UPLOADING_NAME;
 extern const char* const ENABLE_BROKEN_IMAGE;
 
 // Text visual
index 97d5585..3205a0c 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 2;
-const unsigned int TOOLKIT_MICRO_VERSION = 38;
+const unsigned int TOOLKIT_MICRO_VERSION = 39;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index c854e23..e40f159 100644 (file)
@@ -62,6 +62,11 @@ void ParticleEmitter::SetParticleCount(uint32_t maxParticleCount)
   GetImplementation(*this).SetParticleCount(maxParticleCount);
 }
 
+uint32_t ParticleEmitter::GetParticleCount()
+{
+  return GetImplementation(*this).GetParticleCount();
+}
+
 ParticleDomain ParticleEmitter::GetDomain() const
 {
   return GetImplementation(*this).GetDomain();
index 15e3aa7..dffa6e7 100644 (file)
@@ -200,6 +200,13 @@ public:
   void SetParticleCount(uint32_t maxParticleCount);
 
   /**
+   * @brief Returns maximum number of particles in the system
+   *
+   * @return Maximum number of particles
+   */
+  uint32_t GetParticleCount();
+
+  /**
    * @brief Returns currently used particle emitter domain
    *
    * @return Handle to the ParticleDomain object
@@ -213,7 +220,6 @@ public:
    */
   [[nodiscard]] ParticleRenderer GetRenderer() const;
 
-
   /**
    * @brief Attaches particle system to an actor
    *
index 6b1e18a..88cdf80 100644 (file)
@@ -94,6 +94,11 @@ uint32_t ParticleList::GetParticleDataSize(bool includeLocalStreams)
   return GetImplementation(*this).GetStreamElementSize(includeLocalStreams);
 }
 
+int ParticleList::GetDefaultStreamIndex(ParticleStreamTypeFlagBit defaultStreamBit)
+{
+  return GetImplementation(*this).GetDefaultStreamIndex(defaultStreamBit);
+}
+
 std::list<Particle>& ParticleList::GetActiveParticles()
 {
   return GetImplementation(*this).GetParticles();
@@ -101,5 +106,4 @@ std::list<Particle>& ParticleList::GetActiveParticles()
 
 ParticleList::ParticleList() = default;
 
-
 } // namespace Dali::Toolkit::ParticleSystem
\ No newline at end of file
index c165159..7fea6b6 100644 (file)
 #include <dali-toolkit/public-api/particle-system/particle.h>
 
 // EXTERNAL INCLUDES
-#include <dali/public-api/object/base-handle.h>
 #include <dali/public-api/common/list-wrapper.h>
+#include <dali/public-api/object/base-handle.h>
 #include <cinttypes>
 
-
 namespace Dali::Toolkit::ParticleSystem::Internal
 {
 class ParticleList;
@@ -221,6 +220,14 @@ public:
    */
   uint32_t GetParticleDataSize(bool includeLocalStreams);
 
+  /**
+   * @brief Returns index associated with specified default stream
+   *
+   * @param[in] defaultStreamBit Default stream bit
+   * @return Returns a valid index or -1 on error.
+   */
+  int GetDefaultStreamIndex(ParticleStreamTypeFlagBit defaultStreamBit);
+
   std::list<Particle>& GetActiveParticles();
 
 private:
index 472499e..9542289 100644 (file)
@@ -37,4 +37,9 @@ ParticleModifier ParticleModifier::DownCast(BaseHandle handle)
   return {dynamic_cast<Internal::ParticleModifier*>(handle.GetObjectPtr())};
 }
 
+ParticleModifierInterface& ParticleModifier::GetModifierCallback()
+{
+  return GetImplementation(*this).GetUpdater();
+}
+
 } // namespace Dali::Toolkit::ParticleSystem
\ No newline at end of file
index de8d4e6..1769d57 100644 (file)
@@ -112,6 +112,12 @@ public:
   {
     return New(std::move(std::make_unique<T>(args...)));
   }
+  /**
+   * @brief Returns associated particle modifier callback
+   *
+   * @return Valid reference to associated callback
+   */
+  ParticleModifierInterface& GetModifierCallback();
 
   /**
    * @brief Downcasts a handle to ParticleModifier handle.
index 05e9b40..c73949f 100644 (file)
@@ -40,6 +40,11 @@ void ParticleRenderer::SetBlendingMode(BlendingMode blendingMode)
   GetImplementation(*this).SetBlendingMode(blendingMode);
 }
 
+BlendingMode ParticleRenderer::GetBlendingMode() const
+{
+  return GetImplementation(*this).GetBlendingMode();
+}
+
 ParticleRenderer ParticleRenderer::DownCast(BaseHandle handle)
 {
   return {dynamic_cast<Internal::ParticleRenderer*>(handle.GetObjectPtr())};
index 0e0a35b..8474c54 100644 (file)
@@ -66,6 +66,13 @@ public:
   void SetBlendingMode(BlendingMode blendingMode);
 
   /**
+   * @brief Sets blending mode for the renderer
+   *
+   * @return Current blending mode
+   */
+  BlendingMode GetBlendingMode() const;
+
+  /**
    * @brief Sets renderable as a 2D texture (sprites)
    *
    * @param[in] texture Valid texture
index 971a603..7e5b9c9 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.2.38
+Version:    2.2.39
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT