GLES Texture and Buffer naive implementation
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / egl-graphics-controller.cpp
1 /*
2  * Copyright (c) 2021 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/graphics/gles-impl/egl-graphics-controller.h>
19
20 // INTERNAL INCLUDES
21 #include <dali/integration-api/gl-abstraction.h>
22 #include <dali/integration-api/gl-defines.h>
23 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
24 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
25 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
26
27 #include <dali/public-api/common/dali-common.h>
28
29 namespace Dali::Graphics
30 {
31 namespace
32 {
33 /**
34  * @brief Custom deleter for all Graphics objects created
35  * with use of the Controller.
36  *
37  * When Graphics object dies the unique pointer (Graphics::UniquePtr)
38  * doesn't destroy it directly but passes the ownership back
39  * to the Controller. The GLESDeleter is responsible for passing
40  * the object to the discard queue (by calling Resource::DiscardResource()).
41  */
42 template<typename T>
43 struct GLESDeleter
44 {
45   GLESDeleter() = default;
46
47   void operator()(T* object)
48   {
49     // Discard resource (add it to discard queue)
50     object->DiscardResource();
51   }
52 };
53
54 /**
55  * @brief Helper function allocating graphics object
56  *
57  * @param[in] info Create info structure
58  * @param[in] controller Controller object
59  * @param[out] out Unique pointer to the return object
60  */
61 template<class GLESType, class GfxCreateInfo, class T>
62 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
63 {
64   // Use allocator
65   using Type = typename T::element_type;
66   using UPtr = Graphics::UniquePtr<Type>;
67   if(info.allocationCallbacks)
68   {
69     auto* memory = info.allocationCallbacks->allocCallback(
70       sizeof(GLESType),
71       0,
72       info.allocationCallbacks->userData);
73     return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
74   }
75   else // Use standard allocator
76   {
77     return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
78   }
79 }
80
81 template<class T0, class T1>
82 T0* CastObject(T1* apiObject)
83 {
84   return static_cast<T0*>(apiObject);
85 }
86
87 } // namespace
88
89 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
90 {
91   mGlAbstraction = &glAbstraction;
92 }
93
94 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction&          glSyncAbstraction,
95                                        Integration::GlContextHelperAbstraction& glContextHelperAbstraction)
96 {
97   mGlSyncAbstraction          = &glSyncAbstraction;
98   mGlContextHelperAbstraction = &glContextHelperAbstraction;
99 }
100
101 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
102 {
103   for(auto& cmdbuf : submitInfo.cmdBuffer)
104   {
105     // Push command buffers
106     mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
107   }
108
109   // If flush bit set, flush all pending tasks
110   if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
111   {
112     Flush();
113   }
114 }
115
116 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
117 {
118   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
119   return *mGlAbstraction;
120 }
121
122 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
123 {
124   DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
125   return *mGlSyncAbstraction;
126 }
127
128 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
129 {
130   DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
131   return *mGlContextHelperAbstraction;
132 }
133
134 Graphics::UniquePtr<CommandBuffer>
135 EglGraphicsController::CreateCommandBuffer(const CommandBufferCreateInfo&       commandBufferCreateInfo,
136                                            Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
137 {
138   return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
139 }
140
141 Graphics::UniquePtr<Texture>
142 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
143 {
144   return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
145 }
146
147 Graphics::UniquePtr<Buffer>
148 EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
149 {
150   return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
151 }
152
153 void EglGraphicsController::AddTexture(GLES::Texture& texture)
154 {
155   // Assuming we are on the correct context
156   mCreateTextureQueue.push(&texture);
157 }
158
159 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
160 {
161   // Assuming we are on the correct context
162   mCreateBufferQueue.push(&buffer);
163 }
164
165 void EglGraphicsController::ProcessDiscardQueues()
166 {
167   // Process textures
168   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
169
170   // Process buffers
171   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
172 }
173
174 void EglGraphicsController::ProcessCreateQueues()
175 {
176   // Process textures
177   ProcessCreateQueue(mCreateTextureQueue);
178
179   // Process buffers
180   ProcessCreateQueue(mCreateBufferQueue);
181 }
182
183 void EglGraphicsController::ProcessCommandQueues()
184 {
185   while(!mCommandQueue.empty())
186   {
187     auto cmdBuf = mCommandQueue.front();
188     mCommandQueue.pop();
189
190     for(auto& cmd : cmdBuf->GetCommands())
191     {
192       // process command
193       switch(cmd.type)
194       {
195         case GLES::CommandType::FLUSH:
196         {
197           break;
198         }
199
200           // Bind textures
201         case GLES::CommandType::BIND_TEXTURES:
202         {
203           for(auto& binding : cmd.bindTextures.textureBindings)
204           {
205             static_cast<const GLES::Texture*>(binding.texture)->Bind(binding);
206           }
207           break;
208         }
209
210         case GLES::CommandType::BIND_VERTEX_BUFFERS:
211         {
212           auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
213           auto  index    = 0u;
214           for(auto& binding : bindings)
215           {
216             // TODO: this is all wrong, just hack to work with current DALi
217             if(binding.buffer)
218             {
219               CastObject<const GLES::Buffer>(binding.buffer)->Bind(BufferUsage::VERTEX_BUFFER);
220               index++;
221             }
222           }
223
224           break;
225         }
226         case GLES::CommandType::BIND_INDEX_BUFFER:
227         {
228           auto buffer = static_cast<const GLES::Buffer*>(cmd.bindIndexBuffer.buffer);
229           buffer->Bind(BufferUsage::INDEX_BUFFER);
230           break;
231         }
232         case GLES::CommandType::BIND_SAMPLERS:
233         {
234           break;
235         }
236       }
237     }
238   }
239 }
240
241 void EglGraphicsController::ProcessTextureUpdateQueue()
242 {
243   while(!mTextureUpdateRequests.empty())
244   {
245     TextureUpdateRequest& request = mTextureUpdateRequests.front();
246
247     auto& info   = request.first;
248     auto& source = request.second;
249
250     if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
251     {
252       // GPU memory must be already allocated (glTexImage2D())
253       auto*       texture    = static_cast<GLES::Texture*>(info.dstTexture);
254       const auto& createInfo = texture->GetCreateInfo();
255
256       mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
257       mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
258                                     info.level,
259                                     info.dstOffset2D.x,
260                                     info.dstOffset2D.y,
261                                     info.srcExtent2D.width,
262                                     info.srcExtent2D.height,
263                                     GLES::GLTextureFormatType(createInfo.format).format,
264                                     GLES::GLTextureFormatType(createInfo.format).type,
265                                     source.memorySource.memory);
266
267       // free staging memory
268       free(source.memorySource.memory);
269     }
270     else
271     {
272       // TODO: other sources
273     }
274
275     mTextureUpdateRequests.pop();
276   }
277 }
278
279 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
280                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
281 {
282   // Store updates
283   for(auto& info : updateInfoList)
284   {
285     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
286     auto& pair = mTextureUpdateRequests.back();
287     switch(pair.second.sourceType)
288     {
289       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
290       {
291         auto& info   = pair.first;
292         auto& source = pair.second;
293
294         // allocate staging memory and copy the data
295         // TODO: using PBO with GLES3, this is just naive
296         // oldschool way
297
298         char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
299         std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
300                   reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
301                   stagingBuffer);
302
303         // store staging buffer
304         source.memorySource.memory = stagingBuffer;
305
306         printf("Update ptr: %p\n", source.memorySource.memory);
307         break;
308       }
309       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
310       {
311         // TODO, with PBO support
312         break;
313       }
314       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
315       {
316         // TODO texture 2 texture in-GPU copy
317         break;
318       }
319     }
320   }
321 }
322
323 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
324 {
325   // Mapping buffer requires the object to be created NOW
326   // Workaround - flush now, otherwise there will be given a staging buffer
327   // in case when the buffer is not there yet
328   ProcessCreateQueues();
329
330   return Graphics::UniquePtr<Memory>(new GLES::Memory(mapInfo, *this));
331 }
332
333 } // namespace Dali::Graphics