2 * Copyright 2015 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkArithmeticMode_gpu.h"
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"
22 static const bool gUseUnpremul = false;
24 static void add_arithmetic_code(GrGLSLFragmentBuilder* fsBuilder,
27 const char* outputColor,
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);");
34 fsBuilder->codeAppendf("vec4 src = %s;", srcColor);
36 fsBuilder->codeAppend("src.rgb = clamp(src.rgb / src.a, 0.0, 1.0);");
40 fsBuilder->codeAppendf("vec4 dst = %s;", dstColor);
42 fsBuilder->codeAppend("dst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);");
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);
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);
56 class GLArithmeticFP : public GrGLSLFragmentProcessor {
58 GLArithmeticFP(const GrArithmeticFP& arithmeticFP)
59 : fEnforcePMColor(arithmeticFP.enforcePMColor()) {}
61 ~GLArithmeticFP() override {}
63 void emitCode(EmitArgs& args) override {
64 GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
65 SkString dstColor("dstColor");
66 this->emitChild(0, nullptr, &dstColor, args);
68 fKUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
69 kVec4f_GrSLType, kDefault_GrSLPrecision,
71 const char* kUni = args.fBuilder->getUniformCStr(fKUni);
73 add_arithmetic_code(fsBuilder, args.fInputColor, dstColor.c_str(), args.fOutputColor, kUni,
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;
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();
91 GrGLSLProgramDataManager::UniformHandle fKUni;
94 typedef GrGLSLFragmentProcessor INHERITED;
97 ///////////////////////////////////////////////////////////////////////////////
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>();
105 SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst);
106 SkASSERT(0 == dstIndex);
109 void GrArithmeticFP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
110 GLArithmeticFP::GenKey(*this, caps, b);
113 GrGLSLFragmentProcessor* GrArithmeticFP::onCreateGLInstance() const {
114 return new GLArithmeticFP(*this);
117 bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& fpBase) const {
118 const GrArithmeticFP& fp = fpBase.cast<GrArithmeticFP>();
119 return fK1 == fp.fK1 &&
123 fEnforcePMColor == fp.fEnforcePMColor;
126 void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
127 // TODO: optimize this
128 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
131 ///////////////////////////////////////////////////////////////////////////////
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();
140 SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d));
141 return new GrArithmeticFP(k1, k2, k3, k4, enforcePMColor, dst);
144 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP);
146 ///////////////////////////////////////////////////////////////////////////////
148 ///////////////////////////////////////////////////////////////////////////////
150 class ArithmeticXP : public GrXferProcessor {
152 ArithmeticXP(const DstTexture*, bool hasMixedSamples,
153 float k1, float k2, float k3, float k4, bool enforcePMColor);
155 const char* name() const override { return "Arithmetic"; }
157 GrGLXferProcessor* createGLInstance() const override;
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; }
166 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
167 const GrProcOptInfo& coveragePOI,
168 bool doesStencilWrite,
169 GrColor* overrideColor,
170 const GrCaps& caps) override;
172 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
174 bool onIsEqual(const GrXferProcessor& xpBase) const override {
175 const ArithmeticXP& xp = xpBase.cast<ArithmeticXP>();
180 fEnforcePMColor != xp.fEnforcePMColor) {
186 float fK1, fK2, fK3, fK4;
187 bool fEnforcePMColor;
189 typedef GrXferProcessor INHERITED;
192 ///////////////////////////////////////////////////////////////////////////////
194 class GLArithmeticXP : public GrGLXferProcessor {
196 GLArithmeticXP(const ArithmeticXP& arithmeticXP)
197 : fEnforcePMColor(arithmeticXP.enforcePMColor()) {
200 ~GLArithmeticXP() override {}
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;
210 void emitBlendCodeForDstRead(GrGLSLXPBuilder* pb, const char* srcColor, const char* dstColor,
211 const char* outColor, const GrXferProcessor& proc) override {
212 GrGLSLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
214 fKUni = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
215 kVec4f_GrSLType, kDefault_GrSLPrecision,
217 const char* kUni = pb->getUniformCStr(fKUni);
219 add_arithmetic_code(fsBuilder, srcColor, dstColor, outColor, kUni, fEnforcePMColor);
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();
229 GrGLSLProgramDataManager::UniformHandle fKUni;
230 bool fEnforcePMColor;
232 typedef GrGLXferProcessor INHERITED;
235 ///////////////////////////////////////////////////////////////////////////////
237 ArithmeticXP::ArithmeticXP(const DstTexture* dstTexture, bool hasMixedSamples,
238 float k1, float k2, float k3, float k4, bool enforcePMColor)
239 : INHERITED(dstTexture, true, hasMixedSamples)
244 , fEnforcePMColor(enforcePMColor) {
245 this->initClassID<ArithmeticXP>();
248 void ArithmeticXP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
249 GLArithmeticXP::GenKey(*this, caps, b);
252 GrGLXferProcessor* ArithmeticXP::createGLInstance() const { return new GLArithmeticXP(*this); }
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;
262 ///////////////////////////////////////////////////////////////////////////////
264 GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float k4,
266 : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
267 this->initClassID<GrArithmeticXPFactory>();
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);
280 void GrArithmeticXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
281 InvariantBlendedColor* blendedColor) const {
282 blendedColor->fWillBlendWithDst = true;
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;
290 GR_DEFINE_XP_FACTORY_TEST(GrArithmeticXPFactory);
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();
299 return GrArithmeticXPFactory::Create(k1, k2, k3, k4, enforcePMColor);