Multiple context 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/debug.h>
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/gl-defines.h>
24 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
25 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
26 #include <dali/internal/graphics/gles-impl/gles-graphics-render-pass.h>
27 #include <dali/internal/graphics/gles-impl/gles-graphics-render-target.h>
28 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
29 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
30 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
31 #include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
32 #include <dali/public-api/common/dali-common.h>
33 #include "gles-graphics-program.h"
34
35 namespace Dali::Graphics
36 {
37 namespace
38 {
39 /**
40  * @brief Custom deleter for all Graphics objects created
41  * with use of the Controller.
42  *
43  * When Graphics object dies the unique pointer (Graphics::UniquePtr)
44  * doesn't destroy it directly but passes the ownership back
45  * to the Controller. The GLESDeleter is responsible for passing
46  * the object to the discard queue (by calling Resource::DiscardResource()).
47  */
48 template<typename T>
49 struct GLESDeleter
50 {
51   GLESDeleter() = default;
52
53   void operator()(T* object)
54   {
55     // Discard resource (add it to discard queue)
56     object->DiscardResource();
57   }
58 };
59
60 /**
61  * @brief Helper function allocating graphics object
62  *
63  * @param[in] info Create info structure
64  * @param[in] controller Controller object
65  * @param[out] out Unique pointer to the return object
66  */
67 template<class GLESType, class GfxCreateInfo, class T>
68 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
69 {
70   // Use allocator
71   using Type = typename T::element_type;
72   using UPtr = Graphics::UniquePtr<Type>;
73   if(info.allocationCallbacks)
74   {
75     auto* memory = info.allocationCallbacks->allocCallback(
76       sizeof(GLESType),
77       0,
78       info.allocationCallbacks->userData);
79     return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
80   }
81   else // Use standard allocator
82   {
83     return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
84   }
85 }
86
87 template<class T0, class T1>
88 T0* CastObject(T1* apiObject)
89 {
90   return static_cast<T0*>(apiObject);
91 }
92
93 } // namespace
94
95 EglGraphicsController::~EglGraphicsController() = default;
96
97 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
98 {
99   DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #1\n");
100   mGlAbstraction = &glAbstraction;
101   mContext       = std::make_unique<GLES::Context>(*this);
102 }
103
104 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction&          glSyncAbstraction,
105                                        Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
106                                        Internal::Adaptor::GraphicsInterface&    graphicsInterface)
107 {
108   DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
109   mGlSyncAbstraction          = &glSyncAbstraction;
110   mGlContextHelperAbstraction = &glContextHelperAbstraction;
111   mGraphics                   = &graphicsInterface;
112 }
113
114 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
115 {
116   for(auto& cmdbuf : submitInfo.cmdBuffer)
117   {
118     // Push command buffers
119     mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
120   }
121
122   // If flush bit set, flush all pending tasks
123   if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
124   {
125     Flush();
126   }
127 }
128
129 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
130 {
131   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
132   return *mGlAbstraction;
133 }
134
135 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
136 {
137   DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
138   return *mGlSyncAbstraction;
139 }
140
141 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
142 {
143   DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
144   return *mGlContextHelperAbstraction;
145 }
146
147 Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
148   const CommandBufferCreateInfo&       commandBufferCreateInfo,
149   Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
150 {
151   return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
152 }
153
154 Graphics::UniquePtr<RenderPass> EglGraphicsController::CreateRenderPass(const RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<RenderPass>&& oldRenderPass)
155 {
156   return NewObject<GLES::RenderPass>(renderPassCreateInfo, *this, std::move(oldRenderPass));
157 }
158
159 Graphics::UniquePtr<Texture>
160 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
161 {
162   return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
163 }
164
165 Graphics::UniquePtr<Buffer> EglGraphicsController::CreateBuffer(
166   const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
167 {
168   return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
169 }
170
171 Graphics::UniquePtr<Framebuffer> EglGraphicsController::CreateFramebuffer(
172   const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer)
173 {
174   return NewObject<GLES::Framebuffer>(framebufferCreateInfo, *this, std::move(oldFramebuffer));
175 }
176
177 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(
178   const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
179 {
180   // Create pipeline cache if needed
181   if(!mPipelineCache)
182   {
183     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
184   }
185
186   return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
187 }
188
189 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
190   const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
191 {
192   // Create program cache if needed
193   if(!mPipelineCache)
194   {
195     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
196   }
197
198   return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
199 }
200
201 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
202 {
203   return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
204 }
205
206 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
207 {
208   return NewObject<GLES::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
209 }
210
211 Graphics::UniquePtr<RenderTarget> EglGraphicsController::CreateRenderTarget(const RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<RenderTarget>&& oldRenderTarget)
212 {
213   return NewObject<GLES::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
214 }
215
216 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
217 {
218   return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
219 }
220
221 void EglGraphicsController::AddTexture(GLES::Texture& texture)
222 {
223   // Assuming we are on the correct context
224   mCreateTextureQueue.push(&texture);
225 }
226
227 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
228 {
229   // Assuming we are on the correct context
230   mCreateBufferQueue.push(&buffer);
231 }
232
233 void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer)
234 {
235   // Assuming we are on the correct context
236   mCreateFramebufferQueue.push(&framebuffer);
237 }
238
239 void EglGraphicsController::ProcessDiscardQueues()
240 {
241   // Process textures
242   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
243
244   // Process buffers
245   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
246
247   // Process Framebuffers
248   ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
249
250   // Process pipelines
251   ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
252
253   // Process programs
254   ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
255
256   // Process shaders
257   ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
258
259   // Process samplers
260   ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
261
262   // Process command buffers
263   ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
264 }
265
266 void EglGraphicsController::ProcessCreateQueues()
267 {
268   // Process textures
269   ProcessCreateQueue(mCreateTextureQueue);
270
271   // Process buffers
272   ProcessCreateQueue(mCreateBufferQueue);
273
274   // Process framebuffers
275   ProcessCreateQueue(mCreateFramebufferQueue);
276 }
277
278 void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuffer)
279 {
280   for(auto& cmd : commandBuffer.GetCommands())
281   {
282     // process command
283     switch(cmd.type)
284     {
285       case GLES::CommandType::FLUSH:
286       {
287         // Nothing to do here
288         break;
289       }
290       case GLES::CommandType::BIND_TEXTURES:
291       {
292         mContext->BindTextures(cmd.bindTextures.textureBindings);
293         break;
294       }
295       case GLES::CommandType::BIND_VERTEX_BUFFERS:
296       {
297         auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
298         mContext->BindVertexBuffers(bindings);
299         break;
300       }
301       case GLES::CommandType::BIND_UNIFORM_BUFFER:
302       {
303         auto& bindings = cmd.bindUniformBuffers;
304         mContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
305         break;
306       }
307       case GLES::CommandType::BIND_INDEX_BUFFER:
308       {
309         mContext->BindIndexBuffer(cmd.bindIndexBuffer);
310         break;
311       }
312       case GLES::CommandType::BIND_SAMPLERS:
313       {
314         break;
315       }
316       case GLES::CommandType::BIND_PIPELINE:
317       {
318         auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
319         mContext->BindPipeline(pipeline);
320         break;
321       }
322       case GLES::CommandType::DRAW:
323       {
324         mContext->Flush(false, cmd.draw);
325         break;
326       }
327       case GLES::CommandType::DRAW_INDEXED:
328       {
329         mContext->Flush(false, cmd.draw);
330         break;
331       }
332       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
333       {
334         mContext->Flush(false, cmd.draw);
335         break;
336       }
337       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
338       {
339         mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
340         break;
341       }
342       case GLES::CommandType::SET_SCISSOR_TEST:
343       {
344         if(cmd.scissorTest.enable)
345         {
346           mGlAbstraction->Enable(GL_SCISSOR_TEST);
347         }
348         else
349         {
350           mGlAbstraction->Disable(GL_SCISSOR_TEST);
351         }
352         break;
353       }
354       case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
355       {
356         mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
357         break;
358       }
359       case GLES::CommandType::BEGIN_RENDERPASS:
360       {
361         mContext->BeginRenderPass(cmd.beginRenderPass);
362         break;
363       }
364       case GLES::CommandType::END_RENDERPASS:
365       {
366         mContext->EndRenderPass();
367         break;
368       }
369       case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
370       {
371         // Process secondary command buffers
372         // todo: check validity of the secondaries
373         //       there are operations which are illigal to be done
374         //       within secondaries.
375         for(auto& buf : cmd.executeCommandBuffers.buffers)
376         {
377           ProcessCommandBuffer(*static_cast<GLES::CommandBuffer*>(buf));
378         }
379         break;
380       }
381     }
382   }
383 }
384
385 void EglGraphicsController::ProcessCommandQueues()
386 {
387   // TODO: command queue per context, sync between queues should be
388   // done externally
389   currentFramebuffer = nullptr;
390
391   while(!mCommandQueue.empty())
392   {
393     auto cmdBuf = mCommandQueue.front();
394     mCommandQueue.pop();
395     ProcessCommandBuffer(*cmdBuf);
396   }
397 }
398
399 void EglGraphicsController::ProcessTextureUpdateQueue()
400 {
401   while(!mTextureUpdateRequests.empty())
402   {
403     TextureUpdateRequest& request = mTextureUpdateRequests.front();
404
405     auto& info   = request.first;
406     auto& source = request.second;
407
408     if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
409     {
410       // GPU memory must be already allocated (glTexImage2D())
411       auto*       texture    = static_cast<GLES::Texture*>(info.dstTexture);
412       const auto& createInfo = texture->GetCreateInfo();
413
414       mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
415
416       mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
417       mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
418                                     info.level,
419                                     info.dstOffset2D.x,
420                                     info.dstOffset2D.y,
421                                     info.srcExtent2D.width,
422                                     info.srcExtent2D.height,
423                                     GLES::GLTextureFormatType(createInfo.format).format,
424                                     GLES::GLTextureFormatType(createInfo.format).type,
425                                     source.memorySource.memory);
426
427       // free staging memory
428       free(source.memorySource.memory);
429     }
430     else
431     {
432       // TODO: other sources
433     }
434
435     mTextureUpdateRequests.pop();
436   }
437 }
438
439 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
440                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
441 {
442   // Store updates
443   for(auto& info : updateInfoList)
444   {
445     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
446     auto& pair = mTextureUpdateRequests.back();
447     switch(pair.second.sourceType)
448     {
449       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
450       {
451         auto& info   = pair.first;
452         auto& source = pair.second;
453
454         // allocate staging memory and copy the data
455         // TODO: using PBO with GLES3, this is just naive
456         // oldschool way
457
458         char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
459         std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
460                   reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
461                   stagingBuffer);
462
463         // store staging buffer
464         source.memorySource.memory = stagingBuffer;
465         break;
466       }
467       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
468       {
469         // TODO, with PBO support
470         break;
471       }
472       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
473       {
474         // TODO texture 2 texture in-GPU copy
475         break;
476       }
477     }
478   }
479 }
480
481 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
482 {
483   mGraphics->ActivateResourceContext();
484
485   // Mapping buffer requires the object to be created NOW
486   // Workaround - flush now, otherwise there will be given a staging buffer
487   // in case when the buffer is not there yet
488   ProcessCreateQueues();
489
490   if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
491   {
492     return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
493   }
494   else
495   {
496     return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
497   }
498 }
499
500 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
501 {
502   return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
503 }
504
505 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
506 {
507   return *mPipelineCache;
508 }
509
510 } // namespace Dali::Graphics