Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "effects/GrXfermodeFragmentProcessor.h" | 8 #include "effects/GrXfermodeFragmentProcessor.h" |
| 9 | 9 |
| 10 #include "GrFragmentProcessor.h" | 10 #include "GrFragmentProcessor.h" |
| 11 #include "effects/GrConstColorProcessor.h" | 11 #include "effects/GrConstColorProcessor.h" |
| 12 #include "gl/GrGLBlend.h" | 12 #include "gl/GrGLSLBlend.h" |
| 13 #include "gl/builders/GrGLProgramBuilder.h" | 13 #include "gl/builders/GrGLProgramBuilder.h" |
| 14 #include "SkGr.h" | |
| 14 | 15 |
| 15 | 16 class ComposeTwoFragmentProcessor : public GrFragmentProcessor { |
| 16 class GrComposeTwoFragmentProcessor : public GrFragmentProcessor { | |
| 17 public: | 17 public: |
| 18 GrComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragme ntProcessor* dst, | 18 ComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragment Processor* dst, |
| 19 SkXfermode::Mode mode) | 19 SkXfermode::Mode mode) |
| 20 : fMode(mode) { | 20 : fMode(mode) { |
| 21 // Only coefficient xfer modes are supported | 21 this->initClassID<ComposeTwoFragmentProcessor>(); |
| 22 SkASSERT(SkXfermode::kLastCoeffMode >= mode); | |
| 23 this->initClassID<GrComposeTwoFragmentProcessor>(); | |
| 24 SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(src); | 22 SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(src); |
| 25 SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(dst); | 23 SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(dst); |
| 26 SkASSERT(0 == shaderAChildIndex); | 24 SkASSERT(0 == shaderAChildIndex); |
| 27 SkASSERT(1 == shaderBChildIndex); | 25 SkASSERT(1 == shaderBChildIndex); |
| 28 } | 26 } |
| 29 | 27 |
| 30 const char* name() const override { return "ComposeShader"; } | 28 const char* name() const override { return "ComposeTwo"; } |
| 31 | 29 |
| 32 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override { | 30 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override { |
| 33 b->add32(fMode); | 31 b->add32(fMode); |
| 34 } | 32 } |
| 35 | 33 |
| 36 SkXfermode::Mode getMode() const { return fMode; } | 34 SkXfermode::Mode getMode() const { return fMode; } |
| 37 | 35 |
| 38 protected: | 36 protected: |
| 39 bool onIsEqual(const GrFragmentProcessor& other) const override { | 37 bool onIsEqual(const GrFragmentProcessor& other) const override { |
| 40 const GrComposeTwoFragmentProcessor& cs = other.cast<GrComposeTwoFragmen tProcessor>(); | 38 const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentPro cessor>(); |
| 41 return fMode == cs.fMode; | 39 return fMode == cs.fMode; |
| 42 } | 40 } |
| 43 | 41 |
| 44 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { | 42 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { |
| 45 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); | 43 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); |
| 46 } | 44 } |
| 47 | 45 |
| 48 private: | 46 private: |
| 49 GrGLFragmentProcessor* onCreateGLInstance() const override; | 47 GrGLFragmentProcessor* onCreateGLInstance() const override; |
| 50 | 48 |
| 51 SkXfermode::Mode fMode; | 49 SkXfermode::Mode fMode; |
| 52 | 50 |
| 53 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; | 51 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; |
| 54 | 52 |
| 55 typedef GrFragmentProcessor INHERITED; | 53 typedef GrFragmentProcessor INHERITED; |
| 56 }; | 54 }; |
| 57 | 55 |
| 58 ///////////////////////////////////////////////////////////////////// | 56 ///////////////////////////////////////////////////////////////////// |
| 59 | 57 |
| 60 class GrGLComposeTwoFragmentProcessor : public GrGLFragmentProcessor { | 58 class GLComposeTwoFragmentProcessor : public GrGLFragmentProcessor { |
| 61 public: | 59 public: |
| 62 GrGLComposeTwoFragmentProcessor(const GrProcessor& processor) {} | 60 GLComposeTwoFragmentProcessor(const GrProcessor& processor) {} |
| 63 | 61 |
| 64 void emitCode(EmitArgs&) override; | 62 void emitCode(EmitArgs&) override; |
| 65 | 63 |
| 66 private: | 64 private: |
| 67 typedef GrGLFragmentProcessor INHERITED; | 65 typedef GrGLFragmentProcessor INHERITED; |
| 68 }; | 66 }; |
| 69 | 67 |
| 70 ///////////////////////////////////////////////////////////////////// | 68 ///////////////////////////////////////////////////////////////////// |
| 71 | 69 |
| 72 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrComposeTwoFragmentProcessor); | 70 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor); |
| 73 | 71 |
| 74 const GrFragmentProcessor* GrComposeTwoFragmentProcessor::TestCreate(GrProcessor TestData* d) { | 72 const GrFragmentProcessor* ComposeTwoFragmentProcessor::TestCreate(GrProcessorTe stData* d) { |
| 75 // Create two random frag procs. | 73 // Create two random frag procs. |
| 76 SkAutoTUnref<const GrFragmentProcessor> fpA(GrProcessorUnitTest::CreateChild FP(d)); | 74 SkAutoTUnref<const GrFragmentProcessor> fpA(GrProcessorUnitTest::CreateChild FP(d)); |
| 77 SkAutoTUnref<const GrFragmentProcessor> fpB(GrProcessorUnitTest::CreateChild FP(d)); | 75 SkAutoTUnref<const GrFragmentProcessor> fpB(GrProcessorUnitTest::CreateChild FP(d)); |
| 78 | 76 |
| 79 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>( | 77 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>( |
| 80 d->fRandom->nextRangeU(0, SkXfermode::kLastCoeffMode)); | 78 d->fRandom->nextRangeU(0, SkXfermode::kLastMode)); |
| 81 return SkNEW_ARGS(GrComposeTwoFragmentProcessor, (fpA, fpB, mode)); | 79 return new ComposeTwoFragmentProcessor(fpA, fpB, mode); |
| 82 } | 80 } |
| 83 | 81 |
| 84 GrGLFragmentProcessor* GrComposeTwoFragmentProcessor::onCreateGLInstance() const { | 82 GrGLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLInstance() const{ |
| 85 return SkNEW_ARGS(GrGLComposeTwoFragmentProcessor, (*this)); | 83 return new GLComposeTwoFragmentProcessor(*this); |
| 86 } | 84 } |
| 87 | 85 |
| 88 ///////////////////////////////////////////////////////////////////// | 86 ///////////////////////////////////////////////////////////////////// |
| 89 | 87 |
| 90 void GrGLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) { | 88 void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) { |
| 91 | 89 |
| 92 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); | 90 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); |
| 93 const GrComposeTwoFragmentProcessor& cs = args.fFp.cast<GrComposeTwoFragment Processor>(); | 91 const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProc essor>(); |
| 94 | 92 |
| 95 // Store alpha of input color and un-premultiply the input color by its alph a. We will | 93 // Store alpha of input color and un-premultiply the input color by its alph a. We will |
| 96 // re-multiply by this alpha after blending the output colors of the two chi ld procs. | 94 // re-multiply by this alpha after blending the output colors of the two chi ld procs. |
| 97 // This is because we don't want the paint's alpha to affect either child pr oc's output | 95 // This is because we don't want the paint's alpha to affect either child pr oc's output |
| 98 // before the blend; we want to apply the paint's alpha AFTER the blend. Thi s mirrors the | 96 // before the blend; we want to apply the paint's alpha AFTER the blend. Thi s mirrors the |
| 99 // software implementation of SkComposeShader. | 97 // software implementation of SkComposeShader. |
| 100 const char* opaqueInput = nullptr; | 98 const char* opaqueInput = nullptr; |
| 101 const char* inputAlpha = nullptr; | 99 const char* inputAlpha = nullptr; |
| 102 if (args.fInputColor) { | 100 if (args.fInputColor) { |
| 103 inputAlpha = "inputAlpha"; | 101 inputAlpha = "inputAlpha"; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 115 | 113 |
| 116 SkString outputColorDst(args.fOutputColor); | 114 SkString outputColorDst(args.fOutputColor); |
| 117 outputColorDst.append("_dst"); | 115 outputColorDst.append("_dst"); |
| 118 fsBuilder->codeAppendf("vec4 %s;\n", outputColorDst.c_str()); | 116 fsBuilder->codeAppendf("vec4 %s;\n", outputColorDst.c_str()); |
| 119 this->emitChild(1, opaqueInput, outputColorDst.c_str(), args); | 117 this->emitChild(1, opaqueInput, outputColorDst.c_str(), args); |
| 120 | 118 |
| 121 // emit blend code | 119 // emit blend code |
| 122 SkXfermode::Mode mode = cs.getMode(); | 120 SkXfermode::Mode mode = cs.getMode(); |
| 123 fsBuilder->codeAppend("{"); | 121 fsBuilder->codeAppend("{"); |
| 124 fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mo de)); | 122 fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mo de)); |
| 125 GrGLBlend::AppendPorterDuffBlend(fsBuilder, outputColorSrc.c_str(), | 123 GrGLSLBlend::AppendMode(fsBuilder, outputColorSrc.c_str(), |
| 126 outputColorDst.c_str(), args.fOutputColor, mode); | 124 outputColorDst.c_str(), args.fOutputColor, mode); |
| 127 fsBuilder->codeAppend("}"); | 125 fsBuilder->codeAppend("}"); |
| 128 | 126 |
| 129 // re-multiply the output color by the input color's alpha | 127 // re-multiply the output color by the input color's alpha |
| 130 if (inputAlpha) { | 128 if (inputAlpha) { |
| 131 fsBuilder->codeAppendf("%s *= %s;", args.fOutputColor, inputAlpha); | 129 fsBuilder->codeAppendf("%s *= %s;", args.fOutputColor, inputAlpha); |
| 132 } | 130 } |
| 133 } | 131 } |
| 134 | 132 |
| 135 const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromTwoProcessors( | 133 const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromTwoProcessors( |
| 136 const GrFragmentProcessor* src, const GrFragmentProcessor* dst, SkXferm ode::Mode mode) { | 134 const GrFragmentProcessor* src, const GrFragmentProcessor* dst, SkXferm ode::Mode mode) { |
| 137 if (SkXfermode::kLastCoeffMode < mode) { | |
| 138 return nullptr; | |
| 139 } | |
| 140 switch (mode) { | 135 switch (mode) { |
| 141 case SkXfermode::kClear_Mode: | 136 case SkXfermode::kClear_Mode: |
| 142 return GrConstColorProcessor::Create(GrColor_TRANS_BLACK, | 137 return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, |
| 143 GrConstColorProcessor::kIgnore_ InputMode); | 138 GrConstColorProcessor::kIgnore_ InputMode); |
| 144 break; | |
| 145 case SkXfermode::kSrc_Mode: | 139 case SkXfermode::kSrc_Mode: |
| 146 return SkRef(src); | 140 return SkRef(src); |
| 147 break; | |
| 148 case SkXfermode::kDst_Mode: | 141 case SkXfermode::kDst_Mode: |
| 149 return SkRef(dst); | 142 return SkRef(dst); |
| 150 break; | |
| 151 default: | 143 default: |
| 152 return new GrComposeTwoFragmentProcessor(src, dst, mode); | 144 return new ComposeTwoFragmentProcessor(src, dst, mode); |
| 153 } | 145 } |
| 154 } | 146 } |
| 147 | |
| 148 ////////////////////////////////////////////////////////////////////////////// | |
| 149 | |
| 150 class ComposeOneFragmentProcessor : public GrFragmentProcessor { | |
| 151 public: | |
| 152 enum Child { | |
| 153 kDst_Child, | |
| 154 kSrc_Child, | |
| 155 }; | |
| 156 | |
| 157 ComposeOneFragmentProcessor(const GrFragmentProcessor* dst, SkXfermode::Mode mode, Child child) | |
| 158 : fMode(mode) | |
| 159 , fChild(child) { | |
| 160 this->initClassID<ComposeTwoFragmentProcessor>(); | |
|
egdaniel
2015/09/15 20:59:28
ComposeOneFrag
bsalomon
2015/09/15 21:12:07
eek... nice catch.
| |
| 161 SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst); | |
| 162 SkASSERT(0 == dstIndex); | |
| 163 } | |
| 164 | |
| 165 const char* name() const override { return "ComposeOne"; } | |
| 166 | |
| 167 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override { | |
| 168 b->add32(fMode | (fChild << 16)); | |
|
egdaniel
2015/09/15 20:59:28
worth asserting that kLastMode (or whatever it is
bsalomon
2015/09/15 21:12:07
Done.
| |
| 169 } | |
| 170 | |
| 171 SkXfermode::Mode mode() const { return fMode; } | |
| 172 | |
| 173 Child child() const { return fChild; } | |
| 174 | |
| 175 protected: | |
| 176 bool onIsEqual(const GrFragmentProcessor& that) const override { | |
| 177 return fMode == that.cast<ComposeOneFragmentProcessor>().fMode; | |
| 178 } | |
| 179 | |
| 180 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { | |
| 181 SkXfermode::Coeff skSrcCoeff, skDstCoeff; | |
| 182 if (SkXfermode::ModeAsCoeff(fMode, &skSrcCoeff, &skDstCoeff)) { | |
| 183 GrBlendCoeff srcCoeff = SkXfermodeCoeffToGrBlendCoeff(skSrcCoeff); | |
| 184 GrBlendCoeff dstCoeff = SkXfermodeCoeffToGrBlendCoeff(skDstCoeff); | |
| 185 GrInvariantOutput childOutput(0xFFFFFFFF, kRGBA_GrColorComponentFlag s, false); | |
| 186 this->childProcessor(0).computeInvariantOutput(&childOutput); | |
| 187 GrColor blendColor; | |
| 188 GrColorComponentFlags blendFlags; | |
| 189 if (kDst_Child == fChild) { | |
| 190 GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff, | |
| 191 inout->color(), inout->validFlags (), | |
| 192 childOutput.color(), childOutput. validFlags(), | |
| 193 &blendColor, &blendFlags); | |
| 194 } else { | |
| 195 GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff, | |
| 196 childOutput.color(), childOutput. validFlags(), | |
| 197 inout->color(), inout->validFlags (), | |
| 198 &blendColor, &blendFlags); | |
| 199 } | |
| 200 // will the shader code reference the input color? | |
| 201 GrInvariantOutput::ReadInput readsInput = GrInvariantOutput::kWillNo t_ReadInput; | |
| 202 if (kDst_Child == fChild) { | |
| 203 if (SkXfermode::kZero_Coeff != srcCoeff || GrBlendCoeffRefsSrc(d stCoeff)) { | |
| 204 readsInput = GrInvariantOutput::kWill_ReadInput; | |
| 205 } | |
| 206 } else { | |
| 207 if (SkXfermode::kZero_Coeff != dstCoeff || GrBlendCoeffRefsDst(s rcCoeff)) { | |
| 208 readsInput = GrInvariantOutput::kWill_ReadInput; | |
| 209 } | |
| 210 } | |
| 211 inout->setToOther(blendFlags, blendColor, readsInput); | |
| 212 } else { | |
| 213 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 private: | |
| 218 GrGLFragmentProcessor* onCreateGLInstance() const override; | |
| 219 | |
| 220 SkXfermode::Mode fMode; | |
| 221 Child fChild; | |
| 222 | |
| 223 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; | |
| 224 | |
| 225 typedef GrFragmentProcessor INHERITED; | |
| 226 }; | |
| 227 | |
| 228 ////////////////////////////////////////////////////////////////////////////// | |
| 229 | |
| 230 class GLComposeOneFragmentProcessor : public GrGLFragmentProcessor { | |
| 231 public: | |
| 232 GLComposeOneFragmentProcessor(const GrProcessor& processor) {} | |
| 233 | |
| 234 void emitCode(EmitArgs& args) override { | |
| 235 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder (); | |
| 236 SkXfermode::Mode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mod e(); | |
| 237 ComposeOneFragmentProcessor::Child child = | |
| 238 args.fFp.cast<ComposeOneFragmentProcessor>().child(); | |
| 239 // declare _dstColor and emit the code for the two child | |
| 240 fsBuilder->codeAppendf("vec4 _child;"); | |
| 241 this->emitChild(0, nullptr, "_child", args); | |
| 242 | |
| 243 const char* inputColor = args.fInputColor; | |
| 244 // We don't try to optimize for this case at all | |
| 245 if (!inputColor) { | |
| 246 fsBuilder->codeAppendf("const vec4 ones = vec4(1);"); | |
| 247 inputColor = "ones"; | |
| 248 } | |
| 249 | |
| 250 // emit blend code | |
| 251 fsBuilder->codeAppend("{"); | |
| 252 fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeNam e(mode)); | |
| 253 if (ComposeOneFragmentProcessor::kDst_Child == child) { | |
| 254 GrGLSLBlend::AppendMode(fsBuilder, inputColor, "_child", args.fOutpu tColor, mode); | |
| 255 } else { | |
| 256 GrGLSLBlend::AppendMode(fsBuilder, "_child", inputColor, args.fOutpu tColor, mode); | |
| 257 } | |
| 258 fsBuilder->codeAppend("}"); | |
| 259 } | |
| 260 | |
| 261 private: | |
| 262 typedef GrGLFragmentProcessor INHERITED; | |
| 263 }; | |
| 264 | |
| 265 ///////////////////////////////////////////////////////////////////// | |
| 266 | |
| 267 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor); | |
| 268 | |
| 269 const GrFragmentProcessor* ComposeOneFragmentProcessor::TestCreate(GrProcessorTe stData* d) { | |
| 270 // Create one random frag procs. | |
| 271 // For now, we'll prevent either children from being a shader with children to prevent the | |
| 272 // possibility of an arbitrarily large tree of procs. | |
| 273 SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChild FP(d)); | |
| 274 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>( | |
| 275 d->fRandom->nextRangeU(0, SkXfermode::kLastMode)); | |
| 276 ComposeOneFragmentProcessor::Child child = d->fRandom->nextBool() ? | |
| 277 ComposeOneFragmentProcessor::kDst_Child : | |
| 278 ComposeOneFragmentProcessor::kSrc_Child; | |
| 279 return new ComposeOneFragmentProcessor(dst, mode, child); | |
| 280 } | |
| 281 | |
| 282 GrGLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLInstance() const { | |
| 283 return new GLComposeOneFragmentProcessor(*this); | |
| 284 } | |
| 285 | |
| 286 ////////////////////////////////////////////////////////////////////////////// | |
| 287 | |
| 288 const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromDstProcessor( | |
| 289 const GrFragmentProcessor* dst, SkXfermode::Mode mode) { | |
| 290 switch (mode) { | |
| 291 case SkXfermode::kClear_Mode: | |
| 292 return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, | |
| 293 GrConstColorProcessor::kIgnore_ InputMode); | |
| 294 case SkXfermode::kSrc_Mode: | |
| 295 return nullptr; | |
| 296 default: | |
| 297 return new ComposeOneFragmentProcessor(dst, mode, | |
| 298 ComposeOneFragmentProcessor:: kDst_Child); | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromSrcProcessor( | |
| 303 const GrFragmentProcessor* src, SkXfermode::Mode mode) { | |
| 304 switch (mode) { | |
| 305 case SkXfermode::kClear_Mode: | |
| 306 return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, | |
| 307 GrConstColorProcessor::kIgnore_ InputMode); | |
| 308 case SkXfermode::kDst_Mode: | |
| 309 return nullptr; | |
| 310 default: | |
| 311 return new ComposeOneFragmentProcessor(src, mode, | |
| 312 ComposeOneFragmentProcessor:: kSrc_Child); | |
| 313 } | |
| 314 } | |
| OLD | NEW |