Memory Pool Logging
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-command-buffer.cpp
index 83f010e..bc463ab 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.
 
 namespace Dali::Graphics::GLES
 {
+class CommandPool
+{
+  static constexpr uint32_t COMMAND_POOL_DEFAULT_INCREMENT = 1024 * 32 / sizeof(Command); // 32kb banks
+  static const uint32_t     MEMORY_POOL_DEFAULT_INCREMENT  = 1024;                        // 1kb memory pool increment
+  static const uint32_t     MEMORY_POOL_DEFAULT_ALIGNMENT  = 64;                          // 64bytes alignment
+
+  template<class T>
+  struct Block
+  {
+    Block() = default;
+    ~Block()
+    {
+      if(ptr)
+      {
+        free(ptr);
+      }
+    }
+
+    T*        ptr{nullptr};
+    uint32_t  dataSize{0u};
+    uint32_t  capacity{0u};
+    inline T& operator[](int index) const
+    {
+      return ptr[index];
+    }
+
+    inline void clear()
+    {
+      free(ptr);
+      capacity = 0;
+      dataSize = 0;
+    }
+
+    inline void resize(int newSize)
+    {
+      ptr      = reinterpret_cast<T*>(realloc(ptr, newSize * sizeof(T)));
+      capacity = newSize * sizeof(T);
+      dataSize = newSize;
+    }
+
+    inline T* data() const
+    {
+      return ptr;
+    }
+
+    inline uint32_t size() const
+    {
+      return dataSize;
+    }
+  };
+  // This memory pool guarantees all items will be placed
+  // in the continuous memory area but returned pointers are relative
+  // and require translation before using
+  template<class T, int Increment, int Alignment = 0>
+  struct MemoryPool
+  {
+    Block<T>  data;
+    inline T& operator[](int index)
+    {
+      return data[index];
+    }
+    MemoryPool() = default;
+
+    IndirectPtr<T> Allocate(uint32_t count)
+    {
+      // Set fixed capacity
+      if(fixedCapacity)
+      {
+        // resize data size when capacity is not setuped.
+        // Note if totalCapacity is bigger than fixedCapacity,
+        // just skip here and resize dynamically
+        if(DALI_UNLIKELY(totalCapacity < fixedCapacity))
+        {
+          data.resize(fixedCapacity);
+          totalCapacity = data.size();
+        }
+      }
+
+      // Resize dynamically
+      if(DALI_UNLIKELY(totalCapacity < offset + count))
+      {
+        // Resize the memory size as ceil((offset + count - totalCapacity)) / Increment) * Increment
+        // So the incremented size of data is always multiplied of the value Increment.
+        data.resize(data.size() + ((offset + count - totalCapacity - 1) / Increment + 1) * Increment);
+
+        // update base pointer, required for address translation
+        totalCapacity = data.size();
+      }
+
+      basePtr = data.data();
+
+      IndirectPtr<T> retval{uint32_t(uintptr_t(&data[offset]) - uintptr_t(basePtr)), &basePtr};
+      size += count;
+      offset += count;
+
+      // align offset if needed (only if type size is 1)
+      if(Alignment && sizeof(T) == 1)
+      {
+        offset = ((offset / Alignment) * Alignment) + ((offset % Alignment) ? Alignment : 0);
+      }
+      return retval;
+    }
+
+    // Rolls back pool
+    void Rollback()
+    {
+      offset = 0;
+      size   = 0;
+    }
+
+    // Discards all data and storage
+    void Clear()
+    {
+      data.clear();
+      totalCapacity = 0;
+      offset        = 0;
+      size          = 0;
+    }
+
+    uint32_t offset{0u};
+    uint32_t totalCapacity{0u};
+    uint32_t size{0u};
+    uint32_t increment{Increment};
+    uint32_t alignment{Alignment};
+    uint32_t fixedCapacity{0u};
+    void*    basePtr{nullptr};
+  };
+
+  MemoryPool<uint8_t, MEMORY_POOL_DEFAULT_INCREMENT, MEMORY_POOL_DEFAULT_ALIGNMENT>  memoryPool;
+  MemoryPool<Command, COMMAND_POOL_DEFAULT_INCREMENT, MEMORY_POOL_DEFAULT_ALIGNMENT> commandPool;
+
+public:
+  CommandPool() = default;
+  CommandPool(uint32_t fixedCapacity)
+  {
+    commandPool.fixedCapacity = fixedCapacity;
+    memoryPool.fixedCapacity  = fixedCapacity * 1024;
+  }
+
+  /**
+   * Return value may become invalid if pool is resized (by allocating another command)
+   * @param type
+   * @return
+   */
+  Command* AllocateCommand(CommandType type)
+  {
+    auto command  = commandPool.Allocate(1);
+    command->type = type;
+    auto* cmd     = command.Ptr();
+    return cmd;
+  }
+
+  template<class T>
+  IndirectPtr<T> Allocate(uint32_t count)
+  {
+    const auto typeSize       = sizeof(T);
+    const auto memoryRequired = typeSize * count;
+    auto       ptr            = memoryPool.Allocate(memoryRequired);
+
+    // Convert generic pointer and return
+    return IndirectPtr<T>{ptr.ptr, ptr.base};
+  }
+
+  // New (should not be needed)
+  template<class T>
+  T* New(uint32_t count)
+  {
+    auto ptr = Allocate<T>(count);
+    for(auto i = 0u; i < count; ++i)
+    {
+      new(&ptr[i]) T();
+    }
+    return ptr;
+  }
+
+  // TODO: explicit delete?
+  void Rollback(bool discard)
+  {
+    if(discard)
+    {
+      commandPool.Clear();
+      memoryPool.Clear();
+    }
+    else
+    {
+      commandPool.Rollback();
+      memoryPool.Rollback();
+    }
+  }
+
+  const Command* GetCommands(uint32_t& size) const
+  {
+    size = commandPool.size;
+    return commandPool.data.ptr;
+  }
+
+  std::size_t GetTotalCapacity() const
+  {
+    return commandPool.data.capacity + memoryPool.data.capacity;
+  }
+};
+
 CommandBuffer::CommandBuffer(const Graphics::CommandBufferCreateInfo& createInfo, EglGraphicsController& controller)
 : CommandBufferResource(createInfo, controller)
 {
+  mCommandPool = std::make_unique<CommandPool>(createInfo.fixedCapacity);
 }
 
 CommandBuffer::~CommandBuffer() = default;
 
-void CommandBuffer::BindVertexBuffers(uint32_t                             firstBinding,
-                                      std::vector<const Graphics::Buffer*> buffers,
-                                      std::vector<uint32_t>                offsets)
+void CommandBuffer::BindVertexBuffers(uint32_t                                    firstBinding,
+                                      const std::vector<const Graphics::Buffer*>& buffers,
+                                      const std::vector<uint32_t>&                offsets)
 {
-  mCommands.emplace_back(CommandType::BIND_VERTEX_BUFFERS);
-  auto& bindings = mCommands.back().bindVertexBuffers.vertexBufferBindings;
-  if(bindings.size() < firstBinding + buffers.size())
+  auto command                                         = mCommandPool->AllocateCommand(CommandType::BIND_VERTEX_BUFFERS);
+  command->bindVertexBuffers.vertexBufferBindingsCount = firstBinding + static_cast<uint32_t>(buffers.size());
+  auto pBindings                                       = mCommandPool->Allocate<GLES::VertexBufferBindingDescriptor>(firstBinding + buffers.size());
+
+  command->bindVertexBuffers.vertexBufferBindings = pBindings;
+  auto index                                      = firstBinding;
+  for(auto& buf : buffers)
   {
-    bindings.resize(firstBinding + buffers.size());
-    auto index = firstBinding;
-    for(auto& buf : buffers)
-    {
-      bindings[index].buffer = static_cast<const GLES::Buffer*>(buf);
-      bindings[index].offset = offsets[index - firstBinding];
-      index++;
-    }
+    pBindings[index].buffer = static_cast<const GLES::Buffer*>(buf);
+    pBindings[index].offset = offsets[index - firstBinding];
+    index++;
   }
 }
 
 void CommandBuffer::BindUniformBuffers(const std::vector<Graphics::UniformBufferBinding>& bindings)
 {
-  mCommands.emplace_back(CommandType::BIND_UNIFORM_BUFFER);
-  auto& cmd     = mCommands.back();
+  auto command = mCommandPool->AllocateCommand(CommandType::BIND_UNIFORM_BUFFER);
+
+  auto& cmd     = *command;
   auto& bindCmd = cmd.bindUniformBuffers;
+
+  // temporary static set of binding slots (thread local)
+  static const auto MAX_UNIFORM_BUFFER_BINDINGS = 64; // TODO: this should be read from introspection
+
+  // TODO: could use vector?
+  static thread_local UniformBufferBindingDescriptor sTempBindings[MAX_UNIFORM_BUFFER_BINDINGS];
+
+  // reset temp bindings
+  memset(sTempBindings, 0, sizeof(UniformBufferBindingDescriptor) * MAX_UNIFORM_BUFFER_BINDINGS);
+
+  auto maxBinding = 0u;
+
+  // find max binding and standalone UBO
   for(const auto& binding : bindings)
   {
     if(binding.buffer)
@@ -74,37 +290,51 @@ void CommandBuffer::BindUniformBuffers(const std::vector<Graphics::UniformBuffer
       }
       else // Bind regular UBO
       {
-        // resize binding slots
-        if(binding.binding >= bindCmd.uniformBufferBindings.size())
-        {
-          bindCmd.uniformBufferBindings.resize(binding.binding + 1);
-        }
-        auto& slot    = bindCmd.uniformBufferBindings[binding.binding];
+        auto& slot    = sTempBindings[binding.binding];
         slot.buffer   = glesBuffer;
         slot.offset   = binding.offset;
         slot.binding  = binding.binding;
         slot.emulated = false;
+        maxBinding    = std::max(maxBinding, binding.binding);
       }
     }
   }
+  bindCmd.uniformBufferBindings      = nullptr;
+  bindCmd.uniformBufferBindingsCount = 0u;
+
+  // copy data
+  if(maxBinding)
+  {
+    auto destBindings = mCommandPool->Allocate<UniformBufferBindingDescriptor>(maxBinding + 1);
+    // copy
+    memcpy(destBindings.Ptr(), sTempBindings, sizeof(UniformBufferBindingDescriptor) * (maxBinding + 1));
+    bindCmd.uniformBufferBindings      = destBindings;
+    bindCmd.uniformBufferBindingsCount = maxBinding + 1;
+  }
 }
 
 void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
 {
-  mCommands.emplace_back(CommandType::BIND_PIPELINE);
-  mCommands.back().bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
+  auto command                   = mCommandPool->AllocateCommand(CommandType::BIND_PIPELINE);
+  command->bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
 }
 
