From: Eunki, Hong Date: Wed, 12 Jul 2023 07:01:56 +0000 (+0900) Subject: FastTrackUpload task implement X-Git-Tag: dali_2.2.39~9 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=7b0a198bf7d038ee89f1016b66575347c8be63ae FastTrackUpload task implement Let we make another loaderTask for upload texture at work thread. It will use TextureUploadManager. Change-Id: Ibc3e19aad3e1a20f3a553b4cf394b315de66980f Signed-off-by: Eunki, Hong --- diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index 1ddb118..f11bfbf 100755 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -112,6 +112,7 @@ SET(TEST_HARNESS_SOURCES dali-toolkit-test-utils/toolkit-physical-keyboard.cpp dali-toolkit-test-utils/toolkit-style-monitor.cpp dali-toolkit-test-utils/toolkit-test-application.cpp + dali-toolkit-test-utils/toolkit-texture-upload-manager.cpp dali-toolkit-test-utils/toolkit-timer.cpp dali-toolkit-test-utils/toolkit-trigger-event-factory.cpp dali-toolkit-test-utils/toolkit-tts-player.cpp diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp index 4bac7a6..527b9f4 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-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-toolkit/dali-toolkit-test-utils/test-graphics-controller.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.h index ade48d7..9540c3e 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-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/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.cpp new file mode 100644 index 0000000..f1c336c --- /dev/null +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDE +#include +#include +#include +#include + +// INTERNAL INCLUDE +#include +#include + +namespace Dali +{ +namespace Internal +{ +namespace Adaptor +{ +class TextureUploadManager : public Dali::BaseObject +{ +public: + using ResourceId = Dali::Devel::TextureUploadManager::ResourceId; + +public: + static Dali::Devel::TextureUploadManager Get(); + TextureUploadManager(); + ~TextureUploadManager() = default; + + Dali::Texture GenerateTexture2D(); + +public: // Update thread called method + bool ResourceUpload(); + + void InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController); + +private: // Update thread called method + using UploadRequestItem = std::pair; ///< TODO : PixelData? PixelBuffer? + using RequestUploadQueue = std::vector; + + bool ProcessUploadQueue(RequestUploadQueue&& queue); + +public: // Worker thread called method + /** + * @copydoc Dali::Devel::TextureUploadManager::RequestUpload() + */ + void RequestUpload(ResourceId id, Dali::PixelData pixelData); + +private: + Dali::Graphics::Controller* mGraphicsController; + RequestUploadQueue mRequestUploadQueue{}; + +public: + ResourceId gUniqueResourceId{0u}; +}; + +inline Internal::Adaptor::TextureUploadManager& GetImplementation(Dali::Devel::TextureUploadManager& obj) +{ + DALI_ASSERT_ALWAYS(obj && "TextureUploadManager is empty"); + + Dali::BaseObject& handle = obj.GetBaseObject(); + + return static_cast(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); +} + +/********************************************************************************/ +/********************************* INTERNAL CLASS *****************************/ +/********************************************************************************/ + +namespace +{ +Devel::TextureUploadManager gTextureUploadManager; +} // namespace + +Devel::TextureUploadManager TextureUploadManager::Get() +{ + if(!gTextureUploadManager) + { + gTextureUploadManager = Devel::TextureUploadManager(new TextureUploadManager()); + } + return gTextureUploadManager; +} + +TextureUploadManager::TextureUploadManager() +: mGraphicsController{nullptr} +{ +} + +Dali::Texture TextureUploadManager::GenerateTexture2D() +{ + ResourceId resourceId = ++gUniqueResourceId; + + Dali::Texture ret = Dali::Integration::NewTextureWithResourceId(Dali::TextureType::TEXTURE_2D, resourceId); + + return ret; +} + +// Called by update thread + +bool TextureUploadManager::ResourceUpload() +{ + DALI_ASSERT_DEBUG(mGraphicsController && "GraphicsController is not prepared!"); + + // Upload. + bool uploaded = ProcessUploadQueue(std::move(mRequestUploadQueue)); + mRequestUploadQueue.clear(); + + return uploaded; +} + +void TextureUploadManager::InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController) +{ + mGraphicsController = &graphicsController; +} + +bool TextureUploadManager::ProcessUploadQueue(RequestUploadQueue&& queue) +{ + bool uploaded = false; + + if(!queue.empty()) + { + for(auto& requests : queue) + { + auto& resourceId = requests.first; + auto& pixelData = requests.second; + + Graphics::Texture* graphicsTexture = nullptr; + + // TODO : Could we detect TEXTURE_2D or TEXTURE_CUBE case in future? + { + // We always need to create new one + auto createInfo = Graphics::TextureCreateInfo(); + createInfo + .SetTextureType(Dali::Graphics::ConvertTextureType(Dali::TextureType::TEXTURE_2D)) + .SetUsageFlags(static_cast(Graphics::TextureUsageFlagBits::SAMPLE)) + .SetFormat(Dali::Graphics::ConvertPixelFormat(pixelData.GetPixelFormat())) + .SetSize({pixelData.GetWidth(), pixelData.GetHeight()}) + .SetLayout(Graphics::TextureLayout::LINEAR) + .SetData(nullptr) + .SetDataSize(0u) + .SetNativeImage(nullptr) + .SetMipMapFlag(Graphics::TextureMipMapFlag::DISABLED); + + graphicsTexture = mGraphicsController->CreateTextureByResourceId(resourceId, createInfo); + } + + if(graphicsTexture) + { + Graphics::TextureUpdateInfo info{}; + + info.dstTexture = graphicsTexture; + info.dstOffset2D = {0u, 0u}; + info.layer = 0u; + info.level = 0u; + info.srcReference = 0; + info.srcExtent2D = {pixelData.GetWidth(), pixelData.GetHeight()}; + info.srcOffset = 0; + info.srcSize = Dali::Integration::GetPixelDataBuffer(pixelData).bufferSize; + info.srcStride = pixelData.GetStride(); + info.srcFormat = Dali::Graphics::ConvertPixelFormat(pixelData.GetPixelFormat()); + + Graphics::TextureUpdateSourceInfo updateSourceInfo{}; + updateSourceInfo.sourceType = Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA; + updateSourceInfo.pixelDataSource.pixelData = pixelData; + + mGraphicsController->UpdateTextures({info}, {updateSourceInfo}); + + uploaded = true; + } + else + { + // Invalidate resouce id! ignore. + } + } + + if(uploaded) + { + // Flush here + Graphics::SubmitInfo submitInfo; + submitInfo.cmdBuffer.clear(); // Only flush + submitInfo.flags = 0 | Graphics::SubmitFlagBits::FLUSH; + mGraphicsController->SubmitCommandBuffers(submitInfo); + } + } + + return uploaded; +} + +// Called by worker thread + +void TextureUploadManager::RequestUpload(Dali::Devel::TextureUploadManager::ResourceId resourceId, Dali::PixelData pixelData) +{ + mRequestUploadQueue.push_back(std::move(UploadRequestItem(resourceId, pixelData))); +} + +} // namespace Adaptor + +} // namespace Internal + +/********************************************************************************/ +/********************************* PUBLIC CLASS *******************************/ +/********************************************************************************/ + +namespace Devel +{ +// Called by main thread + +TextureUploadManager::TextureUploadManager() = default; + +TextureUploadManager::~TextureUploadManager() = default; + +TextureUploadManager TextureUploadManager::Get() +{ + return Internal::Adaptor::TextureUploadManager::Get(); +} + +Dali::Texture TextureUploadManager::GenerateTexture2D() +{ + return Internal::Adaptor::GetImplementation(*this).GenerateTexture2D(); +} + +TextureUploadManager::TextureUploadManager(Internal::Adaptor::TextureUploadManager* impl) +: BaseHandle(impl) +{ +} + +// Called by update thread + +bool TextureUploadManager::ResourceUpload() +{ + return Internal::Adaptor::GetImplementation(*this).ResourceUpload(); +} + +// Called by worker thread + +void TextureUploadManager::RequestUpload(ResourceId resourceId, PixelData pixelData) +{ + Internal::Adaptor::GetImplementation(*this).RequestUpload(resourceId, pixelData); +} + +} // namespace Devel + +} // namespace Dali + +namespace Test +{ +namespace TextureUploadManager +{ +void InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController) +{ + auto textureUploadManager = Dali::Devel::TextureUploadManager::Get(); + Internal::Adaptor::GetImplementation(textureUploadManager).InitalizeGraphicsController(graphicsController); +} +} // namespace TextureUploadManager +} // namespace Test diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.h new file mode 100644 index 0000000..18585fd --- /dev/null +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-texture-upload-manager.h @@ -0,0 +1,40 @@ +#ifndef DALI_TOOLKIT_TOOLKIT_TEXTURE_UPLOAD_MANAGER_H +#define DALI_TOOLKIT_TOOLKIT_TEXTURE_UPLOAD_MANAGER_H + +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Graphics DALI_INTERNAL +{ +class Controller; +} // namespace DALI_INTERNAL +} // namespace Dali + +namespace Test +{ +namespace TextureUploadManager +{ +void InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController); +} +} // namespace Test + +#endif // DALI_TOOLKIT_TOOLKIT_TEXTURE_UPLOAD_MANAGER_H diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp index 9583e09..4b5e546 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp @@ -18,10 +18,14 @@ #include #include +#include +#include + #include #include #include +#include #include #include @@ -29,10 +33,13 @@ #include #include #include +#include #include #include #include +#include + #include "dummy-control.h" #include "test-encoded-image-buffer.h" #include "test-native-image-source.h" @@ -3550,3 +3557,315 @@ int UtcDaliImageVisualLoadImagePlanes03(void) END_TEST; } + +int UtcDaliImageVisualLoadFastTrackImage01(void) +{ + tet_infoline("Test worker thread uploading with Local URL"); + ToolkitTestApplication application; + + Test::TextureUploadManager::InitalizeGraphicsController(application.GetGraphicsController()); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK(factory); + + // Pair of filename - expect GenTextures count. + std::vector> testCases = { + {TEST_IMAGE_FILE_NAME, 1}, + {TEST_REMOTE_IMAGE_FILE_NAME, 1}, + {TEST_INVALID_FILE_NAME, 0}, + }; + + for(auto&& tc : testCases) + { + auto& filename = tc.first; + auto& expectValue = tc.second; + + tet_printf("Test %s\n", filename.c_str()); + + Property::Map propertyMap; + propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, filename.c_str()); + propertyMap.Insert(DevelImageVisual::Property::FAST_TRACK_UPLOADING, true); + + Visual::Base visual = factory.CreateVisual(propertyMap); + DALI_TEST_CHECK(visual); + + DummyControl actor = DummyControl::New(); + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual); + actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f)); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + application.GetScene().Add(actor); + + application.SendNotification(); + application.Render(); + + // EventThread without callback + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 30, false), true, TEST_LOCATION); + + DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION); + + { + // TODO : There is no way to flush TextureUploadManager in test-application's Render() now. + // How can we make it? Should it be integration-api? + auto textureUploadManager = Dali::Devel::TextureUploadManager::Get(); + DALI_TEST_EQUALS(textureUploadManager.ResourceUpload(), expectValue > 0, TEST_LOCATION); + } + // Render only without SendNotification(). And check whether glTexImage2D called or not. + application.Render(); + + DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), expectValue, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + textureTrace.Reset(); + } + + END_TEST; +} + +int UtcDaliImageVisualLoadFastTrackImage02(void) +{ + tet_infoline("Test worker thread uploading with Local URL"); + ToolkitTestApplication application; + + Test::TextureUploadManager::InitalizeGraphicsController(application.GetGraphicsController()); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK(factory); + + { + auto filename = std::string(TEST_IMAGE_FILE_NAME); + auto expectValue = 1; + + tet_printf("Test %s\n", filename.c_str()); + + Property::Map propertyMap; + propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, filename.c_str()); + propertyMap.Insert("fastTrackUploading", true); + + Visual::Base visual = factory.CreateVisual(propertyMap); + DALI_TEST_CHECK(visual); + + DummyControl actor = DummyControl::New(); + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual); + actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f)); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + application.GetScene().Add(actor); + + application.SendNotification(); + application.Render(); + + // EventThread without callback + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 30, false), true, TEST_LOCATION); + + DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION); + + { + // TODO : There is no way to flush TextureUploadManager in test-application's Render() now. + // How can we make it? Should it be integration-api? + auto textureUploadManager = Dali::Devel::TextureUploadManager::Get(); + DALI_TEST_EQUALS(textureUploadManager.ResourceUpload(), expectValue > 0, TEST_LOCATION); + } + // Render only without SendNotification(). And check whether glTexImage2D called or not. + application.Render(); + + DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), expectValue, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + textureTrace.Reset(); + } + + END_TEST; +} + +int UtcDaliImageVisualLoadFastTrackImageResourceReady(void) +{ + tet_infoline("Test worker thread uploading with Local URL"); + ToolkitTestApplication application; + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK(factory); + + Property::Map propertyMap; + propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME); + propertyMap.Insert(DevelImageVisual::Property::FAST_TRACK_UPLOADING, true); + + Visual::Base visual = factory.CreateVisual(propertyMap); + DALI_TEST_CHECK(visual); + + DummyControl actor = DummyControl::New(); + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual); + actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f)); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + application.GetScene().Add(actor); + + application.SendNotification(); + application.Render(); + + // EventThread with callback + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + + // Check resource ready comes after + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION); + DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliImageVisualLoadFastTrackImageReload(void) +{ + tet_infoline("Test worker thread uploading with Local URL"); + ToolkitTestApplication application; + + Test::TextureUploadManager::InitalizeGraphicsController(application.GetGraphicsController()); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK(factory); + + Property::Map propertyMap; + propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME); + propertyMap.Insert(DevelImageVisual::Property::FAST_TRACK_UPLOADING, true); + + Visual::Base visual = factory.CreateVisual(propertyMap); + DALI_TEST_CHECK(visual); + + DummyControl actor = DummyControl::New(); + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual); + actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f)); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + application.GetScene().Add(actor); + + application.SendNotification(); + application.Render(); + + // EventThread without callback + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 30, false), true, TEST_LOCATION); + + DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION); + + { + // TODO : There is no way to flush TextureUploadManager in test-application's Render() now. + // How can we make it? Should it be integration-api? + auto textureUploadManager = Dali::Devel::TextureUploadManager::Get(); + DALI_TEST_EQUALS(textureUploadManager.ResourceUpload(), true, TEST_LOCATION); + } + // Render only without SendNotification(). And check whether glTexImage2D called or not. + application.Render(); + + DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 1, TEST_LOCATION); + + // Reload + Property::Map attributes; + DevelControl::DoAction(actor, Control::CONTROL_PROPERTY_END_INDEX + 1, DevelImageVisual::Action::RELOAD, attributes); + + // EventThread with callback + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + + // Check resource ready comes after + application.SendNotification(); + application.Render(); + + // Check whether renderer count is 1 or not. + DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION); + DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliImageVisualLoadFastTrackImagePlanes01(void) +{ +#if 0 //< Do not open this UTC yet. + EnvironmentVariable::SetTestEnvironmentVariable(LOAD_IMAGE_YUV_PLANES_ENV, "1"); + EnvironmentVariable::SetTestEnvironmentVariable(ENABLE_DECODE_JPEG_TO_YUV_420_ENV, "1"); + + ToolkitTestApplication application; + + Test::TextureUploadManager::InitalizeGraphicsController(application.GetGraphicsController()); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK(factory); + + Property::Map propertyMap; + propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE); + propertyMap.Insert(ImageVisual::Property::URL, TEST_YUV420_IMAGE_FILE_NAME); + propertyMap.Insert(DevelImageVisual::Property::FAST_TRACK_UPLOADING, true); + + Visual::Base visual = factory.CreateVisual(propertyMap); + DALI_TEST_CHECK(visual); + + DummyControl actor = DummyControl::New(); + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual); + actor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f)); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + application.GetScene().Add(actor); + + application.SendNotification(); + application.Render(); + + // EventThread without callback + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 30, false), true, TEST_LOCATION); + + DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 0, TEST_LOCATION); + + { + // TODO : There is no way to flush TextureUploadManager in test-application's Render() now. + // How can we make it? Should it be integration-api? + auto textureUploadManager = Dali::Devel::TextureUploadManager::Get(); + textureUploadManager.ResourceUpload(); + application.Render(); + } + // Render only without SendNotification(). And check whether glTexImage2D called or not. + application.Render(); + + DALI_TEST_EQUALS(textureTrace.CountMethod("GenTextures"), 3, TEST_LOCATION); + + // Event thread don't know the result yet. + DALI_TEST_EQUALS(actor.IsResourceReady(), false, TEST_LOCATION); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + + // Check resource ready comes after + application.SendNotification(); + + DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION); + DALI_TEST_EQUALS(actor.IsResourceReady(), true, TEST_LOCATION); + +#else + DALI_TEST_CHECK(true); +#endif + END_TEST; +} \ No newline at end of file diff --git a/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h index 3c0e7d6..35dc49d 100644 --- a/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h +++ b/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h @@ -158,6 +158,23 @@ enum Type MASKING_TYPE = ORIENTATION_CORRECTION + 12, /** + * @brief If true, uploads texture before ResourceReady signal is emitted. Otherwise uploads after texture load is completed. + * @details Name "fastTrackUploading", type Property::BOOLEAN + * If true, the upload happens without event-thread dependency, but the following need to be considered: + * - Texture size is not valid until upload is fully complete. + * - Texture cannot be cached (a new image is uploaded every time). + * - Seamless visual change is not supported. + * - The following, if set are also not supported and will be ignored: + * - Alpha masking + * - Synchronous loading + * - Reload action + * - Atlas loading + * - Custom shader + * @note Used by the ImageVisual. The default is false. + */ + FAST_TRACK_UPLOADING = ORIENTATION_CORRECTION + 13, + + /** * @brief Whether to enable broken image in image visual. * Some of visual don't need to show broken image(ex. placeholder) * Disable broken image for these visuals. diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 3ac6c81..9933e1a 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -141,6 +141,7 @@ SET( toolkit_src_files ${toolkit_src_dir}/filters/spread-filter.cpp ${toolkit_src_dir}/image-loader/async-image-loader-impl.cpp ${toolkit_src_dir}/image-loader/atlas-packer.cpp + ${toolkit_src_dir}/image-loader/fast-track-loading-task.cpp ${toolkit_src_dir}/image-loader/image-atlas-impl.cpp ${toolkit_src_dir}/image-loader/loading-task.cpp ${toolkit_src_dir}/image-loader/image-url-impl.cpp diff --git a/dali-toolkit/internal/image-loader/fast-track-loading-task.cpp b/dali-toolkit/internal/image-loader/fast-track-loading-task.cpp new file mode 100644 index 0000000..607abbc --- /dev/null +++ b/dali-toolkit/internal/image-loader/fast-track-loading-task.cpp @@ -0,0 +1,160 @@ +/* + * 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 +#include +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ +FastTrackLoadingTask::FastTrackLoadingTask(const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback) +: AsyncTask(MakeCallback(this, &FastTrackLoadingTask::OnComplete), url.GetProtocolType() == VisualUrl::ProtocolType::REMOTE ? AsyncTask::PriorityType::LOW : AsyncTask::PriorityType::HIGH), + mUrl(url), + mTexture(), + mDimensions(dimensions), + mFittingMode(fittingMode), + mSamplingMode(samplingMode), + mPreMultiplyOnLoad(preMultiplyOnLoad), + mCallback(), + mTextureUploadManager(Dali::Devel::TextureUploadManager::Get()), + mImageWidth(0u), + mImageHeight(0u), + mImageFormat(Pixel::INVALID), + mPixelData(), + mResourceId(0u), + mOrientationCorrection(orientationCorrection), + mLoadSuccess(false), + mPremultiplied(false) +{ + mCallback = std::unique_ptr(callback); + PrepareTexture(); +} + +FastTrackLoadingTask::~FastTrackLoadingTask() +{ +} + +void FastTrackLoadingTask::PrepareTexture() +{ + mTexture = mTextureUploadManager.GenerateTexture2D(); + mResourceId = Integration::GetTextureResourceId(mTexture); +} + +void FastTrackLoadingTask::OnComplete(AsyncTaskPtr task) +{ + if(mLoadSuccess) + { + Dali::Integration::SetTextureSize(mTexture, Dali::ImageDimensions(mImageWidth, mImageHeight)); + Dali::Integration::SetTexturePixelFormat(mTexture, mImageFormat); + } + if(mCallback) + { + CallbackBase::Execute(*mCallback, FastTrackLoadingTaskPtr(reinterpret_cast(task.Get()))); + } +} + +// Called by worker thread + +void FastTrackLoadingTask::Process() +{ + Load(); + UploadToTexture(); +} + +bool FastTrackLoadingTask::IsReady() +{ + return true; +} + +void FastTrackLoadingTask::Load() +{ + Devel::PixelBuffer pixelBuffer; + std::vector pixelBuffers; + + if(mUrl.IsValid() && mUrl.IsLocalResource()) + { + // TODO : We need to consider YUV case in future. + //Dali::LoadImagePlanesFromFile(mUrl.GetUrl(), pixelBuffers, mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection); + + pixelBuffer = Dali::LoadImageFromFile(mUrl.GetUrl(), mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection); + } + else if(mUrl.IsValid()) + { + pixelBuffer = Dali::DownloadImageSynchronously(mUrl.GetUrl(), mDimensions, mFittingMode, mSamplingMode, mOrientationCorrection); + } + + if(pixelBuffer) + { + pixelBuffers.push_back(pixelBuffer); + } + + if(pixelBuffers.empty()) + { + DALI_LOG_ERROR("FastTrackLoadingTask::Load: Loading is failed: ResourceId : %d, url : [%s]\n", mResourceId, mUrl.GetUrl().c_str()); + } + else + { + if(pixelBuffers.size() == 1u) + { + mLoadSuccess = true; + MultiplyAlpha(pixelBuffers[0]); + mPixelData = Dali::Devel::PixelBuffer::Convert(pixelBuffers[0]); + } + else + { + DALI_LOG_ERROR("FastTrackLoadingTask::Load: ??? Undefined case. PixelBuffers.size() : %zu : ResourceId : %d, url : [%s]\n", pixelBuffers.size(), mResourceId, mUrl.GetUrl().c_str()); + } + } +} + +void FastTrackLoadingTask::MultiplyAlpha(Dali::Devel::PixelBuffer pixelBuffer) +{ + if(mPreMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON && Pixel::HasAlpha(pixelBuffer.GetPixelFormat())) + { + pixelBuffer.MultiplyColorByAlpha(); + mPremultiplied = pixelBuffer.IsAlphaPreMultiplied(); + } +} + +void FastTrackLoadingTask::UploadToTexture() +{ + if(mLoadSuccess) + { + mImageWidth = mPixelData.GetWidth(); + mImageHeight = mPixelData.GetHeight(); + mImageFormat = mPixelData.GetPixelFormat(); + + mTextureUploadManager.RequestUpload(mResourceId, mPixelData); + } + + mPixelData.Reset(); +} + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/image-loader/fast-track-loading-task.h b/dali-toolkit/internal/image-loader/fast-track-loading-task.h new file mode 100644 index 0000000..0458352 --- /dev/null +++ b/dali-toolkit/internal/image-loader/fast-track-loading-task.h @@ -0,0 +1,145 @@ +#ifndef DALI_TOOLKIT_FAST_TRACK_IMAGE_LOADING_TASK_H +#define DALI_TOOLKIT_FAST_TRACK_IMAGE_LOADING_TASK_H + +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ +class FastTrackLoadingTask; +using FastTrackLoadingTaskPtr = IntrusivePtr; + +/** + * @brief The task of loading image and uploading texture on fast track. + * It is available that upload the loaded image data on texture at image loader threads. + */ +class FastTrackLoadingTask : public AsyncTask +{ +public: + /** + * @brief Constructor. + */ + FastTrackLoadingTask(const VisualUrl& url, + ImageDimensions dimensions, + FittingMode::Type fittingMode, + SamplingMode::Type samplingMode, + bool orientationCorrection, + DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, + CallbackBase* callback); + + /** + * @brief Destructor. + */ + ~FastTrackLoadingTask() override; + + /** + * @brief Process the task accodring to the type + */ + void Process() override; + + /** + * @brief Whether the task is ready to process. + * @return True if the task is ready to process. + */ + bool IsReady() override; + +private: + // Undefined + FastTrackLoadingTask(const FastTrackLoadingTask& queue) = delete; + FastTrackLoadingTask& operator=(const FastTrackLoadingTask& queue) = delete; + + /** + * @brief Create textures for this task. + * @note This should be called in construct timing. + */ + void PrepareTexture(); + + /** + * @brief Load the image. + */ + void Load(); + + /** + * @brief Multiply alpha if required. + * + * @param[in,out] pixelBuffer target pixel buffer that need to be multiplied alpha. + */ + void MultiplyAlpha(Dali::Devel::PixelBuffer pixelBuffer); + + /** + * @brief Upload loaded pixelBuffer into texture + */ + void UploadToTexture(); + +private: + /** + * @brief Complete callback. + * + * @param[in] task The pointer of task who call this callback. + */ + void OnComplete(AsyncTaskPtr task); + +public: + VisualUrl mUrl; ///< url of the image to load. + Dali::Texture mTexture; ///< texture for regular image. + +private: + ImageDimensions mDimensions; ///< dimensions to load + FittingMode::Type mFittingMode; ///< fitting options + SamplingMode::Type mSamplingMode; ///< sampling options + DevelAsyncImageLoader::PreMultiplyOnLoad mPreMultiplyOnLoad; + std::unique_ptr mCallback; + + // Texture Upload relative API + Dali::Devel::TextureUploadManager mTextureUploadManager; + + // Note : mPixelData is invalid after upload requested. We should keep image size informations. + uint32_t mImageWidth; + uint32_t mImageHeight; + Pixel::Format mImageFormat; + + Dali::PixelData mPixelData; + + uint32_t mResourceId; + + bool mOrientationCorrection : 1; ///< If orientation correction is needed + +public: + bool mLoadSuccess : 1; ///< Whether image load successed or not. + bool mPremultiplied : 1; ///< True if the image's color was multiplied by it's alpha +}; + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_FAST_TRACK_IMAGE_LOADING_TASK_H diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index 18cf2b4..5b2aff8 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include // for strlen() @@ -200,6 +201,8 @@ ImageVisual::~ImageVisual() { RemoveTexture(); } + + ResetFastTrackLoadingTask(); } } @@ -283,6 +286,10 @@ void ImageVisual::DoSetProperties(const Property::Map& propertyMap) { DoSetProperty(Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, keyValue.second); } + else if(keyValue.first == FAST_TRACK_UPLOADING_NAME) + { + DoSetProperty(Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING, keyValue.second); + } } } // Load image immediately if LOAD_POLICY requires it @@ -477,6 +484,16 @@ void ImageVisual::DoSetProperty(Property::Index index, const Property::Value& va } break; } + + case Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING: + { + bool fastTrackUploading = false; + if(value.Get(fastTrackUploading)) + { + mUseFastTrackUploading = fastTrackUploading; + } + break; + } } } @@ -634,9 +651,76 @@ void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& te : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; bool synchronousLoading = IsSynchronousLoadingRequired(); - bool loadingStatus; + bool loadingStatus = false; + + // Remove previous loading task. + ResetFastTrackLoadingTask(); + + // Rare case. If someone call LoadTexture during fast track loading task running, (Ex : Action::RELOAD) + // we should remove previously added renderer now. + if(mRendererAdded) + { + Actor actor = mPlacementActor.GetHandle(); + if(actor) + { + actor.RemoveRenderer(mImpl->mRenderer); + mRendererAdded = false; + } + } + + /** + * @brief Check whether FastTrackUploading is avaliable or not. + * @return True if we can use fast track uploading feature. False otherwise. + */ + auto IsFastTrackUploadingAvailable = [&]() { + if(mUseFastTrackUploading && + mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::ATTACHED && + mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED && + forceReload == TextureManager::ReloadPolicy::CACHED && + (mImageUrl.GetProtocolType() == VisualUrl::LOCAL || mImageUrl.GetProtocolType() == VisualUrl::REMOTE) && + !synchronousLoading && + !atlasing && + !mImpl->mCustomShader && + !(mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid())) + { + return true; + } + else if(mUseFastTrackUploading) + { + DALI_LOG_DEBUG_INFO("FastTrack : Fail to load fast track. mUrl : [%s]%s%s%s%s%s%s%s%s\n", + mImageUrl.GetUrl().c_str(), + (mLoadPolicy != Toolkit::ImageVisual::LoadPolicy::ATTACHED) ? "/ mLoadPolicy != ATTACHED" : "", + (mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::DETACHED) ? "/ mReleasePolicy != DETACHED" : "", + (forceReload != TextureManager::ReloadPolicy::CACHED) ? "/ forceReload != CACHED" : "", + (!(mImageUrl.GetProtocolType() == VisualUrl::LOCAL || mImageUrl.GetProtocolType() == VisualUrl::REMOTE)) ? "/ url is not image" : "", + (synchronousLoading) ? "/ synchronousLoading" : "", + (atlasing) ? "/ atlasing" : "", + (mImpl->mCustomShader) ? "/ use customs shader" : "", + (mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid()) ? "/ use masking url" : ""); + } + return false; + }; + + if(IsFastTrackUploadingAvailable()) + { + // Enable PremultipliedAlpha first. + EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD); + + // Set new TextureSet with fast track loading task + mFastTrackLoadingTask = new FastTrackLoadingTask(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mOrientationCorrection, preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF, MakeCallback(this, &ImageVisual::FastLoadComplete)); + + TextureSet textureSet = TextureSet::New(); + textureSet.SetTexture(0u, mFastTrackLoadingTask->mTexture); + mImpl->mRenderer.SetTextures(textureSet); - textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mTextureId, atlasRect, mAtlasRectSize, atlasing, loadingStatus, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection, forceReload, preMultiplyOnLoad); + Dali::AsyncTaskManager::Get().AddTask(mFastTrackLoadingTask); + + mLoadState = TextureManager::LoadState::LOADING; + } + else + { + textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mTextureId, atlasRect, mAtlasRectSize, atlasing, loadingStatus, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection, forceReload, preMultiplyOnLoad); + } if(textures) { @@ -770,6 +854,7 @@ void ImageVisual::DoSetOnScene(Actor& actor) if(mLoadState == TextureManager::LoadState::LOAD_FINISHED) { actor.AddRenderer(mImpl->mRenderer); + mRendererAdded = true; mPlacementActor.Reset(); // Image loaded and ready to display @@ -780,6 +865,14 @@ void ImageVisual::DoSetOnScene(Actor& actor) ShowBrokenImage(); ResourceReady(Toolkit::Visual::ResourceStatus::FAILED); } + else + { + if(mFastTrackLoadingTask) + { + actor.AddRenderer(mImpl->mRenderer); + mRendererAdded = true; + } + } } void ImageVisual::DoSetOffScene(Actor& actor) @@ -788,6 +881,8 @@ void ImageVisual::DoSetOffScene(Actor& actor) // Image release is dependent on the ReleasePolicy, renderer is removed. actor.RemoveRenderer(mImpl->mRenderer); + mRendererAdded = false; + if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED) { ResetRenderer(); @@ -830,6 +925,8 @@ void ImageVisual::DoCreatePropertyMap(Property::Map& map) const map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy); map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy); map.Insert(Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, mOrientationCorrection); + + map.Insert(Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING, mUseFastTrackUploading); } void ImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const @@ -885,6 +982,7 @@ void ImageVisual::UploadCompleted() { mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect); actor.AddRenderer(mImpl->mRenderer); + mRendererAdded = true; // reset the weak handle so that the renderer only get added to actor once mPlacementActor.Reset(); } @@ -894,6 +992,39 @@ void ImageVisual::UploadCompleted() mLoadState = TextureManager::LoadState::LOAD_FINISHED; } +// From FastTrackLoadingTask +void ImageVisual::FastLoadComplete(FastTrackLoadingTaskPtr task) +{ + Toolkit::Visual::ResourceStatus resourceStatus; + + DALI_ASSERT_ALWAYS(mFastTrackLoadingTask == task && "Task was not canceled successfully!"); + DALI_ASSERT_ALWAYS(mRendererAdded && "Some FastTrack logic missed!"); + + Actor actor = mPlacementActor.GetHandle(); + + if(mFastTrackLoadingTask && mFastTrackLoadingTask->mLoadSuccess) + { + resourceStatus = Toolkit::Visual::ResourceStatus::READY; + mLoadState = TextureManager::LoadState::LOAD_FINISHED; + + // Change premultiplied alpha flag after change renderer. + EnablePreMultipliedAlpha(mFastTrackLoadingTask->mPremultiplied); + } + else + { + resourceStatus = Toolkit::Visual::ResourceStatus::FAILED; + mLoadState = TextureManager::LoadState::LOAD_FAILED; + + // Change renderer as broken. + ShowBrokenImage(); + } + + mFastTrackLoadingTask.Reset(); + + // Signal to observers ( control ) that resources are ready. Must be all resources. + ResourceReady(resourceStatus); +} + // From Texture Manager void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureInformation) { @@ -938,6 +1069,7 @@ void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureIn if(actor) { actor.AddRenderer(mImpl->mRenderer); + mRendererAdded = true; // reset the weak handle so that the renderer only get added to actor once mPlacementActor.Reset(); } @@ -1005,6 +1137,8 @@ void ImageVisual::RemoveTexture() } else { + ResetFastTrackLoadingTask(); + Vector4 atlasRect(0.f, 0.f, 1.f, 1.f); Property::Index index = mImpl->mRenderer.GetPropertyIndex(ATLAS_RECT_UNIFORM_NAME); if(index != Property::INVALID_INDEX) @@ -1200,21 +1334,46 @@ void ImageVisual::ShowBrokenImage() { imageSize = actor.GetProperty(Actor::Property::SIZE).Get(); mPlacementActorSize = imageSize; + + if(mRendererAdded) + { + actor.RemoveRenderer(mImpl->mRenderer); + mRendererAdded = false; + } } mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize); if(actor) { actor.AddRenderer(mImpl->mRenderer); + mRendererAdded = true; mPlacementActor.Reset(); } } else { + if(mRendererAdded) + { + Actor actor = mPlacementActor.GetHandle(); + if(actor) + { + actor.RemoveRenderer(mImpl->mRenderer); + mRendererAdded = false; + } + } ResetRenderer(); } } +void ImageVisual::ResetFastTrackLoadingTask() +{ + if(mFastTrackLoadingTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mFastTrackLoadingTask); + mFastTrackLoadingTask.Reset(); + } +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/visuals/image/image-visual.h b/dali-toolkit/internal/visuals/image/image-visual.h index 1bd414b..925cdad 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.h +++ b/dali-toolkit/internal/visuals/image/image-visual.h @@ -24,10 +24,12 @@ #include #include #include +#include // INTERNAL INCLUDES #include #include +#include #include #include #include @@ -250,6 +252,13 @@ public: */ void LoadComplete(bool success, TextureInformation textureInformation) override; + /** + * @brief Test callback for FastTrackLoadingTask + * + * @param[in] task The pointer of task who call this callback. + */ + void FastLoadComplete(FastTrackLoadingTaskPtr task); + private: /** * Allocate the mask data when a masking property is defined in the property map @@ -333,6 +342,11 @@ private: */ void ShowBrokenImage(); + /** + * @brief Remove current added fast track upload task. + */ + void ResetFastTrackLoadingTask(); + private: Vector4 mPixelArea; WeakHandle mPlacementActor; @@ -345,6 +359,8 @@ private: Vector2 mTextureSize; Vector2 mPlacementActorSize; + FastTrackLoadingTaskPtr mFastTrackLoadingTask; ///< For fast track uploading. + ImageVisualShaderFactory& mImageVisualShaderFactory; Dali::FittingMode::Type mFittingMode : 3; @@ -355,11 +371,13 @@ private: Dali::Toolkit::ImageVisual::ReleasePolicy::Type mReleasePolicy; Vector4 mAtlasRect; Dali::ImageDimensions mAtlasRectSize; - TextureManager::LoadState mLoadState; ///< The texture loading state - bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture - bool mOrientationCorrection; ///< true if the image will have it's orientation corrected. - bool mNeedYuvToRgb{false}; ///< true if we need to convert yuv to rgb. - bool mEnableBrokenImage; + TextureManager::LoadState mLoadState; ///< The texture loading state + bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture + bool mOrientationCorrection; ///< true if the image will have it's orientation corrected. + bool mNeedYuvToRgb{false}; ///< true if we need to convert yuv to rgb. + bool mEnableBrokenImage{true}; ///< true if enable broken image. + bool mUseFastTrackUploading{false}; ///< True if we use fast tack feature. + bool mRendererAdded{false}; ///< True if renderer added into actor. }; } // namespace Internal diff --git a/dali-toolkit/internal/visuals/visual-string-constants.cpp b/dali-toolkit/internal/visuals/visual-string-constants.cpp index ec888ce..0ffa198 100644 --- a/dali-toolkit/internal/visuals/visual-string-constants.cpp +++ b/dali-toolkit/internal/visuals/visual-string-constants.cpp @@ -123,6 +123,7 @@ const char* const ALPHA_MASK_URL("alphaMaskUrl"); const char* const REDRAW_IN_SCALING_DOWN_NAME("redrawInScalingDown"); const char* const MASKING_TYPE_NAME("maskingType"); const char* const MASK_TEXTURE_RATIO_NAME("maskTextureRatio"); +const char* const FAST_TRACK_UPLOADING_NAME("fastTrackUploading"); const char* const ENABLE_BROKEN_IMAGE("enableBrokenImage"); // Text visual diff --git a/dali-toolkit/internal/visuals/visual-string-constants.h b/dali-toolkit/internal/visuals/visual-string-constants.h index 29d75a9..ff492ec 100644 --- a/dali-toolkit/internal/visuals/visual-string-constants.h +++ b/dali-toolkit/internal/visuals/visual-string-constants.h @@ -107,6 +107,7 @@ extern const char* const ALPHA_MASK_URL; extern const char* const REDRAW_IN_SCALING_DOWN_NAME; extern const char* const MASKING_TYPE_NAME; extern const char* const MASK_TEXTURE_RATIO_NAME; +extern const char* const FAST_TRACK_UPLOADING_NAME; extern const char* const ENABLE_BROKEN_IMAGE; // Text visual