| 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 |