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