| /* |
| * Copyright 2013 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "SkArithmeticMode.h" |
| #include "SkColorPriv.h" |
| #include "SkNx.h" |
| #include "SkRasterPipeline.h" |
| #include "SkReadBuffer.h" |
| #include "SkString.h" |
| #include "SkUnPreMultiply.h" |
| #include "SkWriteBuffer.h" |
| #if SK_SUPPORT_GPU |
| #include "SkArithmeticMode_gpu.h" |
| #endif |
| |
| class SkArithmeticMode_scalar : public SkXfermode { |
| public: |
| SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, |
| bool enforcePMColor) { |
| fK[0] = k1; |
| fK[1] = k2; |
| fK[2] = k3; |
| fK[3] = k4; |
| fEnforcePMColor = enforcePMColor; |
| } |
| |
| void xfer32(SkPMColor[], const SkPMColor[], int count, const SkAlpha[]) const override; |
| |
| bool onAppendStages(SkRasterPipeline* p) const override { |
| p->append(&Stage, this); |
| return true; |
| } |
| |
| SK_TO_STRING_OVERRIDE() |
| SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar) |
| |
| #if SK_SUPPORT_GPU |
| sk_sp<GrFragmentProcessor> makeFragmentProcessorForImageFilter( |
| sk_sp<GrFragmentProcessor> dst) const override; |
| sk_sp<GrXPFactory> asXPFactory() const override; |
| #endif |
| |
| private: |
| static void SK_VECTORCALL Stage(SkRasterPipeline::Stage* st, size_t x, |
| Sk4f r, Sk4f g, Sk4f b, Sk4f a, |
| Sk4f dr, Sk4f dg, Sk4f db, Sk4f da); |
| |
| void flatten(SkWriteBuffer& buffer) const override { |
| buffer.writeScalar(fK[0]); |
| buffer.writeScalar(fK[1]); |
| buffer.writeScalar(fK[2]); |
| buffer.writeScalar(fK[3]); |
| buffer.writeBool(fEnforcePMColor); |
| } |
| |
| SkScalar fK[4]; |
| bool fEnforcePMColor; |
| |
| friend class SkArithmeticMode; |
| |
| typedef SkXfermode INHERITED; |
| }; |
| |
| sk_sp<SkFlattenable> SkArithmeticMode_scalar::CreateProc(SkReadBuffer& buffer) { |
| const SkScalar k1 = buffer.readScalar(); |
| const SkScalar k2 = buffer.readScalar(); |
| const SkScalar k3 = buffer.readScalar(); |
| const SkScalar k4 = buffer.readScalar(); |
| const bool enforcePMColor = buffer.readBool(); |
| return SkArithmeticMode::Make(k1, k2, k3, k4, enforcePMColor); |
| } |
| |
| void SK_VECTORCALL SkArithmeticMode_scalar::Stage(SkRasterPipeline::Stage* st, size_t x, |
| Sk4f r, Sk4f g, Sk4f b, Sk4f a, |
| Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { |
| auto self = st->ctx<const SkArithmeticMode_scalar*>(); |
| |
| const Sk4f k1 = self->fK[0], |
| k2 = self->fK[1], |
| k3 = self->fK[2], |
| k4 = self->fK[3]; |
| |
| r = k1*r*dr + k2*r + k3*dr + k4; |
| g = k1*g*dg + k2*g + k3*dg + k4; |
| b = k1*b*db + k2*b + k3*db + k4; |
| a = k1*a*da + k2*a + k3*da + k4; |
| |
| // A later stage (clamp_01_premul) will pin and fEnforcePMColor for us. |
| |
| st->next(x, r,g,b,a, dr,dg,db,da); |
| } |
| |
| void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[], |
| int count, const SkAlpha aaCoverage[]) const { |
| const Sk4f k1 = fK[0] * (1/255.0f), |
| k2 = fK[1], |
| k3 = fK[2], |
| k4 = fK[3] * 255.0f + 0.5f; |
| |
| auto pin = [](float min, const Sk4f& val, float max) { |
| return Sk4f::Max(min, Sk4f::Min(val, max)); |
| }; |
| |
| for (int i = 0; i < count; i++) { |
| if (aaCoverage && aaCoverage[i] == 0) { |
| continue; |
| } |
| |
| Sk4f s = SkNx_cast<float>(Sk4b::Load(src+i)), |
| d = SkNx_cast<float>(Sk4b::Load(dst+i)), |
| r = pin(0, k1*s*d + k2*s + k3*d + k4, 255); |
| |
| if (fEnforcePMColor) { |
| Sk4f a = SkNx_shuffle<3,3,3,3>(r); |
| r = Sk4f::Min(a, r); |
| } |
| |
| if (aaCoverage && aaCoverage[i] != 255) { |
| Sk4f c = aaCoverage[i] * (1/255.0f); |
| r = d + (r-d)*c; |
| } |
| |
| SkNx_cast<uint8_t>(r).store(dst+i); |
| } |
| } |
| |
| #ifndef SK_IGNORE_TO_STRING |
| void SkArithmeticMode_scalar::toString(SkString* str) const { |
| str->append("SkArithmeticMode_scalar: "); |
| for (int i = 0; i < 4; ++i) { |
| str->appendScalar(fK[i]); |
| str->append(" "); |
| } |
| str->appendS32(fEnforcePMColor ? 1 : 0); |
| } |
| #endif |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| sk_sp<SkXfermode> SkArithmeticMode::Make(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, |
| bool enforcePMColor) { |
| if (SkScalarNearlyZero(k1) && SkScalarNearlyEqual(k2, SK_Scalar1) && |
| SkScalarNearlyZero(k3) && SkScalarNearlyZero(k4)) { |
| return SkXfermode::Make(SkXfermode::kSrc_Mode); |
| } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) && |
| SkScalarNearlyEqual(k3, SK_Scalar1) && SkScalarNearlyZero(k4)) { |
| return SkXfermode::Make(SkXfermode::kDst_Mode); |
| } |
| return sk_make_sp<SkArithmeticMode_scalar>(k1, k2, k3, k4, enforcePMColor); |
| } |
| |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| #if SK_SUPPORT_GPU |
| sk_sp<GrFragmentProcessor> SkArithmeticMode_scalar::makeFragmentProcessorForImageFilter( |
| sk_sp<GrFragmentProcessor> dst) const { |
| return GrArithmeticFP::Make(SkScalarToFloat(fK[0]), |
| SkScalarToFloat(fK[1]), |
| SkScalarToFloat(fK[2]), |
| SkScalarToFloat(fK[3]), |
| fEnforcePMColor, |
| std::move(dst)); |
| } |
| |
| sk_sp<GrXPFactory> SkArithmeticMode_scalar::asXPFactory() const { |
| return GrArithmeticXPFactory::Make(SkScalarToFloat(fK[0]), |
| SkScalarToFloat(fK[1]), |
| SkScalarToFloat(fK[2]), |
| SkScalarToFloat(fK[3]), |
| fEnforcePMColor); |
| } |
| |
| #endif |
| |
| SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticMode) |
| SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticMode_scalar) |
| SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |