1 /*
2 * Copyright 2022 Google LLC
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/SkFlattenable.h"
10 #include "include/core/SkRefCnt.h"
11 #include "include/core/SkTypes.h"
12 #include "src/core/SkColorFilterBase.h"
13 #include "src/core/SkColorFilterPriv.h"
14 #include "src/core/SkEffectPriv.h"
15 #include "src/core/SkRasterPipeline.h"
16 #include "src/core/SkRasterPipelineOpList.h"
17 #include "src/core/SkVM.h"
18
19 #if defined(SK_GANESH)
20 #include "src/gpu/ganesh/GrFragmentProcessor.h"
21 // This shouldn't be needed but IWYU needs both (identical) defs of GrFPResult.
22 #include "src/shaders/SkShaderBase.h"
23 #include <memory>
24 #include <utility>
25
26 class GrColorInfo;
27 class GrRecordingContext;
28 class SkSurfaceProps;
29 #endif
30
31 class SkArenaAlloc;
32 class SkColorInfo;
33 class SkReadBuffer;
34 class SkWriteBuffer;
35
36 #if defined(SK_GRAPHITE)
37 #include "src/gpu/graphite/KeyContext.h"
38 #include "src/gpu/graphite/KeyHelpers.h"
39 #include "src/gpu/graphite/PaintParamsKey.h"
40
41 namespace skgpu::graphite {
42 class PipelineDataGatherer;
43 }
44 #endif
45
46 /**
47 * Remaps the input color's alpha to a Gaussian ramp and then outputs premul white using the
48 * remapped alpha.
49 */
50 class SkGaussianColorFilter final : public SkColorFilterBase {
51 public:
SkGaussianColorFilter()52 SkGaussianColorFilter() : SkColorFilterBase() {}
53
appendStages(const SkStageRec & rec,bool shaderIsOpaque) const54 bool appendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
55 rec.fPipeline->append(SkRasterPipelineOp::gauss_a_to_rgba);
56 return true;
57 }
58
59 #if defined(SK_GANESH)
60 GrFPResult asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
61 GrRecordingContext*,
62 const GrColorInfo&,
63 const SkSurfaceProps&) const override;
64 #endif
65
66 #if defined(SK_GRAPHITE)
67 void addToKey(const skgpu::graphite::KeyContext&,
68 skgpu::graphite::PaintParamsKeyBuilder*,
69 skgpu::graphite::PipelineDataGatherer*) const override;
70 #endif
71
72 protected:
flatten(SkWriteBuffer &) const73 void flatten(SkWriteBuffer&) const override {}
74
onProgram(skvm::Builder * p,skvm::Color c,const SkColorInfo & dst,skvm::Uniforms *,SkArenaAlloc *) const75 skvm::Color onProgram(skvm::Builder* p, skvm::Color c, const SkColorInfo& dst, skvm::Uniforms*,
76 SkArenaAlloc*) const override {
77 // x = 1 - x;
78 // exp(-x * x * 4) - 0.018f;
79 // ... now approximate with quartic
80 //
81 skvm::F32 x = p->splat(-2.26661229133605957031f);
82 x = c.a * x + 2.89795351028442382812f;
83 x = c.a * x + 0.21345567703247070312f;
84 x = c.a * x + 0.15489584207534790039f;
85 x = c.a * x + 0.00030726194381713867f;
86 return {x, x, x, x};
87 }
88
89 private:
90 SK_FLATTENABLE_HOOKS(SkGaussianColorFilter)
91 };
92
CreateProc(SkReadBuffer &)93 sk_sp<SkFlattenable> SkGaussianColorFilter::CreateProc(SkReadBuffer&) {
94 return SkColorFilterPriv::MakeGaussian();
95 }
96
97 #if defined(SK_GANESH)
98
99 #include "include/effects/SkRuntimeEffect.h"
100 #include "src/core/SkRuntimeEffectPriv.h"
101 #include "src/gpu/ganesh/effects/GrSkSLFP.h"
102
asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,GrRecordingContext *,const GrColorInfo &,const SkSurfaceProps &) const103 GrFPResult SkGaussianColorFilter::asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
104 GrRecordingContext*,
105 const GrColorInfo&,
106 const SkSurfaceProps&) const {
107 static const SkRuntimeEffect* effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
108 "half4 main(half4 inColor) {"
109 "half factor = 1 - inColor.a;"
110 "factor = exp(-factor * factor * 4) - 0.018;"
111 "return half4(factor);"
112 "}"
113 );
114 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
115 return GrFPSuccess(GrSkSLFP::Make(effect, "gaussian_fp", std::move(inputFP),
116 GrSkSLFP::OptFlags::kNone));
117 }
118 #endif
119
120 #if defined(SK_GRAPHITE)
121
addToKey(const skgpu::graphite::KeyContext & keyContext,skgpu::graphite::PaintParamsKeyBuilder * builder,skgpu::graphite::PipelineDataGatherer * gatherer) const122 void SkGaussianColorFilter::addToKey(const skgpu::graphite::KeyContext& keyContext,
123 skgpu::graphite::PaintParamsKeyBuilder* builder,
124 skgpu::graphite::PipelineDataGatherer* gatherer) const {
125 using namespace skgpu::graphite;
126
127 GaussianColorFilterBlock::BeginBlock(keyContext, builder, gatherer);
128 builder->endBlock();
129 }
130
131 #endif
132
MakeGaussian()133 sk_sp<SkColorFilter> SkColorFilterPriv::MakeGaussian() {
134 return sk_sp<SkColorFilter>(new SkGaussianColorFilter);
135 }
136