[Tizen] TextureUploadManager implement 96/296296/1
authorEunki, Hong <eunkiki.hong@samsung.com>
Mon, 19 Jun 2023 02:51:50 +0000 (11:51 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Tue, 25 Jul 2023 04:55:57 +0000 (13:55 +0900)
Let we make a method to upload PixelData into
Graphics::Texture object from worker-thread way.

1. Generate Dali::Texture from TextureUploadManager.
2. Get ResourceId from generated texture.
3. RequestUpload from worker thread.
4. Next update/render thread loop will upload resource into GPU.

Change-Id: I21f226bdb762e71edfbbc27869207b32828bd933
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
15 files changed:
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.h
dali/devel-api/adaptor-framework/texture-upload-manager.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/texture-upload-manager.h [new file with mode: 0644]
dali/devel-api/file.list
dali/internal/adaptor/common/adaptor-impl.cpp
dali/internal/adaptor/common/adaptor-impl.h
dali/internal/adaptor/common/adaptor-internal-services.h
dali/internal/adaptor/common/combined-update-render-controller.cpp
dali/internal/adaptor/common/combined-update-render-controller.h
dali/internal/graphics/gles-impl/egl-graphics-controller.cpp
dali/internal/graphics/gles-impl/egl-graphics-controller.h
dali/internal/system/common/texture-upload-manager-impl.cpp [new file with mode: 0644]
dali/internal/system/common/texture-upload-manager-impl.h [new file with mode: 0644]
dali/internal/system/file.list

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
   {
   };
diff --git a/dali/devel-api/adaptor-framework/texture-upload-manager.cpp b/dali/devel-api/adaptor-framework/texture-upload-manager.cpp
new file mode 100644 (file)
index 0000000..ffbdfca
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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/devel-api/adaptor-framework/texture-upload-manager.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/texture-upload-manager-impl.h>
+
+namespace Dali::Devel
+{
+// Called by main thread
+
+TextureUploadManager::TextureUploadManager() = default;
+
+TextureUploadManager::~TextureUploadManager() = default;
+
+TextureUploadManager TextureUploadManager::Get()
+{
+  return Internal::Adaptor::TextureUploadManager::Get();
+}
+
+Dali::Texture TextureUploadManager::GenerateTexture2D()
+{
+  return GetImplementation(*this).GenerateTexture2D();
+}
+
+TextureUploadManager::TextureUploadManager(Internal::Adaptor::TextureUploadManager* impl)
+: BaseHandle(impl)
+{
+}
+
+// Called by update thread
+
+bool TextureUploadManager::ResourceUpload()
+{
+  return GetImplementation(*this).ResourceUpload();
+}
+
+// Called by worker thread
+
+void TextureUploadManager::RequestUpload(ResourceId resourceId, PixelData pixelData)
+{
+  GetImplementation(*this).RequestUpload(resourceId, pixelData);
+}
+
+} // namespace Dali::Devel
diff --git a/dali/devel-api/adaptor-framework/texture-upload-manager.h b/dali/devel-api/adaptor-framework/texture-upload-manager.h
new file mode 100644 (file)
index 0000000..a835def
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef DALI_DEVEL_TEXTURE_UPLOAD_MANAGER_H
+#define DALI_DEVEL_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/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/rendering/texture.h>
+#include <stdint.h> ///< For uint32_t
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor DALI_INTERNAL
+{
+class TextureUploadManager;
+} // namespace DALI_INTERNAL
+} // namespace DALI_INTERNAL
+
+namespace Devel
+{
+/**
+ * The manager that make we can upload resource into texture from the worker thread.
+ * @code
+ * (Event Thread)
+ * someAsyncTask.mUploadManager = TextureUploadManager::Get();
+ * someAsyncTask.mTexture = someAsyncTask.mUploadManager.GenerateTexture2D();
+ * someAsyncTask.mResourceId = Integration::GetTextureResourceId(someAsyncTask.mTexture);
+ * AsyncTaskManager::Get().AddTask(someAsyncTask);
+ *
+ * (Worker Thread)
+ * SomeAsyncTask::Process()
+ * {
+ *   PixelData pixelData = LoadImage();
+ *   ...
+ *   mUploadManager.RequestUpload(mResourceId, pixelData); // Upload to Graphics::Texture paired by UploadResourceId.
+ * }
+ * @endcode
+ *
+ * @SINCE_2_2.37
+ */
+class DALI_ADAPTOR_API TextureUploadManager : public BaseHandle
+{
+public:
+  using ResourceId                                = uint32_t;
+  constexpr static ResourceId INVALID_RESOURCE_ID = 0u;
+
+public: // Callbed by main thread.
+  /**
+   * Constructor.
+   * @SINCE_2_2.37
+   */
+  TextureUploadManager();
+
+  /**
+   * Destructor.
+   * @SINCE_2_2.37
+   */
+  ~TextureUploadManager();
+
+  /**
+   * @brief Gets the singleton of TextureUploadManager object.
+   *
+   * @SINCE_2_2.37
+   * @return A handle to the TextureUploadManager
+   */
+  static TextureUploadManager Get();
+
+  /**
+   * @brief Generate the texture 2d that hold unique id for upload resources, called by main thread.
+   *
+   * @SINCE_2_2.37
+   * @return The texture that hold unique id of upload resource.
+   */
+  Dali::Texture GenerateTexture2D();
+
+public: // Called by update thread.
+  /**
+   * @brief Upload all requested resources by RequestUpload.
+   *
+   * @SINCE_2_2.37
+   * @return True if there was at least 1 resources uploaded.
+   */
+  bool ResourceUpload();
+
+public: // Can be callbed by worker thread.
+  /**
+   * @brief Request upload PixelData to given ResourceId.
+   * @note We should not request invalid resouceId.
+   * @note We should not request mutiple times into same resourceId.
+   *
+   * @SINCE_2_2.37
+   * @param[in] resourceId The id of resource.
+   * @param[in] pixelData The buffer of resource.
+   */
+  void RequestUpload(ResourceId resourceId, PixelData pixelData);
+
+public:
+  /// @cond internal
+  /**
+   * @brief Allows the creation of a TextureUploadManager handle from an internal pointer.
+   *
+   * @note Not intended for application developers
+   * @SINCE_2_2.37
+   * @param[in] impl A pointer to the object
+   */
+  explicit DALI_INTERNAL TextureUploadManager(Internal::Adaptor::TextureUploadManager* impl);
+  /// @endcond
+};
+} // namespace Devel
+
+} // namespace Dali
+
+#endif
index b357dc9..caf26c1 100755 (executable)
@@ -40,6 +40,7 @@ SET( devel_api_src_files
   ${adaptor_devel_api_dir}/adaptor-framework/pixel-buffer.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/sound-player.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/style-monitor.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/texture-upload-manager.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/tilt-sensor.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/lifecycle-controller.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/vector-animation-renderer.cpp
@@ -95,6 +96,7 @@ SET( devel_api_adaptor_framework_header_files
   ${adaptor_devel_api_dir}/adaptor-framework/proxy-accessible.h
   ${adaptor_devel_api_dir}/adaptor-framework/sound-player.h
   ${adaptor_devel_api_dir}/adaptor-framework/style-monitor.h
+  ${adaptor_devel_api_dir}/adaptor-framework/texture-upload-manager.h
   ${adaptor_devel_api_dir}/adaptor-framework/tilt-sensor.h
   ${adaptor_devel_api_dir}/adaptor-framework/vector-animation-renderer.h
   ${adaptor_devel_api_dir}/adaptor-framework/vector-animation-renderer-plugin.h
index af57022..2514ac8 100644 (file)
@@ -182,6 +182,9 @@ void Adaptor::Initialize(GraphicsFactory& graphicsFactory)
                                  mGraphics->GetStencilBufferRequired(),
                                  mGraphics->GetPartialUpdateRequired());
 
+  // Create TextureUploadManager after mCore created
+  mTextureUploadManager = Dali::Devel::TextureUploadManager::Get();
+
   defaultWindow->SetAdaptor(Get());
 
   Dali::Integration::SceneHolder defaultSceneHolder(defaultWindow);
@@ -847,6 +850,11 @@ void Adaptor::GetWindowContainerInterface(WindowContainer& windows)
   windows = mWindows;
 }
 
