• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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