diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkPM4fPriv.h | 21 | ||||
-rw-r--r-- | src/core/SkRasterPipeline.h | 3 | ||||
-rw-r--r-- | src/effects/gradients/SkLinearGradient.cpp | 70 | ||||
-rw-r--r-- | src/effects/gradients/SkLinearGradient.h | 3 | ||||
-rw-r--r-- | src/opts/SkRasterPipeline_opts.h | 10 |
5 files changed, 99 insertions, 8 deletions
diff --git a/src/core/SkPM4fPriv.h b/src/core/SkPM4fPriv.h index a6232bead5..a08f158deb 100644 --- a/src/core/SkPM4fPriv.h +++ b/src/core/SkPM4fPriv.h @@ -135,22 +135,29 @@ static inline bool append_gamut_transform(SkRasterPipeline* p, SkArenaAlloc* scr return append_gamut_transform(p, scratch->makeArrayDefault<float>(12), src, dst); } -static inline SkColor4f SkColor4f_from_SkColor(SkColor color, SkColorSpace* dst) { - SkColor4f color4f; - if (dst) { - // sRGB gamma, sRGB gamut. - color4f = SkColor4f::FromColor(color); +static inline SkColor4f to_colorspace(const SkColor4f& c, SkColorSpace* src, SkColorSpace* dst) { + SkColor4f color4f = c; + if (src && dst) { void* color4f_ptr = &color4f; float scratch_matrix_3x4[12]; SkRasterPipeline p; p.append(SkRasterPipeline::constant_color, color4f_ptr); - append_gamut_transform(&p, scratch_matrix_3x4, - SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get(), dst); + append_gamut_transform(&p, scratch_matrix_3x4, src, dst); p.append(SkRasterPipeline::store_f32, &color4f_ptr); p.run(0,0,1); + } + return color4f; +} + +static inline SkColor4f SkColor4f_from_SkColor(SkColor color, SkColorSpace* dst) { + SkColor4f color4f; + if (dst) { + // sRGB gamma, sRGB gamut. + color4f = to_colorspace(SkColor4f::FromColor(color), + SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get(), dst); } else { // Linear gamma, dst gamut. swizzle_rb(SkNx_cast<float>(Sk4b::Load(&color)) * (1/255.0f)).store(&color4f); diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h index ac1e3b926a..558eeade9f 100644 --- a/src/core/SkRasterPipeline.h +++ b/src/core/SkRasterPipeline.h @@ -93,7 +93,8 @@ M(bilinear_nx) M(bilinear_px) M(bilinear_ny) M(bilinear_py) \ M(bicubic_n3x) M(bicubic_n1x) M(bicubic_p1x) M(bicubic_p3x) \ M(bicubic_n3y) M(bicubic_n1y) M(bicubic_p1y) M(bicubic_p3y) \ - M(save_xy) M(accumulate) + M(save_xy) M(accumulate) \ + M(linear_gradient_2stops) class SkRasterPipeline { public: diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp index 4bb640de91..91c0e20955 100644 --- a/src/effects/gradients/SkLinearGradient.cpp +++ b/src/effects/gradients/SkLinearGradient.cpp @@ -86,6 +86,76 @@ SkShader::Context* SkLinearGradient::onCreateContext(const ContextRec& rec, void : CheckedCreateContext< LinearGradientContext>(storage, *this, rec); } +// For now, only a 2-stop raster pipeline specialization. +// +// Stages: +// +// * matrix (map dst -> grad space) +// * clamp/repeat/mirror (tiling) +// * linear_gradient_2stops (lerp c0/c1) +// * optional premul +// +bool SkLinearGradient::onAppendStages(SkRasterPipeline* p, SkColorSpace* cs, SkArenaAlloc* alloc, + const SkMatrix& ctm, const SkPaint& paint) const { + if (fColorCount > 2) { + return false; + } + + // Local matrix not supported currently. Remove once we have a generic RP wrapper. + if (!getLocalMatrix().isIdentity()) { + return false; + } + + SkASSERT(fColorCount == 2); + SkASSERT(fOrigPos == nullptr || (fOrigPos[0] == 0 && fOrigPos[1] == 1)); + + SkMatrix dstToPts; + if (!ctm.invert(&dstToPts)) { + return false; + } + + const auto dstToUnit = SkMatrix::Concat(fPtsToUnit, dstToPts); + + auto* m = alloc->makeArrayDefault<float>(9); + if (dstToUnit.asAffine(m)) { + // TODO: mapping y is not needed; split the matrix stages to save some math? + p->append(SkRasterPipeline::matrix_2x3, m); + } else { + dstToUnit.get9(m); + p->append(SkRasterPipeline::matrix_perspective, m); + } + + // TODO: clamp/repeat/mirror const 1f stages? + auto* limit = alloc->make<float>(1.0f); + + switch (fTileMode) { + case kClamp_TileMode: + *limit += 0.5f; // why is clamp_x offsetting its limit? + p->append(SkRasterPipeline::clamp_x, limit); + break; + case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, limit); break; + case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, limit); break; + } + + const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag; + const SkColor4f c0 = to_colorspace(fOrigColors4f[0], fColorSpace.get(), cs), + c1 = to_colorspace(fOrigColors4f[1], fColorSpace.get(), cs); + const SkPM4f pmc0 = premulGrad ? c0.premul() : SkPM4f::From4f(Sk4f::Load(&c0)), + pmc1 = premulGrad ? c1.premul() : SkPM4f::From4f(Sk4f::Load(&c1)); + + auto* c0_and_dc = alloc->makeArrayDefault<SkPM4f>(2); + c0_and_dc[0] = pmc0; + c0_and_dc[1] = SkPM4f::From4f(pmc1.to4f() - pmc0.to4f()); + + p->append(SkRasterPipeline::linear_gradient_2stops, c0_and_dc); + + if (!premulGrad && !this->colorsAreOpaque()) { + p->append(SkRasterPipeline::premul); + } + + return true; +} + // This swizzles SkColor into the same component order as SkPMColor, but does not actually // "pre" multiply the color components. // diff --git a/src/effects/gradients/SkLinearGradient.h b/src/effects/gradients/SkLinearGradient.h index 7a85b88cb7..acf9c21ec0 100644 --- a/src/effects/gradients/SkLinearGradient.h +++ b/src/effects/gradients/SkLinearGradient.h @@ -69,6 +69,9 @@ protected: size_t onContextSize(const ContextRec&) const override; Context* onCreateContext(const ContextRec&, void* storage) const override; + bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + const SkMatrix&, const SkPaint&) const override; + private: class LinearGradient4fContext; diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h index 00b6ac718b..2376c10e35 100644 --- a/src/opts/SkRasterPipeline_opts.h +++ b/src/opts/SkRasterPipeline_opts.h @@ -1045,6 +1045,16 @@ STAGE_CTX(gather_f16, const SkImageShaderContext*) { from_f16(&px, &r, &g, &b, &a); } +STAGE_CTX(linear_gradient_2stops, const SkPM4f*) { + auto t = r; + SkPM4f c0 = ctx[0], + dc = ctx[1]; + + r = SkNf_fma(t, dc.r(), c0.r()); + g = SkNf_fma(t, dc.g(), c0.g()); + b = SkNf_fma(t, dc.b(), c0.b()); + a = SkNf_fma(t, dc.a(), c0.a()); +} SI Fn enum_to_Fn(SkRasterPipeline::StockStage st) { switch (st) { |