-void CommandBuffer::BindTextures(std::vector<TextureBinding>& textureBindings)
+void CommandBuffer::BindTextures(const std::vector<TextureBinding>& textureBindings)
 {
-  mCommands.emplace_back(CommandType::BIND_TEXTURES);
-  mCommands.back().bindTextures.textureBindings = std::move(textureBindings);
+  auto  command                        = mCommandPool->AllocateCommand(CommandType::BIND_TEXTURES);
+  auto& bindTexturesCmd                = command->bindTextures;
+  bindTexturesCmd.textureBindings      = mCommandPool->Allocate<TextureBinding>(textureBindings.size());
+  bindTexturesCmd.textureBindingsCount = textureBindings.size();
+  memcpy(bindTexturesCmd.textureBindings.Ptr(), textureBindings.data(), sizeof(TextureBinding) * textureBindings.size());
 }
 
-void CommandBuffer::BindSamplers(std::vector<SamplerBinding>& samplerBindings)
+void CommandBuffer::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
 {
-  mCommands.emplace_back(CommandType::BIND_SAMPLERS);
-  mCommands.back().bindSamplers.samplerBindings = std::move(samplerBindings);
+  auto  command                        = mCommandPool->AllocateCommand(CommandType::BIND_SAMPLERS);
+  auto& bindSamplersCmd                = command->bindSamplers;
+  bindSamplersCmd.samplerBindings      = mCommandPool->Allocate<SamplerBinding>(samplerBindings.size());
+  bindSamplersCmd.samplerBindingsCount = samplerBindings.size();
+  memcpy(bindSamplersCmd.samplerBindings.Ptr(), samplerBindings.data(), sizeof(TextureBinding) * samplerBindings.size());
 }
 
 void CommandBuffer::BindPushConstants(void*    data,
@@ -117,39 +347,44 @@ void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& buffer,
                                     uint32_t                offset,
                                     Format                  format)
 {
-  mCommands.emplace_back(CommandType::BIND_INDEX_BUFFER);
-  mCommands.back().bindIndexBuffer.buffer = static_cast<const GLES::Buffer*>(&buffer);
-  mCommands.back().bindIndexBuffer.offset = offset;
-  mCommands.back().bindIndexBuffer.format = format;
+  auto command                    = mCommandPool->AllocateCommand(CommandType::BIND_INDEX_BUFFER);
+  command->bindIndexBuffer.buffer = static_cast<const GLES::Buffer*>(&buffer);
+  command->bindIndexBuffer.offset = offset;
+  command->bindIndexBuffer.format = format;
 }
 
 void CommandBuffer::BeginRenderPass(
-  Graphics::RenderPass*   renderPass,
-  Graphics::RenderTarget* renderTarget,
-  Rect2D                  renderArea,
-  std::vector<ClearValue> clearValues)
+  Graphics::RenderPass*          renderPass,
+  Graphics::RenderTarget*        renderTarget,
+  Rect2D                         renderArea,
+  const std::vector<ClearValue>& clearValues)
 {
-  mCommands.emplace_back(CommandType::BEGIN_RENDERPASS);
-  auto& cmd                        = mCommands.back();
+  auto  command                    = mCommandPool->AllocateCommand(CommandType::BEGIN_RENDERPASS);
+  auto& cmd                        = *command;
   cmd.beginRenderPass.renderPass   = static_cast<GLES::RenderPass*>(renderPass);
   cmd.beginRenderPass.renderTarget = static_cast<GLES::RenderTarget*>(renderTarget);
   cmd.beginRenderPass.renderArea   = renderArea;
-  cmd.beginRenderPass.clearValues  = clearValues;
+
+  cmd.beginRenderPass.clearValues = mCommandPool->Allocate<ClearValue>(clearValues.size());
+  memcpy(cmd.beginRenderPass.clearValues.Ptr(), clearValues.data(), sizeof(ClearValue) * clearValues.size());
+  cmd.beginRenderPass.clearValuesCount = clearValues.size();
 }
 
