Make property resetter age down correctly
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / render-texture.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 // CLASS HEADER
18 #include <dali/internal/render/renderers/render-texture.h>
19
20 // EXTERNAL INCLUDES
21 #include <math.h> //floor, log2
22
23 // INTERNAL INCLUDES
24 #include <dali/integration-api/debug.h>
25 #include <dali/internal/common/memory-pool-object-allocator.h>
26
27 namespace Dali
28 {
29 namespace Internal
30 {
31 namespace Render
32 {
33 namespace
34 {
35 #if defined(DEBUG_ENABLED)
36 Debug::Filter* gTextureFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TEXTURE");
37 #endif
38
39 // Memory pool used to allocate new textures. Memory used by this pool will be released when shutting down DALi
40 MemoryPoolObjectAllocator<Texture>& GetTextureMemoryPool()
41 {
42   static MemoryPoolObjectAllocator<Texture> gTextureMemoryPool;
43   return gTextureMemoryPool;
44 }
45
46 /**
47  * Converts DALi pixel format to Graphics::Format
48  * @param format
49  * @return
50  */
51 constexpr Graphics::Format ConvertPixelFormat(Pixel::Format format)
52 {
53   switch(format)
54   {
55     case Pixel::INVALID:
56       return Graphics::Format::UNDEFINED;
57     case Pixel::A8:
58       return Graphics::Format::R8_UNORM;
59
60     case Pixel::L8:
61       return Graphics::Format::L8;
62     case Pixel::LA88:
63       return Graphics::Format::L8A8;
64     case Pixel::RGB565:
65       return Graphics::Format::R5G6B5_UNORM_PACK16;
66     case Pixel::BGR565:
67       return Graphics::Format::B5G6R5_UNORM_PACK16;
68     case Pixel::RGBA4444:
69       return Graphics::Format::R4G4B4A4_UNORM_PACK16;
70
71     case Pixel::BGRA4444:
72       return Graphics::Format::B4G4R4A4_UNORM_PACK16;
73     case Pixel::RGBA5551:
74       return Graphics::Format::R5G5B5A1_UNORM_PACK16;
75     case Pixel::BGRA5551:
76       return Graphics::Format::B5G5R5A1_UNORM_PACK16;
77     case Pixel::RGB888:
78       return Graphics::Format::R8G8B8_UNORM;
79     case Pixel::RGB8888:
80       return Graphics::Format::R8G8B8A8_UNORM;
81     case Pixel::BGR8888:
82       return Graphics::Format::B8G8R8A8_UNORM;
83     case Pixel::RGBA8888:
84       return Graphics::Format::R8G8B8A8_UNORM;
85     case Pixel::BGRA8888:
86       return Graphics::Format::B8G8R8A8_UNORM;
87
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;
94
95     // EAC
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;
104
105     // ETC
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;
110
111     case Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
112       return Graphics::Format::ETC2_R8G8B8A1_UNORM_BLOCK; // no 'punchthrough' format
113
114     case Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
115       return Graphics::Format::ETC2_R8G8B8A1_SRGB_BLOCK; // no 'punchthrough' format
116
117     case Pixel::COMPRESSED_RGBA8_ETC2_EAC:
118       return Graphics::Format::ETC2_R8G8B8A8_UNORM_BLOCK;
119
120     case Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
121       return Graphics::Format::ETC2_R8G8B8A8_SRGB_BLOCK;
122
123     case Pixel::COMPRESSED_RGB8_ETC1:
124       return Graphics::Format::ETC2_R8G8B8_UNORM_BLOCK; // doesn't seem to be supported at all
125
126     case Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
127       return Graphics::Format::PVRTC1_4BPP_UNORM_BLOCK_IMG; // or SRGB?
128
129     // ASTC
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;
186
187     case Pixel::RGB16F:
188       return Graphics::Format::R16G16B16_SFLOAT;
189     case Pixel::RGB32F:
190       return Graphics::Format::R32G32B32_SFLOAT;
191     case Pixel::R11G11B10F:
192       return Graphics::Format::R11G11B10_UFLOAT_PACK32;
193
194     case Pixel::CHROMINANCE_U:
195       return Graphics::Format::L8;
196     case Pixel::CHROMINANCE_V:
197       return Graphics::Format::L8;
198   }
199   return Graphics::Format::UNDEFINED;
200 }
201
202 constexpr Graphics::TextureType ConvertType(Texture::Type type)
203 {
204   switch(type)
205   {
206     case TextureType::TEXTURE_2D:
207       return Graphics::TextureType::TEXTURE_2D;
208     case TextureType::TEXTURE_CUBE:
209       return Graphics::TextureType::TEXTURE_CUBEMAP;
210   }
211   return Graphics::TextureType::TEXTURE_2D;
212 }
213
214 } //Unnamed namespace
215
216 TextureKey Texture::NewKey(Type type, Pixel::Format format, ImageDimensions size)
217 {
218   void* ptr = GetTextureMemoryPool().AllocateRawThreadSafe();
219   auto  key = GetTextureMemoryPool().GetKeyFromPtr(static_cast<Texture*>(ptr));
220   new(ptr) Texture(type, format, size);
221
222   return TextureKey(key);
223 }
224
225 TextureKey Texture::NewKey(NativeImageInterfacePtr nativeImageInterface)
226 {
227   void* ptr = GetTextureMemoryPool().AllocateRawThreadSafe();
228   auto  key = GetTextureMemoryPool().GetKeyFromPtr(static_cast<Texture*>(ptr));
229   new(ptr) Texture(nativeImageInterface);
230
231   return TextureKey(key);
232 }
233
234 Texture::Texture(Type type, Pixel::Format format, ImageDimensions size)
235 : mGraphicsController(nullptr),
236   mGraphicsTexture(nullptr),
237   mNativeImage(),
238   mSampler(),
239   mPixelFormat(format),
240   mWidth(size.GetWidth()),
241   mHeight(size.GetHeight()),
242   mType(type),
243   mHasAlpha(HasAlpha(format)),
244   mUpdated(true),
245   mUseUploadedParameter(mWidth == 0u && mHeight == 0u && mPixelFormat == Pixel::INVALID)
246 {
247 }
248
249 Texture::Texture(NativeImageInterfacePtr nativeImageInterface)
250 : mGraphicsController(nullptr),
251   mGraphicsTexture(nullptr),
252   mNativeImage(nativeImageInterface),
253   mSampler(),
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()),
259   mUpdated(true),
260   mUseUploadedParameter(false)
261 {
262 }
263
264 Texture::~Texture() = default;
265
266 void Texture::operator delete(void* ptr)
267 {
268   GetTextureMemoryPool().FreeThreadSafe(static_cast<Texture*>(ptr));
269 }
270
271 Render::Texture* Texture::Get(TextureKey::KeyType key)
272 {
273   return GetTextureMemoryPool().GetPtrFromKey(key);
274 }
275
276 void Texture::Initialize(Graphics::Controller& graphicsController)
277 {
278   mGraphicsController = &graphicsController;
279   if(mNativeImage)
280   {
281     Create(static_cast<uint32_t>(Graphics::TextureUsageFlagBits::SAMPLE));
282   }
283 }
284
285 void Texture::Destroy()
286 {
287   mGraphicsTexture.reset();
288 }
289
290 Graphics::Texture* Texture::GetGraphicsObject() const
291 {
292   DALI_LOG_INFO(gTextureFilter, Debug::General, "SC::Texture(%p)::GetGraphicsObject() = %p\n", this, mGraphicsTexture.get());
293
294   return mGraphicsTexture.get();
295 }
296
297 void Texture::Create(Graphics::TextureUsageFlags usage)
298 {
299   CreateWithData(usage, nullptr, 0u);
300 }
301
302 void Texture::CreateWithData(Graphics::TextureUsageFlags usage, uint8_t* data, uint32_t size)
303 {
304   auto createInfo = Graphics::TextureCreateInfo();
305   createInfo
306     .SetTextureType(ConvertType(mType))
307     .SetUsageFlags(usage)
308     .SetFormat(ConvertPixelFormat(mPixelFormat))
309     .SetSize({mWidth, mHeight})
310     .SetLayout(Graphics::TextureLayout::LINEAR)
311     .SetData(data)
312     .SetDataSize(size)
313     .SetNativeImage(mNativeImage)
314     .SetMipMapFlag(Graphics::TextureMipMapFlag::DISABLED);
315
316   mGraphicsTexture = mGraphicsController->CreateTexture(createInfo, std::move(mGraphicsTexture));
317 }
318
319 void Texture::Upload(PixelDataPtr pixelData, const Internal::Texture::UploadParams& params)
320 {
321   DALI_ASSERT_ALWAYS(!mNativeImage);
322
323   const uint32_t srcStride = pixelData->GetStride();
324   uint32_t       srcOffset = 0u;
325   uint32_t       srcSize   = pixelData->GetBufferSize();
326
327   // Cache uploaded data
328   const auto uploadedDataWidth   = params.dataWidth;
329   const auto uploadedDataHeight  = params.dataHeight;
330   const auto uploadedPixelFormat = pixelData->GetPixelFormat();
331
332   const bool requiredSubPixelData = (!Pixel::IsCompressed(uploadedPixelFormat)) &&
333                                     ((params.dataXOffset != 0) ||
334                                      (params.dataYOffset != 0) ||
335                                      (uploadedDataWidth != pixelData->GetWidth()) ||
336                                      (uploadedDataHeight != pixelData->GetHeight()));
337
338   if(requiredSubPixelData)
339   {
340     /**
341      * TextureUpdateInfo use byte scaled offset / size.
342      *
343      * To make we only use sub-data of inputed PixelData, make srcOffset as 'start of SubPixelData.
344      *
345      *   |---- dataStrideByte -----|
346      *   |-----| <-- dataXOffsetByte
347      *   ...........................
348      *   ......A-----------+........
349      *   ......|           |........
350      *   ......|           |........
351      *   ......+-----------+C.......
352      *   ......B....................
353      *
354      * A) Start of SubPixelData. offsetByte = dataStrideByte * dataYOffset + dataXOffsetByte.
355      * B) offsetByte = A).offsetByte + dataStrideByte * dataHeight. Note, It can be out of original PixelData boundary.
356      * C) End of SubPixelData. offsetByte = B).offsetByte - dataStrideByte + dataWidthByte.
357      *
358      * srcOffset = A).offsetByte;
359      * srcSize = ( C).offsetByte - A).offsetByte );
360      */
361     const uint32_t bytePerPixel    = Pixel::GetBytesPerPixel(uploadedPixelFormat);
362     const uint32_t dataStrideByte  = (srcStride ? srcStride : pixelData->GetWidth()) * bytePerPixel;
363     const uint32_t dataXOffsetByte = params.dataXOffset * bytePerPixel;
364     const uint32_t dataWidthByte   = static_cast<uint32_t>(uploadedDataWidth) * bytePerPixel;
365
366     srcOffset = params.dataYOffset * dataStrideByte + dataXOffsetByte;
367     srcSize   = static_cast<uint32_t>(uploadedDataHeight) * dataStrideByte - (dataStrideByte - dataWidthByte);
368   }
369
370   // Update render texture value as uploaded data.
371   if(mUseUploadedParameter)
372   {
373     mWidth       = params.xOffset + uploadedDataWidth;
374     mHeight      = params.yOffset + uploadedDataHeight;
375     mPixelFormat = uploadedPixelFormat;
376   }
377
378   // Always create new graphics texture object if we use uploaded parameter as texture.
379   if(!mGraphicsTexture || mUseUploadedParameter)
380   {
381     Create(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE));
382   }
383
384   Graphics::TextureUpdateInfo info{};
385
386   info.dstTexture   = mGraphicsTexture.get();
387   info.dstOffset2D  = {params.xOffset, params.yOffset};
388   info.layer        = params.layer;
389   info.level        = params.mipmap;
390   info.srcReference = 0;
391   info.srcExtent2D  = {uploadedDataWidth, uploadedDataHeight};
392   info.srcOffset    = srcOffset;
393   info.srcSize      = srcSize;
394   info.srcStride    = srcStride;
395   info.srcFormat    = ConvertPixelFormat(uploadedPixelFormat);
396
397   mUpdatedArea = Rect<uint16_t>(params.xOffset, params.yOffset, params.width, params.height);
398
399   Graphics::TextureUpdateSourceInfo updateSourceInfo{};
400   updateSourceInfo.sourceType                = Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA;
401   updateSourceInfo.pixelDataSource.pixelData = Dali::PixelData(pixelData.Get());
402
403   mGraphicsController->UpdateTextures({info}, {updateSourceInfo});
404
405   SetUpdated(true);
406 }
407
408 bool Texture::HasAlphaChannel() const
409 {
410   bool alpha = mHasAlpha;
411   if(mNativeImage)
412   {
413     alpha = mNativeImage->RequiresBlending();
414   }
415   return alpha;
416 }
417
418 void Texture::GenerateMipmaps()
419 {
420   if(!mGraphicsTexture)
421   {
422     Create(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE));
423   }
424
425   mGraphicsController->GenerateTextureMipmaps(*mGraphicsTexture.get());
426 }
427
428 void Texture::OnRenderFinished()
429 {
430   SetUpdated(false);
431   mUpdatedArea = Rect<uint16_t>{0, 0, 0, 0};
432 }
433
434 Rect<uint16_t> Texture::GetUpdatedArea()
435 {
436   if(mNativeImage)
437   {
438     Rect<uint32_t> rect = mNativeImage->GetUpdatedArea();
439     mUpdatedArea.x      = static_cast<uint16_t>(rect.x);
440     mUpdatedArea.y      = static_cast<uint16_t>(rect.y);
441     mUpdatedArea.width  = static_cast<uint16_t>(rect.width);
442     mUpdatedArea.height = static_cast<uint16_t>(rect.height);
443   }
444   return mUpdatedArea;
445 }
446
447 } // namespace Render
448
449 } // namespace Internal
450
451 } // namespace Dali