| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <functional> |
| |
| #include "flutter/benchmarking/benchmarking.h" |
| |
| #include "flutter/impeller/geometry/matrix.h" |
| #include "flutter/impeller/geometry/rect.h" |
| #include "third_party/skia/include/core/SkM44.h" |
| #include "third_party/skia/include/core/SkMatrix.h" |
| #include "third_party/skia/include/core/SkPoint3.h" |
| |
| namespace flutter { |
| |
| namespace { |
| |
| static constexpr float kPiOver4 = impeller::kPiOver4; |
| |
| static constexpr float kSimplePerspective[16] = { |
| // clang-format off |
| 2.0f, 0.0f, 0.0f, 0.0f, |
| 0.0f, 2.0f, 0.0f, 0.0f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 3.0f |
| // clang-format on |
| }; |
| |
| // The following matrices slowly slide a perspective-skewed transform of |
| // the rect past the near clipping plane. Keeping the Y perspective factor |
| // at -0.006 allows the X perspective factor to slowly move the transformed |
| // rectangle into the clipping pane over the range of [-0.01, to -0.025]. |
| static constexpr float kClipOneCornerPerspective[16] = { |
| // clang-format off |
| 2.0f, 0.0f, 0.0f, -0.01f, |
| 0.0f, 2.0f, 0.0f, -0.006f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 3.0f |
| // clang-format on |
| }; |
| |
| static constexpr float kClipTwoCornersPerspective[16] = { |
| // clang-format off |
| 2.0f, 0.0f, 0.0f, -.015f, |
| 0.0f, 2.0f, 0.0f, -.006f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 3.0f |
| // clang-format on |
| }; |
| |
| static constexpr float kClipThreeCornersPerspective[16] = { |
| // clang-format off |
| 2.0f, 0.0f, 0.0f, -.02f, |
| 0.0f, 2.0f, 0.0f, -.006f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 3.0f |
| // clang-format on |
| }; |
| |
| static constexpr float kClipFourCornersPerspective[16] = { |
| // clang-format off |
| 2.0f, 0.0f, 0.0f, -.025f, |
| 0.0f, 2.0f, 0.0f, -.006f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 3.0f |
| // clang-format on |
| }; |
| |
| enum class AdapterType { |
| kSkMatrix, |
| kSkM44, |
| kImpellerMatrix, |
| }; |
| |
| union TestPoint { |
| TestPoint() {} |
| |
| SkPoint sk_point; |
| impeller::Point impeller_point; |
| }; |
| |
| union TestRect { |
| TestRect() {} |
| |
| SkRect sk_rect; |
| impeller::Rect impeller_rect; |
| }; |
| |
| union TestTransform { |
| TestTransform() {} |
| |
| SkMatrix sk_matrix; |
| SkM44 sk_m44; |
| impeller::Matrix impeller_matrix; |
| }; |
| |
| // We use a virtual adapter class rather than templating the BM_* methods |
| // to prevent the compiler from optimizing the benchmark bodies into a |
| // null set of instructions because the calculation can be proven to have |
| // no side effects and the result is never used. |
| class TransformAdapter { |
| public: |
| TransformAdapter() = default; |
| virtual ~TransformAdapter() = default; |
| |
| // Two methods to test the overhead of just calling a virtual method on |
| // the adapter (should be the same for all inheriting subclasses) and |
| // for a method that does a conversion to and from the TestRect object |
| // (which should be the same as the method call overhead since it does |
| // no work). |
| virtual void DoNothing(TestTransform& ignored) const = 0; |
| |
| virtual void InitRectLTRB(TestRect& rect, |
| float left, |
| float top, |
| float right, |
| float bottom) const = 0; |
| virtual void InitPoint(TestPoint& point, float x, float y) const = 0; |
| |
| // The actual methods that do work and are the meat of the benchmarks. |
| virtual void InitTransformIdentity(TestTransform& result) const = 0; |
| virtual void InitTransformColMatrix(TestTransform& result, |
| const float m[16]) const = 0; |
| |
| virtual void Translate(TestTransform& result, float tx, float ty) const = 0; |
| virtual void Scale(TestTransform& result, float sx, float sy) const = 0; |
| virtual void RotateRadians(TestTransform& result, float radians) const = 0; |
| |
| virtual void Concat(const TestTransform& a, |
| const TestTransform& b, |
| TestTransform& result) const = 0; |
| |
| virtual void TransformPoint(const TestTransform& transform, |
| const TestPoint& in, |
| TestPoint& out) const = 0; |
| virtual void TransformPoints(const TestTransform& transform, |
| const TestPoint in[], |
| TestPoint out[], |
| int n) const = 0; |
| virtual void TransformRectFast(const TestTransform& transform, |
| const TestRect& in, |
| TestRect& out) const = 0; |
| virtual void TransformAndClipRect(const TestTransform& transform, |
| const TestRect& in, |
| TestRect& out) const = 0; |
| virtual int CountClippedCorners(const TestTransform& transform, |
| const TestRect& rect) const = 0; |
| virtual void InvertUnchecked(const TestTransform& transform, |
| TestTransform& result) const = 0; |
| virtual bool InvertAndCheck(const TestTransform& transform, |
| TestTransform& result) const = 0; |
| }; |
| |
| class SkiaAdapterBase : public TransformAdapter { |
| public: |
| // DoNothing methods used to measure overhead for various operations |
| void DoNothing(TestTransform& ignored) const override {} |
| |
| void InitPoint(TestPoint& point, float x, float y) const override { |
| point.sk_point.set(x, y); |
| } |
| |
| void InitRectLTRB(TestRect& rect, |
| float left, |
| float top, |
| float right, |
| float bottom) const override { |
| rect.sk_rect.setLTRB(left, top, right, bottom); |
| } |
| }; |
| |
| class SkMatrixAdapter : public SkiaAdapterBase { |
| public: |
| SkMatrixAdapter() = default; |
| ~SkMatrixAdapter() = default; |
| |
| void InitTransformIdentity(TestTransform& result) const override { |
| result.sk_matrix.setIdentity(); |
| } |
| |
| virtual void InitTransformColMatrix(TestTransform& result, |
| const float m[16]) const override { |
| result.sk_matrix = SkM44::ColMajor(m).asM33(); |
| } |
| |
| void Translate(TestTransform& result, float tx, float ty) const override { |
| result.sk_matrix.preTranslate(tx, ty); |
| } |
| |
| void Scale(TestTransform& result, float sx, float sy) const override { |
| result.sk_matrix.preScale(sx, sy); |
| } |
| |
| void RotateRadians(TestTransform& result, float radians) const override { |
| result.sk_matrix.preRotate(SkRadiansToDegrees(radians)); |
| } |
| |
| void Concat(const TestTransform& a, |
| const TestTransform& b, |
| TestTransform& result) const override { |
| result.sk_matrix = SkMatrix::Concat(a.sk_matrix, b.sk_matrix); |
| } |
| |
| void TransformPoint(const TestTransform& transform, |
| const TestPoint& in, |
| TestPoint& out) const override { |
| out.sk_point = transform.sk_matrix.mapPoint(in.sk_point); |
| } |
| |
| void TransformPoints(const TestTransform& transform, |
| const TestPoint in[], |
| TestPoint out[], |
| int n) const override { |
| static_assert(sizeof(TestPoint) == sizeof(SkPoint)); |
| transform.sk_matrix.mapPoints(reinterpret_cast<SkPoint*>(out), |
| reinterpret_cast<const SkPoint*>(in), n); |
| } |
| |
| void TransformRectFast(const TestTransform& transform, |
| const TestRect& in, |
| TestRect& out) const override { |
| out.sk_rect = |
| transform.sk_matrix.mapRect(in.sk_rect, SkApplyPerspectiveClip::kNo); |
| } |
| |
| void TransformAndClipRect(const TestTransform& transform, |
| const TestRect& in, |
| TestRect& out) const override { |
| out.sk_rect = |
| transform.sk_matrix.mapRect(in.sk_rect, SkApplyPerspectiveClip::kYes); |
| } |
| |
| int CountClippedCorners(const TestTransform& transform, |
| const TestRect& rect) const { |
| SkPoint3 homogenous[4]; |
| SkPoint corners[4]; |
| rect.sk_rect.toQuad(corners); |
| transform.sk_matrix.mapHomogeneousPoints(homogenous, corners, 4); |
| int count = 0; |
| for (SkPoint3 hpt : homogenous) { |
| if (hpt.fZ <= 0) { |
| count++; |
| } |
| } |
| return count; |
| } |
| |
| void InvertUnchecked(const TestTransform& transform, |
| TestTransform& result) const override { |
| [[maybe_unused]] |
| bool ret = transform.sk_matrix.invert(&result.sk_matrix); |
| } |
| |
| bool InvertAndCheck(const TestTransform& transform, |
| TestTransform& result) const override { |
| return transform.sk_matrix.invert(&result.sk_matrix); |
| } |
| }; |
| |
| class SkM44Adapter : public SkiaAdapterBase { |
| public: |
| SkM44Adapter() = default; |
| ~SkM44Adapter() = default; |
| |
| void InitTransformIdentity(TestTransform& storage) const override { |
| storage.sk_m44.setIdentity(); |
| } |
| |
| virtual void InitTransformColMatrix(TestTransform& result, |
| const float m[16]) const override { |
| result.sk_m44 = SkM44::ColMajor(m); |
| } |
| |
| void Translate(TestTransform& storage, float tx, float ty) const override { |
| storage.sk_m44.preTranslate(tx, ty); |
| } |
| |
| void Scale(TestTransform& storage, float sx, float sy) const override { |
| storage.sk_m44.preScale(sx, sy); |
| } |
| |
| void RotateRadians(TestTransform& storage, float radians) const override { |
| storage.sk_m44.preConcat(SkM44::Rotate({0, 0, 1}, radians)); |
| } |
| |
| void Concat(const TestTransform& a, |
| const TestTransform& b, |
| TestTransform& result) const override { |
| result.sk_m44.setConcat(a.sk_m44, b.sk_m44); |
| } |
| |
| void TransformPoint(const TestTransform& transform, |
| const TestPoint& in, |
| TestPoint& out) const override { |
| out.sk_point = transform.sk_m44.asM33().mapPoint(in.sk_point); |
| } |
| |
| void TransformPoints(const TestTransform& transform, |
| const TestPoint in[], |
| TestPoint out[], |
| int n) const override { |
| static_assert(sizeof(TestPoint) == sizeof(SkPoint)); |
| transform.sk_m44.asM33().mapPoints(reinterpret_cast<SkPoint*>(out), |
| reinterpret_cast<const SkPoint*>(in), n); |
| } |
| |
| void TransformRectFast(const TestTransform& transform, |
| const TestRect& in, |
| TestRect& out) const override { |
| // clang-format off |
| out.sk_rect = transform.sk_m44 |
| .asM33() |
| .mapRect(in.sk_rect, SkApplyPerspectiveClip::kNo); |
| // clang-format on |
| } |
| |
| void TransformAndClipRect(const TestTransform& transform, |
| const TestRect& in, |
| TestRect& out) const override { |
| // clang-format off |
| out.sk_rect = transform.sk_m44 |
| .asM33() |
| .mapRect(in.sk_rect, SkApplyPerspectiveClip::kYes); |
| // clang-format on |
| } |
| |
| int CountClippedCorners(const TestTransform& transform, |
| const TestRect& rect) const { |
| SkPoint3 homogenous[4]; |
| SkPoint corners[4]; |
| rect.sk_rect.toQuad(corners); |
| transform.sk_m44.asM33().mapHomogeneousPoints(homogenous, corners, 4); |
| int count = 0; |
| for (SkPoint3 hpt : homogenous) { |
| if (hpt.fZ <= 0) { |
| count++; |
| } |
| } |
| return count; |
| } |
| |
| void InvertUnchecked(const TestTransform& transform, |
| TestTransform& result) const override { |
| [[maybe_unused]] |
| bool ret = transform.sk_m44.invert(&result.sk_m44); |
| } |
| |
| bool InvertAndCheck(const TestTransform& transform, |
| TestTransform& result) const override { |
| return transform.sk_m44.invert(&result.sk_m44); |
| } |
| }; |
| |
| class ImpellerMatrixAdapter : public TransformAdapter { |
| public: |
| ImpellerMatrixAdapter() = default; |
| ~ImpellerMatrixAdapter() = default; |
| |
| void DoNothing(TestTransform& ignored) const override {} |
| |
| void InitPoint(TestPoint& point, float x, float y) const override { |
| point.impeller_point = impeller::Point(x, y); |
| } |
| |
| void InitRectLTRB(TestRect& rect, |
| float left, |
| float top, |
| float right, |
| float bottom) const override { |
| rect.impeller_rect = impeller::Rect::MakeLTRB(left, top, right, bottom); |
| } |
| |
| void InitTransformIdentity(TestTransform& storage) const override { |
| storage.impeller_matrix = impeller::Matrix(); |
| } |
| |
| virtual void InitTransformColMatrix(TestTransform& result, |
| const float m[16]) const override { |
| // clang-format off |
| result.impeller_matrix = impeller::Matrix::MakeColumn( |
| m[ 0], m[ 1], m[ 2], m[ 3], |
| m[ 4], m[ 5], m[ 6], m[ 7], |
| m[ 8], m[ 9], m[10], m[11], |
| m[12], m[13], m[14], m[15] |
| ); |
| // clang-format on |
| } |
| |
| void Translate(TestTransform& storage, float tx, float ty) const override { |
| storage.impeller_matrix = storage.impeller_matrix.Translate({tx, ty}); |
| } |
| |
| void Scale(TestTransform& storage, float sx, float sy) const override { |
| storage.impeller_matrix = storage.impeller_matrix.Scale({sx, sy, 1.0f}); |
| } |
| |
| void RotateRadians(TestTransform& storage, float radians) const override { |
| storage.impeller_matrix = |
| storage.impeller_matrix * |
| impeller::Matrix::MakeRotationZ(impeller::Radians(radians)); |
| } |
| |
| void Concat(const TestTransform& a, |
| const TestTransform& b, |
| TestTransform& result) const override { |
| result.impeller_matrix = a.impeller_matrix * b.impeller_matrix; |
| } |
| |
| void TransformPoint(const TestTransform& transform, |
| const TestPoint& in, |
| TestPoint& out) const override { |
| out.impeller_point = transform.impeller_matrix * in.impeller_point; |
| } |
| |
| void TransformPoints(const TestTransform& transform, |
| const TestPoint in[], |
| TestPoint out[], |
| int n) const override { |
| for (int i = 0; i < n; i++) { |
| out[i].impeller_point = transform.impeller_matrix * in[i].impeller_point; |
| } |
| } |
| |
| void TransformRectFast(const TestTransform& transform, |
| const TestRect& in, |
| TestRect& out) const override { |
| out.impeller_rect = |
| in.impeller_rect.TransformBounds(transform.impeller_matrix); |
| } |
| |
| void TransformAndClipRect(const TestTransform& transform, |
| const TestRect& in, |
| TestRect& out) const override { |
| out.impeller_rect = |
| in.impeller_rect.TransformAndClipBounds(transform.impeller_matrix); |
| } |
| |
| int CountClippedCorners(const TestTransform& transform, |
| const TestRect& rect) const { |
| auto corners = rect.impeller_rect.GetPoints(); |
| int count = 0; |
| for (auto pt : corners) { |
| auto hpt = transform.impeller_matrix.TransformHomogenous(pt); |
| if (hpt.z <= 0) { |
| count++; |
| } |
| } |
| return count; |
| } |
| |
| void InvertUnchecked(const TestTransform& transform, |
| TestTransform& result) const override { |
| result.impeller_matrix = transform.impeller_matrix.Invert(); |
| } |
| |
| bool InvertAndCheck(const TestTransform& transform, |
| TestTransform& result) const override { |
| result.impeller_matrix = transform.impeller_matrix.Invert(); |
| return transform.impeller_matrix.GetDeterminant() != 0.0f; |
| } |
| }; |
| |
| // The rect argument is passed in by the TransformRect benchmarks so that |
| // the setup function can make sure that it sets up a transform that |
| // clips the desired number of corners during the bounds transform. |
| using SetupFunction = |
| std::function<void(TransformAdapter*, TestTransform&, const TestRect*)>; |
| |
| static void SetupIdentity(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformIdentity(transform); |
| } |
| |
| static void SetupTranslate(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformIdentity(transform); |
| adapter->Translate(transform, 10.2, 12.3); |
| } |
| |
| static void SetupScale(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformIdentity(transform); |
| adapter->Scale(transform, 2.0, 2.0); |
| } |
| |
| static void SetupScaleTranslate(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformIdentity(transform); |
| adapter->Scale(transform, 2.0, 2.0); |
| adapter->Translate(transform, 10.2, 12.3); |
| } |
| |
| static void SetupRotate(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformIdentity(transform); |
| adapter->RotateRadians(transform, kPiOver4); |
| } |
| |
| static void SetupPerspective(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformColMatrix(transform, kSimplePerspective); |
| if (rect) { |
| FML_CHECK(adapter->CountClippedCorners(transform, *rect) == 0); |
| } |
| } |
| |
| static void SetupPerspectiveClipNone(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformColMatrix(transform, kSimplePerspective); |
| if (rect) { |
| FML_CHECK(adapter->CountClippedCorners(transform, *rect) == 0); |
| } |
| } |
| |
| static void SetupPerspectiveClipOne(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformColMatrix(transform, kClipOneCornerPerspective); |
| if (rect) { |
| FML_CHECK(adapter->CountClippedCorners(transform, *rect) == 1); |
| } |
| } |
| |
| static void SetupPerspectiveClipTwo(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformColMatrix(transform, kClipTwoCornersPerspective); |
| if (rect) { |
| FML_CHECK(adapter->CountClippedCorners(transform, *rect) == 2); |
| } |
| } |
| |
| static void SetupPerspectiveClipThree(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformColMatrix(transform, kClipThreeCornersPerspective); |
| if (rect) { |
| FML_CHECK(adapter->CountClippedCorners(transform, *rect) == 3); |
| } |
| } |
| |
| static void SetupPerspectiveClipFour(const TransformAdapter* adapter, |
| TestTransform& transform, |
| const TestRect* rect) { |
| adapter->InitTransformColMatrix(transform, kClipFourCornersPerspective); |
| if (rect) { |
| FML_CHECK(adapter->CountClippedCorners(transform, *rect) == 4); |
| } |
| } |
| |
| // We use a function to return the appropriate adapter so that all methods |
| // used in benchmarking are "pure virtual" and cannot be optimized out |
| // due to issues such as the arguments being constexpr and the result |
| // simplified to a constant value. |
| static std::unique_ptr<TransformAdapter> GetAdapter(AdapterType type) { |
| switch (type) { |
| case AdapterType::kSkMatrix: |
| return std::make_unique<SkMatrixAdapter>(); |
| case AdapterType::kSkM44: |
| return std::make_unique<SkM44Adapter>(); |
| case AdapterType::kImpellerMatrix: |
| return std::make_unique<ImpellerMatrixAdapter>(); |
| } |
| FML_UNREACHABLE(); |
| } |
| |
| } // namespace |
| |
| static void BM_AdapterDispatchOverhead(benchmark::State& state, |
| AdapterType type) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| while (state.KeepRunning()) { |
| adapter->DoNothing(transform); |
| } |
| } |
| |
| static void BM_SetIdentity(benchmark::State& state, AdapterType type) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| while (state.KeepRunning()) { |
| adapter->InitTransformIdentity(transform); |
| } |
| } |
| |
| static void BM_SetPerspective(benchmark::State& state, AdapterType type) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| while (state.KeepRunning()) { |
| adapter->InitTransformColMatrix(transform, kSimplePerspective); |
| } |
| } |
| |
| static void BM_Translate(benchmark::State& state, |
| AdapterType type, |
| float tx, |
| float ty) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| adapter->InitTransformIdentity(transform); |
| bool flip = true; |
| while (state.KeepRunning()) { |
| if (flip) { |
| adapter->Translate(transform, tx, ty); |
| } else { |
| adapter->Translate(transform, -tx, -ty); |
| } |
| flip = !flip; |
| } |
| } |
| |
| static void BM_Scale(benchmark::State& state, AdapterType type, float scale) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| adapter->InitTransformIdentity(transform); |
| float inv_scale = 1.0f / scale; |
| bool flip = true; |
| while (state.KeepRunning()) { |
| if (flip) { |
| adapter->Scale(transform, scale, scale); |
| } else { |
| adapter->Scale(transform, inv_scale, inv_scale); |
| } |
| flip = !flip; |
| } |
| } |
| |
| static void BM_Rotate(benchmark::State& state, |
| AdapterType type, |
| float radians) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| adapter->InitTransformIdentity(transform); |
| while (state.KeepRunning()) { |
| adapter->RotateRadians(transform, radians); |
| } |
| } |
| |
| static void BM_Concat(benchmark::State& state, |
| AdapterType type, |
| const SetupFunction& a_setup, |
| const SetupFunction& b_setup) { |
| auto adapter = GetAdapter(type); |
| TestTransform a, b, result; |
| a_setup(adapter.get(), a, nullptr); |
| b_setup(adapter.get(), b, nullptr); |
| while (state.KeepRunning()) { |
| adapter->Concat(a, b, result); |
| } |
| } |
| |
| static void BM_TransformPoint(benchmark::State& state, |
| AdapterType type, |
| const SetupFunction& setup) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| setup(adapter.get(), transform, nullptr); |
| TestPoint point, result; |
| adapter->InitPoint(point, 25.7, 32.4); |
| while (state.KeepRunning()) { |
| adapter->TransformPoint(transform, point, result); |
| } |
| } |
| |
| static void BM_TransformPoints(benchmark::State& state, |
| AdapterType type, |
| const SetupFunction& setup) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| setup(adapter.get(), transform, nullptr); |
| const int Xs = 10; |
| const int Ys = 10; |
| const int N = Xs * Ys; |
| TestPoint points[N]; |
| for (int i = 0; i < Xs; i++) { |
| for (int j = 0; j < Ys; j++) { |
| int index = i * Xs + j; |
| FML_CHECK(index < N); |
| adapter->InitPoint(points[index], i * 23.3 + 17, j * 32.7 + 12); |
| } |
| } |
| TestPoint results[N]; |
| int64_t item_count = 0; |
| while (state.KeepRunning()) { |
| adapter->TransformPoints(transform, points, results, N); |
| item_count += N; |
| } |
| state.SetItemsProcessed(item_count); |
| } |
| |
| static void BM_TransformRectFast(benchmark::State& state, |
| AdapterType type, |
| const SetupFunction& setup) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| TestRect rect, result; |
| adapter->InitRectLTRB(rect, 100, 100, 200, 200); |
| setup(adapter.get(), transform, &rect); |
| while (state.KeepRunning()) { |
| adapter->TransformRectFast(transform, rect, result); |
| } |
| } |
| |
| static void BM_TransformAndClipRect(benchmark::State& state, |
| AdapterType type, |
| const SetupFunction& setup) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| TestRect rect, result; |
| adapter->InitRectLTRB(rect, 100, 100, 200, 200); |
| setup(adapter.get(), transform, &rect); |
| while (state.KeepRunning()) { |
| adapter->TransformAndClipRect(transform, rect, result); |
| } |
| } |
| |
| static void BM_InvertUnchecked(benchmark::State& state, |
| AdapterType type, |
| const SetupFunction& setup) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| setup(adapter.get(), transform, nullptr); |
| TestTransform result; |
| while (state.KeepRunning()) { |
| adapter->InvertUnchecked(transform, result); |
| } |
| } |
| |
| static void BM_InvertAndCheck(benchmark::State& state, |
| AdapterType type, |
| const SetupFunction& setup) { |
| auto adapter = GetAdapter(type); |
| TestTransform transform; |
| setup(adapter.get(), transform, nullptr); |
| TestTransform result; |
| while (state.KeepRunning()) { |
| adapter->InvertAndCheck(transform, result); |
| } |
| } |
| |
| #define BENCHMARK_CAPTURE_TYPE(name, type) \ |
| BENCHMARK_CAPTURE(name, type, AdapterType::k##type) |
| |
| #define BENCHMARK_CAPTURE_TYPE_ARGS(name, type, ...) \ |
| BENCHMARK_CAPTURE(name, type, AdapterType::k##type, __VA_ARGS__) |
| |
| #define BENCHMARK_CAPTURE_ALL(name) \ |
| BENCHMARK_CAPTURE_TYPE(name, SkMatrix); \ |
| BENCHMARK_CAPTURE_TYPE(name, SkM44); \ |
| BENCHMARK_CAPTURE_TYPE(name, ImpellerMatrix) |
| |
| #define BENCHMARK_CAPTURE_ALL_ARGS(name, ...) \ |
| BENCHMARK_CAPTURE_TYPE_ARGS(name, SkMatrix, __VA_ARGS__); \ |
| BENCHMARK_CAPTURE_TYPE_ARGS(name, SkM44, __VA_ARGS__); \ |
| BENCHMARK_CAPTURE_TYPE_ARGS(name, ImpellerMatrix, __VA_ARGS__) |
| |
| BENCHMARK_CAPTURE_ALL(BM_AdapterDispatchOverhead); |
| |
| BENCHMARK_CAPTURE_ALL(BM_SetIdentity); |
| BENCHMARK_CAPTURE_ALL(BM_SetPerspective); |
| BENCHMARK_CAPTURE_ALL_ARGS(BM_Translate, 10.0f, 15.0f); |
| BENCHMARK_CAPTURE_ALL_ARGS(BM_Scale, 2.0f); |
| BENCHMARK_CAPTURE_ALL_ARGS(BM_Rotate, kPiOver4); |
| |
| // clang-format off |
| #define BENCHMARK_CAPTURE_TYPE_SETUP(name, type, setup) \ |
| BENCHMARK_CAPTURE(name, setup/type, AdapterType::k##type, Setup##setup) |
| // clang-format on |
| |
| #define BENCHMARK_CAPTURE_ALL_SETUP(name, setup) \ |
| BENCHMARK_CAPTURE_TYPE_SETUP(name, SkMatrix, setup); \ |
| BENCHMARK_CAPTURE_TYPE_SETUP(name, SkM44, setup); \ |
| BENCHMARK_CAPTURE_TYPE_SETUP(name, ImpellerMatrix, setup) |
| |
| // clang-format off |
| #define BENCHMARK_CAPTURE_TYPE_SETUP2(name, type, setup1, setup2) \ |
| BENCHMARK_CAPTURE(name, setup1*setup2/type, AdapterType::k##type, \ |
| Setup##setup1, Setup##setup2) |
| // clang-format on |
| |
| #define BENCHMARK_CAPTURE_ALL_SETUP2(name, setup1, setup2) \ |
| BENCHMARK_CAPTURE_TYPE_SETUP2(name, SkMatrix, setup1, setup2); \ |
| BENCHMARK_CAPTURE_TYPE_SETUP2(name, SkM44, setup1, setup2); \ |
| BENCHMARK_CAPTURE_TYPE_SETUP2(name, ImpellerMatrix, setup1, setup2) |
| |
| BENCHMARK_CAPTURE_ALL_SETUP2(BM_Concat, Scale, Translate); |
| BENCHMARK_CAPTURE_ALL_SETUP2(BM_Concat, ScaleTranslate, ScaleTranslate); |
| BENCHMARK_CAPTURE_ALL_SETUP2(BM_Concat, ScaleTranslate, Rotate); |
| BENCHMARK_CAPTURE_ALL_SETUP2(BM_Concat, ScaleTranslate, Perspective); |
| BENCHMARK_CAPTURE_ALL_SETUP2(BM_Concat, Perspective, ScaleTranslate); |
| |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertUnchecked, Identity); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertUnchecked, Translate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertUnchecked, Scale); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertUnchecked, ScaleTranslate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertUnchecked, Rotate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertUnchecked, Perspective); |
| |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertAndCheck, Identity); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertAndCheck, Translate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertAndCheck, Scale); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertAndCheck, ScaleTranslate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertAndCheck, Rotate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_InvertAndCheck, Perspective); |
| |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoint, Identity); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoint, Translate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoint, Scale); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoint, ScaleTranslate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoint, Rotate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoint, Perspective); |
| |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoints, Identity); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoints, Translate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoints, Scale); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoints, ScaleTranslate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoints, Rotate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformPoints, Perspective); |
| |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformRectFast, Identity); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformRectFast, Translate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformRectFast, Scale); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformRectFast, ScaleTranslate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformRectFast, Rotate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformRectFast, PerspectiveClipNone); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformRectFast, PerspectiveClipOne); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformRectFast, PerspectiveClipTwo); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformRectFast, PerspectiveClipThree); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformRectFast, PerspectiveClipFour); |
| |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformAndClipRect, Identity); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformAndClipRect, Translate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformAndClipRect, Scale); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformAndClipRect, ScaleTranslate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformAndClipRect, Rotate); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformAndClipRect, PerspectiveClipNone); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformAndClipRect, PerspectiveClipOne); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformAndClipRect, PerspectiveClipTwo); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformAndClipRect, PerspectiveClipThree); |
| BENCHMARK_CAPTURE_ALL_SETUP(BM_TransformAndClipRect, PerspectiveClipFour); |
| |
| } // namespace flutter |