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