Added element stride to the UniformInfo 03/313403/5
authorAdam Bialogonski <adam.b@samsung.com>
Tue, 25 Jun 2024 11:27:33 +0000 (12:27 +0100)
committerAdam Bialogonski <adam.b@samsung.com>
Fri, 28 Jun 2024 09:31:20 +0000 (10:31 +0100)
Added element stride to the UniformInfo when uniform is an array.

Change-Id: Ib006d0ce50589b2ef5cf1a5bd1e6b3ab7fe9ec45

automated-tests/src/dali/dali-test-suite-utils/test-graphics-controller.h
automated-tests/src/dali/dali-test-suite-utils/test-graphics-reflection.cpp
automated-tests/src/dali/dali-test-suite-utils/test-graphics-reflection.h
automated-tests/src/dali/utc-Dali-Renderer.cpp
dali/graphics-api/graphics-program-create-info.h
dali/graphics-api/graphics-types.h
dali/internal/render/renderers/render-renderer.cpp
dali/internal/render/renderers/render-renderer.h

index 6066f67..e21c304 100644 (file)
@@ -442,9 +442,85 @@ public: // Test Functions
     mCustomUniforms = customUniforms;
   }
 
+  constexpr std::pair<uint32_t, uint32_t> GetUniformBufferArrayStrideAndTypeSize(TestGraphicsReflection::TestUniformInfo& uniformInfo, uint32_t requestedStride)
+  {
+    uint32_t dataTypeSize  = 0;
+    uint32_t elementStride = 0;
+    switch(uniformInfo.type)
+    {
+      case Property::FLOAT:
+      case Property::INTEGER:
+      case Property::BOOLEAN:
+      {
+        dataTypeSize = sizeof(float);
+        break;
+      }
+      case Property::MATRIX:
+      {
+        dataTypeSize = sizeof(float) * 16;
+        break;
+      }
+      case Property::MATRIX3:
+      {
+        dataTypeSize = sizeof(float) * 9;
+        break;
+      }
+      case Property::VECTOR2:
+      {
+        dataTypeSize = sizeof(float) * 2;
+        break;
+      }
+      case Property::VECTOR3:
+      {
+        dataTypeSize = sizeof(float) * 3;
+        break;
+      }
+      case Property::VECTOR4:
+      {
+        dataTypeSize = sizeof(float) * 4;
+        break;
+      }
+      default:
+      {
+      }
+    }
+    if(uniformInfo.elementStride)
+    {
+      bool roundUp  = (dataTypeSize % uniformInfo.elementStride);
+      elementStride = (dataTypeSize / uniformInfo.elementStride) * uniformInfo.elementStride + (roundUp ? uniformInfo.elementStride : 0);
+    }
+    return std::make_pair(dataTypeSize, elementStride);
+  }
+
+  void AddMemberToUniformBlock(TestGraphicsReflection::TestUniformBlockInfo& blockInfo,
+                               std::string                                   name,
+                               Property::Type                                type,
+                               uint32_t                                      elementCount,
+                               uint32_t                                      elementStrideInBytes)
+  {
+    TestGraphicsReflection::TestUniformInfo info;
+    info.name          = std::move(name);
+    info.type          = type;
+    info.uniformClass  = Graphics::UniformClass::UNIFORM;
+    info.numElements   = elementCount;
+    info.locations     = {0};
+    info.bufferIndex   = 0;                    // this will update when AddCustomUniformBlock called
+
+    auto retval= GetUniformBufferArrayStrideAndTypeSize(info, elementStrideInBytes);
+    info.elementStride = std::max(retval.first, retval.second);
+    info.offsets       = {blockInfo.size};
+    blockInfo.size += (elementCount == 0 ? 1 : elementCount) * std::max(retval.first, retval.second);
+    blockInfo.members.emplace_back(info);
+  }
+
   void AddCustomUniformBlock(const TestGraphicsReflection::TestUniformBlockInfo& blockInfo)
   {
     mCustomUniformBlocks.push_back(blockInfo);
+    auto& info = mCustomUniformBlocks.back();
+    for(auto& member : info.members)
+    {
+      member.bufferIndex = mCustomUniformBlocks.size();
+    }
   }
 
   void ClearSubmitStack()
