| /* |
| * Copyright 2016 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include <algorithm> |
| #include <array> |
| #include <tuple> |
| #include <vector> |
| #include "SkLinearBitmapPipeline.h" |
| #include "SkColor.h" |
| #include "SkNx.h" |
| #include "SkPoint.h" |
| #include "SkPM4f.h" |
| #include "Test.h" |
| #include "SkLinearBitmapPipeline_tile.h" |
| |
| |
| DEF_TEST(LBPBilerpEdge, reporter) { |
| |
| } |
| |
| static SkString dump(SkScalar cut, Span prefix, Span remainder) { |
| SkPoint prefixStart; SkScalar prefixLen; int prefixCount; |
| std::tie(prefixStart, prefixLen, prefixCount) = prefix; |
| SkPoint remainderStart; SkScalar remainderLen; int remainderCount; |
| std::tie(remainderStart, remainderLen, remainderCount) = remainder; |
| return SkStringPrintf("cut: %f prefix: (%f, %f), %f, %d - remainder: (%f, %f), %f, %d", |
| cut, |
| prefixStart.fX, prefixStart.fY, prefixLen, prefixCount, |
| remainderStart.fX, remainderStart.fY, remainderLen, remainderCount); |
| } |
| |
| static void check_span_result( |
| skiatest::Reporter* reporter, |
| Span span, SkScalar dx, SkScalar cut, SkPoint start, SkScalar len, int count) { |
| SkPoint originalStart; SkScalar originalLen; int originalCount; |
| std::tie(originalStart, originalLen, originalCount) = span; |
| |
| Span prefix = span.breakAt(cut, dx); |
| |
| SkPoint prefixStart; SkScalar prefixLen; int prefixCount; |
| std::tie(prefixStart, prefixLen, prefixCount) = prefix; |
| |
| REPORTER_ASSERT_MESSAGE(reporter, prefixStart == start, dump(cut, prefix, span)); |
| REPORTER_ASSERT_MESSAGE(reporter, prefixLen == len, dump(cut, prefix, span)); |
| REPORTER_ASSERT_MESSAGE(reporter, prefixCount == count, dump(cut, prefix, span)); |
| SkPoint expectedRemainderStart; |
| SkScalar expectedRemainderLen; |
| int expectedRemainderCount; |
| if (prefix.isEmpty()) { |
| expectedRemainderStart = originalStart; |
| expectedRemainderLen = originalLen; |
| expectedRemainderCount = originalCount; |
| } else { |
| expectedRemainderStart = SkPoint::Make(originalStart.fX + prefixLen + dx, originalStart.fY); |
| expectedRemainderLen = originalLen - prefixLen - dx; |
| expectedRemainderCount = originalCount - prefixCount; |
| } |
| |
| if (!span.isEmpty()) { |
| SkPoint remainderStart; |
| SkScalar remainderLen; |
| int remainderCount; |
| std::tie(remainderStart, remainderLen, remainderCount) = span; |
| // Remainder span |
| REPORTER_ASSERT_MESSAGE(reporter, expectedRemainderStart == remainderStart, |
| dump(cut, prefix, span)); |
| REPORTER_ASSERT_MESSAGE(reporter, |
| expectedRemainderLen == remainderLen, |
| dump(cut, prefix, span)); |
| REPORTER_ASSERT_MESSAGE(reporter, |
| expectedRemainderCount == remainderCount, |
| dump(cut, prefix, span)); |
| } |
| } |
| |
| DEF_TEST(LBPSpanOps, reporter) { |
| { |
| SkScalar dx = 1.0f; |
| SkPoint start = SkPoint::Make(-5, -5); |
| Span span{start, 9.0f, 10}; |
| check_span_result(reporter, span, dx, 0.0f, start, 4.0f, 5); |
| check_span_result(reporter, span, dx, -6.0f, SkPoint::Make(0, 0), 0.0f, 0); |
| check_span_result(reporter, span, dx, -5.0f, SkPoint::Make(0, 0), 0.0f, 0); |
| check_span_result(reporter, span, dx, -4.0f, SkPoint::Make(-5, -5), 0.0f, 1); |
| check_span_result(reporter, span, dx, 4.0f, SkPoint::Make(-5, -5), 8.0f, 9); |
| check_span_result(reporter, span, dx, 5.0f, SkPoint::Make(-5, -5), 9.0f, 10); |
| check_span_result(reporter, span, dx, 6.0f, SkPoint::Make(-5, -5), 9.0f, 10); |
| } |
| { |
| SkScalar dx = -1.0f; |
| SkPoint start = SkPoint::Make(5, 5); |
| Span span{start, -9.0f, 10}; |
| check_span_result(reporter, span, dx, 0.0f, start, -5.0f, 6); |
| check_span_result(reporter, span, dx, -6.0f, SkPoint::Make(5, 5), -9.0f, 10); |
| check_span_result(reporter, span, dx, -5.0f, SkPoint::Make(5, 5), -9.0f, 10); |
| check_span_result(reporter, span, dx, -4.0f, SkPoint::Make(5, 5), -9.0f, 10); |
| check_span_result(reporter, span, dx, 4.0f, SkPoint::Make(5, 5), -1.0f, 2); |
| check_span_result(reporter, span, dx, 5.0f, SkPoint::Make(5, 5), 0.0f, 1); |
| check_span_result(reporter, span, dx, 6.0f, SkPoint::Make(0, 0), 0.0f, 0); |
| } |
| } |
| |
| DEF_TEST(LBPBilerpSpanOps, reporter) { |
| |
| } |
| |
| template <typename XTiler, typename YTiler> |
| static bool compare_tiler_case( |
| XTiler& xTiler, YTiler& yTiler, Span span, skiatest::Reporter* reporter) { |
| Span originalSpan = span; |
| std::vector<SkPoint> listPoints; |
| std::vector<SkPoint> spanPoints; |
| struct Sink { |
| void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) { |
| SkASSERT(0 < n && n < 4); |
| if (n >= 1) storePoint({xs[0], ys[0]}); |
| if (n >= 2) storePoint({xs[1], ys[1]}); |
| if (n >= 3) storePoint({xs[2], ys[2]}); |
| } |
| |
| void VECTORCALL pointList4(Sk4s xs, Sk4s ys) { |
| storePoint({xs[0], ys[0]}); |
| storePoint({xs[1], ys[1]}); |
| storePoint({xs[2], ys[2]}); |
| storePoint({xs[3], ys[3]}); |
| } |
| |
| void pointSpan(Span span) { |
| span_fallback(span, this); |
| } |
| |
| void storePoint(SkPoint pt) { |
| fPoints->push_back({SkScalarFloorToScalar(X(pt)), SkScalarFloorToScalar(Y(pt))}); |
| } |
| |
| std::vector<SkPoint>* fPoints; |
| }; |
| |
| Sink listSink = {&listPoints}; |
| Sink spanSink = {&spanPoints}; |
| |
| SkPoint start; SkScalar length; int count; |
| std::tie(start, length, count) = span; |
| |
| SkScalar dx = length / (count - 1); |
| Sk4f xs = Sk4f{X(start)} + Sk4f{0.0f, dx, 2 * dx, 3 * dx}; |
| Sk4f ys = Sk4f{Y(start)}; |
| while (count >= 4) { |
| Sk4f txs = xs; |
| Sk4f tys = ys; |
| xTiler.tileXPoints(&txs); |
| yTiler.tileYPoints(&tys); |
| listSink.pointList4(txs, tys); |
| xs = xs + 4.0f * dx; |
| count -= 4; |
| } |
| if (count > 0) { |
| xTiler.tileXPoints(&xs); |
| yTiler.tileYPoints(&ys); |
| listSink.pointListFew(count, xs, ys); |
| } |
| |
| std::tie(start, length, count) = originalSpan; |
| SkScalar x = X(start); |
| SkScalar y = yTiler.tileY(Y(start)); |
| Span yAdjustedSpan{{x, y}, length, count}; |
| |
| bool handledSpan = xTiler.maybeProcessSpan(yAdjustedSpan, &spanSink); |
| if (handledSpan) { |
| auto firstNotTheSame = std::mismatch( |
| listPoints.begin(), listPoints.end(), spanPoints.begin()); |
| if (firstNotTheSame.first != listSink.fPoints->end()) { |
| auto element = std::distance(listPoints.begin(), firstNotTheSame.first); |
| SkASSERT(element >= 0); |
| std::tie(start, length, count) = originalSpan; |
| ERRORF(reporter, "Span: {%f, %f}, %f, %d", start.fX, start.fY, length, count); |
| ERRORF(reporter, "Size points: %d, size span: %d", |
| listPoints.size(), spanPoints.size()); |
| if ((unsigned)element >= spanPoints.size()) { |
| ERRORF(reporter, "Size points: %d, size span: %d", |
| listPoints.size(), spanPoints.size()); |
| // Mismatch off the end |
| ERRORF(reporter, |
| "The mismatch is at position %d and has value %f, %f - it is off the end " |
| "of the other.", |
| element, X(*firstNotTheSame.first), Y(*firstNotTheSame.first)); |
| } else { |
| ERRORF(reporter, |
| "Mismatch at %d - points: %f, %f - span: %f, %f", |
| element, listPoints[element].fX, listPoints[element].fY, |
| spanPoints[element].fX, spanPoints[element].fY); |
| } |
| SkFAIL("aha"); |
| } |
| } |
| return true; |
| } |
| |
| template <typename XTiler, typename YTiler> |
| static bool compare_tiler_spans(int width, int height, skiatest::Reporter* reporter) { |
| XTiler xTiler{width}; |
| YTiler yTiler{height}; |
| INFOF(reporter, "w: %d, h: %d \n", width, height); |
| std::array<int, 8> interestingX {{-5, -1, 0, 1, width - 1, width, width + 1, width + 5}}; |
| std::array<int, 8> interestingY {{-5, -1, 0, 1, height - 1, height, height + 1, height + 5}}; |
| std::array<int, 6> interestingCount {{1, 2, 3, 4, 5, 10}}; |
| std::array<SkScalar, 7> interestingScale {{0.0f, 1.0f, 0.5f, 2.1f, -2.1f, -1.0f, -0.5f}}; |
| for (auto scale : interestingScale) { |
| for (auto startX : interestingX) { |
| for (auto count : interestingCount) { |
| for (auto y : interestingY) { |
| Span span{ |
| SkPoint::Make((SkScalar)startX, (SkScalar)y), (count-1.0f) * scale, count}; |
| if (!compare_tiler_case(xTiler, yTiler, span, reporter)) { |
| return false; |
| } |
| } |
| } |
| } |
| } |
| return true; |
| } |
| |
| template <typename XTiler, typename YTiler> |
| static void test_tiler(skiatest::Reporter* reporter) { |
| std::array<int, 6> interestingSize {{1, 2, 3, 4, 5, 10}}; |
| for (auto width : interestingSize) { |
| for (auto height : interestingSize) { |
| if (!compare_tiler_spans<XTiler, YTiler>(width, height, reporter)) { return; } |
| } |
| } |
| } |
| /* |
| DEF_TEST(LBPStrategyClampTile, reporter) { |
| #if 0 |
| ClampStrategy tiler{SkSize::Make(1, 1)}; |
| Span span{SkPoint::Make(0, -5), 1.0f, 2}; |
| compare_tiler_case<ClampStrategy>(tiler, span, reporter); |
| #else |
| test_tiler<XClampStrategy, YClampStrategy>(reporter); |
| #endif |
| } |
| |
| DEF_TEST(LBPStrategyRepeatTile, reporter) { |
| #if 0 |
| RepeatStrategy tiler{SkSize::Make(3, 1)}; |
| Span span{SkPoint::Make(-5, -5), 20 * 2.1f, 100}; |
| compare_tiler_case<RepeatStrategy>(tiler, span, reporter); |
| #else |
| test_tiler<XRepeatStrategy, YRepeatStrategy>(reporter); |
| #endif |
| } |
| */ |