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