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 <mtklein@chromium.org>
Reviewed-by: Matt Sarett <msarett@google.com>
This commit is contained in:
Mike Klein 2016-10-12 11:05:05 -04:00 committed by Skia Commit-Bot
parent c0708a40c7
commit 96b333a9a1
5 changed files with 31 additions and 2 deletions

View File

@ -9,6 +9,7 @@
#include "SkColorFilter.h" #include "SkColorFilter.h"
#include "SkColorPriv.h" #include "SkColorPriv.h"
#include "SkModeColorFilter.h" #include "SkModeColorFilter.h"
#include "SkRasterPipeline.h"
#include "SkReadBuffer.h" #include "SkReadBuffer.h"
#include "SkWriteBuffer.h" #include "SkWriteBuffer.h"
#include "SkUtils.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 { void SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const {
SkPM4f color = SkPM4f::FromPMColor(fPMColor);
SkXfermodeProc4f proc = SkXfermode::GetProc4f(fMode); SkXfermodeProc4f proc = SkXfermode::GetProc4f(fMode);
for (int i = 0; i < count; i++) { 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() { void SkModeColorFilter::updateCache() {
fPMColor = SkPreMultiplyColor(fColor); fPMColor = SkPreMultiplyColor(fColor);
fProc = SkXfermode::GetProc(fMode); fProc = SkXfermode::GetProc(fMode);
fPM4f = SkPM4f::FromPMColor(fPMColor);
} }
sk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) { sk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
@ -83,6 +84,20 @@ sk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
return SkColorFilter::MakeModeFilter(color, mode); 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 #if SK_SUPPORT_GPU
#include "GrBlend.h" #include "GrBlend.h"

View File

@ -6,6 +6,7 @@
*/ */
#include "SkColorFilter.h" #include "SkColorFilter.h"
#include "SkPM4f.h"
#include "SkXfermode.h" #include "SkXfermode.h"
#ifndef SkModeColorFilter_DEFINED #ifndef SkModeColorFilter_DEFINED
@ -49,12 +50,15 @@ protected:
void flatten(SkWriteBuffer&) const override; void flatten(SkWriteBuffer&) const override;
bool onAppendStages(SkRasterPipeline*) const override;
private: private:
SkColor fColor; SkColor fColor;
SkXfermode::Mode fMode; SkXfermode::Mode fMode;
// cache // cache
SkPMColor fPMColor; SkPMColor fPMColor;
SkXfermodeProc fProc; SkXfermodeProc fProc;
SkPM4f fPM4f;
void updateCache(); void updateCache();

View File

@ -94,6 +94,7 @@ namespace SkOpts {
SkOpts::VoidFn body[] = { SkOpts::VoidFn body[] = {
(SkOpts::VoidFn)SK_OPTS_NS::just_return, (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_565,
(SkOpts::VoidFn)SK_OPTS_NS::store_srgb, (SkOpts::VoidFn)SK_OPTS_NS::store_srgb,
@ -144,6 +145,7 @@ namespace SkOpts {
SkOpts::VoidFn tail[] = { SkOpts::VoidFn tail[] = {
(SkOpts::VoidFn)SK_OPTS_NS::just_return, (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_565_tail,
(SkOpts::VoidFn)SK_OPTS_NS::store_srgb_tail, (SkOpts::VoidFn)SK_OPTS_NS::store_srgb_tail,

View File

@ -91,6 +91,7 @@ public:
enum StockStage { enum StockStage {
just_return, just_return,
swap_src_dst,
store_565, store_565,
store_srgb, store_srgb,

View File

@ -152,6 +152,13 @@ namespace SK_OPTS_NS {
STAGE(just_return, false) { } 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). // The default shader produces a constant color (from the SkPaint).
STAGE(constant_color, true) { STAGE(constant_color, true) {
auto color = (const SkPM4f*)ctx; auto color = (const SkPM4f*)ctx;