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
DEF_TEST(LBPBilerpEdge,reporter)21 DEF_TEST(LBPBilerpEdge, reporter) {
22
23 }
24
dump(SkScalar cut,Span prefix,Span remainder)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
check_span_result(skiatest::Reporter * reporter,Span span,SkScalar dx,SkScalar cut,SkPoint start,SkScalar len,int count)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
DEF_TEST(LBPSpanOps,reporter)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
DEF_TEST(LBPBilerpSpanOps,reporter)107 DEF_TEST(LBPBilerpSpanOps, reporter) {
108
109 }
110
111 template <typename XTiler, typename YTiler>
compare_tiler_case(XTiler & xTiler,YTiler & yTiler,Span span,skiatest::Reporter * reporter)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>
compare_tiler_spans(int width,int height,skiatest::Reporter * reporter)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>
test_tiler(skiatest::Reporter * reporter)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