UBO support with CPU-backed buffer 10/254410/11
authorAdam Bialogonski <adam.b@samsung.com>
Tue, 9 Mar 2021 11:12:29 +0000 (11:12 +0000)
committerAdam Bialogonski <adam.b@samsung.com>
Tue, 9 Mar 2021 11:13:49 +0000 (11:13 +0000)
- Added CPU based Buffer memory allocation
- Memory mapping of CPU based buffers
- Support for fixed size arrays in reflection
- Writing into arrays (we may need to support array stride for array of matrices?)
- Using custom allocator for CPU buffer (if supplied)
- Writing DALi supported shader types only

Change-Id: I047439b6f4aa1ce69e214a763a987088df9c8454

12 files changed:
dali/internal/graphics/gles-impl/egl-graphics-controller.cpp
dali/internal/graphics/gles-impl/gles-context.cpp
dali/internal/graphics/gles-impl/gles-context.h
dali/internal/graphics/gles-impl/gles-graphics-buffer.cpp
dali/internal/graphics/gles-impl/gles-graphics-buffer.h
dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h
dali/internal/graphics/gles-impl/gles-graphics-memory.cpp
dali/internal/graphics/gles-impl/gles-graphics-program.cpp
dali/internal/graphics/gles-impl/gles-graphics-program.h
dali/internal/graphics/gles-impl/gles-graphics-reflection.cpp
dali/internal/graphics/gles-impl/gles-graphics-reflection.h
dali/internal/graphics/gles-impl/gles-graphics-types.h

index 979c5be..d17fd38 100644 (file)
@@ -260,6 +260,12 @@ void EglGraphicsController::ProcessCommandQueues()
           mContext->BindVertexBuffers(bindings);
           break;
         }
+        case GLES::CommandType::BIND_UNIFORM_BUFFER:
+        {
+          auto& bindings = cmd.bindUniformBuffers;
+          mContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
+          break;
+        }
         case GLES::CommandType::BIND_INDEX_BUFFER:
         {
           mContext->BindIndexBuffer(cmd.bindIndexBuffer);
index a063a94..174d51a 100644 (file)
@@ -21,6 +21,7 @@
 #include "gles-graphics-buffer.h"
 #include "gles-graphics-command-buffer.h"
 #include "gles-graphics-pipeline.h"
+#include "gles-graphics-program.h"
 
 namespace Dali::Graphics::GLES
 {
@@ -50,6 +51,10 @@ struct Context::Impl
 
   // Currently bound buffers
   std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
+
+  // Currently bound UBOs (check if it's needed per program!)
+  std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
+  UniformBufferBindingDescriptor              mCurrentStandaloneUBOBinding{};
 };
 
 Context::Context(EglGraphicsController& controller)
@@ -78,6 +83,9 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
   // Resolve rasterization state
   ResolveRasterizationState();
 
+  // Resolve uniform buffers
+  ResolveUniformBuffers();
+
   // Bind textures
   for(const auto& binding : mImpl->mCurrentTextureBindings)
   {
@@ -121,6 +129,8 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
   // Resolve topology
   const auto& ia = mImpl->mCurrentPipeline->GetCreateInfo().inputAssemblyState;
 
+  // Bind uniforms
+
   // Resolve draw call
   switch(drawCall.type)
   {
@@ -187,6 +197,29 @@ void Context::BindPipeline(const GLES::Pipeline* newPipeline)
   mImpl->mNewPipeline = newPipeline;
 }
 
+void Context::BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& uboBindings,
+                                 const UniformBufferBindingDescriptor&              standaloneBindings)
+{
+  if(standaloneBindings.buffer)
+  {
+    mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
+  }
+
+  if(uboBindings.size() >= mImpl->mCurrentUBOBindings.size())
+  {
+    mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1);
+  }
+
+  auto it = uboBindings.begin();
+  for(auto i = 0u; i < uboBindings.size(); ++i)
+  {
+    if(it->buffer)
+    {
+      mImpl->mCurrentUBOBindings[i] = *it;
+    }
+  }
+}
+
 void Context::ResolveBlendState()
 {
   const auto& state = mImpl->mCurrentPipeline->GetCreateInfo();
@@ -255,4 +288,117 @@ void Context::ResolveRasterizationState()
   //       seems like we don't support it (no glPolygonMode())
 }
 
