2 * Copyright (c) 2024 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.
18 #include <dali/internal/render/renderers/render-texture.h>
21 #include <math.h> //floor, log2
24 #include <dali/integration-api/debug.h>
25 #include <dali/internal/common/memory-pool-object-allocator.h>
26 #include <dali/internal/render/common/render-manager.h>
36 #if defined(DEBUG_ENABLED)
37 Debug::Filter* gTextureFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TEXTURE");
40 // Memory pool used to allocate new textures. Memory used by this pool will be released when shutting down DALi
41 Dali::Internal::MemoryPoolObjectAllocator<Texture>& GetTextureMemoryPool()
43 static Dali::Internal::MemoryPoolObjectAllocator<Texture> gTextureMemoryPool;
44 return gTextureMemoryPool;
49 TextureKey Texture::NewKey(Type type, Pixel::Format format, ImageDimensions size)
51 void* ptr = GetTextureMemoryPool().AllocateRawThreadSafe();
52 auto key = GetTextureMemoryPool().GetKeyFromPtr(static_cast<Texture*>(ptr));
53 new(ptr) Texture(type, format, size);
55 return TextureKey(key);
58 TextureKey Texture::NewKey(NativeImageInterfacePtr nativeImageInterface)
60 void* ptr = GetTextureMemoryPool().AllocateRawThreadSafe();
61 auto key = GetTextureMemoryPool().GetKeyFromPtr(static_cast<Texture*>(ptr));
62 new(ptr) Texture(nativeImageInterface);
64 return TextureKey(key);
67 TextureKey Texture::NewKey(Type type, uint32_t resourceId)
69 void* ptr = GetTextureMemoryPool().AllocateRawThreadSafe();
70 auto key = GetTextureMemoryPool().GetKeyFromPtr(static_cast<Texture*>(ptr));
71 new(ptr) Texture(type, resourceId);
73 return TextureKey(key);
76 void Texture::ResetMemoryPool()
78 GetTextureMemoryPool().ResetMemoryPool();
81 Texture::Texture(Type type, Pixel::Format format, ImageDimensions size)
82 : mGraphicsController(nullptr),
83 mRenderManager(nullptr),
84 mGraphicsTexture(nullptr),
88 mWidth(size.GetWidth()),
89 mHeight(size.GetHeight()),
92 mHasAlpha(HasAlpha(format)),
94 mUseUploadedParameter(mWidth == 0u && mHeight == 0u && mPixelFormat == Pixel::INVALID)
98 Texture::Texture(NativeImageInterfacePtr nativeImageInterface)
99 : mGraphicsController(nullptr),
100 mRenderManager(nullptr),
101 mGraphicsTexture(nullptr),
102 mNativeImage(nativeImageInterface),
104 mPixelFormat(Pixel::RGBA8888),
105 mWidth(static_cast<uint16_t>(nativeImageInterface->GetWidth())), // ignoring overflow, not happening in practice
106 mHeight(static_cast<uint16_t>(nativeImageInterface->GetHeight())), // ignoring overflow, not happening in practice
108 mType(TextureType::TEXTURE_2D),
109 mHasAlpha(nativeImageInterface->RequiresBlending()),
111 mUseUploadedParameter(false)
115 Texture::Texture(Type type, uint32_t resourceId)
116 : mGraphicsController(nullptr),
117 mRenderManager(nullptr),
118 mGraphicsTexture(nullptr),
121 mPixelFormat(Pixel::INVALID),
124 mResourceId(resourceId),
126 mHasAlpha(true), ///< Since we don't assume what kind of texture will be uploaded in this case.
128 mUseUploadedParameter(true)
132 Texture::~Texture() = default;
134 void Texture::operator delete(void* ptr)
136 GetTextureMemoryPool().FreeThreadSafe(static_cast<Texture*>(ptr));
139 Render::Texture* Texture::Get(TextureKey::KeyType key)
141 return GetTextureMemoryPool().GetPtrFromKey(key);
144 void Texture::Initialize(Graphics::Controller& graphicsController, SceneGraph::RenderManager& renderManager)
146 mGraphicsController = &graphicsController;
147 mRenderManager = &renderManager;
150 Create(static_cast<uint32_t>(Graphics::TextureUsageFlagBits::SAMPLE));
153 if(mResourceId != 0u && mGraphicsController->GetTextureFromResourceId(mResourceId))
155 // Take ownership from graphics controller
156 mGraphicsTexture = std::move(mGraphicsController->ReleaseTextureFromResourceId(mResourceId));
157 // Now we take on the Graphics::Texture ownership. We don't need to keep mResourceId anymore.
162 void Texture::Destroy()
164 if(mResourceId != 0u && mGraphicsTexture.get() == nullptr)
166 // We still don't take texture ownership from controller before.
167 // Discard graphics object now.
168 mGraphicsController->DiscardTextureFromResourceId(mResourceId);
172 mGraphicsTexture.reset();
175 Graphics::Texture* Texture::GetGraphicsObject()
177 if(mResourceId != 0u && mGraphicsTexture.get() == nullptr)
179 // The ownership of Graphics::Texture is on Graphics::Controller. Ask to controller.
180 Graphics::Texture* graphicsTexturePtr = nullptr;
181 if(mGraphicsController)
183 graphicsTexturePtr = mGraphicsController->GetTextureFromResourceId(mResourceId);
185 if(graphicsTexturePtr)
187 // Take ownership from graphics controller
188 mGraphicsTexture = std::move(mGraphicsController->ReleaseTextureFromResourceId(mResourceId));
189 // (Partial update) Do not make mResourceId as 0 until we update mLatestUsedGraphicsTexture.
190 NotifyTextureUpdated();
193 DALI_LOG_INFO(gTextureFilter, Debug::General, "Render::Texture(%p)::GetGraphicsObject() = %p [with resource id : %u]\n", this, graphicsTexturePtr, mResourceId);
195 return graphicsTexturePtr;
199 DALI_LOG_INFO(gTextureFilter, Debug::General, "Render::Texture(%p)::GetGraphicsObject() = %p\n", this, mGraphicsTexture.get());
201 return mGraphicsTexture.get();
205 void Texture::Create(Graphics::TextureUsageFlags usage)
207 DALI_ASSERT_ALWAYS(mResourceId == 0u);
209 Create(usage, Graphics::TextureAllocationPolicy::CREATION);
212 void Texture::Create(Graphics::TextureUsageFlags usage, Graphics::TextureAllocationPolicy allocationPolicy)
214 CreateWithData(usage, allocationPolicy, nullptr, 0u);
217 void Texture::CreateWithData(Graphics::TextureUsageFlags usage, Graphics::TextureAllocationPolicy allocationPolicy, uint8_t* data, uint32_t size)
219 auto createInfo = Graphics::TextureCreateInfo();
221 .SetTextureType(Dali::Graphics::ConvertTextureType(mType))
222 .SetUsageFlags(usage)
223 .SetFormat(Dali::Graphics::ConvertPixelFormat(mPixelFormat))
224 .SetSize({mWidth, mHeight})
225 .SetLayout(Graphics::TextureLayout::LINEAR)
226 .SetAllocationPolicy(allocationPolicy)
229 .SetNativeImage(mNativeImage)
230 .SetMipMapFlag(Graphics::TextureMipMapFlag::DISABLED);
232 mGraphicsTexture = mGraphicsController->CreateTexture(createInfo, std::move(mGraphicsTexture));
235 void Texture::Upload(PixelDataPtr pixelData, const Graphics::UploadParams& params)
237 DALI_ASSERT_ALWAYS(!mNativeImage);
238 DALI_ASSERT_ALWAYS(mResourceId == 0u);
240 const uint32_t srcStride = pixelData->GetStride();
241 uint32_t srcOffset = 0u;
242 uint32_t srcSize = pixelData->GetBufferSize();
244 // Cache uploaded data
245 const auto uploadedDataWidth = params.dataWidth;
246 const auto uploadedDataHeight = params.dataHeight;
247 const auto uploadedPixelFormat = pixelData->GetPixelFormat();
249 const bool requiredSubPixelData = (!Pixel::IsCompressed(uploadedPixelFormat)) &&
250 ((params.dataXOffset != 0) ||
251 (params.dataYOffset != 0) ||
252 (uploadedDataWidth != pixelData->GetWidth()) ||
253 (uploadedDataHeight != pixelData->GetHeight()));
255 if(requiredSubPixelData)
258 * TextureUpdateInfo use byte scaled offset / size.
260 * To make we only use sub-data of inputed PixelData, make srcOffset as 'start of SubPixelData.
262 * |---- dataStrideByte -----|
263 * |-----| <-- dataXOffsetByte
264 * ...........................
265 * ......A-----------+........
268 * ......+-----------+C.......
269 * ......B....................
271 * A) Start of SubPixelData. offsetByte = dataStrideByte * dataYOffset + dataXOffsetByte.
272 * B) offsetByte = A).offsetByte + dataStrideByte * dataHeight. Note, It can be out of original PixelData boundary.
273 * C) End of SubPixelData. offsetByte = B).offsetByte - dataStrideByte + dataWidthByte.
275 * srcOffset = A).offsetByte;
276 * srcSize = ( C).offsetByte - A).offsetByte );
278 const uint32_t bytePerPixel = Pixel::GetBytesPerPixel(uploadedPixelFormat);
279 const uint32_t dataStrideByte = (srcStride ? srcStride : pixelData->GetWidth()) * bytePerPixel;
280 const uint32_t dataXOffsetByte = params.dataXOffset * bytePerPixel;
281 const uint32_t dataWidthByte = static_cast<uint32_t>(uploadedDataWidth) * bytePerPixel;
283 srcOffset = params.dataYOffset * dataStrideByte + dataXOffsetByte;
284 srcSize = static_cast<uint32_t>(uploadedDataHeight) * dataStrideByte - (dataStrideByte - dataWidthByte);
287 // Update render texture value as uploaded data.
288 if(mUseUploadedParameter)
290 mWidth = params.xOffset + uploadedDataWidth;
291 mHeight = params.yOffset + uploadedDataHeight;
292 mPixelFormat = uploadedPixelFormat;
295 // Always create new graphics texture object if we use uploaded parameter as texture.
296 if(!mGraphicsTexture || mUseUploadedParameter)
298 const bool isSubImage(params.xOffset != 0u || params.yOffset != 0u ||
299 uploadedDataWidth != (mWidth >> params.mipmap) ||
300 uploadedDataHeight != (mHeight >> params.mipmap));
301 Create(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE), isSubImage ? Graphics::TextureAllocationPolicy::CREATION : Graphics::TextureAllocationPolicy::UPLOAD);
304 Graphics::TextureUpdateInfo info{};
306 info.dstTexture = mGraphicsTexture.get();
307 info.dstOffset2D = {params.xOffset, params.yOffset};
308 info.layer = params.layer;
309 info.level = params.mipmap;
310 info.srcReference = 0;
311 info.srcExtent2D = {uploadedDataWidth, uploadedDataHeight};
312 info.srcOffset = srcOffset;
313 info.srcSize = srcSize;
314 info.srcStride = srcStride;
315 info.srcFormat = Dali::Graphics::ConvertPixelFormat(uploadedPixelFormat);
317 mUpdatedArea = Rect<uint16_t>(params.xOffset, params.yOffset, params.width, params.height);
319 Graphics::TextureUpdateSourceInfo updateSourceInfo{};
320 updateSourceInfo.sourceType = Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA;
321 updateSourceInfo.pixelDataSource.pixelData = Dali::PixelData(pixelData.Get());
323 mGraphicsController->UpdateTextures({info}, {updateSourceInfo});
328 bool Texture::HasAlphaChannel() const
330 bool alpha = mHasAlpha;
333 alpha = mNativeImage->RequiresBlending();
338 bool Texture::IsGraphicsObjectChanged()
340 return mLatestUsedGraphicsTexture != GetGraphicsObject();
343 void Texture::NotifyTextureUpdated()
347 mRenderManager->SetTextureUpdated(TextureKey(GetTextureMemoryPool().GetKeyFromPtr(this)));
351 void Texture::GenerateMipmaps()
353 DALI_ASSERT_ALWAYS(mResourceId == 0u);
355 // Compressed pixel doesn't support mipmap generation.
356 if(Pixel::IsCompressed(mPixelFormat))
361 if(!mGraphicsTexture)
363 Create(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE));
366 mGraphicsController->GenerateTextureMipmaps(*mGraphicsTexture.get());
369 void Texture::OnRenderFinished()
373 if(mResourceId != 0u)
375 mLatestUsedGraphicsTexture = GetGraphicsObject();
376 if(mLatestUsedGraphicsTexture != nullptr)
378 // We don't need to keep mResourceId anymore.
383 mUpdatedArea = Rect<uint16_t>{0, 0, 0, 0};
386 Rect<uint16_t> Texture::GetUpdatedArea()
390 Rect<uint32_t> rect = mNativeImage->GetUpdatedArea();
391 mUpdatedArea.x = static_cast<uint16_t>(rect.x);
392 mUpdatedArea.y = static_cast<uint16_t>(rect.y);
393 mUpdatedArea.width = static_cast<uint16_t>(rect.width);
394 mUpdatedArea.height = static_cast<uint16_t>(rect.height);
399 } // namespace Render
401 } // namespace Internal