-void CommandBuffer::EndRenderPass()
+void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject)
 {
-  mCommands.emplace_back(CommandType::END_RENDERPASS);
+  auto command                      = mCommandPool->AllocateCommand(CommandType::END_RENDERPASS);
+  command->endRenderPass.syncObject = static_cast<GLES::SyncObject*>(syncObject);
 }
 
 void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers)
 {
-  mCommands.emplace_back(CommandType::EXECUTE_COMMAND_BUFFERS);
-  auto& cmd = mCommands.back();
-  cmd.executeCommandBuffers.buffers.reserve(commandBuffers.size());
-  for(auto&& item : commandBuffers)
+  auto  command    = mCommandPool->AllocateCommand(CommandType::EXECUTE_COMMAND_BUFFERS);
+  auto& cmd        = command->executeCommandBuffers;
+  cmd.buffers      = mCommandPool->Allocate<const GLES::CommandBuffer*>(commandBuffers.size());
+  cmd.buffersCount = commandBuffers.size();
+  for(auto i = 0u; i < cmd.buffersCount; ++i)
   {
-    cmd.executeCommandBuffers.buffers.emplace_back(static_cast<const GLES::CommandBuffer*>(item));
+    cmd.buffers[i] = static_cast<const GLES::CommandBuffer*>(commandBuffers[i]);
   }
 }
 
