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