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

Side by Side Diff: src/core/SkLinearBitmapPipeline_core.h

Issue 1775963002: Bilerp + mirror + perspective (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address comments. Created 4 years, 9 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 unified diff | Download patch
« no previous file with comments | « src/core/SkLinearBitmapPipeline.cpp ('k') | src/core/SkLinearBitmapPipeline_matrix.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
OLDNEW
« 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