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