Merge "Merge branch 'devel/master' into devel/graphics" into devel/master
[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 }
292
293 void EglGraphicsController::ActivateSurfaceContext(Dali::RenderSurfaceInterface* surface)
294 {
295   if(surface && mGraphics->IsResourceContextSupported())
296   {
297     auto iter = std::find_if(mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) {
298       return (iter.first == surface);
299     });
300
301     if(iter != mSurfaceContexts.end())
302     {
303       mCurrentContext = iter->second.get();
304     }
305   }
306 }
307
308 void EglGraphicsController::AddTexture(GLES::Texture& texture)
309 {
310   // Assuming we are on the correct context
311   mCreateTextureQueue.push(&texture);
312 }
313
314 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
315 {
316   // Assuming we are on the correct context
317   mCreateBufferQueue.push(&buffer);
318 }
319
320 void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer)
321 {
322   // Assuming we are on the correct context
323   mCreateFramebufferQueue.push(&framebuffer);
324 }
325
326 void EglGraphicsController::ProcessDiscardQueues()
327 {
328   // Process textures
329   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
330
331   // Process buffers
332   ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
333
334   // Process Framebuffers
335   ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
336
337   // Process pipelines
338   ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
339
340   // Process programs
341   ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
342
343   // Process shaders
344   ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
345
346   // Process samplers
347   ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
348
349   // Process command buffers
350   ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
351 }
352
353 void EglGraphicsController::ProcessCreateQueues()
354 {
355   // Process textures
356   ProcessCreateQueue(mCreateTextureQueue);
357
358   // Process buffers
359   ProcessCreateQueue(mCreateBufferQueue);
360
361   // Process framebuffers
362   ProcessCreateQueue(mCreateFramebufferQueue);
363 }
364
365 void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& commandBuffer)
366 {
367   for(auto& cmd : commandBuffer.GetCommands())
368   {
369     // process command
370     switch(cmd.type)
371     {
372       case GLES::CommandType::FLUSH:
373       {
374         // Nothing to do here
375         break;
376       }
377       case GLES::CommandType::BIND_TEXTURES:
378       {
379         mCurrentContext->BindTextures(cmd.bindTextures.textureBindings);
380         break;
381       }
382       case GLES::CommandType::BIND_VERTEX_BUFFERS:
383       {
384         auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
385         mCurrentContext->BindVertexBuffers(bindings);
386         break;
387       }
388       case GLES::CommandType::BIND_UNIFORM_BUFFER:
389       {
390         auto& bindings = cmd.bindUniformBuffers;
391         mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
392         break;
393       }
394       case GLES::CommandType::BIND_INDEX_BUFFER:
395       {
396         mCurrentContext->BindIndexBuffer(cmd.bindIndexBuffer);
397         break;
398       }
399       case GLES::CommandType::BIND_SAMPLERS:
400       {
401         break;
402       }
403       case GLES::CommandType::BIND_PIPELINE:
404       {
405         auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
406         mCurrentContext->BindPipeline(pipeline);
407         break;
408       }
409       case GLES::CommandType::DRAW:
410       {
411         mCurrentContext->Flush(false, cmd.draw);
412         break;
413       }
414       case GLES::CommandType::DRAW_INDEXED:
415       {
416         mCurrentContext->Flush(false, cmd.draw);
417         break;
418       }
419       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
420       {
421         mCurrentContext->Flush(false, cmd.draw);
422         break;
423       }
424       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
425       {
426         mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
427         break;
428       }
429       case GLES::CommandType::SET_SCISSOR_TEST:
430       {
431         if(cmd.scissorTest.enable)
432         {
433           mGlAbstraction->Enable(GL_SCISSOR_TEST);
434         }
435         else
436         {
437           mGlAbstraction->Disable(GL_SCISSOR_TEST);
438         }
439         break;
440       }
441       case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
442       {
443         mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
444         break;
445       }
446
447       case GLES::CommandType::SET_COLOR_MASK:
448       {
449         mCurrentContext->ColorMask(cmd.colorMask.enabled);
450         break;
451       }
452       case GLES::CommandType::CLEAR_STENCIL_BUFFER:
453       {
454         mCurrentContext->ClearStencilBuffer();
455         break;
456       }
457       case GLES::CommandType::CLEAR_DEPTH_BUFFER:
458       {
459         mCurrentContext->ClearDepthBuffer();
460         break;
461       }
462
463       case GLES::CommandType::SET_STENCIL_TEST_ENABLE:
464       {
465         mCurrentContext->SetStencilTestEnable(cmd.stencilTest.enabled);
466         break;
467       }
468
469       case GLES::CommandType::SET_STENCIL_FUNC:
470       {
471         mCurrentContext->StencilFunc(cmd.stencilFunc.compareOp,
472                                      cmd.stencilFunc.reference,
473                                      cmd.stencilFunc.compareMask);
474         break;
475       }
476
477       case GLES::CommandType::SET_STENCIL_WRITE_MASK:
478       {
479         mCurrentContext->StencilMask(cmd.stencilWriteMask.mask);
480         break;
481       }
482
483       case GLES::CommandType::SET_STENCIL_OP:
484       {
485         mCurrentContext->StencilOp(cmd.stencilOp.failOp,
486                                    cmd.stencilOp.depthFailOp,
487                                    cmd.stencilOp.passOp);
488         break;
489       }
490
491       case GLES::CommandType::SET_DEPTH_COMPARE_OP:
492       {
493         mCurrentContext->SetDepthCompareOp(cmd.depth.compareOp);
494         break;
495       }
496       case GLES::CommandType::SET_DEPTH_TEST_ENABLE:
497       {
498         mCurrentContext->SetDepthTestEnable(cmd.depth.testEnabled);
499         break;
500       }
501       case GLES::CommandType::SET_DEPTH_WRITE_ENABLE:
502       {
503         mCurrentContext->SetDepthWriteEnable(cmd.depth.writeEnabled);
504         break;
505       }
506
507       case GLES::CommandType::BEGIN_RENDERPASS:
508       {
509         auto&       renderTarget = *cmd.beginRenderPass.renderTarget;
510         const auto& targetInfo   = renderTarget.GetCreateInfo();
511
512         if(targetInfo.surface)
513         {
514           // switch to surface context
515           mGraphics->ActivateSurfaceContext(static_cast<Dali::RenderSurfaceInterface*>(targetInfo.surface));
516         }
517         else if(targetInfo.framebuffer)
518         {
519           // switch to resource context
520           mGraphics->ActivateResourceContext();
521         }
522
523         mCurrentContext->BeginRenderPass(cmd.beginRenderPass);
524         break;
525       }
526       case GLES::CommandType::END_RENDERPASS:
527       {
528         mCurrentContext->EndRenderPass();
529
530         auto syncObject = const_cast<GLES::SyncObject*>(static_cast<const GLES::SyncObject*>(cmd.endRenderPass.syncObject));
531         if(syncObject)
532         {
533           syncObject->InitializeResource();
534         }
535         break;
536       }
537       case GLES::CommandType::PRESENT_RENDER_TARGET:
538       {
539         ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
540
541         // push this command buffer to the discard queue
542         mDiscardCommandBufferQueue.push(const_cast<GLES::CommandBuffer*>(&commandBuffer));
543         break;
544       }
545       case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
546       {
547         // Process secondary command buffers
548         // todo: check validity of the secondaries
549         //       there are operations which are illigal to be done
550         //       within secondaries.
551         for(auto& buf : cmd.executeCommandBuffers.buffers)
552         {
553           ProcessCommandBuffer(*static_cast<const GLES::CommandBuffer*>(buf));
554         }
555         break;
556       }
557     }
558   }
559 }
560
561 void EglGraphicsController::ProcessCommandQueues()
562 {
563   // TODO: command queue per context, sync between queues should be
564   // done externally
565   currentFramebuffer = nullptr;
566
567   DUMP_FRAME_START();
568
569   while(!mCommandQueue.empty())
570   {
571     auto cmdBuf = mCommandQueue.front();
572     mCommandQueue.pop();
573     DUMP_FRAME_COMMAND_BUFFER(cmdBuf);
574     ProcessCommandBuffer(*cmdBuf);
575   }
576
577   DUMP_FRAME_END();
578 }
579
580 void EglGraphicsController::ProcessTextureUpdateQueue()
581 {
582   while(!mTextureUpdateRequests.empty())
583   {
584     TextureUpdateRequest& request = mTextureUpdateRequests.front();
585
586     auto& info   = request.first;
587     auto& source = request.second;
588
589     if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
590     {
591       // GPU memory must be already allocated.
592
593       // Check if it needs conversion
594       auto*       texture            = static_cast<GLES::Texture*>(info.dstTexture);
595       const auto& createInfo         = texture->GetCreateInfo();
596       auto        srcFormat          = GLES::GLTextureFormatType(info.srcFormat).format;
597       auto        srcType            = GLES::GLTextureFormatType(info.srcFormat).type;
598       auto        destInternalFormat = GLES::GLTextureFormatType(createInfo.format).internalFormat;
599       auto        destFormat         = GLES::GLTextureFormatType(createInfo.format).format;
600
601       // From render-texture.cpp
602       const bool isSubImage(info.dstOffset2D.x != 0 || info.dstOffset2D.y != 0 ||
603                             info.srcExtent2D.width != (createInfo.size.width / (1 << info.level)) ||
604                             info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
605
606       auto*                sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
607       std::vector<uint8_t> tempBuffer;
608       if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
609       {
610         // Convert RGB to RGBA if necessary.
611         texture->TryConvertPixelData(source.memorySource.memory, info.srcFormat, createInfo.format, info.srcSize, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer);
612         sourceBuffer = &tempBuffer[0];
613         srcFormat    = destFormat;
614         srcType      = GLES::GLTextureFormatType(createInfo.format).type;
615       }
616
617       // Calculate the maximum mipmap level for the texture
618       texture->SetMaxMipMapLevel(std::max(texture->GetMaxMipMapLevel(), info.level));
619
620       GLenum bindTarget{GL_TEXTURE_2D};
621       GLenum target{GL_TEXTURE_2D};
622
623       if(createInfo.textureType == Graphics::TextureType::TEXTURE_CUBEMAP)
624       {
625         bindTarget = GL_TEXTURE_CUBE_MAP;
626         target     = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.layer;
627       }
628
629       mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
630       mGlAbstraction->BindTexture(bindTarget, texture->GetGLTexture());
631
632       if(!isSubImage)
633       {
634         if(!texture->IsCompressed())
635         {
636           mGlAbstraction->TexImage2D(target,
637                                      info.level,
638                                      destInternalFormat,
639                                      info.srcExtent2D.width,
640                                      info.srcExtent2D.height,
641                                      0,
642                                      srcFormat,
643                                      srcType,
644                                      sourceBuffer);
645         }
646         else
647         {
648           mGlAbstraction->CompressedTexImage2D(target,
649                                                info.level,
650                                                destInternalFormat,
651                                                info.srcExtent2D.width,
652                                                info.srcExtent2D.height,
653                                                0,
654                                                info.srcSize,
655                                                sourceBuffer);
656         }
657       }
658       else
659       {
660         if(!texture->IsCompressed())
661         {
662           mGlAbstraction->TexSubImage2D(target,
663                                         info.level,
664                                         info.dstOffset2D.x,
665                                         info.dstOffset2D.y,
666                                         info.srcExtent2D.width,
667                                         info.srcExtent2D.height,
668                                         srcFormat,
669                                         srcType,
670                                         sourceBuffer);
671         }
672         else
673         {
674           mGlAbstraction->CompressedTexSubImage2D(target,
675                                                   info.level,
676                                                   info.dstOffset2D.x,
677                                                   info.dstOffset2D.y,
678                                                   info.srcExtent2D.width,
679                                                   info.srcExtent2D.height,
680                                                   srcFormat,
681                                                   info.srcSize,
682                                                   sourceBuffer);
683         }
684       }
685       // free staging memory
686       free(source.memorySource.memory);
687     }
688     else
689     {
690       // TODO: other sources
691     }
692
693     mTextureUpdateRequests.pop();
694   }
695 }
696
697 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&       updateInfoList,
698                                            const std::vector<TextureUpdateSourceInfo>& sourceList)
699 {
700   // Store updates
701   for(auto& info : updateInfoList)
702   {
703     mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
704     auto& pair = mTextureUpdateRequests.back();
705     switch(pair.second.sourceType)
706     {
707       case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
708       {
709         auto& info   = pair.first;
710         auto& source = pair.second;
711
712         // allocate staging memory and copy the data
713         // TODO: using PBO with GLES3, this is just naive
714         // oldschool way
715
716         char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
717         std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
718                   reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
719                   stagingBuffer);
720
721         mTextureUploadTotalCPUMemoryUsed += info.srcSize;
722
723         // store staging buffer
724         source.memorySource.memory = stagingBuffer;
725         break;
726       }
727       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
728       {
729         // TODO, with PBO support
730         break;
731       }
732       case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
733       {
734         // TODO texture 2 texture in-GPU copy
735         break;
736       }
737     }
738   }
739
740   // If upload buffer exceeds maximum size, flush.
741   if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024)
742   {
743     Flush();
744     mTextureUploadTotalCPUMemoryUsed = 0;
745   }
746 }
747
748 void EglGraphicsController::ProcessTextureMipmapGenerationQueue()
749 {
750   while(!mTextureMipmapGenerationRequests.empty())
751   {
752     auto* texture = mTextureMipmapGenerationRequests.front();
753
754     mGlAbstraction->BindTexture(texture->GetGlTarget(), texture->GetGLTexture());
755     mGlAbstraction->GenerateMipmap(texture->GetGlTarget());
756
757     mTextureMipmapGenerationRequests.pop();
758   }
759 }
760
761 void EglGraphicsController::GenerateTextureMipmaps(const Graphics::Texture& texture)
762 {
763   mTextureMipmapGenerationRequests.push(static_cast<const GLES::Texture*>(&texture));
764 }
765
766 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
767 {
768   mGraphics->ActivateResourceContext();
769
770   // Mapping buffer requires the object to be created NOW
771   // Workaround - flush now, otherwise there will be given a staging buffer
772   // in case when the buffer is not there yet
773   ProcessCreateQueues();
774
775   if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
776   {
777     return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
778   }
779   else
780   {
781     return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
782   }
783 }
784
785 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
786 {
787   return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
788 }
789
790 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
791 {
792   return *mPipelineCache;
793 }
794
795 } // namespace Dali::Graphics