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