GrXfermodeFragmentProcessor.cpp revision f276ac5c16d39a2b877300d760041f0291bb5ec9
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 "effects/GrXfermodeFragmentProcessor.h" 9 10#include "GrFragmentProcessor.h" 11#include "effects/GrConstColorProcessor.h" 12#include "gl/GrGLSLBlend.h" 13#include "gl/builders/GrGLProgramBuilder.h" 14#include "SkGrPriv.h" 15 16class ComposeTwoFragmentProcessor : public GrFragmentProcessor { 17public: 18 ComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragmentProcessor* dst, 19 SkXfermode::Mode mode) 20 : fMode(mode) { 21 this->initClassID<ComposeTwoFragmentProcessor>(); 22 SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(src); 23 SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(dst); 24 SkASSERT(0 == shaderAChildIndex); 25 SkASSERT(1 == shaderBChildIndex); 26 } 27 28 const char* name() const override { return "ComposeTwo"; } 29 30 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { 31 b->add32(fMode); 32 } 33 34 SkXfermode::Mode getMode() const { return fMode; } 35 36protected: 37 bool onIsEqual(const GrFragmentProcessor& other) const override { 38 const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>(); 39 return fMode == cs.fMode; 40 } 41 42 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { 43 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); 44 } 45 46private: 47 GrGLFragmentProcessor* onCreateGLInstance() const override; 48 49 SkXfermode::Mode fMode; 50 51 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 52 53 typedef GrFragmentProcessor INHERITED; 54}; 55 56///////////////////////////////////////////////////////////////////// 57 58class GLComposeTwoFragmentProcessor : public GrGLFragmentProcessor { 59public: 60 GLComposeTwoFragmentProcessor(const GrProcessor& processor) {} 61 62 void emitCode(EmitArgs&) override; 63 64private: 65 typedef GrGLFragmentProcessor INHERITED; 66}; 67 68///////////////////////////////////////////////////////////////////// 69 70GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor); 71 72const GrFragmentProcessor* ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) { 73 // Create two random frag procs. 74 SkAutoTUnref<const GrFragmentProcessor> fpA(GrProcessorUnitTest::CreateChildFP(d)); 75 SkAutoTUnref<const GrFragmentProcessor> fpB(GrProcessorUnitTest::CreateChildFP(d)); 76 77 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>( 78 d->fRandom->nextRangeU(0, SkXfermode::kLastMode)); 79 return new ComposeTwoFragmentProcessor(fpA, fpB, mode); 80} 81 82GrGLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLInstance() const{ 83 return new GLComposeTwoFragmentProcessor(*this); 84} 85 86///////////////////////////////////////////////////////////////////// 87 88void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) { 89 90 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); 91 const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>(); 92 93 const char* inputColor = nullptr; 94 if (args.fInputColor) { 95 inputColor = "inputColor"; 96 fsBuilder->codeAppendf("vec4 inputColor = vec4(%s.rgb, 1.0);", args.fInputColor); 97 } 98 99 // declare outputColor and emit the code for each of the two children 100 SkString srcColor("src"); 101 this->emitChild(0, inputColor, &srcColor, args); 102 103 SkString dstColor("dst"); 104 this->emitChild(1, inputColor, &dstColor, args); 105 106 // emit blend code 107 SkXfermode::Mode mode = cs.getMode(); 108 fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode)); 109 GrGLSLBlend::AppendMode(fsBuilder, srcColor.c_str(), dstColor.c_str(), args.fOutputColor, mode); 110 111 // re-multiply the output color by the input color's alpha 112 if (args.fInputColor) { 113 fsBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor); 114 } 115} 116 117const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromTwoProcessors( 118 const GrFragmentProcessor* src, const GrFragmentProcessor* dst, SkXfermode::Mode mode) { 119 switch (mode) { 120 case SkXfermode::kClear_Mode: 121 return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, 122 GrConstColorProcessor::kIgnore_InputMode); 123 case SkXfermode::kSrc_Mode: 124 return SkRef(src); 125 case SkXfermode::kDst_Mode: 126 return SkRef(dst); 127 default: 128 return new ComposeTwoFragmentProcessor(src, dst, mode); 129 } 130} 131 132////////////////////////////////////////////////////////////////////////////// 133 134class ComposeOneFragmentProcessor : public GrFragmentProcessor { 135public: 136 enum Child { 137 kDst_Child, 138 kSrc_Child, 139 }; 140 141 ComposeOneFragmentProcessor(const GrFragmentProcessor* dst, SkXfermode::Mode mode, Child child) 142 : fMode(mode) 143 , fChild(child) { 144 this->initClassID<ComposeOneFragmentProcessor>(); 145 SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst); 146 SkASSERT(0 == dstIndex); 147 } 148 149 const char* name() const override { return "ComposeOne"; } 150 151 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { 152 GR_STATIC_ASSERT((SkXfermode::kLastMode & SK_MaxU16) == SkXfermode::kLastMode); 153 b->add32(fMode | (fChild << 16)); 154 } 155 156 SkXfermode::Mode mode() const { return fMode; } 157 158 Child child() const { return fChild; } 159 160protected: 161 bool onIsEqual(const GrFragmentProcessor& that) const override { 162 return fMode == that.cast<ComposeOneFragmentProcessor>().fMode; 163 } 164 165 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { 166 SkXfermode::Coeff skSrcCoeff, skDstCoeff; 167 if (SkXfermode::ModeAsCoeff(fMode, &skSrcCoeff, &skDstCoeff)) { 168 GrBlendCoeff srcCoeff = SkXfermodeCoeffToGrBlendCoeff(skSrcCoeff); 169 GrBlendCoeff dstCoeff = SkXfermodeCoeffToGrBlendCoeff(skDstCoeff); 170 GrInvariantOutput childOutput(0xFFFFFFFF, kRGBA_GrColorComponentFlags, false); 171 this->childProcessor(0).computeInvariantOutput(&childOutput); 172 GrColor blendColor; 173 GrColorComponentFlags blendFlags; 174 if (kDst_Child == fChild) { 175 GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff, 176 inout->color(), inout->validFlags(), 177 childOutput.color(), childOutput.validFlags(), 178 &blendColor, &blendFlags); 179 } else { 180 GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff, 181 childOutput.color(), childOutput.validFlags(), 182 inout->color(), inout->validFlags(), 183 &blendColor, &blendFlags); 184 } 185 // will the shader code reference the input color? 186 GrInvariantOutput::ReadInput readsInput = GrInvariantOutput::kWillNot_ReadInput; 187 if (kDst_Child == fChild) { 188 if (kZero_GrBlendCoeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff)) { 189 readsInput = GrInvariantOutput::kWill_ReadInput; 190 } 191 } else { 192 if (kZero_GrBlendCoeff != dstCoeff || GrBlendCoeffRefsDst(srcCoeff)) { 193 readsInput = GrInvariantOutput::kWill_ReadInput; 194 } 195 } 196 inout->setToOther(blendFlags, blendColor, readsInput); 197 } else { 198 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); 199 } 200 } 201 202private: 203 GrGLFragmentProcessor* onCreateGLInstance() const override; 204 205 SkXfermode::Mode fMode; 206 Child fChild; 207 208 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 209 210 typedef GrFragmentProcessor INHERITED; 211}; 212 213////////////////////////////////////////////////////////////////////////////// 214 215class GLComposeOneFragmentProcessor : public GrGLFragmentProcessor { 216public: 217 GLComposeOneFragmentProcessor(const GrProcessor& processor) {} 218 219 void emitCode(EmitArgs& args) override { 220 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); 221 SkXfermode::Mode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode(); 222 ComposeOneFragmentProcessor::Child child = 223 args.fFp.cast<ComposeOneFragmentProcessor>().child(); 224 SkString childColor("child"); 225 this->emitChild(0, nullptr, &childColor, args); 226 227 const char* inputColor = args.fInputColor; 228 // We don't try to optimize for this case at all 229 if (!inputColor) { 230 fsBuilder->codeAppendf("const vec4 ones = vec4(1);"); 231 inputColor = "ones"; 232 } 233 234 // emit blend code 235 fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode)); 236 const char* childStr = childColor.c_str(); 237 if (ComposeOneFragmentProcessor::kDst_Child == child) { 238 GrGLSLBlend::AppendMode(fsBuilder, inputColor, childStr, args.fOutputColor, mode); 239 } else { 240 GrGLSLBlend::AppendMode(fsBuilder, childStr, inputColor, args.fOutputColor, mode); 241 } 242 } 243 244private: 245 typedef GrGLFragmentProcessor INHERITED; 246}; 247 248///////////////////////////////////////////////////////////////////// 249 250GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor); 251 252const GrFragmentProcessor* ComposeOneFragmentProcessor::TestCreate(GrProcessorTestData* d) { 253 // Create one random frag procs. 254 // For now, we'll prevent either children from being a shader with children to prevent the 255 // possibility of an arbitrarily large tree of procs. 256 SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d)); 257 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>( 258 d->fRandom->nextRangeU(0, SkXfermode::kLastMode)); 259 ComposeOneFragmentProcessor::Child child = d->fRandom->nextBool() ? 260 ComposeOneFragmentProcessor::kDst_Child : 261 ComposeOneFragmentProcessor::kSrc_Child; 262 return new ComposeOneFragmentProcessor(dst, mode, child); 263} 264 265GrGLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLInstance() const { 266 return new GLComposeOneFragmentProcessor(*this); 267} 268 269////////////////////////////////////////////////////////////////////////////// 270 271const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromDstProcessor( 272 const GrFragmentProcessor* dst, SkXfermode::Mode mode) { 273 switch (mode) { 274 case SkXfermode::kClear_Mode: 275 return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, 276 GrConstColorProcessor::kIgnore_InputMode); 277 case SkXfermode::kSrc_Mode: 278 return nullptr; 279 default: 280 return new ComposeOneFragmentProcessor(dst, mode, 281 ComposeOneFragmentProcessor::kDst_Child); 282 } 283} 284 285const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromSrcProcessor( 286 const GrFragmentProcessor* src, SkXfermode::Mode mode) { 287 switch (mode) { 288 case SkXfermode::kClear_Mode: 289 return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, 290 GrConstColorProcessor::kIgnore_InputMode); 291 case SkXfermode::kDst_Mode: 292 return nullptr; 293 default: 294 return new ComposeOneFragmentProcessor(src, mode, 295 ComposeOneFragmentProcessor::kSrc_Child); 296 } 297} 298