Cleaned up some of the circular dependency between GLES::Context & GLES::GraphicsCont...
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / egl-graphics-controller.cpp
index b17e6f8..2206b12 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 // CLASS HEADER
 #include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
 
+// EXTERNAL INCLUDES
+#include <dali/integration-api/trace.h>
+#include <dali/public-api/common/dali-common.h>
+
 // INTERNAL INCLUDES
 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
 #include <dali/integration-api/debug.h>
 #include <dali/integration-api/gl-abstraction.h>
 #include <dali/integration-api/gl-defines.h>
+#include <dali/integration-api/graphics-sync-abstraction.h>
+#include <dali/integration-api/pixel-data-integ.h>
+#include <dali/internal/graphics/gles-impl/egl-sync-object.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
+#include <dali/internal/graphics/gles-impl/gles-graphics-program.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-render-pass.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-render-target.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
+#include <dali/internal/graphics/gles-impl/gles-sync-object.h>
 #include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
-#include <dali/public-api/common/dali-common.h>
-#include "gles-graphics-program.h"
+#include <dali/internal/graphics/gles/egl-sync-implementation.h>
+
+#include <dali/internal/graphics/gles/egl-graphics.h>
+
+#include <any>
+
+// Uncomment the following define to turn on frame dumping
+//#define ENABLE_COMMAND_BUFFER_FRAME_DUMP 1
+#include <dali/internal/graphics/gles-impl/egl-graphics-controller-debug.h>
+DUMP_FRAME_INIT();
 
 namespace Dali::Graphics
 {
@@ -81,6 +98,24 @@ auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&&
   }
   else // Use standard allocator
   {
+    // We are given all object for recycling
+    if(oldObject)
+    {
+      auto reusedObject = oldObject.release();
+      // If succeeded, attach the object to the unique_ptr and return it back
+      if(static_cast<GLESType*>(reusedObject)->TryRecycle(info, controller))
+      {
+        return UPtr(reusedObject, GLESDeleter<GLESType>());
+      }
+      else
+      {
+        // can't reuse so kill object by giving it back to original
+        // unique pointer.
+        oldObject.reset(reusedObject);
+      }
+    }
+
+    // Create brand new object
     return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
   }
 }
@@ -91,33 +126,61 @@ T0* CastObject(T1* apiObject)
   return static_cast<T0*>(apiObject);
 }
 
+// Maximum size of texture upload buffer.
+const uint32_t TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB = 1;
+
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_EGL, false);
 } // namespace
 
-EglGraphicsController::~EglGraphicsController() = default;
+EglGraphicsController::EglGraphicsController()
+: mTextureDependencyChecker(*this),
+  mSyncPool(*this)
+{
+}
+
+EglGraphicsController::~EglGraphicsController()
+{
+  while(!mPresentationCommandBuffers.empty())
+  {
+    auto presentCommandBuffer = const_cast<GLES::CommandBuffer*>(mPresentationCommandBuffers.front());
+    delete presentCommandBuffer;
+    mPresentationCommandBuffers.pop();
+  }
+}
 
 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
 {
-  DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #1\n");
-  mGlAbstraction = &glAbstraction;
-  mContext       = std::make_unique<GLES::Context>(*this);
+  DALI_LOG_RELEASE_INFO("Initializing Graphics Controller Phase 1\n");
+  mGlAbstraction  = &glAbstraction;
+  mContext        = std::make_unique<GLES::Context>(*this, mGlAbstraction);
+  mCurrentContext = mContext.get();
 }
 
