From: Eunki, Hong Date: Mon, 19 Jun 2023 02:51:50 +0000 (+0900) Subject: [Tizen] TextureUploadManager implement X-Git-Tag: accepted/tizen/unified/20230726.163509~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F96%2F296296%2F1;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git [Tizen] TextureUploadManager implement 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 --- diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp index 4bac7a6..527b9f4 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp @@ -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 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 TestGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId) +{ + TraceCallStack::NamedParams namedParams; + namedParams["resourceId"] << resourceId; + + Graphics::UniquePtr 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 diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.h index ade48d7..9540c3e 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.h +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.h @@ -18,6 +18,7 @@ */ #include +#include #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 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 mAllocatedBuffers; + std::unordered_map> 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 index 0000000..ffbdfca --- /dev/null +++ b/dali/devel-api/adaptor-framework/texture-upload-manager.cpp @@ -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 + +// INTERNAL INCLUDES +#include + +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 index 0000000..a835def --- /dev/null +++ b/dali/devel-api/adaptor-framework/texture-upload-manager.h @@ -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 +#include +#include +#include +#include ///< For uint32_t + +// INTERNAL INCLUDES +#include + +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 diff --git a/dali/devel-api/file.list b/dali/devel-api/file.list index b357dc9..caf26c1 100755 --- a/dali/devel-api/file.list +++ b/dali/devel-api/file.list @@ -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 diff --git a/dali/internal/adaptor/common/adaptor-impl.cpp b/dali/internal/adaptor/common/adaptor-impl.cpp index af57022..2514ac8 100644 --- a/dali/internal/adaptor/common/adaptor-impl.cpp +++ b/dali/internal/adaptor/common/adaptor-impl.cpp @@ -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(), diff --git a/dali/internal/adaptor/common/adaptor-impl.h b/dali/internal/adaptor/common/adaptor-impl.h index a1e5be6..f07b47d 100644 --- a/dali/internal/adaptor/common/adaptor-impl.h +++ b/dali/internal/adaptor/common/adaptor-impl.h @@ -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 mMemoryPoolTimerSlotDelegate; diff --git a/dali/internal/adaptor/common/adaptor-internal-services.h b/dali/internal/adaptor/common/adaptor-internal-services.h index 1b6f8f4..af75f62 100644 --- a/dali/internal/adaptor/common/adaptor-internal-services.h +++ b/dali/internal/adaptor/common/adaptor-internal-services.h @@ -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 // INTERNAL INCLUDES +#include #include #include #include @@ -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 */ diff --git a/dali/internal/adaptor/common/combined-update-render-controller.cpp b/dali/internal/adaptor/common/combined-update-render-controller.cpp index db68e43..51f57a1 100644 --- a/dali/internal/adaptor/common/combined-update-render-controller.cpp +++ b/dali/internal/adaptor/common/combined-update-render-controller.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -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; diff --git a/dali/internal/adaptor/common/combined-update-render-controller.h b/dali/internal/adaptor/common/combined-update-render-controller.h index 8902875..bec2f70 100644 --- a/dali/internal/adaptor/common/combined-update-render-controller.h +++ b/dali/internal/adaptor/common/combined-update-render-controller.h @@ -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 // INTERNAL INCLUDES +#include #include #include #include @@ -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. diff --git a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp index 81616aa..12c4723 100644 --- a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp +++ b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp @@ -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 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 EglGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId) +{ + Graphics::UniquePtr texture; + + auto iter = mExternalTextureResources.find(resourceId); + if(iter != mExternalTextureResources.end()) + { + texture = std::move(iter->second); + mExternalTextureResources.erase(iter); + } + + return texture; +} + } // namespace Dali::Graphics diff --git a/dali/internal/graphics/gles-impl/egl-graphics-controller.h b/dali/internal/graphics/gles-impl/egl-graphics-controller.h index 4693721..2c3f435 100644 --- a/dali/internal/graphics/gles-impl/egl-graphics-controller.h +++ b/dali/internal/graphics/gles-impl/egl-graphics-controller.h @@ -18,8 +18,10 @@ */ // EXTERNAL INCLUDES +#include #include #include +#include // INTERNAL INCLUDES #include @@ -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 ReleaseTextureFromResourceId(uint32_t resourceId) override; + +public: [[nodiscard]] Integration::GlAbstraction* GetGL() const { if(mIsShuttingDown) @@ -810,6 +834,8 @@ private: using TextureUpdateRequest = std::pair; std::queue mTextureUpdateRequests; + std::unordered_map> mExternalTextureResources; ///< Used for ResourceId. + std::queue 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 index 0000000..9100b09 --- /dev/null +++ b/dali/internal/system/common/texture-upload-manager-impl.cpp @@ -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 + +// EXTERNAL INCLUDES +#include +#include ///< for Dali::Graphics::ConvertPixelFormat +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include + +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(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::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 index 0000000..422a5db --- /dev/null +++ b/dali/internal/system/common/texture-upload-manager-impl.h @@ -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 +#include +#include +#include +#include +#include +#include ///< for std::pair + +// INTERNAL INCLUDES +#include + +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; + using RequestUploadQueue = std::vector; + + /** + * @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 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(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(handle); +} + +} // namespace Dali + +#endif diff --git a/dali/internal/system/file.list b/dali/internal/system/file.list index 898d703..7dc4229 100644 --- a/dali/internal/system/file.list +++ b/dali/internal/system/file.list @@ -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