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