Adding instance count and vertex range to Renderer 52/292052/8
authorDavid Steele <david.steele@samsung.com>
Wed, 26 Apr 2023 18:18:47 +0000 (19:18 +0100)
committerDavid Steele <david.steele@samsung.com>
Wed, 31 May 2023 11:11:06 +0000 (12:11 +0100)
VertexRange devel properties map onto the index range properties,
we just use the same storage internally, and figure it out in
the render side.

InstanceCount is used to trigger instanced drawing (it no longer
happens automatically if divisor is set).

Change-Id: I4785021dee97ce9587f6e39bff2a2af8c41a3f16

16 files changed:
automated-tests/src/dali/dali-test-suite-utils/test-graphics-command-buffer.h
automated-tests/src/dali/dali-test-suite-utils/test-graphics-controller.cpp
automated-tests/src/dali/utc-Dali-DecoratedVisualRenderer.cpp
automated-tests/src/dali/utc-Dali-Renderer.cpp
automated-tests/src/dali/utc-Dali-VertexBuffer.cpp
automated-tests/src/dali/utc-Dali-VisualRenderer.cpp
dali/devel-api/rendering/renderer-devel.h
dali/internal/event/rendering/renderer-impl.cpp
dali/internal/event/rendering/renderer-impl.h
dali/internal/render/data-providers/render-data-provider.h
dali/internal/render/renderers/render-geometry.cpp
dali/internal/render/renderers/render-geometry.h
dali/internal/render/renderers/render-renderer.cpp
dali/internal/update/rendering/scene-graph-renderer-messages.h
dali/internal/update/rendering/scene-graph-renderer.cpp
dali/internal/update/rendering/scene-graph-renderer.h

index 407dade..84480ef 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_GRAPHICS_COMMAND_BUFFER_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -843,7 +843,12 @@ public:
     cmd.draw.instanceCount = instanceCount;
     cmd.draw.firstInstance = firstInstance;
     cmd.draw.firstVertex   = firstVertex;
-    mCallStack.PushCall("Draw", "");
+    TraceCallStack::NamedParams namedParams;
+    namedParams["vertexCount"] << vertexCount;
+    namedParams["instanceCount"] << instanceCount;
+    namedParams["firstInstance"] << firstInstance;
+    namedParams["firstVertex"] << firstVertex;
+    mCallStack.PushCall("Draw", namedParams.str(), namedParams);
   }
 
   void DrawIndexed(
@@ -862,7 +867,13 @@ public:
     cmd.drawIndexed.indexCount    = indexCount;
     cmd.drawIndexed.vertexOffset  = vertexOffset;
     cmd.drawIndexed.instanceCount = instanceCount;
-    mCallStack.PushCall("DrawIndexed", "");
+    TraceCallStack::NamedParams namedParams;
+    namedParams["firstIndex"] << firstIndex;
+    namedParams["firstInstance"] << firstInstance;
+    namedParams["indexCount"] << indexCount;
+    namedParams["vertexOffset"] << vertexOffset;
+    namedParams["instanceCount"] << instanceCount;
+    mCallStack.PushCall("DrawIndexed", namedParams.str(), namedParams);
   }
 
   void DrawIndexedIndirect(
@@ -879,7 +890,11 @@ public:
     cmd.drawIndexedIndirect.offset    = offset;
     cmd.drawIndexedIndirect.drawCount = drawCount;
     cmd.drawIndexedIndirect.stride    = stride;
-    mCallStack.PushCall("DrawIndexedIndirect", "");
+    TraceCallStack::NamedParams namedParams;
+    namedParams["offset"] << offset;
+    namedParams["drawCount"] << drawCount;
+    namedParams["stride"] << stride;
+    mCallStack.PushCall("DrawIndexedIndirect", namedParams.str(), namedParams);
   }
 
   void Reset() override
