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.
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>
35 #if defined(DEBUG_ENABLED)
36 Debug::Filter* gTextureFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TEXTURE");
39 // Memory pool used to allocate new textures. Memory used by this pool will be released when shutting down DALi
40 MemoryPoolObjectAllocator<Texture>& GetTextureMemoryPool()
42 static MemoryPoolObjectAllocator<Texture> gTextureMemoryPool;
43 return gTextureMemoryPool;
47 * Converts DALi pixel format to Graphics::Format
51 constexpr Graphics::Format ConvertPixelFormat(Pixel::Format format)
56 return Graphics::Format::UNDEFINED;
58 return Graphics::Format::R8_UNORM;
61 return Graphics::Format::L8;
63 return Graphics::Format::L8A8;
65 return Graphics::Format::R5G6B5_UNORM_PACK16;
67 return Graphics::Format::B5G6R5_UNORM_PACK16;
69 return Graphics::Format::R4G4B4A4_UNORM_PACK16;
72 return Graphics::Format::B4G4R4A4_UNORM_PACK16;
74 return Graphics::Format::R5G5B5A1_UNORM_PACK16;
76 return Graphics::Format::B5G5R5A1_UNORM_PACK16;
78 return Graphics::Format::R8G8B8_UNORM;
80 return Graphics::Format::R8G8B8A8_UNORM;
82 return Graphics::Format::B8G8R8A8_UNORM;
84 return Graphics::Format::R8G8B8A8_UNORM;
86 return Graphics::Format::B8G8R8A8_UNORM;
88 case Pixel::DEPTH_UNSIGNED_INT:
89 return Graphics::Format::D16_UNORM;
90 case Pixel::DEPTH_FLOAT:
91 return Graphics::Format::D32_SFLOAT;
92 case Pixel::DEPTH_STENCIL:
93 return Graphics::Format::D24_UNORM_S8_UINT;
96 case Pixel::COMPRESSED_R11_EAC:
97 return Graphics::Format::EAC_R11_UNORM_BLOCK;
98 case Pixel::COMPRESSED_SIGNED_R11_EAC:
99 return Graphics::Format::EAC_R11_SNORM_BLOCK;
100 case Pixel::COMPRESSED_RG11_EAC:
101 return Graphics::Format::EAC_R11G11_UNORM_BLOCK;
102 case Pixel::COMPRESSED_SIGNED_RG11_EAC:
103 return Graphics::Format::EAC_R11G11_SNORM_BLOCK;
106 case Pixel::COMPRESSED_RGB8_ETC2:
107 return Graphics::Format::ETC2_R8G8B8_UNORM_BLOCK;
108 case Pixel::COMPRESSED_SRGB8_ETC2:
109 return Graphics::Format::ETC2_R8G8B8_SRGB_BLOCK;
111 case Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
112 return Graphics::Format::ETC2_R8G8B8A1_UNORM_BLOCK; // no 'punchthrough' format
114 case Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
115 return Graphics::Format::ETC2_R8G8B8A1_SRGB_BLOCK; // no 'punchthrough' format
117 case Pixel::COMPRESSED_RGBA8_ETC2_EAC:
118 return Graphics::Format::ETC2_R8G8B8A8_UNORM_BLOCK;
120 case Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
121 return Graphics::Format::ETC2_R8G8B8A8_SRGB_BLOCK;
123 case Pixel::COMPRESSED_RGB8_ETC1:
124 return Graphics::Format::ETC2_R8G8B8_UNORM_BLOCK; // doesn't seem to be supported at all
126 case Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
127 return Graphics::Format::PVRTC1_4BPP_UNORM_BLOCK_IMG; // or SRGB?
130 case Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR:
131 return Graphics::Format::ASTC_4x4_UNORM_BLOCK; // or SRGB?
132 case Pixel::COMPRESSED_RGBA_ASTC_5x4_KHR:
133 return Graphics::Format::ASTC_5x4_UNORM_BLOCK;
134 case Pixel::COMPRESSED_RGBA_ASTC_5x5_KHR:
135 return Graphics::Format::ASTC_5x5_UNORM_BLOCK;
136 case Pixel::COMPRESSED_RGBA_ASTC_6x5_KHR:
137 return Graphics::Format::ASTC_6x5_UNORM_BLOCK;
138 case Pixel::COMPRESSED_RGBA_ASTC_6x6_KHR:
139 return Graphics::Format::ASTC_6x6_UNORM_BLOCK;
140 case Pixel::COMPRESSED_RGBA_ASTC_8x5_KHR:
141 return Graphics::Format::ASTC_8x5_UNORM_BLOCK;
142 case Pixel::COMPRESSED_RGBA_ASTC_8x6_KHR:
143 return Graphics::Format::ASTC_8x6_UNORM_BLOCK;
144 case Pixel::COMPRESSED_RGBA_ASTC_8x8_KHR:
145 return Graphics::Format::ASTC_8x8_UNORM_BLOCK;
146 case Pixel::COMPRESSED_RGBA_ASTC_10x5_KHR:
147 return Graphics::Format::ASTC_10x5_UNORM_BLOCK;
148 case Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR:
149 return Graphics::Format::ASTC_10x6_UNORM_BLOCK;
150 case Pixel::COMPRESSED_RGBA_ASTC_10x8_KHR:
151 return Graphics::Format::ASTC_10x8_UNORM_BLOCK;
152 case Pixel::COMPRESSED_RGBA_ASTC_10x10_KHR:
153 return Graphics::Format::ASTC_10x10_UNORM_BLOCK;
154 case Pixel::COMPRESSED_RGBA_ASTC_12x10_KHR:
155 return Graphics::Format::ASTC_12x10_UNORM_BLOCK;
156 case Pixel::COMPRESSED_RGBA_ASTC_12x12_KHR:
157 return Graphics::Format::ASTC_12x12_UNORM_BLOCK;
158 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
159 return Graphics::Format::ASTC_4x4_SRGB_BLOCK; // not type with alpha, but likely to use SRGB
160 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
161 return Graphics::Format::ASTC_5x4_SRGB_BLOCK;
162 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
163 return Graphics::Format::ASTC_5x5_SRGB_BLOCK;
164 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
165 return Graphics::Format::ASTC_6x5_SRGB_BLOCK;
166 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
167 return Graphics::Format::ASTC_6x6_SRGB_BLOCK;
168 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
169 return Graphics::Format::ASTC_8x5_SRGB_BLOCK;
170 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
171 return Graphics::Format::ASTC_8x6_UNORM_BLOCK;
172 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
173 return Graphics::Format::ASTC_8x8_SRGB_BLOCK;
174 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
175 return Graphics::Format::ASTC_10x5_SRGB_BLOCK;
176 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
177 return Graphics::Format::ASTC_10x6_SRGB_BLOCK;
178 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
179 return Graphics::Format::ASTC_10x8_SRGB_BLOCK;
180 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
181 return Graphics::Format::ASTC_10x10_SRGB_BLOCK;
182 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
183 return Graphics::Format::ASTC_12x10_SRGB_BLOCK;
184 case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
185 return Graphics::Format::ASTC_12x12_SRGB_BLOCK;
188 return Graphics::Format::R16G16B16_SFLOAT;
190 return Graphics::Format::R32G32B32_SFLOAT;
191 case Pixel::R11G11B10F:
192 return Graphics::Format::R11G11B10_UFLOAT_PACK32;
194 case Pixel::CHROMINANCE_U:
195 return Graphics::Format::L8;
196 case Pixel::CHROMINANCE_V:
197 return Graphics::Format::L8;
199 return Graphics::Format::UNDEFINED;
202 constexpr Graphics::TextureType ConvertType(Texture::Type type)
206 case TextureType::TEXTURE_2D:
207 return Graphics::TextureType::TEXTURE_2D;
208 case TextureType::TEXTURE_CUBE:
209 return Graphics::TextureType::TEXTURE_CUBEMAP;
211 return Graphics::TextureType::TEXTURE_2D;
214 } //Unnamed namespace
216 TextureKey Texture::NewKey(Type type, Pixel::Format format, ImageDimensions size)
218 void* ptr = GetTextureMemoryPool().AllocateRawThreadSafe();
219 auto key = GetTextureMemoryPool().GetKeyFromPtr(static_cast<Texture*>(ptr));
220 new(ptr) Texture(type, format, size);
222 return TextureKey(key);
225 TextureKey Texture::NewKey(NativeImageInterfacePtr nativeImageInterface)
227 void* ptr = GetTextureMemoryPool().AllocateRawThreadSafe();
228 auto key = GetTextureMemoryPool().GetKeyFromPtr(static_cast<Texture*>(ptr));
229 new(ptr) Texture(nativeImageInterface);
231 return TextureKey(key);
234 Texture::Texture(Type type, Pixel::Format format, ImageDimensions size)
235 : mGraphicsController(nullptr),
236 mGraphicsTexture(nullptr),
239 mPixelFormat(format),
240 mWidth(size.GetWidth()),
241 mHeight(size.GetHeight()),
243 mHasAlpha(HasAlpha(format)),
245 mUseUploadedParameter(mWidth == 0u && mHeight == 0u && mPixelFormat == Pixel::INVALID)
249 Texture::Texture(NativeImageInterfacePtr nativeImageInterface)
250 : mGraphicsController(nullptr),
251 mGraphicsTexture(nullptr),
252 mNativeImage(nativeImageInterface),
254 mPixelFormat(Pixel::RGBA8888),
255 mWidth(static_cast<uint16_t>(nativeImageInterface->GetWidth())), // ignoring overflow, not happening in practice
256 mHeight(static_cast<uint16_t>(nativeImageInterface->GetHeight())), // ignoring overflow, not happening in practice
257 mType(TextureType::TEXTURE_2D),
258 mHasAlpha(nativeImageInterface->RequiresBlending()),
260 mUseUploadedParameter(false)
264 Texture::~Texture() = default;
266 void Texture::operator delete(void* ptr)
268 GetTextureMemoryPool().FreeThreadSafe(static_cast<Texture*>(ptr));
271 Render::Texture* Texture::Get(TextureKey::KeyType key)
273 return GetTextureMemoryPool().GetPtrFromKey(key);
276 void Texture::Initialize(Graphics::Controller& graphicsController)
278 mGraphicsController = &graphicsController;
281 Create(static_cast<uint32_t>(Graphics::TextureUsageFlagBits::SAMPLE));
285 void Texture::Destroy()
287 mGraphicsTexture.reset();
290 Graphics::Texture* Texture::GetGraphicsObject() const
292 DALI_LOG_INFO(gTextureFilter, Debug::General, "SC::Texture(%p)::GetGraphicsObject() = %p\n", this, mGraphicsTexture.get());
294 return mGraphicsTexture.get();
297 void Texture::Create(Graphics::TextureUsageFlags usage)
299 Create(usage, Graphics::TextureAllocationPolicy::CREATION);
302 void Texture::Create(Graphics::TextureUsageFlags usage, Graphics::TextureAllocationPolicy allocationPolicy)
304 CreateWithData(usage, allocationPolicy, nullptr, 0u);
307 void Texture::CreateWithData(Graphics::TextureUsageFlags usage, Graphics::TextureAllocationPolicy allocationPolicy, uint8_t* data, uint32_t size)
309 auto createInfo = Graphics::TextureCreateInfo();
311 .SetTextureType(ConvertType(mType))
312 .SetUsageFlags(usage)
313 .SetFormat(ConvertPixelFormat(mPixelFormat))
314 .SetSize({mWidth, mHeight})
315 .SetLayout(Graphics::TextureLayout::LINEAR)
316 .SetAllocationPolicy(allocationPolicy)
319 .SetNativeImage(mNativeImage)
320 .SetMipMapFlag(Graphics::TextureMipMapFlag::DISABLED);
322 mGraphicsTexture = mGraphicsController->CreateTexture(createInfo, std::move(mGraphicsTexture));
325 void Texture::Upload(PixelDataPtr pixelData, const Internal::Texture::UploadParams& params)
327 DALI_ASSERT_ALWAYS(!mNativeImage);
329 const uint32_t srcStride = pixelData->GetStride();
330 uint32_t srcOffset = 0u;
331 uint32_t srcSize = pixelData->GetBufferSize();
333 // Cache uploaded data
334 const auto uploadedDataWidth = params.dataWidth;
335 const auto uploadedDataHeight = params.dataHeight;
336 const auto uploadedPixelFormat = pixelData->GetPixelFormat();
338 const bool requiredSubPixelData = (!Pixel::IsCompressed(uploadedPixelFormat)) &&
339 ((params.dataXOffset != 0) ||
340 (params.dataYOffset != 0) ||
341 (uploadedDataWidth != pixelData->GetWidth()) ||
342 (uploadedDataHeight != pixelData->GetHeight()));
344 if(requiredSubPixelData)
347 * TextureUpdateInfo use byte scaled offset / size.
349 * To make we only use sub-data of inputed PixelData, make srcOffset as 'start of SubPixelData.
351 * |---- dataStrideByte -----|
352 * |-----| <-- dataXOffsetByte
353 * ...........................
354 * ......A-----------+........
357 * ......+-----------+C.......
358 * ......B....................
360 * A) Start of SubPixelData. offsetByte = dataStrideByte * dataYOffset + dataXOffsetByte.
361 * B) offsetByte = A).offsetByte + dataStrideByte * dataHeight. Note, It can be out of original PixelData boundary.
362 * C) End of SubPixelData. offsetByte = B).offsetByte - dataStrideByte + dataWidthByte.
364 * srcOffset = A).offsetByte;
365 * srcSize = ( C).offsetByte - A).offsetByte );
367 const uint32_t bytePerPixel = Pixel::GetBytesPerPixel(uploadedPixelFormat);
368 const uint32_t dataStrideByte = (srcStride ? srcStride : pixelData->GetWidth()) * bytePerPixel;
369 const uint32_t dataXOffsetByte = params.dataXOffset * bytePerPixel;
370 const uint32_t dataWidthByte = static_cast<uint32_t>(uploadedDataWidth) * bytePerPixel;
372 srcOffset = params.dataYOffset * dataStrideByte + dataXOffsetByte;
373 srcSize = static_cast<uint32_t>(uploadedDataHeight) * dataStrideByte - (dataStrideByte - dataWidthByte);
376 // Update render texture value as uploaded data.
377 if(mUseUploadedParameter)
379 mWidth = params.xOffset + uploadedDataWidth;
380 mHeight = params.yOffset + uploadedDataHeight;
381 mPixelFormat = uploadedPixelFormat;
384 // Always create new graphics texture object if we use uploaded parameter as texture.
385 if(!mGraphicsTexture || mUseUploadedParameter)
387 const bool isSubImage(params.xOffset != 0u || params.yOffset != 0u ||
388 uploadedDataWidth != (mWidth >> params.mipmap) ||
389 uploadedDataHeight != (mHeight >> params.mipmap));
390 Create(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE), isSubImage ? Graphics::TextureAllocationPolicy::CREATION : Graphics::TextureAllocationPolicy::UPLOAD);
393 Graphics::TextureUpdateInfo info{};
395 info.dstTexture = mGraphicsTexture.get();
396 info.dstOffset2D = {params.xOffset, params.yOffset};
397 info.layer = params.layer;
398 info.level = params.mipmap;
399 info.srcReference = 0;
400 info.srcExtent2D = {uploadedDataWidth, uploadedDataHeight};
401 info.srcOffset = srcOffset;
402 info.srcSize = srcSize;
403 info.srcStride = srcStride;
404 info.srcFormat = ConvertPixelFormat(uploadedPixelFormat);
406 mUpdatedArea = Rect<uint16_t>(params.xOffset, params.yOffset, params.width, params.height);
408 Graphics::TextureUpdateSourceInfo updateSourceInfo{};
409 updateSourceInfo.sourceType = Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA;
410 updateSourceInfo.pixelDataSource.pixelData = Dali::PixelData(pixelData.Get());
412 mGraphicsController->UpdateTextures({info}, {updateSourceInfo});
417 bool Texture::HasAlphaChannel() const
419 bool alpha = mHasAlpha;
422 alpha = mNativeImage->RequiresBlending();
427 void Texture::GenerateMipmaps()
429 if(!mGraphicsTexture)
431 Create(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE));
434 mGraphicsController->GenerateTextureMipmaps(*mGraphicsTexture.get());
437 void Texture::OnRenderFinished()
440 mUpdatedArea = Rect<uint16_t>{0, 0, 0, 0};
443 Rect<uint16_t> Texture::GetUpdatedArea()
447 Rect<uint32_t> rect = mNativeImage->GetUpdatedArea();
448 mUpdatedArea.x = static_cast<uint16_t>(rect.x);
449 mUpdatedArea.y = static_cast<uint16_t>(rect.y);
450 mUpdatedArea.width = static_cast<uint16_t>(rect.width);
451 mUpdatedArea.height = static_cast<uint16_t>(rect.height);
456 } // namespace Render
458 } // namespace Internal