C++11 override should now be supported by all of {bots,Chrome,Android,Mozilla}
[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/GrGLCaps.h"
17 #include "gl/GrGLProcessor.h"
18 #include "gl/GrGLProgramDataManager.h"
19 #include "gl/builders/GrGLProgramBuilder.h"
20
21 static const bool gUseUnpremul = false;
22
23 static void add_arithmetic_code(GrGLFPFragmentBuilder* fsBuilder,
24                                 const char* inputColor,
25                                 const char* dstColor,
26                                 const char* outputColor,
27                                 const char* kUni,
28                                 bool enforcePMColor) {
29     // We don't try to optimize for this case at all
30     if (NULL == inputColor) {
31         fsBuilder->codeAppend("const vec4 src = vec4(1);");
32     } else {
33         fsBuilder->codeAppendf("vec4 src = %s;", inputColor);
34         if (gUseUnpremul) {
35             fsBuilder->codeAppend("src.rgb = clamp(src.rgb / src.a, 0.0, 1.0);");
36         }
37     }
38
39     fsBuilder->codeAppendf("vec4 dst = %s;", dstColor);
40     if (gUseUnpremul) {
41         fsBuilder->codeAppend("dst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);");
42     }
43
44     fsBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;",
45                            outputColor, kUni, kUni, kUni, kUni);
46     fsBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
47     if (gUseUnpremul) {
48         fsBuilder->codeAppendf("%s.rgb *= %s.a;", outputColor, outputColor);
49     } else if (enforcePMColor) {
50         fsBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);",
51                                outputColor, outputColor, outputColor);
52     }
53 }
54
55 class GLArithmeticFP : public GrGLFragmentProcessor {
56 public:
57     GLArithmeticFP(const GrProcessor&)
58         : fEnforcePMColor(true) {
59     }
60
61     ~GLArithmeticFP() override {}
62
63     void emitCode(GrGLFPBuilder* builder,
64                   const GrFragmentProcessor& fp,
65                   const char* outputColor,
66                   const char* inputColor,
67                   const TransformedCoordsArray& coords,
68                   const TextureSamplerArray& samplers) override {
69         GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
70         fsBuilder->codeAppend("vec4 bgColor = ");
71         fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType());
72         fsBuilder->codeAppendf(";");
73         const char* dstColor = "bgColor";
74
75         fKUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
76                                     kVec4f_GrSLType, kDefault_GrSLPrecision,
77                                     "k");
78         const char* kUni = builder->getUniformCStr(fKUni);
79
80         add_arithmetic_code(fsBuilder, inputColor, dstColor, outputColor, kUni, fEnforcePMColor);
81     }
82
83     void setData(const GrGLProgramDataManager& pdman, const GrProcessor& proc) override {
84         const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>();
85         pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
86         fEnforcePMColor = arith.enforcePMColor();
87     }
88
89     static void GenKey(const GrProcessor& proc, const GrGLCaps& caps, GrProcessorKeyBuilder* b) {
90         const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>();
91         uint32_t key = arith.enforcePMColor() ? 1 : 0;
92         b->add32(key);
93     }
94
95 private:
96     GrGLProgramDataManager::UniformHandle fKUni;
97     bool fEnforcePMColor;
98
99     typedef GrGLFragmentProcessor INHERITED;
100 };
101
102 ///////////////////////////////////////////////////////////////////////////////
103
104 GrArithmeticFP::GrArithmeticFP(float k1, float k2, float k3, float k4,
105                                bool enforcePMColor, GrTexture* background)
106   : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
107     this->initClassID<GrArithmeticFP>();
108
109     SkASSERT(background);
110
111     fBackgroundTransform.reset(kLocal_GrCoordSet, background,
112                                GrTextureParams::kNone_FilterMode);
113     this->addCoordTransform(&fBackgroundTransform);
114     fBackgroundAccess.reset(background);
115     this->addTextureAccess(&fBackgroundAccess);
116 }
117
118 void GrArithmeticFP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const {
119     GLArithmeticFP::GenKey(*this, caps, b);
120 }
121
122 GrGLFragmentProcessor* GrArithmeticFP::createGLInstance() const {
123     return SkNEW_ARGS(GLArithmeticFP, (*this));
124 }
125
126 bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& fpBase) const {
127     const GrArithmeticFP& fp = fpBase.cast<GrArithmeticFP>();
128     return fK1 == fp.fK1 &&
129            fK2 == fp.fK2 &&
130            fK3 == fp.fK3 &&
131            fK4 == fp.fK4 &&
132            fEnforcePMColor == fp.fEnforcePMColor;
133 }
134
135 void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
136     // TODO: optimize this
137     inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
138 }
139
140 ///////////////////////////////////////////////////////////////////////////////
141
142 GrFragmentProcessor* GrArithmeticFP::TestCreate(SkRandom* rand,
143                                                 GrContext*,
144                                                 const GrDrawTargetCaps&,
145                                                 GrTexture* textures[]) {
146     float k1 = rand->nextF();
147     float k2 = rand->nextF();
148     float k3 = rand->nextF();
149     float k4 = rand->nextF();
150     bool enforcePMColor = rand->nextBool();
151
152     return SkNEW_ARGS(GrArithmeticFP, (k1, k2, k3, k4, enforcePMColor, textures[0]));
153 }
154
155 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP);
156
157 ///////////////////////////////////////////////////////////////////////////////
158 // Xfer Processor
159 ///////////////////////////////////////////////////////////////////////////////
160
161 class ArithmeticXP : public GrXferProcessor {
162 public:
163     static GrXferProcessor* Create(float k1, float k2, float k3, float k4, bool enforcePMColor,
164                                    const GrDeviceCoordTexture* dstCopy,
165                                    bool willReadDstColor) {
166         return SkNEW_ARGS(ArithmeticXP, (k1, k2, k3, k4, enforcePMColor, dstCopy,
167                                          willReadDstColor));
168     }
169
170     ~ArithmeticXP() override {};
171
172     const char* name() const override { return "Arithmetic"; }
173
174     GrGLXferProcessor* createGLInstance() const override;
175
176     bool hasSecondaryOutput() const override { return false; }
177
178     GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
179                                                const GrProcOptInfo& coveragePOI,
180                                                bool doesStencilWrite,
181                                                GrColor* overrideColor,
182                                                const GrDrawTargetCaps& caps) override;
183
184     void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
185         blendInfo->fSrcBlend = kOne_GrBlendCoeff;
186         blendInfo->fDstBlend = kZero_GrBlendCoeff;
187         blendInfo->fBlendConstant = 0;
188     }
189
190     float k1() const { return fK1; }
191     float k2() const { return fK2; }
192     float k3() const { return fK3; }
193     float k4() const { return fK4; }
194     bool enforcePMColor() const { return fEnforcePMColor; }
195
196 private:
197     ArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor,
198                    const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
199
200     void onGetGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const override;
201
202     bool onIsEqual(const GrXferProcessor& xpBase) const override {
203         const ArithmeticXP& xp = xpBase.cast<ArithmeticXP>();
204         if (fK1 != xp.fK1 ||
205             fK2 != xp.fK2 ||
206             fK3 != xp.fK3 ||
207             fK4 != xp.fK4 ||
208             fEnforcePMColor != xp.fEnforcePMColor) {
209             return false;
210         }
211         return true;
212     }
213
214     float                       fK1, fK2, fK3, fK4;
215     bool                        fEnforcePMColor;
216
217     typedef GrXferProcessor INHERITED;
218 };
219
220 ///////////////////////////////////////////////////////////////////////////////
221
222 class GLArithmeticXP : public GrGLXferProcessor {
223 public:
224     GLArithmeticXP(const GrProcessor&)
225         : fEnforcePMColor(true) {
226     }
227
228     ~GLArithmeticXP() override {}
229
230     static void GenKey(const GrProcessor& processor, const GrGLCaps& caps,
231                        GrProcessorKeyBuilder* b) {
232         const ArithmeticXP& arith = processor.cast<ArithmeticXP>();
233         uint32_t key = arith.enforcePMColor() ? 1 : 0;
234         b->add32(key);
235     }
236
237 private:
238     void onEmitCode(const EmitArgs& args) override {
239         GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
240
241         const char* dstColor = fsBuilder->dstColor();
242
243         fKUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
244                                      kVec4f_GrSLType, kDefault_GrSLPrecision,
245                                      "k");
246         const char* kUni = args.fPB->getUniformCStr(fKUni);
247
248         add_arithmetic_code(fsBuilder, args.fInputColor, dstColor, args.fOutputPrimary, kUni, 
249                             fEnforcePMColor);
250
251         fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
252                                args.fOutputPrimary, args.fOutputPrimary, args.fInputCoverage,
253                                args.fInputCoverage, dstColor);
254     }
255
256     void onSetData(const GrGLProgramDataManager& pdman,
257                    const GrXferProcessor& processor) override {
258         const ArithmeticXP& arith = processor.cast<ArithmeticXP>();
259         pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
260         fEnforcePMColor = arith.enforcePMColor();
261     };
262
263     GrGLProgramDataManager::UniformHandle fKUni;
264     bool fEnforcePMColor;
265
266     typedef GrGLXferProcessor INHERITED;
267 };
268
269 ///////////////////////////////////////////////////////////////////////////////
270
271 ArithmeticXP::ArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor,
272                            const GrDeviceCoordTexture* dstCopy, bool willReadDstColor)
273     : INHERITED(dstCopy, willReadDstColor)
274     , fK1(k1)
275     , fK2(k2)
276     , fK3(k3)
277     , fK4(k4)
278     , fEnforcePMColor(enforcePMColor) {
279     this->initClassID<ArithmeticXP>();
280 }
281
282 void ArithmeticXP::onGetGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const {
283     GLArithmeticXP::GenKey(*this, caps, b);
284 }
285
286 GrGLXferProcessor* ArithmeticXP::createGLInstance() const {
287     return SkNEW_ARGS(GLArithmeticXP, (*this));
288 }
289
290 GrXferProcessor::OptFlags ArithmeticXP::getOptimizations(const GrProcOptInfo& colorPOI,
291                                                          const GrProcOptInfo& coveragePOI,
292                                                          bool doesStencilWrite,
293                                                          GrColor* overrideColor,
294                                                          const GrDrawTargetCaps& caps) {
295    return GrXferProcessor::kNone_Opt;
296 }
297
298 ///////////////////////////////////////////////////////////////////////////////
299
300 GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float k4,
301                                              bool enforcePMColor) 
302     : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
303     this->initClassID<GrArithmeticXPFactory>();
304 }
305
306 GrXferProcessor*
307 GrArithmeticXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps,
308                                              const GrProcOptInfo& colorPOI,
309                                              const GrProcOptInfo& coveragePOI,
310                                              const GrDeviceCoordTexture* dstCopy) const {
311     return ArithmeticXP::Create(fK1, fK2, fK3, fK4, fEnforcePMColor, dstCopy,
312                                 this->willReadDstColor(caps, colorPOI, coveragePOI));
313 }
314
315
316 void GrArithmeticXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
317                                                const GrProcOptInfo& coveragePOI,
318                                                GrXPFactory::InvariantOutput* output) const {
319     output->fWillBlendWithDst = true;
320
321     // TODO: We could try to optimize this more. For example if we have solid coverage and fK1 and
322     // fK3 are zero, then we won't be blending the color with dst at all so we can know what the
323     // output color is (up to the valid color components passed in).
324     output->fBlendedColorFlags = 0;
325 }
326
327 GR_DEFINE_XP_FACTORY_TEST(GrArithmeticXPFactory);
328
329 GrXPFactory* GrArithmeticXPFactory::TestCreate(SkRandom* random,
330                                                GrContext*,
331                                                const GrDrawTargetCaps&,
332                                                GrTexture*[]) {
333     float k1 = random->nextF();
334     float k2 = random->nextF();
335     float k3 = random->nextF();
336     float k4 = random->nextF();
337     bool enforcePMColor = random->nextBool();
338
339     return GrArithmeticXPFactory::Create(k1, k2, k3, k4, enforcePMColor);
340 }
341
342 #endif