[Tizen] Support to get raw pixel informations of framebuffer for old driver device
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / egl-graphics-controller.cpp
index 545c257..1f8979f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
 #include <dali/internal/graphics/gles/egl-sync-implementation.h>
 #include <dali/public-api/common/dali-common.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>
@@ -105,7 +109,21 @@ const uint32_t TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB = 1;
 
 } // 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)
 {
@@ -144,11 +162,20 @@ void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
 
 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};
@@ -158,6 +185,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)
   {
@@ -167,6 +196,12 @@ void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* rende
   }
 }
 
+void EglGraphicsController::PostRender()
+{
+  mTextureDependencyChecker.Reset();
+  mSyncPool.AgeSyncObjects();
+}
+
 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
 {
   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
@@ -267,6 +302,21 @@ Graphics::UniquePtr<SyncObject> EglGraphicsController::CreateSyncObject(const Sy
   }
 }
 
+TextureProperties EglGraphicsController::GetTextureProperties(const Texture& texture)
+{
+  const GLES::Texture* glesTexture = static_cast<const GLES::Texture*>(&texture);
+  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();
@@ -289,6 +339,15 @@ 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)
@@ -336,6 +395,12 @@ void EglGraphicsController::ProcessDiscardQueues()
   // Process Framebuffers
   ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
 
+  // Process RenderPass
+  ProcessDiscardQueue<GLES::RenderPass>(mDiscardRenderPassQueue);
+
+  // Process RenderTarget
+  ProcessDiscardQueue<GLES::RenderTarget>(mDiscardRenderTargetQueue);
+
   // Process pipelines
   ProcessDiscardQueue(mDiscardPipelineQueue);
 
@@ -366,8 +431,11 @@ void EglGraphicsController::ProcessCreateQueues()
 
 void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& commandBuffer)
 {
-  for(auto& cmd : commandBuffer.GetCommands())
+  auto       count    = 0u;
+  const auto commands = commandBuffer.GetCommands(count);
+  for(auto i = 0u; i < count; ++i)
   {
+    auto& cmd = commands[i];
     // process command
     switch(cmd.type)
     {
@@ -378,19 +446,19 @@ void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& comm
       }
       case GLES::CommandType::BIND_TEXTURES:
       {
-        mCurrentContext->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;
-        mCurrentContext->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;
-        mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
+        mCurrentContext->BindUniformBuffers(bindings.uniformBufferBindingsCount ? bindings.uniformBufferBindings.Ptr() : nullptr, bindings.uniformBufferBindingsCount, bindings.standaloneUniformsBufferBinding);
         break;
       }
       case GLES::CommandType::BIND_INDEX_BUFFER:
@@ -410,17 +478,17 @@ void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& comm
       }
       case GLES::CommandType::DRAW:
       {
-        mCurrentContext->Flush(false, cmd.draw);
+        mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
         break;
       }
       case GLES::CommandType::DRAW_INDEXED:
       {
-        mCurrentContext->Flush(false, cmd.draw);
+        mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
         break;
       }
       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
       {
-        mCurrentContext->Flush(false, cmd.draw);
+        mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
         break;
       }
       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
@@ -516,12 +584,15 @@ void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& comm
         }
 
         mCurrentContext->BeginRenderPass(cmd.beginRenderPass);
+
         break;
       }
       case GLES::CommandType::END_RENDERPASS:
       {
-        mCurrentContext->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)
         {
@@ -533,8 +604,12 @@ void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& comm
       {
         ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
 
-        // push this command buffer to the discard queue
-        mDiscardCommandBufferQueue.push(const_cast<GLES::CommandBuffer*>(&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:
@@ -543,22 +618,37 @@ void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& comm
         // 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)
         {
+          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;
+      }
     }
   }
 }
 
 void EglGraphicsController::ProcessCommandQueues()
 {
-  // TODO: command queue per context, sync between queues should be
-  // done externally
-  currentFramebuffer = nullptr;
-
   DUMP_FRAME_START();
 
   while(!mCommandQueue.empty())
@@ -599,14 +689,19 @@ void EglGraphicsController::ProcessTextureUpdateQueue()
                             info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
 
       auto*                sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
+      auto                 sourceStride = info.srcStride;
       std::vector<uint8_t> tempBuffer;
+
       if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
       {
         // Convert RGB to RGBA if necessary.
-        texture->TryConvertPixelData(source.memorySource.memory, info.srcFormat, createInfo.format, info.srcSize, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer);
-        sourceBuffer = &tempBuffer[0];
-        srcFormat    = destFormat;
-        srcType      = GLES::GLTextureFormatType(createInfo.format).type;
+        if(texture->TryConvertPixelData(source.memorySource.memory, 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
@@ -622,6 +717,8 @@ void EglGraphicsController::ProcessTextureUpdateQueue()
       }
 
       mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+      mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
+
       mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
 
       if(!isSubImage)
@@ -708,10 +805,11 @@ 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;
 
@@ -733,7 +831,7 @@ void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&
   }
 
   // If upload buffer exceeds maximum size, flush.
-  if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024)
+  if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024 * 1024)
   {
     Flush();
     mTextureUploadTotalCPUMemoryUsed = 0;
@@ -787,4 +885,9 @@ GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
   return *mPipelineCache;
 }
 
+void EglGraphicsController::CaptureRenderingResult(Graphics::Framebuffer& framebuffer, CallbackBase* capturedCallback, uint8_t* capturedBuffer)
+{
+  static_cast<GLES::Framebuffer*>(&framebuffer)->CaptureRenderingResult(capturedCallback, capturedBuffer);
+}
+
 } // namespace Dali::Graphics