OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 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 #include "math.h" |
| 9 |
8 #include "Sk4fLinearGradient.h" | 10 #include "Sk4fLinearGradient.h" |
9 #include "SkLinearGradient.h" | 11 #include "SkLinearGradient.h" |
10 | 12 |
11 // define to test the 4f gradient path | 13 // define to test the 4f gradient path |
12 // #define FORCE_4F_CONTEXT | 14 // #define FORCE_4F_CONTEXT |
13 | 15 |
14 static const float kInv255Float = 1.0f / 255; | 16 static const float kInv255Float = 1.0f / 255; |
15 | 17 |
16 static inline int repeat_8bits(int x) { | 18 static inline int repeat_8bits(float x) { |
17 return x & 0xFF; | 19 float ignore; |
| 20 const float frac = modff(x, &ignore); |
| 21 return (int)(frac * 256) & 0xFF; |
18 } | 22 } |
19 | 23 |
20 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly. | 24 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly. |
21 // See http://code.google.com/p/skia/issues/detail?id=472 | 25 // See http://code.google.com/p/skia/issues/detail?id=472 |
22 #if defined(_MSC_VER) && (_MSC_VER >= 1600) | 26 #if defined(_MSC_VER) && (_MSC_VER >= 1600) |
23 #pragma optimize("", off) | 27 #pragma optimize("", off) |
24 #endif | 28 #endif |
25 | 29 |
26 static inline int mirror_8bits(int x) { | 30 static inline int mirror_8bits(float x) { |
27 if (x & 256) { | 31 const float x_mod_2 = fmod(x, 2.0f); |
28 x = ~x; | 32 int x_9bits = (int)(x_mod_2 * 256); |
| 33 if (x_9bits & 0x100) { |
| 34 x_9bits = ~x_9bits; |
29 } | 35 } |
30 return x & 255; | 36 return x_9bits & 0xFF; |
31 } | 37 } |
32 | 38 |
33 #if defined(_MSC_VER) && (_MSC_VER >= 1600) | 39 #if defined(_MSC_VER) && (_MSC_VER >= 1600) |
34 #pragma optimize("", on) | 40 #pragma optimize("", on) |
35 #endif | 41 #endif |
36 | 42 |
37 static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) { | 43 static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) { |
38 SkVector vec = pts[1] - pts[0]; | 44 SkVector vec = pts[1] - pts[0]; |
39 SkScalar mag = vec.length(); | 45 SkScalar mag = vec.length(); |
40 SkScalar inv = mag ? SkScalarInvert(mag) : 0; | 46 SkScalar inv = mag ? SkScalarInvert(mag) : 0; |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 do { \ | 186 do { \ |
181 unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift;
\ | 187 unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift;
\ |
182 SkASSERT(fi <= 0xFF); \ | 188 SkASSERT(fi <= 0xFF); \ |
183 fx += dx; \ | 189 fx += dx; \ |
184 *dstC++ = cache[toggle + fi]; \ | 190 *dstC++ = cache[toggle + fi]; \ |
185 toggle = next_dither_toggle(toggle); \ | 191 toggle = next_dither_toggle(toggle); \ |
186 } while (0) | 192 } while (0) |
187 | 193 |
188 namespace { | 194 namespace { |
189 | 195 |
190 typedef void (*LinearShadeProc)(TileProc proc, SkGradFixed dx, SkGradFixed fx, | 196 typedef void (*LinearShadeProc)(TileProc proc, float dx, float fx, |
191 SkPMColor* dstC, const SkPMColor* cache, | 197 SkPMColor* dstC, const SkPMColor* cache, |
192 int toggle, int count); | 198 int toggle, int count); |
193 | 199 |
194 // Linear interpolation (lerp) is unnecessary if there are no sharp | 200 // Linear interpolation (lerp) is unnecessary if there are no sharp |
195 // discontinuities in the gradient - which must be true if there are | 201 // discontinuities in the gradient - which must be true if there are |
196 // only 2 colors - but it's cheap. | 202 // only 2 colors - but it's cheap. |
197 void shadeSpan_linear_vertical_lerp(TileProc proc, SkGradFixed dx, SkGradFixed f
x, | 203 void shadeSpan_linear_vertical_lerp(TileProc proc, float dx, float fx, |
198 SkPMColor* SK_RESTRICT dstC, | 204 SkPMColor* SK_RESTRICT dstC, |
199 const SkPMColor* SK_RESTRICT cache, | 205 const SkPMColor* SK_RESTRICT cache, |
200 int toggle, int count) { | 206 int toggle, int count) { |
201 // We're a vertical gradient, so no change in a span. | 207 // We're a vertical gradient, so no change in a span. |
202 // If colors change sharply across the gradient, dithering is | 208 // If colors change sharply across the gradient, dithering is |
203 // insufficient (it subsamples the color space) and we need to lerp. | 209 // insufficient (it subsamples the color space) and we need to lerp. |
204 unsigned fullIndex = proc(SkGradFixedToFixed(fx)); | 210 unsigned fullIndex = proc(fx); |
205 unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift; | 211 unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift; |
206 unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift)
- 1); | 212 unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift)
- 1); |
207 | 213 |
208 int index0 = fi + toggle; | 214 int index0 = fi + toggle; |
209 int index1 = index0; | 215 int index1 = index0; |
210 if (fi < SkGradientShaderBase::kCache32Count - 1) { | 216 if (fi < SkGradientShaderBase::kCache32Count - 1) { |
211 index1 += 1; | 217 index1 += 1; |
212 } | 218 } |
213 SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainde
r); | 219 SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainde
r); |
214 index0 ^= SkGradientShaderBase::kDitherStride32; | 220 index0 ^= SkGradientShaderBase::kDitherStride32; |
215 index1 ^= SkGradientShaderBase::kDitherStride32; | 221 index1 ^= SkGradientShaderBase::kDitherStride32; |
216 SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remaind
er); | 222 SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remaind
er); |
217 sk_memset32_dither(dstC, lerp, dlerp, count); | 223 sk_memset32_dither(dstC, lerp, dlerp, count); |
218 } | 224 } |
219 | 225 |
220 void shadeSpan_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx, | 226 void shadeSpan_linear_clamp(TileProc proc, float float_dx, float float_fx, |
221 SkPMColor* SK_RESTRICT dstC, | 227 SkPMColor* SK_RESTRICT dstC, |
222 const SkPMColor* SK_RESTRICT cache, | 228 const SkPMColor* SK_RESTRICT cache, |
223 int toggle, int count) { | 229 int toggle, int count) { |
224 SkClampRange range; | 230 SkClampRange range; |
225 range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1); | 231 range.init(float_fx, float_dx, count, 0, SkGradientShaderBase::kCache32Count
- 1); |
226 range.validate(count); | 232 range.validate(count); |
227 | 233 |
228 if ((count = range.fCount0) > 0) { | 234 if ((count = range.fCount0) > 0) { |
229 sk_memset32_dither(dstC, | 235 sk_memset32_dither(dstC, |
230 cache[toggle + range.fV0], | 236 cache[toggle + range.fV0], |
231 cache[next_dither_toggle(toggle) + range.fV0], | 237 cache[next_dither_toggle(toggle) + range.fV0], |
232 count); | 238 count); |
233 dstC += count; | 239 dstC += count; |
234 } | 240 } |
235 if ((count = range.fCount1) > 0) { | 241 if ((count = range.fCount1) > 0) { |
236 int unroll = count >> 3; | 242 int unroll = count >> 3; |
237 fx = range.fFx1; | 243 SkGradFixed fx = range.fFx1; |
| 244 const SkGradFixed dx = SkFloatToGradFixed(float_dx); |
238 for (int i = 0; i < unroll; i++) { | 245 for (int i = 0; i < unroll; i++) { |
239 NO_CHECK_ITER; NO_CHECK_ITER; | 246 NO_CHECK_ITER; NO_CHECK_ITER; |
240 NO_CHECK_ITER; NO_CHECK_ITER; | 247 NO_CHECK_ITER; NO_CHECK_ITER; |
241 NO_CHECK_ITER; NO_CHECK_ITER; | 248 NO_CHECK_ITER; NO_CHECK_ITER; |
242 NO_CHECK_ITER; NO_CHECK_ITER; | 249 NO_CHECK_ITER; NO_CHECK_ITER; |
243 } | 250 } |
244 if ((count &= 7) > 0) { | 251 if ((count &= 7) > 0) { |
245 do { | 252 do { |
246 NO_CHECK_ITER; | 253 NO_CHECK_ITER; |
247 } while (--count != 0); | 254 } while (--count != 0); |
248 } | 255 } |
249 } | 256 } |
250 if ((count = range.fCount2) > 0) { | 257 if ((count = range.fCount2) > 0) { |
251 sk_memset32_dither(dstC, | 258 sk_memset32_dither(dstC, |
252 cache[toggle + range.fV1], | 259 cache[toggle + range.fV1], |
253 cache[next_dither_toggle(toggle) + range.fV1], | 260 cache[next_dither_toggle(toggle) + range.fV1], |
254 count); | 261 count); |
255 } | 262 } |
256 } | 263 } |
257 | 264 |
258 void shadeSpan_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx, | 265 void shadeSpan_linear_mirror(TileProc proc, float dx, float fx, |
259 SkPMColor* SK_RESTRICT dstC, | 266 SkPMColor* SK_RESTRICT dstC, |
260 const SkPMColor* SK_RESTRICT cache, | 267 const SkPMColor* SK_RESTRICT cache, |
261 int toggle, int count) { | 268 int toggle, int count) { |
262 do { | 269 do { |
263 unsigned fi = mirror_8bits(SkGradFixedToFixed(fx) >> 8); | 270 unsigned fi = mirror_8bits(fx); |
264 SkASSERT(fi <= 0xFF); | 271 SkASSERT(fi <= 0xFF); |
265 fx += dx; | 272 fx += dx; |
266 *dstC++ = cache[toggle + fi]; | 273 *dstC++ = cache[toggle + fi]; |
267 toggle = next_dither_toggle(toggle); | 274 toggle = next_dither_toggle(toggle); |
268 } while (--count != 0); | 275 } while (--count != 0); |
269 } | 276 } |
270 | 277 |
271 void shadeSpan_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx, | 278 void shadeSpan_linear_repeat(TileProc proc, float dx, float fx, |
272 SkPMColor* SK_RESTRICT dstC, | 279 SkPMColor* SK_RESTRICT dstC, |
273 const SkPMColor* SK_RESTRICT cache, | 280 const SkPMColor* SK_RESTRICT cache, |
274 int toggle, int count) { | 281 int toggle, int count) { |
275 do { | 282 do { |
276 unsigned fi = repeat_8bits(SkGradFixedToFixed(fx) >> 8); | 283 unsigned fi = repeat_8bits(fx); |
277 SkASSERT(fi <= 0xFF); | 284 SkASSERT(fi <= 0xFF); |
278 fx += dx; | 285 fx += dx; |
279 *dstC++ = cache[toggle + fi]; | 286 *dstC++ = cache[toggle + fi]; |
280 toggle = next_dither_toggle(toggle); | 287 toggle = next_dither_toggle(toggle); |
281 } while (--count != 0); | 288 } while (--count != 0); |
282 } | 289 } |
283 | 290 |
284 } | 291 } |
285 | 292 |
286 void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor*
SK_RESTRICT dstC, | 293 void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor*
SK_RESTRICT dstC, |
(...skipping 13 matching lines...) Expand all Loading... |
300 | 307 |
301 SkPoint srcPt; | 308 SkPoint srcPt; |
302 SkMatrix::MapXYProc dstProc = fDstToIndexProc; | 309 SkMatrix::MapXYProc dstProc = fDstToIndexProc; |
303 TileProc proc = linearGradient.fTileProc; | 310 TileProc proc = linearGradient.fTileProc; |
304 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); | 311 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); |
305 int toggle = init_dither_toggle(x, y); | 312 int toggle = init_dither_toggle(x, y); |
306 | 313 |
307 if (fDstToIndexClass != kPerspective_MatrixClass) { | 314 if (fDstToIndexClass != kPerspective_MatrixClass) { |
308 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, | 315 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, |
309 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); | 316 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); |
310 SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX); | 317 float dx, fx = SkScalarToFloat(srcPt.fX); |
311 | 318 |
312 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { | 319 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { |
313 const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y)); | 320 const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y)); |
314 // todo: do we need a real/high-precision value for dx here? | 321 dx = SkScalarToFloat(step.fX); |
315 dx = SkScalarToGradFixed(step.fX); | |
316 } else { | 322 } else { |
317 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); | 323 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); |
318 dx = SkScalarToGradFixed(fDstToIndex.getScaleX()); | 324 dx = SkScalarToFloat(fDstToIndex.getScaleX()); |
319 } | 325 } |
320 | 326 |
321 LinearShadeProc shadeProc = shadeSpan_linear_repeat; | 327 LinearShadeProc shadeProc = shadeSpan_linear_repeat; |
322 if (0 == dx) { | 328 if (SkScalarNearlyZero(dx)) { |
323 shadeProc = shadeSpan_linear_vertical_lerp; | 329 shadeProc = shadeSpan_linear_vertical_lerp; |
324 } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) { | 330 } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) { |
325 shadeProc = shadeSpan_linear_clamp; | 331 shadeProc = shadeSpan_linear_clamp; |
326 } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) { | 332 } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) { |
327 shadeProc = shadeSpan_linear_mirror; | 333 shadeProc = shadeSpan_linear_mirror; |
328 } else { | 334 } else { |
329 SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode); | 335 SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode); |
330 } | 336 } |
331 (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); | 337 (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); |
332 } else { | 338 } else { |
333 SkScalar dstX = SkIntToScalar(x); | 339 SkScalar dstX = SkIntToScalar(x); |
334 SkScalar dstY = SkIntToScalar(y); | 340 SkScalar dstY = SkIntToScalar(y); |
335 do { | 341 do { |
336 dstProc(fDstToIndex, dstX, dstY, &srcPt); | 342 dstProc(fDstToIndex, dstX, dstY, &srcPt); |
337 unsigned fi = proc(SkScalarToFixed(srcPt.fX)); | 343 unsigned fi = proc(SkScalarToFloat(srcPt.fX)); |
338 SkASSERT(fi <= 0xFFFF); | 344 SkASSERT(fi <= 0xFFFF); |
339 *dstC++ = cache[toggle + (fi >> kCache32Shift)]; | 345 *dstC++ = cache[toggle + (fi >> kCache32Shift)]; |
340 toggle = next_dither_toggle(toggle); | 346 toggle = next_dither_toggle(toggle); |
341 dstX += SK_Scalar1; | 347 dstX += SK_Scalar1; |
342 } while (--count != 0); | 348 } while (--count != 0); |
343 } | 349 } |
344 } | 350 } |
345 | 351 |
346 SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { | 352 SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { |
347 if (info) { | 353 if (info) { |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
762 this->shade4_dx_clamp<false, true>(dstC, count, fx, dx, invDx, dithe
r); | 768 this->shade4_dx_clamp<false, true>(dstC, count, fx, dx, invDx, dithe
r); |
763 } | 769 } |
764 } else { | 770 } else { |
765 if (fApplyAlphaAfterInterp) { | 771 if (fApplyAlphaAfterInterp) { |
766 this->shade4_dx_clamp<true, false>(dstC, count, fx, dx, invDx, dithe
r); | 772 this->shade4_dx_clamp<true, false>(dstC, count, fx, dx, invDx, dithe
r); |
767 } else { | 773 } else { |
768 this->shade4_dx_clamp<false, false>(dstC, count, fx, dx, invDx, dith
er); | 774 this->shade4_dx_clamp<false, false>(dstC, count, fx, dx, invDx, dith
er); |
769 } | 775 } |
770 } | 776 } |
771 } | 777 } |
OLD | NEW |