Chromium Code Reviews| Index: src/effects/gradients/Sk4fLinearGradient.cpp |
| diff --git a/src/effects/gradients/Sk4fLinearGradient.cpp b/src/effects/gradients/Sk4fLinearGradient.cpp |
| index 9bc84c49957d6a07ef8e70d10fc3176a10965ccb..1dff802cfac9fdafd1098baf79c8b17459ce41b0 100644 |
| --- a/src/effects/gradients/Sk4fLinearGradient.cpp |
| +++ b/src/effects/gradients/Sk4fLinearGradient.cpp |
| @@ -7,14 +7,15 @@ |
| #include "Sk4fGradientPriv.h" |
| #include "Sk4fLinearGradient.h" |
| +#include "SkXfermode.h" |
| namespace { |
| -template<typename DstType, bool do_premul> |
| +template<typename DstType, SkColorProfileType, bool do_premul> |
| void fill(const Sk4f& c, DstType* dst, int n); |
| template<> |
| -void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) { |
| +void fill<SkPM4f, kLinear_SkColorProfileType, false>(const Sk4f& c, SkPM4f* dst, int n) { |
| while (n > 0) { |
| c.store(dst++); |
| n--; |
| @@ -22,21 +23,50 @@ void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) { |
| } |
| template<> |
| -void fill<SkPM4f, true>(const Sk4f& c, SkPM4f* dst, int n) { |
| - fill<SkPM4f, false>(premul_4f(c), dst, n); |
| +void fill<SkPM4f, kLinear_SkColorProfileType, true>(const Sk4f& c, SkPM4f* dst, int n) { |
| + fill<SkPM4f, kLinear_SkColorProfileType, false>(premul_4f(c), dst, n); |
| } |
| template<> |
| -void fill<SkPMColor, false>(const Sk4f& c, SkPMColor* dst, int n) { |
| +void fill<SkPMColor, kLinear_SkColorProfileType, false>(const Sk4f& c, SkPMColor* dst, int n) { |
| sk_memset32(dst, trunc_from_255<false>(c), n); |
| } |
| template<> |
| -void fill<SkPMColor, true>(const Sk4f& c, SkPMColor* dst, int n) { |
| +void fill<SkPMColor, kLinear_SkColorProfileType, true>(const Sk4f& c, SkPMColor* dst, int n) { |
| sk_memset32(dst, trunc_from_255<true>(c), n); |
| } |
| -template<typename DstType, bool do_premul> |
| +template<> |
| +void fill<SkPMColor, kSRGB_SkColorProfileType, false>(const Sk4f& c, SkPMColor* dst, int n) { |
| + // FIXME: this assumes opaque colors. Handle unpremultiplication. |
| + const SkPMColor pmc = Sk4f_toS32(c); |
| + sk_memset32(dst, pmc, n); |
| +} |
| + |
| +template<> |
| +void fill<SkPMColor, kSRGB_SkColorProfileType, true>(const Sk4f& c, SkPMColor* dst, int n) { |
| + const SkPMColor s32 = Sk4f_toS32(c); |
| + const SkPMColor pmc = SkPreMultiplyARGB(SkGetPackedA32(s32), SkGetPackedR32(s32), |
| + SkGetPackedG32(s32), SkGetPackedB32(s32)); |
| + sk_memset32(dst, pmc, n); |
| +} |
| + |
| +template<> |
| +void fill<uint64_t, kLinear_SkColorProfileType, false>(const Sk4f& c, uint64_t* dst, int n) { |
| + const uint64_t c64 = SkFloatToHalf_01(c); |
| + while (n > 0) { |
|
reed1
2016/03/18 14:28:59
sk_memset64() ?
f(malita)
2016/03/18 16:54:11
added/done.
|
| + *dst++ = c64; |
| + n--; |
| + } |
| +} |
| + |
| +template<> |
| +void fill<uint64_t, kLinear_SkColorProfileType, true>(const Sk4f& c, uint64_t* dst, int n) { |
| + fill<uint64_t, kLinear_SkColorProfileType, false>(premul_4f(c), dst, n); |
| +} |
| + |
| +template<typename DstType, SkColorProfileType profile, bool do_premul> |
| void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { |
| SkASSERT(n > 0); |
| @@ -49,7 +79,7 @@ void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { |
| Sk4f c3 = c1 + dc2; |
| while (n >= 4) { |
| - store4x<DstType, do_premul>(c0, c1, c2, c3, dst); |
| + store4x<DstType, profile, do_premul>(c0, c1, c2, c3, dst); |
| dst += 4; |
| c0 = c0 + dc4; |
| @@ -59,12 +89,12 @@ void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { |
| n -= 4; |
| } |
| if (n & 2) { |
| - store<DstType, do_premul>(c0, dst++); |
| - store<DstType, do_premul>(c1, dst++); |
| + store<DstType, profile, do_premul>(c0, dst++); |
| + store<DstType, profile, do_premul>(c1, dst++); |
| c0 = c0 + dc2; |
| } |
| if (n & 1) { |
| - store<DstType, do_premul>(c0, dst); |
| + store<DstType, profile, do_premul>(c0, dst); |
| } |
| } |
| @@ -163,9 +193,9 @@ LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { |
| // TODO: plumb dithering |
| SkASSERT(count > 0); |
| if (fColorsArePremul) { |
| - this->shadePremulSpan<SkPMColor, false>(x, y, dst, count); |
| + this->shadePremulSpan<SkPMColor, kLinear_SkColorProfileType, false>(x, y, dst, count); |
| } else { |
| - this->shadePremulSpan<SkPMColor, true>(x, y, dst, count); |
| + this->shadePremulSpan<SkPMColor, kLinear_SkColorProfileType, true>(x, y, dst, count); |
| } |
| } |
| @@ -179,13 +209,13 @@ LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { |
| // TONOTDO: plumb dithering |
| SkASSERT(count > 0); |
| if (fColorsArePremul) { |
| - this->shadePremulSpan<SkPM4f, false>(x, y, dst, count); |
| + this->shadePremulSpan<SkPM4f, kLinear_SkColorProfileType, false>(x, y, dst, count); |
| } else { |
| - this->shadePremulSpan<SkPM4f, true>(x, y, dst, count); |
| + this->shadePremulSpan<SkPM4f, kLinear_SkColorProfileType, true>(x, y, dst, count); |
| } |
| } |
| -template<typename DstType, bool do_premul> |
| +template<typename DstType, SkColorProfileType profile, bool do_premul> |
| void SkLinearGradient:: |
| LinearGradient4fContext::shadePremulSpan(int x, int y, |
| DstType dst[], |
| @@ -195,23 +225,27 @@ LinearGradient4fContext::shadePremulSpan(int x, int y, |
| switch (shader.fTileMode) { |
| case kClamp_TileMode: |
| this->shadeSpanInternal<DstType, |
| + profile, |
| do_premul, |
| kClamp_TileMode>(x, y, dst, count); |
| break; |
| case kRepeat_TileMode: |
| this->shadeSpanInternal<DstType, |
| + profile, |
| do_premul, |
| kRepeat_TileMode>(x, y, dst, count); |
| break; |
| case kMirror_TileMode: |
| this->shadeSpanInternal<DstType, |
| + profile, |
| do_premul, |
| kMirror_TileMode>(x, y, dst, count); |
| break; |
| } |
| } |
| -template<typename DstType, bool do_premul, SkShader::TileMode tileMode> |
| +template<typename DstType, SkColorProfileType profile, bool do_premul, |
| + SkShader::TileMode tileMode> |
| void SkLinearGradient:: |
| LinearGradient4fContext::shadeSpanInternal(int x, int y, |
| DstType dst[], |
| @@ -223,12 +257,12 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, |
| &pt); |
| const SkScalar fx = pinFx<tileMode>(pt.x()); |
| const SkScalar dx = fDstToPos.getScaleX(); |
| - LinearIntervalProcessor<DstType, tileMode> proc(fIntervals.begin(), |
| - fIntervals.end() - 1, |
| - this->findInterval(fx), |
| - fx, |
| - dx, |
| - SkScalarNearlyZero(dx * count)); |
| + LinearIntervalProcessor<DstType, profile, tileMode> proc(fIntervals.begin(), |
| + fIntervals.end() - 1, |
| + this->findInterval(fx), |
| + fx, |
| + dx, |
| + SkScalarNearlyZero(dx * count)); |
| while (count > 0) { |
| // What we really want here is SkTPin(advance, 1, count) |
| // but that's a significant perf hit for >> stops; investigate. |
| @@ -243,12 +277,12 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, |
| || (n == count && proc.currentRampIsZero())); |
| if (proc.currentRampIsZero()) { |
| - fill<DstType, do_premul>(proc.currentColor(), |
| - dst, n); |
| + fill<DstType, profile, do_premul>(proc.currentColor(), |
| + dst, n); |
| } else { |
| - ramp<DstType, do_premul>(proc.currentColor(), |
| - proc.currentColorGrad(), |
| - dst, n); |
| + ramp<DstType, profile, do_premul>(proc.currentColor(), |
| + proc.currentColorGrad(), |
| + dst, n); |
| } |
| proc.advance(SkIntToScalar(n)); |
| @@ -257,7 +291,7 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, |
| } |
| } |
| -template<typename DstType, SkShader::TileMode tileMode> |
| +template<typename DstType, SkColorProfileType profile, SkShader::TileMode tileMode> |
| class SkLinearGradient:: |
| LinearGradient4fContext::LinearIntervalProcessor { |
| public: |
| @@ -267,8 +301,7 @@ public: |
| SkScalar fx, |
| SkScalar dx, |
| bool is_vertical) |
| - : fDstComponentScale(dst_component_scale<DstType>()) |
| - , fAdvX((i->fP1 - fx) / dx) |
| + : fAdvX((i->fP1 - fx) / dx) |
| , fFirstInterval(firstInterval) |
| , fLastInterval(lastInterval) |
| , fInterval(i) |
| @@ -308,8 +341,8 @@ private: |
| fDc = dst_swizzle<DstType>(fInterval->fDc); |
| fCc = dst_swizzle<DstType>(fInterval->fC0); |
| fCc = fCc + fDc * Sk4f(t); |
| - fCc = fCc * fDstComponentScale; |
| - fDcDx = fDc * fDstComponentScale * Sk4f(fDx); |
| + fCc = scale_for_dest<DstType, profile>(fCc); |
| + fDcDx = scale_for_dest<DstType, profile>(fDc * Sk4f(fDx)); |
| fZeroRamp = fIsVertical || fInterval->isZeroRamp(); |
| } |
| @@ -342,8 +375,6 @@ private: |
| return advX; |
| } |
| - const Sk4f fDstComponentScale; // cached dst scale (PMC: 255, PM4f: 1) |
| - |
| // Current interval properties. |
| Sk4f fDc; // local color gradient (dc/dt) |
| Sk4f fDcDx; // dst color gradient (dc/dx) |
| @@ -402,3 +433,68 @@ LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const { |
| } |
| } |
| } |
| + |
| +SkShader::Context::BlitProc SkLinearGradient:: |
| +LinearGradient4fContext::onChooseBlitProc(const SkImageInfo& info, BlitState* state) { |
| + SkXfermode::Mode mode; |
| + if (!SkXfermode::AsMode(state->fXfer, &mode)) { |
| + return nullptr; |
| + } |
| + |
| + const SkGradientShaderBase& shader = static_cast<const SkGradientShaderBase&>(fShader); |
| + if (mode != SkXfermode::kSrc_Mode && |
| + !(mode == SkXfermode::kSrcOver_Mode && shader.colorsAreOpaque())) { |
| + return nullptr; |
| + } |
| + |
| + switch (info.colorType()) { |
| + case kN32_SkColorType: |
| + return D32_BlitProc; |
| + case kRGBA_F16_SkColorType: |
| + return D64_BlitProc; |
| + default: |
| + return nullptr; |
| + } |
| +} |
| + |
| +void SkLinearGradient:: |
| +LinearGradient4fContext::D32_BlitProc(BlitState* state, int x, int y, const SkPixmap& dst, |
| + int count, const SkAlpha aa[]) { |
| + // FIXME: ignoring coverage for now |
| + const LinearGradient4fContext* ctx = |
| + static_cast<const LinearGradient4fContext*>(state->fCtx); |
| + |
| + if (dst.info().isLinear()) { |
| + if (ctx->fColorsArePremul) { |
| + ctx->shadePremulSpan<SkPMColor, kLinear_SkColorProfileType, false>( |
| + x, y, dst.writable_addr32(x, y), count); |
| + } else { |
| + ctx->shadePremulSpan<SkPMColor, kLinear_SkColorProfileType, true>( |
| + x, y, dst.writable_addr32(x, y), count); |
| + } |
| + } else { |
| + if (ctx->fColorsArePremul) { |
| + ctx->shadePremulSpan<SkPMColor, kSRGB_SkColorProfileType, false>( |
| + x, y, dst.writable_addr32(x, y), count); |
| + } else { |
| + ctx->shadePremulSpan<SkPMColor, kSRGB_SkColorProfileType, true>( |
| + x, y, dst.writable_addr32(x, y), count); |
| + } |
| + } |
| +} |
| + |
| +void SkLinearGradient:: |
| +LinearGradient4fContext::D64_BlitProc(BlitState* state, int x, int y, const SkPixmap& dst, |
| + int count, const SkAlpha aa[]) { |
| + // FIXME: ignoring coverage for now |
| + const LinearGradient4fContext* ctx = |
| + static_cast<const LinearGradient4fContext*>(state->fCtx); |
| + |
| + if (ctx->fColorsArePremul) { |
| + ctx->shadePremulSpan<uint64_t, kLinear_SkColorProfileType, false>( |
| + x, y, dst.writable_addr64(x, y), count); |
| + } else { |
| + ctx->shadePremulSpan<uint64_t, kLinear_SkColorProfileType, true>( |
| + x, y, dst.writable_addr64(x, y), count); |
| + } |
| +} |