+void Context::ResolveUniformBuffers()
+{
+  // Resolve standalone uniforms if we have binding
+  if(mImpl->mCurrentStandaloneUBOBinding.buffer)
+  {
+    ResolveStandaloneUniforms();
+  }
+}
+
+void Context::ResolveStandaloneUniforms()
+{
+  auto& gl = *mImpl->mController.GetGL();
+
+  // Find reflection for program
+  const auto program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
+
+  const auto& reflection = program->GetReflection();
+
+  auto extraInfos = reflection.GetStandaloneUniformExtraInfo();
+
+  const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress());
+
+  for(const auto& info : extraInfos)
+  {
+    auto type   = GLTypeConversion(info.type).type;
+    auto offset = info.offset;
+    switch(type)
+    {
+      case GLType::FLOAT_VEC2:
+      {
+        gl.Uniform2fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
+        break;
+      }
+      case GLType::FLOAT_VEC3:
+      {
+        gl.Uniform3fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
+        break;
+      }
+      case GLType::FLOAT_VEC4:
+      {
+        gl.Uniform4fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
+        break;
+      }
+      case GLType::INT_VEC2:
+      {
+        gl.Uniform2iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
+        break;
+      }
+      case GLType::INT_VEC3:
+      {
+        gl.Uniform3iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
+        break;
+      }
+      case GLType::INT_VEC4:
+      {
+        gl.Uniform4iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
+        break;
+      }
+      case GLType::BOOL:
+      {
+        // not supported by DALi
+        break;
+      }
+      case GLType::BOOL_VEC2:
+      {
+        // not supported by DALi
+        break;
+      }
+      case GLType::BOOL_VEC3:
+      {
+        // not supported by DALi
+        break;
+      }
+      case GLType::BOOL_VEC4:
+      {
+        // not supported by DALi
+        break;
+      }
+      case GLType::FLOAT:
+      {
+        gl.Uniform1fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
+        break;
+      }
+      case GLType::FLOAT_MAT2:
+      {
+        gl.UniformMatrix2fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
+        break;
+      }
+      case GLType::FLOAT_MAT3:
+      {
+        gl.UniformMatrix3fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
+        break;
+      }
+      case GLType::FLOAT_MAT4:
+      {
+        gl.UniformMatrix4fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
+        break;
+      }
+      case GLType::SAMPLER_2D:
+      {
+        break;
+      }
+      case GLType::SAMPLER_CUBE:
+      {
+        break;
+      }
+      default:
+      {
+      }
+    }
+  }
+}
+
 } // namespace Dali::Graphics::GLES
index 50de21e..734bdaa 100644 (file)
@@ -94,6 +94,14 @@ public:
   void BindPipeline(const GLES::Pipeline* newPipeline);
 
   /**
+   * @brief Binds uniform buffers to the context
+   *
+   * @param[in] uboBindings real UBO binfins
+   * @param[in] standaloneBindings emulated (legacy) UBO object
+   */
+  void BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& uboBindings, const UniformBufferBindingDescriptor& standaloneBindings);
+
+  /**
    * @brief Resolves blend state on the currently attached pipeline
    */
   void ResolveBlendState();
@@ -103,6 +111,16 @@ public:
    */
   void ResolveRasterizationState();
 
+  /**
+   * @brief Resolves uniform buffers and binds data to the pipeline
+   */
+  void ResolveUniformBuffers();
+
+  /**
+   * @brief Special usecase for legacy shaders, called by ResolveUniformBuffers()
+   */
+  void ResolveStandaloneUniforms();
+
 private:
   struct Impl;
   std::unique_ptr<Impl> mImpl;