-void EglGraphicsController::Initialize(Integration::GlSyncAbstraction&          glSyncAbstraction,
+void EglGraphicsController::Initialize(Integration::GraphicsSyncAbstraction&    syncImplementation,
                                        Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
                                        Internal::Adaptor::GraphicsInterface&    graphicsInterface)
 {
-  DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
-  mGlSyncAbstraction          = &glSyncAbstraction;
+  DALI_LOG_RELEASE_INFO("Initializing Graphics Controller Phase 2\n");
+  auto* syncImplPtr = static_cast<Internal::Adaptor::EglSyncImplementation*>(&syncImplementation);
+
+  mEglSyncImplementation      = syncImplPtr;
   mGlContextHelperAbstraction = &glContextHelperAbstraction;
   mGraphics                   = &graphicsInterface;
 }
 
+void EglGraphicsController::FrameStart()
+{
+  mCapacity = 0; // Reset the command buffer capacity at the start of the frame.
+}
+
 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
 {
   for(auto& cmdbuf : submitInfo.cmdBuffer)
   {
     // Push command buffers
-    mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
+    auto* commandBuffer = static_cast<GLES::CommandBuffer*>(cmdbuf);
+    mCapacity += commandBuffer->GetCapacity();
+    mCommandQueue.push(commandBuffer);
   }
 
   // If flush bit set, flush all pending tasks
@@ -127,13 +190,27 @@ void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
   }
 }
 
+void EglGraphicsController::WaitIdle()
+{
+  Flush();
+}
+
 void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
 {
-  // Use command buffer to execute presentation (we should pool it)
-  CommandBufferCreateInfo info;
-  info.SetLevel(CommandBufferLevel::PRIMARY);
-  info.fixedCapacity        = 1; // only one command
-  auto presentCommandBuffer = new GLES::CommandBuffer(info, *this);
+  GLES::CommandBuffer* presentCommandBuffer{nullptr};
+  if(mPresentationCommandBuffers.empty())
+  {
+    CommandBufferCreateInfo info;
+    info.SetLevel(CommandBufferLevel::PRIMARY);
+    info.fixedCapacity   = 1; // only one command
+    presentCommandBuffer = new GLES::CommandBuffer(info, *this);
+  }
+  else
+  {
+    presentCommandBuffer = const_cast<GLES::CommandBuffer*>(mPresentationCommandBuffers.front());
+    presentCommandBuffer->Reset();
+    mPresentationCommandBuffers.pop();
+  }
   presentCommandBuffer->PresentRenderTarget(static_cast<GLES::RenderTarget*>(renderTarget));
   SubmitInfo submitInfo;
   submitInfo.cmdBuffer = {presentCommandBuffer};
@@ -143,6 +220,8 @@ void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
 
 void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* renderTarget)
 {
+  mCurrentContext->InvalidateDepthStencilBuffers();
+
   auto* rt = static_cast<GLES::RenderTarget*>(renderTarget);
   if(rt->GetCreateInfo().surface)
   {
@@ -152,16 +231,16 @@ void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* rende
   }
 }
 
-Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
+void EglGraphicsController::PostRender()
 {
-  DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
-  return *mGlAbstraction;
+  mTextureDependencyChecker.Reset();
+  mSyncPool.AgeSyncObjects();
 }
 
-Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
+Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
 {
-  DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
-  return *mGlSyncAbstraction;
+  DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
+  return *mGlAbstraction;
 }
 
 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
@@ -170,6 +249,12 @@ Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelp
   return *mGlContextHelperAbstraction;
 }
 
+Internal::Adaptor::EglSyncImplementation& EglGraphicsController::GetEglSyncImplementation()
+{
+  DALI_ASSERT_DEBUG(mEglSyncImplementation && "Sync implementation not initialized");
+  return *mEglSyncImplementation;
+}
+
 Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
   const CommandBufferCreateInfo&       commandBufferCreateInfo,
   Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