+Devel::TextureUploadManager& Adaptor::GetTextureUploadManager()
+{
+  return mTextureUploadManager;
+}
+
 void Adaptor::DestroyTtsPlayer(Dali::TtsPlayer::Mode mode)
 {
   if(mTtsPlayers[mode])
@@ -1281,6 +1289,7 @@ Adaptor::Adaptor(Dali::Integration::SceneHolder window, Dali::Adaptor& adaptor,
   mPerformanceInterface(nullptr),
   mKernelTracer(),
   mSystemTracer(),
+  mTextureUploadManager(),
   mObjectProfiler(nullptr),
   mMemoryPoolTimerSlotDelegate(this),
   mSocketFactory(),
index a1e5be6..f07b47d 100644 (file)
@@ -174,6 +174,9 @@ public:
    */
   void SceneCreated();
 
+  /**
+   * Get the application package name
+   */
   static std::string GetApplicationPackageName();
 
 public: // AdaptorInternalServices implementation
@@ -515,6 +518,11 @@ public: //AdaptorInternalServices
   void GetWindowContainerInterface(WindowContainer& windows) override;
 
   /**
+   * copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetTextureUploadManager()
+   */
+  Devel::TextureUploadManager& GetTextureUploadManager() override;
+
+  /**
    * @brief Get the configuration manager
    * @return The configuration manager, or null if it hasn't been created yet
    */
@@ -701,6 +709,7 @@ private:                                          // Data
   PerformanceInterface*            mPerformanceInterface;                  ///< Performance interface
   KernelTrace                      mKernelTracer;                          ///< Kernel tracer
   SystemTrace                      mSystemTracer;                          ///< System tracer
+  Devel::TextureUploadManager      mTextureUploadManager;                  ///< TextureUploadManager
   ObjectProfiler*                  mObjectProfiler;                        ///< Tracks object lifetime for profiling
   Dali::Timer                      mMemoryPoolTimer;                       ///< Logs memory pool capacity
   SlotDelegate<Adaptor>            mMemoryPoolTimerSlotDelegate;
index 1b6f8f4..af75f62 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ADAPTOR_INTERNAL_SERVICES_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.
@@ -23,6 +23,7 @@
 #include <dali/integration-api/gl-abstraction.h>
 
 // INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
 #include <dali/integration-api/adaptor-framework/trigger-event-interface.h>
 #include <dali/internal/graphics/common/graphics-interface.h>
@@ -105,6 +106,11 @@ public:
   virtual TraceInterface& GetSystemTraceInterface() = 0;
 
   /**
+   * @return texture upload manager
+   */
+  virtual Devel::TextureUploadManager& GetTextureUploadManager() = 0;
+
+  /**
    * Used to access the list of windows from the Render thread
    * @param[out] windows The list of created windows
    */
index db68e43..51f57a1 100644 (file)
@@ -31,6 +31,7 @@
 #include <dali/internal/graphics/common/graphics-interface.h>
 #include <dali/internal/graphics/gles/egl-graphics.h>
 #include <dali/internal/system/common/environment-options.h>
+#include <dali/internal/system/common/texture-upload-manager-impl.h>
 #include <dali/internal/system/common/time-service.h>
 #include <dali/internal/thread/common/thread-settings-impl.h>
 #include <dali/internal/window-system/common/window-impl.h>
@@ -98,6 +99,7 @@ CombinedUpdateRenderController::CombinedUpdateRenderController(AdaptorInternalSe
   mNotificationTrigger(adaptorInterfaces.GetProcessCoreEventsTrigger()),
   mSleepTrigger(NULL),
   mPreRenderCallback(NULL),
+  mTextureUploadManager(adaptorInterfaces.GetTextureUploadManager()),
   mUpdateRenderThread(NULL),
   mDefaultFrameDelta(0.0f),
   mDefaultFrameDurationMilliseconds(0u),
@@ -520,6 +522,9 @@ void CombinedUpdateRenderController::UpdateRenderThread()
   Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
   displayConnection.Initialize(); //@todo Move InitializeGraphics code into graphics implementation
 
+  // Setup graphics controller into upload manager.
+  GetImplementation(mTextureUploadManager).InitalizeGraphicsController(graphics.GetController());
+
   NotifyGraphicsInitialised();
 
   //@todo Vk swaps this around, but we need to support surfaceless context for multi-window
@@ -595,6 +600,18 @@ void CombinedUpdateRenderController::UpdateRenderThread()
       SurfaceReplaced();
     }
 
+    //////////////////////////////
+    // TextureUploadRequest
+    //////////////////////////////
+
+    // Upload requested resources after resource context activated.
+    graphics.ActivateResourceContext();
+
+    const bool textureUploaded = mTextureUploadManager.ResourceUpload();
+
+    // Update & Render forcely if there exist some uploaded texture.
+    uploadOnly = textureUploaded ? false : uploadOnly;
+
     const bool isRenderingToFbo = renderToFboEnabled && ((0u == frameCount) || (0u != frameCount % renderToFboInterval));
     ++frameCount;
 
index 8902875..bec2f70 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_COMBINED_UPDATE_RENDER_CONTROLLER_H
 
 /*
- * Copyright (c) 2022 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.
@@ -28,6 +28,7 @@
 #include <atomic>
 
 // INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
 #include <dali/integration-api/adaptor-framework/thread-synchronization-interface.h>
 #include <dali/internal/adaptor/common/thread-controller-interface.h>
 #include <dali/internal/system/common/fps-tracker.h>
@@ -349,6 +350,8 @@ private:
   TriggerEventInterface*    mSleepTrigger;         ///< Used by the update-render thread to trigger the event thread when it no longer needs to do any updates
   CallbackBase*             mPreRenderCallback;    ///< Used by Update/Render thread when PreRender is about to be called on graphics.
 
+  Dali::Devel::TextureUploadManager& mTextureUploadManager; ///< TextureUploadManager
+
   pthread_t* mUpdateRenderThread; ///< The Update/Render thread.
 
   float mDefaultFrameDelta; ///< Default time delta between each frame (used for animations). Not protected by lock, but written to rarely so not worth adding a lock when reading.
index 81616aa..12c4723 100644 (file)
@@ -959,4 +959,57 @@ GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
   return *mPipelineCache;
 }
 
+Graphics::Texture* EglGraphicsController::CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo)
+{
+  Graphics::Texture*                     ret = nullptr;
+  Graphics::UniquePtr<Graphics::Texture> texture;
+
+  auto iter = mExternalTextureResources.find(resourceId);
+  DALI_ASSERT_ALWAYS(iter == mExternalTextureResources.end());
+
+  texture = CreateTexture(createInfo, std::move(texture));
+
+  ret = texture.get();
+
+  mExternalTextureResources.insert(std::make_pair(resourceId, std::move(texture)));
+
+  return ret;
+}
+
+void EglGraphicsController::DiscardTextureFromResourceId(uint32_t resourceId)
+{
+  auto iter = mExternalTextureResources.find(resourceId);
+  if(iter != mExternalTextureResources.end())
+  {
+    mExternalTextureResources.erase(iter);
+  }
+}
+
+Graphics::Texture* EglGraphicsController::GetTextureFromResourceId(uint32_t resourceId)
+{
+  Graphics::Texture* ret = nullptr;
+
+  auto iter = mExternalTextureResources.find(resourceId);
+  if(iter != mExternalTextureResources.end())
+  {
+    ret = iter->second.get();
+  }
+
+  return ret;
+}
+
+Graphics::UniquePtr<Graphics::Texture> EglGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId)
+{
+  Graphics::UniquePtr<Graphics::Texture> texture;
+
+  auto iter = mExternalTextureResources.find(resourceId);
+  if(iter != mExternalTextureResources.end())
+  {
+    texture = std::move(iter->second);
+    mExternalTextureResources.erase(iter);
+  }
+
+  return texture;
+}
+
 } // namespace Dali::Graphics
index 4693721..2c3f435 100644 (file)
  */
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/common/map-wrapper.h>
 #include <dali/graphics-api/graphics-controller.h>
 #include <queue>
+#include <unordered_map>
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/graphics-sync-abstraction.h>
@@ -315,6 +317,28 @@ public:
     return {};
   }
 
+public: // ResourceId relative API.
+  /**
+   * @copydoc Dali::Graphics::CreateTextureByResourceId()
+   */
+  Graphics::Texture* CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo) override;
+
+  /**
+   * @copydoc Dali::Graphics::DiscardTextureFromResourceId()
+   */
+  void DiscardTextureFromResourceId(uint32_t resourceId) override;
+
+  /**
+   * @copydoc Dali::Graphics::GetTextureFromResourceId()
+   */
+  Graphics::Texture* GetTextureFromResourceId(uint32_t resourceId) override;
+
+  /**
+   * @copydoc Dali::Graphics::ReleaseTextureFromResourceId()
+   */
+  Graphics::UniquePtr<Graphics::Texture> ReleaseTextureFromResourceId(uint32_t resourceId) override;
+
+public:
   [[nodiscard]] Integration::GlAbstraction* GetGL() const
   {
     if(mIsShuttingDown)
@@ -810,6 +834,8 @@ private:
   using TextureUpdateRequest = std::pair<TextureUpdateInfo, TextureUpdateSourceInfo>;
   std::queue<TextureUpdateRequest> mTextureUpdateRequests;
 
+  std::unordered_map<uint32_t, Graphics::UniquePtr<Graphics::Texture>> mExternalTextureResources; ///< Used for ResourceId.
+
   std::queue<const GLES::Texture*> mTextureMipmapGenerationRequests; ///< Queue for texture mipmap generation requests
 
   GLES::Context*                 mCurrentContext{nullptr}; ///< The current context
diff --git a/dali/internal/system/common/texture-upload-manager-impl.cpp b/dali/internal/system/common/texture-upload-manager-impl.cpp
new file mode 100644 (file)
index 0000000..9100b09
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * 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/internal/system/common/texture-upload-manager-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/graphics-api/graphics-texture-upload-helper.h> ///< for Dali::Graphics::ConvertPixelFormat
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/pixel-data-integ.h>
+#include <dali/integration-api/texture-integ.h>
+#include <dali/integration-api/trace.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+namespace
+{
+Dali::Devel::TextureUploadManager::ResourceId gUniqueResourceId = 0;
+
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gTextureUploadManagerLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_TEXTURE_UPLOAD_MANAGER");
+#endif
+
+} // unnamed namespace
+
+// Called by main thread
+
+Dali::Devel::TextureUploadManager TextureUploadManager::Get()
+{
+  Dali::Devel::TextureUploadManager manager;
+  SingletonService                  singletonService(SingletonService::Get());
+  if(singletonService)
+  {
+    // Check whether the texture upload manager is already created
+    Dali::BaseHandle handle = singletonService.GetSingleton(typeid(Dali::Devel::TextureUploadManager));
+    if(handle)
+    {
+      // If so, downcast the handle of singleton
+      manager = Dali::Devel::TextureUploadManager(dynamic_cast<Internal::Adaptor::TextureUploadManager*>(handle.GetObjectPtr()));
+    }
+
+    if(!manager)
+    {
+      // If not, create the texture upload manager and register it as a singleton
+      Internal::Adaptor::TextureUploadManager* internalTextureUploadManager = new Internal::Adaptor::TextureUploadManager();
+      manager                                                               = Dali::Devel::TextureUploadManager(internalTextureUploadManager);
+      singletonService.Register(typeid(manager), manager);
+    }
+  }
+  return manager;
+}
+
+TextureUploadManager::TextureUploadManager()
+: mGraphicsController{nullptr},
+  mRenderTrigger(new EventThreadCallback(MakeCallback(this, &TextureUploadManager::RequestUpdateOnce)))
+{
+}
+
+TextureUploadManager::~TextureUploadManager()
+{
+}
+
+Dali::Texture TextureUploadManager::GenerateTexture2D()
+{
+  ResourceId resourceId = GenerateUploadResourceId();
+
+  Dali::Texture ret = Dali::Integration::NewTextureWithResourceId(Dali::TextureType::TEXTURE_2D, resourceId);
+
+  return ret;
+}
+
+Dali::Devel::TextureUploadManager::ResourceId TextureUploadManager::GenerateUploadResourceId()
+{
+  auto id = ++gUniqueResourceId;
+
+  // Jump overflow case so we can assume that resource id always valid.
+  if(DALI_UNLIKELY(gUniqueResourceId == Dali::Devel::TextureUploadManager::INVALID_RESOURCE_ID))
+  {
+    ++gUniqueResourceId;
+  }
+
+  return id;
+}
+
+void TextureUploadManager::RequestUpdateOnce()
+{
+  if(Dali::Adaptor::IsAvailable())
+  {
+    DALI_LOG_INFO(gTextureUploadManagerLogFilter, Debug::Concise, "RenderOnce requested\n");
+    Dali::Adaptor::Get().RenderOnce();
+  }
+}
+
+// Called by update thread
+
+bool TextureUploadManager::ResourceUpload()
+{
+  DALI_ASSERT_DEBUG(mGraphicsController && "GraphicsController is not prepared!");
+
+  // Copy queue first.
+  RequestUploadQueue copiedRequestUploadQueue;
+
+  {
+    Dali::Mutex::ScopedLock lock(mRequestMutex);
+    copiedRequestUploadQueue = std::move(mRequestUploadQueue);
+  }
+
+  // Upload.
+  bool uploaded = ProcessUploadQueue(std::move(copiedRequestUploadQueue));
+
+  return uploaded;
+}
+
+void TextureUploadManager::InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController)
+{
+  mGraphicsController = &graphicsController;
+}
+
+bool TextureUploadManager::ProcessUploadQueue(RequestUploadQueue&& queue)
+{
+  bool uploaded = false;
+
+  if(!queue.empty())
+  {
+#ifdef TRACE_ENABLED
+    if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+    {
+      std::ostringstream stream;
+      stream << "[upload request \'" << queue.size() << "\' images]";
+      DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_WORKER_THREAD_RESOURCE_UPLOAD", stream.str().c_str());
+    }
+    uint32_t uploadedCount = 0u;
+    uint32_t canceledCount = 0u;
+#endif
+
+    DALI_LOG_INFO(gTextureUploadManagerLogFilter, Debug::Concise, "Upload request %zu images\n", queue.size());
+    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;
+#ifdef TRACE_ENABLED
+        ++uploadedCount;
+#endif
+      }
+      else
+      {
+        // Invalidate resouce id! ignore.
+#ifdef TRACE_ENABLED
+        ++canceledCount;
+#endif
+      }
+    }
+
+    if(uploaded)
+    {
+      // Flush here
+      Graphics::SubmitInfo submitInfo;
+      submitInfo.cmdBuffer.clear(); // Only flush
+      submitInfo.flags = 0 | Graphics::SubmitFlagBits::FLUSH;
+      mGraphicsController->SubmitCommandBuffers(submitInfo);
+    }
+#ifdef TRACE_ENABLED
+    if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+    {
+      std::ostringstream stream;
+      stream << "[upload : \'" << uploadedCount << "\', cancel : \'" << canceledCount << "\']";
+      DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_WORKER_THREAD_RESOURCE_UPLOAD", stream.str().c_str());
+    }
+#endif
+  }
+
+  return uploaded;
+}
+
+// Called by worker thread
+
+void TextureUploadManager::RequestUpload(Dali::Devel::TextureUploadManager::ResourceId resourceId, Dali::PixelData pixelData)
+{
+  DALI_ASSERT_ALWAYS(resourceId != Dali::Devel::TextureUploadManager::INVALID_RESOURCE_ID && "Invalid resource id generated!");
+  DALI_ASSERT_ALWAYS(pixelData && "Invalid pixelData!");
+
+  {
+    Dali::Mutex::ScopedLock lock(mRequestMutex); // Worker-Update thread mutex
+
+    mRequestUploadQueue.push_back(std::move(UploadRequestItem(resourceId, pixelData)));
+  }
+
+  // wake up the main thread
+  // TODO : Is there any way to request upload once without main thread dependency?
+  mRenderTrigger->Trigger();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/texture-upload-manager-impl.h b/dali/internal/system/common/texture-upload-manager-impl.h
new file mode 100644 (file)
index 0000000..422a5db
--- /dev/null
@@ -0,0 +1,155 @@
+#ifndef DALI_INTERNAL_TEXTURE_UPLOAD_MANAGER_IMPL_H
+#define DALI_INTERNAL_TEXTURE_UPLOAD_MANAGER_IMPL_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/event-thread-callback.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/graphics-api/graphics-controller.h>
+#include <dali/graphics-api/graphics-texture.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/base-object.h>
+#include <utility> ///< for std::pair
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+/**
+ * The manager for texture upload
+ */
+class TextureUploadManager : public Dali::BaseObject
+{
+public:
+  using ResourceId = Dali::Devel::TextureUploadManager::ResourceId;
+
+public: // Main thread called method
+  /**
+   * Singleton access
+   *
+   * @return The TextureUploadManager object
+   */
+  static Dali::Devel::TextureUploadManager Get();
+
+  /**
+   * Constructor.
+   */
+  TextureUploadManager();
+
+  /**
+   * Destructor.
+   */
+  ~TextureUploadManager() override;
+
+  /**
+   * @copydoc Dali::Devel::TextureUploadManager::GenerateTexture2D()
+   */
+  Dali::Texture GenerateTexture2D();
+
+private: // Main thread called method
+  /**
+   * @brief Get the unique id for upload resources, called by main thread.
+   *
+   * @return The unique id of upload resource.
+   */
+  ResourceId GenerateUploadResourceId();
+
+  /**
+   * @brief Reqeust update thread once
+   */
+  void RequestUpdateOnce();
+
+public: // Update thread called method
+  /**
+   * @copydoc Dali::Devel::TextureUploadManager::ResourceUpload()
+   */
+  bool ResourceUpload();
+
+  /**
+   * @brief Install graphics controller to be used when upload.
+   * @note Please use this API internal side only.
+   * @note This API will be removed after toolkit UTC code fixed.
+   *
+   * @param[in] graphicsController The graphics controller.
+   */
+  void InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController);
+
+private: // Update thread called method
+  using UploadRequestItem  = std::pair<ResourceId, Dali::PixelData>;
+  using RequestUploadQueue = std::vector<UploadRequestItem>;
+
+  /**
+   * @brief Process queue of upload.
+   *
+   * @param queue The requested upload queue.
+   * @return True if there was at least 1 resources uploaded.
+   */
+  bool ProcessUploadQueue(RequestUploadQueue&& queue);
+
+public: // Worker thread called method
+  /**
+   * @copydoc Dali::Devel::TextureUploadManager::RequestUpload()
+   */
+  void RequestUpload(ResourceId id, Dali::PixelData pixelData);
+
+private:
+  // Undefined
+  TextureUploadManager(const TextureUploadManager& manager);
+
+  // Undefined
+  TextureUploadManager& operator=(const TextureUploadManager& manager);
+
+private:
+  Dali::Graphics::Controller* mGraphicsController;
+
+  std::unique_ptr<EventThreadCallback> mRenderTrigger; ///< Trigger to update/render once for worker thread.
+
+  Dali::Mutex        mRequestMutex; ///< For worker thread
+  RequestUploadQueue mRequestUploadQueue{};
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+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);
+}
+
+} // namespace Dali
+
+#endif
index 898d703..7dc4229 100644 (file)
@@ -24,6 +24,7 @@ SET( adaptor_system_common_src_files
     ${adaptor_system_dir}/common/update-status-logger.cpp
     ${adaptor_system_dir}/common/widget-application-impl.cpp
     ${adaptor_system_dir}/common/async-task-manager-impl.cpp
+    ${adaptor_system_dir}/common/texture-upload-manager-impl.cpp
 )
 
 # module: system, backend: linux