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
*/
#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"
*/
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)
{
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);
std::vector<TestGraphicsBuffer*> mAllocatedBuffers;
+ std::unordered_map<uint32_t, Graphics::UniquePtr<Graphics::Texture>> mTextureUploadBindMapper;
+
struct PipelineCache
{
};
--- /dev/null
+/*
+ * 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
--- /dev/null
+#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
${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
${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
mGraphics->GetStencilBufferRequired(),
mGraphics->GetPartialUpdateRequired());
+ // Create TextureUploadManager after mCore created
+ mTextureUploadManager = Dali::Devel::TextureUploadManager::Get();
+
defaultWindow->SetAdaptor(Get());
Dali::Integration::SceneHolder defaultSceneHolder(defaultWindow);
windows = mWindows;
}
+Devel::TextureUploadManager& Adaptor::GetTextureUploadManager()
+{
+ return mTextureUploadManager;
+}
+
void Adaptor::DestroyTtsPlayer(Dali::TtsPlayer::Mode mode)
{
if(mTtsPlayers[mode])
mPerformanceInterface(nullptr),
mKernelTracer(),
mSystemTracer(),
+ mTextureUploadManager(),
mObjectProfiler(nullptr),
mMemoryPoolTimerSlotDelegate(this),
mSocketFactory(),
*/
void SceneCreated();
+ /**
+ * Get the application package name
+ */
static std::string GetApplicationPackageName();
public: // AdaptorInternalServices implementation
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
*/
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;
#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.
#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>
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
*/
#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>
mNotificationTrigger(adaptorInterfaces.GetProcessCoreEventsTrigger()),
mSleepTrigger(NULL),
mPreRenderCallback(NULL),
+ mTextureUploadManager(adaptorInterfaces.GetTextureUploadManager()),
mUpdateRenderThread(NULL),
mDefaultFrameDelta(0.0f),
mDefaultFrameDurationMilliseconds(0u),
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
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;
#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.
#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>
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.
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
*/
// 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>
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)
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
--- /dev/null
+/*
+ * 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
--- /dev/null
+#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
${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