@@ -215,7 +300,7 @@ Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(
 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
   const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
 {
-  // Create program cache if needed
+  // Create pipeline cache if needed
   if(!mPipelineCache)
   {
     mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
@@ -226,7 +311,12 @@ Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
 
 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
 {
-  return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
+  // Create pipeline cache if needed
+  if(!mPipelineCache)
+  {
+    mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
+  }
+  return mPipelineCache->GetShader(shaderCreateInfo, std::move(oldShader));
 }
 
 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
@@ -239,11 +329,94 @@ Graphics::UniquePtr<RenderTarget> EglGraphicsController::CreateRenderTarget(cons
   return NewObject<GLES::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
 }
 
+Graphics::UniquePtr<SyncObject> EglGraphicsController::CreateSyncObject(const SyncObjectCreateInfo& syncObjectCreateInfo,
+                                                                        UniquePtr<SyncObject>&&     oldSyncObject)
+{
+  if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
+  {
+    return NewObject<EGL::SyncObject>(syncObjectCreateInfo, *this, std::move(oldSyncObject));
+  }
+  else
+  {
+    return NewObject<GLES::SyncObject>(syncObjectCreateInfo, *this, std::move(oldSyncObject));
+  }
+}
+
+MemoryRequirements EglGraphicsController::GetBufferMemoryRequirements(Buffer& buffer) const
+{
+  MemoryRequirements requirements{};
+
+  auto gl = GetGL();
+  if(gl)
+  {
+    GLint align;
+    gl->GetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &align);
+    requirements.alignment = align;
+  }
+  return requirements;
+}
+
+TextureProperties EglGraphicsController::GetTextureProperties(const Texture& texture)
+{
+  const GLES::Texture* glesTexture = static_cast<const GLES::Texture*>(&texture);
+  const auto&          createInfo  = glesTexture->GetCreateInfo();
+
+  TextureProperties properties{};
+  properties.format       = createInfo.format;
+  properties.compressed   = glesTexture->IsCompressed();
+  properties.extent2D     = createInfo.size;
+  properties.nativeHandle = glesTexture->GetGLTexture();
+  // TODO: Skip format1, emulated, packed, directWriteAccessEnabled of TextureProperties for now
+
+  return properties;
+}
+
 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
 {
   return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
 }
 
+void EglGraphicsController::CreateSurfaceContext(Dali::RenderSurfaceInterface* surface)
+{
+  std::unique_ptr<GLES::Context> context = std::make_unique<GLES::Context>(*this, mGlAbstraction);
+  mSurfaceContexts.push_back(std::move(std::make_pair(surface, std::move(context))));
+}
+
+void EglGraphicsController::DeleteSurfaceContext(Dali::RenderSurfaceInterface* surface)
+{
+  mSurfaceContexts.erase(std::remove_if(
+                           mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return surface == iter.first; }),
+                         mSurfaceContexts.end());
+}
+
+void EglGraphicsController::ActivateResourceContext()
+{
+  mCurrentContext = mContext.get();
+  mCurrentContext->GlContextCreated();
+  if(!mSharedContext)
+  {
+    auto eglGraphics = dynamic_cast<Dali::Internal::Adaptor::EglGraphics*>(mGraphics);
+    if(eglGraphics)
+    {
+      mSharedContext = eglGraphics->GetEglImplementation().GetContext();
+    }
+  }
+}
+
+void EglGraphicsController::ActivateSurfaceContext(Dali::RenderSurfaceInterface* surface)
+{
+  if(surface && mGraphics->IsResourceContextSupported())
+  {
+    auto iter = std::find_if(mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return (iter.first == surface); });
+
+    if(iter != mSurfaceContexts.end())
+    {
+      mCurrentContext = iter->second.get();
+      mCurrentContext->GlContextCreated();
+    }
+  }
+}
+
 void EglGraphicsController::AddTexture(GLES::Texture& texture)
 {
   // Assuming we are on the correct context
@@ -264,6 +437,8 @@ void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer)
 
 void EglGraphicsController::ProcessDiscardQueues()
 {
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_DISCARD_QUEUE");
+
   // Process textures
   ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
 
@@ -273,10 +448,24 @@ void EglGraphicsController::ProcessDiscardQueues()
   // Process Framebuffers
   ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
 
+  // Process RenderPass
+  ProcessDiscardQueue<GLES::RenderPass>(mDiscardRenderPassQueue);
+
+  // Process RenderTarget
+  ProcessDiscardQueue<GLES::RenderTarget>(mDiscardRenderTargetQueue);
+
   // Process pipelines
-  ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
+  if(mPipelineCache && !mDiscardPipelineQueue.empty())
+  {
+    mPipelineCache->MarkPipelineCacheFlushRequired();
+  }
+  ProcessDiscardQueue(mDiscardPipelineQueue);
 
   // Process programs
+  if(mPipelineCache && !mDiscardProgramQueue.empty())
+  {
+    mPipelineCache->MarkProgramCacheFlushRequired();
+  }
   ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
 
   // Process shaders
@@ -291,6 +480,7 @@ void EglGraphicsController::ProcessDiscardQueues()
 
 void EglGraphicsController::ProcessCreateQueues()
 {
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_CREATE_QUEUE");
   // Process textures
   ProcessCreateQueue(mCreateTextureQueue);
 
@@ -301,10 +491,18 @@ void EglGraphicsController::ProcessCreateQueues()
   ProcessCreateQueue(mCreateFramebufferQueue);
 }
 
-void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuffer)
+void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& commandBuffer)
 {
-  for(auto& cmd : commandBuffer.GetCommands())
+  auto       count    = 0u;
+  const auto commands = commandBuffer.GetCommands(count);
+
+  DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_EGL_CONTROLLER_PROCESS", [&](std::ostringstream& oss) {
+    oss << "[commandCount:" << count << "]";
+  });
+
+  for(auto i = 0u; i < count; ++i)
   {
+    auto& cmd = commands[i];
     // process command
     switch(cmd.type)
     {
@@ -315,24 +513,24 @@ void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuf
       }
       case GLES::CommandType::BIND_TEXTURES:
       {
-        mContext->BindTextures(cmd.bindTextures.textureBindings);
+        mCurrentContext->BindTextures(cmd.bindTextures.textureBindings.Ptr(), cmd.bindTextures.textureBindingsCount);
         break;
       }
       case GLES::CommandType::BIND_VERTEX_BUFFERS:
       {
-        auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
-        mContext->BindVertexBuffers(bindings);
+        auto bindings = cmd.bindVertexBuffers.vertexBufferBindings.Ptr();
+        mCurrentContext->BindVertexBuffers(bindings, cmd.bindVertexBuffers.vertexBufferBindingsCount);
         break;
       }
       case GLES::CommandType::BIND_UNIFORM_BUFFER:
       {
         auto& bindings = cmd.bindUniformBuffers;
-        mContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
+        mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindingsCount ? bindings.uniformBufferBindings.Ptr() : nullptr, bindings.uniformBufferBindingsCount, bindings.standaloneUniformsBufferBinding);
         break;
       }
       case GLES::CommandType::BIND_INDEX_BUFFER:
       {
-        mContext->BindIndexBuffer(cmd.bindIndexBuffer);
+        mCurrentContext->BindIndexBuffer(cmd.bindIndexBuffer);
         break;
       }
       case GLES::CommandType::BIND_SAMPLERS:
