1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkColorFilter.h"
9 #include "include/core/SkRefCnt.h"
10 #include "include/core/SkString.h"
11 #include "include/core/SkUnPreMultiply.h"
12 #include "include/private/SkNx.h"
13 #include "include/private/SkTDArray.h"
14 #include "src/core/SkArenaAlloc.h"
15 #include "src/core/SkColorFilterPriv.h"
16 #include "src/core/SkColorSpacePriv.h"
17 #include "src/core/SkColorSpaceXformSteps.h"
18 #include "src/core/SkRasterPipeline.h"
19 #include "src/core/SkReadBuffer.h"
20 #include "src/core/SkWriteBuffer.h"
21 
22 #if SK_SUPPORT_GPU
23 #include "src/gpu/GrFragmentProcessor.h"
24 #include "src/gpu/effects/generated/GrMixerEffect.h"
25 #endif
26 
onAsAColorMode(SkColor *,SkBlendMode *) const27 bool SkColorFilter::onAsAColorMode(SkColor*, SkBlendMode*) const {
28     return false;
29 }
30 
onAsAColorMatrix(float matrix[20]) const31 bool SkColorFilter::onAsAColorMatrix(float matrix[20]) const {
32     return false;
33 }
34 
35 #if SK_SUPPORT_GPU
asFragmentProcessor(GrRecordingContext *,const GrColorInfo &) const36 std::unique_ptr<GrFragmentProcessor> SkColorFilter::asFragmentProcessor(GrRecordingContext*,
37                                                                         const GrColorInfo&) const {
38     return nullptr;
39 }
40 #endif
41 
appendStages(const SkStageRec & rec,bool shaderIsOpaque) const42 bool SkColorFilter::appendStages(const SkStageRec& rec, bool shaderIsOpaque) const {
43     return this->onAppendStages(rec, shaderIsOpaque);
44 }
45 
filterColor(SkColor c) const46 SkColor SkColorFilter::filterColor(SkColor c) const {
47     // This is mostly meaningless. We should phase-out this call entirely.
48     SkColorSpace* cs = nullptr;
49     return this->filterColor4f(SkColor4f::FromColor(c), cs, cs).toSkColor();
50 }
51 
filterColor4f(const SkColor4f & origSrcColor,SkColorSpace * srcCS,SkColorSpace * dstCS) const52 SkColor4f SkColorFilter::filterColor4f(const SkColor4f& origSrcColor, SkColorSpace* srcCS,
53                                        SkColorSpace* dstCS) const {
54 #ifdef SK_SUPPORT_LEGACY_COLORFILTER_NO_SHADER
55     SkPMColor4f src = origSrcColor.premul();
56     SkColor4f color = *(SkColor4f*)&src;
57 #else
58     SkColor4f color = origSrcColor;
59     SkColorSpaceXformSteps(srcCS, kUnpremul_SkAlphaType,
60                            dstCS, kPremul_SkAlphaType).apply(color.vec());
61 #endif
62 
63     constexpr size_t kEnoughForCommonFilters = 512; // big enough for compose+colormatrix
64     SkSTArenaAlloc<kEnoughForCommonFilters> alloc;
65     SkRasterPipeline    pipeline(&alloc);
66     pipeline.append_constant_color(&alloc, color.vec());
67     SkPaint dummyPaint;
68     SkStageRec rec = {
69         &pipeline, &alloc, kRGBA_F32_SkColorType, dstCS, dummyPaint, nullptr, SkMatrix::I()
70     };
71     this->onAppendStages(rec, color.fA == 1);
72 
73     SkPMColor4f dst;
74     SkRasterPipeline_MemoryCtx dstPtr = { &dst, 0 };
75     pipeline.append(SkRasterPipeline::store_f32, &dstPtr);
76     pipeline.run(0,0, 1,1);
77     return dst.unpremul();
78 }
79 
80 ///////////////////////////////////////////////////////////////////////////////////////////////////
81 
82 /*
83  *  Since colorfilters may be used on the GPU backend, and in that case we may string together
84  *  many GrFragmentProcessors, we might exceed some internal instruction/resource limit.
85  *
86  *  Since we don't yet know *what* those limits might be when we construct the final shader,
87  *  we just set an arbitrary limit during construction. If later we find smarter ways to know what
88  *  the limnits are, we can change this constant (or remove it).
89  */
90 #define SK_MAX_COMPOSE_COLORFILTER_COUNT    4
91 
92 class SkComposeColorFilter : public SkColorFilter {
93 public:
getFlags() const94     uint32_t getFlags() const override {
95         // Can only claim alphaunchanged support if both our proxys do.
96         return fOuter->getFlags() & fInner->getFlags();
97     }
98 
onAppendStages(const SkStageRec & rec,bool shaderIsOpaque) const99     bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
100         bool innerIsOpaque = shaderIsOpaque;
101         if (!(fInner->getFlags() & kAlphaUnchanged_Flag)) {
102             innerIsOpaque = false;
103         }
104         return fInner->appendStages(rec, shaderIsOpaque) &&
105                fOuter->appendStages(rec, innerIsOpaque);
106     }
107 
108 #if SK_SUPPORT_GPU
asFragmentProcessor(GrRecordingContext * context,const GrColorInfo & dstColorInfo) const109     std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
110             GrRecordingContext* context, const GrColorInfo& dstColorInfo) const override {
111         auto innerFP = fInner->asFragmentProcessor(context, dstColorInfo);
112         auto outerFP = fOuter->asFragmentProcessor(context, dstColorInfo);
113         if (!innerFP || !outerFP) {
114             return nullptr;
115         }
116         std::unique_ptr<GrFragmentProcessor> series[] = { std::move(innerFP), std::move(outerFP) };
117         return GrFragmentProcessor::RunInSeries(series, 2);
118     }
119 #endif
120 
121 protected:
flatten(SkWriteBuffer & buffer) const122     void flatten(SkWriteBuffer& buffer) const override {
123         buffer.writeFlattenable(fOuter.get());
124         buffer.writeFlattenable(fInner.get());
125     }
126 
127 private:
128     SK_FLATTENABLE_HOOKS(SkComposeColorFilter)
129 
SkComposeColorFilter(sk_sp<SkColorFilter> outer,sk_sp<SkColorFilter> inner,int composedFilterCount)130     SkComposeColorFilter(sk_sp<SkColorFilter> outer, sk_sp<SkColorFilter> inner,
131                          int composedFilterCount)
132         : fOuter(std::move(outer))
133         , fInner(std::move(inner))
134         , fComposedFilterCount(composedFilterCount)
135     {
136         SkASSERT(composedFilterCount >= 2);
137         SkASSERT(composedFilterCount <= SK_MAX_COMPOSE_COLORFILTER_COUNT);
138     }
139 
privateComposedFilterCount() const140     int privateComposedFilterCount() const override {
141         return fComposedFilterCount;
142     }
143 
144     sk_sp<SkColorFilter> fOuter;
145     sk_sp<SkColorFilter> fInner;
146     const int            fComposedFilterCount;
147 
148     friend class SkColorFilter;
149 
150     typedef SkColorFilter INHERITED;
151 };
152 
CreateProc(SkReadBuffer & buffer)153 sk_sp<SkFlattenable> SkComposeColorFilter::CreateProc(SkReadBuffer& buffer) {
154     sk_sp<SkColorFilter> outer(buffer.readColorFilter());
155     sk_sp<SkColorFilter> inner(buffer.readColorFilter());
156     return outer ? outer->makeComposed(std::move(inner)) : inner;
157 }
158 
159 
makeComposed(sk_sp<SkColorFilter> inner) const160 sk_sp<SkColorFilter> SkColorFilter::makeComposed(sk_sp<SkColorFilter> inner) const {
161     if (!inner) {
162         return sk_ref_sp(this);
163     }
164 
165     int count = inner->privateComposedFilterCount() + this->privateComposedFilterCount();
166     if (count > SK_MAX_COMPOSE_COLORFILTER_COUNT) {
167         return nullptr;
168     }
169     return sk_sp<SkColorFilter>(new SkComposeColorFilter(sk_ref_sp(this), std::move(inner), count));
170 }
171 
172 ///////////////////////////////////////////////////////////////////////////////////////////////////
173 
174 #if SK_SUPPORT_GPU
175 #include "src/gpu/effects/GrSRGBEffect.h"
176 #endif
177 
178 class SkSRGBGammaColorFilter : public SkColorFilter {
179 public:
180     enum class Direction {
181         kLinearToSRGB,
182         kSRGBToLinear,
183     };
__anon5cc7d1040102null184     SkSRGBGammaColorFilter(Direction dir) : fDir(dir), fSteps([&]{
185         // We handle premul/unpremul separately, so here just always upm->upm.
186         if (dir == Direction::kLinearToSRGB) {
187             return SkColorSpaceXformSteps{sk_srgb_linear_singleton(), kUnpremul_SkAlphaType,
188                                           sk_srgb_singleton(),        kUnpremul_SkAlphaType};
189         } else {
190             return SkColorSpaceXformSteps{sk_srgb_singleton(),        kUnpremul_SkAlphaType,
191                                           sk_srgb_linear_singleton(), kUnpremul_SkAlphaType};
192         }
193     }()) {}
194 
195 #if SK_SUPPORT_GPU
asFragmentProcessor(GrRecordingContext *,const GrColorInfo &) const196     std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(GrRecordingContext*,
197                                                              const GrColorInfo&) const override {
198         // wish our caller would let us know if our input was opaque...
199         GrSRGBEffect::Alpha alpha = GrSRGBEffect::Alpha::kPremul;
200         switch (fDir) {
201             case Direction::kLinearToSRGB:
202                 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kLinearToSRGB, alpha);
203             case Direction::kSRGBToLinear:
204                 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear, alpha);
205         }
206         return nullptr;
207     }
208 #endif
209 
onAppendStages(const SkStageRec & rec,bool shaderIsOpaque) const210     bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
211         if (!shaderIsOpaque) {
212             rec.fPipeline->append(SkRasterPipeline::unpremul);
213         }
214 
215         // TODO: is it valuable to thread this through appendStages()?
216         bool shaderIsNormalized = false;
217         fSteps.apply(rec.fPipeline, shaderIsNormalized);
218 
219         if (!shaderIsOpaque) {
220             rec.fPipeline->append(SkRasterPipeline::premul);
221         }
222         return true;
223     }
224 
225 protected:
flatten(SkWriteBuffer & buffer) const226     void flatten(SkWriteBuffer& buffer) const override {
227         buffer.write32(static_cast<uint32_t>(fDir));
228     }
229 
230 private:
231     SK_FLATTENABLE_HOOKS(SkSRGBGammaColorFilter)
232 
233     const Direction fDir;
234     SkColorSpaceXformSteps fSteps;
235 
236     friend class SkColorFilter;
237     typedef SkColorFilter INHERITED;
238 };
239 
CreateProc(SkReadBuffer & buffer)240 sk_sp<SkFlattenable> SkSRGBGammaColorFilter::CreateProc(SkReadBuffer& buffer) {
241     uint32_t dir = buffer.read32();
242     if (!buffer.validate(dir <= 1)) {
243         return nullptr;
244     }
245     return sk_sp<SkFlattenable>(new SkSRGBGammaColorFilter(static_cast<Direction>(dir)));
246 }
247 
248 template <SkSRGBGammaColorFilter::Direction dir>
MakeSRGBGammaCF()249 sk_sp<SkColorFilter> MakeSRGBGammaCF() {
250     static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir);
251     return sk_ref_sp(gSingleton);
252 }
253 
LinearToSRGBGamma()254 sk_sp<SkColorFilter> SkColorFilters::LinearToSRGBGamma() {
255     return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>();
256 }
257 
SRGBToLinearGamma()258 sk_sp<SkColorFilter> SkColorFilters::SRGBToLinearGamma() {
259     return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kSRGBToLinear>();
260 }
261 
262 ///////////////////////////////////////////////////////////////////////////////////////////////////
263 
264 class SkMixerColorFilter : public SkColorFilter {
265 public:
SkMixerColorFilter(sk_sp<SkColorFilter> cf0,sk_sp<SkColorFilter> cf1,float weight)266     SkMixerColorFilter(sk_sp<SkColorFilter> cf0, sk_sp<SkColorFilter> cf1, float weight)
267         : fCF0(std::move(cf0)), fCF1(std::move(cf1)), fWeight(weight)
268     {
269         SkASSERT(fCF0);
270         SkASSERT(fWeight >= 0 && fWeight <= 1);
271     }
272 
getFlags() const273     uint32_t getFlags() const override {
274         uint32_t f0 = fCF0->getFlags();
275         uint32_t f1 = fCF1 ? fCF1->getFlags() : ~0U;
276         return f0 & f1;
277     }
278 
onAppendStages(const SkStageRec & rec,bool shaderIsOpaque) const279     bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
280         // want cf0 * (1 - w) + cf1 * w == lerp(w)
281         // which means
282         //      dr,dg,db,da <-- cf0
283         //      r,g,b,a     <-- cf1
284         struct State {
285             float     orig_rgba[4 * SkRasterPipeline_kMaxStride];
286             float filtered_rgba[4 * SkRasterPipeline_kMaxStride];
287         };
288         auto state = rec.fAlloc->make<State>();
289         SkRasterPipeline* p = rec.fPipeline;
290 
291         p->append(SkRasterPipeline::store_src, state->orig_rgba);
292         if (!fCF1) {
293             fCF0->appendStages(rec, shaderIsOpaque);
294             p->append(SkRasterPipeline::move_src_dst);
295             p->append(SkRasterPipeline::load_src, state->orig_rgba);
296         } else {
297             fCF0->appendStages(rec, shaderIsOpaque);
298             p->append(SkRasterPipeline::store_src, state->filtered_rgba);
299             p->append(SkRasterPipeline::load_src, state->orig_rgba);
300             fCF1->appendStages(rec, shaderIsOpaque);
301             p->append(SkRasterPipeline::load_dst, state->filtered_rgba);
302         }
303         float* storage = rec.fAlloc->make<float>(fWeight);
304         p->append(SkRasterPipeline::lerp_1_float, storage);
305         return true;
306     }
307 
308 #if SK_SUPPORT_GPU
asFragmentProcessor(GrRecordingContext * context,const GrColorInfo & dstColorInfo) const309     std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
310             GrRecordingContext* context, const GrColorInfo& dstColorInfo) const override {
311         return GrMixerEffect::Make(
312                 fCF0->asFragmentProcessor(context, dstColorInfo),
313                 fCF1 ? fCF1->asFragmentProcessor(context, dstColorInfo) : nullptr,
314                 fWeight);
315     }
316 #endif
317 
318 protected:
flatten(SkWriteBuffer & buffer) const319     void flatten(SkWriteBuffer& buffer) const override {
320         buffer.writeFlattenable(fCF0.get());
321         buffer.writeFlattenable(fCF1.get());
322         buffer.writeScalar(fWeight);
323     }
324 
325 private:
326     SK_FLATTENABLE_HOOKS(SkMixerColorFilter)
327 
328     sk_sp<SkColorFilter> fCF0;
329     sk_sp<SkColorFilter> fCF1;
330     const float          fWeight;
331 
332     friend class SkColorFilter;
333 
334     typedef SkColorFilter INHERITED;
335 };
336 
CreateProc(SkReadBuffer & buffer)337 sk_sp<SkFlattenable> SkMixerColorFilter::CreateProc(SkReadBuffer& buffer) {
338     sk_sp<SkColorFilter> cf0(buffer.readColorFilter());
339     sk_sp<SkColorFilter> cf1(buffer.readColorFilter());
340     const float weight = buffer.readScalar();
341     return SkColorFilters::Lerp(weight, std::move(cf0), std::move(cf1));
342 }
343 
Lerp(float weight,sk_sp<SkColorFilter> cf0,sk_sp<SkColorFilter> cf1)344 sk_sp<SkColorFilter> SkColorFilters::Lerp(float weight, sk_sp<SkColorFilter> cf0,
345                                                         sk_sp<SkColorFilter> cf1) {
346     if (!cf0 && !cf1) {
347         return nullptr;
348     }
349     if (SkScalarIsNaN(weight)) {
350         return nullptr;
351     }
352 
353     if (cf0 == cf1) {
354         return cf0; // or cf1
355     }
356 
357     if (weight <= 0) {
358         return cf0;
359     }
360     if (weight >= 1) {
361         return cf1;
362     }
363 
364     return sk_sp<SkColorFilter>(cf0
365             ? new SkMixerColorFilter(std::move(cf0), std::move(cf1), weight)
366             : new SkMixerColorFilter(std::move(cf1), nullptr, 1 - weight));
367 }
368 
369 ///////////////////////////////////////////////////////////////////////////////////////////////////
370 
371 #include "include/private/SkMutex.h"
372 
373 #if SK_SUPPORT_GPU
374 #include "include/private/GrRecordingContext.h"
375 #include "src/gpu/effects/GrSkSLFP.h"
376 #include "src/sksl/SkSLByteCode.h"
377 
378 class SkRuntimeColorFilter : public SkColorFilter {
379 public:
SkRuntimeColorFilter(int index,SkString sksl,sk_sp<SkData> inputs,void (* cpuFunction)(float[4],const void *))380     SkRuntimeColorFilter(int index, SkString sksl, sk_sp<SkData> inputs,
381                          void (*cpuFunction)(float[4], const void*))
382         : fIndex(index)
383         , fSkSL(std::move(sksl))
384         , fInputs(std::move(inputs))
385         , fCpuFunction(cpuFunction) {}
386 
387 #if SK_SUPPORT_GPU
asFragmentProcessor(GrRecordingContext * context,const GrColorInfo &) const388     std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(GrRecordingContext* context,
389                                                              const GrColorInfo&) const override {
390         return GrSkSLFP::Make(context, fIndex, "Runtime Color Filter", fSkSL,
391                               fInputs ? fInputs->data() : nullptr,
392                               fInputs ? fInputs->size() : 0);
393     }
394 #endif
395 
onAppendStages(const SkStageRec & rec,bool shaderIsOpaque) const396     bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
397         if (fCpuFunction) {
398             struct CpuFuncCtx : public SkRasterPipeline_CallbackCtx {
399                 SkRuntimeColorFilterFn cpuFn;
400                 const void* inputs;
401             };
402             auto ctx = rec.fAlloc->make<CpuFuncCtx>();
403             ctx->inputs = fInputs->data();
404             ctx->cpuFn = fCpuFunction;
405             ctx->fn = [](SkRasterPipeline_CallbackCtx* arg, int active_pixels) {
406                 auto ctx = (CpuFuncCtx*)arg;
407                 for (int i = 0; i < active_pixels; i++) {
408                     ctx->cpuFn(ctx->rgba + i * 4, ctx->inputs);
409                 }
410             };
411             rec.fPipeline->append(SkRasterPipeline::callback, ctx);
412         } else {
413             auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
414             // don't need to set ctx->paintColor
415             ctx->inputs = fInputs->data();
416             ctx->ninputs = fInputs->size() / 4;
417             ctx->shaderConvention = false;
418 
419             SkAutoMutexExclusive ama(fByteCodeMutex);
420             if (!fByteCode) {
421                 SkSL::Compiler c;
422                 auto prog = c.convertProgram(SkSL::Program::kPipelineStage_Kind,
423                                              SkSL::String(fSkSL.c_str()),
424                                              SkSL::Program::Settings());
425                 if (c.errorCount()) {
426                     SkDebugf("%s\n", c.errorText().c_str());
427                     return false;
428                 }
429                 fByteCode = c.toByteCode(*prog);
430             }
431             ctx->byteCode = fByteCode.get();
432             ctx->fn = ctx->byteCode->getFunction("main");
433             rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
434         }
435         return true;
436     }
437 
438 protected:
flatten(SkWriteBuffer & buffer) const439     void flatten(SkWriteBuffer& buffer) const override {
440         // the client is responsible for ensuring that the indices match up between flattening and
441         // unflattening; we don't have a reasonable way to enforce that at the moment
442         buffer.writeInt(fIndex);
443         buffer.writeString(fSkSL.c_str());
444         if (fInputs) {
445             buffer.writeDataAsByteArray(fInputs.get());
446         } else {
447             buffer.writeByteArray(nullptr, 0);
448         }
449     }
450 
451 private:
452     SK_FLATTENABLE_HOOKS(SkRuntimeColorFilter)
453 
454     int fIndex;
455     SkString fSkSL;
456     sk_sp<SkData> fInputs;
457     SkRuntimeColorFilterFn fCpuFunction;
458 
459     mutable SkMutex fByteCodeMutex;
460     mutable std::unique_ptr<SkSL::ByteCode> fByteCode;
461 
462     friend class SkColorFilter;
463 
464     typedef SkColorFilter INHERITED;
465 };
466 
CreateProc(SkReadBuffer & buffer)467 sk_sp<SkFlattenable> SkRuntimeColorFilter::CreateProc(SkReadBuffer& buffer) {
468     int index = buffer.readInt();
469     SkString sksl;
470     buffer.readString(&sksl);
471     sk_sp<SkData> inputs = buffer.readByteArrayAsData();
472     return sk_sp<SkFlattenable>(new SkRuntimeColorFilter(index, std::move(sksl), std::move(inputs),
473                                                          nullptr));
474 }
475 
SkRuntimeColorFilterFactory(SkString sksl,SkRuntimeColorFilterFn cpuFunc)476 SkRuntimeColorFilterFactory::SkRuntimeColorFilterFactory(SkString sksl,
477                                                          SkRuntimeColorFilterFn cpuFunc)
478     : fIndex(GrSkSLFP::NewIndex())
479     , fSkSL(std::move(sksl))
480     , fCpuFunc(cpuFunc) {}
481 
make(sk_sp<SkData> inputs)482 sk_sp<SkColorFilter> SkRuntimeColorFilterFactory::make(sk_sp<SkData> inputs) {
483     return sk_sp<SkColorFilter>(new SkRuntimeColorFilter(fIndex, fSkSL, std::move(inputs),
484                                                          fCpuFunc));
485 }
486 
487 #endif // SK_SUPPORT_GPU
488 
489 ///////////////////////////////////////////////////////////////////////////////////////////////////
490 
491 #include "src/core/SkModeColorFilter.h"
492 
RegisterFlattenables()493 void SkColorFilter::RegisterFlattenables() {
494     SK_REGISTER_FLATTENABLE(SkComposeColorFilter);
495     SK_REGISTER_FLATTENABLE(SkModeColorFilter);
496     SK_REGISTER_FLATTENABLE(SkSRGBGammaColorFilter);
497     SK_REGISTER_FLATTENABLE(SkMixerColorFilter);
498 #if SK_SUPPORT_GPU
499     SK_REGISTER_FLATTENABLE(SkRuntimeColorFilter);
500 #endif
501 }
502