/* * 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 SK_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 SK_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 } */