Memory Pool Logging
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-command-buffer.cpp
index 70006da..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.
 
 // CLASS HEADER
 #include "gles-graphics-command-buffer.h"
+
+// INTERNAL INCLUDES
+#include "egl-graphics-controller.h"
+#include "gles-graphics-buffer.h"
+#include "gles-graphics-framebuffer.h"
+#include "gles-graphics-pipeline.h"
+#include "gles-graphics-render-pass.h"
+#include "gles-graphics-render-target.h"
+#include "gles-graphics-texture.h"
+
+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,
+                                      const std::vector<const Graphics::Buffer*>& buffers,
+                                      const std::vector<uint32_t>&                offsets)
+{
+  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)
+  {
+    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)
+{
+  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)
+    {
+      auto glesBuffer = static_cast<const GLES::Buffer*>(binding.buffer);
+      if(glesBuffer->IsCPUAllocated()) // standalone uniforms
+      {
+        bindCmd.standaloneUniformsBufferBinding.buffer   = glesBuffer;
+        bindCmd.standaloneUniformsBufferBinding.offset   = binding.offset;
+        bindCmd.standaloneUniformsBufferBinding.binding  = binding.binding;
+        bindCmd.standaloneUniformsBufferBinding.emulated = true;
+      }
+      else // Bind regular UBO
+      {
+        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)
+{
+  auto command                   = mCommandPool->AllocateCommand(CommandType::BIND_PIPELINE);
+  command->bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
+}
+
+void CommandBuffer::BindTextures(const std::vector<TextureBinding>& 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(const std::vector<SamplerBinding>& 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,
+                                      uint32_t size,
+                                      uint32_t binding)
+{
+}
+
+void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& buffer,
+                                    uint32_t                offset,
+                                    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,
+  const std::vector<ClearValue>& clearValues)
+{
+  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 = mCommandPool->Allocate<ClearValue>(clearValues.size());
+  memcpy(cmd.beginRenderPass.clearValues.Ptr(), clearValues.data(), sizeof(ClearValue) * clearValues.size());
+  cmd.beginRenderPass.clearValuesCount = clearValues.size();
+}
+
+void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject)
+{
+  auto command                      = mCommandPool->AllocateCommand(CommandType::END_RENDERPASS);
+  command->endRenderPass.syncObject = static_cast<GLES::SyncObject*>(syncObject);
+}
+
+void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& 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.buffers[i] = static_cast<const GLES::CommandBuffer*>(commandBuffers[i]);
+  }
+}
+
+void CommandBuffer::Draw(
+  uint32_t vertexCount,
+  uint32_t instanceCount,
+  uint32_t firstVertex,
+  uint32_t firstInstance)
+{
+  auto  command          = mCommandPool->AllocateCommand(CommandType::DRAW);
+  auto& cmd              = command->draw;
+  cmd.type               = DrawCallDescriptor::Type::DRAW;
+  cmd.draw.vertexCount   = vertexCount;
+  cmd.draw.instanceCount = instanceCount;
+  cmd.draw.firstInstance = firstInstance;
+  cmd.draw.firstVertex   = firstVertex;
+}
+
+void CommandBuffer::DrawIndexed(
+  uint32_t indexCount,
+  uint32_t instanceCount,
+  uint32_t firstIndex,
+  int32_t  vertexOffset,
+  uint32_t firstInstance)
+{
+  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;
+  cmd.drawIndexed.indexCount    = indexCount;
+  cmd.drawIndexed.vertexOffset  = vertexOffset;
+  cmd.drawIndexed.instanceCount = instanceCount;
+}
+
+void CommandBuffer::DrawIndexedIndirect(
+  Graphics::Buffer& buffer,
+  uint32_t          offset,
+  uint32_t          drawCount,
+  uint32_t          stride)
+{
+  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;
+  cmd.drawIndexedIndirect.drawCount = drawCount;
+  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()
+{
+  mCommandPool->Rollback(false);
+}
+
+void CommandBuffer::SetScissor(Graphics::Rect2D value)
+{
+  auto command            = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR);
+  command->scissor.region = value;
+}
+
+void CommandBuffer::SetScissorTestEnable(bool value)
+{
+  auto command                = mCommandPool->AllocateCommand(CommandType::SET_SCISSOR_TEST);
+  command->scissorTest.enable = value;
+}
+
+void CommandBuffer::SetViewport(Viewport value)
+{
+  auto command             = mCommandPool->AllocateCommand(CommandType::SET_VIEWPORT);
+  command->viewport.region = value;
+}
+
+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)
+{
+  auto command                                 = mCommandPool->AllocateCommand(CommandType::PRESENT_RENDER_TARGET);
+  command->presentRenderTarget.targetToPresent = renderTarget;
+}
+
+[[nodiscard]] const Command* CommandBuffer::GetCommands(uint32_t& size) const
+{
+  return mCommandPool->GetCommands(size);
+}
+
+void CommandBuffer::DestroyResource()
+{
+  // Nothing to do
+}
+
+bool CommandBuffer::InitializeResource()
+{
+  // Nothing to do
+  return true;
+}
+
+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