@@ -159,8 +394,8 @@ void CommandBuffer::Draw(
   uint32_t firstVertex,
   uint32_t firstInstance)
 {
-  mCommands.emplace_back(CommandType::DRAW);
-  auto& cmd              = mCommands.back().draw;
+  auto  command          = mCommandPool->AllocateCommand(CommandType::DRAW);
+  auto& cmd              = command->draw;
   cmd.type               = DrawCallDescriptor::Type::DRAW;
   cmd.draw.vertexCount   = vertexCount;
   cmd.draw.instanceCount = instanceCount;
@@ -175,8 +410,8 @@ void CommandBuffer::DrawIndexed(
   int32_t  vertexOffset,
   uint32_t firstInstance)
 {
-  mCommands.emplace_back(CommandType::DRAW_INDEXED);
-  auto& cmd                     = mCommands.back().draw;
+  auto  command                 = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED);
+  auto& cmd                     = command->draw;
   cmd.type                      = DrawCallDescriptor::Type::DRAW_INDEXED;
   cmd.drawIndexed.firstIndex    = firstIndex;
   cmd.drawIndexed.firstInstance = firstInstance;
@@ -191,8 +426,8 @@ void CommandBuffer::DrawIndexedIndirect(
   uint32_t          drawCount,
   uint32_t          stride)
 {
-  mCommands.emplace_back(CommandType::DRAW_INDEXED_INDIRECT);
-  auto& cmd                         = mCommands.back().draw;
+  auto  command                     = mCommandPool->AllocateCommand(CommandType::DRAW_INDEXED_INDIRECT);
+  auto& cmd                         = command->draw;
   cmd.type                          = DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT;
   cmd.drawIndexedIndirect.buffer    = static_cast<const GLES::Buffer*>(&buffer);
   cmd.drawIndexedIndirect.offset    = offset;
@@ -200,27 +435,34 @@ void CommandBuffer::DrawIndexedIndirect(
   cmd.drawIndexedIndirect.stride    = stride;
 }
 
+void CommandBuffer::DrawNative(const DrawNativeInfo* drawNativeInfo)
+{
+  auto  command = mCommandPool->AllocateCommand(CommandType::DRAW_NATIVE);
+  auto& cmd     = command->drawNative;
+  memcpy(&cmd.drawNativeInfo, drawNativeInfo, sizeof(DrawNativeInfo));
+}
+
 void CommandBuffer::Reset()
 {
-  mCommands.clear();
+  mCommandPool->Rollback(false);
 }
 
 void CommandBuffer::SetScissor(Graphics::Rect2D value)
 {
-  mCommands.emplace_back(CommandType::SET_SCISSOR);
-  mCommands.back().scissor.region = value;
+  auto command            = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR);
+  command->scissor.region = value;
 }
 
 void CommandBuffer::SetScissorTestEnable(bool value)
 {
-  mCommands.emplace_back(CommandType::SET_SCISSOR_TEST);
-  mCommands.back().scissorTest.enable = value;
+  auto command                = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR_TEST);
+  command->scissorTest.enable = value;
 }
 
 void CommandBuffer::SetViewport(Viewport value)
 {
-  mCommands.emplace_back(CommandType::SET_VIEWPORT);
-  mCommands.back().viewport.region = value;
+  auto command             = mCommandPool->AllocateCommand(CommandType::SET_VIEWPORT);
+  command->viewport.region = value;
 }
 
 void CommandBuffer::SetViewportEnable(bool value)
