Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Unified Diff: src/core/SkLinearBitmapPipeline_core.h

Issue 1765953002: break out the tile and matrix strategies (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkLinearBitmapPipeline.cpp ('k') | src/core/SkLinearBitmapPipeline_matrix.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkLinearBitmapPipeline_core.h
diff --git a/src/core/SkLinearBitmapPipeline_core.h b/src/core/SkLinearBitmapPipeline_core.h
new file mode 100644
index 0000000000000000000000000000000000000000..9a8ec0e37eb0b7ffd8dd5cf5227e25963a80b724
--- /dev/null
+++ b/src/core/SkLinearBitmapPipeline_core.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkLinearBitmapPipeline_core_DEFINED
+#define SkLinearBitmapPipeline_core_DEFINED
+
+// 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
+#elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON)
+ #define VECTORCALL __attribute__((pcs("aapcs-vfp")))
+#else
+ #define VECTORCALL
+#endif
+
+namespace {
+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) { }
+ operator SkScalar () const {return fVal;}
+private:
+ SkScalar fVal;
+};
+
+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) { }
+ operator SkScalar () const {return fVal;}
+private:
+ SkScalar fVal;
+};
+
+// The Span class enables efficient processing horizontal spans of pixels.
+// * start - the point where to start the span.
+// * length - the number of pixels to traverse in source space.
+// * count - the number of pixels to produce in destination space.
+// Both start and length are mapped through the inversion matrix to produce values in source
+// space. After the matrix operation, the tilers may break the spans up into smaller spans.
+// The tilers can produce spans that seem nonsensical.
+// * The clamp tiler can create spans with length of 0. This indicates to copy an edge pixel out
+// to the edge of the destination scan.
+// * The mirror tiler can produce spans with negative length. This indicates that the source
+// should be traversed in the opposite direction to the destination pixels.
+class Span {
+public:
+ Span(SkPoint start, SkScalar length, int count)
+ : fStart(start)
+ , fLength(length)
+ , fCount{count} {
+ SkASSERT(std::isfinite(length));
+ }
+
+ operator std::tuple<SkPoint&, SkScalar&, int&>() {
+ return std::tie(fStart, fLength, fCount);
+ }
+
+ bool isEmpty() const { return 0 == fCount; }
+ SkScalar length() const { return fLength; }
+ SkScalar startX() const { return X(fStart); }
+ SkScalar endX() const { return startX() + length(); }
+ void clear() {
+ fCount = 0;
+ }
+
+ bool completelyWithin(SkScalar xMin, SkScalar xMax) const {
+ SkScalar sMin, sMax;
+ std::tie(sMin, sMax) = std::minmax(startX(), endX());
+ return xMin <= sMin && sMax <= xMax;
+ }
+
+ void offset(SkScalar offsetX) {
+ fStart.offset(offsetX, 0.0f);
+ }
+
+ Span breakAt(SkScalar breakX, SkScalar dx) {
+ SkASSERT(std::isfinite(breakX));
+ SkASSERT(std::isfinite(dx));
+ SkASSERT(dx != 0.0f);
+
+ if (this->isEmpty()) {
+ return Span{{0.0, 0.0}, 0.0f, 0};
+ }
+
+ int dxSteps = SkScalarFloorToInt((breakX - this->startX()) / dx);
+ if (dxSteps < 0) {
+ // The span is wholly after breakX.
+ return Span{{0.0, 0.0}, 0.0f, 0};
+ } 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.
+ SkPoint newStart = fStart;
+ SkScalar newLength = dxSteps * dx;
+ int newCount = dxSteps + 1;
+ SkASSERT(newCount > 0);
+
+ // Update this span to reflect the break.
+ SkScalar lengthToStart = newLength + dx;
+ fLength -= lengthToStart;
+ fCount -= newCount;
+ fStart = {this->startX() + lengthToStart, Y(fStart)};
+
+ return Span{newStart, newLength, newCount};
+ }
+
+ void clampToSinglePixel(SkPoint pixel) {
+ fStart = pixel;
+ fLength = 0.0f;
+ }
+
+private:
+ SkPoint fStart;
+ SkScalar fLength;
+ int fCount;
+};
+
+// BilerpSpans are similar to Spans, but they represent four source samples converting to single
+// destination pixel per count. The pixels for the four samples are collect along two horizontal
+// lines; one starting at {x, y0} and the other starting at {x, y1}. There are two distinct lines
+// to deal with the edge case of the tile mode. For example, y0 may be at the last y position in
+// a tile while y1 would be at the first.
+// The step of a Bilerp (dx) is still length / (count - 1) and the start to the next sample is
+// still dx * count, but the bounds are complicated by the sampling kernel so that the pixels
+// touched are from x to x + length + 1.
+class BilerpSpan {
+public:
+ BilerpSpan(SkScalar x, SkScalar y0, SkScalar y1, SkScalar length, int count)
+ : fX{x}, fY0{y0}, fY1{y1}, fLength{length}, fCount{count} {
+ SkASSERT(count >= 0);
+ SkASSERT(std::isfinite(length));
+ SkASSERT(std::isfinite(x));
+ SkASSERT(std::isfinite(y0));
+ SkASSERT(std::isfinite(y1));
+ }
+
+ operator std::tuple<SkScalar&, SkScalar&, SkScalar&, SkScalar&, int&>() {
+ return std::tie(fX, fY0, fY1, fLength, fCount);
+ }
+
+ bool isEmpty() const { return 0 == fCount; }
+
+private:
+ SkScalar fX;
+ SkScalar fY0;
+ SkScalar fY1;
+ SkScalar fLength;
+ int fCount;
+};
+
+template<typename Stage>
+void span_fallback(Span span, Stage* stage) {
+ SkPoint start;
+ SkScalar length;
+ int count;
+ std::tie(start, length, count) = span;
+ Sk4f xs{X(start)};
+ Sk4f ys{Y(start)};
+
+ // Initializing this is not needed, but some compilers can't figure this out.
+ Sk4s fourDx{0.0f};
+ if (count > 1) {
+ SkScalar dx = length / (count - 1);
+ xs = xs + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * dx;
+ // Only used if count is >= 4.
+ fourDx = Sk4f{4.0f * dx};
+ }
+
+ while (count >= 4) {
+ stage->pointList4(xs, ys);
+ xs = xs + fourDx;
+ count -= 4;
+ }
+ if (count > 0) {
+ stage->pointListFew(count, xs, ys);
+ }
+}
+
+template <typename Next>
+void bilerp_span_fallback(BilerpSpan span, Next* next) {
+ SkScalar x, y0, y1; SkScalar length; int count;
+ std::tie(x, y0, y1, length, count) = span;
+
+ SkASSERT(!span.isEmpty());
+ float dx = length / (count - 1);
+
+ Sk4f xs = Sk4f{x} + Sk4f{0.0f, 1.0f, 0.0f, 1.0f};
+ Sk4f ys = Sk4f{y0, y0, y1, y1};
+
+ // If count == 1 then dx will be inf or NaN, but that is ok because the resulting addition is
+ // never used.
+ while (count > 0) {
+ next->bilerpList(xs, ys);
+ xs = xs + dx;
+ count -= 1;
+ }
+}
+} // namespace
+
+#endif // SkLinearBitmapPipeline_core_DEFINED
« no previous file with comments | « src/core/SkLinearBitmapPipeline.cpp ('k') | src/core/SkLinearBitmapPipeline_matrix.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698