GLES Pipeline and draw call support
[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-pipeline.h>
25 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
26 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
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   mContext       = std::make_unique<GLES::Context>(*this);
93 }
94
95 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction&          glSyncAbstraction,
96                                        Integration::GlContextHelperAbstraction& glContextHelperAbstraction)
97 {
98   mGlSyncAbstraction          = &glSyncAbstraction;
99   mGlContextHelperAbstraction = &glContextHelperAbstraction;
100 }
101
102 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
103 {
104   for(auto& cmdbuf : submitInfo.cmdBuffer)
105   {
106     // Push command buffers
107     mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
108   }
109
110   // If flush bit set, flush all pending tasks
111   if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
112   {
113     Flush();
114   }
115 }
116
117 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
118 {
119   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
120   return *mGlAbstraction;
121 }
122
123 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
124 {
125   DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
126   return *mGlSyncAbstraction;
127 }
128
129 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
130 {
131   DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
132   return *mGlContextHelperAbstraction;
133 }
134
135 Graphics::UniquePtr<CommandBuffer>
136 EglGraphicsController::CreateCommandBuffer(const CommandBufferCreateInfo&       commandBufferCreateInfo,
137                                            Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
138 {
139   return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
140 }
141
142 Graphics::UniquePtr<Texture>
143 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
144 {
145   return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
146 }
147
148 Graphics::UniquePtr<Buffer>
149 EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
150 {
151   return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
152 }
153
154 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Pipeline>&& oldPipeline)
155 {
156   return NewObject<GLES::Pipeline>(pipelineCreateInfo, *this, std::move(oldPipeline));
157 }
158
159 void EglGraphicsController::AddTexture(GLES::Texture& texture)
160 {
161   // Assuming we are on the correct context
162   mCreateTextureQueue.push(&texture);
163 }
164
165 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
166 {
167   // Assuming we are on the correct context
168   mCreateBufferQueue.push(&buffer);
169 }
170
171 void EglGraphicsController::ProcessDiscardQueues()
172 {
173   // Process textures
174   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
175
176   // Process buffers
177   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
178 }
179
180 void EglGraphicsController::ProcessCreateQueues()
181 {
182   // Process textures
183   ProcessCreateQueue(mCreateTextureQueue);
184
185   // Process buffers
186   ProcessCreateQueue(mCreateBufferQueue);
187 }
188
189 void EglGraphicsController::ProcessCommandQueues()
190 {
191   // TODO: command queue per context, sync between queues should be
192   // done externally
193
194   while(!mCommandQueue.empty())
195   {
196     auto cmdBuf = mCommandQueue.front();
197     mCommandQueue.pop();
198
199     for(auto& cmd : cmdBuf->GetCommands())
200     {
201       // process command
202       switch(cmd.type)
203       {
204         case GLES::CommandType::FLUSH:
205         {
206           // Nothing to do here
207           break;
208         }
209         case GLES::CommandType::BIND_TEXTURES:
210         {
211           mContext->BindTextures(cmd.bindTextures.textureBindings);
212           break;
213         }
214         case GLES::CommandType::BIND_VERTEX_BUFFERS:
215         {
216           auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
217           mContext->BindVertexBuffers(bindings);
218           break;
219         }
220         case GLES::CommandType::BIND_INDEX_BUFFER:
221         {
222           mContext->BindIndexBuffer(cmd.bindIndexBuffer);
223           break;
224         }
225         case GLES::CommandType::BIND_SAMPLERS:
226         {
227           break;
228         }
229         case GLES::CommandType::BIND_PIPELINE:
230         {
231           mContext->BindPipeline(cmd.bindPipeline.pipeline);
232           break;
233         }
234         case GLES::CommandType::DRAW:
235         {
236           mContext->Flush(false, cmd.draw);
237           break;
238         }
239         case GLES::CommandType::DRAW_INDEXED:
240         {
241           mContext->Flush(false, cmd.draw);
242           break;
243         }
244         case GLES::CommandType::DRAW_INDEXED_INDIRECT:
245         {
246           mContext->Flush(false, cmd.draw);
247           break;
248         }
249       }
250     }
251   }
252 }
253
254 void EglGraphicsController::ProcessTextureUpdateQueue()
255 {
256   while(!mTextureUpdateRequests.empty())
257   {
258     TextureUpdateRequest& request = mTextureUpdateRequests.front();
259
260     auto& info   = request.first;
261     auto& source = request.second;
262
263     if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
264     {
265       // GPU memory must be already allocated (glTexImage2D())
266       auto*       texture    = static_cast<GLES::Texture*>(info.dstTexture);
267       const auto& createInfo = texture->GetCreateInfo();
268
269       mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
270       mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
271                                     info.level,
272                                     info.dstOffset2D.x,
273                                     info.dstOffset2D.y,
274                                     info.srcExtent2D.width,
275                                     info.srcExtent2D.height,
276                                     GLES::GLTextureFormatType(createInfo.format).format,
277                                     GLES::GLTextureFormatType(createInfo.format).type,
278                                     source.memorySource.memory);
279
280       // free staging memory
281       free(source.memorySource.memory);
282     }
283     else
284     {
285       // TODO: other sources
286     }
287
288     mTextureUpdateRequests.pop();
289   }
290 }
291
292 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
293                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
294 {
295   // Store updates
296   for(auto& info : updateInfoList)
297   {
298     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
299     auto& pair = mTextureUpdateRequests.back();
300     switch(pair.second.sourceType)
301     {
302       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
303       {
304         auto& info   = pair.first;
305         auto& source = pair.second;
306
307         // allocate staging memory and copy the data
308         // TODO: using PBO with GLES3, this is just naive
309         // oldschool way
310
311         char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
312         std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
313                   reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
314                   stagingBuffer);
315
316         // store staging buffer
317         source.memorySource.memory = stagingBuffer;
318         break;
319       }
320       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
321       {
322         // TODO, with PBO support
323         break;
324       }
325       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
326       {
327         // TODO texture 2 texture in-GPU copy
328         break;
329       }
330     }
331   }
332 }
333
334 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
335 {
336   // Mapping buffer requires the object to be created NOW
337   // Workaround - flush now, otherwise there will be given a staging buffer
338   // in case when the buffer is not there yet
339   ProcessCreateQueues();
340
341   return Graphics::UniquePtr<Memory>(new GLES::Memory(mapInfo, *this));
342 }
343
344 } // namespace Dali::Graphics