@@ -342,22 +540,22 @@ void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuf
       case GLES::CommandType::BIND_PIPELINE:
       {
         auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
-        mContext->BindPipeline(pipeline);
+        mCurrentContext->BindPipeline(pipeline);
         break;
       }
       case GLES::CommandType::DRAW:
       {
-        mContext->Flush(false, cmd.draw);
+        mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
         break;
       }
       case GLES::CommandType::DRAW_INDEXED:
       {
-        mContext->Flush(false, cmd.draw);
+        mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
         break;
       }
       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
       {
-        mContext->Flush(false, cmd.draw);
+        mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
         break;
       }
       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
@@ -367,14 +565,7 @@ void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuf
       }
       case GLES::CommandType::SET_SCISSOR_TEST:
       {
-        if(cmd.scissorTest.enable)
-        {
-          mGlAbstraction->Enable(GL_SCISSOR_TEST);
-        }
-        else
-        {
-          mGlAbstraction->Disable(GL_SCISSOR_TEST);
-        }
+        mCurrentContext->SetScissorTestEnabled(cmd.scissorTest.enable);
         break;
       }
       case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
@@ -382,22 +573,110 @@ void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuf
         mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
         break;
       }
+
+      case GLES::CommandType::SET_COLOR_MASK:
+      {
+        mCurrentContext->ColorMask(cmd.colorMask.enabled);
+        break;
+      }
+      case GLES::CommandType::CLEAR_STENCIL_BUFFER:
+      {
+        mCurrentContext->ClearStencilBuffer();
+        break;
+      }
+      case GLES::CommandType::CLEAR_DEPTH_BUFFER:
+      {
+        mCurrentContext->ClearDepthBuffer();
+        break;
+      }
+
+      case GLES::CommandType::SET_STENCIL_TEST_ENABLE:
+      {
+        mCurrentContext->SetStencilTestEnable(cmd.stencilTest.enabled);
+        break;
+      }
+
+      case GLES::CommandType::SET_STENCIL_FUNC:
+      {
+        mCurrentContext->StencilFunc(cmd.stencilFunc.compareOp,
+                                     cmd.stencilFunc.reference,
+                                     cmd.stencilFunc.compareMask);
+        break;
+      }
+
+      case GLES::CommandType::SET_STENCIL_WRITE_MASK:
+      {
+        mCurrentContext->StencilMask(cmd.stencilWriteMask.mask);
+        break;
+      }
+
+      case GLES::CommandType::SET_STENCIL_OP:
+      {
+        mCurrentContext->StencilOp(cmd.stencilOp.failOp,
+                                   cmd.stencilOp.depthFailOp,
+                                   cmd.stencilOp.passOp);
+        break;
+      }
+
+      case GLES::CommandType::SET_DEPTH_COMPARE_OP:
+      {
+        mCurrentContext->SetDepthCompareOp(cmd.depth.compareOp);
+        break;
+      }
+      case GLES::CommandType::SET_DEPTH_TEST_ENABLE:
+      {
+        mCurrentContext->SetDepthTestEnable(cmd.depth.testEnabled);
+        break;
+      }
+      case GLES::CommandType::SET_DEPTH_WRITE_ENABLE:
+      {
+        mCurrentContext->SetDepthWriteEnable(cmd.depth.writeEnabled);
+        break;
+      }
+
       case GLES::CommandType::BEGIN_RENDERPASS:
       {
-        mContext->BeginRenderPass(cmd.beginRenderPass);
+        auto&       renderTarget = *cmd.beginRenderPass.renderTarget;
+        const auto& targetInfo   = renderTarget.GetCreateInfo();
+
+        if(targetInfo.surface)
+        {
+          // switch to surface context
+          mGraphics->ActivateSurfaceContext(static_cast<Dali::RenderSurfaceInterface*>(targetInfo.surface));
+        }
+        else if(targetInfo.framebuffer)
+        {
+          // switch to resource context
+          mGraphics->ActivateResourceContext();
+        }
+
+        mCurrentContext->BeginRenderPass(cmd.beginRenderPass);
+
         break;
       }
       case GLES::CommandType::END_RENDERPASS:
       {
-        mContext->EndRenderPass();
+        mCurrentContext->EndRenderPass(mTextureDependencyChecker);
+
+        // This sync object is to enable cpu to wait for rendering to complete, not gpu.
+        // It's only needed for reading the framebuffer texture in the client.
+        auto syncObject = const_cast<GLES::SyncObject*>(static_cast<const GLES::SyncObject*>(cmd.endRenderPass.syncObject));
+        if(syncObject)
+        {
+          syncObject->InitializeResource();
+        }
         break;
       }
       case GLES::CommandType::PRESENT_RENDER_TARGET:
       {
         ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
 
-        // push this command buffer to the discard queue
-        mDiscardCommandBufferQueue.push(&commandBuffer);
+        // The command buffer will be pushed into the queue of presentation command buffers
+        // for further reuse.
+        if(commandBuffer.GetCreateInfo().fixedCapacity == 1)
+        {
+          mPresentationCommandBuffers.push(&commandBuffer);
+        }
         break;
       }
       case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
