Merge branch 'devel/master' into devel/graphics
[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-shader.h>
26 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
27 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
28 #include <dali/public-api/common/dali-common.h>
29 #include "gles-graphics-program.h"
30
31 namespace Dali::Graphics
32 {
33 namespace
34 {
35 /**
36  * @brief Custom deleter for all Graphics objects created
37  * with use of the Controller.
38  *
39  * When Graphics object dies the unique pointer (Graphics::UniquePtr)
40  * doesn't destroy it directly but passes the ownership back
41  * to the Controller. The GLESDeleter is responsible for passing
42  * the object to the discard queue (by calling Resource::DiscardResource()).
43  */
44 template<typename T>
45 struct GLESDeleter
46 {
47   GLESDeleter() = default;
48
49   void operator()(T* object)
50   {
51     // Discard resource (add it to discard queue)
52     object->DiscardResource();
53   }
54 };
55
56 /**
57  * @brief Helper function allocating graphics object
58  *
59  * @param[in] info Create info structure
60  * @param[in] controller Controller object
61  * @param[out] out Unique pointer to the return object
62  */
63 template<class GLESType, class GfxCreateInfo, class T>
64 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
65 {
66   // Use allocator
67   using Type = typename T::element_type;
68   using UPtr = Graphics::UniquePtr<Type>;
69   if(info.allocationCallbacks)
70   {
71     auto* memory = info.allocationCallbacks->allocCallback(
72       sizeof(GLESType),
73       0,
74       info.allocationCallbacks->userData);
75     return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
76   }
77   else // Use standard allocator
78   {
79     return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
80   }
81 }
82
83 template<class T0, class T1>
84 T0* CastObject(T1* apiObject)
85 {
86   return static_cast<T0*>(apiObject);
87 }
88
89 } // namespace
90
91 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
92 {
93   mGlAbstraction = &glAbstraction;
94   mContext       = std::make_unique<GLES::Context>(*this);
95 }
96
97 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction&          glSyncAbstraction,
98                                        Integration::GlContextHelperAbstraction& glContextHelperAbstraction)
99 {
100   mGlSyncAbstraction          = &glSyncAbstraction;
101   mGlContextHelperAbstraction = &glContextHelperAbstraction;
102 }
103
104 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
105 {
106   for(auto& cmdbuf : submitInfo.cmdBuffer)
107   {
108     // Push command buffers
109     mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
110   }
111
112   // If flush bit set, flush all pending tasks
113   if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
114   {
115     Flush();
116   }
117 }
118
119 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
120 {
121   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
122   return *mGlAbstraction;
123 }
124
125 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
126 {
127   DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
128   return *mGlSyncAbstraction;
129 }
130
131 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
132 {
133   DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
134   return *mGlContextHelperAbstraction;
135 }
136
137 Graphics::UniquePtr<CommandBuffer>
138 EglGraphicsController::CreateCommandBuffer(const CommandBufferCreateInfo&       commandBufferCreateInfo,
139                                            Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
140 {
141   return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
142 }
143
144 Graphics::UniquePtr<Texture>
145 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
146 {
147   return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
148 }
149
150 Graphics::UniquePtr<Buffer>
151 EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
152 {
153   return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
154 }
155
156 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
157 {
158   // Create pipeline cache if needed
159   if(!mPipelineCache)
160   {
161     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
162   }
163
164   return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
165 }
166
167 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
168 {
169   // Create program cache if needed
170   if(!mPipelineCache)
171   {
172     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
173   }
174
175   return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
176 }
177
178 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
179 {
180   return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
181 }
182
183 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
184 {
185   return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
186 }
187
188 void EglGraphicsController::AddTexture(GLES::Texture& texture)
189 {
190   // Assuming we are on the correct context
191   mCreateTextureQueue.push(&texture);
192 }
193
194 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
195 {
196   // Assuming we are on the correct context
197   mCreateBufferQueue.push(&buffer);
198 }
199
200 void EglGraphicsController::ProcessDiscardQueues()
201 {
202   // Process textures
203   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
204
205   // Process buffers
206   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
207
208   // Process pipelines
209   ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
210
211   // Process programs
212   ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
213 }
214
215 void EglGraphicsController::ProcessCreateQueues()
216 {
217   // Process textures
218   ProcessCreateQueue(mCreateTextureQueue);
219
220   // Process buffers
221   ProcessCreateQueue(mCreateBufferQueue);
222 }
223
224 void EglGraphicsController::ProcessCommandQueues()
225 {
226   // TODO: command queue per context, sync between queues should be
227   // done externally
228
229   while(!mCommandQueue.empty())
230   {
231     auto cmdBuf = mCommandQueue.front();
232     mCommandQueue.pop();
233
234     for(auto& cmd : cmdBuf->GetCommands())
235     {
236       // process command
237       switch(cmd.type)
238       {
239         case GLES::CommandType::FLUSH:
240         {
241           // Nothing to do here
242           break;
243         }
244         case GLES::CommandType::BIND_TEXTURES:
245         {
246           mContext->BindTextures(cmd.bindTextures.textureBindings);
247           break;
248         }
249         case GLES::CommandType::BIND_VERTEX_BUFFERS:
250         {
251           auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
252           mContext->BindVertexBuffers(bindings);
253           break;
254         }
255         case GLES::CommandType::BIND_INDEX_BUFFER:
256         {
257           mContext->BindIndexBuffer(cmd.bindIndexBuffer);
258           break;
259         }
260         case GLES::CommandType::BIND_SAMPLERS:
261         {
262           break;
263         }
264         case GLES::CommandType::BIND_PIPELINE:
265         {
266           mContext->BindPipeline(cmd.bindPipeline.pipeline);
267           break;
268         }
269         case GLES::CommandType::DRAW:
270         {
271           mContext->Flush(false, cmd.draw);
272           break;
273         }
274         case GLES::CommandType::DRAW_INDEXED:
275         {
276           mContext->Flush(false, cmd.draw);
277           break;
278         }
279         case GLES::CommandType::DRAW_INDEXED_INDIRECT:
280         {
281           mContext->Flush(false, cmd.draw);
282           break;
283         }
284       }
285     }
286   }
287 }
288
289 void EglGraphicsController::ProcessTextureUpdateQueue()
290 {
291   while(!mTextureUpdateRequests.empty())
292   {
293     TextureUpdateRequest& request = mTextureUpdateRequests.front();
294
295     auto& info   = request.first;
296     auto& source = request.second;
297
298     if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
299     {
300       // GPU memory must be already allocated (glTexImage2D())
301       auto*       texture    = static_cast<GLES::Texture*>(info.dstTexture);
302       const auto& createInfo = texture->GetCreateInfo();
303
304       mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
305
306       mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
307       mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
308                                     info.level,
309                                     info.dstOffset2D.x,
310                                     info.dstOffset2D.y,
311                                     info.srcExtent2D.width,
312                                     info.srcExtent2D.height,
313                                     GLES::GLTextureFormatType(createInfo.format).format,
314                                     GLES::GLTextureFormatType(createInfo.format).type,
315                                     source.memorySource.memory);
316
317       // free staging memory
318       free(source.memorySource.memory);
319     }
320     else
321     {
322       // TODO: other sources
323     }
324
325     mTextureUpdateRequests.pop();
326   }
327 }
328
329 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
330                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
331 {
332   // Store updates
333   for(auto& info : updateInfoList)
334   {
335     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
336     auto& pair = mTextureUpdateRequests.back();
337     switch(pair.second.sourceType)
338     {
339       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
340       {
341         auto& info   = pair.first;
342         auto& source = pair.second;
343
344         // allocate staging memory and copy the data
345         // TODO: using PBO with GLES3, this is just naive
346         // oldschool way
347
348         char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
349         std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
350                   reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
351                   stagingBuffer);
352
353         // store staging buffer
354         source.memorySource.memory = stagingBuffer;
355         break;
356       }
357       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
358       {
359         // TODO, with PBO support
360         break;
361       }
362       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
363       {
364         // TODO texture 2 texture in-GPU copy
365         break;
366       }
367     }
368   }
369 }
370
371 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
372 {
373   // Mapping buffer requires the object to be created NOW
374   // Workaround - flush now, otherwise there will be given a staging buffer
375   // in case when the buffer is not there yet
376   ProcessCreateQueues();
377
378   return Graphics::UniquePtr<Memory>(new GLES::Memory(mapInfo, *this));
379 }
380
381 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
382 {
383   return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
384 }
385
386 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
387 {
388   return *mPipelineCache;
389 }
390
391 } // namespace Dali::Graphics