[Tizen] Create Texture by ResourceId + Set Texture size and format internally.
[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 #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 MemoryPoolObjectAllocator<Texture>& GetTextureMemoryPool()
42 {
43   static 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 Texture::Texture(Type type, Pixel::Format format, ImageDimensions size)
77 : mGraphicsController(nullptr),
78   mGraphicsTexture(nullptr),
79   mNativeImage(),
80   mSampler(),
81   mPixelFormat(format),
82   mWidth(size.GetWidth()),
83   mHeight(size.GetHeight()),
84   mResourceId(0u),
85   mType(type),
86   mHasAlpha(HasAlpha(format)),
87   mUpdated(true),
88   mUseUploadedParameter(mWidth == 0u && mHeight == 0u && mPixelFormat == Pixel::INVALID)
89 {
90 }
91
92 Texture::Texture(NativeImageInterfacePtr nativeImageInterface)
93 : mGraphicsController(nullptr),
94   mGraphicsTexture(nullptr),
95   mNativeImage(nativeImageInterface),
96   mSampler(),
97   mPixelFormat(Pixel::RGBA8888),
98   mWidth(static_cast<uint16_t>(nativeImageInterface->GetWidth())),   // ignoring overflow, not happening in practice
99   mHeight(static_cast<uint16_t>(nativeImageInterface->GetHeight())), // ignoring overflow, not happening in practice
100   mResourceId(0u),
101   mType(TextureType::TEXTURE_2D),
102   mHasAlpha(nativeImageInterface->RequiresBlending()),
103   mUpdated(true),
104   mUseUploadedParameter(false)
105 {
106 }
107
108 Texture::Texture(Type type, uint32_t resourceId)
109 : mGraphicsController(nullptr),
110   mGraphicsTexture(nullptr),
111   mNativeImage(),
112   mSampler(),
113   mPixelFormat(Pixel::INVALID),
114   mWidth(0u),
115   mHeight(0u),
116   mResourceId(resourceId),
117   mType(type),
118   mHasAlpha(true), ///< Since we don't assume what kind of texture will be uploaded in this case.
119   mUpdated(true),
120   mUseUploadedParameter(true)
121 {
122 }
123
124 Texture::~Texture() = default;
125
126 void Texture::operator delete(void* ptr)
127 {
128   GetTextureMemoryPool().FreeThreadSafe(static_cast<Texture*>(ptr));
129 }
130
131 Render::Texture* Texture::Get(TextureKey::KeyType key)
132 {
133   return GetTextureMemoryPool().GetPtrFromKey(key);
134 }
135
136 void Texture::Initialize(Graphics::Controller& graphicsController, SceneGraph::RenderManager& renderManager)
137 {
138   mGraphicsController = &graphicsController;
139   mRenderManager      = &renderManager;
140   if(mNativeImage)
141   {
142     Create(static_cast<uint32_t>(Graphics::TextureUsageFlagBits::SAMPLE));
143   }
144
145   if(mResourceId != 0u && mGraphicsController->GetTextureFromResourceId(mResourceId))
146   {
147     // Take ownership from graphics controller
148     mGraphicsTexture = std::move(mGraphicsController->ReleaseTextureFromResourceId(mResourceId));
149     // Now we take on the Graphics::Texture ownership. We don't need to keep mResourceId anymore.
150     mResourceId = 0u;
151   }
152 }
153
154 void Texture::Destroy()
155 {
156   if(mResourceId != 0u && mGraphicsTexture.get() == nullptr)
157   {
158     // We still don't take texture ownership from controller before.
159     // Discard graphics object now.
160     mGraphicsController->DiscardTextureFromResourceId(mResourceId);
161     mResourceId = 0u;
162   }
163
164   mGraphicsTexture.reset();
165 }
166
167 Graphics::Texture* Texture::GetGraphicsObject()
168 {
169   if(mResourceId != 0u && mGraphicsTexture.get() == nullptr)
170   {
171     // The ownership of Graphics::Texture is on Graphics::Controller. Ask to controller.
172     Graphics::Texture* graphicsTexturePtr = nullptr;
173     if(mGraphicsController)
174     {
175       graphicsTexturePtr = mGraphicsController->GetTextureFromResourceId(mResourceId);
176
177       if(graphicsTexturePtr)
178       {
179         // Take ownership from graphics controller
180         mGraphicsTexture = std::move(mGraphicsController->ReleaseTextureFromResourceId(mResourceId));
181         // (Partial update) Do not make mResourceId as 0 until we update mLatestUsedGraphicsTexture.
182       }
183     }
184     DALI_LOG_INFO(gTextureFilter, Debug::General, "SC::Texture(%p)::GetGraphicsObject() = %p [with resource id : %u]\n", this, graphicsTexturePtr, mResourceId);
185
186     return graphicsTexturePtr;
187   }
188   else
189   {
190     DALI_LOG_INFO(gTextureFilter, Debug::General, "SC::Texture(%p)::GetGraphicsObject() = %p\n", this, mGraphicsTexture.get());
191
192     return mGraphicsTexture.get();
193   }
194 }
195
196 void Texture::Create(Graphics::TextureUsageFlags usage)
197 {
198   CreateWithData(usage, nullptr, 0u);
199 }
200
201 void Texture::CreateWithData(Graphics::TextureUsageFlags usage, uint8_t* data, uint32_t size)
202 {
203   auto createInfo = Graphics::TextureCreateInfo();
204   createInfo
205     .SetTextureType(Dali::Graphics::ConvertTextureType(mType))
206     .SetUsageFlags(usage)
207     .SetFormat(Dali::Graphics::ConvertPixelFormat(mPixelFormat))
208     .SetSize({mWidth, mHeight})
209     .SetLayout(Graphics::TextureLayout::LINEAR)
210     .SetData(data)
211     .SetDataSize(size)
212     .SetNativeImage(mNativeImage)
213     .SetMipMapFlag(Graphics::TextureMipMapFlag::DISABLED);
214
215   mGraphicsTexture = mGraphicsController->CreateTexture(createInfo, std::move(mGraphicsTexture));
216 }
217
218 void Texture::Upload(PixelDataPtr pixelData, const Graphics::UploadParams& params)
219 {
220   DALI_ASSERT_ALWAYS(!mNativeImage);
221   DALI_ASSERT_ALWAYS(mResourceId == 0u);
222
223   const uint32_t srcStride = pixelData->GetStride();
224   uint32_t       srcOffset = 0u;
225   uint32_t       srcSize   = pixelData->GetBufferSize();
226
227   // Cache uploaded data
228   const auto uploadedDataWidth   = params.dataWidth;
229   const auto uploadedDataHeight  = params.dataHeight;
230   const auto uploadedPixelFormat = pixelData->GetPixelFormat();
231
232   const bool requiredSubPixelData = (!Pixel::IsCompressed(uploadedPixelFormat)) &&
233                                     ((params.dataXOffset != 0) ||
234                                      (params.dataYOffset != 0) ||
235                                      (uploadedDataWidth != pixelData->GetWidth()) ||
236                                      (uploadedDataHeight != pixelData->GetHeight()));
237
238   if(requiredSubPixelData)
239   {
240     /**
241      * TextureUpdateInfo use byte scaled offset / size.
242      *
243      * To make we only use sub-data of inputed PixelData, make srcOffset as 'start of SubPixelData.
244      *
245      *   |---- dataStrideByte -----|
246      *   |-----| <-- dataXOffsetByte
247      *   ...........................
248      *   ......A-----------+........
249      *   ......|           |........
250      *   ......|           |........
251      *   ......+-----------+C.......
252      *   ......B....................
253      *
254      * A) Start of SubPixelData. offsetByte = dataStrideByte * dataYOffset + dataXOffsetByte.
255      * B) offsetByte = A).offsetByte + dataStrideByte * dataHeight. Note, It can be out of original PixelData boundary.
256      * C) End of SubPixelData. offsetByte = B).offsetByte - dataStrideByte + dataWidthByte.
257      *
258      * srcOffset = A).offsetByte;
259      * srcSize = ( C).offsetByte - A).offsetByte );
260      */
261     const uint32_t bytePerPixel    = Pixel::GetBytesPerPixel(uploadedPixelFormat);
262     const uint32_t dataStrideByte  = (srcStride ? srcStride : pixelData->GetWidth()) * bytePerPixel;
263     const uint32_t dataXOffsetByte = params.dataXOffset * bytePerPixel;
264     const uint32_t dataWidthByte   = static_cast<uint32_t>(uploadedDataWidth) * bytePerPixel;
265
266     srcOffset = params.dataYOffset * dataStrideByte + dataXOffsetByte;
267     srcSize   = static_cast<uint32_t>(uploadedDataHeight) * dataStrideByte - (dataStrideByte - dataWidthByte);
268   }
269
270   // Update render texture value as uploaded data.
271   if(mUseUploadedParameter)
272   {
273     mWidth       = params.xOffset + uploadedDataWidth;
274     mHeight      = params.yOffset + uploadedDataHeight;
275     mPixelFormat = uploadedPixelFormat;
276   }
277
278   // Always create new graphics texture object if we use uploaded parameter as texture.
279   if(!mGraphicsTexture || mUseUploadedParameter)
280   {
281     Create(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE));
282   }
283
284   Graphics::TextureUpdateInfo info{};
285
286   info.dstTexture   = mGraphicsTexture.get();
287   info.dstOffset2D  = {params.xOffset, params.yOffset};
288   info.layer        = params.layer;
289   info.level        = params.mipmap;
290   info.srcReference = 0;
291   info.srcExtent2D  = {uploadedDataWidth, uploadedDataHeight};
292   info.srcOffset    = srcOffset;
293   info.srcSize      = srcSize;
294   info.srcStride    = srcStride;
295   info.srcFormat    = Dali::Graphics::ConvertPixelFormat(uploadedPixelFormat);
296
297   mUpdatedArea = Rect<uint16_t>(params.xOffset, params.yOffset, params.width, params.height);
298
299   Graphics::TextureUpdateSourceInfo updateSourceInfo{};
300   updateSourceInfo.sourceType                = Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA;
301   updateSourceInfo.pixelDataSource.pixelData = Dali::PixelData(pixelData.Get());
302
303   mGraphicsController->UpdateTextures({info}, {updateSourceInfo});
304
305   SetUpdated(true);
306 }
307
308 bool Texture::HasAlphaChannel() const
309 {
310   bool alpha = mHasAlpha;
311   if(mNativeImage)
312   {
313     alpha = mNativeImage->RequiresBlending();
314   }
315   return alpha;
316 }
317
318 bool Texture::IsGraphicsObjectChanged()
319 {
320   return mLatestUsedGraphicsTexture != GetGraphicsObject();
321 }
322
323 void Texture::NotifyTextureUpdated()
324 {
325   if(mRenderManager)
326   {
327     mRenderManager->SetTextureUpdated(TextureKey(GetTextureMemoryPool().GetKeyFromPtr(this)));
328   }
329 }
330
331 void Texture::GenerateMipmaps()
332 {
333   if(!mGraphicsTexture)
334   {
335     Create(static_cast<Graphics::TextureUsageFlags>(Graphics::TextureUsageFlagBits::SAMPLE));
336   }
337
338   mGraphicsController->GenerateTextureMipmaps(*mGraphicsTexture.get());
339 }
340
341 void Texture::OnRenderFinished()
342 {
343   SetUpdated(false);
344
345   if(mResourceId != 0u)
346   {
347     mLatestUsedGraphicsTexture = GetGraphicsObject();
348     if(mLatestUsedGraphicsTexture != nullptr)
349     {
350       // We don't need to keep mResourceId anymore.
351       mResourceId = 0u;
352     }
353   }
354
355   mUpdatedArea = Rect<uint16_t>{0, 0, 0, 0};
356 }
357
358 Rect<uint16_t> Texture::GetUpdatedArea()
359 {
360   if(mNativeImage)
361   {
362     Rect<uint32_t> rect = mNativeImage->GetUpdatedArea();
363     mUpdatedArea.x      = static_cast<uint16_t>(rect.x);
364     mUpdatedArea.y      = static_cast<uint16_t>(rect.y);
365     mUpdatedArea.width  = static_cast<uint16_t>(rect.width);
366     mUpdatedArea.height = static_cast<uint16_t>(rect.height);
367   }
368   return mUpdatedArea;
369 }
370
371 } // namespace Render
372
373 } // namespace Internal
374
375 } // namespace Dali