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
return graphicsProgram->GetParameter(parameterId, outData);
}
+Graphics::Texture* TestGraphicsController::CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo)
+{
+ Graphics::Texture* ret = nullptr;
+ Graphics::UniquePtr<Graphics::Texture> texture;
+ TraceCallStack::NamedParams namedParams;
+ namedParams["resourceId"] << resourceId;
+
+ auto iter = mTextureUploadBindMapper.find(resourceId);
+ DALI_ASSERT_ALWAYS(iter == mTextureUploadBindMapper.end());
+
+ // Create new graphics texture.
+ texture = CreateTexture(createInfo, std::move(texture));
+ ret = texture.get();
+
+ mTextureUploadBindMapper.insert(std::make_pair(resourceId, std::move(texture)));
+
+ mCallStack.PushCall("CreateTextureByResourceId", "", namedParams);
+ return ret;
+}
+
+void TestGraphicsController::DiscardTextureFromResourceId(uint32_t resourceId)
+{
+ TraceCallStack::NamedParams namedParams;
+ namedParams["resourceId"] << resourceId;
+
+ mTextureUploadBindMapper.erase(resourceId);
+
+ mCallStack.PushCall("DiscardTextureFromResourceId", "", namedParams);
+}
+
+Graphics::Texture* TestGraphicsController::GetTextureFromResourceId(uint32_t resourceId)
+{
+ TraceCallStack::NamedParams namedParams;
+ namedParams["resourceId"] << resourceId;
+
+ Graphics::Texture* ret = nullptr;
+
+ auto iter = mTextureUploadBindMapper.find(resourceId);
+ if(iter != mTextureUploadBindMapper.end())
+ {
+ ret = iter->second.get();
+ }
+
+ mCallStack.PushCall("GetTextureFromResourceId", "", namedParams);
+
+ return ret;
+}
+
+Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId)
+{
+ TraceCallStack::NamedParams namedParams;
+ namedParams["resourceId"] << resourceId;
+
+ Graphics::UniquePtr<Graphics::Texture> texture;
+
+ auto iter = mTextureUploadBindMapper.find(resourceId);
+ if(iter != mTextureUploadBindMapper.end())
+ {
+ texture = std::move(iter->second);
+ mTextureUploadBindMapper.erase(iter);
+ }
+
+ mCallStack.PushCall("ReleaseTextureFromResourceId", "", namedParams);
+
+ return texture;
+}
+
} // namespace Dali
*/
#include <dali/graphics-api/graphics-controller.h>
+#include <unordered_map>
#include "test-gl-abstraction.h"
#include "test-gl-context-helper-abstraction.h"
#include "test-graphics-command-buffer.h"
*/
bool PipelineEquals(const Graphics::Pipeline& pipeline0, const Graphics::Pipeline& pipeline1) const override;
+ /**
+ * @brief Retrieves program parameters
+ *
+ * This function can be used to retrieve data from internal implementation
+ *
+ * @param[in] program Valid program object
+ * @param[in] parameterId Integer parameter id
+ * @param[out] outData Pointer to output memory
+ * @return True on success
+ */
+ bool GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) override;
+
+public: // ResourceId relative API.
+ /**
+ * @brief Create Graphics::Texture as resourceId.
+ * The ownership of Graphics::Texture will be hold on this controller.
+ * @note If some Graphics::Texture already created before, assert.
+ * @post DiscardTextureFromResourceId() or ReleaseTextureFromResourceId() should be called when we don't use resourceId texture anymore.
+ *
+ * @param[in] resourceId The unique id of resouces.
+ * @return Pointer of Graphics::Texture, or nullptr if we fail to create.
+ */
+ Graphics::Texture* CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo) override;
+
+ /**
+ * @brief Discard Graphics::Texture as resourceId.
+ *
+ * @param[in] resourceId The unique id of resouces.
+ */
+ void DiscardTextureFromResourceId(uint32_t resourceId) override;
+
+ /**
+ * @brief Get the Graphics::Texture as resourceId.
+ *
+ * @param[in] resourceId The unique id of resouces.
+ * @return Pointer of Graphics::Texture, or nullptr if there is no valid objects.
+ */
+ Graphics::Texture* GetTextureFromResourceId(uint32_t resourceId) override;
+
+ /**
+ * @brief Get the ownership of Graphics::Texture as resourceId.
+ *
+ * @param[in] resourceId The unique id of resouces.
+ * @return Pointer of Graphics::Texture.
+ */
+ Graphics::UniquePtr<Graphics::Texture> ReleaseTextureFromResourceId(uint32_t resourceId) override;
+
public: // Test Functions
void SetVertexFormats(Property::Array& vfs)
{
mSubmitStack.clear();
}
- /**
- * @brief Retrieves program parameters
- *
- * This function can be used to retrieve data from internal implementation
- *
- * @param[in] program Valid program object
- * @param[in] parameterId Integer parameter id
- * @param[out] outData Pointer to output memory
- * @return True on success
- */
- bool GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) override;
-
void ProcessCommandBuffer(TestGraphicsCommandBuffer& commandBuffer);
void BindPipeline(TestGraphicsPipeline* pipeline);
std::vector<TestGraphicsBuffer*> mAllocatedBuffers;
+ std::unordered_map<uint32_t, Graphics::UniquePtr<Graphics::Texture>> mTextureUploadBindMapper;
+
struct PipelineCache
{
};
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <toolkit-texture-upload-manager.h>
+
+// EXTERNAL INCLUDE
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+#include <dali/graphics-api/graphics-controller.h>
+#include <dali/integration-api/pixel-data-integ.h>
+#include <dali/integration-api/texture-integ.h>
+
+// INTERNAL INCLUDE
+#include <test-graphics-controller.h>
+#include <toolkit-application.h>
+
+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<ResourceId, Dali::PixelData>; ///< TODO : PixelData? PixelBuffer?
+ using RequestUploadQueue = std::vector<UploadRequestItem>;
+
+ 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<Internal::Adaptor::TextureUploadManager&>(handle);
+}
+
+inline const Internal::Adaptor::TextureUploadManager& GetImplementation(const Dali::Devel::TextureUploadManager& obj)
+{
+ DALI_ASSERT_ALWAYS(obj && "TextureUploadManager is empty");
+
+ const Dali::BaseObject& handle = obj.GetBaseObject();
+
+ return static_cast<const Internal::Adaptor::TextureUploadManager&>(handle);
+}
+
+/********************************************************************************/
+/********************************* 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::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE))
+ .SetFormat(Dali::Graphics::ConvertPixelFormat(pixelData.GetPixelFormat()))
+ .SetSize({pixelData.GetWidth(), pixelData.GetHeight()})
+ .SetLayout(Graphics::TextureLayout::LINEAR)
+ .SetData(nullptr)
+ .SetDataSize(0u)
+ .SetNativeImage(nullptr)
+ .SetMipMapFlag(Graphics::TextureMipMapFlag::DISABLED);
+
+ graphicsTexture = mGraphicsController->CreateTextureByResourceId(resourceId, createInfo);
+ }
+
+ if(graphicsTexture)
+ {
+ Graphics::TextureUpdateInfo info{};
+
+ info.dstTexture = graphicsTexture;
+ info.dstOffset2D = {0u, 0u};
+ info.layer = 0u;
+ info.level = 0u;
+ info.srcReference = 0;
+ info.srcExtent2D = {pixelData.GetWidth(), pixelData.GetHeight()};
+ info.srcOffset = 0;
+ info.srcSize = Dali::Integration::GetPixelDataBuffer(pixelData).bufferSize;
+ info.srcStride = pixelData.GetStride();
+ info.srcFormat = Dali::Graphics::ConvertPixelFormat(pixelData.GetPixelFormat());
+
+ Graphics::TextureUpdateSourceInfo updateSourceInfo{};
+ updateSourceInfo.sourceType = Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA;
+ updateSourceInfo.pixelDataSource.pixelData = pixelData;
+
+ mGraphicsController->UpdateTextures({info}, {updateSourceInfo});
+
+ uploaded = true;
+ }
+ 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
--- /dev/null
+#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 <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+
+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
#include <iostream>
#include <vector>
+#include <unistd.h>
+#include <thread>
+
#include <dali-toolkit-test-suite-utils.h>
#include <toolkit-environment-variable.h>
#include <toolkit-event-thread-callback.h>
+#include <toolkit-texture-upload-manager.h>
#include <toolkit-timer.h>
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
#include <dali-toolkit/public-api/image-loader/image-url.h>
#include <dali-toolkit/public-api/image-loader/image.h>
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+
#include "dummy-control.h"
#include "test-encoded-image-buffer.h"
#include "test-native-image-source.h"
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<std::pair<std::string, int>> 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<DummyControlImpl&>(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<DummyControlImpl&>(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<DummyControlImpl&>(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<DummyControlImpl&>(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<DummyControlImpl&>(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
* So we change its value to MASKING_ON_RENDERING even if the visual sets the MASKING_TYPE as MASKING_ON_LOADING when it uses external texture.
* @note It is used in the ImageVisual and AnimatedImageVisual. The default is MASKING_ON_LOADING.
*/
- MASKING_TYPE = ORIENTATION_CORRECTION + 12
+ MASKING_TYPE = ORIENTATION_CORRECTION + 12,
+
+ /**
+ * @brief Whether to uploading texture before ResourceReady signal emit or after texture load completed time.
+ * @details Name "fastTrackUploading", type Property::BOOLEAN.
+ * If we use fast track uploading feature, It can upload texture without event-thead dependency. But also,
+ * - Texture size is invalid until upload completed.
+ * - Texture cannot be cached (We always try to load new image).
+ * - Seamless visual change didn't supported.
+ * - Alpha masking didn't supported. If you try, It will load as normal case.
+ * - Synchronous loading didn't supported. If you try, It will load as normal case.
+ * - Reload action didn't supported. If you try, It will load as normal case.
+ * - Atlas loading didn't supported. If you try, It will load as normal case.
+ * - Custom shader didn't supported. If you try, It will load as normal case.
+ * @note It is used in the ImageVisual. The default is false.
+ */
+ FAST_TRACK_UPLOADING = ORIENTATION_CORRECTION + 13
};
} //namespace Property
${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
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/image-loader/fast-track-loading-task.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/texture-integ.h>
+
+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),
+ mLoadYuvImage(false),
+ mPremultiplied(false)
+{
+ mCallback = std::unique_ptr<CallbackBase>(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<FastTrackLoadingTask*>(task.Get())));
+ }
+}
+
+// Called by worker thread
+
+void FastTrackLoadingTask::Process()
+{
+ Load();
+ UploadToTexture();
+}
+
+bool FastTrackLoadingTask::IsReady()
+{
+ return true;
+}
+
+void FastTrackLoadingTask::Load()
+{
+ Devel::PixelBuffer pixelBuffer;
+ std::vector<Devel::PixelBuffer> 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
--- /dev/null
+#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 <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
+#include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/devel-api/adaptor-framework/texture-upload-manager.h>
+#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
+#include <dali/public-api/rendering/texture.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+class FastTrackLoadingTask;
+using FastTrackLoadingTaskPtr = IntrusivePtr<FastTrackLoadingTask>;
+
+/**
+ * @brief The task of loading and packing an image into the atlas
+ */
+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);
+
+ // Undefined
+ FastTrackLoadingTask& operator=(const FastTrackLoadingTask& queue);
+
+ /**
+ * @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<CallbackBase> 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 mLoadYuvImage : 1; ///< Whether we load image yuv format 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
#include <dali/devel-api/scripting/scripting.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
#include <dali/public-api/rendering/decorated-visual-renderer.h>
#include <cstring> // for strlen()
{
RemoveTexture();
}
+
+ ResetFastTrackLoadingTask();
}
}
{
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
}
break;
}
+
+ case Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING:
+ {
+ bool fastTrackUploading = false;
+ if(value.Get(fastTrackUploading))
+ {
+ mUseFastTrackUploading = fastTrackUploading;
+ }
+ break;
+ }
}
}
bool synchronousLoading = IsSynchronousLoadingRequired();
bool loadingStatus;
- textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mTextureId, atlasRect, mAtlasRectSize, atlasing, loadingStatus, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection, forceReload, preMultiplyOnLoad);
+ // 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);
+
+ 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)
{
if(mLoadState == TextureManager::LoadState::LOAD_FINISHED)
{
actor.AddRenderer(mImpl->mRenderer);
+ mRendererAdded = true;
mPlacementActor.Reset();
// Image loaded and ready to display
mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
actor.AddRenderer(mImpl->mRenderer);
+ mRendererAdded = true;
+
mPlacementActor.Reset();
ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
}
+ else
+ {
+ if(mFastTrackLoadingTask)
+ {
+ actor.AddRenderer(mImpl->mRenderer);
+ mRendererAdded = true;
+ }
+ }
}
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)
{
RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
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
{
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();
}
mLoadState = TextureManager::LoadState::LOAD_FINISHED;
}
+// From FastTrackLoadingTask
+void ImageVisual::FastLoadComplete(FastTrackLoadingTaskPtr task)
+{
+ Toolkit::Visual::ResourceStatus resourceStatus;
+
+ DALI_ASSERT_ALWAYS(task.Get() == mFastTrackLoadingTask.Get() && "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;
+ if(mFastTrackLoadingTask->mLoadYuvImage)
+ {
+ // TODO : Implement here.
+ }
+ else
+ {
+ // TODO : Implement here.
+ }
+
+ // Change premultiplied alpha flag after change renderer.
+ EnablePreMultipliedAlpha(mFastTrackLoadingTask->mPremultiplied);
+ }
+ else
+ {
+ resourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
+ mLoadState = TextureManager::LoadState::LOAD_FAILED;
+ Vector2 imageSize = Vector2::ZERO;
+ if(actor)
+ {
+ imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+ mPlacementActorSize = imageSize;
+ }
+ else
+ {
+ imageSize = mPlacementActorSize;
+ }
+
+ // Change renderer as broken.
+ if(actor)
+ {
+ actor.RemoveRenderer(mImpl->mRenderer);
+ }
+ mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
+ if(actor)
+ {
+ actor.AddRenderer(mImpl->mRenderer);
+ }
+ }
+
+ ResetFastTrackLoadingTask();
+
+ // Signal to observers ( control ) that resources are ready. Must be all resources.
+ ResourceReady(resourceStatus);
+}
+
// From Texture Manager
void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureInformation)
{
if(actor)
{
actor.AddRenderer(mImpl->mRenderer);
+ mRendererAdded = true;
// reset the weak handle so that the renderer only get added to actor once
mPlacementActor.Reset();
}
}
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)
}
}
+void ImageVisual::ResetFastTrackLoadingTask()
+{
+ if(mFastTrackLoadingTask)
+ {
+ Dali::AsyncTaskManager::Get().RemoveTask(mFastTrackLoadingTask);
+ mFastTrackLoadingTask.Reset();
+ }
+}
+
} // namespace Internal
} // namespace Toolkit
#include <dali/public-api/common/intrusive-ptr.h>
#include <dali/public-api/images/image-operations.h>
#include <dali/public-api/object/weak-handle.h>
+#include <dali/public-api/rendering/visual-renderer.h>
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/image-loader/atlas-upload-observer.h>
#include <dali-toolkit/internal/visuals/visual-url.h>
#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/internal/image-loader/fast-track-loading-task.h> ///< For test WorkerThread uploading.
+
namespace Dali
{
class NativeImage;
*/
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
*/
void CheckMaskTexture();
+ /**
+ * @brief Remove current added fast track upload task.
+ */
+ void ResetFastTrackLoadingTask();
+
private:
Vector4 mPixelArea;
WeakHandle<Actor> mPlacementActor;
Vector2 mTextureSize;
Vector2 mPlacementActorSize;
+ FastTrackLoadingTaskPtr mFastTrackLoadingTask; ///< For fast track uploading.
+
ImageVisualShaderFactory& mImageVisualShaderFactory;
Dali::FittingMode::Type mFittingMode : 3;
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.
+ 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 mUseFastTrackUploading{false}; ///< True if we use fast tack feature.
+ bool mRendererAdded{false}; ///< True if renderer added into actor.
};
} // namespace Internal
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");
// Text visual
const char* const TEXT_PROPERTY("text");
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;
// Text visual
extern const char* const TEXT_PROPERTY;