Merge branch 'devel/master' into tizen accepted/tizen/unified/20230428.155057
authorjoogab.yun <joogab.yun@samsung.com>
Wed, 26 Apr 2023 05:38:05 +0000 (14:38 +0900)
committerjoogab.yun <joogab.yun@samsung.com>
Wed, 26 Apr 2023 05:38:05 +0000 (14:38 +0900)
Change-Id: I85114c943283abae4cac7b0d21a5466d68b9c86f

39 files changed:
automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h
automated-tests/src/dali/dali-test-suite-utils/test-graphics-controller.cpp
automated-tests/src/dali/utc-Dali-Constraint.cpp
automated-tests/src/dali/utc-Dali-TapGestureRecognizer.cpp
automated-tests/src/dali/utc-Dali-VertexBuffer.cpp
dali/graphics-api/graphics-reflection.h
dali/graphics-api/graphics-types.h
dali/integration-api/input-options.cpp
dali/integration-api/input-options.h
dali/internal/event/animation/constraint-base.cpp
dali/internal/event/animation/constraint-base.h
dali/internal/event/animation/constraint-impl.h
dali/internal/event/events/gesture-event-processor.cpp
dali/internal/event/events/gesture-event-processor.h
dali/internal/event/events/tap-gesture/tap-gesture-processor.cpp
dali/internal/event/events/tap-gesture/tap-gesture-processor.h
dali/internal/event/events/tap-gesture/tap-gesture-recognizer.cpp
dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h
dali/internal/event/rendering/vertex-buffer-impl.cpp
dali/internal/event/rendering/vertex-buffer-impl.h
dali/internal/render/renderers/pipeline-cache.cpp
dali/internal/render/renderers/render-geometry.cpp
dali/internal/render/renderers/render-geometry.h
dali/internal/render/renderers/render-vertex-buffer.cpp
dali/internal/render/renderers/render-vertex-buffer.h
dali/internal/render/shaders/program.cpp
dali/internal/update/common/property-owner-messages.h
dali/internal/update/common/property-owner.cpp
dali/internal/update/common/property-owner.h
dali/internal/update/manager/update-algorithms.cpp
dali/internal/update/manager/update-algorithms.h
dali/internal/update/manager/update-manager.cpp
dali/internal/update/manager/update-manager.h
dali/public-api/animation/constraint.cpp
dali/public-api/animation/constraint.h
dali/public-api/dali-core-version.cpp
dali/public-api/rendering/vertex-buffer.cpp
dali/public-api/rendering/vertex-buffer.h
packaging/dali.spec

index 7ba7834..834ae6f 100644 (file)
@@ -2,7 +2,7 @@
 #define TEST_GL_ABSTRACTION_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.
@@ -1893,10 +1893,26 @@ public:
 
   inline void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) override
   {
+    std::stringstream out;
+    out << mode << ", " << first << ", " << count << ", " << instanceCount;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["mode"] << std::hex << mode;
+    namedParams["first"] << first;
+    namedParams["count"] << count;
+    namedParams["instanceCount"] << instanceCount;
+    mDrawTrace.PushCall("DrawArraysInstanced", out.str(), namedParams);
   }
 
   inline void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount) override
   {
+    std::stringstream out;
+    out << mode << ", " << count << ", " << type << ", " << instanceCount;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["mode"] << std::hex << mode;
+    namedParams["count"] << count;
+    namedParams["type"] << std::hex << type;
+    namedParams["indexCount"] << instanceCount;
+    mDrawTrace.PushCall("DrawElementsInstanced", out.str(), namedParams);
   }
 
   inline GLsync FenceSync(GLenum condition, GLbitfield flags) override
@@ -1981,6 +1997,12 @@ public:
 
   inline void VertexAttribDivisor(GLuint index, GLuint divisor) override
   {
+    std::stringstream out;
+    out << index << ", " << divisor;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["index"] << index;
+    namedParams["divisor"] << divisor;
+    mBufferTrace.PushCall("VertexAttribDivisor", out.str(), namedParams);
   }
 
   inline void BindTransformFeedback(GLenum target, GLuint id) override
index 319ec67..3cc464c 100644 (file)
@@ -712,9 +712,19 @@ void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& com
       {
         if(currentPipeline)
         {
-          mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology),
-                         0,
-                         cmd.data.draw.draw.vertexCount);
+          if(cmd.data.draw.draw.instanceCount == 0)
+          {
+            mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology),
+                           0,
+                           cmd.data.draw.draw.vertexCount);
+          }
+          else
+          {
+            mGl.DrawArraysInstanced(GetTopology(currentPipeline->inputAssemblyState.topology),
+                                    0,
+                                    cmd.data.draw.draw.vertexCount,
+                                    cmd.data.draw.draw.instanceCount);
+          }
         }
         break;
       }
@@ -722,10 +732,21 @@ void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& com
       {
         if(currentPipeline)
         {
-          mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
-                           static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
-                           GL_UNSIGNED_SHORT,
-                           reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
+          if(cmd.data.draw.draw.instanceCount == 0)
+          {
+            mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
+                             static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
+                             GL_UNSIGNED_SHORT,
+                             reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
+          }
+          else
+          {
+            mGl.DrawElementsInstanced(GetTopology(currentPipeline->inputAssemblyState.topology),
+                                      static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
+                                      GL_UNSIGNED_SHORT,
+                                      reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex),
+                                      cmd.data.draw.drawIndexed.instanceCount);
+          }
         }
         break;
       }
@@ -983,12 +1004,22 @@ void TestGraphicsController::BindPipeline(TestGraphicsPipeline* pipeline)
     uint32_t attributeOffset = attribute.offset;
     GLsizei  stride          = vi.bufferBindings[attribute.binding].stride;
 
+    auto rate = vi.bufferBindings[attribute.binding].inputRate;
+
     mGl.VertexAttribPointer(attribute.location,
                             GetNumComponents(attribute.format),
                             GetGlType(attribute.format),
                             GL_FALSE, // Not normalized
                             stride,
                             reinterpret_cast<void*>(attributeOffset));
+    if(rate == Graphics::VertexInputRate::PER_VERTEX)
+    {
+      mGl.VertexAttribDivisor(attribute.location, 0);
+    }
+    else if(rate == Graphics::VertexInputRate::PER_INSTANCE)
+    {
+      mGl.VertexAttribDivisor(attribute.location, 1);
+    }
   }
 
   // Cull face setup
index 30b361f..e0255b2 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <dali-test-suite-utils.h>
 #include <dali/public-api/dali-core.h>
+#include <mesh-builder.h>
 #include <stdlib.h>
 
 #include <iostream>
@@ -1628,4 +1629,67 @@ int UtcDaliConstraintComponentNonTransformPropertyConstraintP(void)
   ComponentTest::CheckComponentProperty(application, actor, Actor::Property::COLOR_ALPHA); // Component 3
 
   END_TEST;