@@ -228,15 +470,81 @@ void CommandBuffer::SetViewportEnable(bool value)
   // There is no GL equivalent
 }
 
+void CommandBuffer::SetColorMask(bool enabled)
+{
+  auto command               = mCommandPool->AllocateCommand(CommandType::SET_COLOR_MASK);
+  command->colorMask.enabled = enabled;
+}
+
+void CommandBuffer::ClearStencilBuffer()
+{
+  mCommandPool->AllocateCommand(CommandType::CLEAR_STENCIL_BUFFER);
+}
+
+void CommandBuffer::SetStencilTestEnable(bool stencilEnable)
+{
+  auto command                 = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_TEST_ENABLE);
+  command->stencilTest.enabled = stencilEnable;
+}
+
+void CommandBuffer::SetStencilWriteMask(uint32_t writeMask)
+{
+  auto command                   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_WRITE_MASK);
+  command->stencilWriteMask.mask = writeMask;
+}
+
+void CommandBuffer::SetStencilOp(Graphics::StencilOp failOp,
+                                 Graphics::StencilOp passOp,
+                                 Graphics::StencilOp depthFailOp)
+{
+  auto  command   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_OP);
+  auto& cmd       = command->stencilOp;
+  cmd.failOp      = failOp;
+  cmd.passOp      = passOp;
+  cmd.depthFailOp = depthFailOp;
+}
+
+void CommandBuffer::SetStencilFunc(Graphics::CompareOp compareOp,
+                                   uint32_t            reference,
+                                   uint32_t            compareMask)
+{
+  auto  command   = mCommandPool->AllocateCommand(CommandType::SET_STENCIL_FUNC);
+  auto& cmd       = command->stencilFunc;
+  cmd.compareOp   = compareOp;
+  cmd.compareMask = compareMask;
+  cmd.reference   = reference;
+}
+
+void CommandBuffer::SetDepthCompareOp(Graphics::CompareOp compareOp)
+{
+  auto command             = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_COMPARE_OP);
+  command->depth.compareOp = compareOp;
+}
+
+void CommandBuffer::SetDepthTestEnable(bool depthTestEnable)
+{
+  auto command               = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_TEST_ENABLE);
+  command->depth.testEnabled = depthTestEnable;
+}
+void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable)
+{
+  auto command                = mCommandPool->AllocateCommand(CommandType::SET_DEPTH_WRITE_ENABLE);
+  command->depth.writeEnabled = depthWriteEnable;
+}
+void CommandBuffer::ClearDepthBuffer()
+{
+  mCommandPool->AllocateCommand(CommandType::CLEAR_DEPTH_BUFFER);
+}
+
 void CommandBuffer::PresentRenderTarget(GLES::RenderTarget* renderTarget)
 {
-  mCommands.emplace_back(CommandType::PRESENT_RENDER_TARGET);
-  mCommands.back().presentRenderTarget.targetToPresent = renderTarget;
+  auto command                                 = mCommandPool->AllocateCommand(CommandType::PRESENT_RENDER_TARGET);
+  command->presentRenderTarget.targetToPresent = renderTarget;
 }
 
-[[nodiscard]] const std::vector<Command>& CommandBuffer::GetCommands() const
+[[nodiscard]] const Command* CommandBuffer::GetCommands(uint32_t& size) const
 {
-  return mCommands;
+  return mCommandPool->GetCommands(size);
 }
 
 void CommandBuffer::DestroyResource()
@@ -255,4 +563,14 @@ void CommandBuffer::DiscardResource()
   GetController().DiscardResource(this);
 }
 
+std::size_t CommandBuffer::GetCapacity()
+{
+  std::size_t total{0u};
+  if(mCommandPool)
+  {
+    total = mCommandPool->GetTotalCapacity();
+  }
+  return total;
+}
+
 } // namespace Dali::Graphics::GLES