LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkLinearBitmapPipeline_core.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 86 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 53 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #ifndef SkLinearBitmapPipeline_core_DEFINED
       9             : #define SkLinearBitmapPipeline_core_DEFINED
      10             : 
      11             : #include <algorithm>
      12             : #include <cmath>
      13             : #include "SkNx.h"
      14             : 
      15             : // New bilerp strategy:
      16             : // Pass through on bilerpList4 and bilerpListFew (analogs to pointList), introduce bilerpEdge
      17             : // which takes 4 points. If the sample spans an edge, then break it into a bilerpEdge. Bilerp
      18             : // span then becomes a normal span except in special cases where an extra Y is given. The bilerp
      19             : // need to stay single point calculations until the tile layer.
      20             : // TODO:
      21             : //  - edge span predicate.
      22             : //  - introduce new point API
      23             : //  - Add tile for new api.
      24             : 
      25             : namespace {
      26             : struct X {
      27             :     explicit X(SkScalar val) : fVal{val} { }
      28           0 :     explicit X(SkPoint pt)   : fVal{pt.fX} { }
      29             :     explicit X(SkSize s)     : fVal{s.fWidth} { }
      30             :     explicit X(SkISize s)    : fVal((SkScalar)s.fWidth) { }
      31           0 :     operator SkScalar () const {return fVal;}
      32             : private:
      33             :     SkScalar fVal;
      34             : };
      35             : 
      36             : struct Y {
      37             :     explicit Y(SkScalar val) : fVal{val} { }
      38           0 :     explicit Y(SkPoint pt)   : fVal{pt.fY} { }
      39             :     explicit Y(SkSize s)     : fVal{s.fHeight} { }
      40             :     explicit Y(SkISize s)    : fVal((SkScalar)s.fHeight) { }
      41           0 :     operator SkScalar () const {return fVal;}
      42             : private:
      43             :     SkScalar fVal;
      44             : };
      45             : 
      46             : // The Span class enables efficient processing horizontal spans of pixels.
      47             : // * start - the point where to start the span.
      48             : // * length - the number of pixels to traverse in source space.
      49             : // * count - the number of pixels to produce in destination space.
      50             : // Both start and length are mapped through the inversion matrix to produce values in source
      51             : // space. After the matrix operation, the tilers may break the spans up into smaller spans.
      52             : // The tilers can produce spans that seem nonsensical.
      53             : // * The clamp tiler can create spans with length of 0. This indicates to copy an edge pixel out
      54             : //   to the edge of the destination scan.
      55             : // * The mirror tiler can produce spans with negative length. This indicates that the source
      56             : //   should be traversed in the opposite direction to the destination pixels.
      57             : class Span {
      58             : public:
      59           0 :     Span(SkPoint start, SkScalar length, int count)
      60           0 :         : fStart(start)
      61             :         , fLength(length)
      62           0 :         , fCount{count} {
      63           0 :         SkASSERT(std::isfinite(length));
      64           0 :     }
      65             : 
      66           0 :     operator std::tuple<SkPoint&, SkScalar&, int&>() {
      67           0 :         return std::tie(fStart, fLength, fCount);
      68             :     }
      69             : 
      70           0 :     bool isEmpty() const { return 0 == fCount; }
      71           0 :     void clear() { fCount = 0; }
      72           0 :     int count() const { return fCount; }
      73           0 :     SkScalar length() const { return fLength; }
      74           0 :     SkScalar startX() const { return X(fStart); }
      75           0 :     SkScalar endX() const { return this->startX() + this->length(); }
      76           0 :     SkScalar startY() const { return Y(fStart); }
      77           0 :     Span emptySpan() { return Span{{0.0, 0.0}, 0.0f, 0}; }
      78             : 
      79           0 :     bool completelyWithin(SkScalar xMin, SkScalar xMax) const {
      80             :         SkScalar sMin, sMax;
      81           0 :         std::tie(sMin, sMax) = std::minmax(startX(), endX());
      82           0 :         return xMin <= sMin && sMax < xMax;
      83             :     }
      84             : 
      85           0 :     void offset(SkScalar offsetX) {
      86           0 :         fStart.offset(offsetX, 0.0f);
      87           0 :     }
      88             : 
      89           0 :     Span breakAt(SkScalar breakX, SkScalar dx) {
      90           0 :         SkASSERT(std::isfinite(breakX));
      91           0 :         SkASSERT(std::isfinite(dx));
      92           0 :         SkASSERT(dx != 0.0f);
      93             : 
      94           0 :         if (this->isEmpty()) {
      95           0 :             return this->emptySpan();
      96             :         }
      97             : 
      98           0 :         int dxSteps = SkScalarFloorToInt((breakX - this->startX()) / dx);
      99             : 
     100           0 :         if (dxSteps < 0) {
     101             :             // The span is wholly after breakX.
     102           0 :             return this->emptySpan();
     103           0 :         } else if (dxSteps >= fCount) {
     104             :             // The span is wholly before breakX.
     105           0 :             Span answer = *this;
     106           0 :             this->clear();
     107           0 :             return answer;
     108             :         }
     109             : 
     110             :         // Calculate the values for the span to cleave off.
     111           0 :         SkScalar newLength = dxSteps * dx;
     112             : 
     113             :         // If the last (or first if count = 1) sample lands directly on the boundary. Include it
     114             :         // when dx < 0 and exclude it when dx > 0.
     115             :         // Reasoning:
     116             :         //  dx > 0: The sample point on the boundary is part of the next span because the entire
     117             :         // pixel is after the boundary.
     118             :         //  dx < 0: The sample point on the boundary is part of the current span because the
     119             :         // entire pixel is before the boundary.
     120           0 :         if (this->startX() + newLength == breakX && dx > 0) {
     121           0 :             if (dxSteps > 0) {
     122           0 :                 dxSteps -= 1;
     123           0 :                 newLength -= dx;
     124             :             } else {
     125           0 :                 return this->emptySpan();
     126             :             }
     127             :         }
     128             : 
     129             :         // Calculate new span parameters
     130           0 :         SkPoint newStart = fStart;
     131           0 :         int newCount = dxSteps + 1;
     132           0 :         SkASSERT(newCount > 0);
     133             : 
     134             :         // Update this span to reflect the break.
     135           0 :         SkScalar lengthToStart = newLength + dx;
     136           0 :         fLength -= lengthToStart;
     137           0 :         fCount -= newCount;
     138           0 :         fStart = {this->startX() + lengthToStart, Y(fStart)};
     139             : 
     140           0 :         return Span{newStart, newLength, newCount};
     141             :     }
     142             : 
     143           0 :     void clampToSinglePixel(SkPoint pixel) {
     144           0 :         fStart = pixel;
     145           0 :         fLength = 0.0f;
     146           0 :     }
     147             : 
     148             : private:
     149             :     SkPoint  fStart;
     150             :     SkScalar fLength;
     151             :     int      fCount;
     152             : };
     153             : 
     154             : template<typename Stage>
     155           0 : void span_fallback(Span span, Stage* stage) {
     156             :     SkPoint start;
     157             :     SkScalar length;
     158             :     int count;
     159           0 :     std::tie(start, length, count) = span;
     160           0 :     Sk4f startXs{X(start)};
     161           0 :     Sk4f ys{Y(start)};
     162             :     Sk4f mults = {0.0f, 1.0f, 2.0f, 3.0f};
     163             : 
     164             :     // Initializing this is not needed, but some compilers can't figure this out.
     165             :     Sk4s dXs{0.0f};
     166           0 :     if (count > 1) {
     167           0 :         SkScalar dx = length / (count - 1);
     168           0 :         dXs = Sk4f{dx};
     169             :     }
     170             : 
     171             :     // Instead of using xs = xs + dx every round, this uses xs = i * dx + X(start). This
     172             :     // eliminates the rounding error for the sum.
     173           0 :     Sk4f xs = startXs + mults * dXs;
     174           0 :     while (count >= 4) {
     175           0 :         stage->pointList4(xs, ys);
     176             : 
     177           0 :         mults += Sk4f{4.0f};
     178           0 :         xs = mults * dXs + startXs;
     179           0 :         count -= 4;
     180             :     }
     181             : 
     182           0 :     if (count > 0) {
     183           0 :         stage->pointListFew(count, xs, ys);
     184             :     }
     185           0 : }
     186             : 
     187           0 : inline Sk4f SK_VECTORCALL check_pixel(const Sk4f& pixel) {
     188           0 :     SkASSERTF(0.0f <= pixel[0] && pixel[0] <= 1.0f, "pixel[0]: %f", pixel[0]);
     189           0 :     SkASSERTF(0.0f <= pixel[1] && pixel[1] <= 1.0f, "pixel[1]: %f", pixel[1]);
     190           0 :     SkASSERTF(0.0f <= pixel[2] && pixel[2] <= 1.0f, "pixel[2]: %f", pixel[2]);
     191           0 :     SkASSERTF(0.0f <= pixel[3] && pixel[3] <= 1.0f, "pixel[3]: %f", pixel[3]);
     192           0 :     return pixel;
     193             : }
     194             : 
     195             : }  // namespace
     196             : 
     197           0 : class SkLinearBitmapPipeline::PointProcessorInterface {
     198             : public:
     199           0 :     virtual ~PointProcessorInterface() { }
     200             :     // Take the first n (where 0 < n && n < 4) items from xs and ys and sample those points. For
     201             :     // nearest neighbor, that means just taking the floor xs and ys. For bilerp, this means
     202             :     // to expand the bilerp filter around the point and sample using that filter.
     203             :     virtual void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0;
     204             :     // Same as pointListFew, but n = 4.
     205             :     virtual void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0;
     206             :     // A span is a compact form of sample points that are obtained by mapping points from
     207             :     // destination space to source space. This is used for horizontal lines only, and is mainly
     208             :     // used to take advantage of memory coherence for horizontal spans.
     209             :     virtual void pointSpan(Span span) = 0;
     210             : };
     211             : 
     212           0 : class SkLinearBitmapPipeline::SampleProcessorInterface
     213             :     : public SkLinearBitmapPipeline::PointProcessorInterface {
     214             : public:
     215             :     // Used for nearest neighbor when scale factor is 1.0. The span can just be repeated with no
     216             :     // edge pixel alignment problems. This is for handling a very common case.
     217             :     virtual void repeatSpan(Span span, int32_t repeatCount) = 0;
     218             : };
     219             : 
     220           0 : class SkLinearBitmapPipeline::DestinationInterface {
     221             : public:
     222           0 :     virtual ~DestinationInterface() { }
     223             :     // Count is normally not needed, but in these early stages of development it is useful to
     224             :     // check bounds.
     225             :     // TODO(herb): 4/6/2016 - remove count when code is stable.
     226             :     virtual void setDestination(void* dst, int count) = 0;
     227             : };
     228             : 
     229           0 : class SkLinearBitmapPipeline::BlendProcessorInterface
     230             :     : public SkLinearBitmapPipeline::DestinationInterface {
     231             : public:
     232             :     virtual void SK_VECTORCALL blendPixel(Sk4f pixel0) = 0;
     233             :     virtual void SK_VECTORCALL blend4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0;
     234             : };
     235             : 
     236           0 : class SkLinearBitmapPipeline::PixelAccessorInterface {
     237             : public:
     238           0 :     virtual ~PixelAccessorInterface() { }
     239             :     virtual void SK_VECTORCALL getFewPixels(
     240             :         int n, Sk4i xs, Sk4i ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) const = 0;
     241             : 
     242             :     virtual void SK_VECTORCALL get4Pixels(
     243             :         Sk4i xs, Sk4i ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const = 0;
     244             : 
     245             :     virtual void get4Pixels(
     246             :         const void* src, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const = 0;
     247             : 
     248             :     virtual Sk4f getPixelFromRow(const void* row, int index) const = 0;
     249             : 
     250             :     virtual Sk4f getPixelAt(int index) const = 0;
     251             : 
     252             :     virtual const void* row(int y) const = 0;
     253             : };
     254             : 
     255             : #endif // SkLinearBitmapPipeline_core_DEFINED

Generated by: LCOV version 1.13