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