index 3cc464c..14c6d50 100644 (file)
@@ -715,13 +715,13 @@ void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& com
           if(cmd.data.draw.draw.instanceCount == 0)
           {
             mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology),
-                           0,
+                           cmd.data.draw.draw.firstVertex,
                            cmd.data.draw.draw.vertexCount);
           }
           else
           {
             mGl.DrawArraysInstanced(GetTopology(currentPipeline->inputAssemblyState.topology),
-                                    0,
+                                    cmd.data.draw.draw.firstVertex,
                                     cmd.data.draw.draw.vertexCount,
                                     cmd.data.draw.draw.instanceCount);
           }
index 4cad47c..08122d3 100644 (file)
@@ -202,9 +202,9 @@ int UtcDaliDecoratedVisualRendererDefaultProperties(void)
   VisualRenderer          baseVisualRenderer = VisualRenderer::New(geometry, shader);
   Renderer                baseRenderer       = Renderer::New(geometry, shader);
 
-  DALI_TEST_EQUALS(baseRenderer.GetPropertyCount(), 27, TEST_LOCATION);
-  DALI_TEST_EQUALS(baseVisualRenderer.GetPropertyCount(), 27 + 8, TEST_LOCATION);
-  DALI_TEST_EQUALS(renderer.GetPropertyCount(), 27 + 8 + 6, TEST_LOCATION);
+  DALI_TEST_EQUALS(baseRenderer.GetPropertyCount(), 28, TEST_LOCATION);
+  DALI_TEST_EQUALS(baseVisualRenderer.GetPropertyCount(), 28 + 8, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetPropertyCount(), 28 + 8 + 6, TEST_LOCATION);
 
   TEST_RENDERER_PROPERTY(renderer, "cornerRadius", Property::VECTOR4, true, true, true, DecoratedVisualRenderer::Property::CORNER_RADIUS, TEST_LOCATION);
   TEST_RENDERER_PROPERTY(renderer, "cornerRadiusPolicy", Property::FLOAT, true, false, true, DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY, TEST_LOCATION);
index 6d4abd7..9038a62 100644 (file)
@@ -288,7 +288,7 @@ int UtcDaliRendererDefaultProperties(void)
   Geometry geometry = CreateQuadGeometry();
   Shader   shader   = CreateShader();
   Renderer renderer = Renderer::New(geometry, shader);
-  DALI_TEST_EQUALS(renderer.GetPropertyCount(), 27, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetPropertyCount(), 28, TEST_LOCATION);
 
   TEST_RENDERER_PROPERTY(renderer, "depthIndex", Property::INTEGER, true, false, false, Renderer::Property::DEPTH_INDEX, TEST_LOCATION);
   TEST_RENDERER_PROPERTY(renderer, "faceCullingMode", Property::INTEGER, true, false, false, Renderer::Property::FACE_CULLING_MODE, TEST_LOCATION);
@@ -317,6 +317,7 @@ int UtcDaliRendererDefaultProperties(void)
   TEST_RENDERER_PROPERTY(renderer, "opacity", Property::FLOAT, true, true, true, DevelRenderer::Property::OPACITY, TEST_LOCATION);
   TEST_RENDERER_PROPERTY(renderer, "renderingBehavior", Property::INTEGER, true, false, false, DevelRenderer::Property::RENDERING_BEHAVIOR, TEST_LOCATION);
   TEST_RENDERER_PROPERTY(renderer, "blendEquation", Property::INTEGER, true, false, false, DevelRenderer::Property::BLEND_EQUATION, TEST_LOCATION);
+  TEST_RENDERER_PROPERTY(renderer, "instanceCount", Property::INTEGER, true, false, false, Dali::DevelRenderer::Property::INSTANCE_COUNT, TEST_LOCATION);
 
   END_TEST;
 }
@@ -4384,3 +4385,214 @@ int utcDaliRendererDoNotSkipRenderIfTextureSetChanged(void)
 
   END_TEST;
 }
