aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/core/SkPM4fPriv.h21
-rw-r--r--src/core/SkRasterPipeline.h3
-rw-r--r--src/effects/gradients/SkLinearGradient.cpp70
-rw-r--r--src/effects/gradients/SkLinearGradient.h3
-rw-r--r--src/opts/SkRasterPipeline_opts.h10
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) {