OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
| 8 #include <algorithm> |
| 9 #include <array> |
| 10 #include <tuple> |
| 11 #include <vector> |
8 #include "SkLinearBitmapPipeline.h" | 12 #include "SkLinearBitmapPipeline.h" |
9 #include "SkColor.h" | 13 #include "SkColor.h" |
| 14 #include "SkNx.h" |
| 15 #include "SkPoint.h" |
10 #include "SkPM4f.h" | 16 #include "SkPM4f.h" |
11 #include "Test.h" | 17 #include "Test.h" |
12 | 18 #include "SkLinearBitmapPipeline_tile.h" |
13 using Pixel = float[4]; | 19 |
14 DEF_TEST(SkBitmapFP, reporter) { | 20 |
15 | 21 static SkString dump(SkScalar cut, Span prefix, Span remainder) { |
16 int width = 10; | 22 SkPoint prefixStart; SkScalar prefixLen; int prefixCount; |
17 int height = 10; | 23 std::tie(prefixStart, prefixLen, prefixCount) = prefix; |
18 uint32_t* bitmap = new uint32_t[width * height]; | 24 SkPoint remainderStart; SkScalar remainderLen; int remainderCount; |
19 for (int y = 0; y < height; y++) { | 25 std::tie(remainderStart, remainderLen, remainderCount) = remainder; |
20 for (int x = 0; x < width; x++) { | 26 return SkStringPrintf("cut: %f prefix: (%f, %f), %f, %d - remainder: (%f, %f
), %f, %d", |
21 bitmap[y * width + x] = (y << 8) + x + (128<<24); | 27 cut, |
22 } | 28 prefixStart.fX, prefixStart.fY, prefixLen, prefixCount
, |
23 } | 29 remainderStart.fX, remainderStart.fY, remainderLen, re
mainderCount); |
24 | 30 } |
25 SkPM4f* FPbuffer = new SkPM4f[width * height]; | 31 |
26 | 32 static void check_span_result( |
27 SkMatrix m = SkMatrix::I(); | 33 skiatest::Reporter* reporter, |
28 //m.setRotate(30.0f, 1.0f, 1.0f); | 34 Span span, SkScalar dx, SkScalar cut, SkPoint start, SkScalar len, int count
) { |
29 SkMatrix invert; | 35 SkPoint originalStart; SkScalar originalLen; int originalCount; |
30 bool trash = m.invert(&invert); | 36 std::tie(originalStart, originalLen, originalCount) = span; |
31 sk_ignore_unused_variable(trash); | 37 |
32 | 38 Span prefix = span.breakAt(cut, dx); |
33 const SkImageInfo info = | 39 |
34 SkImageInfo::MakeN32Premul(width, height, kLinear_SkColorProfileType); | 40 SkPoint prefixStart; SkScalar prefixLen; int prefixCount; |
35 | 41 std::tie(prefixStart, prefixLen, prefixCount) = prefix; |
36 SkPixmap srcPixmap{info, bitmap, static_cast<size_t>(4 * width)}; | 42 |
37 | 43 REPORTER_ASSERT_MESSAGE(reporter, prefixStart == start, dump(cut, prefix, sp
an)); |
38 SkLinearBitmapPipeline pipeline{invert, kNone_SkFilterQuality, SkShader::kCl
amp_TileMode, | 44 REPORTER_ASSERT_MESSAGE(reporter, prefixLen == len, dump(cut, prefix, span))
; |
39 SkShader::kClamp_TileMode, srcPixmap}; | 45 REPORTER_ASSERT_MESSAGE(reporter, prefixCount == count, dump(cut, prefix, sp
an)); |
40 | 46 SkPoint expectedRemainderStart; |
41 int count = 10; | 47 SkScalar expectedRemainderLen; |
42 | 48 int expectedRemainderCount; |
43 pipeline.shadeSpan4f(3, 6, FPbuffer, count); | 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 == remainderSta
rt, |
| 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* repo
rter) { |
| 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)), SkScalarFloorToSca
lar(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.fir
st); |
| 162 SkASSERT(element >= 0); |
| 163 std::tie(start, length, count) = originalSpan; |
| 164 ERRORF(reporter, "Span: {%f, %f}, %f, %d", start.fX, start.fY, lengt
h, 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.fi
rst)); |
| 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"); |
| 182 } |
| 183 } |
| 184 return true; |
| 185 } |
| 186 |
| 187 template <typename Tiler> |
| 188 static bool compare_tiler_spans(int width, int height, skiatest::Reporter* repor
ter) { |
| 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.0
f) * 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) { |
44 #if 0 | 222 #if 0 |
45 Pixel* pixelBuffer = (Pixel*)FPbuffer; | 223 ClampStrategy tiler{SkSize::Make(1, 1)}; |
46 for (int i = 0; i < count; i++) { | 224 Span span{SkPoint::Make(0, -5), 1.0f, 2}; |
47 printf("i: %d - (%g, %g, %g, %g)\n", i, | 225 compare_tiler_case<ClampStrategy>(tiler, span, reporter); |
48 pixelBuffer[i][0] * 255.0f, | 226 #else |
49 pixelBuffer[i][1] * 255.0f, | 227 test_tiler<ClampStrategy>(reporter); |
50 pixelBuffer[i][2] * 255.0f, | |
51 pixelBuffer[i][3] * 255.0f); | |
52 } | |
53 #endif | 228 #endif |
54 | 229 } |
55 delete [] bitmap; | 230 |
56 delete [] FPbuffer; | 231 DEF_TEST(LBPStrategyRepeatTile, reporter) { |
57 } | 232 #if 0 |
58 | 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 |
OLD | NEW |