+
+int UtcDaliRendererSetInstanceCount(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test setting the instance count results in instanced draw");
+
+  Property::Map vertexFormat{{"aPosition", Property::VECTOR2}, {"aTexCoord", Property::VECTOR2}};
+  Property::Map instanceFormat{{"aTranslation", Property::VECTOR2}, {"aSize", Property::VECTOR2}};
+
+  const float halfQuadSize = .5f;
+  struct TexturedQuadVertex
+  {
+    Vector2 aPosition;
+    Vector2 aTexCoord;
+  };
+  TexturedQuadVertex texturedQuadVertexData[4] = {
+    {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
+    {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
+    {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
+    {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
+
+  VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
+  vertexBuffer.SetData(texturedQuadVertexData, 4);
+
+  VertexBuffer instanceBuffer = VertexBuffer::New(instanceFormat);
+  instanceBuffer.SetDivisor(1);
+
+  struct Instance
+  {
+    Vector2 aTranslation;
+    Vector2 aSize;
+  };
+  std::vector<Instance> instanceData = {{Vector2{111.f, 222.f}, Vector2{32, 32}}, {Vector2{-112.f, 342.f}, Vector2{32, 32}}, {Vector2{124.f, 294.f}, Vector2{32, 32}}, {Vector2{459.f, -392.f}, Vector2{32, 32}}};
+
+  Dali::Geometry geometry = Dali::Geometry::New();
+  geometry.AddVertexBuffer(vertexBuffer);
+  geometry.AddVertexBuffer(instanceBuffer);
+  geometry.SetType(Geometry::TRIANGLE_STRIP);
+
+  Shader shader = CreateShader();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+  application.GetScene().Add(actor);
+
+  Renderer renderer = Renderer::New(geometry, shader);
+  actor.AddRenderer(renderer);
+
+  auto& graphicsController = application.GetGraphicsController();
+  graphicsController.mCallStack.EnableLogging(true);
+  graphicsController.mCommandBufferCallStack.EnableLogging(true);
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  auto&              drawTrace     = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+  drawTrace.EnableLogging(true);
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Without instance buffer loaded, should not draw");
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawArrays"));
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawArraysInstanced"));
+
+  instanceBuffer.SetData(&instanceData[0], 4);
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("With no instance count set, should not draw instanced.");
+  DALI_TEST_CHECK(drawTrace.FindMethod("DrawArrays"));
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawArraysInstanced"));
+
+  renderer[DevelRenderer::Property::INSTANCE_COUNT] = 4;
+
+  Property::Value v = renderer["instanceCount"];
+  DALI_TEST_EQUALS(v, Property::Value(4), TEST_LOCATION);
+
+  drawTrace.Reset();
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("With instance count set to 4, should draw 4 instances.");
+  TraceCallStack::NamedParams params;
+  params["instanceCount"] << 4;
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawArrays"));
+  DALI_TEST_CHECK(drawTrace.FindMethodAndParams("DrawArraysInstanced", params));
+
+  renderer[DevelRenderer::Property::INSTANCE_COUNT] = 1;
+  drawTrace.Reset();
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("With instance count set to 1, should draw 1 instance.");
+  TraceCallStack::NamedParams params2;
+  params["instanceCount"] << 1;
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawArrays"));
+  DALI_TEST_CHECK(drawTrace.FindMethodAndParams("DrawArraysInstanced", params2));
+
+  renderer[DevelRenderer::Property::INSTANCE_COUNT] = 0;
+  drawTrace.Reset();
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("With instance count set to 0, should revert to DrawArrays.");
+  DALI_TEST_CHECK(drawTrace.FindMethod("DrawArrays"));
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawArraysInstanced"));
+
+  END_TEST;
+}
+
+int UtcDaliRendererVertexRange(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test setting the instance count results in instanced draw");
+
+  Property::Map vertexFormat{{"aPosition", Property::VECTOR2}, {"aTexCoord", Property::VECTOR2}};
+  Property::Map instanceFormat{{"aTranslation", Property::VECTOR2}, {"aSize", Property::VECTOR2}};
+
+  const float halfQuadSize = .5f;
+  struct TexturedQuadVertex
+  {
+    Vector2 aPosition;
+    Vector2 aTexCoord;
+  };
+  TexturedQuadVertex texturedQuadVertexData[4] = {
+    {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
+    {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
+    {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
+    {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
+
+  const int                       VERTEX_SET_COUNT(10);
+  std::vector<TexturedQuadVertex> vertexData;
+  vertexData.resize(VERTEX_SET_COUNT * 4);
+  for(int i = 0; i < VERTEX_SET_COUNT; ++i)
+  {
+    for(int j = 0; j < 4; ++j)
+    {
+      vertexData.push_back({texturedQuadVertexData[j].aPosition * (20.0f * i), texturedQuadVertexData[j].aTexCoord});
+    }
+  }
+
+  VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
+  vertexBuffer.SetData(&vertexData[0], VERTEX_SET_COUNT * 4);
+
+  Dali::Geometry geometry = Dali::Geometry::New();
+  geometry.AddVertexBuffer(vertexBuffer);
+  geometry.SetType(Geometry::TRIANGLE_STRIP);
+
+  Shader shader = CreateShader();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+  application.GetScene().Add(actor);
+
+  for(int i = 0; i < VERTEX_SET_COUNT; ++i)
+  {
+    Renderer renderer                                     = Renderer::New(geometry, shader);
+    renderer[DevelRenderer::Property::VERTEX_RANGE_FIRST] = i * 4;
+    renderer[DevelRenderer::Property::VERTEX_RANGE_COUNT] = 4;
+    actor.AddRenderer(renderer);
+  }
+
+  for(uint32_t i = 0; i < actor.GetRendererCount(); ++i)
+  {
+    auto renderer = actor.GetRendererAt(i);
+    DALI_TEST_EQUALS(renderer.GetProperty<int>(DevelRenderer::Property::VERTEX_RANGE_FIRST), i * 4, TEST_LOCATION);
+    DALI_TEST_EQUALS(renderer.GetProperty<int>(DevelRenderer::Property::VERTEX_RANGE_COUNT), 4, TEST_LOCATION);
+  }
+
+  auto& graphicsController = application.GetGraphicsController();
+  graphicsController.mCallStack.EnableLogging(true);
+  graphicsController.mCommandBufferCallStack.EnableLogging(true);
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  auto&              drawTrace     = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+  drawTrace.EnableLogging(true);
+
+  application.SendNotification();
+  application.Render();
+
+  TraceCallStack::NamedParams namedParams;
+  namedParams["first"] << 0;
+  namedParams["count"] << 4;
+  DALI_TEST_CHECK(drawTrace.FindMethodAndParams("DrawArrays", namedParams));
+
+  namedParams["first"].str("");
+  namedParams["first"].clear();
+  namedParams["first"] << 4;
+  DALI_TEST_CHECK(drawTrace.FindMethodAndParams("DrawArrays", namedParams));
+
+  namedParams["first"].str("");
+  namedParams["first"].clear();
+  namedParams["first"] << 8;
+  DALI_TEST_CHECK(drawTrace.FindMethodAndParams("DrawArrays", namedParams));
+
+  namedParams["first"].str("");
+  namedParams["first"].clear();
+  namedParams["first"] << 12;
+  DALI_TEST_CHECK(drawTrace.FindMethodAndParams("DrawArrays", namedParams));
+
+  namedParams["first"].str("");
+  namedParams["first"].clear();
+  namedParams["first"] << 16;
+  DALI_TEST_CHECK(drawTrace.FindMethodAndParams("DrawArrays", namedParams));
+
+  DALI_TEST_EQUALS(drawTrace.CountMethod("DrawArrays"), 10, TEST_LOCATION);
+  END_TEST;
+}
index 079a3fe..71b7f92 100644 (file)
@@ -500,11 +500,24 @@ int UtcDaliVertexBufferSetDivisor(void)
   params["divisor"] << "1";
   DALI_TEST_CHECK(bufferTrace.FindMethodAndParams("VertexAttribDivisor", params));
 
+  tet_infoline("Test that by default, instancing isn't used");
   TraceCallStack::NamedParams params2;
-  DALI_TEST_CHECK(drawTrace.FindMethodAndGetParameters("DrawArraysInstanced", params2));
-  std::ostringstream oss;
-  oss << sizeof(instanceData) / sizeof(InstanceData);
-  DALI_TEST_EQUALS(params2["instanceCount"].str(), oss.str(), TEST_LOCATION);
+  params2["instanceCount"] << 0;
+  DALI_TEST_CHECK(!drawTrace.FindMethodAndGetParameters("DrawArraysInstanced", params2));
+  DALI_TEST_CHECK(drawTrace.FindMethod("DrawArrays"));
+
+  tet_infoline("Test that instancing is used if Renderer requests an instance count");
+  drawTrace.Reset();
+
+  int instanceCount         = sizeof(instanceData) / sizeof(InstanceData);
+  renderer["instanceCount"] = instanceCount;
+  application.SendNotification();
+  application.Render();
+
+  TraceCallStack::NamedParams params3;
+  params3["instanceCount"] << instanceCount;
+  DALI_TEST_CHECK(drawTrace.FindMethodAndGetParameters("DrawArraysInstanced", params3));
+  DALI_TEST_CHECK(!drawTrace.FindMethod("DrawArrays"));
   END_TEST;
 }
 
index d5b2f70..c86b503 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -189,8 +189,8 @@ int UtcDaliVisualRendererDefaultProperties(void)
   VisualRenderer  renderer     = VisualRenderer::New(geometry, shader);
   Renderer        baseRenderer = Renderer::New(geometry, shader);
 
-  DALI_TEST_EQUALS(baseRenderer.GetPropertyCount(), 27, TEST_LOCATION);
-  DALI_TEST_EQUALS(renderer.GetPropertyCount(), 27 + 8, TEST_LOCATION);
+  DALI_TEST_EQUALS(baseRenderer.GetPropertyCount(), 28, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetPropertyCount(), 28 + 8, TEST_LOCATION);
 
   TEST_RENDERER_PROPERTY(renderer, "transformOffset", Property::VECTOR2, true, true, true, VisualRenderer::Property::TRANSFORM_OFFSET, TEST_LOCATION);
   TEST_RENDERER_PROPERTY(renderer, "transformSize", Property::VECTOR2, true, true, true, VisualRenderer::Property::TRANSFORM_SIZE, TEST_LOCATION);
index 5cfc8fd..8d23214 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_RENDERER_DEVEL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -129,15 +129,15 @@ enum Type
   STENCIL_OPERATION_ON_Z_PASS = Dali::Renderer::Property::STENCIL_OPERATION_ON_Z_PASS,
 
   /**
-     * @brief The opacity of the renderer.
-     * @details Name "opacity", type Property::FLOAT.
-     */
+   * @brief The opacity of the renderer.
+   * @details Name "opacity", type Property::FLOAT.
+   */
   OPACITY = STENCIL_OPERATION_ON_Z_PASS + 1,
 
   /**
-     * @brief The rendering behavior of the renderer.
-     * @details Name "renderingBehavior", type Property::INTEGER.
-     */
+   * @brief The rendering behavior of the renderer.
+   * @details Name "renderingBehavior", type Property::INTEGER.
+   */
   RENDERING_BEHAVIOR = STENCIL_OPERATION_ON_Z_PASS + 2,
 
   /**
@@ -145,6 +145,25 @@ enum Type
    * @note The default value is BlendEquation::ADD
    */
   BLEND_EQUATION = STENCIL_OPERATION_ON_Z_PASS + 3,
+
+  /**
+   * @brief Which vertex to render first from a vertex buffer without indices
+   * @details name "vertexRangeFirst", type INTEGER
+   */
+  VERTEX_RANGE_FIRST = INDEX_RANGE_FIRST,
+
+  /**
+   * @brief How many vertices to render to render from a vertex buffer without indices
+   * @details name "vertexRangeCount", type INTEGER
+   */
+  VERTEX_RANGE_COUNT = INDEX_RANGE_COUNT,
+
+  /**
+   * @brief How many instances to render from a vertex buffer with non-zero divisor.
+   * @note Overrides computed instance count on vertex buffer.
+   * @details name "instanceCount", type INTEGER
+   */
+  INSTANCE_COUNT = STENCIL_OPERATION_ON_Z_PASS + 4,
 };
 } // namespace Property
 
index 0865182..a34ad18 100644 (file)
@@ -65,6 +65,7 @@ DALI_PROPERTY("stencilOperationOnZPass", INTEGER, true, false, false, Dali::Rend
 DALI_PROPERTY("opacity", FLOAT, true, true, true, Dali::DevelRenderer::Property::OPACITY)
 DALI_PROPERTY("renderingBehavior", INTEGER, true, false, false, Dali::DevelRenderer::Property::RENDERING_BEHAVIOR)
 DALI_PROPERTY("blendEquation", INTEGER, true, false, false, Dali::DevelRenderer::Property::BLEND_EQUATION)
+DALI_PROPERTY("instanceCount", INTEGER, true, false, false, Dali::DevelRenderer::Property::INSTANCE_COUNT)
 DALI_PROPERTY_TABLE_END(DEFAULT_RENDERER_PROPERTY_START_INDEX, RendererDefaultProperties)
 
 // Property string to enumeration tables:
@@ -681,6 +682,19 @@ void Renderer::SetDefaultProperty(Property::Index        index,
       }
       break;
     }
+    case DevelRenderer::Property::INSTANCE_COUNT:
+    {
+      int instanceCount;
+      if(propertyValue.Get(instanceCount))
+      {
+        if(instanceCount != int(mInstanceCount))
+        {
+          mInstanceCount = uint32_t(instanceCount);
+          SetInstanceCountMessage(GetEventThreadServices(), GetRendererSceneObject(), mInstanceCount);
+        }
+      }
+      break;
+    }
   }
 }
 
@@ -974,6 +988,11 @@ bool Renderer::GetCachedPropertyValue(Property::Index index, Property::Value& va
       value = mRenderingBehavior;
       break;
     }
+    case DevelRenderer::Property::INSTANCE_COUNT:
+    {
+      value = int(mInstanceCount);
+      break;
+    }
     default:
     {
       // Must be a scene-graph only property
index 3a5ffa1..c292730 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_RENDERER_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -270,6 +270,7 @@ protected:
 
   uint32_t mIndexedDrawFirstElement; ///< Offset of first element to draw from bound index buffer
   uint32_t mIndexedDrawElementCount; ///< Number of elements to draw
+  uint32_t mInstanceCount{0};        ///< Number of instances to draw
 
   Render::Renderer::StencilParameters mStencilParameters; ///< Struct containing all stencil related options
   BlendingOptions                     mBlendingOptions;   ///< Local copy of blending options bitmask
index 06d9e9b..e7774cb 100644 (file)
@@ -98,6 +98,8 @@ public:
    * @return The recalculated size after visual properties applied.
    */
   virtual Vector4 GetVisualTransformedUpdateArea(BufferIndex bufferIndex, const Vector4& originalUpdateArea) noexcept = 0;
+
+  virtual uint32_t GetInstanceCount() const = 0;
 };
 
 } // namespace SceneGraph
index ed21d36..adab748 100644 (file)
@@ -93,7 +93,7 @@ void Geometry::SetIndexBuffer(Uint32ContainerType& indices)
 void Geometry::RemoveVertexBuffer(const Render::VertexBuffer* vertexBuffer)
 {
   const auto&& end = mVertexBuffers.End();
-  // @todo if this buffer is the only instance buffer, reduce instance count to 1.
+
   for(auto&& iter = mVertexBuffers.Begin(); iter != end; ++iter)
   {
     if(*iter == vertexBuffer)
@@ -161,11 +161,6 @@ bool Geometry::BindVertexAttributes(Graphics::CommandBuffer& commandBuffer)
 
   for(uint32_t i = 0; i < vertexBufferCount; ++i)
   {
-    if(mVertexBuffers[i]->GetDivisor() > 0)
-    {
-      mInstanceCount = mVertexBuffers[i]->GetElementCount();
-    }
-
     const GpuBuffer* gpuBuffer = mVertexBuffers[i]->GetGpuBuffer();
     if(gpuBuffer)
     {
@@ -193,7 +188,8 @@ bool Geometry::Draw(
   Graphics::Controller&    graphicsController,
   Graphics::CommandBuffer& commandBuffer,
   uint32_t                 elementBufferOffset,
-  uint32_t                 elementBufferCount)
+  uint32_t                 elementBufferCount,
+  uint32_t                 instanceCount)
 {
   uint32_t numIndices(0u);
   intptr_t firstIndexOffset(0u);
@@ -226,17 +222,19 @@ bool Geometry::Draw(
       commandBuffer.BindIndexBuffer(*ibo, 0, mIndexType);
     }
 
-    commandBuffer.DrawIndexed(numIndices, mInstanceCount, firstIndexOffset, 0, 0);
+    commandBuffer.DrawIndexed(numIndices, instanceCount, firstIndexOffset, 0, 0);
   }
   else
   {
     // Un-indexed draw call
     uint32_t numVertices(0u);
+    uint32_t firstVertex(0u);
 
     // Use element buffer count for drawing arrays (needs changing API, for workaround)
     if(elementBufferCount)
     {
       numVertices = elementBufferCount;
+      firstVertex = elementBufferOffset;
     }
     else if(mVertexBuffers.Count() > 0)
     {
@@ -254,10 +252,11 @@ bool Geometry::Draw(
       }
       numVertices = elementsCount;
     }
+
     // Issue draw call only if there's non-zero numVertices
     if(numVertices)
     {
-      commandBuffer.Draw(numVertices, mInstanceCount, 0, 0);
+      commandBuffer.Draw(numVertices, instanceCount, firstVertex, 0);
     }
   }
   return true;
index 0af4faa..f2f27b2 100644 (file)
@@ -126,14 +126,16 @@ public:
    *
    * @param[in] graphicsController The graphics controller
    * @param[in,out] commandBuffer The current command buffer queue
-   * @param[in] elementBufferOffset The index of first element to draw if index buffer bound
-   * @param[in] elementBufferCount Number of elements to draw if index buffer bound, uses whole buffer when 0
+   * @param[in] elementBufferOffset The index of first vertex / element to draw if index buffer bound
+   * @param[in] elementBufferCount Number of vertices / elements to draw if index buffer bound, uses whole buffer when 0
+   * @param[in] instanceCount Number of instances to draw (use in conjunction with VertexBuffer divisor)
    * @return true if the draw command was issued, false otherwise
    */
   bool Draw(Graphics::Controller&    graphicsController,
             Graphics::CommandBuffer& commandBuffer,
             uint32_t                 elementBufferOffset,
-            uint32_t                 elementBufferCount);
+            uint32_t                 elementBufferCount,
+            uint32_t                 instanceCount);
 
   /**
    * @brief Set up the attributes bind commaneds
@@ -151,7 +153,6 @@ private:
   OwnerPointer<GpuBuffer> mIndexBuffer;
   IndexType               mIndexType;
   Type                    mGeometryType;
-  uint32_t                mInstanceCount{0};
 
   // Booleans
   bool mIndicesChanged : 1;
index 70d0d03..18e3c58 100644 (file)
@@ -612,15 +612,17 @@ bool Renderer::Render(Graphics::CommandBuffer&                             comma
   // Reuse latest bound vertex attributes location, or Bind buffers to attribute locations.
   if(ReuseLatestBoundVertexAttributes(mGeometry) || mGeometry->BindVertexAttributes(commandBuffer))
   {
+    uint32_t instanceCount = mRenderDataProvider->GetInstanceCount();
+
     if(mDrawCommands.empty())
     {
-      drawn = mGeometry->Draw(*mGraphicsController, commandBuffer, mIndexedDrawFirstElement, mIndexedDrawElementsCount);
+      drawn = mGeometry->Draw(*mGraphicsController, commandBuffer, mIndexedDrawFirstElement, mIndexedDrawElementsCount, instanceCount);
     }
     else
     {
       for(auto& cmd : commands)
       {
-        drawn |= mGeometry->Draw(*mGraphicsController, commandBuffer, cmd->firstIndex, cmd->elementCount);
+        drawn |= mGeometry->Draw(*mGraphicsController, commandBuffer, cmd->firstIndex, cmd->elementCount, instanceCount);
       }
     }
   }
index 625e196..a821d29 100644 (file)
@@ -299,6 +299,13 @@ inline void SetRenderCallbackMessage(EventThreadServices& eventThreadServices, c
   new(slot) LocalType(&renderer, &Renderer::SetRenderCallback, callback);
 }
 
+inline void SetInstanceCountMessage(EventThreadServices& eventThreadServices, const Renderer& renderer, uint32_t instanceCount)
+{
+  using LocalType = MessageValue1<SceneGraph::Renderer, uint32_t>;
+  uint32_t* slot  = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
+  new(slot) LocalType(&renderer, &SceneGraph::Renderer::SetInstanceCount, instanceCount);
+}
+
 } // namespace Dali::Internal::SceneGraph
 
 #endif //DALI_INTERNAL_SCENE_GRAPH_RENDERER_MESSAGES_H
index 3d4faab..2a44378 100644 (file)
@@ -642,7 +642,7 @@ void Renderer::DisconnectFromSceneGraph(SceneController& sceneController, Buffer
   mSceneController = nullptr;
 }
 
-Render::RendererKey Renderer::GetRenderer()
+Render::RendererKey Renderer::GetRenderer() const
 {
   return mRenderer;
 }
index 033dfc1..11914ae 100644 (file)
@@ -391,7 +391,7 @@ public:
    * Retrieve the Render thread renderer
    * @return The associated render thread renderer
    */
-  Render::RendererKey GetRenderer();
+  Render::RendererKey GetRenderer() const;
 
   /**
    * Query whether the renderer is fully opaque, fully transparent or transparent.
@@ -439,6 +439,16 @@ public:
    */
   Vector4 GetVisualTransformedUpdateArea(BufferIndex updateBufferIndex, const Vector4& originalUpdateArea) noexcept override;
 
+  uint32_t GetInstanceCount() const override
+  {
+    return mInstanceCount;
+  }
+
+  void SetInstanceCount(uint32_t instanceCount)
+  {
+    mInstanceCount = instanceCount;
+  }
+
   /**
    * Sets RenderCallback object
    *
@@ -570,6 +580,7 @@ private:
 
   uint32_t             mIndexedDrawFirstElement;     ///< first element index to be drawn using indexed draw
   uint32_t             mIndexedDrawElementsCount;    ///< number of elements to be drawn using indexed draw
+  uint32_t             mInstanceCount{0};            ///< The number of instances to be drawn
   uint32_t             mBlendBitmask;                ///< The bitmask of blending options
   uint32_t             mResendFlag;                  ///< Indicate whether data should be resent to the renderer
   UniformMap::SizeType mUniformMapChangeCounter{0u}; ///< Value to check if uniform data should be updated