@@ -406,32 +685,58 @@ void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuf
         // todo: check validity of the secondaries
         //       there are operations which are illigal to be done
         //       within secondaries.
-        for(auto& buf : cmd.executeCommandBuffers.buffers)
+        auto buffers = cmd.executeCommandBuffers.buffers.Ptr();
+        for(auto j = 0u; j < cmd.executeCommandBuffers.buffersCount; ++j)
         {
-          ProcessCommandBuffer(*static_cast<GLES::CommandBuffer*>(buf));
+          auto& buf = buffers[j];
+          ProcessCommandBuffer(*static_cast<const GLES::CommandBuffer*>(buf));
         }
         break;
       }
+      case GLES::CommandType::DRAW_NATIVE:
+      {
+        auto* info = &cmd.drawNative.drawNativeInfo;
+
+        mCurrentContext->PrepareForNativeRendering();
+
+        if(info->glesNativeInfo.eglSharedContextStoragePointer)
+        {
+          auto* anyContext = reinterpret_cast<std::any*>(info->glesNativeInfo.eglSharedContextStoragePointer);
+          *anyContext      = mSharedContext;
+        }
+
+        CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
+
+        mCurrentContext->RestoreFromNativeRendering();
+        break;
+      }
     }
   }
+  DALI_TRACE_END(gTraceFilter, "DALI_EGL_CONTROLLER_PROCESS");
 }
 
 void EglGraphicsController::ProcessCommandQueues()
 {
-  // TODO: command queue per context, sync between queues should be
-  // done externally
-  currentFramebuffer = nullptr;
+  DUMP_FRAME_START();
 
   while(!mCommandQueue.empty())
   {
     auto cmdBuf = mCommandQueue.front();
     mCommandQueue.pop();
+    DUMP_FRAME_COMMAND_BUFFER(cmdBuf);
     ProcessCommandBuffer(*cmdBuf);
   }
+
+  DUMP_FRAME_END();
 }
 
 void EglGraphicsController::ProcessTextureUpdateQueue()
 {
+  if(mTextureUpdateRequests.empty())
+  {
+    return;
+  }
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_TEXTURE_UPDATE");
   while(!mTextureUpdateRequests.empty())
   {
     TextureUpdateRequest& request = mTextureUpdateRequests.front();
@@ -439,31 +744,145 @@ void EglGraphicsController::ProcessTextureUpdateQueue()
     auto& info   = request.first;
     auto& source = request.second;
 
-    if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
-    {
-      // GPU memory must be already allocated (glTexImage2D())
-      auto*       texture    = static_cast<GLES::Texture*>(info.dstTexture);
-      const auto& createInfo = texture->GetCreateInfo();
-
-      mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
-      mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
-      mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
-                                    info.level,
-                                    info.dstOffset2D.x,
-                                    info.dstOffset2D.y,
-                                    info.srcExtent2D.width,
-                                    info.srcExtent2D.height,
-                                    GLES::GLTextureFormatType(createInfo.format).format,
-                                    GLES::GLTextureFormatType(createInfo.format).type,
-                                    source.memorySource.memory);
-
-      // free staging memory
-      free(source.memorySource.memory);
-    }
-    else
+    switch(source.sourceType)
     {
-      // TODO: other sources
+      case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
+      case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
+      {
+        // GPU memory must be already allocated.
+
+        // Check if it needs conversion
+        auto*       texture            = static_cast<GLES::Texture*>(info.dstTexture);
+        const auto& createInfo         = texture->GetCreateInfo();
+        auto        srcFormat          = GLES::GLTextureFormatType(info.srcFormat).format;
+        auto        srcType            = GLES::GLTextureFormatType(info.srcFormat).type;
+        auto        destInternalFormat = GLES::GLTextureFormatType(createInfo.format).internalFormat;
+        auto        destFormat         = GLES::GLTextureFormatType(createInfo.format).format;
+
+        // From render-texture.cpp
+        const bool isSubImage(info.dstOffset2D.x != 0 || info.dstOffset2D.y != 0 ||
+                              info.srcExtent2D.width != (createInfo.size.width / (1 << info.level)) ||
+                              info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
+
+        uint8_t* sourceBuffer                = nullptr;
+        bool     sourceBufferReleaseRequired = false;
+        if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
+        {
+          sourceBuffer                = reinterpret_cast<uint8_t*>(source.memorySource.memory);
+          sourceBufferReleaseRequired = true;
+        }
+        else
+        {
+          Dali::Integration::PixelDataBuffer pixelBufferData = Dali::Integration::GetPixelDataBuffer(source.pixelDataSource.pixelData);
+
+          sourceBuffer                = pixelBufferData.buffer + info.srcOffset;
+          sourceBufferReleaseRequired = Dali::Integration::IsPixelDataReleaseAfterUpload(source.pixelDataSource.pixelData) && info.srcOffset == 0u;
+        }
+
+        auto                 sourceStride = info.srcStride;
+        std::vector<uint8_t> tempBuffer;
+
+        if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
+        {
+          // Convert RGB to RGBA if necessary.
+          if(texture->TryConvertPixelData(sourceBuffer, info.srcFormat, createInfo.format, info.srcSize, info.srcStride, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer))
+          {
+            sourceBuffer = &tempBuffer[0];
+            sourceStride = 0u; // Converted buffer compacted. make stride as 0.
+            srcFormat    = destFormat;
+            srcType      = GLES::GLTextureFormatType(createInfo.format).type;
+          }
+        }
+
+        // Calculate the maximum mipmap level for the texture
+        texture->SetMaxMipMapLevel(std::max(texture->GetMaxMipMapLevel(), info.level));
+
+        GLenum bindTarget{GL_TEXTURE_2D};
+        GLenum target{GL_TEXTURE_2D};
+
+        if(createInfo.textureType == Graphics::TextureType::TEXTURE_CUBEMAP)
+        {
+          bindTarget = GL_TEXTURE_CUBE_MAP;
+          target     = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.layer;
+        }
+
+        mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
+
+        mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
+
+        if(!isSubImage)
+        {
+          if(!texture->IsCompressed())
+          {
+            mGlAbstraction->TexImage2D(target,
+                                       info.level,
+                                       destInternalFormat,
+                                       info.srcExtent2D.width,
+                                       info.srcExtent2D.height,
+                                       0,
+                                       srcFormat,
+                                       srcType,
+                                       sourceBuffer);
+          }
+          else
+          {
+            mGlAbstraction->CompressedTexImage2D(target,
+                                                 info.level,
+                                                 destInternalFormat,
+                                                 info.srcExtent2D.width,
+                                                 info.srcExtent2D.height,
+                                                 0,
+                                                 info.srcSize,
+                                                 sourceBuffer);
+          }
+        }
+        else
+        {
+          if(!texture->IsCompressed())
+          {
+            mGlAbstraction->TexSubImage2D(target,
+                                          info.level,
+                                          info.dstOffset2D.x,
+                                          info.dstOffset2D.y,
+                                          info.srcExtent2D.width,
+                                          info.srcExtent2D.height,
+                                          srcFormat,
+                                          srcType,
+                                          sourceBuffer);
+          }
+          else
+          {
+            mGlAbstraction->CompressedTexSubImage2D(target,
+                                                    info.level,
+                                                    info.dstOffset2D.x,
+                                                    info.dstOffset2D.y,
+                                                    info.srcExtent2D.width,
+                                                    info.srcExtent2D.height,
+                                                    srcFormat,
+                                                    info.srcSize,
+                                                    sourceBuffer);
+          }
+        }
+
+        if(sourceBufferReleaseRequired && sourceBuffer != nullptr)
+        {
+          if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
+          {
+            free(reinterpret_cast<void*>(sourceBuffer));
+          }
+          else
+          {
+            Dali::Integration::ReleasePixelDataBuffer(source.pixelDataSource.pixelData);
+          }
+        }
+        break;
+      }
+      default:
+      {
+        // TODO: other sources
+        break;
+      }
     }
 
     mTextureUpdateRequests.pop();
@@ -489,15 +908,24 @@ void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&
         // TODO: using PBO with GLES3, this is just naive
         // oldschool way
 
-        char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
-        std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
-                  reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
-                  stagingBuffer);
+        uint8_t* stagingBuffer = reinterpret_cast<uint8_t*>(malloc(info.srcSize));
+
+        uint8_t* srcMemory = &reinterpret_cast<uint8_t*>(source.memorySource.memory)[info.srcOffset];
+
+        std::copy(srcMemory, srcMemory + info.srcSize, stagingBuffer);
+
+        mTextureUploadTotalCPUMemoryUsed += info.srcSize;
 
         // store staging buffer
         source.memorySource.memory = stagingBuffer;
         break;
       }
