[dali_2.3.38] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / render-texture.cpp
1 /*
2  * Copyright (c) 2024 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 #include <dali/internal/render/common/render-manager.h>
27
28 namespace Dali
29 {
30 namespace Internal
31 {
32 namespace Render
33 {
34 namespace
35 {
36 #if defined(DEBUG_ENABLED)
37 Debug::Filter* gTextureFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TEXTURE");
38 #endif
39
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()
42 {
43   static Dali::Internal::MemoryPoolObjectAllocator<Texture> gTextureMemoryPool;
44   return gTextureMemoryPool;
45 }
46
47 } //Unnamed namespace
48
49 TextureKey Texture::NewKey(Type type, Pixel::Format format, ImageDimensions size)
50 {
51   void* ptr = GetTextureMemoryPool().AllocateRawThreadSafe();
52   auto  key = GetTextureMemoryPool().GetKeyFromPtr(static_cast<Texture*>(ptr));
53   new(ptr) Texture(type, format, size);
54
55   return TextureKey(key);
56 }
57
58 TextureKey Texture::NewKey(NativeImageInterfacePtr nativeImageInterface)
59 {
60   void* ptr = GetTextureMemoryPool().AllocateRawThreadSafe();
61   auto  key = GetTextureMemoryPool().GetKeyFromPtr(static_cast<Texture*>(ptr));
62   new(ptr) Texture(nativeImageInterface);
63
64   return TextureKey(key);
65 }
66
67 TextureKey Texture::NewKey(Type type, uint32_t resourceId)
68 {
69   void* ptr = GetTextureMemoryPool().AllocateRawThreadSafe();
70   auto  key = GetTextureMemoryPool().GetKeyFromPtr(static_cast<Texture*>(ptr));
71   new(ptr) Texture(type, resourceId);
72
73   return TextureKey(key);
74 }
75
76 void Texture::ResetMemoryPool()
77 {
78   GetTextureMemoryPool().ResetMemoryPool();
79 }
80
81 Texture::Texture(Type type, Pixel::Format format, ImageDimensions size)
82 : mGraphicsController(nullptr),
83   mRenderManager(nullptr),
84   mGraphicsTexture(nullptr),
85   mNativeImage(),
86   mSampler(),
87   mPixelFormat(format),
88   mWidth(size.GetWidth()),
89   mHeight(size.GetHeight()),
90   mResourceId(0u),
91   mType(type),
92   mHasAlpha(HasAlpha(format)),
93   mUpdated(true),
94   mUseUploadedParameter(mWidth == 0u && mHeight == 0u && mPixelFormat == Pixel::INVALID)
95 {
96 }
97
98 Texture::Texture(NativeImageInterfacePtr nativeImageInterface)
99 : mGraphicsController(nullptr),
100   mRenderManager(nullptr),
101   mGraphicsTexture(nullptr),
102   mNativeImage(nativeImageInterface),
103   mSampler(),
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
107   mResourceId(0u),
108   mType(TextureType::TEXTURE_2D),
109   mHasAlpha(nativeImageInterface->RequiresBlending()),
110   mUpdated(true),
111   mUseUploadedParameter(false)
112 {
113 }
114
115 Texture::Texture(Type type, uint32_t resourceId)
116 : mGraphicsController(nullptr),
117   mRenderManager(nullptr),
118   mGraphicsTexture(nullptr),
119   mNativeImage(),
120   mSampler(),
121   mPixelFormat(Pixel::INVALID),
122   mWidth(0u),
123   mHeight(0u),
124   mResourceId(resourceId),
125   mType(type),
126   mHasAlpha(true), ///< Since we don't assume what kind of texture will be uploaded in this case.
127   mUpdated(true),
128   mUseUploadedParameter(true)
129 {
130 }
131
132 Texture::~Texture() = default;
133
134 void Texture::operator delete(void* ptr)
135 {
136   GetTextureMemoryPool().FreeThreadSafe(static_cast<Texture*>(ptr));
137 }
138
139 Render::Texture* Texture::Get(TextureKey::KeyType key)
140 {
141   return GetTextureMemoryPool().GetPtrFromKey(key);
142 }
143
144 void Texture::Initialize(Graphics::Controller& graphicsController, SceneGraph::RenderManager& renderManager)
145 {
146   mGraphicsController = &graphicsController;
147   mRenderManager      = &renderManager;
148   if(mNativeImage)
149   {
150     Create(static_cast<uint32_t>(Graphics::TextureUsageFlagBits::SAMPLE));
151   }
152
153   if(mResourceId != 0u && mGraphicsController->GetTextureFromResourceId(mResourceId))
154   {
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.
158     mResourceId = 0u;
159   }
160 }
161
162 void Texture::Destroy()
163 {
164   if(mResourceId != 0u && mGraphicsTexture.get() == nullptr)
165   {
166     // We still don't take texture ownership from controller before.
167     // Discard graphics object now.
168     mGraphicsController->DiscardTextureFromResourceId(mResourceId);
169     mResourceId = 0u;
170   }
171
172   mGraphicsTexture.reset();
173 }
174
175 Graphics::Texture* Texture::GetGraphicsObject()
176 {
177   if(mResourceId != 0u && mGraphicsTexture.get() == nullptr)
178   {
179     // The ownership of Graphics::Texture is on Graphics::Controller. Ask to controller.
180     Graphics::Texture* graphicsTexturePtr = nullptr;
181     if(mGraphicsController)
182     {
183       graphicsTexturePtr = mGraphicsController->GetTextureFromResourceId(mResourceId);
184
185       if(graphicsTexturePtr)
186       {
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();
191       }
192     }
193     DALI_LOG_INFO(gTextureFilter, Debug::General, "Render::Texture(%p)::GetGraphicsObject() = %p [with resource id : %u]\n", this, graphicsTexturePtr, mResourceId);
194
195     return graphicsTexturePtr;
196   }
197   else
198   {
199     DALI_LOG_INFO(gTextureFilter, Debug::General, "Render::Texture(%p)::GetGraphicsObject() = %p\n", this, mGraphicsTexture.get());
200
201     return mGraphicsTexture.get();
202   }
203 }
204
205 void Texture::Create(Graphics::TextureUsageFlags usage)
206 {
207   DALI_ASSERT_ALWAYS(mResourceId == 0u);
208
209   Create(usage, Graphics::TextureAllocationPolicy::CREATION);
210 }
211
212 void Texture::Create(Graphics::TextureUsageFlags usage, Graphics::TextureAllocationPolicy allocationPolicy)
213 {
214   CreateWithData(usage, allocationPolicy, nullptr, 0u);
215 }
216
217 void Texture::CreateWithData(Graphics::TextureUsageFlags usage, Graphics::TextureAllocationPolicy allocationPolicy, uint8_t* data, uint32_t size)
218 {
219   auto createInfo = Graphics::TextureCreateInfo();
220   createInfo
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)
227     .SetData(data)
228     .SetDataSize(size)
229     .SetNativeImage(mNativeImage)
230     .SetMipMapFlag(Graphics::TextureMipMapFlag::DISABLED);
231
232   mGraphicsTexture = mGraphicsController->CreateTexture(createInfo, std::move(mGraphicsTexture));
233 }
234
235 void Texture::Upload(PixelDataPtr pixelData, const Graphics::UploadParams& params)
236 {
237   DALI_ASSERT_ALWAYS(!mNativeImage);
238   DALI_ASSERT_ALWAYS(mResourceId == 0u);
239
240   const uint32_t srcStride = pixelData->GetStride();
241   uint32_t       srcOffset = 0u;
242   uint32_t       srcSize   = pixelData->GetBufferSize();
243
244   // Cache uploaded data
245   const auto uploadedDataWidth   = params.dataWidth;
246   const auto uploadedDataHeight  = params.dataHeight;
247   const auto uploadedPixelFormat = pixelData->GetPixelFormat();
248
249   const bool requiredSubPixelData = (!Pixel::IsCompressed(uploadedPixelFormat)) &&
250                                     ((params.dataXOffset != 0) ||
251                                      (params.dataYOffset != 0) ||
252                                      (uploadedDataWidth != pixelData->GetWidth()) ||
253                                      (uploadedDataHeight != pixelData->GetHeight()));
254
255   if(requiredSubPixelData)
256   {
257     /**
258      * TextureUpdateInfo use byte scaled offset / size.
259      *
260      * To make we only use sub-data of inputed PixelData, make srcOffset as 'start of SubPixelData.
261      *
262      *   |---- dataStrideByte -----|
263      *   |-----| <-- dataXOffsetByte
264      *   ...........................
265      *   ......A-----------+........
266      *   ......|           |........
267      *   ......|           |........
268      *   ......+-----------+C.......
269      *   ......B....................
270      *
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.
274      *
275      * srcOffset = A).offsetByte;
276      * srcSize = ( C).offsetByte - A).offsetByte );
277      */
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;
282
283     srcOffset = params.dataYOffset * dataStrideByte + dataXOffsetByte;
284     srcSize   = static_cast<uint32_t>(uploadedDataHeight) * dataStrideByte - (dataStrideByte - dataWidthByte);
285   }
286
287   // Update render texture value as uploaded data.
288   if(mUseUploadedParameter)
289   {
290     mWidth       = params.xOffset + uploadedDataWidth;
291     mHeight      = params.yOffset + uploadedDataHeight;
292     mPixelFormat = uploadedPixelFormat;
293   }
294
295   // Always create new graphics texture object if we use uploaded parameter as texture.
296   if(!mGraphicsTexture || mUseUploadedParameter)
297   {
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);
302   }
303
304   Graphics::TextureUpdateInfo info{};
305
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);
316
317   mUpdatedArea = Rect<uint16_t>(params.xOffset, params.yOffset, params.width, params.height);
318
319   Graphics::TextureUpdateSourceInfo updateSourceInfo{};
320   updateSourceInfo.sourceType                = Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA;
321   updateSourceInfo.pixelDataSource.pixelData = Dali::PixelData(pixelData.Get());
322
323   mGraphicsController->UpdateTextures({info}, {updateSourceInfo});
324
325   SetUpdated(true);
326 }
327
328 bool Texture::HasAlphaChannel() const
329 {
330   bool alpha = mHasAlpha;
331   if(mNativeImage)
332   {
333     alpha = mNativeImage->RequiresBlending();
334   }
335   return alpha;
336 }
337
338 bool Texture::IsGraphicsObjectChanged()
339 {
340   return mLatestUsedGraphicsTexture != GetGraphicsObject();
341 }
342
343 void Texture::NotifyTextureUpdated()
344 {
345   if(mRenderManager)
346   {
347     mRenderManager->SetTextureUpdated(TextureKey(GetTextureMemoryPool().GetKeyFromPtr(this)));
348   }
349 }
350
351 void Texture::GenerateMipmaps()
352 {
353   DALI_ASSERT_ALWAYS(mResourceId == 0u);
354
355   // Compressed pixel doesn't support mipmap generation.
356   if(Pixel::IsCompressed(mPixelFormat))
357   {
358     return;
359   }
360
361   if(!mGraphicsTexture)
362   {
363     Create(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE));
364   }
365
366   mGraphicsController->GenerateTextureMipmaps(*mGraphicsTexture.get());
367 }
368
369 void Texture::OnRenderFinished()
370 {
371   SetUpdated(false);
372
373   if(mResourceId != 0u)
374   {
375     mLatestUsedGraphicsTexture = GetGraphicsObject();
376     if(mLatestUsedGraphicsTexture != nullptr)
377     {
378       // We don't need to keep mResourceId anymore.
379       mResourceId = 0u;
380     }
381   }
382
383   mUpdatedArea = Rect<uint16_t>{0, 0, 0, 0};
384 }
385
386 Rect<uint16_t> Texture::GetUpdatedArea()
387 {
388   if(mNativeImage)
389   {
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);
395   }
396   return mUpdatedArea;
397 }
398
399 } // namespace Render
400
401 } // namespace Internal
402
403 } // namespace Dali