1 /*
2  * Copyright 2016 Google Inc.
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 "GrAlphaThresholdFragmentProcessor.h"
9 
10 #if SK_SUPPORT_GPU
11 
12 #include "GrContext.h"
13 #include "SkRefCnt.h"
14 #include "glsl/GrGLSLColorSpaceXformHelper.h"
15 #include "glsl/GrGLSLFragmentProcessor.h"
16 #include "glsl/GrGLSLFragmentShaderBuilder.h"
17 #include "glsl/GrGLSLUniformHandler.h"
18 #include "../private/GrGLSL.h"
19 
OptFlags(float outerThreshold)20 inline GrFragmentProcessor::OptimizationFlags GrAlphaThresholdFragmentProcessor::OptFlags(float outerThreshold) {
21     if (outerThreshold >= 1.f) {
22         return kPreservesOpaqueInput_OptimizationFlag |
23                kCompatibleWithCoverageAsAlpha_OptimizationFlag;
24     } else {
25         return kCompatibleWithCoverageAsAlpha_OptimizationFlag;
26     }
27 }
28 
GrAlphaThresholdFragmentProcessor(GrResourceProvider * resourceProvider,sk_sp<GrTextureProxy> proxy,sk_sp<GrColorSpaceXform> colorSpaceXform,sk_sp<GrTextureProxy> maskProxy,float innerThreshold,float outerThreshold,const SkIRect & bounds)29 GrAlphaThresholdFragmentProcessor::GrAlphaThresholdFragmentProcessor(
30                                                            GrResourceProvider* resourceProvider,
31                                                            sk_sp<GrTextureProxy> proxy,
32                                                            sk_sp<GrColorSpaceXform> colorSpaceXform,
33                                                            sk_sp<GrTextureProxy> maskProxy,
34                                                            float innerThreshold,
35                                                            float outerThreshold,
36                                                            const SkIRect& bounds)
37         : INHERITED(OptFlags(outerThreshold))
38         , fInnerThreshold(innerThreshold)
39         , fOuterThreshold(outerThreshold)
40         , fImageCoordTransform(resourceProvider, SkMatrix::I(), proxy.get(),
41                                GrSamplerParams::kNone_FilterMode)
42         , fImageTextureSampler(resourceProvider, std::move(proxy))
43         , fColorSpaceXform(std::move(colorSpaceXform))
44         , fMaskCoordTransform(
45                   resourceProvider,
46                   SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())),
47                   maskProxy.get(),
48                   GrSamplerParams::kNone_FilterMode)
49         , fMaskTextureSampler(resourceProvider, maskProxy) {
50     this->initClassID<GrAlphaThresholdFragmentProcessor>();
51     this->addCoordTransform(&fImageCoordTransform);
52     this->addTextureSampler(&fImageTextureSampler);
53     this->addCoordTransform(&fMaskCoordTransform);
54     this->addTextureSampler(&fMaskTextureSampler);
55 }
56 
onIsEqual(const GrFragmentProcessor & sBase) const57 bool GrAlphaThresholdFragmentProcessor::onIsEqual(const GrFragmentProcessor& sBase) const {
58     const GrAlphaThresholdFragmentProcessor& s = sBase.cast<GrAlphaThresholdFragmentProcessor>();
59     return (this->fInnerThreshold == s.fInnerThreshold &&
60             this->fOuterThreshold == s.fOuterThreshold);
61 }
62 
63 ///////////////////////////////////////////////////////////////////////////////
64 
65 class GrGLAlphaThresholdFragmentProcessor : public GrGLSLFragmentProcessor {
66 public:
67     void emitCode(EmitArgs&) override;
68 
GenKey(const GrProcessor & effect,const GrShaderCaps &,GrProcessorKeyBuilder * b)69     static inline void GenKey(const GrProcessor& effect, const GrShaderCaps&,
70                               GrProcessorKeyBuilder* b) {
71         const GrAlphaThresholdFragmentProcessor& atfp =
72             effect.cast<GrAlphaThresholdFragmentProcessor>();
73         b->add32(GrColorSpaceXform::XformKey(atfp.colorSpaceXform()));
74     }
75 
76 protected:
77     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
78 
79 private:
80     GrGLSLProgramDataManager::UniformHandle fInnerThresholdVar;
81     GrGLSLProgramDataManager::UniformHandle fOuterThresholdVar;
82     GrGLSLColorSpaceXformHelper fColorSpaceHelper;
83     typedef GrGLSLFragmentProcessor INHERITED;
84 };
85 
emitCode(EmitArgs & args)86 void GrGLAlphaThresholdFragmentProcessor::emitCode(EmitArgs& args) {
87     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
88     fInnerThresholdVar = uniformHandler->addUniform(kFragment_GrShaderFlag,
89                                                     kFloat_GrSLType, kDefault_GrSLPrecision,
90                                                     "inner_threshold");
91     fOuterThresholdVar = uniformHandler->addUniform(kFragment_GrShaderFlag,
92                                                     kFloat_GrSLType, kDefault_GrSLPrecision,
93                                                     "outer_threshold");
94 
95     const GrAlphaThresholdFragmentProcessor& atfp =
96         args.fFp.cast<GrAlphaThresholdFragmentProcessor>();
97     fColorSpaceHelper.emitCode(uniformHandler, atfp.colorSpaceXform());
98 
99     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
100     SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
101     SkString maskCoords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[1]);
102 
103     fragBuilder->codeAppendf("vec2 coord = %s;", coords2D.c_str());
104     fragBuilder->codeAppendf("vec2 mask_coord = %s;", maskCoords2D.c_str());
105     fragBuilder->codeAppend("vec4 input_color = ");
106     fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord", kVec2f_GrSLType,
107                                      &fColorSpaceHelper);
108     fragBuilder->codeAppend(";");
109     fragBuilder->codeAppend("vec4 mask_color = ");
110     fragBuilder->appendTextureLookup(args.fTexSamplers[1], "mask_coord");
111     fragBuilder->codeAppend(";");
112 
113     fragBuilder->codeAppendf("float inner_thresh = %s;",
114                              uniformHandler->getUniformCStr(fInnerThresholdVar));
115     fragBuilder->codeAppendf("float outer_thresh = %s;",
116                              uniformHandler->getUniformCStr(fOuterThresholdVar));
117     fragBuilder->codeAppend("float mask = mask_color.a;");
118 
119     fragBuilder->codeAppend("vec4 color = input_color;");
120     fragBuilder->codeAppend("if (mask < 0.5) {"
121                             "if (color.a > outer_thresh) {"
122                             "float scale = outer_thresh / color.a;"
123                             "color.rgb *= scale;"
124                             "color.a = outer_thresh;"
125                             "}"
126                             "} else if (color.a < inner_thresh) {"
127                             "float scale = inner_thresh / max(0.001, color.a);"
128                             "color.rgb *= scale;"
129                             "color.a = inner_thresh;"
130                             "}");
131 
132     fragBuilder->codeAppendf("%s = %s;", args.fOutputColor,
133                              (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr4("color")).c_str());
134 }
135 
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & proc)136 void GrGLAlphaThresholdFragmentProcessor::onSetData(const GrGLSLProgramDataManager& pdman,
137                                                     const GrProcessor& proc) {
138     const GrAlphaThresholdFragmentProcessor& atfp = proc.cast<GrAlphaThresholdFragmentProcessor>();
139     pdman.set1f(fInnerThresholdVar, atfp.innerThreshold());
140     pdman.set1f(fOuterThresholdVar, atfp.outerThreshold());
141     if (SkToBool(atfp.colorSpaceXform())) {
142         fColorSpaceHelper.setData(pdman, atfp.colorSpaceXform());
143     }
144 }
145 
146 /////////////////////////////////////////////////////////////////////
147 
148 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrAlphaThresholdFragmentProcessor);
149 
150 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)151 sk_sp<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::TestCreate(GrProcessorTestData* d) {
152     sk_sp<GrTextureProxy> bmpProxy = d->textureProxy(GrProcessorUnitTest::kSkiaPMTextureIdx);
153     sk_sp<GrTextureProxy> maskProxy = d->textureProxy(GrProcessorUnitTest::kAlphaTextureIdx);
154     // Make the inner and outer thresholds be in (0, 1) exclusive and be sorted correctly.
155     float innerThresh = d->fRandom->nextUScalar1() * .99f + 0.005f;
156     float outerThresh = d->fRandom->nextUScalar1() * .99f + 0.005f;
157     const int kMaxWidth = 1000;
158     const int kMaxHeight = 1000;
159     uint32_t width = d->fRandom->nextULessThan(kMaxWidth);
160     uint32_t height = d->fRandom->nextULessThan(kMaxHeight);
161     uint32_t x = d->fRandom->nextULessThan(kMaxWidth - width);
162     uint32_t y = d->fRandom->nextULessThan(kMaxHeight - height);
163     SkIRect bounds = SkIRect::MakeXYWH(x, y, width, height);
164     sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(d->fRandom);
165     return GrAlphaThresholdFragmentProcessor::Make(d->resourceProvider(),
166                                                    std::move(bmpProxy),
167                                                    std::move(colorSpaceXform),
168                                                    std::move(maskProxy),
169                                                    innerThresh, outerThresh,
170                                                    bounds);
171 }
172 #endif
173 
174 ///////////////////////////////////////////////////////////////////////////////
175 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const176 void GrAlphaThresholdFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
177                                                               GrProcessorKeyBuilder* b) const {
178     GrGLAlphaThresholdFragmentProcessor::GenKey(*this, caps, b);
179 }
180 
onCreateGLSLInstance() const181 GrGLSLFragmentProcessor* GrAlphaThresholdFragmentProcessor::onCreateGLSLInstance() const {
182     return new GrGLAlphaThresholdFragmentProcessor;
183 }
184 
185 #endif
186