Seperate some matrix operations to MatrixUtils 51/283151/18
authorEunki, Hong <eunkiki.hong@samsung.com>
Wed, 19 Oct 2022 05:33:36 +0000 (14:33 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Mon, 24 Oct 2022 04:31:26 +0000 (13:31 +0900)
Move some static Matrix / Matrix3 operations into specific file.
Previous logic doesn't support multiply-asign operations.

 A = A * B; (valid. Because A operator=({result-of-(A*B)}))
 A *= B; (invalid)

To resolve this issue, we plan to implement another operator *= for Matrix.

To seperate codes more clean + If we plan to make some util API about Matrix
(something like Internal::MatrixUtils::MultiplyProjectionMatrix)
Make another file for matrix utils internal.

TODO : Internal::MatrixUtils::MultiplyProjectionMatrix use NEON.
TODO : Make projection matrix use MatrixUtils after camera refator finished

Change-Id: I4333c52c93fb24f618ed509fe101a83e4a9f36c1
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
19 files changed:
automated-tests/src/dali-internal/CMakeLists.txt
automated-tests/src/dali-internal/utc-Dali-Internal-MatrixUtils.cpp [new file with mode: 0644]
automated-tests/src/dali/utc-Dali-Matrix.cpp
automated-tests/src/dali/utc-Dali-Matrix3.cpp
dali/internal/common/matrix-utils.cpp [new file with mode: 0644]
dali/internal/common/matrix-utils.h [new file with mode: 0644]
dali/internal/event/actors/actor-coords.cpp
dali/internal/event/actors/camera-actor-impl.cpp
dali/internal/event/common/projection.cpp
dali/internal/file.list
dali/internal/render/renderers/render-renderer.cpp
dali/internal/update/common/animatable-property.h
dali/internal/update/manager/render-instruction-processor.cpp
dali/internal/update/manager/transform-manager.cpp
dali/internal/update/render-tasks/scene-graph-camera.cpp
dali/public-api/math/matrix.cpp
dali/public-api/math/matrix.h
dali/public-api/math/matrix3.cpp
dali/public-api/math/matrix3.h

index c1a3fcb..02c9cf4 100644 (file)
@@ -17,6 +17,7 @@ SET(TC_SOURCES
         utc-Dali-Internal-IndexedConstStringMap.cpp
         utc-Dali-Internal-IndexedIntegerMap.cpp
         utc-Dali-Internal-LongPressGesture.cpp
+        utc-Dali-Internal-MatrixUtils.cpp
         utc-Dali-Internal-MemoryPoolObjectAllocator.cpp
         utc-Dali-Internal-OwnerPointer.cpp
         utc-Dali-Internal-PinchGesture.cpp
diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-MatrixUtils.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-MatrixUtils.cpp
new file mode 100644 (file)
index 0000000..8b6ce8f
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-test-suite-utils.h>
+#include <dali/devel-api/actors/camera-actor-devel.h>
+#include <dali/internal/common/matrix-utils.h>
+#include <dali/public-api/dali-core.h>
+#include <stdlib.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace Dali;
+
+namespace
+{
+// Final projection matrix logic, calculated at scene-graph-camera.
+Matrix CalculateFinalProjectionMatrix(Matrix projection, uint32_t mProjectionRotation)
+{
+  Matrix     finalProjection;
+  Quaternion rotationAngle;
+  switch(mProjectionRotation)
+  {
+    case 90:
+    {
+      rotationAngle = Quaternion(Dali::ANGLE_90, Vector3::ZAXIS);
+      break;
+    }
+    case 180:
+    {
+      rotationAngle = Quaternion(Dali::ANGLE_180, Vector3::ZAXIS);
+      break;
+    }
+    case 270:
+    {
+      rotationAngle = Quaternion(Dali::ANGLE_270, Vector3::ZAXIS);
+      break;
+    }
+    default:
+      rotationAngle = Quaternion(Dali::ANGLE_0, Vector3::ZAXIS);
+      break;
+  }
+
+  Matrix rotation;
+  rotation.SetIdentity();
+  rotation.SetTransformComponents(Vector3(1.0f, 1.0f, 1.0f), rotationAngle, Vector3(0.0f, 0.0f, 0.0f));
+
+  Dali::Internal::MatrixUtils::Multiply(finalProjection, projection, rotation);
+
+  return finalProjection;
+}
+
+} // namespace
+
+void utc_dali_internal_matrix_utils_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_internal_matrix_utils_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+// Dali::Matrix
+
+int UtcDaliMatrixUtilsMultiplyMatrixP(void)
+{
+  const float ll[16] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+  const float rr[16] = {1.0f, 5.0f, 0.0f, 0.0f, 2.0f, 6.0f, 0.0f, 0.0f, 3.0f, 7.0f, 0.0f, 0.0f, 4.0f, 8.0f, 0.0f, 0.0f};
+  Matrix      left(ll);
+  Matrix      right(rr);
+
+  const float els[16] = {26.0f, 32.0f, 38.0f, 44.0f, 32.0f, 40.0f, 48.0f, 56.0f, 38.0f, 48.0f, 58.0f, 68.0f, 44.0f, 56.0f, 68.0f, 80.0f};
+  Matrix      result(els);
+
+  Matrix multResult;
+
+  // Get result by Multiply API
+  Internal::MatrixUtils::Multiply(multResult, right, left);
+  DALI_TEST_EQUALS(multResult, result, 0.01f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliMatrixUtilsMultiplyMatrixQuaternionP(void)
+{
+  Matrix m1 = Matrix::IDENTITY;
+
+  float  els[] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.707f, 0.707f, 0.0f, 0.0f, -0.707f, 0.707f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+  Matrix result(els);
+
+  Quaternion q(Radian(Degree(45.0f)), Vector3::XAXIS);
+  Matrix     m2(false);
+  Internal::MatrixUtils::Multiply(m2, m1, q);
+
+  DALI_TEST_EQUALS(m2, result, 0.01f, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliMatrixUtilsMultiplyProjectionMatrix(void)
+{
+  tet_infoline("Multiplication Assign operator with self matrix\n");
+
+  Matrix viewMatrix;
+  Matrix projectionMatrix;
+  Matrix finalProjectionMatrix;
+
+  Matrix expectViewProjection;
+  Matrix resultViewProjection;
+
+  TestApplication application;
+
+  Vector2 sceneSize = application.GetScene().GetSize();
+
+  CameraActor camera = CameraActor::New();
+  DALI_TEST_CHECK(camera);
+  application.GetScene().Add(camera);
+
+  // Rotate camera 4 times
+  for(int32_t i = 0; i < 4; i++)
+  {
+    int32_t rotationAngle = i * 90;
+    tet_printf("Window rotation angle : %d\n", rotationAngle);
+
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+    application.Render();
+
+    for(int32_t repeatCount = 0; repeatCount < 10; repeatCount++)
+    {
+      Vector3    pos         = Vector3(Dali::Random::Range(-50.0f, 50.0f), Dali::Random::Range(-50.0f, 50.0f), Dali::Random::Range(-50.0f, 50.0f));
+      Vector3    axis        = Vector3(Dali::Random::Range(1.0f, 50.0f), Dali::Random::Range(-50.0f, 50.0f), Dali::Random::Range(-50.0f, 50.0f));
+      float      radian      = Dali::Random::Range(0.0f, 5.0f);
+      Quaternion orientation = Quaternion(Radian(radian), axis);
+
+      camera.SetPerspectiveProjection(sceneSize);
+
+      // Change ViewMatrix randomly.
+      camera.SetProperty(Dali::Actor::Property::POSITION, pos);
+      camera.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
+
+      application.SendNotification();
+      application.Render();
+      application.SendNotification();
+      application.Render();
+
+      camera.GetProperty(CameraActor::CameraActor::Property::PROJECTION_MATRIX).Get(projectionMatrix);
+      camera.GetProperty(CameraActor::CameraActor::Property::VIEW_MATRIX).Get(viewMatrix);
+      finalProjectionMatrix = CalculateFinalProjectionMatrix(projectionMatrix, rotationAngle);
+
+      // Get result by Multiply API
+      Internal::MatrixUtils::Multiply(expectViewProjection, viewMatrix, finalProjectionMatrix);
+      // Get result by MultiplyProjectionMatrix API
+      Internal::MatrixUtils::MultiplyProjectionMatrix(resultViewProjection, viewMatrix, finalProjectionMatrix);
+
+      {
+        std::ostringstream oss;
+        oss << "projection : " << projectionMatrix << "\n";
+        oss << "final      : " << finalProjectionMatrix << "\n";
+        oss << "view       : " << viewMatrix << "\n";
+        oss << "expect     : " << expectViewProjection << "\n";
+        oss << "result     : " << resultViewProjection << "\n";
+        tet_printf("pespective : \n%s\n", oss.str().c_str());
+      }
+
+      DALI_TEST_EQUALS(resultViewProjection, expectViewProjection, 0.01f, TEST_LOCATION);
+
+      camera.SetOrthographicProjection(sceneSize);
+
+      // Change ViewMatrix randomly.
+      camera.SetProperty(Dali::Actor::Property::POSITION, pos);
+      camera.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
+
+      application.SendNotification();
+      application.Render();
+      application.SendNotification();
+      application.Render();
+
+      camera.GetProperty(CameraActor::CameraActor::Property::PROJECTION_MATRIX).Get(projectionMatrix);
+      camera.GetProperty(CameraActor::CameraActor::Property::VIEW_MATRIX).Get(viewMatrix);
+      finalProjectionMatrix = CalculateFinalProjectionMatrix(projectionMatrix, rotationAngle);
+
+      // Get result by Multiply API
+      Internal::MatrixUtils::Multiply(expectViewProjection, viewMatrix, finalProjectionMatrix);
+      // Get result by MultiplyProjectionMatrix API
+      Internal::MatrixUtils::MultiplyProjectionMatrix(resultViewProjection, viewMatrix, finalProjectionMatrix);
+
+      {
+        std::ostringstream oss;
+        oss << "projection : " << projectionMatrix << "\n";
+        oss << "final      : " << finalProjectionMatrix << "\n";
+        oss << "view       : " << viewMatrix << "\n";
+        oss << "expect     : " << expectViewProjection << "\n";
+        oss << "result     : " << resultViewProjection << "\n";
+        tet_printf("orthographic : \n%s\n", oss.str().c_str());
+      }
+
+      DALI_TEST_EQUALS(resultViewProjection, expectViewProjection, 0.01f, TEST_LOCATION);
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliMatrixUtilsMultiplyAssignMatrix01P(void)
+{
+  tet_infoline("Multiplication Assign operator\n");
+  const float ll[16] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 0.0f, 0.0f, 11.0f, 12.0f, 0.0f, 0.0f};
+  const float rr[16] = {1.0f, 5.0f, 9.0f, 10.0f, 2.0f, 6.0f, 11.0f, 12.0f, 3.0f, 7.0f, 0.0f, 0.0f, 4.0f, 8.0f, 0.0f, 0.0f};
+  Matrix      left(ll);
+  Matrix      right(rr);
+
+  const float els[16] = {217.0f, 242.0f, 38.0f, 44.0f, 263.0f, 294.0f, 48.0f, 56.0f, 38.0f, 48.0f, 58.0f, 68.0f, 44.0f, 56.0f, 68.0f, 80.0f};
+  Matrix      result(els);
+
+  // Get result by MultiplyAssign API
+  Internal::MatrixUtils::MultiplyAssign(left, right);
+  DALI_TEST_EQUALS(left, result, 0.01f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliMatrixUtilsMultiplyAssignMatrix02P(void)
+{
+  tet_infoline("Multiplication Assign operator with self matrix\n");
+  const float ll[16] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 0.0f, 0.0f, 11.0f, 12.0f, 0.0f, 0.0f};
+  Matrix      left(ll);
+
+  const float els[16] = {82.0f, 92.0f, 17.0f, 20.0f, 186.0f, 212.0f, 57.0f, 68.0f, 59.0f, 78.0f, 97.0f, 116.0f, 71.0f, 94.0f, 117.0f, 140.0f};
+  Matrix      result(els);
+
+  // Get result by MultiplyAssign API
+  Internal::MatrixUtils::MultiplyAssign(left, left);
+  DALI_TEST_EQUALS(left, result, 0.01f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Dali::Matrix3
+
+int UtcDaliMatrixUtilsMultiplyMatrix3P(void)
+{
+  Matrix3 left(
+    1.0f, 2.0f, 3.0f, 5.0f, 6.0f, 7.0f, 0.0f, 0.0f, 0.0f);
+  Matrix3 right(
+    1.0f, 5.0f, 0.0f, 2.0f, 6.0f, 0.0f, 3.0f, 7.0f, 0.0f);
+
+  Matrix3 result(
+    26.0f, 32.0f, 38.0f, 32.0f, 40.0f, 48.0f, 38.0f, 48.0f, 58.0f);
+
+  Matrix3 multResult;
+
+  // Get result by Multiply API
+  Internal::MatrixUtils::Multiply(multResult, right, left);
+  DALI_TEST_EQUALS(multResult, result, 0.01f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliMatrixUtilsMultiplyAssignMatrix301P(void)
+{
+  tet_infoline("Multiplication Assign operator\n");
+  Matrix3 left(
+    1.0f, 2.0f, 3.0f, 5.0f, 6.0f, 7.0f, 9.0f, 10.0f, 0.0f);
+  Matrix3 right(
+    1.0f, 5.0f, 9.0f, 2.0f, 6.0f, 11.0f, 3.0f, 7.0f, 0.0f);
+
+  Matrix3 result(
+    107.0f, 122.0f, 38.0f, 131.0f, 150.0f, 48.0f, 38.0f, 48.0f, 58.0f);
+
+  // Get result by MultiplyAssign API
+  Internal::MatrixUtils::MultiplyAssign(left, right);
+  DALI_TEST_EQUALS(left, result, 0.01f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliMatrixUtilsMultiplyAssignMatrix302P(void)
+{
+  tet_infoline("Multiplication Assign operator with self matrix\n");
+  Matrix3 left(
+    1.0f, 2.0f, 3.0f, 5.0f, 6.0f, 7.0f, 9.0f, 10.0f, 0.0f);
+
+  Matrix3 result(
+    38.0f, 44.0f, 17.0f, 98.0f, 116.0f, 57.0f, 59.0f, 78.0f, 97.0f);
+
+  // Get result by MultiplyAssign API
+  Internal::MatrixUtils::MultiplyAssign(left, left);
+  DALI_TEST_EQUALS(left, result, 0.01f, TEST_LOCATION);
+
+  END_TEST;
+}
index d689185..f72dd93 100644 (file)
@@ -583,6 +583,50 @@ int UtcDaliMatrixOperatorMultiply03P(void)
   END_TEST;
 }
 
+int UtcDaliMatrixOperatorMultiplyAssign01P(void)
+{
+  tet_infoline("Multiplication Assign operator\n");
+  const float ll[16] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 0.0f, 0.0f, 11.0f, 12.0f, 0.0f, 0.0f};
+  const float rr[16] = {1.0f, 5.0f, 9.0f, 10.0f, 2.0f, 6.0f, 11.0f, 12.0f, 3.0f, 7.0f, 0.0f, 0.0f, 4.0f, 8.0f, 0.0f, 0.0f};
+  Matrix      left(ll);
+  Matrix      right(rr);
+  Matrix      copyedLeft(ll);
+
+  const float els[16] = {217.0f, 242.0f, 38.0f, 44.0f, 263.0f, 294.0f, 48.0f, 56.0f, 38.0f, 48.0f, 58.0f, 68.0f, 44.0f, 56.0f, 68.0f, 80.0f};
+  Matrix      result(els);
+
+  // Get result by operator*
+  Matrix multResult = left * right;
+  DALI_TEST_EQUALS(multResult, result, 0.01f, TEST_LOCATION);
+
+  // Get result by operator*=
+  left *= right;
+  DALI_TEST_EQUALS(left, result, 0.01f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliMatrixOperatorMultiplyAssign02P(void)
+{
+  tet_infoline("Multiplication Assign operator with self matrix\n");
+  const float ll[16] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 0.0f, 0.0f, 11.0f, 12.0f, 0.0f, 0.0f};
+  Matrix      left(ll);
+  Matrix      copyedLeft(ll);
+
+  const float els[16] = {82.0f, 92.0f, 17.0f, 20.0f, 186.0f, 212.0f, 57.0f, 68.0f, 59.0f, 78.0f, 97.0f, 116.0f, 71.0f, 94.0f, 117.0f, 140.0f};
+  Matrix      result(els);
+
+  // Get result by operator*
+  Matrix multResult = left * copyedLeft;
+  DALI_TEST_EQUALS(multResult, result, 0.01f, TEST_LOCATION);
+
+  // Get result by operator*=
+  left *= left;
+  DALI_TEST_EQUALS(left, result, 0.01f, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliMatrixOperatorEqualsP(void)
 {
   Matrix m1 = Matrix::IDENTITY;
index 9e59a29..6fffad2 100644 (file)
@@ -354,6 +354,48 @@ int UtcDaliMatrix3OperatorMultiply03P(void)
   END_TEST;
 }
 
+int UtcDaliMatrix3OperatorMultiplyAssign01P(void)
+{
+  tet_infoline("Multiplication Assign operator\n");
+  Matrix3 left(
+    1.0f, 2.0f, 3.0f, 5.0f, 6.0f, 7.0f, 9.0f, 10.0f, 0.0f);
+  Matrix3 right(
+    1.0f, 5.0f, 9.0f, 2.0f, 6.0f, 11.0f, 3.0f, 7.0f, 0.0f);
+  Matrix3 copiedLeft(left);
+
+  Matrix3 result(
+    107.0f, 122.0f, 38.0f, 131.0f, 150.0f, 48.0f, 38.0f, 48.0f, 58.0f);
+
+  // Get result by operator*
+  Matrix3 multResult = left * right;
+  DALI_TEST_EQUALS(multResult, result, 0.01f, TEST_LOCATION);
+
+  // Get result by operator*=
+  left *= right;
+  DALI_TEST_EQUALS(left, result, 0.01f, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliMatrix3OperatorMultiplyAssign02P(void)
+{
+  tet_infoline("Multiplication Assign operator with self matrix\n");
+  Matrix3 left(
+    1.0f, 2.0f, 3.0f, 5.0f, 6.0f, 7.0f, 9.0f, 10.0f, 0.0f);
+  Matrix3 copiedLeft(left);
+
+  Matrix3 result(
+    38.0f, 44.0f, 17.0f, 98.0f, 116.0f, 57.0f, 59.0f, 78.0f, 97.0f);
+
+  // Get result by operator*
+  Matrix3 multResult = left * copiedLeft;
+  DALI_TEST_EQUALS(multResult, result, 0.01f, TEST_LOCATION);
+
+  // Get result by operator*=
+  left *= left;
+  DALI_TEST_EQUALS(left, result, 0.01f, TEST_LOCATION);
+  END_TEST;
+}
+
 int UtcDaliMatrix3EqualityOperator(void)
 {
   Matrix3 m1(0.0f, 3.0f, 6.0f, 12.0f, 15.0f, 18.0f, 24.0f, 27.0f, 30.0f);
diff --git a/dali/internal/common/matrix-utils.cpp b/dali/internal/common/matrix-utils.cpp
new file mode 100644 (file)
index 0000000..ce2eb1f
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADERS
+#include <dali/internal/common/matrix-utils.h>
+
+// EXTERNAL INCLUDES
+#include <cstdint> // uint32_t
+#include <cstring> // memcpy
+
+// INTERNAL INCLUDE
+#include <dali/internal/render/common/performance-monitor.h>
+#include <dali/public-api/math/matrix.h>
+#include <dali/public-api/math/matrix3.h>
+#include <dali/public-api/math/quaternion.h>
+
+namespace
+{
+const uint32_t NUM_BYTES_IN_MATRIX(16 * sizeof(float));
+const uint32_t NUM_BYTES_IN_MATRIX3(9 * sizeof(float));
+
+} // namespace
+
+namespace Dali::Internal
+{
+using Internal::PerformanceMonitor;
+
+namespace MatrixUtils
+{
+// Dali::Quaternion
+
+void ConvertQuaternion(float*& result, const Dali::Quaternion& rotation)
+{
+  MATH_INCREASE_COUNTER(PerformanceMonitor::QUATERNION_TO_MATRIX);
+
+  const float xx = rotation.mVector.x * rotation.mVector.x;
+  const float yy = rotation.mVector.y * rotation.mVector.y;
+  const float zz = rotation.mVector.z * rotation.mVector.z;
+  const float xy = rotation.mVector.x * rotation.mVector.y;
+  const float xz = rotation.mVector.x * rotation.mVector.z;
+  const float wx = rotation.mVector.w * rotation.mVector.x;
+  const float wy = rotation.mVector.w * rotation.mVector.y;
+  const float wz = rotation.mVector.w * rotation.mVector.z;
+  const float yz = rotation.mVector.y * rotation.mVector.z;
+
+  // clang-format off
+  result[0] = 1.0f - 2.0f * (yy + zz);
+  result[1] =        2.0f * (xy + wz);
+  result[2] =        2.0f * (xz - wy);
+  result[3] = 0.0f;
+
+  result[4] =        2.0f * (xy - wz);
+  result[5] = 1.0f - 2.0f * (xx + zz);
+  result[6] =        2.0f * (yz + wx);
+  result[7] = 0.0f;
+
+  result[8] =        2.0f * (xz + wy);
+  result[9] =        2.0f * (yz - wx);
+  result[10]= 1.0f - 2.0f * (xx + yy);
+  result[11]= 0.0f;
+
+  result[12]= 0.0f;
+  result[13]= 0.0f;
+  result[14]= 0.0f;
+  result[15]= 1.0f;
+  // clang-format on
+}
+
+// Dali::Matrix
+
+void Multiply(Dali::Matrix& result, const Dali::Matrix& lhs, const Dali::Matrix& rhs)
+{
+  MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
+  MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY, 64); // 64 = 16*4
+
+  float*       temp   = result.AsFloat();
+  const float* rhsPtr = rhs.AsFloat();
+  const float* lhsPtr = lhs.AsFloat();
+
+#ifndef __ARM_NEON__
+
+  for(int32_t i = 0; i < 4; i++)
+  {
+    // i<<2 gives the first vector / column
+    const int32_t loc0 = i << 2;
+    const int32_t loc1 = loc0 + 1;
+    const int32_t loc2 = loc0 + 2;
+    const int32_t loc3 = loc0 + 3;
+
+    const float value0 = lhsPtr[loc0];
+    const float value1 = lhsPtr[loc1];
+    const float value2 = lhsPtr[loc2];
+    const float value3 = lhsPtr[loc3];
+
+    temp[loc0] = (value0 * rhsPtr[0]) +
+                 (value1 * rhsPtr[4]) +
+                 (value2 * rhsPtr[8]) +
+                 (value3 * rhsPtr[12]);
+
+    temp[loc1] = (value0 * rhsPtr[1]) +
+                 (value1 * rhsPtr[5]) +
+                 (value2 * rhsPtr[9]) +
+                 (value3 * rhsPtr[13]);
+
+    temp[loc2] = (value0 * rhsPtr[2]) +
+                 (value1 * rhsPtr[6]) +
+                 (value2 * rhsPtr[10]) +
+                 (value3 * rhsPtr[14]);
+
+    temp[loc3] = (value0 * rhsPtr[3]) +
+                 (value1 * rhsPtr[7]) +
+                 (value2 * rhsPtr[11]) +
+                 (value3 * rhsPtr[15]);
+  }
+
+#else
+
+  // 64 32bit registers,
+  // aliased to
+  // d = 64 bit double-word d0 -d31
+  // q =128 bit quad-word   q0 -q15  (enough to handle a column of 4 floats in a matrix)
+  // e.g. q0 = d0 and d1
+
+  // load and stores interleaved as NEON can load and store while calculating
+  asm volatile(
+    "VLDM         %1,  {q0-q3}        \n\t" // load matrix 1 (lhsPtr) q[0..q3]
+    "VLDM         %0,  {q8-q11}       \n\t" // load matrix 2 (rhsPtr) q[q8-q11]
+    "VMUL.F32     q12, q8, d0[0]      \n\t" // column 0 = rhsPtr[0..3] * lhsPtr[0..3]
+    "VMUL.F32     q13, q8, d2[0]      \n\t" // column 1 = rhsPtr[0..3] * lhsPtr[4..7]
+    "VMUL.F32     q14, q8, d4[0]      \n\t" // column 2 = rhsPtr[0..3] * lhsPtr[8..11]
+    "VMUL.F32     q15, q8, d6[0]      \n\t" // column 3 = rhsPtr[0..3] * lhsPtr[12..15]
+
+    "VMLA.F32     q12, q9, d0[1]      \n\t" // column 0 += rhsPtr[4..7] * lhsPtr[0..3]
+    "VMLA.F32     q13, q9, d2[1]      \n\t" // column 1 += rhsPtr[4..7] * lhsPtr[4..7]
+    "VMLA.F32     q14, q9, d4[1]      \n\t" // column 2 += rhsPtr[4..7] * lhsPtr[8..11]
+    "VMLA.F32     q15, q9, d6[1]      \n\t" // column 3 += rhsPtr[4..7] * lhsPtr[12..15]
+
+    "VMLA.F32     q12, q10, d1[0]     \n\t" // column 0 += rhsPtr[8..11] * lhsPtr[0..3]
+    "VMLA.F32     q13, q10, d3[0]     \n\t" // column 1 += rhsPtr[8..11] * lhsPtr[4..7]
+    "VMLA.F32     q14, q10, d5[0]     \n\t" // column 2 += rhsPtr[8..11] * lhsPtr[8..11]
+    "VMLA.F32     q15, q10, d7[0]     \n\t" // column 3 += rhsPtr[8..11] * lhsPtr[12..15]
+
+    "VMLA.F32     q12, q11, d1[1]     \n\t" // column 0 += rhsPtr[12..15] * lhsPtr[0..3]
+    "VMLA.F32     q13, q11, d3[1]     \n\t" // column 1 += rhsPtr[12..15] * lhsPtr[4..7]
+    "VMLA.F32     q14, q11, d5[1]     \n\t" // column 2 += rhsPtr[12..15] * lhsPtr[8..11]
+    "VMLA.F32     q15, q11, d7[1]     \n\t" // column 3 += rhsPtr[12..15] * lhsPtr[12..15]
+    "VSTM         %2,  {q12-q15}      \n\t" // store entire output matrix.
+    : "+r"(rhsPtr), "+r"(lhsPtr), "+r"(temp)
+    :
+    : "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", "memory");
+
+#endif
+}
+
+void Multiply(Dali::Matrix& result, const Dali::Matrix& lhs, const Dali::Quaternion& rhs)
+{
+  MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
+  MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY, 54); // 54 = 36+18
+
+  float  matrix[16];
+  float* rhsPtr = &matrix[0];
+  ConvertQuaternion(rhsPtr, rhs);
+
+  // quaternion contains just rotation so it really only needs 3x3 matrix
+
+  float*       temp   = result.AsFloat();
+  const float* lhsPtr = lhs.AsFloat();
+
+#ifndef __ARM_NEON__
+
+  for(int32_t i = 0; i < 4; i++)
+  {
+    // i<<2 gives the first vector / column
+    const int32_t loc0 = i << 2;
+    const int32_t loc1 = loc0 + 1;
+    const int32_t loc2 = loc0 + 2;
+    const int32_t loc3 = loc0 + 3;
+
+    const float value0 = lhsPtr[loc0];
+    const float value1 = lhsPtr[loc1];
+    const float value2 = lhsPtr[loc2];
+    const float value3 = lhsPtr[loc3];
+
+    temp[loc0] = (value0 * rhsPtr[0]) +
+                 (value1 * rhsPtr[4]) +
+                 (value2 * rhsPtr[8]) +
+                 (0.0f); //value3 * rhsPtr[12] is 0.0f
+
+    temp[loc1] = (value0 * rhsPtr[1]) +
+                 (value1 * rhsPtr[5]) +
+                 (value2 * rhsPtr[9]) +
+                 (0.0f); //value3 * rhsPtr[13] is 0.0f
+
+    temp[loc2] = (value0 * rhsPtr[2]) +
+                 (value1 * rhsPtr[6]) +
+                 (value2 * rhsPtr[10]) +
+                 (0.0f); //value3 * rhsPtr[14] is 0.0f
+
+    temp[loc3] = (0.0f) +  //value0 * rhsPtr[3] is 0.0f
+                 (0.0f) +  //value1 * rhsPtr[7] is 0.0f
+                 (0.0f) +  //value2 * rhsPtr[11] is 0.0f
+                 (value3); // rhsPtr[15] is 1.0f
+  }
+
+#else
+
+  // 64 32bit registers,
+  // aliased to
+  // d = 64 bit double-word d0 -d31
+  // q =128 bit quad-word   q0 -q15  (enough to handle a column of 4 floats in a matrix)
+  // e.g. q0 = d0 and d1
+  // load and stores interleaved as NEON can load and store while calculating
+  asm volatile(
+    "VLDM         %1,   {q4-q6}       \n\t" // load matrix 1 (lhsPtr)
+    "VLD1.F32     {q7}, [%2]!         \n\t" // load matrix 2 (rhsPtr) [0..3]
+    "VMUL.F32     q0,   q7,   d8[0]   \n\t" // column 0 = rhsPtr[0..3] * lhsPtr[0..3]
+    "VMUL.F32     q1,   q7,   d10[0]  \n\t" // column 1 = rhsPtr[0..3] * lhsPtr[4..7]
+    "VMUL.F32     q2,   q7,   d12[0]  \n\t" // column 2 = rhsPtr[0..3] * lhsPtr[8..11]
+    "VLD1.F32     {q7}, [%2]!         \n\t" // load matrix 2 (rhsPtr) [4..7]
+    "VMLA.F32     q0,   q7,   d8[1]   \n\t" // column 0+= rhsPtr[4..7] * lhsPtr[0..3]
+    "VMLA.F32     q1,   q7,   d10[1]  \n\t" // column 1+= rhsPtr[4..7] * lhsPtr[4..7]
+    "VMLA.F32     q2,   q7,   d12[1]  \n\t" // column 2+= rhsPtr[4..7] * lhsPtr[8..11]
+    "VLD1.F32     {q7}, [%2]!         \n\t" // load matrix 2 (rhsPtr) [8..11]
+    "VMLA.F32     q0,   q7,   d9[0]   \n\t" // column 0+= rhsPtr[8..11] * lhsPtr[0..3]
+    "VMLA.F32     q1,   q7,   d11[0]  \n\t" // column 1+= rhsPtr[8..11] * lhsPtr[4..7]
+    "VMLA.F32     q2,   q7,   d13[0]  \n\t" // column 2+= rhsPtr[8..11] * lhsPtr[8..11]
+    "VSTM         %0,   {q0-q2}       \n\t" // store entire output matrix.
+    :
+    : "r"(temp), "r"(lhsPtr), "r"(rhsPtr)
+    : "%r0", "%q0", "%q1", "%q2", "%q4", "%q5", "%q6", "%q7", "memory");
+
+  temp[12] = 0.0f;
+  temp[13] = 0.0f;
+  temp[14] = 0.0f;
+  temp[15] = 1.0f;
+#endif
+}
+
+void MultiplyProjectionMatrix(Dali::Matrix& result, const Dali::Matrix& lhs, const Dali::Matrix& projection)
+{
+  // TODO : Implement with NEON.
+  // Current NEON code is copy of Multiply.
+
+  MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
+  MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY, 32); // 32 = 8*4
+
+  float*       temp   = result.AsFloat();
+  const float* rhsPtr = projection.AsFloat();
+  const float* lhsPtr = lhs.AsFloat();
+
+#ifndef __ARM_NEON__
+
+  // We only use rhsPtr's 0, 1, 4, 5, 10, 11, 14, 15 index.
+  const float rhs0  = rhsPtr[0];
+  const float rhs1  = rhsPtr[1];
+  const float rhs4  = rhsPtr[4];
+  const float rhs5  = rhsPtr[5];
+  const float rhs10 = rhsPtr[10];
+  const float rhs11 = rhsPtr[11];
+  const float rhs14 = rhsPtr[14];
+  const float rhs15 = rhsPtr[15];
+
+  for(int32_t i = 0; i < 4; i++)
+  {
+    // i<<2 gives the first vector / column
+    const int32_t loc0 = i << 2;
+    const int32_t loc1 = loc0 + 1;
+    const int32_t loc2 = loc0 + 2;
+    const int32_t loc3 = loc0 + 3;
+
+    const float value0 = lhsPtr[loc0];
+    const float value1 = lhsPtr[loc1];
+    const float value2 = lhsPtr[loc2];
+    const float value3 = lhsPtr[loc3];
+
+    temp[loc0] = (value0 * rhs0) + (value1 * rhs4);
+    temp[loc1] = (value0 * rhs1) + (value1 * rhs5);
+    temp[loc2] = (value2 * rhs10) + (value3 * rhs14);
+    temp[loc3] = (value2 * rhs11) + (value3 * rhs15);
+  }
+
+#else
+
+  // 64 32bit registers,
+  // aliased to
+  // d = 64 bit double-word d0 -d31
+  // q =128 bit quad-word   q0 -q15  (enough to handle a column of 4 floats in a matrix)
+  // e.g. q0 = d0 and d1
+
+  // load and stores interleaved as NEON can load and store while calculating
+  asm volatile(
+    "VLDM         %1,  {q0-q3}        \n\t" // load matrix 1 (lhsPtr) q[0..q3]
+    "VLDM         %0,  {q8-q11}       \n\t" // load matrix 2 (rhsPtr) q[q8-q11]
+    "VMUL.F32     q12, q8, d0[0]      \n\t" // column 0 = rhsPtr[0..3] * lhsPtr[0..3]
+    "VMUL.F32     q13, q8, d2[0]      \n\t" // column 1 = rhsPtr[0..3] * lhsPtr[4..7]
+    "VMUL.F32     q14, q8, d4[0]      \n\t" // column 2 = rhsPtr[0..3] * lhsPtr[8..11]
+    "VMUL.F32     q15, q8, d6[0]      \n\t" // column 3 = rhsPtr[0..3] * lhsPtr[12..15]
+
+    "VMLA.F32     q12, q9, d0[1]      \n\t" // column 0 += rhsPtr[4..7] * lhsPtr[0..3]
+    "VMLA.F32     q13, q9, d2[1]      \n\t" // column 1 += rhsPtr[4..7] * lhsPtr[4..7]
+    "VMLA.F32     q14, q9, d4[1]      \n\t" // column 2 += rhsPtr[4..7] * lhsPtr[8..11]
+    "VMLA.F32     q15, q9, d6[1]      \n\t" // column 3 += rhsPtr[4..7] * lhsPtr[12..15]
+
+    "VMLA.F32     q12, q10, d1[0]     \n\t" // column 0 += rhsPtr[8..11] * lhsPtr[0..3]
+    "VMLA.F32     q13, q10, d3[0]     \n\t" // column 1 += rhsPtr[8..11] * lhsPtr[4..7]
+    "VMLA.F32     q14, q10, d5[0]     \n\t" // column 2 += rhsPtr[8..11] * lhsPtr[8..11]
+    "VMLA.F32     q15, q10, d7[0]     \n\t" // column 3 += rhsPtr[8..11] * lhsPtr[12..15]
+
+    "VMLA.F32     q12, q11, d1[1]     \n\t" // column 0 += rhsPtr[12..15] * lhsPtr[0..3]
+    "VMLA.F32     q13, q11, d3[1]     \n\t" // column 1 += rhsPtr[12..15] * lhsPtr[4..7]
+    "VMLA.F32     q14, q11, d5[1]     \n\t" // column 2 += rhsPtr[12..15] * lhsPtr[8..11]
+    "VMLA.F32     q15, q11, d7[1]     \n\t" // column 3 += rhsPtr[12..15] * lhsPtr[12..15]
+    "VSTM         %2,  {q12-q15}      \n\t" // store entire output matrix.
+    : "+r"(rhsPtr), "+r"(lhsPtr), "+r"(temp)
+    :
+    : "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", "memory");
+
+#endif
+}
+
+void MultiplyAssign(Dali::Matrix& result, const Dali::Matrix& rhs)
+{
+  MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
+  MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY, 64); // 64 = 16*4
+
+  // TODO : Implement with NEON.
+
+  float*       lhsPtr = result.AsFloat();
+  const float* rhsPtr = rhs.AsFloat();
+  float*       temp   = nullptr;
+
+  if(lhsPtr == rhsPtr)
+  {
+    // If rhs is same matrix with result, we need to copy temperal vaules.
+    temp = static_cast<float*>(malloc(NUM_BYTES_IN_MATRIX));
+    memcpy(temp, rhsPtr, NUM_BYTES_IN_MATRIX);
+    rhsPtr = temp;
+  }
+
+  // Calculate and store as row major.
+  for(int32_t i = 0; i < 4; i++)
+  {
+    const int32_t loc0 = i;
+    const int32_t loc1 = loc0 | 4;
+    const int32_t loc2 = loc0 | 8;
+    const int32_t loc3 = loc0 | 12;
+
+    const float value0 = lhsPtr[loc0];
+    const float value1 = lhsPtr[loc1];
+    const float value2 = lhsPtr[loc2];
+    const float value3 = lhsPtr[loc3];
+
+    lhsPtr[loc0] = (value0 * rhsPtr[0]) +
+                   (value1 * rhsPtr[1]) +
+                   (value2 * rhsPtr[2]) +
+                   (value3 * rhsPtr[3]);
+
+    lhsPtr[loc1] = (value0 * rhsPtr[4]) +
+                   (value1 * rhsPtr[5]) +
+                   (value2 * rhsPtr[6]) +
+                   (value3 * rhsPtr[7]);
+
+    lhsPtr[loc2] = (value0 * rhsPtr[8]) +
+                   (value1 * rhsPtr[9]) +
+                   (value2 * rhsPtr[10]) +
+                   (value3 * rhsPtr[11]);
+
+    lhsPtr[loc3] = (value0 * rhsPtr[12]) +
+                   (value1 * rhsPtr[13]) +
+                   (value2 * rhsPtr[14]) +
+                   (value3 * rhsPtr[15]);
+  }
+
+  if(temp)
+  {
+    // If we allocate temperal memory, we should free it.
+    free(temp);
+  }
+}
+
+// Dali::Matrix3
+
+void Multiply(Dali::Matrix3& result, const Dali::Matrix3& lhs, const Dali::Matrix3& rhs)
+{
+  float*       temp   = result.AsFloat();
+  const float* rhsPtr = rhs.AsFloat();
+  const float* lhsPtr = lhs.AsFloat();
+
+  for(int32_t i = 0; i < 3; i++)
+  {
+    const int32_t loc0 = i * 3;
+    const int32_t loc1 = loc0 + 1;
+    const int32_t loc2 = loc0 + 2;
+
+    const float value0 = lhsPtr[loc0];
+    const float value1 = lhsPtr[loc1];
+    const float value2 = lhsPtr[loc2];
+
+    temp[loc0] = (value0 * rhsPtr[0]) +
+                 (value1 * rhsPtr[3]) +
+                 (value2 * rhsPtr[6]);
+
+    temp[loc1] = (value0 * rhsPtr[1]) +
+                 (value1 * rhsPtr[4]) +
+                 (value2 * rhsPtr[7]);
+
+    temp[loc2] = (value0 * rhsPtr[2]) +
+                 (value1 * rhsPtr[5]) +
+                 (value2 * rhsPtr[8]);
+  }
+}
+
+void MultiplyAssign(Dali::Matrix3& result, const Dali::Matrix3& rhs)
+{
+  float*       lhsPtr = result.AsFloat();
+  const float* rhsPtr = rhs.AsFloat();
+  float*       temp   = nullptr;
+
+  if(lhsPtr == rhsPtr)
+  {
+    // If rhs is same matrix with result, we need to copy temperal vaules.
+    temp = static_cast<float*>(malloc(NUM_BYTES_IN_MATRIX3));
+    memcpy(temp, rhsPtr, NUM_BYTES_IN_MATRIX3);
+    rhsPtr = temp;
+  }
+
+  // Calculate and store as row major.
+  for(int32_t i = 0; i < 3; i++)
+  {
+    const int32_t loc0 = i;
+    const int32_t loc1 = loc0 + 3;
+    const int32_t loc2 = loc0 + 6;
+
+    const float value0 = lhsPtr[loc0];
+    const float value1 = lhsPtr[loc1];
+    const float value2 = lhsPtr[loc2];
+
+    lhsPtr[loc0] = (value0 * rhsPtr[0]) +
+                   (value1 * rhsPtr[1]) +
+                   (value2 * rhsPtr[2]);
+
+    lhsPtr[loc1] = (value0 * rhsPtr[3]) +
+                   (value1 * rhsPtr[4]) +
+                   (value2 * rhsPtr[5]);
+
+    lhsPtr[loc2] = (value0 * rhsPtr[6]) +
+                   (value1 * rhsPtr[7]) +
+                   (value2 * rhsPtr[8]);
+  }
+
+  if(temp)
+  {
+    // If we allocate temperal memory, we should free it.
+    free(temp);
+  }
+}
+
+} // namespace MatrixUtils
+} // namespace Dali::Internal
diff --git a/dali/internal/common/matrix-utils.h b/dali/internal/common/matrix-utils.h
new file mode 100644 (file)
index 0000000..f65687c
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef DALI_INTERNAL_MATRIX_UTILS_H
+#define DALI_INTERNAL_MATRIX_UTILS_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+class Matrix;
+class Matrix3;
+class Quaternion;
+
+namespace Internal
+{
+namespace MatrixUtils
+{
+// Quaternion
+
+/**
+ * @brief Function to convert from Quaternion to Matrix as float16 array form
+ *
+ * @SINCE_2_1.46
+ * @param[out] result Result stored float16 array. It must have at least 16 * sizeof(float) bytes.
+ * @param[in] rotation Input Quaternion.
+ */
+void ConvertQuaternion(float*& result, const Dali::Quaternion& rotation);
+
+// Matrix
+
+/**
+ * @copydoc Dali::Matrix::Multiply
+ */
+void Multiply(Dali::Matrix& result, const Dali::Matrix& lhs, const Dali::Matrix& rhs);
+
+/**
+ * @copydoc Dali::Matrix::Multiply
+ */
+void Multiply(Dali::Matrix& result, const Dali::Matrix& lhs, const Dali::Quaternion& rhs);
+
+/**
+ * @brief Function to multiply projection matrix and store the result onto third.
+ *
+ * This API assume that projection is Projection Matrix which top/bottom/left/right is symmetrical.
+ *
+ * Perspective matrix only has 0, 5, 10, 11, 14 (14 is const value, 1.0f).
+ * Orthographic matrix only has 0, 5, 10, 14, 15 (15 is const value, 1.0f).
+ * If window rotated, we use 1, 4 index instead of 0, 5.
+ * So we only need 8 values to multiplication.
+ *
+ * Use this method in time critical path as it does not require temporaries.
+ *
+ * result = projection * lhs
+ *
+ * @SINCE_2_1.46
+ * @param[out] result Result of the multiplication
+ * @param[in] lhs Matrix, this cannot be same matrix as result
+ * @param[in] projection Projection Matrix, this can be same matrix as result
+ */
+void MultiplyProjectionMatrix(Dali::Matrix& result, const Dali::Matrix& lhs, const Dali::Matrix& projection);
+
+/**
+ * @brief Function to multiply two matrices and store the result onto first one.
+ *
+ * result = result * rhs
+ * result *= rhs
+ *
+ * @note This method might copy data internally.
+ *
+ * @SINCE_2_1.46
+ * @param[in,out] result Result of the multiplication
+ * @param[in] rhs Matrix, this can be same matrix as result
+ */
+void MultiplyAssign(Dali::Matrix& result, const Dali::Matrix& rhs);
+
+// Matrix3
+
+/**
+ * @copydoc Dali::Matrix3::Multiply
+ */
+void Multiply(Dali::Matrix3& result, const Dali::Matrix3& lhs, const Dali::Matrix3& rhs);
+
+/**
+ * @brief Function to multiply two matrices and store the result onto first one.
+ *
+ * result = result * rhs
+ * result *= rhs
+ *
+ * @note This method might copy data internally.
+ *
+ * @SINCE_2_1.46
+ * @param[in,out] result Result of the multiplication
+ * @param[in] rhs Matrix, this can be same matrix as result
+ */
+void MultiplyAssign(Dali::Matrix3& result, const Dali::Matrix3& rhs);
+
+} // namespace MatrixUtils
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_MATH_UTILS_H
index bad1233..4ee6566 100644 (file)
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/internal/event/actors/actor-coords.h>
 #include <dali/internal/event/common/event-thread-services.h>
 #include <dali/internal/event/common/projection.h>
@@ -78,11 +79,11 @@ bool ConvertScreenToLocal(
 {
   // Get the ModelView matrix
   Matrix modelView;
-  Matrix::Multiply(modelView, worldMatrix, viewMatrix);
+  MatrixUtils::Multiply(modelView, worldMatrix, viewMatrix);
 
   // Calculate the inverted ModelViewProjection matrix; this will be used for 2 unprojects
   Matrix invertedMvp(false /*don't init*/);
-  Matrix::Multiply(invertedMvp, modelView, projectionMatrix);
+  MatrixUtils::Multiply(invertedMvp, modelView, projectionMatrix);
   bool success = invertedMvp.Invert();
 
   // Convert to GL coordinates
@@ -524,7 +525,7 @@ Matrix CalculateActorWorldTransform(const Actor& actor)
 
         //Update the world matrix
         Matrix tempMatrix;
-        Matrix::Multiply(tempMatrix, localMatrix, worldMatrix);
+        MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
         worldMatrix = tempMatrix;
       }
       else
@@ -550,7 +551,7 @@ Matrix CalculateActorWorldTransform(const Actor& actor)
         {
           localMatrix.SetTransformComponents(localScale, localOrientation, Vector3::ZERO);
           Matrix tempMatrix;
-          Matrix::Multiply(tempMatrix, localMatrix, worldMatrix);
+          MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
           worldMatrix = tempMatrix;
           worldMatrix.SetTranslation(actorPosition + centerPosition);
         }
@@ -559,7 +560,7 @@ Matrix CalculateActorWorldTransform(const Actor& actor)
           localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
           localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
           Matrix tempMatrix;
-          Matrix::Multiply(tempMatrix, localMatrix, worldMatrix);
+          MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
           worldMatrix = tempMatrix;
         }
       }
index 5f118f9..9fc8ead 100644 (file)
@@ -24,6 +24,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/actors/camera-actor-devel.h>
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/internal/event/common/projection.h>
 #include <dali/internal/event/common/property-helper.h>
 #include <dali/internal/event/common/thread-local-storage.h>
@@ -104,7 +105,7 @@ void BuildOrthoPickingRay(const Matrix&   viewMatrix,
 
   // Transforms the touch point from the screen reference system to the world reference system.
   Matrix invViewProjection(false); // Don't initialize.
-  Matrix::Multiply(invViewProjection, viewMatrix, projectionMatrix);
+  MatrixUtils::Multiply(invViewProjection, viewMatrix, projectionMatrix);
   if(!invViewProjection.Invert())
   {
     DALI_ASSERT_DEBUG(false);
index ff4adea..e6cae8d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/public-api/math/math-utils.h>
 #include <dali/public-api/math/matrix.h>
 #include <dali/public-api/math/rect.h>
@@ -72,7 +73,7 @@ bool UnprojectFull(const Vector4& windowPos,
                    Vector4&       objectPos)
 {
   Matrix invertedMvp(false); // Don't initialize.
-  Matrix::Multiply(invertedMvp, modelView, projection);
+  MatrixUtils::Multiply(invertedMvp, modelView, projection);
 
   if(invertedMvp.Invert())
   {
@@ -123,7 +124,7 @@ bool ProjectFull(const Vector4& position,
   bool ok = false;
 
   Matrix Mvp(false); // Don't initialize.
-  Matrix::Multiply(Mvp, modelView, projection);
+  MatrixUtils::Multiply(Mvp, modelView, projection);
 
   Vector4 p = Mvp * position;
 
index 884868d..e868466 100644 (file)
@@ -6,6 +6,7 @@ SET( internal_src_files
   ${internal_src_dir}/common/blending-options.cpp
   ${internal_src_dir}/common/core-impl.cpp
   ${internal_src_dir}/common/math.cpp
+  ${internal_src_dir}/common/matrix-utils.cpp
   ${internal_src_dir}/common/message-buffer.cpp
   ${internal_src_dir}/common/mutex-trace.cpp
   ${internal_src_dir}/common/image-sampler.cpp
index 80dbc6f..105b496 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/graphics-api/graphics-types.h>
 #include <dali/integration-api/debug.h>
 #include <dali/internal/common/image-sampler.h>
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/internal/event/rendering/texture-impl.h>
 #include <dali/internal/render/common/render-instruction.h>
 #include <dali/internal/render/data-providers/node-data-provider.h>
@@ -478,7 +479,7 @@ bool Renderer::Render(Graphics::CommandBuffer&                             comma
     mRenderCallbackInput.size       = size;
     mRenderCallbackInput.projection = projectionMatrix;
 
-    Matrix::Multiply(mRenderCallbackInput.mvp, modelViewMatrix, projectionMatrix);
+    MatrixUtils::Multiply(mRenderCallbackInput.mvp, modelViewMatrix, projectionMatrix);
 
     // submit draw
     commandBuffer.DrawNative(&info);
@@ -731,7 +732,7 @@ void Renderer::WriteUniformBuffer(
     if(mvpUniformInfo && !mvpUniformInfo->name.empty())
     {
       Matrix modelViewProjectionMatrix(false);
-      Matrix::Multiply(modelViewProjectionMatrix, modelViewMatrix, projectionMatrix);
+      MatrixUtils::Multiply(modelViewProjectionMatrix, modelViewMatrix, projectionMatrix);
       WriteDefaultUniform(mvpUniformInfo, *uboView, modelViewProjectionMatrix);
     }
 
index ebc2c82..7bc5831 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_SCENE_GRAPH_ANIMATABLE_PROPERTY_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
 #include <limits>
 
 // INTERNAL INCLUDES
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/internal/common/message.h>
 #include <dali/internal/event/common/event-thread-services.h>
 #include <dali/internal/event/common/property-input-impl.h>
@@ -95,7 +96,6 @@ protected: // for derived classes
   }
 
 public:
-
   /**
    * Mark the property as dirty so that it will be reset to the base value in the next two frames.
    */
@@ -1832,7 +1832,7 @@ public:
   void SetRelative(BufferIndex bufferIndex, const Matrix& delta)
   {
     Matrix temp;
-    Matrix::Multiply(temp, mValue[bufferIndex], delta);
+    MatrixUtils::Multiply(temp, mValue[bufferIndex], delta);
     mValue[bufferIndex] = temp;
 
     OnSet();
@@ -1898,7 +1898,7 @@ public:
   void BakeRelative(BufferIndex bufferIndex, const Matrix& delta)
   {
     Matrix temp;
-    Matrix::Multiply(temp, mValue[bufferIndex], delta);
+    MatrixUtils::Multiply(temp, mValue[bufferIndex], delta);
     mValue[bufferIndex] = temp;
     mBaseValue          = temp;
 
@@ -1988,7 +1988,7 @@ public:
   void SetRelative(BufferIndex bufferIndex, const Matrix3& delta)
   {
     Matrix3 temp;
-    Matrix3::Multiply(temp, mValue[bufferIndex], delta);
+    MatrixUtils::Multiply(temp, mValue[bufferIndex], delta);
     mValue[bufferIndex] = temp;
     OnSet();
   }
@@ -2053,7 +2053,7 @@ public:
   void BakeRelative(BufferIndex bufferIndex, const Matrix3& delta)
   {
     Matrix3 temp;
-    Matrix3::Multiply(temp, mValue[bufferIndex], delta);
+    MatrixUtils::Multiply(temp, mValue[bufferIndex], delta);
     mValue[bufferIndex] = temp;
     mBaseValue          = temp;
 
index 3f85f40..f3c0440 100644 (file)
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/internal/event/actors/layer-impl.h> // for the default sorting function
 #include <dali/internal/render/common/render-instruction-container.h>
 #include <dali/internal/render/common/render-instruction.h>
@@ -220,7 +221,7 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
 
       if(size.LengthSquared() > Math::MACHINE_EPSILON_1000)
       {
-        Matrix::Multiply(nodeModelViewMatrix, nodeWorldMatrix, viewMatrix);
+        MatrixUtils::Multiply(nodeModelViewMatrix, nodeWorldMatrix, viewMatrix);
         nodeModelViewMatrixSet = true;
 
         // Assume actors are at z=0, compute AABB in view space & test rect intersection
@@ -317,7 +318,7 @@ inline void AddRendererToRenderList(BufferIndex               updateBufferIndex,
 
       if(!nodeModelViewMatrixSet)
       {
-        Matrix::Multiply(nodeModelViewMatrix, nodeWorldMatrix, viewMatrix);
+        MatrixUtils::Multiply(nodeModelViewMatrix, nodeWorldMatrix, viewMatrix);
       }
       item.mModelViewMatrix = nodeModelViewMatrix;
 
index bec0a7c..342d820 100644 (file)
@@ -25,6 +25,7 @@
 
 //INTERNAL INCLUDES
 #include <dali/internal/common/math.h>
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/public-api/common/constants.h>
 
 namespace Dali
@@ -260,7 +261,7 @@ bool TransformManager::Update()
         }
 
         //Update the world matrix
-        Matrix::Multiply(mWorld[i], mLocal[i], mWorld[parentIndex]);
+        MatrixUtils::Multiply(mWorld[i], mLocal[i], mWorld[parentIndex]);
       }
       else
       {
@@ -292,7 +293,7 @@ bool TransformManager::Update()
           //Don't inherit position
           CalculateCenterPosition(centerPosition, mTxComponentStatic[i], mTxComponentAnimatable[i], mSize[i], half, topLeft);
           mLocal[i].SetTransformComponents(localScale, localOrientation, Vector3::ZERO);
-          Matrix::Multiply(mWorld[i], mLocal[i], parentMatrix);
+          MatrixUtils::Multiply(mWorld[i], mLocal[i], parentMatrix);
           mWorld[i].SetTranslation(mTxComponentAnimatable[i].mPosition + centerPosition);
         }
         else
@@ -300,7 +301,7 @@ bool TransformManager::Update()
           CalculateCenterPosition(centerPosition, mTxComponentStatic[i], mTxComponentAnimatable[i], mSize[i], half, topLeft);
           localPosition = mTxComponentAnimatable[i].mPosition + centerPosition + (mTxComponentStatic[i].mParentOrigin - half) * mSize[parentIndex];
           mLocal[i].SetTransformComponents(localScale, localOrientation, localPosition);
-          Matrix::Multiply(mWorld[i], mLocal[i], parentMatrix);
+          MatrixUtils::Multiply(mWorld[i], mLocal[i], parentMatrix);
         }
 
         mLocalMatrixDirty[i] = mComponentDirty[i] || (localMatrix != mLocal[i]);
index d80acd6..3995388 100644 (file)
@@ -23,6 +23,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/internal/common/memory-pool-object-allocator.h>
 #include <dali/internal/update/nodes/node.h>
 #include <dali/public-api/common/dali-common.h>
@@ -416,7 +417,7 @@ void Camera::Update(BufferIndex updateBufferIndex)
   if(viewUpdateCount > COPY_PREVIOUS_MATRIX || projectionUpdateCount > COPY_PREVIOUS_MATRIX)
   {
     // either has actually changed so recalculate
-    Matrix::Multiply(mInverseViewProjection[updateBufferIndex], mViewMatrix[updateBufferIndex], mProjectionMatrix[updateBufferIndex]);
+    MatrixUtils::Multiply(mInverseViewProjection[updateBufferIndex], mViewMatrix[updateBufferIndex], mProjectionMatrix[updateBufferIndex]);
     UpdateFrustum(updateBufferIndex);
 
     // ignore the error, if the view projection is incorrect (non inversible) then you will have tough times anyways
@@ -472,7 +473,7 @@ uint32_t Camera::UpdateViewMatrix(BufferIndex updateBufferIndex)
 
             Matrix& viewMatrix = mViewMatrix.Get(updateBufferIndex);
             Matrix  oldViewMatrix(viewMatrix);
-            Matrix::Multiply(viewMatrix, oldViewMatrix, mReflectionMtx);
+            MatrixUtils::Multiply(viewMatrix, oldViewMatrix, mReflectionMtx);
           }
 
           viewMatrix.Invert();
@@ -515,7 +516,7 @@ uint32_t Camera::UpdateViewMatrix(BufferIndex updateBufferIndex)
             Matrix oldViewMatrix(viewMatrix);
             Matrix tmp;
             tmp.SetIdentityAndScale(Vector3(-1.0, 1.0, 1.0));
-            Matrix::Multiply(viewMatrix, oldViewMatrix, tmp);
+            MatrixUtils::Multiply(viewMatrix, oldViewMatrix, tmp);
 
             mReflectionEye     = positionNew;
             mUseReflectionClip = true;
@@ -538,7 +539,7 @@ void Camera::UpdateFrustum(BufferIndex updateBufferIndex, bool normalize)
 {
   // Extract the clip matrix planes
   Matrix clipMatrix;
-  Matrix::Multiply(clipMatrix, mViewMatrix[updateBufferIndex], mProjectionMatrix[updateBufferIndex]);
+  MatrixUtils::Multiply(clipMatrix, mViewMatrix[updateBufferIndex], mProjectionMatrix[updateBufferIndex]);
 
   const float*   cm     = clipMatrix.AsFloat();
   FrustumPlanes& planes = mFrustum[updateBufferIndex];
@@ -684,7 +685,7 @@ uint32_t Camera::UpdateProjection(BufferIndex updateBufferIndex)
             matZ.SetIdentity();
             float* vZ = matZ.AsFloat();
             vZ[10]    = -vZ[10];
-            Matrix::Multiply(projectionMatrix, projectionMatrix, matZ);
+            MatrixUtils::Multiply(projectionMatrix, projectionMatrix, matZ);
           }
           break;
         }
@@ -732,7 +733,7 @@ uint32_t Camera::UpdateProjection(BufferIndex updateBufferIndex)
       rotation.SetIdentity();
       rotation.SetTransformComponents(Vector3(1.0f, 1.0f, 1.0f), rotationAngle, Vector3(0.0f, 0.0f, 0.0f));
 
-      Matrix::Multiply(finalProjection, mProjectionMatrix.Get(updateBufferIndex), rotation);
+      MatrixUtils::Multiply(finalProjection, mProjectionMatrix.Get(updateBufferIndex), rotation);
     }
     --mUpdateProjectionFlag;
   }
index 730030c..45b8535 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
 #include <ostream>
 
 // INTERNAL INCLUDES
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/internal/render/common/performance-monitor.h>
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/math/math-utils.h>
@@ -42,44 +43,6 @@ const uint32_t NUM_BYTES_IN_MATRIX(16 * sizeof(float));
 const uint32_t ROW1_OFFSET(4);
 const uint32_t ROW2_OFFSET(8);
 const uint32_t ROW3_OFFSET(12);
-
-/**
- * Helper to convert to Quaternion to float16 array
- */
-void Convert(float*& m, const Dali::Quaternion& rotation)
-{
-  const float xx = rotation.mVector.x * rotation.mVector.x;
-  const float yy = rotation.mVector.y * rotation.mVector.y;
-  const float zz = rotation.mVector.z * rotation.mVector.z;
-  const float xy = rotation.mVector.x * rotation.mVector.y;
-  const float xz = rotation.mVector.x * rotation.mVector.z;
-  const float wx = rotation.mVector.w * rotation.mVector.x;
-  const float wy = rotation.mVector.w * rotation.mVector.y;
-  const float wz = rotation.mVector.w * rotation.mVector.z;
-  const float yz = rotation.mVector.y * rotation.mVector.z;
-
-  // clang-format off
-  m[0] = 1.0f - 2.0f * (yy + zz);
-  m[1] =        2.0f * (xy + wz);
-  m[2] =        2.0f * (xz - wy);
-  m[3] = 0.0f;
-
-  m[4] =        2.0f * (xy - wz);
-  m[5] = 1.0f - 2.0f * (xx + zz);
-  m[6] =        2.0f * (yz + wx);
-  m[7] = 0.0f;
-
-  m[8] =        2.0f * (xz + wy);
-  m[9] =        2.0f * (yz - wx);
-  m[10]= 1.0f - 2.0f * (xx + yy);
-  m[11]= 0.0f;
-
-  m[12]= 0.0f;
-  m[13]= 0.0f;
-  m[14]= 0.0f;
-  m[15]= 1.0f;
-  // clang-format on
-}
 } // namespace
 
 namespace Dali
@@ -119,7 +82,7 @@ Matrix::Matrix(const Quaternion& rotation)
   MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY, 18);
 
   float* matrixPtr = &mMatrix[0];
-  Convert(matrixPtr, rotation);
+  Internal::MatrixUtils::ConvertQuaternion(matrixPtr, rotation);
 }
 
 Matrix::Matrix(const Matrix& matrix)
@@ -284,168 +247,25 @@ void Matrix::SetTranslation(const Vector3& other)
 
 void Matrix::Multiply(Matrix& result, const Matrix& lhs, const Matrix& rhs)
 {
-  MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
-  MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY, 64); // 64 = 16*4
-
-  float*       temp   = result.AsFloat();
-  const float* rhsPtr = rhs.AsFloat();
-  const float* lhsPtr = lhs.AsFloat();
-
-#ifndef __ARM_NEON__
-
-  for(int32_t i = 0; i < 4; i++)
-  {
-    // i<<2 gives the first vector / column
-    int32_t loc    = i << 2;
-    int32_t loc1   = loc + 1;
-    int32_t loc2   = loc + 2;
-    int32_t loc3   = loc + 3;
-    float   value0 = lhsPtr[loc];
-    float   value1 = lhsPtr[loc1];
-    float   value2 = lhsPtr[loc2];
-    float   value3 = lhsPtr[loc3];
-
-    temp[loc] = (value0 * rhsPtr[0]) +
-                (value1 * rhsPtr[4]) +
-                (value2 * rhsPtr[8]) +
-                (value3 * rhsPtr[12]);
-
-    temp[loc1] = (value0 * rhsPtr[1]) +
-                 (value1 * rhsPtr[5]) +
-                 (value2 * rhsPtr[9]) +
-                 (value3 * rhsPtr[13]);
-
-    temp[loc2] = (value0 * rhsPtr[2]) +
-                 (value1 * rhsPtr[6]) +
-                 (value2 * rhsPtr[10]) +
-                 (value3 * rhsPtr[14]);
-
-    temp[loc3] = (value0 * rhsPtr[3]) +
-                 (value1 * rhsPtr[7]) +
-                 (value2 * rhsPtr[11]) +
-                 (value3 * rhsPtr[15]);
-  }
-
-#else
-
-  // 64 32bit registers,
-  // aliased to
-  // d = 64 bit double-word d0 -d31
-  // q =128 bit quad-word   q0 -q15  (enough to handle a column of 4 floats in a matrix)
-  // e.g. q0 = d0 and d1
-
-  // load and stores interleaved as NEON can load and store while calculating
-  asm volatile(
-    "VLDM         %1,  {q0-q3}        \n\t" // load matrix 1 (lhsPtr) q[0..q3]
-    "VLDM         %0,  {q8-q11}       \n\t" // load matrix 2 (rhsPtr) q[q8-q11]
-    "VMUL.F32     q12, q8, d0[0]      \n\t" // column 0 = rhsPtr[0..3] * lhsPtr[0..3]
-    "VMUL.F32     q13, q8, d2[0]      \n\t" // column 1 = rhsPtr[0..3] * lhsPtr[4..7]
-    "VMUL.F32     q14, q8, d4[0]      \n\t" // column 2 = rhsPtr[0..3] * lhsPtr[8..11]
-    "VMUL.F32     q15, q8, d6[0]      \n\t" // column 3 = rhsPtr[0..3] * lhsPtr[12..15]
-
-    "VMLA.F32     q12, q9, d0[1]      \n\t" // column 0 += rhsPtr[4..7] * lhsPtr[0..3]
-    "VMLA.F32     q13, q9, d2[1]      \n\t" // column 1 += rhsPtr[4..7] * lhsPtr[4..7]
-    "VMLA.F32     q14, q9, d4[1]      \n\t" // column 2 += rhsPtr[4..7] * lhsPtr[8..11]
-    "VMLA.F32     q15, q9, d6[1]      \n\t" // column 3 += rhsPtr[4..7] * lhsPtr[12..15]
-
-    "VMLA.F32     q12, q10, d1[0]     \n\t" // column 0 += rhsPtr[8..11] * lhsPtr[0..3]
-    "VMLA.F32     q13, q10, d3[0]     \n\t" // column 1 += rhsPtr[8..11] * lhsPtr[4..7]
-    "VMLA.F32     q14, q10, d5[0]     \n\t" // column 2 += rhsPtr[8..11] * lhsPtr[8..11]
-    "VMLA.F32     q15, q10, d7[0]     \n\t" // column 3 += rhsPtr[8..11] * lhsPtr[12..15]
-
-    "VMLA.F32     q12, q11, d1[1]     \n\t" // column 0 += rhsPtr[12..15] * lhsPtr[0..3]
-    "VMLA.F32     q13, q11, d3[1]     \n\t" // column 1 += rhsPtr[12..15] * lhsPtr[4..7]
-    "VMLA.F32     q14, q11, d5[1]     \n\t" // column 2 += rhsPtr[12..15] * lhsPtr[8..11]
-    "VMLA.F32     q15, q11, d7[1]     \n\t" // column 3 += rhsPtr[12..15] * lhsPtr[12..15]
-    "VSTM         %2,  {q12-q15}      \n\t" // store entire output matrix.
-    : "+r"(rhsPtr), "+r"(lhsPtr), "+r"(temp)
-    :
-    : "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", "memory");
-
-#endif
+  Internal::MatrixUtils::Multiply(result, lhs, rhs);
 }
 
 void Matrix::Multiply(Matrix& result, const Matrix& lhs, const Quaternion& rhs)
 {
-  MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
-  MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY, 54); // 54 = 36+18
-
-  float  matrix[16];
-  float* rhsPtr = &matrix[0];
-  Convert(rhsPtr, rhs);
-
-  // quaternion contains just rotation so it really only needs 3x3 matrix
-
-  float*       temp   = result.AsFloat();
-  const float* lhsPtr = lhs.AsFloat();
-
-#ifndef __ARM_NEON__
-
-  for(int32_t i = 0; i < 4; i++)
-  {
-    // i<<2 gives the first vector / column
-    int32_t loc    = i << 2;
-    int32_t loc1   = loc + 1;
-    int32_t loc2   = loc + 2;
-    int32_t loc3   = loc + 3;
-    float   value0 = lhsPtr[loc];
-    float   value1 = lhsPtr[loc1];
-    float   value2 = lhsPtr[loc2];
-    float   value3 = lhsPtr[loc3];
-
-    temp[loc] = (value0 * rhsPtr[0]) +
-                (value1 * rhsPtr[4]) +
-                (value2 * rhsPtr[8]) +
-                (0.0f); //value3 * rhsPtr[12] is 0.0f
-
-    temp[loc1] = (value0 * rhsPtr[1]) +
-                 (value1 * rhsPtr[5]) +
-                 (value2 * rhsPtr[9]) +
-                 (0.0f); //value3 * rhsPtr[13] is 0.0f
-
-    temp[loc2] = (value0 * rhsPtr[2]) +
-                 (value1 * rhsPtr[6]) +
-                 (value2 * rhsPtr[10]) +
-                 (0.0f); //value3 * rhsPtr[14] is 0.0f
-
-    temp[loc3] = (0.0f) +  //value0 * rhsPtr[3] is 0.0f
-                 (0.0f) +  //value1 * rhsPtr[7] is 0.0f
-                 (0.0f) +  //value2 * rhsPtr[11] is 0.0f
-                 (value3); // rhsPtr[15] is 1.0f
-  }
-
-#else
+  Internal::MatrixUtils::Multiply(result, lhs, rhs);
+}
 
-  // 64 32bit registers,
-  // aliased to
-  // d = 64 bit double-word d0 -d31
-  // q =128 bit quad-word   q0 -q15  (enough to handle a column of 4 floats in a matrix)
-  // e.g. q0 = d0 and d1
-  // load and stores interleaved as NEON can load and store while calculating
-  asm volatile(
-    "VLDM         %1,   {q4-q6}       \n\t" // load matrix 1 (lhsPtr)
-    "VLD1.F32     {q7}, [%2]!         \n\t" // load matrix 2 (rhsPtr) [0..3]
-    "VMUL.F32     q0,   q7,   d8[0]   \n\t" // column 0 = rhsPtr[0..3] * lhsPtr[0..3]
-    "VMUL.F32     q1,   q7,   d10[0]  \n\t" // column 1 = rhsPtr[0..3] * lhsPtr[4..7]
-    "VMUL.F32     q2,   q7,   d12[0]  \n\t" // column 2 = rhsPtr[0..3] * lhsPtr[8..11]
-    "VLD1.F32     {q7}, [%2]!         \n\t" // load matrix 2 (rhsPtr) [4..7]
-    "VMLA.F32     q0,   q7,   d8[1]   \n\t" // column 0+= rhsPtr[4..7] * lhsPtr[0..3]
-    "VMLA.F32     q1,   q7,   d10[1]  \n\t" // column 1+= rhsPtr[4..7] * lhsPtr[4..7]
-    "VMLA.F32     q2,   q7,   d12[1]  \n\t" // column 2+= rhsPtr[4..7] * lhsPtr[8..11]
-    "VLD1.F32     {q7}, [%2]!         \n\t" // load matrix 2 (rhsPtr) [8..11]
-    "VMLA.F32     q0,   q7,   d9[0]   \n\t" // column 0+= rhsPtr[8..11] * lhsPtr[0..3]
-    "VMLA.F32     q1,   q7,   d11[0]  \n\t" // column 1+= rhsPtr[8..11] * lhsPtr[4..7]
-    "VMLA.F32     q2,   q7,   d13[0]  \n\t" // column 2+= rhsPtr[8..11] * lhsPtr[8..11]
-    "VSTM         %0,   {q0-q2}       \n\t" // store entire output matrix.
-    :
-    : "r"(temp), "r"(lhsPtr), "r"(rhsPtr)
-    : "%r0", "%q0", "%q1", "%q2", "%q4", "%q5", "%q6", "%q7", "memory");
+Matrix Matrix::operator*(const Matrix& rhs) const
+{
+  Matrix result(false);
+  Internal::MatrixUtils::Multiply(result, rhs, *this);
+  return result;
+}
 
-  temp[12] = 0.0f;
-  temp[13] = 0.0f;
-  temp[14] = 0.0f;
-  temp[15] = 1.0f;
-#endif
+Matrix& Matrix::operator*=(const Matrix& rhs)
+{
+  Internal::MatrixUtils::MultiplyAssign(*this, rhs);
+  return *this;
 }
 
 Vector4 Matrix::operator*(const Vector4& rhs) const
index 8a1481d..bdd80bf 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_MATRIX_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -319,7 +319,6 @@ public:
   {
     return mMatrix;
   }
-
   /**
    * @brief Function to multiply two matrices and store the result onto third.
    *
@@ -357,12 +356,20 @@ public:
    * @param[in] rhs The Matrix to multiply this by
    * @return A Matrix containing the result
    */
-  Matrix operator*(const Matrix& rhs) const
-  {
-    Matrix result(false);
-    Multiply(result, rhs, *this);
-    return result;
-  }
+  Matrix operator*(const Matrix& rhs) const;
+
+  /**
+   * @brief Multiplication assignment operator.
+   *
+   * This Matrix *= rhs
+   *
+   * @note It makes some memory allocate & copy internally.
+   *
+   * @SINCE_2_1.46
+   * @param[in] rhs The Matrix to multiply this by
+   * @return Itself
+   */
+  Matrix& operator*=(const Matrix& rhs);
 
   /**
    * @brief The multiplication operator.
index 1db2e94..fce3ff1 100644 (file)
@@ -24,6 +24,7 @@
 #include <ostream>
 
 // INTERNAL INCLUDES
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/public-api/math/math-utils.h>
 
 #define S00 0
@@ -249,31 +250,20 @@ float Matrix3::Magnitude() const
 
 void Matrix3::Multiply(Matrix3& result, const Matrix3& lhs, const Matrix3& rhs)
 {
-  float*       temp   = result.AsFloat();
-  const float* rhsPtr = rhs.AsFloat();
-  const float* lhsPtr = lhs.AsFloat();
+  Internal::MatrixUtils::Multiply(result, lhs, rhs);
+}
 
-  for(int32_t i = 0; i < 3; i++)
-  {
-    int32_t loc  = i * 3;
-    int32_t loc1 = loc + 1;
-    int32_t loc2 = loc + 2;
-
-    float value0 = lhsPtr[loc];
-    float value1 = lhsPtr[loc1];
-    float value2 = lhsPtr[loc2];
-    temp[loc]    = (value0 * rhsPtr[0]) +
-                (value1 * rhsPtr[3]) +
-                (value2 * rhsPtr[6]);
-
-    temp[loc1] = (value0 * rhsPtr[1]) +
-                 (value1 * rhsPtr[4]) +
-                 (value2 * rhsPtr[7]);
-
-    temp[loc2] = (value0 * rhsPtr[2]) +
-                 (value1 * rhsPtr[5]) +
-                 (value2 * rhsPtr[8]);
-  }
+Matrix3 Matrix3::operator*(const Matrix3& rhs) const
+{
+  Matrix3 result;
+  Internal::MatrixUtils::Multiply(result, rhs, *this);
+  return result;
+}
+
+Matrix3& Matrix3::operator*=(const Matrix3& rhs)
+{
+  Internal::MatrixUtils::MultiplyAssign(*this, rhs);
+  return *this;
 }
 
 Vector3 Matrix3::operator*(const Vector3& rhs) const
index d6d629e..72f2eb4 100644 (file)
@@ -272,12 +272,20 @@ public:
    * @param[in] rhs The Matrix to multiply this by
    * @return A Matrix containing the result
    */
-  Matrix3 operator*(const Matrix3& rhs) const
-  {
-    Matrix3 result;
-    Multiply(result, rhs, *this);
-    return result;
-  }
+  Matrix3 operator*(const Matrix3& rhs) const;
+
+  /**
+   * @brief Multiplication assignment operator.
+   *
+   * This Matrix *= rhs
+   *
+   * @note It makes some memory allocate & copy internally.
+   *
+   * @SINCE_2_1.46
+   * @param[in] rhs The Matrix to multiply this by
+   * @return Itself
+   */
+  Matrix3& operator*=(const Matrix3& rhs);
 
   /**
    * @brief The multiplication operator.