1 /* 2 * Copyright 2016 Google Inc. 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 8 #include <algorithm> 9 #include <array> 10 #include <tuple> 11 #include <vector> 12 #include "SkLinearBitmapPipeline.h" 13 #include "SkColor.h" 14 #include "SkNx.h" 15 #include "SkPoint.h" 16 #include "SkPM4f.h" 17 #include "Test.h" 18 #include "SkLinearBitmapPipeline_tile.h" 19 20 21 DEF_TEST(LBPBilerpEdge, reporter) { 22 23 } 24 25 static SkString dump(SkScalar cut, Span prefix, Span remainder) { 26 SkPoint prefixStart; SkScalar prefixLen; int prefixCount; 27 std::tie(prefixStart, prefixLen, prefixCount) = prefix; 28 SkPoint remainderStart; SkScalar remainderLen; int remainderCount; 29 std::tie(remainderStart, remainderLen, remainderCount) = remainder; 30 return SkStringPrintf("cut: %f prefix: (%f, %f), %f, %d - remainder: (%f, %f), %f, %d", 31 cut, 32 prefixStart.fX, prefixStart.fY, prefixLen, prefixCount, 33 remainderStart.fX, remainderStart.fY, remainderLen, remainderCount); 34 } 35 36 static void check_span_result( 37 skiatest::Reporter* reporter, 38 Span span, SkScalar dx, SkScalar cut, SkPoint start, SkScalar len, int count) { 39 SkPoint originalStart; SkScalar originalLen; int originalCount; 40 std::tie(originalStart, originalLen, originalCount) = span; 41 42 Span prefix = span.breakAt(cut, dx); 43 44 SkPoint prefixStart; SkScalar prefixLen; int prefixCount; 45 std::tie(prefixStart, prefixLen, prefixCount) = prefix; 46 47 REPORTER_ASSERT_MESSAGE(reporter, prefixStart == start, dump(cut, prefix, span)); 48 REPORTER_ASSERT_MESSAGE(reporter, prefixLen == len, dump(cut, prefix, span)); 49 REPORTER_ASSERT_MESSAGE(reporter, prefixCount == count, dump(cut, prefix, span)); 50 SkPoint expectedRemainderStart; 51 SkScalar expectedRemainderLen; 52 int expectedRemainderCount; 53 if (prefix.isEmpty()) { 54 expectedRemainderStart = originalStart; 55 expectedRemainderLen = originalLen; 56 expectedRemainderCount = originalCount; 57 } else { 58 expectedRemainderStart = SkPoint::Make(originalStart.fX + prefixLen + dx, originalStart.fY); 59 expectedRemainderLen = originalLen - prefixLen - dx; 60 expectedRemainderCount = originalCount - prefixCount; 61 } 62 63 if (!span.isEmpty()) { 64 SkPoint remainderStart; 65 SkScalar remainderLen; 66 int remainderCount; 67 std::tie(remainderStart, remainderLen, remainderCount) = span; 68 // Remainder span 69 REPORTER_ASSERT_MESSAGE(reporter, expectedRemainderStart == remainderStart, 70 dump(cut, prefix, span)); 71 REPORTER_ASSERT_MESSAGE(reporter, 72 expectedRemainderLen == remainderLen, 73 dump(cut, prefix, span)); 74 REPORTER_ASSERT_MESSAGE(reporter, 75 expectedRemainderCount == remainderCount, 76 dump(cut, prefix, span)); 77 } 78 } 79 80 DEF_TEST(LBPSpanOps, reporter) { 81 { 82 SkScalar dx = 1.0f; 83 SkPoint start = SkPoint::Make(-5, -5); 84 Span span{start, 9.0f, 10}; 85 check_span_result(reporter, span, dx, 0.0f, start, 4.0f, 5); 86 check_span_result(reporter, span, dx, -6.0f, SkPoint::Make(0, 0), 0.0f, 0); 87 check_span_result(reporter, span, dx, -5.0f, SkPoint::Make(0, 0), 0.0f, 0); 88 check_span_result(reporter, span, dx, -4.0f, SkPoint::Make(-5, -5), 0.0f, 1); 89 check_span_result(reporter, span, dx, 4.0f, SkPoint::Make(-5, -5), 8.0f, 9); 90 check_span_result(reporter, span, dx, 5.0f, SkPoint::Make(-5, -5), 9.0f, 10); 91 check_span_result(reporter, span, dx, 6.0f, SkPoint::Make(-5, -5), 9.0f, 10); 92 } 93 { 94 SkScalar dx = -1.0f; 95 SkPoint start = SkPoint::Make(5, 5); 96 Span span{start, -9.0f, 10}; 97 check_span_result(reporter, span, dx, 0.0f, start, -5.0f, 6); 98 check_span_result(reporter, span, dx, -6.0f, SkPoint::Make(5, 5), -9.0f, 10); 99 check_span_result(reporter, span, dx, -5.0f, SkPoint::Make(5, 5), -9.0f, 10); 100 check_span_result(reporter, span, dx, -4.0f, SkPoint::Make(5, 5), -9.0f, 10); 101 check_span_result(reporter, span, dx, 4.0f, SkPoint::Make(5, 5), -1.0f, 2); 102 check_span_result(reporter, span, dx, 5.0f, SkPoint::Make(5, 5), 0.0f, 1); 103 check_span_result(reporter, span, dx, 6.0f, SkPoint::Make(0, 0), 0.0f, 0); 104 } 105 } 106 107 DEF_TEST(LBPBilerpSpanOps, reporter) { 108 109 } 110 111 template <typename XTiler, typename YTiler> 112 static bool compare_tiler_case( 113 XTiler& xTiler, YTiler& yTiler, Span span, skiatest::Reporter* reporter) { 114 Span originalSpan = span; 115 std::vector<SkPoint> listPoints; 116 std::vector<SkPoint> spanPoints; 117 struct Sink { 118 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) { 119 SkASSERT(0 < n && n < 4); 120 if (n >= 1) storePoint({xs[0], ys[0]}); 121 if (n >= 2) storePoint({xs[1], ys[1]}); 122 if (n >= 3) storePoint({xs[2], ys[2]}); 123 } 124 125 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) { 126 storePoint({xs[0], ys[0]}); 127 storePoint({xs[1], ys[1]}); 128 storePoint({xs[2], ys[2]}); 129 storePoint({xs[3], ys[3]}); 130 } 131 132 void pointSpan(Span span) { 133 span_fallback(span, this); 134 } 135 136 void storePoint(SkPoint pt) { 137 fPoints->push_back({SkScalarFloorToScalar(X(pt)), SkScalarFloorToScalar(Y(pt))}); 138 } 139 140 std::vector<SkPoint>* fPoints; 141 }; 142 143 Sink listSink = {&listPoints}; 144 Sink spanSink = {&spanPoints}; 145 146 SkPoint start; SkScalar length; int count; 147 std::tie(start, length, count) = span; 148 149 SkScalar dx = length / (count - 1); 150 Sk4f xs = Sk4f{X(start)} + Sk4f{0.0f, dx, 2 * dx, 3 * dx}; 151 Sk4f ys = Sk4f{Y(start)}; 152 while (count >= 4) { 153 Sk4f txs = xs; 154 Sk4f tys = ys; 155 xTiler.tileXPoints(&txs); 156 yTiler.tileYPoints(&tys); 157 listSink.pointList4(txs, tys); 158 xs = xs + 4.0f * dx; 159 count -= 4; 160 } 161 if (count > 0) { 162 xTiler.tileXPoints(&xs); 163 yTiler.tileYPoints(&ys); 164 listSink.pointListFew(count, xs, ys); 165 } 166 167 std::tie(start, length, count) = originalSpan; 168 SkScalar x = X(start); 169 SkScalar y = yTiler.tileY(Y(start)); 170 Span yAdjustedSpan{{x, y}, length, count}; 171 172 bool handledSpan = xTiler.maybeProcessSpan(yAdjustedSpan, &spanSink); 173 if (handledSpan) { 174 auto firstNotTheSame = std::mismatch( 175 listPoints.begin(), listPoints.end(), spanPoints.begin()); 176 if (firstNotTheSame.first != listSink.fPoints->end()) { 177 auto element = std::distance(listPoints.begin(), firstNotTheSame.first); 178 SkASSERT(element >= 0); 179 std::tie(start, length, count) = originalSpan; 180 ERRORF(reporter, "Span: {%f, %f}, %f, %d", start.fX, start.fY, length, count); 181 ERRORF(reporter, "Size points: %d, size span: %d", 182 listPoints.size(), spanPoints.size()); 183 if ((unsigned)element >= spanPoints.size()) { 184 ERRORF(reporter, "Size points: %d, size span: %d", 185 listPoints.size(), spanPoints.size()); 186 // Mismatch off the end 187 ERRORF(reporter, 188 "The mismatch is at position %d and has value %f, %f - it is off the end " 189 "of the other.", 190 element, X(*firstNotTheSame.first), Y(*firstNotTheSame.first)); 191 } else { 192 ERRORF(reporter, 193 "Mismatch at %d - points: %f, %f - span: %f, %f", 194 element, listPoints[element].fX, listPoints[element].fY, 195 spanPoints[element].fX, spanPoints[element].fY); 196 } 197 SkFAIL("aha"); 198 } 199 } 200 return true; 201 } 202 203 template <typename XTiler, typename YTiler> 204 static bool compare_tiler_spans(int width, int height, skiatest::Reporter* reporter) { 205 XTiler xTiler{width}; 206 YTiler yTiler{height}; 207 INFOF(reporter, "w: %d, h: %d \n", width, height); 208 std::array<int, 8> interestingX {{-5, -1, 0, 1, width - 1, width, width + 1, width + 5}}; 209 std::array<int, 8> interestingY {{-5, -1, 0, 1, height - 1, height, height + 1, height + 5}}; 210 std::array<int, 6> interestingCount {{1, 2, 3, 4, 5, 10}}; 211 std::array<SkScalar, 7> interestingScale {{0.0f, 1.0f, 0.5f, 2.1f, -2.1f, -1.0f, -0.5f}}; 212 for (auto scale : interestingScale) { 213 for (auto startX : interestingX) { 214 for (auto count : interestingCount) { 215 for (auto y : interestingY) { 216 Span span{ 217 SkPoint::Make((SkScalar)startX, (SkScalar)y), (count-1.0f) * scale, count}; 218 if (!compare_tiler_case(xTiler, yTiler, span, reporter)) { 219 return false; 220 } 221 } 222 } 223 } 224 } 225 return true; 226 } 227 228 template <typename XTiler, typename YTiler> 229 static void test_tiler(skiatest::Reporter* reporter) { 230 std::array<int, 6> interestingSize {{1, 2, 3, 4, 5, 10}}; 231 for (auto width : interestingSize) { 232 for (auto height : interestingSize) { 233 if (!compare_tiler_spans<XTiler, YTiler>(width, height, reporter)) { return; } 234 } 235 } 236 } 237 /* 238 DEF_TEST(LBPStrategyClampTile, reporter) { 239 #if 0 240 ClampStrategy tiler{SkSize::Make(1, 1)}; 241 Span span{SkPoint::Make(0, -5), 1.0f, 2}; 242 compare_tiler_case<ClampStrategy>(tiler, span, reporter); 243 #else 244 test_tiler<XClampStrategy, YClampStrategy>(reporter); 245 #endif 246 } 247 248 DEF_TEST(LBPStrategyRepeatTile, reporter) { 249 #if 0 250 RepeatStrategy tiler{SkSize::Make(3, 1)}; 251 Span span{SkPoint::Make(-5, -5), 20 * 2.1f, 100}; 252 compare_tiler_case<RepeatStrategy>(tiler, span, reporter); 253 #else 254 test_tiler<XRepeatStrategy, YRepeatStrategy>(reporter); 255 #endif 256 } 257 */ 258