OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef SkLinearBitmapPipeline_core_DEFINED | 8 #ifndef SkLinearBitmapPipeline_core_DEFINED |
9 #define SkLinearBitmapPipeline_core_DEFINED | 9 #define SkLinearBitmapPipeline_core_DEFINED |
10 | 10 |
11 #include <cmath> | 11 #include <cmath> |
12 | 12 |
| 13 // New bilerp strategy: |
| 14 // Pass through on bilerpList4 and bilerpListFew (analogs to pointList), introdu
ce bilerpEdge |
| 15 // which takes 4 points. If the sample spans an edge, then break it into a biler
pEdge. Bilerp |
| 16 // span then becomes a normal span except in special cases where an extra Y is g
iven. The bilerp |
| 17 // need to stay single point calculations until the tile layer. |
| 18 // TODO: |
| 19 // - edge span predicate. |
| 20 // - introduce new point API |
| 21 // - Add tile for new api. |
| 22 |
13 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. | 23 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. |
14 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 | 24 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
15 #define VECTORCALL __vectorcall | 25 #define VECTORCALL __vectorcall |
16 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) | 26 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) |
17 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) | 27 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) |
18 #else | 28 #else |
19 #define VECTORCALL | 29 #define VECTORCALL |
20 #endif | 30 #endif |
21 | 31 |
22 namespace { | 32 namespace { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 , fLength(length) | 68 , fLength(length) |
59 , fCount{count} { | 69 , fCount{count} { |
60 SkASSERT(std::isfinite(length)); | 70 SkASSERT(std::isfinite(length)); |
61 } | 71 } |
62 | 72 |
63 operator std::tuple<SkPoint&, SkScalar&, int&>() { | 73 operator std::tuple<SkPoint&, SkScalar&, int&>() { |
64 return std::tie(fStart, fLength, fCount); | 74 return std::tie(fStart, fLength, fCount); |
65 } | 75 } |
66 | 76 |
67 bool isEmpty() const { return 0 == fCount; } | 77 bool isEmpty() const { return 0 == fCount; } |
| 78 void clear() { fCount = 0; } |
| 79 int count() const { return fCount; } |
68 SkScalar length() const { return fLength; } | 80 SkScalar length() const { return fLength; } |
69 SkScalar startX() const { return X(fStart); } | 81 SkScalar startX() const { return X(fStart); } |
70 SkScalar endX() const { return startX() + length(); } | 82 SkScalar endX() const { return this->startX() + this->length(); } |
71 void clear() { | 83 SkScalar startY() const { return Y(fStart); } |
72 fCount = 0; | 84 Span emptySpan() { return Span{{0.0, 0.0}, 0.0f, 0}; } |
73 } | |
74 | 85 |
75 bool completelyWithin(SkScalar xMin, SkScalar xMax) const { | 86 bool completelyWithin(SkScalar xMin, SkScalar xMax) const { |
76 SkScalar sMin, sMax; | 87 SkScalar sMin, sMax; |
77 std::tie(sMin, sMax) = std::minmax(startX(), endX()); | 88 std::tie(sMin, sMax) = std::minmax(startX(), endX()); |
78 return xMin <= sMin && sMax < xMax; | 89 return xMin <= sMin && sMax < xMax; |
79 } | 90 } |
80 | 91 |
81 void offset(SkScalar offsetX) { | 92 void offset(SkScalar offsetX) { |
82 fStart.offset(offsetX, 0.0f); | 93 fStart.offset(offsetX, 0.0f); |
83 } | 94 } |
84 | 95 |
85 Span breakAt(SkScalar breakX, SkScalar dx) { | 96 Span breakAt(SkScalar breakX, SkScalar dx) { |
86 SkASSERT(std::isfinite(breakX)); | 97 SkASSERT(std::isfinite(breakX)); |
87 SkASSERT(std::isfinite(dx)); | 98 SkASSERT(std::isfinite(dx)); |
88 SkASSERT(dx != 0.0f); | 99 SkASSERT(dx != 0.0f); |
89 | 100 |
90 if (this->isEmpty()) { | 101 if (this->isEmpty()) { |
91 return Span{{0.0, 0.0}, 0.0f, 0}; | 102 return this->emptySpan(); |
92 } | 103 } |
93 | 104 |
94 int dxSteps = SkScalarFloorToInt((breakX - this->startX()) / dx); | 105 int dxSteps = SkScalarFloorToInt((breakX - this->startX()) / dx); |
95 | 106 |
96 // Calculate the values for the span to cleave off. | |
97 SkScalar newLength = dxSteps * dx; | |
98 | |
99 if (dxSteps < 0) { | 107 if (dxSteps < 0) { |
100 // The span is wholly after breakX. | 108 // The span is wholly after breakX. |
101 return Span{{0.0, 0.0}, 0.0f, 0}; | 109 return this->emptySpan(); |
102 } else if (dxSteps >= fCount) { | 110 } else if (dxSteps >= fCount) { |
103 // The span is wholly before breakX. | 111 // The span is wholly before breakX. |
104 Span answer = *this; | 112 Span answer = *this; |
105 this->clear(); | 113 this->clear(); |
106 return answer; | 114 return answer; |
107 } | 115 } |
108 | 116 |
| 117 // Calculate the values for the span to cleave off. |
| 118 SkScalar newLength = dxSteps * dx; |
| 119 |
109 // If the last (or first if count = 1) sample lands directly on the boun
dary. Include it | 120 // If the last (or first if count = 1) sample lands directly on the boun
dary. Include it |
110 // when dx < 0 and exclude it when dx > 0. | 121 // when dx < 0 and exclude it when dx > 0. |
111 // Reasoning: | 122 // Reasoning: |
112 // dx > 0: The sample point on the boundary is part of the next span be
cause the entire | 123 // dx > 0: The sample point on the boundary is part of the next span be
cause the entire |
113 // pixel is after the boundary. | 124 // pixel is after the boundary. |
114 // dx < 0: The sample point on the boundary is part of the current span
because the | 125 // dx < 0: The sample point on the boundary is part of the current span
because the |
115 // entire pixel is before the boundary. | 126 // entire pixel is before the boundary. |
116 if (startX() + newLength == breakX && dx > 0) { | 127 if (this->startX() + newLength == breakX && dx > 0) { |
117 if (dxSteps != 0) { | 128 if (dxSteps > 0) { |
118 dxSteps -= 1; | 129 dxSteps -= 1; |
119 newLength -= dx; | 130 newLength -= dx; |
120 } else { | 131 } else { |
121 return Span{{0.0, 0.0}, 0.0f, 0}; | 132 return this->emptySpan(); |
122 } | 133 } |
123 } | 134 } |
124 | 135 |
| 136 // Calculate new span parameters |
125 SkPoint newStart = fStart; | 137 SkPoint newStart = fStart; |
126 int newCount = dxSteps + 1; | 138 int newCount = dxSteps + 1; |
127 SkASSERT(newCount > 0); | 139 SkASSERT(newCount > 0); |
128 | 140 |
129 // Update this span to reflect the break. | 141 // Update this span to reflect the break. |
130 SkScalar lengthToStart = newLength + dx; | 142 SkScalar lengthToStart = newLength + dx; |
131 fLength -= lengthToStart; | 143 fLength -= lengthToStart; |
132 fCount -= newCount; | 144 fCount -= newCount; |
133 fStart = {this->startX() + lengthToStart, Y(fStart)}; | 145 fStart = {this->startX() + lengthToStart, Y(fStart)}; |
134 | 146 |
135 return Span{newStart, newLength, newCount}; | 147 return Span{newStart, newLength, newCount}; |
136 } | 148 } |
137 | 149 |
138 void clampToSinglePixel(SkPoint pixel) { | 150 void clampToSinglePixel(SkPoint pixel) { |
139 fStart = pixel; | 151 fStart = pixel; |
140 fLength = 0.0f; | 152 fLength = 0.0f; |
141 } | 153 } |
142 | 154 |
143 private: | 155 private: |
144 SkPoint fStart; | 156 SkPoint fStart; |
145 SkScalar fLength; | 157 SkScalar fLength; |
146 int fCount; | 158 int fCount; |
147 }; | 159 }; |
148 | 160 |
149 // BilerpSpans are similar to Spans, but they represent four source samples conv
erting to single | |
150 // destination pixel per count. The pixels for the four samples are collect alon
g two horizontal | |
151 // lines; one starting at {x, y0} and the other starting at {x, y1}. There are t
wo distinct lines | |
152 // to deal with the edge case of the tile mode. For example, y0 may be at the la
st y position in | |
153 // a tile while y1 would be at the first. | |
154 // The step of a Bilerp (dx) is still length / (count - 1) and the start to the
next sample is | |
155 // still dx * count, but the bounds are complicated by the sampling kernel so th
at the pixels | |
156 // touched are from x to x + length + 1. | |
157 class BilerpSpan { | |
158 public: | |
159 BilerpSpan(SkScalar x, SkScalar y0, SkScalar y1, SkScalar length, int count) | |
160 : fX{x}, fY0{y0}, fY1{y1}, fLength{length}, fCount{count} { | |
161 SkASSERT(count >= 0); | |
162 SkASSERT(std::isfinite(length)); | |
163 SkASSERT(std::isfinite(x)); | |
164 SkASSERT(std::isfinite(y0)); | |
165 SkASSERT(std::isfinite(y1)); | |
166 } | |
167 | |
168 operator std::tuple<SkScalar&, SkScalar&, SkScalar&, SkScalar&, int&>() { | |
169 return std::tie(fX, fY0, fY1, fLength, fCount); | |
170 } | |
171 | |
172 bool isEmpty() const { return 0 == fCount; } | |
173 | |
174 private: | |
175 SkScalar fX; | |
176 SkScalar fY0; | |
177 SkScalar fY1; | |
178 SkScalar fLength; | |
179 int fCount; | |
180 }; | |
181 | |
182 template<typename Stage> | 161 template<typename Stage> |
183 void span_fallback(Span span, Stage* stage) { | 162 void span_fallback(Span span, Stage* stage) { |
184 SkPoint start; | 163 SkPoint start; |
185 SkScalar length; | 164 SkScalar length; |
186 int count; | 165 int count; |
187 std::tie(start, length, count) = span; | 166 std::tie(start, length, count) = span; |
188 Sk4f xs{X(start)}; | 167 Sk4f xs{X(start)}; |
189 Sk4f ys{Y(start)}; | 168 Sk4f ys{Y(start)}; |
190 | 169 |
191 // Initializing this is not needed, but some compilers can't figure this out
. | 170 // Initializing this is not needed, but some compilers can't figure this out
. |
192 Sk4s fourDx{0.0f}; | 171 Sk4s fourDx{0.0f}; |
193 if (count > 1) { | 172 if (count > 1) { |
194 SkScalar dx = length / (count - 1); | 173 SkScalar dx = length / (count - 1); |
195 xs = xs + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * dx; | 174 xs = xs + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * dx; |
196 // Only used if count is >= 4. | 175 // Only used if count is >= 4. |
197 fourDx = Sk4f{4.0f * dx}; | 176 fourDx = Sk4f{4.0f * dx}; |
198 } | 177 } |
199 | 178 |
200 while (count >= 4) { | 179 while (count >= 4) { |
201 stage->pointList4(xs, ys); | 180 stage->pointList4(xs, ys); |
202 xs = xs + fourDx; | 181 xs = xs + fourDx; |
203 count -= 4; | 182 count -= 4; |
204 } | 183 } |
205 if (count > 0) { | 184 if (count > 0) { |
206 stage->pointListFew(count, xs, ys); | 185 stage->pointListFew(count, xs, ys); |
207 } | 186 } |
208 } | 187 } |
209 | |
210 template <typename Next> | |
211 void bilerp_span_fallback(BilerpSpan span, Next* next) { | |
212 SkScalar x, y0, y1; SkScalar length; int count; | |
213 std::tie(x, y0, y1, length, count) = span; | |
214 | |
215 SkASSERT(!span.isEmpty()); | |
216 float dx = length / (count - 1); | |
217 | |
218 Sk4f xs = Sk4f{x} + Sk4f{0.0f, 1.0f, 0.0f, 1.0f}; | |
219 Sk4f ys = Sk4f{y0, y0, y1, y1}; | |
220 | |
221 // If count == 1 then dx will be inf or NaN, but that is ok because the resu
lting addition is | |
222 // never used. | |
223 while (count > 0) { | |
224 next->bilerpList(xs, ys); | |
225 xs = xs + dx; | |
226 count -= 1; | |
227 } | |
228 } | |
229 } // namespace | 188 } // namespace |
230 | 189 |
231 #endif // SkLinearBitmapPipeline_core_DEFINED | 190 #endif // SkLinearBitmapPipeline_core_DEFINED |
OLD | NEW |