Rework files and add test cases.
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1757193002 Review URL: https://codereview.chromium.org/1757193002
This commit is contained in:
parent
1590f3b328
commit
c60fee0f15
@ -54,7 +54,6 @@ public:
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
// PointProcessor uses a strategy to help complete the work of the different stages. The strategy
|
||||
// must implement the following methods:
|
||||
// * processPoints(xs, ys) - must mutate the xs and ys for the stage.
|
||||
|
@ -8,6 +8,8 @@
|
||||
#ifndef SkLinearBitmapPipeline_core_DEFINED
|
||||
#define SkLinearBitmapPipeline_core_DEFINED
|
||||
|
||||
#include <cmath>
|
||||
|
||||
// Tweak ABI of functions that pass Sk4f by value to pass them via registers.
|
||||
#if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
|
||||
#define VECTORCALL __vectorcall
|
||||
@ -22,7 +24,7 @@ struct X {
|
||||
explicit X(SkScalar val) : fVal{val} { }
|
||||
explicit X(SkPoint pt) : fVal{pt.fX} { }
|
||||
explicit X(SkSize s) : fVal{s.fWidth} { }
|
||||
explicit X(SkISize s) : fVal(s.fWidth) { }
|
||||
explicit X(SkISize s) : fVal((SkScalar)s.fWidth) { }
|
||||
operator SkScalar () const {return fVal;}
|
||||
private:
|
||||
SkScalar fVal;
|
||||
@ -32,7 +34,7 @@ struct Y {
|
||||
explicit Y(SkScalar val) : fVal{val} { }
|
||||
explicit Y(SkPoint pt) : fVal{pt.fY} { }
|
||||
explicit Y(SkSize s) : fVal{s.fHeight} { }
|
||||
explicit Y(SkISize s) : fVal(s.fHeight) { }
|
||||
explicit Y(SkISize s) : fVal((SkScalar)s.fHeight) { }
|
||||
operator SkScalar () const {return fVal;}
|
||||
private:
|
||||
SkScalar fVal;
|
||||
@ -73,7 +75,7 @@ public:
|
||||
bool completelyWithin(SkScalar xMin, SkScalar xMax) const {
|
||||
SkScalar sMin, sMax;
|
||||
std::tie(sMin, sMax) = std::minmax(startX(), endX());
|
||||
return xMin <= sMin && sMax <= xMax;
|
||||
return xMin <= sMin && sMax < xMax;
|
||||
}
|
||||
|
||||
void offset(SkScalar offsetX) {
|
||||
@ -90,19 +92,37 @@ public:
|
||||
}
|
||||
|
||||
int dxSteps = SkScalarFloorToInt((breakX - this->startX()) / dx);
|
||||
|
||||
// Calculate the values for the span to cleave off.
|
||||
SkScalar newLength = dxSteps * dx;
|
||||
|
||||
if (dxSteps < 0) {
|
||||
// The span is wholly after breakX.
|
||||
return Span{{0.0, 0.0}, 0.0f, 0};
|
||||
} else if (dxSteps > fCount) {
|
||||
} else if (dxSteps >= fCount) {
|
||||
// The span is wholly before breakX.
|
||||
Span answer = *this;
|
||||
this->clear();
|
||||
return answer;
|
||||
}
|
||||
|
||||
// Calculate the values for the span to cleave off.
|
||||
// If the last (or first if count = 1) sample lands directly on the boundary. Include it
|
||||
// when dx < 0 and exclude it when dx > 0.
|
||||
// Reasoning:
|
||||
// dx > 0: The sample point on the boundary is part of the next span because the entire
|
||||
// pixel is after the boundary.
|
||||
// dx < 0: The sample point on the boundary is part of the current span because the
|
||||
// entire pixel is before the boundary.
|
||||
if (startX() + newLength == breakX && dx > 0) {
|
||||
if (dxSteps != 0) {
|
||||
dxSteps -= 1;
|
||||
newLength -= dx;
|
||||
} else {
|
||||
return Span{{0.0, 0.0}, 0.0f, 0};
|
||||
}
|
||||
}
|
||||
|
||||
SkPoint newStart = fStart;
|
||||
SkScalar newLength = dxSteps * dx;
|
||||
int newCount = dxSteps + 1;
|
||||
SkASSERT(newCount > 0);
|
||||
|
||||
|
@ -100,6 +100,7 @@ public:
|
||||
}
|
||||
} else {
|
||||
Span rightClamped = span.breakAt(xMax, dx);
|
||||
|
||||
if (!rightClamped.isEmpty()) {
|
||||
rightClamped.clampToSinglePixel({xMax - 1, y});
|
||||
next->pointSpan(rightClamped);
|
||||
@ -198,7 +199,7 @@ public:
|
||||
|
||||
Span span({x, y}, length, count);
|
||||
if (dx > 0) {
|
||||
while (!span.isEmpty() && span.endX() > xMax) {
|
||||
while (!span.isEmpty() && span.endX() >= xMax) {
|
||||
Span toDraw = span.breakAt(xMax, dx);
|
||||
next->pointSpan(toDraw);
|
||||
span.offset(-xMax);
|
||||
|
@ -5,54 +5,237 @@
|
||||
* 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"
|
||||
|
||||
using Pixel = float[4];
|
||||
DEF_TEST(SkBitmapFP, reporter) {
|
||||
|
||||
int width = 10;
|
||||
int height = 10;
|
||||
uint32_t* bitmap = new uint32_t[width * height];
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
bitmap[y * width + x] = (y << 8) + x + (128<<24);
|
||||
}
|
||||
}
|
||||
|
||||
SkPM4f* FPbuffer = new SkPM4f[width * height];
|
||||
|
||||
SkMatrix m = SkMatrix::I();
|
||||
//m.setRotate(30.0f, 1.0f, 1.0f);
|
||||
SkMatrix invert;
|
||||
bool trash = m.invert(&invert);
|
||||
sk_ignore_unused_variable(trash);
|
||||
|
||||
const SkImageInfo info =
|
||||
SkImageInfo::MakeN32Premul(width, height, kLinear_SkColorProfileType);
|
||||
|
||||
SkPixmap srcPixmap{info, bitmap, static_cast<size_t>(4 * width)};
|
||||
|
||||
SkLinearBitmapPipeline pipeline{invert, kNone_SkFilterQuality, SkShader::kClamp_TileMode,
|
||||
SkShader::kClamp_TileMode, srcPixmap};
|
||||
|
||||
int count = 10;
|
||||
|
||||
pipeline.shadeSpan4f(3, 6, FPbuffer, count);
|
||||
#if 0
|
||||
Pixel* pixelBuffer = (Pixel*)FPbuffer;
|
||||
for (int i = 0; i < count; i++) {
|
||||
printf("i: %d - (%g, %g, %g, %g)\n", i,
|
||||
pixelBuffer[i][0] * 255.0f,
|
||||
pixelBuffer[i][1] * 255.0f,
|
||||
pixelBuffer[i][2] * 255.0f,
|
||||
pixelBuffer[i][3] * 255.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
delete [] bitmap;
|
||||
delete [] FPbuffer;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tiler>
|
||||
static bool compare_tiler_case(Tiler& tiler, 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;
|
||||
tiler.processPoints(&txs, &tys);
|
||||
listSink.pointList4(txs, tys);
|
||||
xs = xs + 4.0f * dx;
|
||||
count -= 4;
|
||||
}
|
||||
if (count > 0) {
|
||||
tiler.processPoints(&xs, &ys);
|
||||
listSink.pointListFew(count, xs, ys);
|
||||
}
|
||||
|
||||
bool handledSpan = tiler.maybeProcessSpan(span, &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 Tiler>
|
||||
static bool compare_tiler_spans(int width, int height, skiatest::Reporter* reporter) {
|
||||
Tiler tiler{SkSize::Make((SkScalar)width, (SkScalar)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(tiler, span, reporter)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Tiler>
|
||||
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<Tiler>(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<ClampStrategy>(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<RepeatStrategy>(reporter);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user