index 8b5fb4b..2e4d4dc 100644 (file)
@@ -30,22 +30,87 @@ namespace Dali::Graphics::GLES
 Buffer::Buffer(const Graphics::BufferCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
 : BufferResource(createInfo, controller)
 {
+  // Check if buffer is CPU allocated
+  if(((0 | BufferUsage::UNIFORM_BUFFER) & mCreateInfo.usage) &&
+     (0 | BufferPropertiesFlagBit::CPU_ALLOCATED) & mCreateInfo.propertiesFlags)
+  {
+    // cpu allocated buffer
+    mCpuAllocated = true;
+  }
+
+  // Check if buffer is transient
+  if((0 | BufferPropertiesFlagBit::TRANSIENT_MEMORY) & mCreateInfo.propertiesFlags)
+  {
+    // memory is transient, may be lazily allocated when
+    // mapped, together with cpu allocated it may create emulated uniform
+    // buffer in this implementation
+    mTransient = true;
+  }
+
   controller.AddBuffer(*this);
 }
 
 bool Buffer::InitializeResource()
 {
+  // CPU allocated uniform buffer is a special "compatibility" mode
+  // for older GLES
+  if(mCpuAllocated && !mTransient)
+  {
+    InitializeCPUBuffer();
+  }
+  else if(!mCpuAllocated)
+  {
+    InitializeGPUBuffer();
+  }
+
+  return true;
+}
+
+void Buffer::InitializeCPUBuffer()
+{
+  // Just allocate memory
+  // @TODO put better CPU memory management in place
+  const auto allocators = GetCreateInfo().allocationCallbacks;
+  if(allocators)
+  {
+    mBufferPtr = allocators->allocCallback(mCreateInfo.size, 0, allocators->userData);
+  }
+  else
+  {
+    mBufferPtr = malloc(mCreateInfo.size);
+  }
+}
+
+void Buffer::InitializeGPUBuffer()
+{
   auto gl = mController.GetGL();
   gl->GenBuffers(1, &mBufferId);
   gl->BindBuffer(GL_ARRAY_BUFFER, mBufferId);
   gl->BufferData(GL_ARRAY_BUFFER, mCreateInfo.size, nullptr, GL_STATIC_DRAW);
-  return true;
 }
 
 void Buffer::DestroyResource()
 {
-  auto gl = mController.GetGL();
-  gl->DeleteBuffers(1, &mBufferId);
+  // Destroy CPU allocated buffer
+  if(mCpuAllocated && mBufferPtr)
+  {
+    const auto allocators = GetCreateInfo().allocationCallbacks;
+    if(allocators)
+    {
+      allocators->freeCallback(mBufferPtr, allocators->userData);
+    }
+    else
+    {
+      free(mBufferPtr);
+    }
+    mBufferPtr = nullptr;
+  }
+  // Deestroy GPU allocation
+  else
+  {
+    auto gl = mController.GetGL();
+    gl->DeleteBuffers(1, &mBufferId);
+  }
 }
 
 void Buffer::DiscardResource()
@@ -56,21 +121,36 @@ void Buffer::DiscardResource()
 void Buffer::Bind(Graphics::BufferUsage bindingTarget) const
 {
   auto gl = mController.GetGL();
-  switch(bindingTarget)
+
+  // CPU allocated buffer may be bound only as Uniform Buffer
+  // on special binding point
+  if(mCpuAllocated && mBufferPtr)
   {
-    case Graphics::BufferUsage::VERTEX_BUFFER:
+    if(bindingTarget == Graphics::BufferUsage::UNIFORM_BUFFER)
     {
-      gl->BindBuffer(GL_ARRAY_BUFFER, mBufferId);
-      break;
+      // TODO: probably nothing to do, the GLES Context
+      //       we may use CPU backed buffer for future data
+      //       transfers (copy operations)
     }
-    case Graphics::BufferUsage::INDEX_BUFFER:
-    {
-      gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBufferId);
-      break;
-    }
-    default:
+  }
+  else
+  {
+    switch(bindingTarget)
     {
-      //
+      case Graphics::BufferUsage::VERTEX_BUFFER:
+      {
+        gl->BindBuffer(GL_ARRAY_BUFFER, mBufferId);
+        break;
+      }
+      case Graphics::BufferUsage::INDEX_BUFFER:
+      {
+        gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBufferId);
+        break;
+      }
+      default:
+      {
+        // Nothing to do
+      }
     }
   }
 }
index 6f0a245..2e1f96b 100644 (file)
@@ -61,8 +61,31 @@ public:
     return mBufferId;
   }
 
