GrQuadCropTest.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * Copyright 2019 Google LLC
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkScalar.h"
  8. #include "src/gpu/geometry/GrQuad.h"
  9. #include "src/gpu/geometry/GrQuadUtils.h"
  10. #include "tests/Test.h"
  11. #define ASSERT(cond) REPORTER_ASSERT(r, cond)
  12. #define ASSERTF(cond, ...) REPORTER_ASSERT(r, cond, __VA_ARGS__)
  13. #define TEST(name) DEF_TEST(GrQuadCrop##name, r)
  14. #define ASSERT_NEARLY_EQUAL(expected, actual) \
  15. ASSERTF(SkScalarNearlyEqual(expected, actual), "expected: %f, actual: %f", \
  16. expected, actual)
  17. // Make the base rect contain the origin and have unique edge values so that each transform
  18. // produces a different axis-aligned rectangle.
  19. static const SkRect kDrawRect = SkRect::MakeLTRB(-5.f, -6.f, 10.f, 11.f);
  20. static void run_crop_axis_aligned_test(skiatest::Reporter* r, const SkRect& clipRect, GrAA clipAA,
  21. const SkMatrix& viewMatrix, const SkMatrix* localMatrix) {
  22. // Should use run_crop_fully_covers_test for non-rect matrices
  23. SkASSERT(viewMatrix.rectStaysRect());
  24. GrQuad drawQuad = GrQuad::MakeFromRect(kDrawRect, viewMatrix);
  25. GrQuad localQuad = GrQuad::MakeFromRect(kDrawRect, localMatrix ? *localMatrix : SkMatrix::I());
  26. GrQuad* localQuadPtr = localMatrix ? &localQuad : nullptr;
  27. GrQuadAAFlags edgeFlags = clipAA == GrAA::kYes ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll;
  28. bool exact = GrQuadUtils::CropToRect(clipRect, clipAA, &edgeFlags, &drawQuad, localQuadPtr);
  29. ASSERTF(exact, "Expected exact crop");
  30. ASSERTF(drawQuad.quadType() == GrQuad::Type::kAxisAligned,
  31. "Expected quad to remain axis-aligned");
  32. // Since we remained a rectangle, the bounds will exactly match the coordinates
  33. SkRect expectedBounds = viewMatrix.mapRect(kDrawRect);
  34. SkAssertResult(expectedBounds.intersect(clipRect));
  35. SkRect actualBounds = drawQuad.bounds();
  36. ASSERT_NEARLY_EQUAL(expectedBounds.fLeft, actualBounds.fLeft);
  37. ASSERT_NEARLY_EQUAL(expectedBounds.fTop, actualBounds.fTop);
  38. ASSERT_NEARLY_EQUAL(expectedBounds.fRight, actualBounds.fRight);
  39. ASSERT_NEARLY_EQUAL(expectedBounds.fBottom, actualBounds.fBottom);
  40. // Confirm that local coordinates match up with clipped edges and the transform
  41. SkMatrix invViewMatrix;
  42. SkAssertResult(viewMatrix.invert(&invViewMatrix));
  43. if (localMatrix) {
  44. SkMatrix toLocal = SkMatrix::Concat(*localMatrix, invViewMatrix);
  45. for (int p = 0; p < 4; ++p) {
  46. SkPoint expectedPoint = drawQuad.point(p);
  47. toLocal.mapPoints(&expectedPoint, 1);
  48. SkPoint actualPoint = localQuad.point(p);
  49. ASSERT_NEARLY_EQUAL(expectedPoint.fX, actualPoint.fX);
  50. ASSERT_NEARLY_EQUAL(expectedPoint.fY, actualPoint.fY);
  51. }
  52. }
  53. // Confirm that the edge flags match, by mapping clip rect to drawRect space and
  54. // comparing to the original draw rect edges
  55. SkRect drawClip = invViewMatrix.mapRect(clipRect);
  56. if (drawClip.fLeft > kDrawRect.fLeft) {
  57. if (clipAA == GrAA::kYes) {
  58. ASSERTF(edgeFlags & GrQuadAAFlags::kLeft, "Expected left edge AA set");
  59. } else {
  60. ASSERTF(!(edgeFlags & GrQuadAAFlags::kLeft), "Expected left edge AA unset");
  61. }
  62. }
  63. if (drawClip.fRight < kDrawRect.fRight) {
  64. if (clipAA == GrAA::kYes) {
  65. ASSERTF(edgeFlags & GrQuadAAFlags::kRight, "Expected right edge AA set");
  66. } else {
  67. ASSERTF(!(edgeFlags & GrQuadAAFlags::kRight), "Expected right edge AA unset");
  68. }
  69. }
  70. if (drawClip.fTop > kDrawRect.fTop) {
  71. if (clipAA == GrAA::kYes) {
  72. ASSERTF(edgeFlags & GrQuadAAFlags::kTop, "Expected top edge AA set");
  73. } else {
  74. ASSERTF(!(edgeFlags & GrQuadAAFlags::kTop), "Expected top edge AA unset");
  75. }
  76. }
  77. if (drawClip.fBottom < kDrawRect.fBottom) {
  78. if (clipAA == GrAA::kYes) {
  79. ASSERTF(edgeFlags & GrQuadAAFlags::kBottom, "Expected bottom edge AA set");
  80. } else {
  81. ASSERTF(!(edgeFlags & GrQuadAAFlags::kBottom), "Expected bottom edge AA unset");
  82. }
  83. }
  84. }
  85. static void run_crop_fully_covered_test(skiatest::Reporter* r, GrAA clipAA,
  86. const SkMatrix& viewMatrix, const SkMatrix* localMatrix) {
  87. // Should use run_crop_axis_aligned for rect transforms since that verifies more behavior
  88. SkASSERT(!viewMatrix.rectStaysRect());
  89. // Test what happens when the geometry fully covers the crop rect. Given a fixed crop,
  90. // use the provided view matrix to derive the "input" geometry that we know covers the crop.
  91. SkMatrix invViewMatrix;
  92. SkAssertResult(viewMatrix.invert(&invViewMatrix));
  93. SkRect containsCrop = kDrawRect; // Use kDrawRect as the crop rect for this test
  94. containsCrop.outset(10.f, 10.f);
  95. SkRect drawRect = invViewMatrix.mapRect(containsCrop);
  96. GrQuad drawQuad = GrQuad::MakeFromRect(drawRect, viewMatrix);
  97. GrQuadAAFlags edgeFlags = clipAA == GrAA::kYes ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll;
  98. if (localMatrix) {
  99. GrQuad localQuad = GrQuad::MakeFromRect(drawRect, *localMatrix);
  100. GrQuad originalDrawQuad = drawQuad;
  101. GrQuad originalLocalQuad = localQuad;
  102. GrQuadAAFlags originalEdgeFlags = edgeFlags;
  103. bool exact = GrQuadUtils::CropToRect(kDrawRect, clipAA, &edgeFlags, &drawQuad, &localQuad);
  104. // Currently non-rect matrices don't know how to update local coordinates, so the crop
  105. // doesn't know how to restrict itself and should leave the inputs unmodified
  106. ASSERTF(!exact, "Expected crop to be not exact");
  107. ASSERTF(edgeFlags == originalEdgeFlags, "Expected edge flags not to be modified");
  108. for (int i = 0; i < 4; ++i) {
  109. ASSERT_NEARLY_EQUAL(originalDrawQuad.x(i), drawQuad.x(i));
  110. ASSERT_NEARLY_EQUAL(originalDrawQuad.y(i), drawQuad.y(i));
  111. ASSERT_NEARLY_EQUAL(originalDrawQuad.w(i), drawQuad.w(i));
  112. ASSERT_NEARLY_EQUAL(originalLocalQuad.x(i), localQuad.x(i));
  113. ASSERT_NEARLY_EQUAL(originalLocalQuad.y(i), localQuad.y(i));
  114. ASSERT_NEARLY_EQUAL(originalLocalQuad.w(i), localQuad.w(i));
  115. }
  116. } else {
  117. // Since no local coordinates were provided, and the input draw geometry is known to
  118. // fully cover the crop rect, the quad should be updated to match cropRect exactly
  119. bool exact = GrQuadUtils::CropToRect(kDrawRect, clipAA, &edgeFlags, &drawQuad, nullptr);
  120. ASSERTF(exact, "Expected crop to be exact");
  121. GrQuadAAFlags expectedFlags = clipAA == GrAA::kYes ? GrQuadAAFlags::kAll
  122. : GrQuadAAFlags::kNone;
  123. ASSERTF(expectedFlags == edgeFlags, "Expected edge flags do not match clip AA setting");
  124. ASSERTF(drawQuad.quadType() == GrQuad::Type::kAxisAligned, "Unexpected quad type");
  125. ASSERT_NEARLY_EQUAL(kDrawRect.fLeft, drawQuad.x(0));
  126. ASSERT_NEARLY_EQUAL(kDrawRect.fTop, drawQuad.y(0));
  127. ASSERT_NEARLY_EQUAL(1.f, drawQuad.w(0));
  128. ASSERT_NEARLY_EQUAL(kDrawRect.fLeft, drawQuad.x(1));
  129. ASSERT_NEARLY_EQUAL(kDrawRect.fBottom, drawQuad.y(1));
  130. ASSERT_NEARLY_EQUAL(1.f, drawQuad.w(1));
  131. ASSERT_NEARLY_EQUAL(kDrawRect.fRight, drawQuad.x(2));
  132. ASSERT_NEARLY_EQUAL(kDrawRect.fTop, drawQuad.y(2));
  133. ASSERT_NEARLY_EQUAL(1.f, drawQuad.w(2));
  134. ASSERT_NEARLY_EQUAL(kDrawRect.fRight, drawQuad.x(3));
  135. ASSERT_NEARLY_EQUAL(kDrawRect.fBottom, drawQuad.y(3));
  136. ASSERT_NEARLY_EQUAL(1.f, drawQuad.w(3));
  137. }
  138. }
  139. static void test_axis_aligned_all_clips(skiatest::Reporter* r, const SkMatrix& viewMatrix,
  140. const SkMatrix* localMatrix) {
  141. static const float kInsideEdge = SkScalarAbs(kDrawRect.fLeft) - 1.f;
  142. static const float kOutsideEdge = SkScalarAbs(kDrawRect.fBottom) + 1.f;
  143. static const float kIntersectEdge = SkScalarAbs(kDrawRect.fTop) + 1.f;
  144. static const SkRect kInsideClipRect = SkRect::MakeLTRB(-kInsideEdge, -kInsideEdge,
  145. kInsideEdge, kInsideEdge);
  146. static const SkRect kContainsClipRect = SkRect::MakeLTRB(-kOutsideEdge, -kOutsideEdge,
  147. kOutsideEdge, kOutsideEdge);
  148. static const SkRect kXYAxesClipRect = SkRect::MakeLTRB(-kIntersectEdge, -kIntersectEdge,
  149. kIntersectEdge, kIntersectEdge);
  150. static const SkRect kXAxisClipRect = SkRect::MakeLTRB(-kIntersectEdge, -kOutsideEdge,
  151. kIntersectEdge, kOutsideEdge);
  152. static const SkRect kYAxisClipRect = SkRect::MakeLTRB(-kOutsideEdge, -kIntersectEdge,
  153. kOutsideEdge, kIntersectEdge);
  154. run_crop_axis_aligned_test(r, kInsideClipRect, GrAA::kNo, viewMatrix, localMatrix);
  155. run_crop_axis_aligned_test(r, kContainsClipRect, GrAA::kNo, viewMatrix, localMatrix);
  156. run_crop_axis_aligned_test(r, kXYAxesClipRect, GrAA::kNo, viewMatrix, localMatrix);
  157. run_crop_axis_aligned_test(r, kXAxisClipRect, GrAA::kNo, viewMatrix, localMatrix);
  158. run_crop_axis_aligned_test(r, kYAxisClipRect, GrAA::kNo, viewMatrix, localMatrix);
  159. run_crop_axis_aligned_test(r, kInsideClipRect, GrAA::kYes, viewMatrix, localMatrix);
  160. run_crop_axis_aligned_test(r, kContainsClipRect, GrAA::kYes, viewMatrix, localMatrix);
  161. run_crop_axis_aligned_test(r, kXYAxesClipRect, GrAA::kYes, viewMatrix, localMatrix);
  162. run_crop_axis_aligned_test(r, kXAxisClipRect, GrAA::kYes, viewMatrix, localMatrix);
  163. run_crop_axis_aligned_test(r, kYAxisClipRect, GrAA::kYes, viewMatrix, localMatrix);
  164. }
  165. static void test_axis_aligned(skiatest::Reporter* r, const SkMatrix& viewMatrix) {
  166. test_axis_aligned_all_clips(r, viewMatrix, nullptr);
  167. SkMatrix normalized = SkMatrix::MakeRectToRect(kDrawRect, SkRect::MakeWH(1.f, 1.f),
  168. SkMatrix::kFill_ScaleToFit);
  169. test_axis_aligned_all_clips(r, viewMatrix, &normalized);
  170. SkMatrix rotated;
  171. rotated.setRotate(45.f);
  172. test_axis_aligned_all_clips(r, viewMatrix, &rotated);
  173. SkMatrix perspective;
  174. perspective.setPerspY(0.001f);
  175. perspective.setSkewX(8.f / 25.f);
  176. test_axis_aligned_all_clips(r, viewMatrix, &perspective);
  177. }
  178. static void test_crop_fully_covered(skiatest::Reporter* r, const SkMatrix& viewMatrix) {
  179. run_crop_fully_covered_test(r, GrAA::kNo, viewMatrix, nullptr);
  180. run_crop_fully_covered_test(r, GrAA::kYes, viewMatrix, nullptr);
  181. SkMatrix normalized = SkMatrix::MakeRectToRect(kDrawRect, SkRect::MakeWH(1.f, 1.f),
  182. SkMatrix::kFill_ScaleToFit);
  183. run_crop_fully_covered_test(r, GrAA::kNo, viewMatrix, &normalized);
  184. run_crop_fully_covered_test(r, GrAA::kYes, viewMatrix, &normalized);
  185. SkMatrix rotated;
  186. rotated.setRotate(45.f);
  187. run_crop_fully_covered_test(r, GrAA::kNo, viewMatrix, &rotated);
  188. run_crop_fully_covered_test(r, GrAA::kYes, viewMatrix, &rotated);
  189. SkMatrix perspective;
  190. perspective.setPerspY(0.001f);
  191. perspective.setSkewX(8.f / 25.f);
  192. run_crop_fully_covered_test(r, GrAA::kNo, viewMatrix, &perspective);
  193. run_crop_fully_covered_test(r, GrAA::kYes, viewMatrix, &perspective);
  194. }
  195. TEST(AxisAligned) {
  196. test_axis_aligned(r, SkMatrix::I());
  197. test_axis_aligned(r, SkMatrix::MakeScale(-1.f, 1.f));
  198. test_axis_aligned(r, SkMatrix::MakeScale(1.f, -1.f));
  199. SkMatrix rotation;
  200. rotation.setRotate(90.f);
  201. test_axis_aligned(r, rotation);
  202. rotation.setRotate(180.f);
  203. test_axis_aligned(r, rotation);
  204. rotation.setRotate(270.f);
  205. test_axis_aligned(r, rotation);
  206. }
  207. TEST(FullyCovered) {
  208. SkMatrix rotation;
  209. rotation.setRotate(34.f);
  210. test_crop_fully_covered(r, rotation);
  211. SkMatrix skew;
  212. skew.setSkewX(0.3f);
  213. skew.setSkewY(0.04f);
  214. test_crop_fully_covered(r, skew);
  215. SkMatrix perspective;
  216. perspective.setPerspX(0.001f);
  217. perspective.setSkewY(8.f / 25.f);
  218. test_crop_fully_covered(r, perspective);
  219. }