+      case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
+      {
+        // Increase CPU memory usage since ownership of PixelData is now on mTextureUpdateRequests.
+        mTextureUploadTotalCPUMemoryUsed += info.srcSize;
+        break;
+      }
       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
       {
         // TODO, with PBO support
@@ -510,16 +938,48 @@ void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&
       }
     }
   }
+
+  // If upload buffer exceeds maximum size, flush.
+  if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024 * 1024)
+  {
+    Flush();
+    mTextureUploadTotalCPUMemoryUsed = 0;
+  }
 }
 
-Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
+void EglGraphicsController::ProcessTextureMipmapGenerationQueue()
+{
+  if(mTextureMipmapGenerationRequests.empty())
+  {
+    return;
+  }
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_EGL_CONTROLLER_TEXTURE_MIPMAP");
+  while(!mTextureMipmapGenerationRequests.empty())
+  {
+    auto* texture = mTextureMipmapGenerationRequests.front();
+
+    mCurrentContext->BindTexture(texture->GetGlTarget(), texture->GetTextureTypeId(), texture->GetGLTexture());
+    mCurrentContext->GenerateMipmap(texture->GetGlTarget());
+
+    mTextureMipmapGenerationRequests.pop();
+  }
+}
+
+void EglGraphicsController::GenerateTextureMipmaps(const Graphics::Texture& texture)
 {
-  mGraphics->ActivateResourceContext();
+  mTextureMipmapGenerationRequests.push(static_cast<const GLES::Texture*>(&texture));
+}
 
+Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
+{
   // Mapping buffer requires the object to be created NOW
   // Workaround - flush now, otherwise there will be given a staging buffer
   // in case when the buffer is not there yet
-  ProcessCreateQueues();
+  if(!mCreateBufferQueue.empty())
+  {
+    mGraphics->ActivateResourceContext();
+    ProcessCreateQueues();
+  }
 
   if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
   {
@@ -541,4 +1001,57 @@ GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
   return *mPipelineCache;
 }
 
+Graphics::Texture* EglGraphicsController::CreateTextureByResourceId(uint32_t resourceId, const Graphics::TextureCreateInfo& createInfo)
+{
+  Graphics::Texture*                     ret = nullptr;
+  Graphics::UniquePtr<Graphics::Texture> texture;
+
+  auto iter = mExternalTextureResources.find(resourceId);
+  DALI_ASSERT_ALWAYS(iter == mExternalTextureResources.end());
+
+  texture = CreateTexture(createInfo, std::move(texture));
+
+  ret = texture.get();
+
+  mExternalTextureResources.insert(std::make_pair(resourceId, std::move(texture)));
+
+  return ret;
+}
+
+void EglGraphicsController::DiscardTextureFromResourceId(uint32_t resourceId)
+{
+  auto iter = mExternalTextureResources.find(resourceId);
+  if(iter != mExternalTextureResources.end())
+  {
+    mExternalTextureResources.erase(iter);
+  }
+}
+
+Graphics::Texture* EglGraphicsController::GetTextureFromResourceId(uint32_t resourceId)
+{
+  Graphics::Texture* ret = nullptr;
+
+  auto iter = mExternalTextureResources.find(resourceId);
+  if(iter != mExternalTextureResources.end())
+  {
+    ret = iter->second.get();
+  }
+
+  return ret;
+}
+
+Graphics::UniquePtr<Graphics::Texture> EglGraphicsController::ReleaseTextureFromResourceId(uint32_t resourceId)
+{
+  Graphics::UniquePtr<Graphics::Texture> texture;
+
+  auto iter = mExternalTextureResources.find(resourceId);
+  if(iter != mExternalTextureResources.end())
+  {
+    texture = std::move(iter->second);
+    mExternalTextureResources.erase(iter);
+  }
+
+  return texture;
+}
+
 } // namespace Dali::Graphics