+}
+
+
+namespace PostConstraintTest
+{
+void CheckComponentProperty(TestApplication& application, Actor& actor, Handle target)
+{
+  actor.SetProperty(Actor::Property::POSITION, Vector3::ONE);
+  DALI_TEST_EQUALS(actor.GetProperty<Vector3>(Actor::Property::POSITION), Vector3::ONE, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  actor.SetProperty(Actor::Property::POSITION, Vector3::ONE * 2.0f);
+
+  DALI_TEST_EQUALS(actor.GetProperty<Vector3>(Actor::Property::POSITION), Vector3::ONE * 2.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), Vector3::ONE, TEST_LOCATION);
+
+  Property::Index prePropertyIndex = target.RegisterProperty("testPreProperty", Vector3::ZERO);
+  Constraint preConstraint = Constraint::New<Vector3>(target, prePropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs) {
+    output = inputs[0]->GetVector3();
+  });
+  preConstraint.AddSource(Source{actor, Actor::Property::WORLD_POSITION});
+  preConstraint.Apply();
+
+  Property::Index postPropertyIndex = target.RegisterProperty("testPostProperty", Vector3::ZERO);
+  Constraint postConstraint = Constraint::New<Vector3>(target, postPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs) {
+    output = inputs[0]->GetVector3();
+  });
+  postConstraint.AddSource(Source{actor, Actor::Property::WORLD_POSITION});
+  postConstraint.ApplyPost();
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(target.GetCurrentProperty<Vector3>(prePropertyIndex), Vector3(-239.0, -399.0, 1.0), TEST_LOCATION);
+  DALI_TEST_EQUALS(target.GetCurrentProperty<Vector3>(postPropertyIndex), Vector3(-238.0, -398.0, 2.0), TEST_LOCATION);
+
+  preConstraint.Remove();
+  postConstraint.Remove();
+}
+}
+
+int UtcDaliConstraintApplyPost(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  application.GetScene().Add(actor);
+
+  Geometry       targetGeometry = CreateQuadGeometry();
+  Shader         targetShader   = CreateShader();
+  Renderer       targetRenderer = Renderer::New(targetGeometry, targetShader);
+  Actor          targetActor    = Actor::New();
+  RenderTaskList taskList       = application.GetScene().GetRenderTaskList();
+
+  application.GetScene().Add(targetActor);
+  PostConstraintTest::CheckComponentProperty(application, actor, targetShader);         // Shader
+  PostConstraintTest::CheckComponentProperty(application, actor, targetRenderer);       // Renderer
+  PostConstraintTest::CheckComponentProperty(application, actor, targetActor);          // Actor(Node)
+  PostConstraintTest::CheckComponentProperty(application, actor, taskList.GetTask(0u)); // RenderTask
+
+  END_TEST;
 }
\ No newline at end of file
index 165fbc4..0d2064b 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.
@@ -628,3 +628,60 @@ int UtcDaliTapGestureSetMaximumAllowedTime(void)
 
   END_TEST;
 }
+
+int UtcDaliTapGestureSetRecognizerTime(void)
+{
+  TestApplication application;
+
+  TapGestureDetector detector = TapGestureDetector::New();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  detector.Attach(actor);
+
+  try
+  {
+    Integration::SetTapRecognizerTime(0);
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(false); // Should not get here
+  }
+
+  // Reduce the recognizer time. 500 -> 100
+  Integration::SetTapRecognizerTime(100);
+
+  SignalData             data;
+  GestureReceivedFunctor functor(data);
+  detector.DetectedSignal().Connect(&application, functor);
+
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(20.0f, 20.0f), 150));
+
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(20.0f, 20.0f), 200));
+
+  application.SendNotification();
+
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(20.0f, 20.0f), 300));
+
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(20.0f, 20.0f), 450));
+
+  application.SendNotification();
+
+  // The tap fails because the recognizer time has been exceeded
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+
+  // reset recognizer time
+  Integration::SetTapRecognizerTime(500);
+
+  END_TEST;
+}
index 153e8c9..b03d938 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.
@@ -183,6 +183,9 @@ int UtcDaliVertexBufferSetData01(void)
     actor.AddRenderer(renderer);
     application.GetScene().Add(actor);
 
+    auto& drawTrace = application.GetGlAbstraction().GetDrawTrace();
+    drawTrace.Enable(true);
+
     application.SendNotification();
     application.Render(0);
     application.Render();
@@ -191,6 +194,8 @@ int UtcDaliVertexBufferSetData01(void)
     const TestGlAbstraction::BufferDataCalls& bufferDataCalls =
       application.GetGlAbstraction().GetBufferDataCalls();
 
+    DALI_TEST_CHECK(drawTrace.FindMethod("DrawArrays"));
+
     DALI_TEST_EQUALS(bufferDataCalls.size(), 3u, TEST_LOCATION);
 
     DALI_TEST_EQUALS(bufferDataCalls[0], sizeof(texturedQuadVertexData), TEST_LOCATION);
@@ -260,27 +265,31 @@ int UtcDaliVertexBufferSetData02(void)
   application.SendNotification();
   application.Render(0);
 
-  {
-    const TestGlAbstraction::BufferSubDataCalls& bufferSubDataCalls =
-      application.GetGlAbstraction().GetBufferSubDataCalls();
+  END_TEST;
+}
 
-    const TestGlAbstraction::BufferDataCalls& bufferDataCalls =
-      application.GetGlAbstraction().GetBufferDataCalls();
+int UtcDaliVertexBufferMapInitializerList(void)
+{
+  TestApplication application;
 
-    // Should be 3 (2 Render + 1 vertexBuffer reload)
-    DALI_TEST_EQUALS(bufferSubDataCalls.size(), 3u, TEST_LOCATION);
-    DALI_TEST_EQUALS(bufferDataCalls.size(), 3u, TEST_LOCATION);
+  Property::Map texturedQuadVertexFormat = Property::Map{{"aPosition", Property::VECTOR2},
+                                                         {"aTexCoord", Property::VECTOR2},
+                                                         {"aColor", Property::VECTOR4}};
 
-    if(bufferSubDataCalls.size() >= 2)
-    {
-      DALI_TEST_EQUALS(bufferSubDataCalls[1], sizeof(texturedQuadVertexData), TEST_LOCATION);
-    }
+  try
+  {
+    VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
+    tet_result(TET_PASS);
+  }
+  catch(Dali::DaliException& e)
+  {
+    // Shouldn't assert any more
+    tet_result(TET_FAIL);
   }
-
   END_TEST;
 }
 
-int UtcDaliVertexBufferInvalidTypeN(void)
+int UtcDaliVertexBufferInvalidTypeN01(void)
 {
   TestApplication application;
 
@@ -300,6 +309,26 @@ int UtcDaliVertexBufferInvalidTypeN(void)
   END_TEST;
 }
 
+int UtcDaliVertexBufferInvalidTypeN02(void)
+{
+  TestApplication application;
+
+  Property::Map texturedQuadVertexFormat = Property::Map{{"aPosition", Property::MAP},
+                                                         {"aTexCoord", Property::STRING},
+                                                         {"aColor", Property::VECTOR4}};
+
+  try
+  {
+    VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
+    tet_result(TET_FAIL);
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "Property::Type not supported in VertexBuffer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
 int UtcDaliVertexBufferSetDataNegative(void)
 {
   TestApplication    application;
@@ -333,3 +362,87 @@ int UtcDaliVertexBufferGetSizeNegative(void)
   }
   END_TEST;
 }
+
+int UtcDaliVertexBufferSetDivisor(void)
+{
+  TestApplication application;
+
+  Property::Map texturedQuadVertexFormat;
+  texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
+  texturedQuadVertexFormat["aTexCoord"] = Property::VECTOR2;
+
+  Property::Map instanceFormat{{"aTranslate", Property::VECTOR2}, {"aColor", Property::VECTOR4}};
+
+  VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
+  DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(0, vertexBuffer.GetDivisor(), TEST_LOCATION);
+
+  VertexBuffer instanceBuffer = VertexBuffer::New(instanceFormat);
+  DALI_TEST_EQUALS((bool)instanceBuffer, true, TEST_LOCATION);
+
+  const float halfQuadSize = .5f;
+  struct TexturedQuadVertex
+  {
+    Vector2 position;
+    Vector2 textureCoordinates;
+  };
+  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.SetData(texturedQuadVertexData, 4);
+
+  struct InstanceData
+  {
+    Vector2 translate;
+    Vector4 color;
+  };
+
+  InstanceData instanceData[] = {{Vector2(12, 33), Color::WHITE},
+                                 {Vector2(-2000, 43), Color::BLUE},
+                                 {Vector2(200, 43), Color::GREEN},
+                                 {Vector2(-243, 43), Color::TURQUOISE},
+                                 {Vector2(192, 43), Color::CYAN},
+                                 {Vector2(-2000, 43), Color::MAGENTA},
+                                 {Vector2(-292, 393), Color::BLUE},
+                                 {Vector2(-499, 128), Color::BLUE},
+                                 {Vector2(328, 43), Color::BLUE},
+                                 {Vector2(726, 43), Color::BLUE}};
+  instanceBuffer.SetData(instanceData, sizeof(instanceData) / sizeof(InstanceData));
+  instanceBuffer.SetDivisor(1);
+  DALI_TEST_EQUALS(1, instanceBuffer.GetDivisor(), TEST_LOCATION);
+
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer(vertexBuffer);
+  geometry.AddVertexBuffer(instanceBuffer);
+
+  Shader   shader   = CreateShader();
+  Renderer renderer = Renderer::New(geometry, shader);
+  Actor    actor    = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
+  actor.AddRenderer(renderer);
+  application.GetScene().Add(actor);
+
+  TestGlAbstraction& gl          = application.GetGlAbstraction();
+  auto&              bufferTrace = gl.GetBufferTrace();
+  auto&              drawTrace   = gl.GetDrawTrace();
+  bufferTrace.Enable(true);
+  drawTrace.Enable(true);
+
+  application.SendNotification();
+  application.Render();
+
+  TraceCallStack::NamedParams params;
+  params["divisor"] << "1";
+  DALI_TEST_CHECK(bufferTrace.FindMethodAndParams("VertexAttribDivisor", params));
+
+  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);
+  END_TEST;
+}
index b6e187b..5203c65 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_GRAPHICS_REFLECTION_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.
@@ -166,7 +166,9 @@ public:
   // Sampler
 
   /**
-   * @brief Gets all the sampler uniforms
+   * @brief Gets all the sampler uniforms. In the case of arrays of samplers,
+   * it contains only the name of the sampler array without the [N] size, but,
+   * the element count is set to N.
    *
    * @return A vector of the sampler uniforms
    */
