1/*
2 * Copyright 2015 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 "SkArithmeticMode_gpu.h"
9
10#if SK_SUPPORT_GPU
11#include "GrContext.h"
12#include "GrFragmentProcessor.h"
13#include "GrInvariantOutput.h"
14#include "GrProcessor.h"
15#include "GrTexture.h"
16#include "glsl/GrGLSLFragmentProcessor.h"
17#include "glsl/GrGLSLFragmentShaderBuilder.h"
18#include "glsl/GrGLSLProgramDataManager.h"
19#include "glsl/GrGLSLUniformHandler.h"
20#include "glsl/GrGLSLXferProcessor.h"
21
22static void add_arithmetic_code(GrGLSLFragmentBuilder* fragBuilder,
23                                const char* srcColor,
24                                const char* dstColor,
25                                const char* outputColor,
26                                const char* kUni,
27                                bool enforcePMColor) {
28    // We don't try to optimize for this case at all
29    if (nullptr == srcColor) {
30        fragBuilder->codeAppend("const vec4 src = vec4(1);");
31    } else {
32        fragBuilder->codeAppendf("vec4 src = %s;", srcColor);
33    }
34
35    fragBuilder->codeAppendf("vec4 dst = %s;", dstColor);
36    fragBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;",
37                             outputColor, kUni, kUni, kUni, kUni);
38    fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
39    if (enforcePMColor) {
40        fragBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);",
41                                 outputColor, outputColor, outputColor);
42    }
43}
44
45class GLArithmeticFP : public GrGLSLFragmentProcessor {
46public:
47    void emitCode(EmitArgs& args) override {
48        const GrArithmeticFP& arith = args.fFp.cast<GrArithmeticFP>();
49
50        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
51        SkString dstColor("dstColor");
52        this->emitChild(0, nullptr, &dstColor, args);
53
54        fKUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
55                                                 kVec4f_GrSLType, kDefault_GrSLPrecision,
56                                                 "k");
57        const char* kUni = args.fUniformHandler->getUniformCStr(fKUni);
58
59        add_arithmetic_code(fragBuilder,
60                            args.fInputColor,
61                            dstColor.c_str(),
62                            args.fOutputColor,
63                            kUni,
64                            arith.enforcePMColor());
65    }
66
67    static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
68        const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>();
69        uint32_t key = arith.enforcePMColor() ? 1 : 0;
70        b->add32(key);
71    }
72
73protected:
74    void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
75        const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>();
76        pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
77    }
78
79private:
80    GrGLSLProgramDataManager::UniformHandle fKUni;
81
82    typedef GrGLSLFragmentProcessor INHERITED;
83};
84
85///////////////////////////////////////////////////////////////////////////////
86
87GrArithmeticFP::GrArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor,
88                               const GrFragmentProcessor* dst)
89  : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
90    this->initClassID<GrArithmeticFP>();
91
92    SkASSERT(dst);
93    SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst);
94    SkASSERT(0 == dstIndex);
95}
96
97void GrArithmeticFP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
98    GLArithmeticFP::GenKey(*this, caps, b);
99}
100
101GrGLSLFragmentProcessor* GrArithmeticFP::onCreateGLSLInstance() const {
102    return new GLArithmeticFP;
103}
104
105bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& fpBase) const {
106    const GrArithmeticFP& fp = fpBase.cast<GrArithmeticFP>();
107    return fK1 == fp.fK1 &&
108           fK2 == fp.fK2 &&
109           fK3 == fp.fK3 &&
110           fK4 == fp.fK4 &&
111           fEnforcePMColor == fp.fEnforcePMColor;
112}
113
114void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
115    // TODO: optimize this
116    inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
117}
118
119///////////////////////////////////////////////////////////////////////////////
120
121const GrFragmentProcessor* GrArithmeticFP::TestCreate(GrProcessorTestData* d) {
122    float k1 = d->fRandom->nextF();
123    float k2 = d->fRandom->nextF();
124    float k3 = d->fRandom->nextF();
125    float k4 = d->fRandom->nextF();
126    bool enforcePMColor = d->fRandom->nextBool();
127
128    SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d));
129    return new GrArithmeticFP(k1, k2, k3, k4, enforcePMColor, dst);
130}
131
132GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP);
133
134///////////////////////////////////////////////////////////////////////////////
135// Xfer Processor
136///////////////////////////////////////////////////////////////////////////////
137
138class ArithmeticXP : public GrXferProcessor {
139public:
140    ArithmeticXP(const DstTexture*, bool hasMixedSamples,
141                 float k1, float k2, float k3, float k4, bool enforcePMColor);
142
143    const char* name() const override { return "Arithmetic"; }
144
145    GrGLSLXferProcessor* createGLSLInstance() const override;
146
147    float k1() const { return fK1; }
148    float k2() const { return fK2; }
149    float k3() const { return fK3; }
150    float k4() const { return fK4; }
151    bool enforcePMColor() const { return fEnforcePMColor; }
152
153private:
154    GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
155                                                 bool doesStencilWrite,
156                                                 GrColor* overrideColor,
157                                                 const GrCaps& caps) const override;
158
159    void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
160
161    bool onIsEqual(const GrXferProcessor& xpBase) const override {
162        const ArithmeticXP& xp = xpBase.cast<ArithmeticXP>();
163        if (fK1 != xp.fK1 ||
164            fK2 != xp.fK2 ||
165            fK3 != xp.fK3 ||
166            fK4 != xp.fK4 ||
167            fEnforcePMColor != xp.fEnforcePMColor) {
168            return false;
169        }
170        return true;
171    }
172
173    float                       fK1, fK2, fK3, fK4;
174    bool                        fEnforcePMColor;
175
176    typedef GrXferProcessor INHERITED;
177};
178
179///////////////////////////////////////////////////////////////////////////////
180
181class GLArithmeticXP : public GrGLSLXferProcessor {
182public:
183    GLArithmeticXP(const ArithmeticXP& arithmeticXP)
184        : fEnforcePMColor(arithmeticXP.enforcePMColor()) {
185    }
186
187    ~GLArithmeticXP() override {}
188
189    static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
190                       GrProcessorKeyBuilder* b) {
191        const ArithmeticXP& arith = processor.cast<ArithmeticXP>();
192        uint32_t key = arith.enforcePMColor() ? 1 : 0;
193        b->add32(key);
194    }
195
196private:
197    void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
198                                 GrGLSLUniformHandler* uniformHandler,
199                                 const char* srcColor,
200                                 const char* srcCoverage,
201                                 const char* dstColor,
202                                 const char* outColor,
203                                 const char* outColorSecondary,
204                                 const GrXferProcessor& proc) override {
205        fKUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
206                                           kVec4f_GrSLType, kDefault_GrSLPrecision,
207                                           "k");
208        const char* kUni = uniformHandler->getUniformCStr(fKUni);
209
210        add_arithmetic_code(fragBuilder, srcColor, dstColor, outColor, kUni, fEnforcePMColor);
211
212        // Apply coverage.
213        INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor,
214                                             outColorSecondary, proc);
215    }
216
217    void onSetData(const GrGLSLProgramDataManager& pdman,
218                   const GrXferProcessor& processor) override {
219        const ArithmeticXP& arith = processor.cast<ArithmeticXP>();
220        pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
221        fEnforcePMColor = arith.enforcePMColor();
222    };
223
224    GrGLSLProgramDataManager::UniformHandle fKUni;
225    bool fEnforcePMColor;
226
227    typedef GrGLSLXferProcessor INHERITED;
228};
229
230///////////////////////////////////////////////////////////////////////////////
231
232ArithmeticXP::ArithmeticXP(const DstTexture* dstTexture, bool hasMixedSamples,
233                           float k1, float k2, float k3, float k4, bool enforcePMColor)
234    : INHERITED(dstTexture, true, hasMixedSamples)
235    , fK1(k1)
236    , fK2(k2)
237    , fK3(k3)
238    , fK4(k4)
239    , fEnforcePMColor(enforcePMColor) {
240    this->initClassID<ArithmeticXP>();
241}
242
243void ArithmeticXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
244    GLArithmeticXP::GenKey(*this, caps, b);
245}
246
247GrGLSLXferProcessor* ArithmeticXP::createGLSLInstance() const { return new GLArithmeticXP(*this); }
248
249GrXferProcessor::OptFlags ArithmeticXP::onGetOptimizations(
250                                                       const GrPipelineOptimizations& optimizations,
251                                                       bool doesStencilWrite,
252                                                       GrColor* overrideColor,
253                                                       const GrCaps& caps) const {
254   return GrXferProcessor::kNone_OptFlags;
255}
256
257///////////////////////////////////////////////////////////////////////////////
258
259GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float k4,
260                                             bool enforcePMColor)
261    : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
262    this->initClassID<GrArithmeticXPFactory>();
263}
264
265GrXferProcessor*
266GrArithmeticXPFactory::onCreateXferProcessor(const GrCaps& caps,
267                                             const GrPipelineOptimizations& optimizations,
268                                             bool hasMixedSamples,
269                                             const DstTexture* dstTexture) const {
270    return new ArithmeticXP(dstTexture, hasMixedSamples, fK1, fK2, fK3, fK4, fEnforcePMColor);
271}
272
273
274void GrArithmeticXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
275                                                     InvariantBlendedColor* blendedColor) const {
276    blendedColor->fWillBlendWithDst = true;
277
278    // TODO: We could try to optimize this more. For example if fK1 and fK3 are zero, then we won't
279    // be blending the color with dst at all so we can know what the output color is (up to the
280    // valid color components passed in).
281    blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
282}
283
284GR_DEFINE_XP_FACTORY_TEST(GrArithmeticXPFactory);
285
286const GrXPFactory* GrArithmeticXPFactory::TestCreate(GrProcessorTestData* d) {
287    float k1 = d->fRandom->nextF();
288    float k2 = d->fRandom->nextF();
289    float k3 = d->fRandom->nextF();
290    float k4 = d->fRandom->nextF();
291    bool enforcePMColor = d->fRandom->nextBool();
292
293    return GrArithmeticXPFactory::Create(k1, k2, k3, k4, enforcePMColor);
294}
295
296#endif
297