From 96b333a9a1b6a367d6c542118638e3108d8ed23b Mon Sep 17 00:00:00 2001 From: Mike Klein Date: Wed, 12 Oct 2016 11:05:05 -0400 Subject: [PATCH] Add SkRasterPipeline support to SkModeColorFilter. The shader leaves its color in r,g,b,a, so to implement this color filter, we move {r,g,b,a} into {dr,dg,db,da}, then load the filter's color in {r,g,b,a}, then apply the xfermode as usual. I've left a note about how we could sometimes cut a stage for some xfermodes. Similarly we really only need to move_src_dst instead of swap_src_dst, but it seemed handy and less error prone to do a full two way swap. As usual, we can always circle back and fine-tune these things if we want. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=3243 CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot Change-Id: I928c0fb25236eb75cf238134c6bebb53af5ddf07 Reviewed-on: https://skia-review.googlesource.com/3243 Commit-Queue: Mike Klein Reviewed-by: Matt Sarett --- src/core/SkModeColorFilter.cpp | 19 +++++++++++++++++-- src/core/SkModeColorFilter.h | 4 ++++ src/core/SkOpts.cpp | 2 ++ src/core/SkRasterPipeline.h | 1 + src/opts/SkRasterPipeline_opts.h | 7 +++++++ 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/core/SkModeColorFilter.cpp b/src/core/SkModeColorFilter.cpp index ba3b50d763..e165f69bcd 100644 --- a/src/core/SkModeColorFilter.cpp +++ b/src/core/SkModeColorFilter.cpp @@ -9,6 +9,7 @@ #include "SkColorFilter.h" #include "SkColorPriv.h" #include "SkModeColorFilter.h" +#include "SkRasterPipeline.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkUtils.h" @@ -59,11 +60,10 @@ void SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColo } void SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const { - SkPM4f color = SkPM4f::FromPMColor(fPMColor); SkXfermodeProc4f proc = SkXfermode::GetProc4f(fMode); for (int i = 0; i < count; i++) { - result[i] = proc(color, shader[i]); + result[i] = proc(fPM4f, shader[i]); } } @@ -75,6 +75,7 @@ void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const { void SkModeColorFilter::updateCache() { fPMColor = SkPreMultiplyColor(fColor); fProc = SkXfermode::GetProc(fMode); + fPM4f = SkPM4f::FromPMColor(fPMColor); } sk_sp SkModeColorFilter::CreateProc(SkReadBuffer& buffer) { @@ -83,6 +84,20 @@ sk_sp SkModeColorFilter::CreateProc(SkReadBuffer& buffer) { return SkColorFilter::MakeModeFilter(color, mode); } +bool SkModeColorFilter::onAppendStages(SkRasterPipeline* p) const { + // TODO: For some modes we can cut a stage by loading the fPM4f into dr,dg,db,da + // and applying the opposite xfermode, e.g. dst-in instead of src-in. + p->append(SkRasterPipeline::swap_src_dst); + p->append(SkRasterPipeline::constant_color, &fPM4f); + + // TODO: This is ugly. I think we want static SkXfermode::AppendStages(Mode). + if (auto xfermode = SkXfermode::Make(fMode)) { + return xfermode->appendStages(p); + } + p->append(SkRasterPipeline::srcover); + return true; +} + /////////////////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU #include "GrBlend.h" diff --git a/src/core/SkModeColorFilter.h b/src/core/SkModeColorFilter.h index 7d4d4cc3ef..6222e06fd8 100644 --- a/src/core/SkModeColorFilter.h +++ b/src/core/SkModeColorFilter.h @@ -6,6 +6,7 @@ */ #include "SkColorFilter.h" +#include "SkPM4f.h" #include "SkXfermode.h" #ifndef SkModeColorFilter_DEFINED @@ -49,12 +50,15 @@ protected: void flatten(SkWriteBuffer&) const override; + bool onAppendStages(SkRasterPipeline*) const override; + private: SkColor fColor; SkXfermode::Mode fMode; // cache SkPMColor fPMColor; SkXfermodeProc fProc; + SkPM4f fPM4f; void updateCache(); diff --git a/src/core/SkOpts.cpp b/src/core/SkOpts.cpp index 88261f65bd..627f0e3b21 100644 --- a/src/core/SkOpts.cpp +++ b/src/core/SkOpts.cpp @@ -94,6 +94,7 @@ namespace SkOpts { SkOpts::VoidFn body[] = { (SkOpts::VoidFn)SK_OPTS_NS::just_return, + (SkOpts::VoidFn)SK_OPTS_NS::swap_src_dst, (SkOpts::VoidFn)SK_OPTS_NS::store_565, (SkOpts::VoidFn)SK_OPTS_NS::store_srgb, @@ -144,6 +145,7 @@ namespace SkOpts { SkOpts::VoidFn tail[] = { (SkOpts::VoidFn)SK_OPTS_NS::just_return, + (SkOpts::VoidFn)SK_OPTS_NS::swap_src_dst, (SkOpts::VoidFn)SK_OPTS_NS::store_565_tail, (SkOpts::VoidFn)SK_OPTS_NS::store_srgb_tail, diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h index 3ef8c50d9f..05947fcb59 100644 --- a/src/core/SkRasterPipeline.h +++ b/src/core/SkRasterPipeline.h @@ -91,6 +91,7 @@ public: enum StockStage { just_return, + swap_src_dst, store_565, store_srgb, diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h index 1d8b04452d..52b02d045e 100644 --- a/src/opts/SkRasterPipeline_opts.h +++ b/src/opts/SkRasterPipeline_opts.h @@ -152,6 +152,13 @@ namespace SK_OPTS_NS { STAGE(just_return, false) { } + STAGE(swap_src_dst, true) { + SkTSwap(r,dr); + SkTSwap(g,dg); + SkTSwap(b,db); + SkTSwap(a,da); + } + // The default shader produces a constant color (from the SkPaint). STAGE(constant_color, true) { auto color = (const SkPM4f*)ctx;