index 3d0f0f5..45b8e6f 100644 (file)
@@ -630,6 +630,7 @@ struct VertexInputState
     }
     uint32_t        stride;
     VertexInputRate inputRate;
+    //@todo Add actual rate...
   };
 
   /**
@@ -1149,6 +1150,7 @@ struct UniformInfo
   uint32_t     bufferIndex{0u};
   uint32_t     offset{0u};
   uint32_t     location{0u};
+  uint32_t     elementCount{0u};
 
   bool operator==(const UniformInfo& rhs)
   {
@@ -1157,7 +1159,8 @@ struct UniformInfo
            binding == rhs.binding &&
            bufferIndex == rhs.bufferIndex &&
            offset == rhs.offset &&
-           location == rhs.location;
+           location == rhs.location &&
+           elementCount == rhs.elementCount;
   }
 };
 
index e77ab70..48a2a19 100644 (file)
@@ -154,6 +154,12 @@ void SetTapMaximumAllowedTime(uint32_t time)
   eventProcessor.SetTapMaximumAllowedTime(time);
 }
 
+void SetTapRecognizerTime(uint32_t time)
+{
+  GestureEventProcessor& eventProcessor = ThreadLocalStorage::Get().GetGestureEventProcessor();
+  eventProcessor.SetTapRecognizerTime(time);
+}
+
 } // namespace Integration
 
 } // namespace Dali
index a585e03..f35de12 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTEGRATION_INPUT_OPTIONS_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.
@@ -201,10 +201,34 @@ DALI_CORE_API void SetLongPressMinimumHoldingTime(unsigned int value);
 /**
  * @brief Sets the maximum allowed time required to be recognized as a multi tap gesture (millisecond)
  *
+ * Recognizes how many tap gestures occurred within the maximum allowed time interval.
+ * If there are two tap gestures within this time, it is a double tap gesture.
+ *
+ * @note If it's a double tap, it's like this:
+ * |<---                                           maximumAllowedTime                                           --->|
+ * |(touch down <--recognizerTime--> touch up) <-- maximumAllowedTime --> (touch down <--recognizerTime--> touch up)|
+ *
+ * @see SetTapRecognizerTime()
+ *
  * @param[in] time The time value in milliseconds
  */
 DALI_CORE_API void SetTapMaximumAllowedTime(uint32_t time);
 
+/**
+ * @brief Sets the recognizer time required to be recognized as a tap gesture (millisecond)
+ *
+ * This time is from touch down to touch up to recognize the tap gesture.
+ *
+ * @note The tab is like below:
+ * touch down <--recognizerTime--> touch up
+ * If the time between touch down and touch up is longer than recognizer time, it is not recognized as a tap gesture.
+ *
+ * @see SetTapMaximumAllowedTime()
+ *
+ * @param[in] time The time value in milliseconds
+ */
+DALI_CORE_API void SetTapRecognizerTime(uint32_t time);
+
 } // namespace Integration
 
 } // namespace Dali
index 24230a7..d41825d 100644 (file)
@@ -62,7 +62,8 @@ ConstraintBase::ConstraintBase(Object& object, Property::Index targetPropertyInd
   mRemoveAction(Dali::Constraint::DEFAULT_REMOVE_ACTION),
   mTag(0),
   mApplied(false),
-  mSourceDestroyed(false)
+  mSourceDestroyed(false),
+  mIsPreConstraint(true)
 {
   ObserveObject(object);
 }
@@ -103,15 +104,25 @@ void ConstraintBase::AddSource(Source source)
   }
 }
 
-void ConstraintBase::Apply()
+void ConstraintBase::Apply(bool isPreConstraint)
 {
   if(mTargetObject && !mApplied && !mSourceDestroyed)
   {
     mApplied = true;
-    ConnectConstraint();
+    mIsPreConstraint = isPreConstraint;
+    ConnectConstraint(mIsPreConstraint);
 
     mTargetObject->ApplyConstraint(*this);
   }
+  else
+  {
+    DALI_LOG_ERROR("Fail to apply constraint\n");
+  }
+}
+
+void ConstraintBase::ApplyPost()
+{
+  Apply(false);
 }
 
 void ConstraintBase::Remove()
@@ -122,6 +133,7 @@ void ConstraintBase::Remove()
   {
     mTargetObject->RemoveConstraint(*this);
   }
+  mIsPreConstraint = true;
 }
 
 void ConstraintBase::RemoveInternal()
@@ -137,7 +149,14 @@ void ConstraintBase::RemoveInternal()
       {
         const SceneGraph::PropertyOwner& propertyOwner = mTargetObject->GetSceneObject();
         // Remove from scene-graph
-        RemoveConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
+        if(mIsPreConstraint)
+        {
+          RemoveConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
+        }
+        else
+        {
+          RemovePostConstraintMessage(GetEventThreadServices(), propertyOwner, *(mSceneGraphConstraint));
+        }
         // mSceneGraphConstraint will be deleted in update-thread, remove dangling pointer
         mSceneGraphConstraint = nullptr;
       }
@@ -186,7 +205,7 @@ void ConstraintBase::SceneObjectAdded(Object& object)
      (nullptr == mSceneGraphConstraint) &&
      mTargetObject)
   {
-    ConnectConstraint();
+    ConnectConstraint(mIsPreConstraint);
   }
 }
 
index 2b8ba21..e286e43 100644 (file)
@@ -82,7 +82,12 @@ public:
   /**
    * @copydoc Dali::Constraint::Apply()
    */
-  void Apply();
+  void Apply(bool isPreConstraint = true);
+
+  /**
+   * @copydoc Dali::Constraint::ApplyPost()
+   */
+  void ApplyPost();
 
   /**
    * @copydoc Dali::Constraint::Remove()
@@ -172,7 +177,7 @@ private:
   /**
    * Connect the constraint
    */
-  virtual void ConnectConstraint() = 0;
+  virtual void ConnectConstraint(bool isPreConstraint = true) = 0;
 
 protected:
   /**
@@ -221,6 +226,7 @@ protected:
   uint32_t                          mTag;
   bool                              mApplied : 1;         ///< Whether the constraint has been applied
   bool                              mSourceDestroyed : 1; ///< Is set to true if any of our input source objects are destroyed
+  bool                              mIsPreConstraint : 1; ///< Is set to true if this constraint is run before transform.
 };
 
 } // namespace Internal
index 7b7ec26..1fdb68e 100644 (file)
@@ -106,7 +106,7 @@ private:
   /**
    * @copydoc ConstraintBase::ConnectConstraint()
    */
-  void ConnectConstraint() final
+  void ConnectConstraint(bool isPreConstraint) final
   {
     // Should not come here if target object has been destroyed
     DALI_ASSERT_DEBUG(nullptr != mTargetObject);
@@ -148,7 +148,14 @@ private:
         resetter              = SceneGraph::ConstraintResetter::New(targetObject, *targetProperty, *mSceneGraphConstraint);
       }
       OwnerPointer<SceneGraph::ConstraintBase> transferOwnership(const_cast<SceneGraph::ConstraintBase*>(mSceneGraphConstraint));
