Synchronize framebuffer textures on different contexts
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / egl-graphics-controller.cpp
1 /*
2  * Copyright (c) 2022 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/adaptor-framework/render-surface-interface.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/gl-abstraction.h>
24 #include <dali/integration-api/gl-defines.h>
25 #include <dali/integration-api/graphics-sync-abstraction.h>
26 #include <dali/internal/graphics/gles-impl/egl-sync-object.h>
27 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
28 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
29 #include <dali/internal/graphics/gles-impl/gles-graphics-program.h>
30 #include <dali/internal/graphics/gles-impl/gles-graphics-render-pass.h>
31 #include <dali/internal/graphics/gles-impl/gles-graphics-render-target.h>
32 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
33 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
34 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
35 #include <dali/internal/graphics/gles-impl/gles-sync-object.h>
36 #include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
37 #include <dali/internal/graphics/gles/egl-sync-implementation.h>
38 #include <dali/public-api/common/dali-common.h>
39
40 #include <dali/internal/graphics/gles/egl-graphics.h>
41
42 #include <any>
43
44 // Uncomment the following define to turn on frame dumping
45 //#define ENABLE_COMMAND_BUFFER_FRAME_DUMP 1
46 #include <dali/internal/graphics/gles-impl/egl-graphics-controller-debug.h>
47 DUMP_FRAME_INIT();
48
49 namespace Dali::Graphics
50 {
51 namespace
52 {
53 /**
54  * @brief Custom deleter for all Graphics objects created
55  * with use of the Controller.
56  *
57  * When Graphics object dies the unique pointer (Graphics::UniquePtr)
58  * doesn't destroy it directly but passes the ownership back
59  * to the Controller. The GLESDeleter is responsible for passing
60  * the object to the discard queue (by calling Resource::DiscardResource()).
61  */
62 template<typename T>
63 struct GLESDeleter
64 {
65   GLESDeleter() = default;
66
67   void operator()(T* object)
68   {
69     // Discard resource (add it to discard queue)
70     object->DiscardResource();
71   }
72 };
73
74 /**
75  * @brief Helper function allocating graphics object
76  *
77  * @param[in] info Create info structure
78  * @param[in] controller Controller object
79  * @param[out] out Unique pointer to the return object
80  */
81 template<class GLESType, class GfxCreateInfo, class T>
82 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
83 {
84   // Use allocator
85   using Type = typename T::element_type;
86   using UPtr = Graphics::UniquePtr<Type>;
87   if(info.allocationCallbacks)
88   {
89     auto* memory = info.allocationCallbacks->allocCallback(
90       sizeof(GLESType),
91       0,
92       info.allocationCallbacks->userData);
93     return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
94   }
95   else // Use standard allocator
96   {
97     return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
98   }
99 }
100
101 template<class T0, class T1>
102 T0* CastObject(T1* apiObject)
103 {
104   return static_cast<T0*>(apiObject);
105 }
106
107 // Maximum size of texture upload buffer.
108 const uint32_t TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB = 1;
109
110 } // namespace
111
112 EglGraphicsController::EglGraphicsController()
113 : mTextureDependencyChecker(*this),
114   mSyncPool(*this)
115 {
116 }
117
118 EglGraphicsController::~EglGraphicsController()
119 {
120   while(!mPresentationCommandBuffers.empty())
121   {
122     auto presentCommandBuffer = const_cast<GLES::CommandBuffer*>(mPresentationCommandBuffers.front());
123     delete presentCommandBuffer;
124     mPresentationCommandBuffers.pop();
125   }
126 }
127
128 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
129 {
130   DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #1\n");
131   mGlAbstraction  = &glAbstraction;
132   mContext        = std::make_unique<GLES::Context>(*this);
133   mCurrentContext = mContext.get();
134 }
135
136 void EglGraphicsController::Initialize(Integration::GraphicsSyncAbstraction&    syncImplementation,
137                                        Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
138                                        Internal::Adaptor::GraphicsInterface&    graphicsInterface)
139 {
140   DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
141   auto* syncImplPtr = static_cast<Internal::Adaptor::EglSyncImplementation*>(&syncImplementation);
142
143   mEglSyncImplementation      = syncImplPtr;
144   mGlContextHelperAbstraction = &glContextHelperAbstraction;
145   mGraphics                   = &graphicsInterface;
146 }
147
148 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
149 {
150   for(auto& cmdbuf : submitInfo.cmdBuffer)
151   {
152     // Push command buffers
153     mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
154   }
155
156   // If flush bit set, flush all pending tasks
157   if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
158   {
159     Flush();
160   }
161 }
162
163 void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
164 {
165   GLES::CommandBuffer* presentCommandBuffer{nullptr};
166   if(mPresentationCommandBuffers.empty())
167   {
168     CommandBufferCreateInfo info;
169     info.SetLevel(CommandBufferLevel::PRIMARY);
170     info.fixedCapacity   = 1; // only one command
171     presentCommandBuffer = new GLES::CommandBuffer(info, *this);
172   }
173   else
174   {
175     presentCommandBuffer = const_cast<GLES::CommandBuffer*>(mPresentationCommandBuffers.front());
176     presentCommandBuffer->Reset();
177     mPresentationCommandBuffers.pop();
178   }
179   presentCommandBuffer->PresentRenderTarget(static_cast<GLES::RenderTarget*>(renderTarget));
180   SubmitInfo submitInfo;
181   submitInfo.cmdBuffer = {presentCommandBuffer};
182   submitInfo.flags     = 0 | SubmitFlagBits::FLUSH;
183   SubmitCommandBuffers(submitInfo);
184 }
185
186 void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* renderTarget)
187 {
188   mCurrentContext->InvalidateDepthStencilBuffers();
189
190   auto* rt = static_cast<GLES::RenderTarget*>(renderTarget);
191   if(rt->GetCreateInfo().surface)
192   {
193     auto* surfaceInterface = reinterpret_cast<Dali::RenderSurfaceInterface*>(rt->GetCreateInfo().surface);
194     surfaceInterface->MakeContextCurrent();
195     surfaceInterface->PostRender();
196   }
197 }
198
199 void EglGraphicsController::PostRender()
200 {
201   mTextureDependencyChecker.Reset();
202   mSyncPool.AgeSyncObjects();
203 }
204
205 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
206 {
207   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
208   return *mGlAbstraction;
209 }
210
211 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
212 {
213   DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
214   return *mGlContextHelperAbstraction;
215 }
216
217 Internal::Adaptor::EglSyncImplementation& EglGraphicsController::GetEglSyncImplementation()
218 {
219   DALI_ASSERT_DEBUG(mEglSyncImplementation && "Sync implementation not initialized");
220   return *mEglSyncImplementation;
221 }
222
223 Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
224   const CommandBufferCreateInfo&       commandBufferCreateInfo,
225   Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
226 {
227   return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
228 }
229
230 Graphics::UniquePtr<RenderPass> EglGraphicsController::CreateRenderPass(const RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<RenderPass>&& oldRenderPass)
231 {
232   return NewObject<GLES::RenderPass>(renderPassCreateInfo, *this, std::move(oldRenderPass));
233 }
234
235 Graphics::UniquePtr<Texture>
236 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
237 {
238   return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
239 }
240
241 Graphics::UniquePtr<Buffer> EglGraphicsController::CreateBuffer(
242   const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
243 {
244   return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
245 }
246
247 Graphics::UniquePtr<Framebuffer> EglGraphicsController::CreateFramebuffer(
248   const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer)
249 {
250   return NewObject<GLES::Framebuffer>(framebufferCreateInfo, *this, std::move(oldFramebuffer));
251 }
252
253 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(
254   const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
255 {
256   // Create pipeline cache if needed
257   if(!mPipelineCache)
258   {
259     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
260   }
261
262   return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
263 }
264
265 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
266   const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
267 {
268   // Create program cache if needed
269   if(!mPipelineCache)
270   {
271     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
272   }
273
274   return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
275 }
276
277 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
278 {
279   return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
280 }
281
282 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
283 {
284   return NewObject<GLES::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
285 }
286
287 Graphics::UniquePtr<RenderTarget> EglGraphicsController::CreateRenderTarget(const RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<RenderTarget>&& oldRenderTarget)
288 {
289   return NewObject<GLES::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
290 }
291
292 Graphics::UniquePtr<SyncObject> EglGraphicsController::CreateSyncObject(const SyncObjectCreateInfo& syncObjectCreateInfo,
293                                                                         UniquePtr<SyncObject>&&     oldSyncObject)
294 {
295   if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
296   {
297     return NewObject<EGL::SyncObject>(syncObjectCreateInfo, *this, std::move(oldSyncObject));
298   }
299   else
300   {
301     return NewObject<GLES::SyncObject>(syncObjectCreateInfo, *this, std::move(oldSyncObject));
302   }
303 }
304
305 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
306 {
307   return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
308 }
309
310 void EglGraphicsController::CreateSurfaceContext(Dali::RenderSurfaceInterface* surface)
311 {
312   std::unique_ptr<GLES::Context> context = std::make_unique<GLES::Context>(*this);
313   mSurfaceContexts.push_back(std::move(std::make_pair(surface, std::move(context))));
314 }
315
316 void EglGraphicsController::DeleteSurfaceContext(Dali::RenderSurfaceInterface* surface)
317 {
318   mSurfaceContexts.erase(std::remove_if(
319                            mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return surface == iter.first; }),
320                          mSurfaceContexts.end());
321 }
322
323 void EglGraphicsController::ActivateResourceContext()
324 {
325   mCurrentContext = mContext.get();
326   mCurrentContext->GlContextCreated();
327
328   if(!mSharedContext)
329   {
330     auto eglGraphics = dynamic_cast<Dali::Internal::Adaptor::EglGraphics*>(mGraphics);
331     if(eglGraphics)
332     {
333       mSharedContext = eglGraphics->GetEglImplementation().GetContext();
334     }
335   }
336 }
337
338 void EglGraphicsController::ActivateSurfaceContext(Dali::RenderSurfaceInterface* surface)
339 {
340   if(surface && mGraphics->IsResourceContextSupported())
341   {
342     auto iter = std::find_if(mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) {
343       return (iter.first == surface);
344     });
345
346     if(iter != mSurfaceContexts.end())
347     {
348       mCurrentContext = iter->second.get();
349       mCurrentContext->GlContextCreated();
350     }
351   }
352 }
353
354 void EglGraphicsController::AddTexture(GLES::Texture& texture)
355 {
356   // Assuming we are on the correct context
357   mCreateTextureQueue.push(&texture);
358 }
359
360 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
361 {
362   // Assuming we are on the correct context
363   mCreateBufferQueue.push(&buffer);
364 }
365
366 void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer)
367 {
368   // Assuming we are on the correct context
369   mCreateFramebufferQueue.push(&framebuffer);
370 }
371
372 void EglGraphicsController::ProcessDiscardQueues()
373 {
374   // Process textures
375   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
376
377   // Process buffers
378   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
379
380   // Process Framebuffers
381   ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
382
383   // Process RenderPass
384   ProcessDiscardQueue<GLES::RenderPass>(mDiscardRenderPassQueue);
385
386   // Process RenderTarget
387   ProcessDiscardQueue<GLES::RenderTarget>(mDiscardRenderTargetQueue);
388
389   // Process pipelines
390   ProcessDiscardQueue(mDiscardPipelineQueue);
391
392   // Process programs
393   ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
394
395   // Process shaders
396   ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
397
398   // Process samplers
399   ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
400
401   // Process command buffers
402   ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
403 }
404
405 void EglGraphicsController::ProcessCreateQueues()
406 {
407   // Process textures
408   ProcessCreateQueue(mCreateTextureQueue);
409
410   // Process buffers
411   ProcessCreateQueue(mCreateBufferQueue);
412
413   // Process framebuffers
414   ProcessCreateQueue(mCreateFramebufferQueue);
415 }
416
417 void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& commandBuffer)
418 {
419   auto       count    = 0u;
420   const auto commands = commandBuffer.GetCommands(count);
421   for(auto i = 0u; i < count; ++i)
422   {
423     auto& cmd = commands[i];
424     // process command
425     switch(cmd.type)
426     {
427       case GLES::CommandType::FLUSH:
428       {
429         // Nothing to do here
430         break;
431       }
432       case GLES::CommandType::BIND_TEXTURES:
433       {
434         mCurrentContext->BindTextures(cmd.bindTextures.textureBindings.Ptr(), cmd.bindTextures.textureBindingsCount);
435         break;
436       }
437       case GLES::CommandType::BIND_VERTEX_BUFFERS:
438       {
439         auto bindings = cmd.bindVertexBuffers.vertexBufferBindings.Ptr();
440         mCurrentContext->BindVertexBuffers(bindings, cmd.bindVertexBuffers.vertexBufferBindingsCount);
441         break;
442       }
443       case GLES::CommandType::BIND_UNIFORM_BUFFER:
444       {
445         auto& bindings = cmd.bindUniformBuffers;
446         mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindingsCount ? bindings.uniformBufferBindings.Ptr() : nullptr, bindings.uniformBufferBindingsCount, bindings.standaloneUniformsBufferBinding);
447         break;
448       }
449       case GLES::CommandType::BIND_INDEX_BUFFER:
450       {
451         mCurrentContext->BindIndexBuffer(cmd.bindIndexBuffer);
452         break;
453       }
454       case GLES::CommandType::BIND_SAMPLERS:
455       {
456         break;
457       }
458       case GLES::CommandType::BIND_PIPELINE:
459       {
460         auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
461         mCurrentContext->BindPipeline(pipeline);
462         break;
463       }
464       case GLES::CommandType::DRAW:
465       {
466         mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
467         break;
468       }
469       case GLES::CommandType::DRAW_INDEXED:
470       {
471         mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
472         break;
473       }
474       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
475       {
476         mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
477         break;
478       }
479       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
480       {
481         mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
482         break;
483       }
484       case GLES::CommandType::SET_SCISSOR_TEST:
485       {
486         mCurrentContext->SetScissorTestEnabled(cmd.scissorTest.enable);
487         break;
488       }
489       case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
490       {
491         mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
492         break;
493       }
494
495       case GLES::CommandType::SET_COLOR_MASK:
496       {
497         mCurrentContext->ColorMask(cmd.colorMask.enabled);
498         break;
499       }
500       case GLES::CommandType::CLEAR_STENCIL_BUFFER:
501       {
502         mCurrentContext->ClearStencilBuffer();
503         break;
504       }
505       case GLES::CommandType::CLEAR_DEPTH_BUFFER:
506       {
507         mCurrentContext->ClearDepthBuffer();
508         break;
509       }
510
511       case GLES::CommandType::SET_STENCIL_TEST_ENABLE:
512       {
513         mCurrentContext->SetStencilTestEnable(cmd.stencilTest.enabled);
514         break;
515       }
516
517       case GLES::CommandType::SET_STENCIL_FUNC:
518       {
519         mCurrentContext->StencilFunc(cmd.stencilFunc.compareOp,
520                                      cmd.stencilFunc.reference,
521                                      cmd.stencilFunc.compareMask);
522         break;
523       }
524
525       case GLES::CommandType::SET_STENCIL_WRITE_MASK:
526       {
527         mCurrentContext->StencilMask(cmd.stencilWriteMask.mask);
528         break;
529       }
530
531       case GLES::CommandType::SET_STENCIL_OP:
532       {
533         mCurrentContext->StencilOp(cmd.stencilOp.failOp,
534                                    cmd.stencilOp.depthFailOp,
535                                    cmd.stencilOp.passOp);
536         break;
537       }
538
539       case GLES::CommandType::SET_DEPTH_COMPARE_OP:
540       {
541         mCurrentContext->SetDepthCompareOp(cmd.depth.compareOp);
542         break;
543       }
544       case GLES::CommandType::SET_DEPTH_TEST_ENABLE:
545       {
546         mCurrentContext->SetDepthTestEnable(cmd.depth.testEnabled);
547         break;
548       }
549       case GLES::CommandType::SET_DEPTH_WRITE_ENABLE:
550       {
551         mCurrentContext->SetDepthWriteEnable(cmd.depth.writeEnabled);
552         break;
553       }
554
555       case GLES::CommandType::BEGIN_RENDERPASS:
556       {
557         auto&       renderTarget = *cmd.beginRenderPass.renderTarget;
558         const auto& targetInfo   = renderTarget.GetCreateInfo();
559
560         if(targetInfo.surface)
561         {
562           // switch to surface context
563           mGraphics->ActivateSurfaceContext(static_cast<Dali::RenderSurfaceInterface*>(targetInfo.surface));
564         }
565         else if(targetInfo.framebuffer)
566         {
567           // switch to resource context
568           mGraphics->ActivateResourceContext();
569         }
570
571         mCurrentContext->BeginRenderPass(cmd.beginRenderPass);
572
573         break;
574       }
575       case GLES::CommandType::END_RENDERPASS:
576       {
577         mCurrentContext->EndRenderPass(mTextureDependencyChecker);
578
579         // This sync object is to enable cpu to wait for rendering to complete, not gpu.
580         // It's only needed for reading the framebuffer texture in the client.
581         auto syncObject = const_cast<GLES::SyncObject*>(static_cast<const GLES::SyncObject*>(cmd.endRenderPass.syncObject));
582         if(syncObject)
583         {
584           syncObject->InitializeResource();
585         }
586         break;
587       }
588       case GLES::CommandType::PRESENT_RENDER_TARGET:
589       {
590         ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
591
592         // The command buffer will be pushed into the queue of presentation command buffers
593         // for further reuse.
594         if(commandBuffer.GetCreateInfo().fixedCapacity == 1)
595         {
596           mPresentationCommandBuffers.push(&commandBuffer);
597         }
598         break;
599       }
600       case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
601       {
602         // Process secondary command buffers
603         // todo: check validity of the secondaries
604         //       there are operations which are illigal to be done
605         //       within secondaries.
606         auto buffers = cmd.executeCommandBuffers.buffers.Ptr();
607         for(auto j = 0u; j < cmd.executeCommandBuffers.buffersCount; ++j)
608         {
609           auto& buf = buffers[j];
610           ProcessCommandBuffer(*static_cast<const GLES::CommandBuffer*>(buf));
611         }
612         break;
613       }
614       case GLES::CommandType::DRAW_NATIVE:
615       {
616         auto* info = &cmd.drawNative.drawNativeInfo;
617
618         mCurrentContext->PrepareForNativeRendering();
619
620         if(info->glesNativeInfo.eglSharedContextStoragePointer)
621         {
622           auto* anyContext = reinterpret_cast<std::any*>(info->glesNativeInfo.eglSharedContextStoragePointer);
623           *anyContext      = mSharedContext;
624         }
625
626         CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
627
628         mCurrentContext->RestoreFromNativeRendering();
629         break;
630       }
631     }
632   }
633 }
634
635 void EglGraphicsController::ProcessCommandQueues()
636 {
637   DUMP_FRAME_START();
638
639   while(!mCommandQueue.empty())
640   {
641     auto cmdBuf = mCommandQueue.front();
642     mCommandQueue.pop();
643     DUMP_FRAME_COMMAND_BUFFER(cmdBuf);
644     ProcessCommandBuffer(*cmdBuf);
645   }
646
647   DUMP_FRAME_END();
648 }
649
650 void EglGraphicsController::ProcessTextureUpdateQueue()
651 {
652   while(!mTextureUpdateRequests.empty())
653   {
654     TextureUpdateRequest& request = mTextureUpdateRequests.front();
655
656     auto& info   = request.first;
657     auto& source = request.second;
658
659     if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
660     {
661       // GPU memory must be already allocated.
662
663       // Check if it needs conversion
664       auto*       texture            = static_cast<GLES::Texture*>(info.dstTexture);
665       const auto& createInfo         = texture->GetCreateInfo();
666       auto        srcFormat          = GLES::GLTextureFormatType(info.srcFormat).format;
667       auto        srcType            = GLES::GLTextureFormatType(info.srcFormat).type;
668       auto        destInternalFormat = GLES::GLTextureFormatType(createInfo.format).internalFormat;
669       auto        destFormat         = GLES::GLTextureFormatType(createInfo.format).format;
670
671       // From render-texture.cpp
672       const bool isSubImage(info.dstOffset2D.x != 0 || info.dstOffset2D.y != 0 ||
673                             info.srcExtent2D.width != (createInfo.size.width / (1 << info.level)) ||
674                             info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
675
676       auto*                sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
677       auto                 sourceStride = info.srcStride;
678       std::vector<uint8_t> tempBuffer;
679
680       if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
681       {
682         // Convert RGB to RGBA if necessary.
683         if(texture->TryConvertPixelData(source.memorySource.memory, info.srcFormat, createInfo.format, info.srcSize, info.srcStride, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer))
684         {
685           sourceBuffer = &tempBuffer[0];
686           sourceStride = 0u; // Converted buffer compacted. make stride as 0.
687           srcFormat    = destFormat;
688           srcType      = GLES::GLTextureFormatType(createInfo.format).type;
689         }
690       }
691
692       // Calculate the maximum mipmap level for the texture
693       texture->SetMaxMipMapLevel(std::max(texture->GetMaxMipMapLevel(), info.level));
694
695       GLenum bindTarget{GL_TEXTURE_2D};
696       GLenum target{GL_TEXTURE_2D};
697
698       if(createInfo.textureType == Graphics::TextureType::TEXTURE_CUBEMAP)
699       {
700         bindTarget = GL_TEXTURE_CUBE_MAP;
701         target     = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.layer;
702       }
703
704       mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
705       mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
706
707       mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
708
709       if(!isSubImage)
710       {
711         if(!texture->IsCompressed())
712         {
713           mGlAbstraction->TexImage2D(target,
714                                      info.level,
715                                      destInternalFormat,
716                                      info.srcExtent2D.width,
717                                      info.srcExtent2D.height,
718                                      0,
719                                      srcFormat,
720                                      srcType,
721                                      sourceBuffer);
722         }
723         else
724         {
725           mGlAbstraction->CompressedTexImage2D(target,
726                                                info.level,
727                                                destInternalFormat,
728                                                info.srcExtent2D.width,
729                                                info.srcExtent2D.height,
730                                                0,
731                                                info.srcSize,
732                                                sourceBuffer);
733         }
734       }
735       else
736       {
737         if(!texture->IsCompressed())
738         {
739           mGlAbstraction->TexSubImage2D(target,
740                                         info.level,
741                                         info.dstOffset2D.x,
742                                         info.dstOffset2D.y,
743                                         info.srcExtent2D.width,
744                                         info.srcExtent2D.height,
745                                         srcFormat,
746                                         srcType,
747                                         sourceBuffer);
748         }
749         else
750         {
751           mGlAbstraction->CompressedTexSubImage2D(target,
752                                                   info.level,
753                                                   info.dstOffset2D.x,
754                                                   info.dstOffset2D.y,
755                                                   info.srcExtent2D.width,
756                                                   info.srcExtent2D.height,
757                                                   srcFormat,
758                                                   info.srcSize,
759                                                   sourceBuffer);
760         }
761       }
762       // free staging memory
763       free(source.memorySource.memory);
764     }
765     else
766     {
767       // TODO: other sources
768     }
769
770     mTextureUpdateRequests.pop();
771   }
772 }
773
774 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
775                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
776 {
777   // Store updates
778   for(auto& info : updateInfoList)
779   {
780     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
781     auto& pair = mTextureUpdateRequests.back();
782     switch(pair.second.sourceType)
783     {
784       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
785       {
786         auto& info   = pair.first;
787         auto& source = pair.second;
788
789         // allocate staging memory and copy the data
790         // TODO: using PBO with GLES3, this is just naive
791         // oldschool way
792
793         uint8_t* stagingBuffer = reinterpret_cast<uint8_t*>(malloc(info.srcSize));
794
795         uint8_t* srcMemory = &reinterpret_cast<uint8_t*>(source.memorySource.memory)[info.srcOffset];
796
797         std::copy(srcMemory, srcMemory + info.srcSize, stagingBuffer);
798
799         mTextureUploadTotalCPUMemoryUsed += info.srcSize;
800
801         // store staging buffer
802         source.memorySource.memory = stagingBuffer;
803         break;
804       }
805       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
806       {
807         // TODO, with PBO support
808         break;
809       }
810       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
811       {
812         // TODO texture 2 texture in-GPU copy
813         break;
814       }
815     }
816   }
817
818   // If upload buffer exceeds maximum size, flush.
819   if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024 * 1024)
820   {
821     Flush();
822     mTextureUploadTotalCPUMemoryUsed = 0;
823   }
824 }
825
826 void EglGraphicsController::ProcessTextureMipmapGenerationQueue()
827 {
828   while(!mTextureMipmapGenerationRequests.empty())
829   {
830     auto* texture = mTextureMipmapGenerationRequests.front();
831
832     mCurrentContext->BindTexture(texture->GetGlTarget(), texture->GetTextureTypeId(), texture->GetGLTexture());
833     mCurrentContext->GenerateMipmap(texture->GetGlTarget());
834
835     mTextureMipmapGenerationRequests.pop();
836   }
837 }
838
839 void EglGraphicsController::GenerateTextureMipmaps(const Graphics::Texture& texture)
840 {
841   mTextureMipmapGenerationRequests.push(static_cast<const GLES::Texture*>(&texture));
842 }
843
844 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
845 {
846   mGraphics->ActivateResourceContext();
847
848   // Mapping buffer requires the object to be created NOW
849   // Workaround - flush now, otherwise there will be given a staging buffer
850   // in case when the buffer is not there yet
851   ProcessCreateQueues();
852
853   if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
854   {
855     return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
856   }
857   else
858   {
859     return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
860   }
861 }
862
863 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
864 {
865   return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
866 }
867
868 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
869 {
870   return *mPipelineCache;
871 }
872
873 } // namespace Dali::Graphics