2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/system/common/texture-upload-manager-impl.h>
22 #include <dali/devel-api/common/singleton-service.h>
23 #include <dali/graphics-api/graphics-texture-upload-helper.h> ///< for Dali::Graphics::ConvertPixelFormat
24 #include <dali/integration-api/adaptor-framework/adaptor.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/integration-api/pixel-data-integ.h>
27 #include <dali/integration-api/texture-integ.h>
28 #include <dali/integration-api/trace.h>
31 #include <dali/internal/adaptor/common/adaptor-impl.h>
41 Dali::Devel::TextureUploadManager::ResourceId gUniqueResourceId = 0;
43 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
45 #if defined(DEBUG_ENABLED)
46 Debug::Filter* gTextureUploadManagerLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_TEXTURE_UPLOAD_MANAGER");
49 } // unnamed namespace
51 // Called by main thread
53 Dali::Devel::TextureUploadManager TextureUploadManager::Get()
55 Dali::Devel::TextureUploadManager manager;
56 SingletonService singletonService(SingletonService::Get());
59 // Check whether the texture upload manager is already created
60 Dali::BaseHandle handle = singletonService.GetSingleton(typeid(Dali::Devel::TextureUploadManager));
63 // If so, downcast the handle of singleton
64 manager = Dali::Devel::TextureUploadManager(dynamic_cast<Internal::Adaptor::TextureUploadManager*>(handle.GetObjectPtr()));
69 // If not, create the texture upload manager and register it as a singleton
70 Internal::Adaptor::TextureUploadManager* internalTextureUploadManager = new Internal::Adaptor::TextureUploadManager();
71 manager = Dali::Devel::TextureUploadManager(internalTextureUploadManager);
72 singletonService.Register(typeid(manager), manager);
78 TextureUploadManager::TextureUploadManager()
79 : mGraphicsController{nullptr},
80 mRenderTrigger(new EventThreadCallback(MakeCallback(this, &TextureUploadManager::RequestUpdateOnce)))
84 TextureUploadManager::~TextureUploadManager()
88 Dali::Texture TextureUploadManager::GenerateTexture2D()
90 ResourceId resourceId = GenerateUploadResourceId();
92 Dali::Texture ret = Dali::Integration::NewTextureWithResourceId(Dali::TextureType::TEXTURE_2D, resourceId);
97 Dali::Devel::TextureUploadManager::ResourceId TextureUploadManager::GenerateUploadResourceId()
99 auto id = ++gUniqueResourceId;
101 // Jump overflow case so we can assume that resource id always valid.
102 if(DALI_UNLIKELY(gUniqueResourceId == Dali::Devel::TextureUploadManager::INVALID_RESOURCE_ID))
110 void TextureUploadManager::RequestUpdateOnce()
112 if(Dali::Adaptor::IsAvailable())
114 DALI_LOG_INFO(gTextureUploadManagerLogFilter, Debug::Concise, "RenderOnce requested\n");
115 Dali::Adaptor::Get().RenderOnce();
119 // Called by update thread
121 bool TextureUploadManager::ResourceUpload()
123 DALI_ASSERT_DEBUG(mGraphicsController && "GraphicsController is not prepared!");
126 RequestUploadQueue copiedRequestUploadQueue;
129 Dali::Mutex::ScopedLock lock(mRequestMutex);
130 copiedRequestUploadQueue = std::move(mRequestUploadQueue);
134 bool uploaded = ProcessUploadQueue(std::move(copiedRequestUploadQueue));
139 void TextureUploadManager::InitalizeGraphicsController(Dali::Graphics::Controller& graphicsController)
141 mGraphicsController = &graphicsController;
144 bool TextureUploadManager::ProcessUploadQueue(RequestUploadQueue&& queue)
146 bool uploaded = false;
151 if(gTraceFilter && gTraceFilter->IsTraceEnabled())
153 std::ostringstream stream;
154 stream << "[upload request \'" << queue.size() << "\' images]";
155 DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_WORKER_THREAD_RESOURCE_UPLOAD", stream.str().c_str());
157 uint32_t uploadedCount = 0u;
158 uint32_t canceledCount = 0u;
161 DALI_LOG_INFO(gTextureUploadManagerLogFilter, Debug::Concise, "Upload request %zu images\n", queue.size());
162 for(auto& requests : queue)
164 auto& resourceId = requests.first;
165 auto& pixelData = requests.second;
167 Graphics::Texture* graphicsTexture = nullptr;
169 // TODO : Could we detect TEXTURE_2D or TEXTURE_CUBE case in future?
171 // We always need to create new one
172 auto createInfo = Graphics::TextureCreateInfo();
174 .SetTextureType(Dali::Graphics::ConvertTextureType(Dali::TextureType::TEXTURE_2D))
175 .SetUsageFlags(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE))
176 .SetFormat(Dali::Graphics::ConvertPixelFormat(pixelData.GetPixelFormat()))
177 .SetSize({pixelData.GetWidth(), pixelData.GetHeight()})
178 .SetLayout(Graphics::TextureLayout::LINEAR)
181 .SetNativeImage(nullptr)
182 .SetMipMapFlag(Graphics::TextureMipMapFlag::DISABLED);
184 graphicsTexture = mGraphicsController->CreateTextureByResourceId(resourceId, createInfo);
189 Graphics::TextureUpdateInfo info{};
191 info.dstTexture = graphicsTexture;
192 info.dstOffset2D = {0u, 0u};
195 info.srcReference = 0;
196 info.srcExtent2D = {pixelData.GetWidth(), pixelData.GetHeight()};
198 info.srcSize = Dali::Integration::GetPixelDataBuffer(pixelData).bufferSize;
199 info.srcStride = pixelData.GetStride();
200 info.srcFormat = Dali::Graphics::ConvertPixelFormat(pixelData.GetPixelFormat());
202 Graphics::TextureUpdateSourceInfo updateSourceInfo{};
203 updateSourceInfo.sourceType = Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA;
204 updateSourceInfo.pixelDataSource.pixelData = pixelData;
206 mGraphicsController->UpdateTextures({info}, {updateSourceInfo});
215 // Invalidate resouce id! ignore.
225 Graphics::SubmitInfo submitInfo;
226 submitInfo.cmdBuffer.clear(); // Only flush
227 submitInfo.flags = 0 | Graphics::SubmitFlagBits::FLUSH;
228 mGraphicsController->SubmitCommandBuffers(submitInfo);
231 if(gTraceFilter && gTraceFilter->IsTraceEnabled())
233 std::ostringstream stream;
234 stream << "[upload : \'" << uploadedCount << "\', cancel : \'" << canceledCount << "\']";
235 DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_WORKER_THREAD_RESOURCE_UPLOAD", stream.str().c_str());
243 // Called by worker thread
245 void TextureUploadManager::RequestUpload(Dali::Devel::TextureUploadManager::ResourceId resourceId, Dali::PixelData pixelData)
247 DALI_ASSERT_ALWAYS(resourceId != Dali::Devel::TextureUploadManager::INVALID_RESOURCE_ID && "Invalid resource id generated!");
248 DALI_ASSERT_ALWAYS(pixelData && "Invalid pixelData!");
251 Dali::Mutex::ScopedLock lock(mRequestMutex); // Worker-Update thread mutex
253 mRequestUploadQueue.push_back(std::move(UploadRequestItem(resourceId, pixelData)));
256 // wake up the main thread
257 // TODO : Is there any way to request upload once without main thread dependency?
258 mRenderTrigger->Trigger();
261 } // namespace Adaptor
263 } // namespace Internal