-      ApplyConstraintMessage(GetEventThreadServices(), targetObject, transferOwnership);
+      if(isPreConstraint)
+      {
+        ApplyConstraintMessage(GetEventThreadServices(), targetObject, transferOwnership);
+      }
+      else
+      {
+        ApplyPostConstraintMessage(GetEventThreadServices(), targetObject, transferOwnership);
+      }
       if(resetter)
       {
         AddResetterMessage(GetEventThreadServices().GetUpdateManager(), resetter);
@@ -256,7 +263,7 @@ private:
   /**
    * @copydoc ConstraintBase::ConnectConstraint()
    */
-  void ConnectConstraint() final
+  void ConnectConstraint(bool isPreConstraint) final
   {
     // Should not come here if target object has been destroyed
     DALI_ASSERT_DEBUG(nullptr != mTargetObject);
@@ -295,7 +302,14 @@ private:
       if(mSceneGraphConstraint)
       {
         OwnerPointer<SceneGraph::ConstraintBase> transferOwnership(const_cast<SceneGraph::ConstraintBase*>(mSceneGraphConstraint));
-        ApplyConstraintMessage(GetEventThreadServices(), targetObject, transferOwnership);
+        if(isPreConstraint)
+        {
+          ApplyConstraintMessage(GetEventThreadServices(), targetObject, transferOwnership);
+        }
+        else
+        {
+          ApplyPostConstraintMessage(GetEventThreadServices(), targetObject, transferOwnership);
+        }
         if(resetterRequired)
         {
           OwnerPointer<SceneGraph::PropertyResetterBase> resetter = SceneGraph::ConstraintResetter::New(targetObject, *targetProperty, *mSceneGraphConstraint);
index 118c783..260170f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -339,6 +339,11 @@ void GestureEventProcessor::SetTapMaximumAllowedTime(uint32_t time)
   mTapGestureProcessor.SetMaximumAllowedTime(time);
 }
 
+void GestureEventProcessor::SetTapRecognizerTime(uint32_t time)
+{
+  mTapGestureProcessor.SetRecognizerTime(time);
+}
+
 } // namespace Internal
 
 } // namespace Dali
index d2b1930..9731fe6 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_GESTURE_EVENT_PROCESSOR_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.
@@ -291,6 +291,15 @@ public: // Called by Core
    */
   void SetTapMaximumAllowedTime(uint32_t time);
 
+  /**
+   * @brief Sets the recognizer time required to be recognized as a tap gesture (millisecond)
+   *
+   * This time is from touch down to touch up to recognize the tap gesture.
+   *
+   * @param[in] time The time value in milliseconds
+   */
+  void SetTapRecognizerTime(uint32_t time);
+
 public: // needed for PanGesture
   /**
    * @return the pan gesture processor
index bbdac01..04574ba 100644 (file)
@@ -44,6 +44,7 @@ namespace
 {
 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
 constexpr uint32_t DEFAULT_MAXIMUM_ALLOWED_TIME = 500u;
+constexpr uint32_t DEFAULT_RECOGNIZER_TIME      = 500u;
 
 /**
  * Creates a TapGesture and asks the specified detector to emit its detected signal.
@@ -88,7 +89,8 @@ TapGestureProcessor::TapGestureProcessor()
   mMaxTouchesRequired(1),
   mCurrentTapEvent(nullptr),
   mPossibleProcessed(false),
-  mMaximumAllowedTime(DEFAULT_MAXIMUM_ALLOWED_TIME)
+  mMaximumAllowedTime(DEFAULT_MAXIMUM_ALLOWED_TIME),
+  mRecognizerTime(DEFAULT_RECOGNIZER_TIME)
 {
 }
 
@@ -189,7 +191,7 @@ void TapGestureProcessor::AddGestureDetector(TapGestureDetector* gestureDetector
     request.maxTouches = mMaxTouchesRequired;
 
     Size size          = scene.GetSize();
-    mGestureRecognizer = new TapGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const TapGestureRequest&>(request), mMaximumAllowedTime);
+    mGestureRecognizer = new TapGestureRecognizer(*this, Vector2(size.width, size.height), static_cast<const TapGestureRequest&>(request), mMaximumAllowedTime, mRecognizerTime);
   }
   else
   {
@@ -273,6 +275,28 @@ void TapGestureProcessor::SetMaximumAllowedTime(uint32_t time)
   }
 }
 
+void TapGestureProcessor::SetRecognizerTime(uint32_t time)
+{
+  if(time == 0u)
+  {
+    DALI_LOG_WARNING("RecognizerTime must be greater than zero.");
+    return;
+  }
+  if(mRecognizerTime != time)
+  {
+    mRecognizerTime = time;
+
+    if(mGestureRecognizer)
+    {
+      TapGestureRecognizer* tapRecognizer = dynamic_cast<TapGestureRecognizer*>(mGestureRecognizer.Get());
+      if(tapRecognizer)
+      {
+        tapRecognizer->SetRecognizerTime(time);
+      }
+    }
+  }
+}
+
 void TapGestureProcessor::UpdateDetection()
 {
   DALI_ASSERT_DEBUG(!mTapGestureDetectors.empty());
index 9804679..726d77e 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_TAP_GESTURE_EVENT_PROCESSOR_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.
@@ -91,6 +91,15 @@ public: // To be called by GestureEventProcessor
    */
   void SetMaximumAllowedTime(uint32_t time);
 
+  /**
+   * @brief This method sets the recognizer time required to be recognized as a tap gesture (millisecond)
+   *
+   * This time is from touch down to touch up to recognize the tap gesture.
+   *
+   * @param[in] time The time value in milliseconds
+   */
+  void SetRecognizerTime(uint32_t time);
+
 private:
   // Undefined
   TapGestureProcessor(const TapGestureProcessor&);
@@ -135,6 +144,7 @@ private:
   bool                   mPossibleProcessed; ///< Indication of whether we've processed a touch down for this gestuee
 
   uint32_t mMaximumAllowedTime; ///< The maximum allowed time required to be recognized as a multi tap gesture (millisecond)
+  uint32_t mRecognizerTime;     ///< The recognizer time required to be recognized as a tap gesture (millisecond)
 };
 
 } // namespace Internal
index 33ce529..609c161 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.
@@ -39,7 +39,7 @@ namespace
 constexpr float MAXIMUM_MOTION_ALLOWED = 20.0f;
 } // unnamed namespace
 
-TapGestureRecognizer::TapGestureRecognizer(Observer& observer, Vector2 screenSize, const TapGestureRequest& request, uint32_t maximumAllowedTime)
+TapGestureRecognizer::TapGestureRecognizer(Observer& observer, Vector2 screenSize, const TapGestureRequest& request, uint32_t maximumAllowedTime, uint32_t recognizerTime)
 : GestureRecognizer(screenSize, GestureType::TAP),
   mObserver(observer),
   mState(CLEAR),