+  [[nodiscard]] void* GetCPUAllocatedAddress() const
+  {
+    return mBufferPtr;
+  }
+
+  [[nodiscard]] bool IsTransient() const
+  {
+    return mTransient;
+  }
+
+  [[nodiscard]] bool IsCPUAllocated() const
+  {
+    return mCpuAllocated;
+  }
+
 private:
+
+  void InitializeCPUBuffer();
+
+  void InitializeGPUBuffer();
+
   uint32_t mBufferId{};
+  void*    mBufferPtr{nullptr}; // CPU allocated memory
+  bool     mCpuAllocated{false};
+  bool     mTransient{false};
 };
 } // namespace GLES
 } // namespace Dali::Graphics
index 6601fc5..e9ec39f 100644 (file)
 
 // INTERNAL INCLUDES
 #include "egl-graphics-controller.h"
+#include "gles-graphics-buffer.h"
 #include "gles-graphics-pipeline.h"
 #include "gles-graphics-types.h"
 
 namespace Dali::Graphics::GLES
 {
 class Texture;
-class Buffer;
-class Sampler;
 class Pipeline;
 
 enum class CommandType
@@ -93,6 +92,11 @@ struct Command
         bindPipeline = rhs.bindPipeline;
         break;
       }
+      case CommandType::BIND_UNIFORM_BUFFER:
+      {
+        bindUniformBuffers = rhs.bindUniformBuffers;
+        break;
+      }
       case CommandType::DRAW:
       {
         draw.type = rhs.draw.type;
@@ -212,8 +216,8 @@ struct Command
 
     struct
     {
-      using Binding = GLES::UniformBufferBindingDescriptor;
-      std::vector<Binding> uniformBufferBindings;
+      std::vector<UniformBufferBindingDescriptor> uniformBufferBindings{};
+      UniformBufferBindingDescriptor              standaloneUniformsBufferBinding{};
     } bindUniformBuffers;
 
     struct
@@ -261,16 +265,36 @@ public:
 
   void BindUniformBuffers(const std::vector<Graphics::UniformBufferBinding>& bindings) override
   {
-    printf("BindUniformBuffers: bindings.size(): %lu\n", bindings.size());
-
     mCommands.emplace_back();
-    mCommands.back().type       = CommandType::BIND_UNIFORM_BUFFER;
-    auto& uniformBufferBindings = mCommands.back().bindUniformBuffers.uniformBufferBindings;
-
-    for(auto i = 0u; i < bindings.size(); ++i)
+    auto& cmd     = mCommands.back();
+    cmd.type      = CommandType::BIND_UNIFORM_BUFFER;
+    auto& bindCmd = cmd.bindUniformBuffers;
+    for(const auto& binding : bindings)
     {
-      const auto& binding = bindings[i];
-      printf("bindings[%u]->buffer: %p, dataSize: %u, offset: %u, binding: %u\n", i, binding.buffer, binding.dataSize, binding.offset, binding.binding);
+      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
+        {
+          // resize binding slots
+          if(binding.binding >= bindCmd.uniformBufferBindings.size())
+          {
+            bindCmd.uniformBufferBindings.resize(binding.binding + 1);
+          }
+          auto& slot    = bindCmd.uniformBufferBindings[binding.binding];
+          slot.buffer   = glesBuffer;
+          slot.offset   = binding.offset;
+          slot.binding  = binding.binding;
+          slot.emulated = false;
+        }
+      }
     }
   }
 
@@ -382,7 +406,7 @@ public:
     cmd.drawIndexedIndirect.stride    = stride;
   }
 
-  void Reset(Graphics::CommandBuffer& commandBuffer) override
+  void Reset() override
   {
     mCommands.clear();
   }
@@ -429,4 +453,4 @@ private:
 };
 } // namespace Dali::Graphics::GLES
 
-#endif
\ No newline at end of file
+#endif
index 017ed30..8335364 100644 (file)
@@ -53,14 +53,21 @@ void* Memory::LockRegion(uint32_t offset, uint32_t size)
   if(mMapObjectType == MapObjectType::BUFFER)
   {
     auto buffer = static_cast<GLES::Buffer*>(mMapBufferInfo.buffer);
-    buffer->Bind(Graphics::BufferUsage::VERTEX_BUFFER);
-
-    void* ptr = nullptr;
-    ptr       = gl->MapBufferRange(GL_ARRAY_BUFFER, mMapBufferInfo.offset, mMapBufferInfo.size, GL_MAP_WRITE_BIT);
-
-    mMappedPointer = ptr;
 
-    return ptr;
+    if(buffer->IsCPUAllocated())
+    {
+      using Ptr = char*;
+      return Ptr(buffer->GetCPUAllocatedAddress()) + offset;
+    }
+    else
+    {
+      // @TODO: trashing vertex binding, better find target that is rarely used
+      buffer->Bind(Graphics::BufferUsage::VERTEX_BUFFER);
+      void* ptr      = nullptr;
+      ptr            = gl->MapBufferRange(GL_ARRAY_BUFFER, mMapBufferInfo.offset, mMapBufferInfo.size, GL_MAP_WRITE_BIT);
+      mMappedPointer = ptr;
+    }
+    return mMappedPointer;
   }
 
   return nullptr;
index 9171203..a7686e1 100644 (file)
@@ -132,7 +132,7 @@ uint32_t ProgramImpl::Release()
   return --mImpl->refCount;
 }
 
-const Graphics::Reflection& ProgramImpl::GetReflection() const
+const GLES::Reflection& ProgramImpl::GetReflection() const
 {
   return *mImpl->reflection;
 }
@@ -168,7 +168,7 @@ Program::~Program()
   }
 }
 
-const Graphics::Reflection& Program::GetReflection() const
+const GLES::Reflection& Program::GetReflection() const
 {
   return mProgram->GetReflection();
 }
index a080012..73ed75c 100644 (file)
 // INTERNAL INCLUDES
 #include "gles-graphics-resource.h"
 
-namespace Dali::Graphics
+namespace Dali::Graphics::GLES
 {
 class Reflection;
-namespace GLES
-{
+
 /**
  * @brief Program implementation
  *
@@ -92,7 +91,7 @@ public:
    *
    * @return Valid reflection associated with the Program
    */
-  [[nodiscard]] const Graphics::Reflection& GetReflection() const;
+  [[nodiscard]] const GLES::Reflection& GetReflection() const;
 
   /**
    * @brief Returns controller
@@ -159,7 +158,7 @@ public:
 
    * @return Reflection
    */
-  [[nodiscard]] const Graphics::Reflection& GetReflection() const;
+  [[nodiscard]] const GLES::Reflection& GetReflection() const;
 
   /**
    * @brief Retrieves internal program implementation
@@ -219,7 +218,6 @@ public:
 private:
   ProgramImpl* mProgram{nullptr};
 };
-} // namespace GLES
-} // namespace Dali::Graphics
+} // namespace Dali::Graphics::GLES
 
-#endif //DALI_GRAPHICS_PROGRAM_H
+#endif //DALI_GRAPHICS_GLES_PROGRAM_H
index aec46ae..43420ad 100644 (file)
@@ -163,14 +163,24 @@ void Reflection::BuildUniformReflection()
 
   for(int i = 0; i < numUniforms; ++i)
   {
-    int    size;
+    int    elementCount;
     GLenum type;
     int    written;
-    gl->GetActiveUniform(glProgram, i, maxLen, &written, &size, &type, name);
+    gl->GetActiveUniform(glProgram, i, maxLen, &written, &elementCount, &type, name);
     int location = gl->GetUniformLocation(glProgram, name);
 
     Dali::Graphics::UniformInfo uniformInfo;
-    uniformInfo.name         = name;
+
+    uniformInfo.name = name;
+    if(elementCount > 1)
+    {
+      auto iter = std::string(uniformInfo.name).find("[", 0);
+      if(iter != std::string::npos)
+      {
+        uniformInfo.name = std::string(name).substr(0, iter);
+      }
+    }
+
     uniformInfo.uniformClass = IsSampler(type) ? Dali::Graphics::UniformClass::COMBINED_IMAGE_SAMPLER : Dali::Graphics::UniformClass::UNIFORM;
     uniformInfo.location     = IsSampler(type) ? 0 : location;
     uniformInfo.binding      = IsSampler(type) ? location : 0;
@@ -183,14 +193,16 @@ void Reflection::BuildUniformReflection()
     else
     {
       mDefaultUniformBlock.members.push_back(uniformInfo);
-      mStandaloneUniformExtraInfos.push_back(UniformExtraInfo(location, GetGLDataTypeSize(type), type));
+      mStandaloneUniformExtraInfos.emplace_back(location, GetGLDataTypeSize(type), uniformInfo.offset, elementCount, type);
     }
   }
 
   // Re-order according to uniform locations.
+
   if(mDefaultUniformBlock.members.size() > 1)
   {
     std::sort(mDefaultUniformBlock.members.begin(), mDefaultUniformBlock.members.end(), SortUniformInfoByLocation);
+    std::sort(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), SortUniformExtraInfoByLocation);
   }
 
   if(mUniformOpaques.size() > 1)
@@ -209,7 +221,8 @@ void Reflection::BuildUniformReflection()
     {
       uint32_t previousUniformLocation       = mDefaultUniformBlock.members[i - 1].location;
       auto     previousUniform               = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&previousUniformLocation](const UniformExtraInfo& iter) { return iter.location == previousUniformLocation; });
-      mDefaultUniformBlock.members[i].offset = mDefaultUniformBlock.members[i - 1].offset + previousUniform->size;
+      mDefaultUniformBlock.members[i].offset = mDefaultUniformBlock.members[i - 1].offset + (previousUniform->size * previousUniform->arraySize);
+      mStandaloneUniformExtraInfos[i].offset = mDefaultUniformBlock.members[i].offset;
     }
   }
 
@@ -217,8 +230,7 @@ void Reflection::BuildUniformReflection()
   {
   uint32_t lastUniformLocation = mDefaultUniformBlock.members.back().location;
   auto     lastUniform         = std::find_if(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), [&lastUniformLocation](const UniformExtraInfo& iter) { return iter.location == lastUniformLocation; });
-  mDefaultUniformBlock.size    = mDefaultUniformBlock.members.back().offset + lastUniform->size;
-
+  mDefaultUniformBlock.size    = mDefaultUniformBlock.members.back().offset + (lastUniform->size * lastUniform->arraySize);
   mUniformBlocks.push_back(mDefaultUniformBlock);
   }
   else
@@ -226,12 +238,6 @@ void Reflection::BuildUniformReflection()
     mDefaultUniformBlock.size = 0;
   }
 
-  // Re-order according to uniform locations.
-  if(mStandaloneUniformExtraInfos.size() > 1)
-  {
-    std::sort(mStandaloneUniformExtraInfos.begin(), mStandaloneUniformExtraInfos.end(), SortUniformExtraInfoByLocation);
-  }
-
   delete[] name;
 }
 
@@ -486,9 +492,15 @@ std::vector<GLenum> Reflection::GetStandaloneUniformTypes() const
   {
     retval.emplace_back(uniform.type);
   }
+
   return retval;
 }
 
+const std::vector<Reflection::UniformExtraInfo>& Reflection::GetStandaloneUniformExtraInfo() const
+{
+  return mStandaloneUniformExtraInfos;
+}
+
 std::vector<Dali::Graphics::UniformInfo> Reflection::GetSamplers() const
 {
   return mUniformOpaques;
index 1781ffa..c54c505 100644 (file)
@@ -203,17 +203,28 @@ public:
    */
   struct UniformExtraInfo
   {
-    UniformExtraInfo(uint32_t location, uint32_t size, GLenum type)
+    UniformExtraInfo(uint32_t location, uint32_t size, uint32_t offset, uint32_t arraySize, GLenum type)
     : location(location),
       size(size),
+      offset(offset),
+      arraySize(arraySize),
       type(type){};
 
     uint32_t location; ///< Location of uniform
     uint32_t size;     ///< size of uniform
+    uint32_t offset;   ///< offset of uniform within UBO
+    uint32_t arraySize; ///< number of array elements (1 for non-arrays)
     GLenum   type;     ///< type of uniform
   };
 
   /**
+   * @brief Returns array of additional info about standalone uniforms
+   *
+   * @return Array of internal uniform data
+   */
+  [[nodiscard]] const std::vector<UniformExtraInfo>& GetStandaloneUniformExtraInfo() const;
+
+  /**
    * @brief Build the reflection of vertex attributes
    */
   void BuildVertexAttributeReflection();
index b59fed1..74a1ccd 100644 (file)
@@ -1276,7 +1276,9 @@ struct IndexBufferBindingDescriptor
 struct UniformBufferBindingDescriptor
 {
   const GLES::Buffer* buffer{nullptr};
+  uint32_t            binding{0u};
   uint32_t            offset{0u};
+  bool                emulated; ///<true if UBO is emulated for old gfx API
 };
 
 /**
@@ -1643,6 +1645,136 @@ struct GLCullMode
   GLenum glCullMode{0u};
 };
 
+/**
+ * @brief enum with GL types
+ */
+enum class GLType
+{
+  UNDEFINED      = 0x0,
+  FLOAT_VEC2     = 0x8B50,
+  FLOAT_VEC3     = 0x8B51,
+  FLOAT_VEC4     = 0x8B52,
+  INT_VEC2       = 0x8B53,
+  INT_VEC3       = 0x8B54,
+  INT_VEC4       = 0x8B55,
+  BOOL           = 0x8B56,
+  BOOL_VEC2      = 0x8B57,
+  BOOL_VEC3      = 0x8B58,
+  BOOL_VEC4      = 0x8B59,
+  FLOAT_MAT2     = 0x8B5A,
+  FLOAT_MAT3     = 0x8B5B,
+  FLOAT_MAT4     = 0x8B5C,
+  SAMPLER_2D     = 0x8B5E,
+  SAMPLER_CUBE   = 0x8B60,
+  BYTE           = 0x1400,
+  UNSIGNED_BYTE  = 0x1401,
+  SHORT          = 0x1402,
+  UNSIGNED_SHORT = 0x1403,
+  INT            = 0x1404,
+  UNSIGNED_INT   = 0x1405,
+  FLOAT          = 0x1406,
+  FIXED          = 0x140C,
+};
+
+/**
+ * @brief GL type conversion (used with reflection)
+ */
+struct GLTypeConversion
+{
+  constexpr explicit GLTypeConversion(GLenum value)
+  {
+    switch(value)
+    {
+      case GL_FLOAT_VEC2:
+      {
+        type = GLType::FLOAT_VEC2;
+        break;
+      }
+      case GL_FLOAT_VEC3:
+      {
+        type = GLType::FLOAT_VEC3;
+        break;
+      }
+      case GL_FLOAT_VEC4:
+      {
+        type = GLType::FLOAT_VEC4;
+        break;
+      }
+      case GL_INT_VEC2:
+      {
+        type = GLType::INT_VEC2;
+        break;
+      }
+      case GL_INT_VEC3:
+      {
+        type = GLType::INT_VEC3;
+        break;
+      }
+      case GL_INT_VEC4:
+      {
+        type = GLType::INT_VEC4;
+        break;
+      }
+      case GL_BOOL:
+      {
+        type = GLType::BOOL;
+        break;
+      }
+      case GL_BOOL_VEC2:
+      {
+        type = GLType::BOOL_VEC2;
+        break;
+      }
+      case GL_BOOL_VEC3:
+      {
+        type = GLType::BOOL_VEC3;
+        break;
+      }
+      case GL_BOOL_VEC4:
+      {
+        type = GLType::BOOL_VEC4;
+        break;
+      }
+      case GL_FLOAT_MAT2:
+      {
+        type = GLType::FLOAT_MAT2;
+        break;
+      }
+      case GL_FLOAT_MAT3:
+      {
+        type = GLType::FLOAT_MAT3;
+        break;
+      }
+      case GL_FLOAT_MAT4:
+      {
+        type = GLType::FLOAT_MAT4;
+        break;
+      }
+      case GL_SAMPLER_2D:
+      {
+        type = GLType::SAMPLER_2D;
+        break;
+      }
+      case GL_SAMPLER_CUBE:
+      {
+        type = GLType::SAMPLER_CUBE;
+        break;
+      }
+      case GL_FLOAT:
+      {
+        type = GLType::FLOAT;
+        break;
+      }
+      default:
+      {
+        type = GLType::UNDEFINED;
+      }
+    }
+  }
+
+  GLType type{GLType::UNDEFINED};
+};
+
 } // namespace Dali::Graphics::GLES
 
 #endif //DALI_GRAPHICS_API_TYPES_H