index 22d09e1..2d507f7 100644 (file)
@@ -325,13 +325,14 @@ bool TestGraphicsReflection::GetUniformBlock(uint32_t index, Dali::Graphics::Uni
   out.size = block.size;
   for(auto i = 0u; i < out.members.size(); ++i)
   {
-    const auto& memberUniform   = block.members[i];
-    out.members[i].name         = memberUniform.name;
-    out.members[i].binding      = block.binding;
-    out.members[i].uniformClass = Graphics::UniformClass::UNIFORM;
-    out.members[i].offset       = memberUniform.offsets[0];
-    out.members[i].location     = memberUniform.locations[0];
-    out.members[i].elementCount = memberUniform.numElements;
+    const auto& memberUniform    = block.members[i];
+    out.members[i].name          = memberUniform.name;
+    out.members[i].binding       = block.binding;
+    out.members[i].uniformClass  = Graphics::UniformClass::UNIFORM;
+    out.members[i].offset        = memberUniform.offsets[0];
+    out.members[i].location      = memberUniform.locations[0];
+    out.members[i].elementCount  = memberUniform.numElements;
+    out.members[i].elementStride = memberUniform.elementStride;
   }
 
   return true;
index b598435..3521ed0 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_GRAPHICS_REFLECTION_H
 
 /*
- * Copyright (c) 2023 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.
@@ -60,6 +60,7 @@ public: // Test methods
     std::vector<uint32_t>  locations{};
     uint32_t               numElements{0u}; // 0 elements means this isn't an array; 1 element means this is an array of size 1
     Property::Type         type;
+    uint32_t               elementStride{0u}; // array element stride, 0 - tightly packed
   };
 
   struct TestUniformBlockInfo
index 14f607d..9b83276 100644 (file)
@@ -4795,7 +4795,10 @@ int UtcDaliRendererUniformBlocks01(void)
   const int MAX_BONE_COUNT{300};
   const int skinningBlockSize = MAX_BONE_COUNT * sizeof(Matrix);
 
-  graphics.AddCustomUniformBlock(TestGraphicsReflection::TestUniformBlockInfo{"Skinning Block", 0, 0, skinningBlockSize, {{"uBone", Graphics::UniformClass::UNIFORM, 0, 0, {0}, {1}, MAX_BONE_COUNT, Property::Type::MATRIX}}});
+  graphics.AddCustomUniformBlock(TestGraphicsReflection::TestUniformBlockInfo{
+    "Skinning Block", 0, 0,
+    skinningBlockSize,
+    {{"uBone", Graphics::UniformClass::UNIFORM, 0, 0, {0}, {1}, MAX_BONE_COUNT, Property::Type::MATRIX}}});
 
   const int MAX_MORPH_COUNT{128};
   const int morphBlockSize = MAX_MORPH_COUNT * sizeof(float) + sizeof(float);
@@ -4937,6 +4940,108 @@ int UtcDaliRendererUniformBlocks02(void)
   END_TEST;
 }
 
+int UtcDaliRendererUniformBlocksWithStride(void)
+{
+  setenv("LOG_UNIFORM_BUFFER", "5f", 1); // Turns on buffer logging
+  TestApplication application;
+
+  tet_infoline("Test that repeated update/render cycles write into alternative buffers");
+  auto& graphics = application.GetGraphicsController();
+  auto& gl       = application.GetGlAbstraction();
+  gl.mBufferTrace.EnableLogging(true);
+
+  const uint32_t UNIFORM_BLOCK_ALIGNMENT(512);
+  gl.SetUniformBufferOffsetAlignment(UNIFORM_BLOCK_ALIGNMENT);
+
+  const int MAX_BONE_COUNT{300};
+  TestGraphicsReflection::TestUniformBlockInfo skinningBlock;
+  skinningBlock.name          = "SkinningBlock";
+  skinningBlock.binding       = 0;
+  skinningBlock.descriptorSet = 0;
+  graphics.AddMemberToUniformBlock( skinningBlock, "uBone", Property::Type::MATRIX, MAX_BONE_COUNT, 16 );
+  graphics.AddCustomUniformBlock(skinningBlock);
+  const int skinningBlockSize = int(skinningBlock.size);
+
+  const int MAX_MORPH_COUNT{128};
+  TestGraphicsReflection::TestUniformBlockInfo morphBlock;
+  morphBlock.name          = "MorphBlock";
+  morphBlock.binding       = 1;
+  morphBlock.descriptorSet = 0;
+  graphics.AddMemberToUniformBlock( morphBlock, "uNumberOfBlendShapes", Property::Type::FLOAT, 0, 0 );
+  graphics.AddMemberToUniformBlock( morphBlock, "uBlendShapeWeight", Property::Type::FLOAT, MAX_MORPH_COUNT, 16 );
+  graphics.AddCustomUniformBlock(morphBlock);
+
+  Actor    actor    = CreateActor(application.GetScene().GetRootLayer(), 0, TEST_LOCATION);
+  Shader   shader   = CreateShader(); // Don't care about src content
+  Geometry geometry = CreateQuadGeometry();
+  Renderer renderer = CreateRenderer(actor, geometry, shader, 0);
+  Matrix   m, n;
+  m.SetIdentity();
+  n.SetIdentity();
+  n.SetTransformComponents(Vector3(2.f, 2.f, 2.f), Quaternion(Radian(0.3f), Vector3::YAXIS), Vector3(200.0f, 1.0f, 20.0f));
+
+  CreateRendererProperties(renderer, m, n);
+  float w1                           = 0.01f;
+  float w2                           = 0.5f;
+  float w3                           = 0.79f;
+  renderer["uBlendShapeWeight[0]"]   = w1;
+  renderer["uBlendShapeWeight[55]"]  = w2;
+  renderer["uBlendShapeWeight[127]"] = w3;
+
+  TraceCallStack& graphicsTrace = graphics.mCallStack;
+  TraceCallStack& cmdTrace      = graphics.mCommandBufferCallStack;
+  graphicsTrace.EnableLogging(true);
+  cmdTrace.EnableLogging(true);
+
+  application.SendNotification();
+  application.Render();
+
+  // We expect 1 vertex buffer, 1 index buffer and 1 uniform buffer (representing 2 blocks)
+  DALI_TEST_EQUALS(cmdTrace.CountMethod("BindUniformBuffers"), 1, TEST_LOCATION);
+
+  const uint32_t MORPH_BLOCK_OFFSET = (skinningBlockSize % UNIFORM_BLOCK_ALIGNMENT == 0) ? skinningBlockSize : ((skinningBlockSize / UNIFORM_BLOCK_ALIGNMENT) + 1) * UNIFORM_BLOCK_ALIGNMENT;
+
+  for(int i = 0; i < 50; ++i)
+  {
+    tet_infoline("\nTest that uBone[299] is written correctly");
+    TestGraphicsBuffer* bufferPtr = FindUniformBuffer(i % 2, graphics);
+    DALI_TEST_CHECK(graphics.mAllocatedBuffers.size() == (i == 0 ? 4 : 5));
+    DALI_TEST_CHECK(bufferPtr != nullptr);
+    auto offset0 = sizeof(Dali::Matrix) * 299;
+    Matrix* mPtr = reinterpret_cast<Dali::Matrix*>(&bufferPtr->memory[0] + offset0);
+    DALI_TEST_EQUALS(*mPtr, n, 0.0001, TEST_LOCATION);
+
+    const auto size = morphBlock.members[1].elementStride;
+    const auto memberOffset = morphBlock.members[1].offsets[0];
+    float* wPtr1 = reinterpret_cast<float*>(&bufferPtr->memory[MORPH_BLOCK_OFFSET] + memberOffset + size * 0);
+    float* wPtr2 = reinterpret_cast<float*>(&bufferPtr->memory[MORPH_BLOCK_OFFSET] + memberOffset + size * 55);
+    float* wPtr3 = reinterpret_cast<float*>(&bufferPtr->memory[MORPH_BLOCK_OFFSET] + memberOffset + size * 127);
+
+    tet_printf("Test that uBlendShapeWeight[0] is written correctly as %4.2f\n", w1);
+    tet_printf("Test that uBlendShapeWeight[55] is written correctly as %4.2f\n", w2);
+    tet_printf("Test that uBlendShapeWeight[127] is written correctly as %4.2f\n", w3);
+
+    DALI_TEST_EQUALS(*wPtr1, w1, 0.0001f, TEST_LOCATION);
+    DALI_TEST_EQUALS(*wPtr2, w2, 0.0001f, TEST_LOCATION);
+    DALI_TEST_EQUALS(*wPtr3, w3, 0.0001f, TEST_LOCATION);
+
+    n.SetTransformComponents(Vector3(2.f, 2.f, 2.f), Quaternion(Radian(i * 0.3f), Vector3::YAXIS), Vector3(200.0f + i * 10.0f, -i, 20.0f));
+    renderer["uBone[299]"] = n;
+
+    w1 += 0.005f;
+    w2 += 0.005f;
+    w3 -= 0.01f;
+    renderer["uBlendShapeWeight[0]"]   = w1;
+    renderer["uBlendShapeWeight[55]"]  = w2;
+    renderer["uBlendShapeWeight[127]"] = w3;
+
+    application.SendNotification();
+    application.Render();
+  }
+
+  END_TEST;
+}
+
 int AlignSize(int size, int align)
 {
   return (size % align == 0) ? size : ((size / align) + 1) * align;
index 4c17677..3f98d16 100644 (file)
@@ -85,7 +85,7 @@ struct ProgramCreateInfo
    *
    * The Program will compile and link all given shaders.
    *
-   * param[in] value Valid array of shder states
+   * param[in] value Valid array of shader states
    * @return reference to this structure
    */
   auto& SetShaderState(const std::vector<ShaderState>& value)
index a9dc532..eae2272 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_GRAPHICS_API_TYPES
 
 /*
- * Copyright (c) 2023 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.
@@ -1151,6 +1151,7 @@ struct UniformInfo
   uint32_t     offset{0u};
   uint32_t     location{0u};
   uint32_t     elementCount{0u};
+  uint32_t     elementStride{0u};
 
   bool operator==(const UniformInfo& rhs)
   {
index 975664a..2b81a0c 100644 (file)
@@ -862,14 +862,16 @@ void Renderer::FillUniformBuffer(Program&
         continue;
       }
 
-      uniform.uniformOffset     = uniformInfo.offset;
-      uniform.uniformLocation   = uniformInfo.location;
-      uniform.uniformBlockIndex = uniformInfo.bufferIndex;
-      uniform.initialized       = true;
+      uniform.uniformOffset      = uniformInfo.offset;
+      uniform.uniformLocation    = int16_t(uniformInfo.location);
+      uniform.uniformBlockIndex  = uniformInfo.bufferIndex;
+      uniform.initialized        = true;
 
       auto       dst      = ubo->GetOffset() + uniformInfo.offset;
       const auto typeSize = iter.propertyValue->GetValueSize();
-      const auto dest     = dst + static_cast<uint32_t>(typeSize) * arrayIndex;
+      uniform.arrayElementStride = uniformInfo.elementCount > 0 ? (uniformInfo.elementStride ? uniformInfo.elementStride : typeSize) : typeSize;
+
+      const auto dest     = dst + uniform.arrayElementStride * arrayIndex;
 
       ubo->Write(iter.propertyValue->GetValueAddress(updateBufferIndex),
                  typeSize,
@@ -881,7 +883,7 @@ void Renderer::FillUniformBuffer(Program&
 
       auto       dst      = ubo->GetOffset() + uniform.uniformOffset;
       const auto typeSize = iter.propertyValue->GetValueSize();
-      const auto dest     = dst + static_cast<uint32_t>(typeSize) * arrayIndex;
+      const auto dest     = dst + uniform.arrayElementStride * arrayIndex;
 
       ubo->Write(iter.propertyValue->GetValueAddress(updateBufferIndex),
                  typeSize,
index af05bcc..c4aa33a 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_RENDER_RENDERER_H
 
 /*
- * Copyright (c) 2023 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.
@@ -637,6 +637,7 @@ private:
     Hash                     uniformNameHash{0u};
     Hash                     uniformNameHashNoArray{0u};
     int32_t                  arrayIndex{-1}; ///< The array index
+    uint32_t                 arrayElementStride{0u}; ///< The stride for element of an array (0 - tightly packed)
 
     int16_t  uniformLocation{0u};
     uint16_t uniformOffset{0u};