From: Heeyong Song Date: Thu, 19 Jan 2023 08:46:20 +0000 (+0900) Subject: [Tizen] Backport tizen_7.5 for Scene3D X-Git-Tag: accepted/tizen/7.0/unified/20230223.015615^0 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git;a=commitdiff_plain;h=d95eb9157c392e5684e3170de3d96867d0fdd591 [Tizen] Backport tizen_7.5 for Scene3D This is a combination of 4 commits. Fix deadlock issue of AsyncTaskThread mDestroyThread may be changed to true after while(!mDestroyThread) because we don't lock the part. Support to load an image from uint8_t* encoded buffer. Fix coverity issue : Adaptor available check in async task manager Add GetCallbackInvocationThread() for AsyncTaskMananager When AsyncTaskManager use other thread, no need to wake up main thread. Change-Id: I17cf6d123304e5bef991afdd692dd25222ceace7 Signed-off-by: Eunki, Hong --- diff --git a/dali/devel-api/adaptor-framework/image-loading.cpp b/dali/devel-api/adaptor-framework/image-loading.cpp index 207b79a..e82d488 100644 --- a/dali/devel-api/adaptor-framework/image-loading.cpp +++ b/dali/devel-api/adaptor-framework/image-loading.cpp @@ -87,6 +87,30 @@ Devel::PixelBuffer LoadImageFromBuffer(const Dali::Vector& buffer, Imag return Dali::Devel::PixelBuffer(); } +Devel::PixelBuffer LoadImageFromBuffer(uint8_t* buffer, size_t bufferSize, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection) +{ + if(buffer == nullptr) + { + DALI_LOG_ERROR("buffer is empty!\n"); + return Dali::Devel::PixelBuffer(); + } + Integration::BitmapResourceType resourceType(size, fittingMode, samplingMode, orientationCorrection); + + Internal::Platform::FileReader fileReader(buffer, bufferSize); + FILE* const fp = fileReader.GetFile(); + if(fp != NULL) + { + Dali::Devel::PixelBuffer bitmap; + // Make path as empty string. Path information just for file format hint. + bool success = TizenPlatform::ImageLoader::ConvertStreamToBitmap(resourceType, std::string(""), fp, bitmap); + if(success && bitmap) + { + return bitmap; + } + } + return Dali::Devel::PixelBuffer(); +} + ImageDimensions GetClosestImageSize(const std::string& filename, ImageDimensions size, FittingMode::Type fittingMode, diff --git a/dali/devel-api/adaptor-framework/image-loading.h b/dali/devel-api/adaptor-framework/image-loading.h index 53e07df..365b38d 100644 --- a/dali/devel-api/adaptor-framework/image-loading.h +++ b/dali/devel-api/adaptor-framework/image-loading.h @@ -88,6 +88,28 @@ DALI_ADAPTOR_API Devel::PixelBuffer LoadImageFromBuffer( bool orientationCorrection = true); /** + * @brief Load an image synchronously from encoded buffer. + * + * @note This method is thread safe, i.e. can be called from any thread. + * + * @param [in] buffer The encoded buffer of the image to load. + * The buffer is not owned by FileStream and must be valid for entire lifetime of FileStream + * @param [in] bufferSize Size of the encoded buffer. + * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image + * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter. + * @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size. + * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header. + * @return handle to the loaded PixelBuffer object or an empty handle in case loading failed. + */ +DALI_ADAPTOR_API Devel::PixelBuffer LoadImageFromBuffer( + uint8_t* buffer, + size_t bufferSize, + ImageDimensions size = ImageDimensions(0, 0), + FittingMode::Type fittingMode = FittingMode::DEFAULT, + SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR, + bool orientationCorrection = true); + +/** * @brief Determine the size of an image that LoadImageFromFile will provide when * given the same image loading parameters. * diff --git a/dali/internal/system/common/async-task-manager-impl.cpp b/dali/internal/system/common/async-task-manager-impl.cpp index 22e274c..55ebe7a 100644 --- a/dali/internal/system/common/async-task-manager-impl.cpp +++ b/dali/internal/system/common/async-task-manager-impl.cpp @@ -1,5 +1,5 @@ /* - * 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. @@ -19,9 +19,9 @@ #include "async-task-manager-impl.h" // EXTERNAL INCLUDES -#include #include #include +#include #include #include @@ -109,8 +109,11 @@ void AsyncTaskThread::Run() if(!task) { ConditionalWait::ScopedLock lock(mConditionalWait); - mIsThreadIdle = true; - mConditionalWait.Wait(lock); + if(!mDestroyThread) + { + mIsThreadIdle = true; + mConditionalWait.Wait(lock); + } } else { @@ -123,7 +126,7 @@ void AsyncTaskThread::Run() Dali::AsyncTaskManager AsyncTaskManager::Get() { Dali::AsyncTaskManager manager; - SingletonService singletonService(SingletonService::Get()); + SingletonService singletonService(SingletonService::Get()); if(singletonService) { // Check whether the async task manager is already created @@ -138,7 +141,7 @@ Dali::AsyncTaskManager AsyncTaskManager::Get() { // If not, create the async task manager and register it as a singleton Internal::Adaptor::AsyncTaskManager* internalAsyncTaskManager = new Internal::Adaptor::AsyncTaskManager(); - manager = Dali::AsyncTaskManager(internalAsyncTaskManager); + manager = Dali::AsyncTaskManager(internalAsyncTaskManager); singletonService.Register(typeid(manager), manager); } } @@ -154,7 +157,7 @@ AsyncTaskManager::AsyncTaskManager() AsyncTaskManager::~AsyncTaskManager() { - if(mProcessorRegistered) + if(mProcessorRegistered && Dali::Adaptor::IsAvailable()) { Dali::Adaptor::Get().UnregisterProcessor(*this); } @@ -189,7 +192,7 @@ void AsyncTaskManager::AddTask(AsyncTaskPtr task) // If all threads are busy, then it's ok just to push the task because they will try to get the next job. } - if(!mProcessorRegistered) + if(!mProcessorRegistered && Dali::Adaptor::IsAvailable()) { Dali::Adaptor::Get().RegisterProcessor(*this); mProcessorRegistered = true; @@ -292,29 +295,41 @@ AsyncTaskPtr AsyncTaskManager::PopNextCompletedTask() void AsyncTaskManager::CompleteTask(AsyncTaskPtr task) { // Lock while adding task to the queue - Mutex::ScopedLock lock(mMutex); - for(auto iter = mRunningTasks.begin(), endIter = mRunningTasks.end(); iter != endIter; ++iter) { - if((*iter).first == task) + Mutex::ScopedLock lock(mMutex); + for(auto iter = mRunningTasks.begin(), endIter = mRunningTasks.end(); iter != endIter; ++iter) { - if(!(*iter).second) + if((*iter).first == task) { - mCompletedTasks.push_back(task); - } + if(!(*iter).second) + { + if(task->GetCallbackInvocationThread() == AsyncTask::ThreadType::MAIN_THREAD) + { + mCompletedTasks.push_back(task); + } + } - // Delete this task in running queue - mRunningTasks.erase(iter); - break; + // Delete this task in running queue + mRunningTasks.erase(iter); + break; + } } } // wake up the main thread - mTrigger->Trigger(); + if(task->GetCallbackInvocationThread() == AsyncTask::ThreadType::MAIN_THREAD) + { + mTrigger->Trigger(); + } + else + { + CallbackBase::Execute(*(task->GetCompletedCallback()), task); + } } void AsyncTaskManager::UnregisterProcessor() { - if(mProcessorRegistered) + if(mProcessorRegistered && Dali::Adaptor::IsAvailable()) { Mutex::ScopedLock lock(mMutex); if(mWaitingTasks.empty() && mCompletedTasks.empty() && mRunningTasks.empty()) @@ -329,7 +344,7 @@ void AsyncTaskManager::TasksCompleted() { while(AsyncTaskPtr task = PopNextCompletedTask()) { - CallbackBase::Execute(*(task->GetCompletedCallback()),task); + CallbackBase::Execute(*(task->GetCompletedCallback()), task); } UnregisterProcessor(); diff --git a/dali/public-api/adaptor-framework/async-task-manager.cpp b/dali/public-api/adaptor-framework/async-task-manager.cpp index 20a1a6c..2a2d58b 100644 --- a/dali/public-api/adaptor-framework/async-task-manager.cpp +++ b/dali/public-api/adaptor-framework/async-task-manager.cpp @@ -1,5 +1,5 @@ /* - * 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. @@ -22,9 +22,9 @@ namespace Dali { - -AsyncTask::AsyncTask(CallbackBase* callback) -: mCompletedCallback(std::unique_ptr(callback)) +AsyncTask::AsyncTask(CallbackBase* callback, ThreadType threadType) +: mCompletedCallback(std::unique_ptr(callback)), + mThreadType(threadType) { } @@ -33,6 +33,11 @@ CallbackBase* AsyncTask::GetCompletedCallback() return mCompletedCallback.get(); } +AsyncTask::ThreadType AsyncTask::GetCallbackInvocationThread() +{ + return mThreadType; +} + AsyncTaskManager::AsyncTaskManager() = default; AsyncTaskManager::~AsyncTaskManager() = default; diff --git a/dali/public-api/adaptor-framework/async-task-manager.h b/dali/public-api/adaptor-framework/async-task-manager.h index 02021c1..dd3ebc0 100644 --- a/dali/public-api/adaptor-framework/async-task-manager.h +++ b/dali/public-api/adaptor-framework/async-task-manager.h @@ -2,7 +2,7 @@ #define DALI_ASYNC_TASK_MANAGER_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. @@ -46,12 +46,20 @@ using AsyncTaskPtr = IntrusivePtr; class DALI_ADAPTOR_API AsyncTask : public RefObject { public: + // The Type of invocation thread + enum class ThreadType + { + MAIN_THREAD, + WORKER_THREAD + }; + /** * Constructor * @SINCE_2_2.3 - * @param[in] callback The callback to up the main thread. The ownership of callback is taken by this class + * @param[in] callback The callback to invoke on task completion, either on the main thread on the worker thread. The ownership of callback is taken by this class. + * @param[in] threadType The thread type of invocation callback. */ - AsyncTask(CallbackBase* callback); + AsyncTask(CallbackBase* callback, ThreadType threadType = AsyncTask::ThreadType::MAIN_THREAD); /** * Get the complated callback @@ -60,6 +68,13 @@ public: CallbackBase* GetCompletedCallback(); /** + * Get the thread of the invocation callback + * @SINCE_2_2.9 + * @return the type of invocation callback. + */ + ThreadType GetCallbackInvocationThread(); + + /** * Destructor. * @SINCE_2_2.3 */ @@ -80,6 +95,7 @@ public: private: std::unique_ptr mCompletedCallback; + ThreadType mThreadType; // Undefined AsyncTask(const AsyncTask& task) = delete;