@@ -50,7 +50,8 @@ TapGestureRecognizer::TapGestureRecognizer(Observer& observer, Vector2 screenSiz
   mTouchTime(0u),
   mLastTapTime(0u),
   mLastTouchTime(0u),
-  mMaximumAllowedTime(maximumAllowedTime)
+  mMaximumAllowedTime(maximumAllowedTime),
+  mRecognizerTime(recognizerTime)
 {
 }
 
@@ -83,7 +84,7 @@ void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
 
         if(pointState == PointState::UP)
         {
-          if(deltaBetweenTouchDownTouchUp < mMaximumAllowedTime)
+          if(deltaBetweenTouchDownTouchUp < mRecognizerTime)
           {
             mLastTapTime = event.time;
             EmitSingleTap(event.time, point);
@@ -107,7 +108,7 @@ void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
         {
           uint32_t deltaBetweenLastTouchDownTouchUp = event.time - mLastTouchTime;
           // Clear if the time between touch down and touch up is long.
-          if(deltaBetweenLastTouchDownTouchUp > mMaximumAllowedTime)
+          if(deltaBetweenLastTouchDownTouchUp > mRecognizerTime)
           {
             mState = CLEAR;
           }
@@ -194,6 +195,11 @@ void TapGestureRecognizer::SetMaximumAllowedTime(uint32_t time)
   mMaximumAllowedTime = time;
 }
 
+void TapGestureRecognizer::SetRecognizerTime(uint32_t time)
+{
+  mRecognizerTime = time;
+}
+
 void TapGestureRecognizer::EmitGesture(GestureState state, uint32_t time)
 {
   if((state == GestureState::CANCELLED) ||
index 293c1c9..e8e36a8 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_EVENT_EVENTS_TAP_GESTURE_RECOGNIZER_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.
@@ -52,8 +52,9 @@ public:
    * @param[in]  screenSize  The size of the screen.
    * @param[in]  request     The tap gesture request.
    * @param[in]  maximumAllowedTime    The maximum allowed time required in milliseconds.
+   * @param[in]  recognizerTime    This recognizer time required in milliseconds.
    */
-  TapGestureRecognizer(Observer& observer, Vector2 screenSize, const TapGestureRequest& request, uint32_t maximumAllowedTime);
+  TapGestureRecognizer(Observer& observer, Vector2 screenSize, const TapGestureRequest& request, uint32_t maximumAllowedTime, uint32_t recognizerTime);
 
   /**
    * Virtual destructor.
@@ -78,6 +79,13 @@ public:
    */
   void SetMaximumAllowedTime(uint32_t time);
 
+  /**
+   * @brief This method sets the recognizer time required to be recognized as a tap gesture (millisecond)
+   *
+   * @param[in] time The time value in milliseconds
+   */
+  void SetRecognizerTime(uint32_t time);
+
 private:
   /**
    * Checks if registered taps are within required bounds and emits tap gesture if they are.
@@ -152,6 +160,7 @@ private:
   uint32_t mLastTouchTime; ///< The last touch down time.
 
   uint32_t mMaximumAllowedTime; ///< The maximum allowed time required to be recognized as a multi tap gesture (millisecond)
+  uint32_t mRecognizerTime;     ///< The recognizer time required to be recognized as a tap gesture (millisecond)
 };
 
 } // namespace Internal
index 689d703..547d60d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -171,6 +171,17 @@ uint32_t VertexBuffer::GetSize() const
   return mSize;
 }
 
+void VertexBuffer::SetDivisor(uint32_t divisor)
+{
+  SceneGraph::SetVertexBufferDivisorMessage(mEventThreadServices.GetUpdateManager(), *mRenderObject, divisor);
+  mDivisor = divisor;
+}
+
+uint32_t VertexBuffer::GetDivisor() const
+{
+  return mDivisor;
+}
+
 const Render::VertexBuffer* VertexBuffer::GetRenderObject() const
 {
   return mRenderObject;
@@ -222,6 +233,15 @@ void VertexBuffer::Initialize(Dali::Property::Map& formatMap)
     Property::Type type = Property::Type(component.second.Get<int>());
 
     // Get the size and alignment
+    if(type == Property::NONE)
+    {
+      /* Note, Property::Value() has an explicit constructor using Property::Type enum,
+       * which will generate a property value of that type. This constructor is used when
+       * using C++ initializer lists.
+       */
+      type = component.second.GetType();
+    }
+
     if((type == Property::NONE) ||
        (type == Property::STRING) ||
        (type == Property::ARRAY) ||
@@ -229,6 +249,7 @@ void VertexBuffer::Initialize(Dali::Property::Map& formatMap)
     {
       DALI_ABORT("Property::Type not supported in VertexBuffer");
     }
+
     uint32_t elementSize      = GetPropertyImplementationSize(type);
     uint32_t elementAlignment = GetPropertyImplementationAlignment(type);
 
index dcba098..a10a886 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_VERTEX_BUFFER_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.
@@ -44,20 +44,30 @@ class VertexBuffer : public BaseObject
 {
 public:
   /**
-   * @copydoc PropertBuffer::New()
+   * @copydoc Dali::VertexBuffer::New()
    */
   static VertexBufferPtr New(Dali::Property::Map& format);
 
   /**
-   * @copydoc PropertBuffer::SetData()
+   * @copydoc Dali::VertexBuffer::SetData()
    */
   void SetData(const void* data, uint32_t size);
 
   /**
-   * @copydoc PropertBuffer::GetSize()
+   * @copydoc Dali::VertexBuffer::GetSize()
    */
   uint32_t GetSize() const;
 
+  /**
+   * @copydoc Dali::VertexBuffer::SetDivisor()
+   */
+  void SetDivisor(uint32_t divisor);
+
+  /**
+   * @copydoc Dali::VertexBuffer::GetDivisor()
+   */
+  uint32_t GetDivisor() const;
+
 public: // Default property extensions from Object
   /**
    * @brief Get the render thread side of the VertexBuffer
@@ -87,11 +97,12 @@ private: // unimplemented methods
   VertexBuffer(const VertexBuffer&);
   VertexBuffer& operator=(const VertexBuffer&);
 
-private:                                      // data
-  EventThreadServices&  mEventThreadServices; ///<Used to send messages to the render thread via update thread
-  Render::VertexBuffer* mRenderObject;        ///<Render side object
-  uint32_t              mBufferFormatSize;
-  uint32_t              mSize; ///< Number of elements in the buffer
+private:                                        // data
+  EventThreadServices&  mEventThreadServices;   ///<Used to send messages to the render thread via update thread
+  Render::VertexBuffer* mRenderObject{nullptr}; ///<Render side object
+  uint32_t              mBufferFormatSize{0};
+  uint32_t              mSize{0};    ///< Number of elements in the buffer
+  uint32_t              mDivisor{0}; ///< How many elements to skip in instanced draw
 };
 
 /**
index 3f655f4..4e4633f 100644 (file)
@@ -209,8 +209,14 @@ PipelineCacheL0* PipelineCache::GetPipelineCacheL0(std::size_t hash, Program* pr
     {
       const VertexBuffer::Format& vertexFormat = *vertexBuffer->GetFormat();
 
+      uint32_t                  divisor         = vertexBuffer->GetDivisor();
+      Graphics::VertexInputRate vertexInputRate = (divisor == 0
+                                                     ? Graphics::VertexInputRate::PER_VERTEX
+                                                     : Graphics::VertexInputRate::PER_INSTANCE);
+
       vertexInputState.bufferBindings.emplace_back(vertexFormat.size, // stride
-                                                   Graphics::VertexInputRate::PER_VERTEX);
+                                                   vertexInputRate);
+      //@todo Add the actual rate to the graphics struct
 
       const uint32_t attributeCount          = vertexBuffer->GetAttributeCount();
       uint32_t       lastBoundAttributeIndex = 0;
index b407b6f..83be141 100644 (file)
@@ -93,6 +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)
@@ -159,6 +160,11 @@ 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)
     {
@@ -219,7 +225,7 @@ bool Geometry::Draw(
       commandBuffer.BindIndexBuffer(*ibo, 0, mIndexType);
     }
 
-    commandBuffer.DrawIndexed(numIndices, 1, firstIndexOffset, 0, 0);
+    commandBuffer.DrawIndexed(numIndices, mInstanceCount, firstIndexOffset, 0, 0);
   }
   else
   {
@@ -232,7 +238,7 @@ bool Geometry::Draw(
       numVertices = static_cast<uint32_t>(mVertexBuffers[0]->GetElementCount());
     }
 
-    commandBuffer.Draw(numVertices, 1, 0, 0);
+    commandBuffer.Draw(numVertices, mInstanceCount, 0, 0);
   }
   return true;
 }
index 2f04c97..0af4faa 100644 (file)
@@ -151,6 +151,7 @@ private:
   OwnerPointer<GpuBuffer> mIndexBuffer;
   IndexType               mIndexType;
   Type                    mGeometryType;
+  uint32_t                mInstanceCount{0};
 
   // Booleans
   bool mIndicesChanged : 1;
index 1a881d1..b140cef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -78,6 +78,16 @@ bool VertexBuffer::Update(Graphics::Controller& graphicsController)
   return true;
 }
 
+void VertexBuffer::SetDivisor(uint32_t divisor)
+{
+  mDivisor = divisor;
+}
+
+uint32_t VertexBuffer::GetDivisor()
+{
+  return mDivisor;
+}
+
 } // namespace Render
 } // namespace Internal
 } // namespace Dali
index b7074ef..a8b86c1 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_RENDER_VERTEX_BUFFER_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.
@@ -87,6 +87,17 @@ public:
   bool Update(Graphics::Controller& graphicsController);
 
   /**
+   * @brief Set the divisor of the buffer for instanced drawing
+   * @param[in] divisor The divisor (0 = not instanced, >=1 = instanced)
+   */
+  void SetDivisor(uint32_t divisor);
+
+  /**
+   * Get the divisor for the vertex buffer
+   */
+  [[nodiscard]] uint32_t GetDivisor();
+
+  /**
    * Get the number of attributes present in the buffer
    * @return The number of attributes stored in this buffer
    */
@@ -152,6 +163,7 @@ private:
   OwnerPointer<GpuBuffer>              mGpuBuffer; ///< Pointer to the GpuBuffer associated with this RenderVertexBuffer
 
   uint32_t mSize;        ///< Number of Elements in the buffer
+  uint32_t mDivisor{0};  ///< The divisor (0:not instanced, >=1:instanced)
   bool     mDataChanged; ///< Flag to know if data has changed in a frame
 };
 
index 4cfbcb4..f6d9f97 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.
@@ -143,7 +143,7 @@ void Program::BuildReflection(const Graphics::Reflection& graphicsReflection)
   }
 
   // add samplers
-  auto samplers = graphicsReflection.GetSamplers();
+  auto samplers = graphicsReflection.GetSamplers(); // Only holds first element of arrays without [].
   for(const auto& sampler : samplers)
   {
     mReflection.emplace_back(ReflectionUniformInfo{CalculateHash(sampler.name), false, sampler});
index d6d24e2..9dce203 100644 (file)
@@ -248,6 +248,31 @@ inline void RemoveConstraintMessage(EventThreadServices& eventThreadServices, co
   new(slot) LocalType(&owner, &PropertyOwner::RemoveConstraint, &constraint);
 }
 
+inline void ApplyPostConstraintMessage(EventThreadServices& eventThreadServices, const PropertyOwner& owner, OwnerPointer<ConstraintBase>& constraint)
+{
+  using LocalType = MessageValue1<PropertyOwner, OwnerPointer<ConstraintBase> >;
+
+  // Reserve some memory inside the message queue
+  uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new(slot) LocalType(&owner, &PropertyOwner::ApplyPostConstraint, constraint);
+}
+
+inline void RemovePostConstraintMessage(EventThreadServices& eventThreadServices, const PropertyOwner& owner, const ConstraintBase& constConstraint)
+{
+  // The update-thread can modify this object.
+  ConstraintBase& constraint = const_cast<ConstraintBase&>(constConstraint);
+
+  using LocalType = MessageValue1<PropertyOwner, ConstraintBase*>;
+
+  // Reserve some memory inside the message queue
+  uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new(slot) LocalType(&owner, &PropertyOwner::RemovePostConstraint, &constraint);
+}
+
 inline void AddUniformMapMessage(EventThreadServices& eventThreadServices, const PropertyOwner& owner, UniformPropertyMapping map)
 {
   using LocalType = MessageValue1<PropertyOwner, UniformPropertyMapping>;
index 1111f94..314e335 100644 (file)
@@ -83,6 +83,7 @@ void PropertyOwner::Destroy()
 
   // Remove all constraints when disconnected from scene-graph
   mConstraints.Clear();
+  mPostConstraints.Clear();
 }
 
 void PropertyOwner::ConnectToSceneGraph()
@@ -111,6 +112,7 @@ void PropertyOwner::DisconnectFromSceneGraph(BufferIndex updateBufferIndex)
 
   // Remove all constraints when disconnected from scene-graph
   mConstraints.Clear();
+  mPostConstraints.Clear();
 }
 
 void PropertyOwner::ReserveProperties(int propertyCount)
@@ -149,6 +151,32 @@ void PropertyOwner::RemoveConstraint(ConstraintBase* constraint)
   //it may be that the constraint has already been removed e.g. from disconnection from scene graph, so nothing needs to be done
 }
 
+ConstraintOwnerContainer& PropertyOwner::GetPostConstraints()
+{
+  return mPostConstraints;
+}
+
+void PropertyOwner::ApplyPostConstraint(OwnerPointer<ConstraintBase>& constraint)
+{
+  constraint->OnConnect();
+  mPostConstraints.PushBack(constraint.Release());
+}
+
+void PropertyOwner::RemovePostConstraint(ConstraintBase* constraint)
+{
+  const ConstraintIter constraintEndIter = mPostConstraints.End();
+  for(ConstraintIter iter = mPostConstraints.Begin(); constraintEndIter != iter; ++iter)
+  {
+    if(*iter == constraint)
+    {
+      mPostConstraints.Erase(iter);
+      return; // We're finished
+    }
+  }
+
+  //it may be that the constraint has already been removed e.g. from disconnection from scene graph, so nothing needs to be done
+}
+
 PropertyOwner::PropertyOwner()
 : mUpdated(false),
   mIsConnectedToSceneGraph(false)
index 769dc35..9850e2f 100644 (file)
@@ -192,12 +192,30 @@ public:
   void RemoveConstraint(ConstraintBase* constraint);
 
   /**
+   * Apply a post constraint.
+   * @param[in] constraint The constraint to apply.
+   */
+  void ApplyPostConstraint(OwnerPointer<ConstraintBase>& constraint);
+
+  /**
+   * Begin removal of post constraints.
+   * @param[in] constraint The constraint to remove.
+   */
+  void RemovePostConstraint(ConstraintBase* constraint);
+
+  /**
    * Retrieve the constraints that are currently applied.
    * @return A container of constraints.
    */
   ConstraintOwnerContainer& GetConstraints();
 
   /**
+   * Retrieve the post constraints that are currently applied.
+   * @return A container of post constraints.
+   */
+  ConstraintOwnerContainer& GetPostConstraints();
+
+  /**
    * @copydoc UniformMap::Add
    */
   virtual void AddUniformMapping(const UniformPropertyMapping& map);
@@ -267,6 +285,7 @@ private:
   ObserverContainer mObservers; ///< Container of observer raw-pointers (not owned)
 
   ConstraintOwnerContainer mConstraints; ///< Container of owned constraints
+  ConstraintOwnerContainer mPostConstraints; ///< Container of owned constraints
 };
 
 } // namespace SceneGraph
index 9cdd211..0cfd6dd 100644 (file)
@@ -51,9 +51,9 @@ Debug::Filter* gUpdateFilter = Debug::Filter::New(Debug::Concise, false, "LOG_UP
  * @param propertyOwner to constrain
  * @param updateBufferIndex buffer index to use
  */
-void ConstrainPropertyOwner(PropertyOwner& propertyOwner, BufferIndex updateBufferIndex)
+void ConstrainPropertyOwner(PropertyOwner& propertyOwner, BufferIndex updateBufferIndex, bool isPreConstraint)
 {
-  ConstraintOwnerContainer& constraints = propertyOwner.GetConstraints();
+  ConstraintOwnerContainer& constraints = (isPreConstraint) ? propertyOwner.GetConstraints() : propertyOwner.GetPostConstraints();
 
   const ConstraintIter endIter = constraints.End();
   for(ConstraintIter iter = constraints.Begin(); iter != endIter; ++iter)
@@ -97,14 +97,19 @@ inline void UpdateNodeOpacity(Node& node, NodePropertyFlags nodeDirtyFlags, Buff
 /**
  * This is called recursively for all children of the root Node
  */
-inline NodePropertyFlags UpdateNodes(Node&             node,
-                                     NodePropertyFlags parentFlags,
-                                     BufferIndex       updateBufferIndex,
-                                     RenderQueue&      renderQueue,
-                                     bool              updated)
+inline NodePropertyFlags UpdateNodes(Node&                   node,
+                                     NodePropertyFlags       parentFlags,
+                                     BufferIndex             updateBufferIndex,
+                                     RenderQueue&            renderQueue,
+                                     PropertyOwnerContainer& postPropertyOwners,
+                                     bool                    updated)
 {
   // Apply constraints to the node
   ConstrainPropertyOwner(node, updateBufferIndex);
+  if(!node.GetPostConstraints().Empty())
+  {
+    postPropertyOwners.PushBack(&node);
+  }
 
   // Some dirty flags are inherited from parent
   NodePropertyFlags nodeDirtyFlags = node.GetDirtyFlags() | node.GetInheritedDirtyFlags(parentFlags);
@@ -133,6 +138,7 @@ inline NodePropertyFlags UpdateNodes(Node&             node,
                                         nodeDirtyFlags,
                                         updateBufferIndex,
                                         renderQueue,
+                                        postPropertyOwners,
                                         updated);
   }
 
@@ -142,9 +148,10 @@ inline NodePropertyFlags UpdateNodes(Node&             node,
 /**
  * The root node is treated separately; it cannot inherit values since it has no parent
  */
-NodePropertyFlags UpdateNodeTree(Layer&       rootNode,
-                                 BufferIndex  updateBufferIndex,
-                                 RenderQueue& renderQueue)
+NodePropertyFlags UpdateNodeTree(Layer&                  rootNode,
+                                 BufferIndex             updateBufferIndex,
+                                 RenderQueue&            renderQueue,
+                                 PropertyOwnerContainer& postPropertyOwners)
 {
   DALI_ASSERT_DEBUG(rootNode.IsRoot());
 
@@ -180,6 +187,7 @@ NodePropertyFlags UpdateNodeTree(Layer&       rootNode,
                                         nodeDirtyFlags,
                                         updateBufferIndex,
                                         renderQueue,
+                                        postPropertyOwners,
                                         updated);
   }
 
index eeeb09e..ce0ed89 100644 (file)
@@ -32,12 +32,15 @@ class Layer;
 class PropertyOwner;
 class RenderQueue;
 
+using PropertyOwnerContainer = Dali::Vector<PropertyOwner*>;
+
 /**
  * Constrain the local properties of the PropertyOwner.
  * @param[in] propertyOwner The PropertyOwner to constrain
  * @param[in] updateBufferIndex The current update buffer index.
+ * @param[in] isPreConstraint True if the constraint is performed before transform.
  */
-void ConstrainPropertyOwner(PropertyOwner& propertyOwner, BufferIndex updateBufferIndex);
+void ConstrainPropertyOwner(PropertyOwner& propertyOwner, BufferIndex updateBufferIndex, bool isPreConstraint = true);
 
 /**
  * Update a tree of nodes
@@ -45,11 +48,13 @@ void ConstrainPropertyOwner(PropertyOwner& propertyOwner, BufferIndex updateBuff
  * @param[in] rootNode The root of a tree of nodes.
  * @param[in] updateBufferIndex The current update buffer index.
  * @param[in] renderQueue Used to query messages for the next Render.
+ * @param[out] postPropertyOwner property owners those have post constraint.
  * @return The cumulative (ORed) dirty flags for the updated nodes
  */
-NodePropertyFlags UpdateNodeTree(Layer&       rootNode,
-                                 BufferIndex  updateBufferIndex,
-                                 RenderQueue& renderQueue);
+NodePropertyFlags UpdateNodeTree(Layer&                  rootNode,
+                                 BufferIndex             updateBufferIndex,
+                                 RenderQueue&            renderQueue,
+                                 PropertyOwnerContainer& postPropertyOwners);
 /**
  * This updates all the sub-layer's reusability flags without affecting
  * the root layer.
index 4a2f1bb..d7437f1 100644 (file)
@@ -42,6 +42,7 @@
 
 #include <dali/internal/render/common/render-manager.h>
 #include <dali/internal/render/queue/render-queue.h>
+#include <dali/internal/render/renderers/render-vertex-buffer.h>
 
 // Un-comment to enable node tree debug logging
 //#define NODE_TREE_LOGGING 1
@@ -830,16 +831,20 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds)
   return animationActive;
 }
 
-void UpdateManager::ConstrainCustomObjects(BufferIndex bufferIndex)
+void UpdateManager::ConstrainCustomObjects(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
 {
   // Constrain custom objects (in construction order)
   for(auto&& object : mImpl->customObjects)
   {
     ConstrainPropertyOwner(*object, bufferIndex);
+    if(!object->GetPostConstraints().Empty())
+    {
+      postPropertyOwners.PushBack(object);
+    }
   }
 }
 
-void UpdateManager::ConstrainRenderTasks(BufferIndex bufferIndex)
+void UpdateManager::ConstrainRenderTasks(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
 {
   // Constrain render-tasks
   for(auto&& scene : mImpl->scenes)
@@ -850,17 +855,25 @@ void UpdateManager::ConstrainRenderTasks(BufferIndex bufferIndex)
       for(auto&& task : tasks)
       {
         ConstrainPropertyOwner(*task, bufferIndex);
+        if(!task->GetPostConstraints().Empty())
+        {
+          postPropertyOwners.PushBack(task);
+        }
       }
     }
   }
 }
 
-void UpdateManager::ConstrainShaders(BufferIndex bufferIndex)
+void UpdateManager::ConstrainShaders(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
 {
   // constrain shaders... (in construction order)
   for(auto&& shader : mImpl->shaders)
   {
     ConstrainPropertyOwner(*shader, bufferIndex);
+    if(!shader->GetPostConstraints().Empty())
+    {
+      postPropertyOwners.PushBack(shader);
+    }
   }
 }
 
@@ -901,19 +914,23 @@ void UpdateManager::ForwardCompiledShadersToEventThread()
   }
 }
 
-void UpdateManager::UpdateRenderers(BufferIndex bufferIndex)
+void UpdateManager::UpdateRenderers(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
 {
   for(const auto& rendererKey : mImpl->renderers)
   {
     // Apply constraints
     auto renderer = rendererKey.Get();
     ConstrainPropertyOwner(*renderer, bufferIndex);
+    if(!renderer->GetPostConstraints().Empty())
+    {
+      postPropertyOwners.PushBack(renderer);
+    }
 
     mImpl->renderingRequired = renderer->PrepareRender(bufferIndex) || mImpl->renderingRequired;
   }
 }
 
-void UpdateManager::UpdateNodes(BufferIndex bufferIndex)
+void UpdateManager::UpdateNodes(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
 {
   mImpl->nodeDirtyFlags = NodePropertyFlags::NOTHING;
 
@@ -925,7 +942,8 @@ void UpdateManager::UpdateNodes(BufferIndex bufferIndex)
       // And add the renderers to the sorted layers. Start from root, which is also a layer
       mImpl->nodeDirtyFlags |= UpdateNodeTree(*scene->root,
                                               bufferIndex,
-                                              mImpl->renderQueue);
+                                              mImpl->renderQueue,
+                                              postPropertyOwners);
     }
   }
 }
@@ -996,8 +1014,9 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
     // Animate
     bool animationActive = Animate(bufferIndex, elapsedSeconds);
 
+    PropertyOwnerContainer postPropertyOwners;
     // Constraint custom objects
-    ConstrainCustomObjects(bufferIndex);
+    ConstrainCustomObjects(postPropertyOwners, bufferIndex);
 
     // Clear the lists of renderers from the previous update
     for(auto&& scene : mImpl->scenes)
@@ -1021,14 +1040,14 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
     }
 
     // Update node hierarchy, apply constraints,
-    UpdateNodes(bufferIndex);
+    UpdateNodes(postPropertyOwners, bufferIndex);
 
     // Apply constraints to RenderTasks, shaders
-    ConstrainRenderTasks(bufferIndex);
-    ConstrainShaders(bufferIndex);
+    ConstrainRenderTasks(postPropertyOwners, bufferIndex);
+    ConstrainShaders(postPropertyOwners, bufferIndex);
 
     // Update renderers and apply constraints
-    UpdateRenderers(bufferIndex);
+    UpdateRenderers(postPropertyOwners, bufferIndex);
 
     // Update the transformations of all the nodes
     if(mImpl->transformManager.Update())
@@ -1036,6 +1055,12 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
       mImpl->nodeDirtyFlags |= NodePropertyFlags::TRANSFORM;
     }
 
+    // Constraint applied after transform manager updated. Only required property owner processed.
+    for(auto&& propertyOwner : postPropertyOwners)
+    {
+      ConstrainPropertyOwner(*propertyOwner, bufferIndex, false);
+    }
+
     // Initialise layer renderable reuse
     UpdateLayers(bufferIndex);
 
@@ -1375,6 +1400,13 @@ void UpdateManager::SetVertexBufferData(Render::VertexBuffer* vertexBuffer, Owne
   new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetVertexBufferData, vertexBuffer, data, size);
 }
 
+void UpdateManager::SetVertexBufferDivisor(Render::VertexBuffer* vertexBuffer, uint32_t divisor)
+{
+  using LocalType = MessageValue1<Render::VertexBuffer, uint32_t>;
+  uint32_t* slot  = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(LocalType));
+  new(slot) LocalType(vertexBuffer, &Render::VertexBuffer::SetDivisor, divisor);
+}
+
 void UpdateManager::AddGeometry(OwnerPointer<Render::Geometry>& geometry)
 {
   // Message has ownership of format while in transit from update -> render
index 908f827..674a603 100644 (file)
@@ -477,6 +477,14 @@ public:
   void SetVertexBufferData(Render::VertexBuffer* vertexBuffer, OwnerPointer<Vector<uint8_t>>& data, uint32_t size);
 
   /**
+   * Sets the divisor of a vertex buffer. This is used by the GPU to provide
+   * instanced drawing.
+   * @param[in] vertexBuffer The property buffer.
+   * @param[in] divisor The instance divisor. 0 to turn instancing off.
+   */
+  void SetVertexBufferDivisor(Render::VertexBuffer* vertexBuffer, uint32_t divisor);
+
+  /**
    * Adds a geometry to the RenderManager
    * @param[in] geometry The geometry to add
    * @post Sends a message to RenderManager to add the Geometry
@@ -739,21 +747,24 @@ private:
 
   /**
    * Applies constraints to CustomObjects
+   * @param[out] postPropertyOwner property owners those have post constraint.
    * @param[in] bufferIndex to use
    */
-  void ConstrainCustomObjects(BufferIndex bufferIndex);
+  void ConstrainCustomObjects(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex);
 
   /**
    * Applies constraints to RenderTasks
+   * @param[out] postPropertyOwner property owners those have post constraint.
    * @param[in] bufferIndex to use
    */
-  void ConstrainRenderTasks(BufferIndex bufferIndex);
+  void ConstrainRenderTasks(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex);
 
   /**
    * Applies constraints to Shaders
+   * @param[out] postPropertyOwner property owners those have post constraint.
    * @param[in] bufferIndex to use
    */
-  void ConstrainShaders(BufferIndex bufferIndex);
+  void ConstrainShaders(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex);
 
   /**
    * Perform property notification updates
@@ -768,9 +779,10 @@ private:
 
   /**
    * Update node shaders, opacity, geometry etc.
+   * @param[out] postPropertyOwner property owners those have post constraint.
    * @param[in] bufferIndex to use
    */
-  void UpdateNodes(BufferIndex bufferIndex);
+  void UpdateNodes(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex);
 
   /**
    * initialize layer renderables
@@ -780,9 +792,10 @@ private:
 
   /**
    * Update Renderers
+   * @param[out] postPropertyOwner property owners those have post constraint.
    * @param[in] bufferIndex to use
    */
-  void UpdateRenderers(BufferIndex bufferIndex);
+  void UpdateRenderers(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex);
 
 private:
   // needs to be direct member so that getter for event buffer can be inlined
@@ -1263,6 +1276,13 @@ inline void SetVertexBufferData(UpdateManager& manager, Render::VertexBuffer& ve
   new(slot) LocalType(&manager, &UpdateManager::SetVertexBufferData, &vertexBuffer, data, size);
 }
 
+inline void SetVertexBufferDivisorMessage(UpdateManager& manager, Render::VertexBuffer& vertexBuffer, uint32_t divisor)
+{
+  using LocalType = MessageValue2<UpdateManager, Render::VertexBuffer*, uint32_t>;
+  uint32_t* slot  = manager.ReserveMessageSlot(sizeof(LocalType));
+  new(slot) LocalType(&manager, &UpdateManager::SetVertexBufferDivisor, &vertexBuffer, divisor);
+}
+
 inline void AddGeometry(UpdateManager& manager, OwnerPointer<Render::Geometry>& geometry)
 {
   // Message has ownership of Geometry while in transit from event -> update
index 8fdc606..e8b5ea5 100644 (file)
@@ -70,6 +70,11 @@ void Constraint::Apply()
   GetImplementation(*this).Apply();
 }
 
+void Constraint::ApplyPost()
+{
+  GetImplementation(*this).ApplyPost();
+}
+
 void Constraint::Remove()
 {
   GetImplementation(*this).Remove();
index 8df0446..51a4f72 100644 (file)
@@ -454,16 +454,30 @@ public:
   void AddSource(ConstraintSource source);
 
   /**
-   * @brief Applies this constraint.
+   * @brief Applies this constraint to be computed before transform.
    *
    * @SINCE_1_0.0
    * @pre The constraint must be initialized.
    * @pre The target object must still be alive.
    * @pre The source inputs should not have been destroyed.
+   *
+   * @note This method cannot be called with ApplyPost at the same time.
    */
   void Apply();
 
   /**
+   * @brief Applies this constraint to be computed after transform.
+   *
+   * @SINCE_2_2.23
+   * @pre The constraint must be initialized.
+   * @pre The target object must still be alive.
+   * @pre The source inputs should not have been destroyed.
+   *
+   * @note This method cannot be called with Apply at the same time.
+   */
+  void ApplyPost();
+
+  /**
    * @brief Removes this constraint.
    * @SINCE_1_0.0
    */
index 2bc0924..6343b5d 100644 (file)
@@ -27,7 +27,7 @@ namespace Dali
 {
 const uint32_t    CORE_MAJOR_VERSION = 2;
 const uint32_t    CORE_MINOR_VERSION = 2;
-const uint32_t    CORE_MICRO_VERSION = 22;
+const uint32_t    CORE_MICRO_VERSION = 23;
 const char* const CORE_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index c2351c4..85b8bb3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 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.
@@ -58,6 +58,16 @@ std::size_t VertexBuffer::GetSize() const
   return GetImplementation(*this).GetSize();
 }
 
+void VertexBuffer::SetDivisor(uint32_t divisor)
+{
+  GetImplementation(*this).SetDivisor(divisor);
+}
+
+uint32_t VertexBuffer::GetDivisor() const
+{
+  return GetImplementation(*this).GetDivisor();
+}
+
 VertexBuffer::VertexBuffer(Internal::VertexBuffer* pointer)
 : BaseHandle(pointer)
 {
index 6c80284..7300a38 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_VERTEX_BUFFER_H
 
 /*
- * Copyright (c) 2020 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.
@@ -171,6 +171,27 @@ public:
    */
   std::size_t GetSize() const;
 
+  /**
+   * @brief Sets vertex divisor for all attributes
+   *
+   * If instancing isn't supported, the function has no effect.
+   * It's responsibility of developer to make sure the feature is supported.
+   * A divisor of 0 will turn off instanced drawing.
+   * Currently, a divisor > 1 will turn on instanced draw, but will have an
+   * actual rate of 1.
+   *
+   * @param[in] divisor Sets vertex buffer divisor for an instanced draw
+   */
+  void SetDivisor(uint32_t divisor);
+
+  /**
+   * @brief Get the divisor for the given attribute. A return value of 0 means that
+   * instancing is turned off.
+   *
+   * @return either 0 (not instanced), or > 0 (instanced)
+   */
+  uint32_t GetDivisor() const;
+
 public:
   /**
    * @brief The constructor.
index 50216cd..7c799d5 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2
 Summary:    DALi 3D Engine
-Version:    2.2.22
+Version:    2.2.23
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT