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