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/GrGLCaps.h"
17 #include "gl/GrGLProcessor.h"
18 #include "gl/GrGLProgramDataManager.h"
19 #include "gl/builders/GrGLProgramBuilder.h"
21 static const bool gUseUnpremul = false;
23 static void add_arithmetic_code(GrGLFPFragmentBuilder* fsBuilder,
24 const char* inputColor,
26 const char* outputColor,
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);");
33 fsBuilder->codeAppendf("vec4 src = %s;", inputColor);
35 fsBuilder->codeAppend("src.rgb = clamp(src.rgb / src.a, 0.0, 1.0);");
39 fsBuilder->codeAppendf("vec4 dst = %s;", dstColor);
41 fsBuilder->codeAppend("dst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);");
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);
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);
55 class GLArithmeticFP : public GrGLFragmentProcessor {
57 GLArithmeticFP(const GrProcessor&)
58 : fEnforcePMColor(true) {
61 ~GLArithmeticFP() override {}
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";
75 fKUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
76 kVec4f_GrSLType, kDefault_GrSLPrecision,
78 const char* kUni = builder->getUniformCStr(fKUni);
80 add_arithmetic_code(fsBuilder, inputColor, dstColor, outputColor, kUni, fEnforcePMColor);
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();
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;
96 GrGLProgramDataManager::UniformHandle fKUni;
99 typedef GrGLFragmentProcessor INHERITED;
102 ///////////////////////////////////////////////////////////////////////////////
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>();
109 SkASSERT(background);
111 fBackgroundTransform.reset(kLocal_GrCoordSet, background,
112 GrTextureParams::kNone_FilterMode);
113 this->addCoordTransform(&fBackgroundTransform);
114 fBackgroundAccess.reset(background);
115 this->addTextureAccess(&fBackgroundAccess);
118 void GrArithmeticFP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const {
119 GLArithmeticFP::GenKey(*this, caps, b);
122 GrGLFragmentProcessor* GrArithmeticFP::createGLInstance() const {
123 return SkNEW_ARGS(GLArithmeticFP, (*this));
126 bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& fpBase) const {
127 const GrArithmeticFP& fp = fpBase.cast<GrArithmeticFP>();
128 return fK1 == fp.fK1 &&
132 fEnforcePMColor == fp.fEnforcePMColor;
135 void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
136 // TODO: optimize this
137 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
140 ///////////////////////////////////////////////////////////////////////////////
142 GrFragmentProcessor* GrArithmeticFP::TestCreate(SkRandom* rand,
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();
152 return SkNEW_ARGS(GrArithmeticFP, (k1, k2, k3, k4, enforcePMColor, textures[0]));
155 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP);
157 ///////////////////////////////////////////////////////////////////////////////
159 ///////////////////////////////////////////////////////////////////////////////
161 class ArithmeticXP : public GrXferProcessor {
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,
170 ~ArithmeticXP() override {};
172 const char* name() const override { return "Arithmetic"; }
174 GrGLXferProcessor* createGLInstance() const override;
176 bool hasSecondaryOutput() const override { return false; }
178 GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
179 const GrProcOptInfo& coveragePOI,
180 bool doesStencilWrite,
181 GrColor* overrideColor,
182 const GrDrawTargetCaps& caps) override;
184 void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
185 blendInfo->fSrcBlend = kOne_GrBlendCoeff;
186 blendInfo->fDstBlend = kZero_GrBlendCoeff;
187 blendInfo->fBlendConstant = 0;
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; }
197 ArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor,
198 const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
200 void onGetGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const override;
202 bool onIsEqual(const GrXferProcessor& xpBase) const override {
203 const ArithmeticXP& xp = xpBase.cast<ArithmeticXP>();
208 fEnforcePMColor != xp.fEnforcePMColor) {
214 float fK1, fK2, fK3, fK4;
215 bool fEnforcePMColor;
217 typedef GrXferProcessor INHERITED;
220 ///////////////////////////////////////////////////////////////////////////////
222 class GLArithmeticXP : public GrGLXferProcessor {
224 GLArithmeticXP(const GrProcessor&)
225 : fEnforcePMColor(true) {
228 ~GLArithmeticXP() override {}
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;
238 void onEmitCode(const EmitArgs& args) override {
239 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
241 const char* dstColor = fsBuilder->dstColor();
243 fKUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
244 kVec4f_GrSLType, kDefault_GrSLPrecision,
246 const char* kUni = args.fPB->getUniformCStr(fKUni);
248 add_arithmetic_code(fsBuilder, args.fInputColor, dstColor, args.fOutputPrimary, kUni,
251 fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
252 args.fOutputPrimary, args.fOutputPrimary, args.fInputCoverage,
253 args.fInputCoverage, dstColor);
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();
263 GrGLProgramDataManager::UniformHandle fKUni;
264 bool fEnforcePMColor;
266 typedef GrGLXferProcessor INHERITED;
269 ///////////////////////////////////////////////////////////////////////////////
271 ArithmeticXP::ArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor,
272 const GrDeviceCoordTexture* dstCopy, bool willReadDstColor)
273 : INHERITED(dstCopy, willReadDstColor)
278 , fEnforcePMColor(enforcePMColor) {
279 this->initClassID<ArithmeticXP>();
282 void ArithmeticXP::onGetGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const {
283 GLArithmeticXP::GenKey(*this, caps, b);
286 GrGLXferProcessor* ArithmeticXP::createGLInstance() const {
287 return SkNEW_ARGS(GLArithmeticXP, (*this));
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;
298 ///////////////////////////////////////////////////////////////////////////////
300 GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float k4,
302 : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
303 this->initClassID<GrArithmeticXPFactory>();
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));
316 void GrArithmeticXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
317 const GrProcOptInfo& coveragePOI,
318 GrXPFactory::InvariantOutput* output) const {
319 output->fWillBlendWithDst = true;
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;
327 GR_DEFINE_XP_FACTORY_TEST(GrArithmeticXPFactory);
329 GrXPFactory* GrArithmeticXPFactory::TestCreate(SkRandom* random,
331 const GrDrawTargetCaps&,
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();
339 return GrArithmeticXPFactory::Create(k1, k2, k3, k4, enforcePMColor);