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 21static const bool gUseUnpremul = false; 22 23static void add_arithmetic_code(GrGLFragmentBuilder* 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 55class GLArithmeticFP : public GrGLFragmentProcessor { 56public: 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 GrGLFragmentBuilder* 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 GrGLSLCaps& caps, GrProcessorKeyBuilder* b) { 90 const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>(); 91 uint32_t key = arith.enforcePMColor() ? 1 : 0; 92 b->add32(key); 93 } 94 95private: 96 GrGLProgramDataManager::UniformHandle fKUni; 97 bool fEnforcePMColor; 98 99 typedef GrGLFragmentProcessor INHERITED; 100}; 101 102/////////////////////////////////////////////////////////////////////////////// 103 104GrArithmeticFP::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 118void GrArithmeticFP::getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { 119 GLArithmeticFP::GenKey(*this, caps, b); 120} 121 122GrGLFragmentProcessor* GrArithmeticFP::createGLInstance() const { 123 return SkNEW_ARGS(GLArithmeticFP, (*this)); 124} 125 126bool 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 135void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const { 136 // TODO: optimize this 137 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); 138} 139 140/////////////////////////////////////////////////////////////////////////////// 141 142GrFragmentProcessor* 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 155GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP); 156 157/////////////////////////////////////////////////////////////////////////////// 158// Xfer Processor 159/////////////////////////////////////////////////////////////////////////////// 160 161class ArithmeticXP : public GrXferProcessor { 162public: 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 float k1() const { return fK1; } 179 float k2() const { return fK2; } 180 float k3() const { return fK3; } 181 float k4() const { return fK4; } 182 bool enforcePMColor() const { return fEnforcePMColor; } 183 184private: 185 ArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor, 186 const GrDeviceCoordTexture* dstCopy, bool willReadDstColor); 187 188 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, 189 const GrProcOptInfo& coveragePOI, 190 bool doesStencilWrite, 191 GrColor* overrideColor, 192 const GrDrawTargetCaps& caps) override; 193 194 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; 195 196 bool onIsEqual(const GrXferProcessor& xpBase) const override { 197 const ArithmeticXP& xp = xpBase.cast<ArithmeticXP>(); 198 if (fK1 != xp.fK1 || 199 fK2 != xp.fK2 || 200 fK3 != xp.fK3 || 201 fK4 != xp.fK4 || 202 fEnforcePMColor != xp.fEnforcePMColor) { 203 return false; 204 } 205 return true; 206 } 207 208 float fK1, fK2, fK3, fK4; 209 bool fEnforcePMColor; 210 211 typedef GrXferProcessor INHERITED; 212}; 213 214/////////////////////////////////////////////////////////////////////////////// 215 216class GLArithmeticXP : public GrGLXferProcessor { 217public: 218 GLArithmeticXP(const GrProcessor&) 219 : fEnforcePMColor(true) { 220 } 221 222 ~GLArithmeticXP() override {} 223 224 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps, 225 GrProcessorKeyBuilder* b) { 226 const ArithmeticXP& arith = processor.cast<ArithmeticXP>(); 227 uint32_t key = arith.enforcePMColor() ? 1 : 0; 228 b->add32(key); 229 } 230 231private: 232 void onEmitCode(const EmitArgs& args) override { 233 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 234 235 const char* dstColor = fsBuilder->dstColor(); 236 237 fKUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, 238 kVec4f_GrSLType, kDefault_GrSLPrecision, 239 "k"); 240 const char* kUni = args.fPB->getUniformCStr(fKUni); 241 242 add_arithmetic_code(fsBuilder, args.fInputColor, dstColor, args.fOutputPrimary, kUni, 243 fEnforcePMColor); 244 245 fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;", 246 args.fOutputPrimary, args.fOutputPrimary, args.fInputCoverage, 247 args.fInputCoverage, dstColor); 248 } 249 250 void onSetData(const GrGLProgramDataManager& pdman, 251 const GrXferProcessor& processor) override { 252 const ArithmeticXP& arith = processor.cast<ArithmeticXP>(); 253 pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); 254 fEnforcePMColor = arith.enforcePMColor(); 255 }; 256 257 GrGLProgramDataManager::UniformHandle fKUni; 258 bool fEnforcePMColor; 259 260 typedef GrGLXferProcessor INHERITED; 261}; 262 263/////////////////////////////////////////////////////////////////////////////// 264 265ArithmeticXP::ArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor, 266 const GrDeviceCoordTexture* dstCopy, bool willReadDstColor) 267 : INHERITED(dstCopy, willReadDstColor) 268 , fK1(k1) 269 , fK2(k2) 270 , fK3(k3) 271 , fK4(k4) 272 , fEnforcePMColor(enforcePMColor) { 273 this->initClassID<ArithmeticXP>(); 274} 275 276void ArithmeticXP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { 277 GLArithmeticXP::GenKey(*this, caps, b); 278} 279 280GrGLXferProcessor* ArithmeticXP::createGLInstance() const { 281 return SkNEW_ARGS(GLArithmeticXP, (*this)); 282} 283 284GrXferProcessor::OptFlags ArithmeticXP::onGetOptimizations(const GrProcOptInfo& colorPOI, 285 const GrProcOptInfo& coveragePOI, 286 bool doesStencilWrite, 287 GrColor* overrideColor, 288 const GrDrawTargetCaps& caps) { 289 return GrXferProcessor::kNone_Opt; 290} 291 292/////////////////////////////////////////////////////////////////////////////// 293 294GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float k4, 295 bool enforcePMColor) 296 : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) { 297 this->initClassID<GrArithmeticXPFactory>(); 298} 299 300GrXferProcessor* 301GrArithmeticXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps, 302 const GrProcOptInfo& colorPOI, 303 const GrProcOptInfo& coveragePOI, 304 const GrDeviceCoordTexture* dstCopy) const { 305 return ArithmeticXP::Create(fK1, fK2, fK3, fK4, fEnforcePMColor, dstCopy, 306 this->willReadDstColor(caps, colorPOI, coveragePOI)); 307} 308 309 310void GrArithmeticXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, 311 const GrProcOptInfo& coveragePOI, 312 GrXPFactory::InvariantOutput* output) const { 313 output->fWillBlendWithDst = true; 314 315 // TODO: We could try to optimize this more. For example if we have solid coverage and fK1 and 316 // fK3 are zero, then we won't be blending the color with dst at all so we can know what the 317 // output color is (up to the valid color components passed in). 318 output->fBlendedColorFlags = 0; 319} 320 321GR_DEFINE_XP_FACTORY_TEST(GrArithmeticXPFactory); 322 323GrXPFactory* GrArithmeticXPFactory::TestCreate(SkRandom* random, 324 GrContext*, 325 const GrDrawTargetCaps&, 326 GrTexture*[]) { 327 float k1 = random->nextF(); 328 float k2 = random->nextF(); 329 float k3 = random->nextF(); 330 float k4 = random->nextF(); 331 bool enforcePMColor = random->nextBool(); 332 333 return GrArithmeticXPFactory::Create(k1, k2, k3, k4, enforcePMColor); 334} 335 336#endif 337