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