Merge "[AT-SPI] Rework intercepting key events" into devel/master
[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/integration-api/trace.h>
22 #include <dali/public-api/common/dali-common.h>
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/integration-api/gl-abstraction.h>
28 #include <dali/integration-api/gl-defines.h>
29 #include <dali/integration-api/graphics-sync-abstraction.h>
30 #include <dali/integration-api/pixel-data-integ.h>
31 #include <dali/internal/graphics/gles-impl/egl-sync-object.h>
32 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
33 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
34 #include <dali/internal/graphics/gles-impl/gles-graphics-program.h>
35 #include <dali/internal/graphics/gles-impl/gles-graphics-render-pass.h>
36 #include <dali/internal/graphics/gles-impl/gles-graphics-render-target.h>
37 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
38 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
39 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
40 #include <dali/internal/graphics/gles-impl/gles-sync-object.h>
41 #include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
42 #include <dali/internal/graphics/gles/egl-sync-implementation.h>
43
44 #include <dali/internal/graphics/gles/egl-graphics.h>
45
46 #include <any>
47
48 // Uncomment the following define to turn on frame dumping
49 //#define ENABLE_COMMAND_BUFFER_FRAME_DUMP 1
50 #include <dali/internal/graphics/gles-impl/egl-graphics-controller-debug.h>
51 DUMP_FRAME_INIT();
52
53 namespace Dali::Graphics
54 {
55 namespace
56 {
57 /**
58  * @brief Custom deleter for all Graphics objects created
59  * with use of the Controller.
60  *
61  * When Graphics object dies the unique pointer (Graphics::UniquePtr)
62  * doesn't destroy it directly but passes the ownership back
63  * to the Controller. The GLESDeleter is responsible for passing
64  * the object to the discard queue (by calling Resource::DiscardResource()).
65  */
66 template<typename T>
67 struct GLESDeleter
68 {
69   GLESDeleter() = default;
70
71   void operator()(T* object)
72   {
73     // Discard resource (add it to discard queue)
74     object->DiscardResource();
75   }
76 };
77
78 /**
79  * @brief Helper function allocating graphics object
80  *
81  * @param[in] info Create info structure
82  * @param[in] controller Controller object
83  * @param[out] out Unique pointer to the return object
84  */
85 template<class GLESType, class GfxCreateInfo, class T>
86 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
87 {
88   // Use allocator
89   using Type = typename T::element_type;
90   using UPtr = Graphics::UniquePtr<Type>;
91   if(info.allocationCallbacks)
92   {
93     auto* memory = info.allocationCallbacks->allocCallback(
94       sizeof(GLESType),
95       0,
96       info.allocationCallbacks->userData);
97     return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
98   }
99   else // Use standard allocator
100   {
101     // We are given all object for recycling
102     if(oldObject)
103     {
104       auto reusedObject = oldObject.release();
105       // If succeeded, attach the object to the unique_ptr and return it back
106       if(static_cast<GLESType*>(reusedObject)->TryRecycle(info, controller))
107       {
108         return UPtr(reusedObject, GLESDeleter<GLESType>());
109       }
110       else
111       {
112         // can't reuse so kill object by giving it back to original
113         // unique pointer.
114         oldObject.reset(reusedObject);
115       }
116     }
117
118     // Create brand new object
119     return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
120   }
121 }
122
123 template<class T0, class T1>
124 T0* CastObject(T1* apiObject)
125 {
126   return static_cast<T0*>(apiObject);
127 }
128
129 // Maximum size of texture upload buffer.
130 const uint32_t TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB = 1;
131
132 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_EGL, false);
133 } // namespace
134
135 EglGraphicsController::EglGraphicsController()
136 : mTextureDependencyChecker(*this),
137   mSyncPool(*this)
138 {
139 }
140
141 EglGraphicsController::~EglGraphicsController()
142 {
143   while(!mPresentationCommandBuffers.empty())
144   {
145     auto presentCommandBuffer = const_cast<GLES::CommandBuffer*>(mPresentationCommandBuffers.front());
146     delete presentCommandBuffer;
147     mPresentationCommandBuffers.pop();
148   }
149 }
150
151 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
152 {
153   DALI_LOG_RELEASE_INFO("Initializing Graphics Controller Phase 1\n");
154   mGlAbstraction  = &glAbstraction;
155   mContext        = std::make_unique<GLES::Context>(*this, mGlAbstraction);
156   mCurrentContext = mContext.get();
157 }
158
159 void EglGraphicsController::Initialize(Integration::GraphicsSyncAbstraction& syncImplementation,
160                                        Internal::Adaptor::GraphicsInterface& graphicsInterface)
161 {
162   DALI_LOG_RELEASE_INFO("Initializing Graphics Controller Phase 2\n");
163   auto* syncImplPtr = static_cast<Internal::Adaptor::EglSyncImplementation*>(&syncImplementation);
164
165   mEglSyncImplementation = syncImplPtr;
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::GraphicsConfig& EglGraphicsController::GetGraphicsConfig()
245 {
246   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
247   return *mGlAbstraction;
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   const 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, mGlAbstraction);
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   DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_DISCARD_QUEUE");
439
440   // Process textures
441   ProcessDiscardSet<GLES::Texture>(mDiscardTextureSet);
442
443   // Process buffers
444   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
445
446   // Process Framebuffers
447   ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
448
449   // Process RenderPass
450   ProcessDiscardQueue<GLES::RenderPass>(mDiscardRenderPassQueue);
451
452   // Process RenderTarget
453   ProcessDiscardQueue<GLES::RenderTarget>(mDiscardRenderTargetQueue);
454
455   // Process pipelines
456   if(mPipelineCache && !mDiscardPipelineQueue.empty())
457   {
458     mPipelineCache->MarkPipelineCacheFlushRequired();
459   }
460   ProcessDiscardQueue(mDiscardPipelineQueue);
461
462   // Process programs
463   if(mPipelineCache && !mDiscardProgramQueue.empty())
464   {
465     mPipelineCache->MarkProgramCacheFlushRequired();
466   }
467   ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
468
469   // Process shaders
470   ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
471
472   // Process samplers
473   ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
474
475   // Process command buffers
476   ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
477 }
478
479 void EglGraphicsController::ProcessCreateQueues()
480 {
481   DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_CREATE_QUEUE");
482   // Process textures
483   ProcessCreateQueue(mCreateTextureQueue);
484
485   // Process buffers
486   ProcessCreateQueue(mCreateBufferQueue);
487
488   // Process framebuffers
489   ProcessCreateQueue(mCreateFramebufferQueue);
490 }
491
492 void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& commandBuffer)
493 {
494   auto       count    = 0u;
495   const auto commands = commandBuffer.GetCommands(count);
496
497   DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_EGL_CONTROLLER_PROCESS", [&](std::ostringstream& oss) {
498     oss << "[commandCount:" << count << "]";
499   });
500
501   for(auto i = 0u; i < count; ++i)
502   {
503     auto& cmd = commands[i];
504     // process command
505     switch(cmd.type)
506     {
507       case GLES::CommandType::FLUSH:
508       {
509         // Nothing to do here
510         break;
511       }
512       case GLES::CommandType::BIND_TEXTURES:
513       {
514         mCurrentContext->BindTextures(cmd.bindTextures.textureBindings.Ptr(), cmd.bindTextures.textureBindingsCount);
515         break;
516       }
517       case GLES::CommandType::BIND_VERTEX_BUFFERS:
518       {
519         auto bindings = cmd.bindVertexBuffers.vertexBufferBindings.Ptr();
520         mCurrentContext->BindVertexBuffers(bindings, cmd.bindVertexBuffers.vertexBufferBindingsCount);
521         break;
522       }
523       case GLES::CommandType::BIND_UNIFORM_BUFFER:
524       {
525         auto& bindings = cmd.bindUniformBuffers;
526         mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindingsCount ? bindings.uniformBufferBindings.Ptr() : nullptr, bindings.uniformBufferBindingsCount, bindings.standaloneUniformsBufferBinding);
527         break;
528       }
529       case GLES::CommandType::BIND_INDEX_BUFFER:
530       {
531         mCurrentContext->BindIndexBuffer(cmd.bindIndexBuffer);
532         break;
533       }
534       case GLES::CommandType::BIND_SAMPLERS:
535       {
536         break;
537       }
538       case GLES::CommandType::BIND_PIPELINE:
539       {
540         auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
541         mCurrentContext->BindPipeline(pipeline);
542         break;
543       }
544       case GLES::CommandType::DRAW:
545       {
546         mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
547         break;
548       }
549       case GLES::CommandType::DRAW_INDEXED:
550       {
551         mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
552         break;
553       }
554       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
555       {
556         mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
557         break;
558       }
559       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
560       {
561         mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
562         break;
563       }
564       case GLES::CommandType::SET_SCISSOR_TEST:
565       {
566         mCurrentContext->SetScissorTestEnabled(cmd.scissorTest.enable);
567         break;
568       }
569       case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
570       {
571         mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
572         break;
573       }
574
575       case GLES::CommandType::SET_COLOR_MASK:
576       {
577         mCurrentContext->ColorMask(cmd.colorMask.enabled);
578         break;
579       }
580       case GLES::CommandType::CLEAR_STENCIL_BUFFER:
581       {
582         mCurrentContext->ClearStencilBuffer();
583         break;
584       }
585       case GLES::CommandType::CLEAR_DEPTH_BUFFER:
586       {
587         mCurrentContext->ClearDepthBuffer();
588         break;
589       }
590
591       case GLES::CommandType::SET_STENCIL_TEST_ENABLE:
592       {
593         mCurrentContext->SetStencilTestEnable(cmd.stencilTest.enabled);
594         break;
595       }
596
597       case GLES::CommandType::SET_STENCIL_FUNC:
598       {
599         mCurrentContext->StencilFunc(cmd.stencilFunc.compareOp,
600                                      cmd.stencilFunc.reference,
601                                      cmd.stencilFunc.compareMask);
602         break;
603       }
604
605       case GLES::CommandType::SET_STENCIL_WRITE_MASK:
606       {
607         mCurrentContext->StencilMask(cmd.stencilWriteMask.mask);
608         break;
609       }
610
611       case GLES::CommandType::SET_STENCIL_OP:
612       {
613         mCurrentContext->StencilOp(cmd.stencilOp.failOp,
614                                    cmd.stencilOp.depthFailOp,
615                                    cmd.stencilOp.passOp);
616         break;
617       }
618
619       case GLES::CommandType::SET_DEPTH_COMPARE_OP:
620       {
621         mCurrentContext->SetDepthCompareOp(cmd.depth.compareOp);
622         break;
623       }
624       case GLES::CommandType::SET_DEPTH_TEST_ENABLE:
625       {
626         mCurrentContext->SetDepthTestEnable(cmd.depth.testEnabled);
627         break;
628       }
629       case GLES::CommandType::SET_DEPTH_WRITE_ENABLE:
630       {
631         mCurrentContext->SetDepthWriteEnable(cmd.depth.writeEnabled);
632         break;
633       }
634
635       case GLES::CommandType::BEGIN_RENDERPASS:
636       {
637         auto&       renderTarget = *cmd.beginRenderPass.renderTarget;
638         const auto& targetInfo   = renderTarget.GetCreateInfo();
639
640         if(targetInfo.surface)
641         {
642           // switch to surface context
643           mGraphics->ActivateSurfaceContext(static_cast<Dali::RenderSurfaceInterface*>(targetInfo.surface));
644         }
645         else if(targetInfo.framebuffer)
646         {
647           // switch to resource context
648           mGraphics->ActivateResourceContext();
649         }
650
651         mCurrentContext->BeginRenderPass(cmd.beginRenderPass);
652
653         break;
654       }
655       case GLES::CommandType::END_RENDERPASS:
656       {
657         mCurrentContext->EndRenderPass(mTextureDependencyChecker);
658
659         // This sync object is to enable cpu to wait for rendering to complete, not gpu.
660         // It's only needed for reading the framebuffer texture in the client.
661         auto syncObject = const_cast<GLES::SyncObject*>(static_cast<const GLES::SyncObject*>(cmd.endRenderPass.syncObject));
662         if(syncObject)
663         {
664           syncObject->InitializeResource();
665         }
666         break;
667       }
668       case GLES::CommandType::PRESENT_RENDER_TARGET:
669       {
670         ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
671
672         // The command buffer will be pushed into the queue of presentation command buffers
673         // for further reuse.
674         if(commandBuffer.GetCreateInfo().fixedCapacity == 1)
675         {
676           mPresentationCommandBuffers.push(&commandBuffer);
677         }
678         break;
679       }
680       case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
681       {
682         // Process secondary command buffers
683         // todo: check validity of the secondaries
684         //       there are operations which are illigal to be done
685         //       within secondaries.
686         auto buffers = cmd.executeCommandBuffers.buffers.Ptr();
687         for(auto j = 0u; j < cmd.executeCommandBuffers.buffersCount; ++j)
688         {
689           auto& buf = buffers[j];
690           ProcessCommandBuffer(*static_cast<const GLES::CommandBuffer*>(buf));
691         }
692         break;
693       }
694       case GLES::CommandType::DRAW_NATIVE:
695       {
696         auto* info = &cmd.drawNative.drawNativeInfo;
697
698         // ISOLATED execution mode will isolate GL graphics context from
699         // DALi renderning pipeline which is the safest way of rendering
700         // the 'injected' code.
701         if(info->executionMode == DrawNativeExecutionMode::ISOLATED)
702         {
703           mCurrentContext->PrepareForNativeRendering();
704         }
705
706         if(info->glesNativeInfo.eglSharedContextStoragePointer)
707         {
708           auto* anyContext = reinterpret_cast<std::any*>(info->glesNativeInfo.eglSharedContextStoragePointer);
709           *anyContext      = mSharedContext;
710         }
711
712         CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
713         if(info->executionMode == DrawNativeExecutionMode::ISOLATED)
714         {
715           mCurrentContext->RestoreFromNativeRendering();
716         }
717         else
718         {
719           // After native rendering reset all states and caches.
720           // This is going to be called only when DIRECT execution mode is used
721           // and some GL states need to be reset.
722           // This does not guarantee that after execution a custom GL code
723           // the main rendering pipeline will work correctly and it's a responsibility
724           // of developer to make sure the GL states are not interfering with main
725           // rendering pipeline (by restoring/cleaning up GL states after drawing).
726           mCurrentContext->ResetGLESState();
727         }
728         break;
729       }
730     }
731   }
732   DALI_TRACE_END(gTraceFilter, "DALI_EGL_CONTROLLER_PROCESS");
733 }
734
735 void EglGraphicsController::ProcessCommandQueues()
736 {
737   DUMP_FRAME_START();
738
739   while(!mCommandQueue.empty())
740   {
741     auto cmdBuf = mCommandQueue.front();
742     mCommandQueue.pop();
743     DUMP_FRAME_COMMAND_BUFFER(cmdBuf);
744     ProcessCommandBuffer(*cmdBuf);
745   }
746
747   DUMP_FRAME_END();
748 }
749
750 void EglGraphicsController::ProcessTextureUpdateQueue()
751 {
752   if(mTextureUpdateRequests.empty())
753   {
754     return;
755   }
756   DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_TEXTURE_UPDATE");
757   while(!mTextureUpdateRequests.empty())
758   {
759     TextureUpdateRequest& request = mTextureUpdateRequests.front();
760
761     auto& info   = request.first;
762     auto& source = request.second;
763
764     switch(source.sourceType)
765     {
766       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
767       case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
768       {
769         // GPU memory must be already allocated.
770
771         // Check if it needs conversion
772         auto*       texture            = static_cast<GLES::Texture*>(info.dstTexture);
773         const auto& createInfo         = texture->GetCreateInfo();
774         auto        srcFormat          = GLES::GLTextureFormatType(info.srcFormat).format;
775         auto        srcType            = GLES::GLTextureFormatType(info.srcFormat).type;
776         auto        destInternalFormat = GLES::GLTextureFormatType(createInfo.format).internalFormat;
777         auto        destFormat         = GLES::GLTextureFormatType(createInfo.format).format;
778
779         // From render-texture.cpp
780         const bool isSubImage(info.dstOffset2D.x != 0 || info.dstOffset2D.y != 0 ||
781                               info.srcExtent2D.width != (createInfo.size.width / (1 << info.level)) ||
782                               info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
783
784         uint8_t* sourceBuffer                = nullptr;
785         bool     sourceBufferReleaseRequired = false;
786         if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
787         {
788           sourceBuffer                = reinterpret_cast<uint8_t*>(source.memorySource.memory);
789           sourceBufferReleaseRequired = true;
790         }
791         else
792         {
793           Dali::Integration::PixelDataBuffer pixelBufferData = Dali::Integration::GetPixelDataBuffer(source.pixelDataSource.pixelData);
794
795           sourceBuffer                = pixelBufferData.buffer + info.srcOffset;
796           sourceBufferReleaseRequired = Dali::Integration::IsPixelDataReleaseAfterUpload(source.pixelDataSource.pixelData) && info.srcOffset == 0u;
797         }
798
799         // Skip texture upload if given texture is already discarded for this render loop.
800         if(mDiscardTextureSet.find(texture) == mDiscardTextureSet.end())
801         {
802           auto                 sourceStride = info.srcStride;
803           std::vector<uint8_t> tempBuffer;
804
805           uint8_t* srcBuffer = sourceBuffer;
806
807           if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
808           {
809             // Convert RGB to RGBA if necessary.
810             if(texture->TryConvertPixelData(sourceBuffer, info.srcFormat, createInfo.format, info.srcSize, info.srcStride, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer))
811             {
812               srcBuffer    = &tempBuffer[0];
813               sourceStride = 0u; // Converted buffer compacted. make stride as 0.
814               srcFormat    = destFormat;
815               srcType      = GLES::GLTextureFormatType(createInfo.format).type;
816             }
817           }
818
819           // Calculate the maximum mipmap level for the texture
820           texture->SetMaxMipMapLevel(std::max(texture->GetMaxMipMapLevel(), info.level));
821
822           GLenum bindTarget{GL_TEXTURE_2D};
823           GLenum target{GL_TEXTURE_2D};
824
825           if(createInfo.textureType == Graphics::TextureType::TEXTURE_CUBEMAP)
826           {
827             bindTarget = GL_TEXTURE_CUBE_MAP;
828             target     = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.layer;
829           }
830
831           mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
832           mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
833
834           mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
835
836           if(!isSubImage)
837           {
838             if(!texture->IsCompressed())
839             {
840               mGlAbstraction->TexImage2D(target,
841                                          info.level,
842                                          destInternalFormat,
843                                          info.srcExtent2D.width,
844                                          info.srcExtent2D.height,
845                                          0,
846                                          srcFormat,
847                                          srcType,
848                                          srcBuffer);
849             }
850             else
851             {
852               mGlAbstraction->CompressedTexImage2D(target,
853                                                    info.level,
854                                                    destInternalFormat,
855                                                    info.srcExtent2D.width,
856                                                    info.srcExtent2D.height,
857                                                    0,
858                                                    info.srcSize,
859                                                    srcBuffer);
860             }
861           }
862           else
863           {
864             if(!texture->IsCompressed())
865             {
866               mGlAbstraction->TexSubImage2D(target,
867                                             info.level,
868                                             info.dstOffset2D.x,
869                                             info.dstOffset2D.y,
870                                             info.srcExtent2D.width,
871                                             info.srcExtent2D.height,
872                                             srcFormat,
873                                             srcType,
874                                             srcBuffer);
875             }
876             else
877             {
878               mGlAbstraction->CompressedTexSubImage2D(target,
879                                                       info.level,
880                                                       info.dstOffset2D.x,
881                                                       info.dstOffset2D.y,
882                                                       info.srcExtent2D.width,
883                                                       info.srcExtent2D.height,
884                                                       srcFormat,
885                                                       info.srcSize,
886                                                       srcBuffer);
887             }
888           }
889         }
890
891         if(sourceBufferReleaseRequired && sourceBuffer != nullptr)
892         {
893           if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
894           {
895             free(reinterpret_cast<void*>(sourceBuffer));
896           }
897           else
898           {
899             Dali::Integration::ReleasePixelDataBuffer(source.pixelDataSource.pixelData);
900           }
901         }
902         break;
903       }
904       default:
905       {
906         // TODO: other sources
907         break;
908       }
909     }
910
911     mTextureUpdateRequests.pop();
912   }
913 }
914
915 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
916                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
917 {
918   // Store updates
919   for(auto& info : updateInfoList)
920   {
921     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
922     auto& pair = mTextureUpdateRequests.back();
923     switch(pair.second.sourceType)
924     {
925       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
926       {
927         auto& info   = pair.first;
928         auto& source = pair.second;
929
930         // allocate staging memory and copy the data
931         // TODO: using PBO with GLES3, this is just naive
932         // oldschool way
933
934         uint8_t* stagingBuffer = reinterpret_cast<uint8_t*>(malloc(info.srcSize));
935
936         if(DALI_UNLIKELY(stagingBuffer == nullptr))
937         {
938           DALI_LOG_ERROR("malloc is failed. request malloc size : %u\n", info.srcSize);
939         }
940         else
941         {
942           uint8_t* srcMemory = &reinterpret_cast<uint8_t*>(source.memorySource.memory)[info.srcOffset];
943
944           std::copy(srcMemory, srcMemory + info.srcSize, stagingBuffer);
945
946           mTextureUploadTotalCPUMemoryUsed += info.srcSize;
947         }
948
949         // store staging buffer
950         source.memorySource.memory = stagingBuffer;
951         break;
952       }
953       case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
954       {
955         // Increase CPU memory usage since ownership of PixelData is now on mTextureUpdateRequests.
956         mTextureUploadTotalCPUMemoryUsed += info.srcSize;
957         break;
958       }
959       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
960       {
961         // TODO, with PBO support
962         break;
963       }
964       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
965       {
966         // TODO texture 2 texture in-GPU copy
967         break;
968       }
969     }
970   }
971
972   // If upload buffer exceeds maximum size, flush.
973   if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024 * 1024)
974   {
975     Flush();
976     mTextureUploadTotalCPUMemoryUsed = 0;
977   }
978 }
979
980 void EglGraphicsController::ProcessTextureMipmapGenerationQueue()
981 {
982   if(mTextureMipmapGenerationRequests.empty())
983   {
984     return;
985   }
986   DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_TEXTURE_MIPMAP");
987   while(!mTextureMipmapGenerationRequests.empty())
988   {
989     auto* texture = mTextureMipmapGenerationRequests.front();
990
991     mCurrentContext->BindTexture(texture->GetGlTarget(), texture->GetTextureTypeId(), texture->GetGLTexture());
992     mCurrentContext->GenerateMipmap(texture->GetGlTarget());
993
994     mTextureMipmapGenerationRequests.pop();
995   }
996 }
997
998 void EglGraphicsController::GenerateTextureMipmaps(const Graphics::Texture& texture)
999 {
1000   mTextureMipmapGenerationRequests.push(static_cast<const GLES::Texture*>(&texture));
1001 }
1002
1003 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
1004 {
1005   // Mapping buffer requires the object to be created NOW
1006   // Workaround - flush now, otherwise there will be given a staging buffer
1007   // in case when the buffer is not there yet
1008   if(!mCreateBufferQueue.empty())
1009   {
1010     mGraphics->ActivateResourceContext();
1011     ProcessCreateQueues();
1012   }
1013
1014   if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
1015   {
1016     return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
1017   }
1018   else
1019   {
1020     return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
1021   }
1022 }
1023
1024 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
1025 {
1026   return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
1027 }
1028
1029 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
1030 {
1031   return *mPipelineCache;
1032 }
1033
1034 Graphics::Texture* EglGraphicsController::CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo)
1035 {
1036   Graphics::Texture*                     ret = nullptr;
1037   Graphics::UniquePtr<Graphics::Texture> texture;
1038
1039   auto iter = mExternalTextureResources.find(resourceId);
1040   DALI_ASSERT_ALWAYS(iter == mExternalTextureResources.end());
1041
1042   texture = CreateTexture(createInfo, std::move(texture));
1043
1044   ret = texture.get();
1045
1046   mExternalTextureResources.insert(std::make_pair(resourceId, std::move(texture)));
1047
1048   return ret;
1049 }
1050
1051 void EglGraphicsController::DiscardTextureFromResourceId(uint32_t resourceId)
1052 {
1053   auto iter = mExternalTextureResources.find(resourceId);
1054   if(iter != mExternalTextureResources.end())
1055   {
1056     mExternalTextureResources.erase(iter);
1057   }
1058 }
1059
1060 Graphics::Texture* EglGraphicsController::GetTextureFromResourceId(uint32_t resourceId)
1061 {
1062   Graphics::Texture* ret = nullptr;
1063
1064   auto iter = mExternalTextureResources.find(resourceId);
1065   if(iter != mExternalTextureResources.end())
1066   {
1067     ret = iter->second.get();
1068   }
1069
1070   return ret;
1071 }
1072
1073 Graphics::UniquePtr<Graphics::Texture> EglGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId)
1074 {
1075   Graphics::UniquePtr<Graphics::Texture> texture;
1076
1077   auto iter = mExternalTextureResources.find(resourceId);
1078   if(iter != mExternalTextureResources.end())
1079   {
1080     texture = std::move(iter->second);
1081     mExternalTextureResources.erase(iter);
1082   }
1083
1084   return texture;
1085 }
1086
1087 } // namespace Dali::Graphics