Chromium Code Reviews| Index: src/gpu/effects/GrXfermodeFragmentProcessor.cpp |
| diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp |
| index ab944d86fcbcb19f1bc157bf753fa135da503e76..612d291868104762f6319eb08bd105d5507bda1e 100644 |
| --- a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp |
| +++ b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp |
| @@ -9,25 +9,23 @@ |
| #include "GrFragmentProcessor.h" |
| #include "effects/GrConstColorProcessor.h" |
| -#include "gl/GrGLBlend.h" |
| +#include "gl/GrGLSLBlend.h" |
| #include "gl/builders/GrGLProgramBuilder.h" |
| +#include "SkGr.h" |
| - |
| -class GrComposeTwoFragmentProcessor : public GrFragmentProcessor { |
| +class ComposeTwoFragmentProcessor : public GrFragmentProcessor { |
| public: |
| - GrComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragmentProcessor* dst, |
| + ComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragmentProcessor* dst, |
| SkXfermode::Mode mode) |
| : fMode(mode) { |
| - // Only coefficient xfer modes are supported |
| - SkASSERT(SkXfermode::kLastCoeffMode >= mode); |
| - this->initClassID<GrComposeTwoFragmentProcessor>(); |
| + this->initClassID<ComposeTwoFragmentProcessor>(); |
| SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(src); |
| SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(dst); |
| SkASSERT(0 == shaderAChildIndex); |
| SkASSERT(1 == shaderBChildIndex); |
| } |
| - const char* name() const override { return "ComposeShader"; } |
| + const char* name() const override { return "ComposeTwo"; } |
| void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { |
| b->add32(fMode); |
| @@ -37,7 +35,7 @@ public: |
| protected: |
| bool onIsEqual(const GrFragmentProcessor& other) const override { |
| - const GrComposeTwoFragmentProcessor& cs = other.cast<GrComposeTwoFragmentProcessor>(); |
| + const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>(); |
| return fMode == cs.fMode; |
| } |
| @@ -57,9 +55,9 @@ private: |
| ///////////////////////////////////////////////////////////////////// |
| -class GrGLComposeTwoFragmentProcessor : public GrGLFragmentProcessor { |
| +class GLComposeTwoFragmentProcessor : public GrGLFragmentProcessor { |
| public: |
| - GrGLComposeTwoFragmentProcessor(const GrProcessor& processor) {} |
| + GLComposeTwoFragmentProcessor(const GrProcessor& processor) {} |
| void emitCode(EmitArgs&) override; |
| @@ -69,28 +67,28 @@ private: |
| ///////////////////////////////////////////////////////////////////// |
| -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrComposeTwoFragmentProcessor); |
| +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor); |
| -const GrFragmentProcessor* GrComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) { |
| +const GrFragmentProcessor* ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) { |
| // Create two random frag procs. |
| SkAutoTUnref<const GrFragmentProcessor> fpA(GrProcessorUnitTest::CreateChildFP(d)); |
| SkAutoTUnref<const GrFragmentProcessor> fpB(GrProcessorUnitTest::CreateChildFP(d)); |
| SkXfermode::Mode mode = static_cast<SkXfermode::Mode>( |
| - d->fRandom->nextRangeU(0, SkXfermode::kLastCoeffMode)); |
| - return SkNEW_ARGS(GrComposeTwoFragmentProcessor, (fpA, fpB, mode)); |
| + d->fRandom->nextRangeU(0, SkXfermode::kLastMode)); |
| + return new ComposeTwoFragmentProcessor(fpA, fpB, mode); |
| } |
| -GrGLFragmentProcessor* GrComposeTwoFragmentProcessor::onCreateGLInstance() const{ |
| - return SkNEW_ARGS(GrGLComposeTwoFragmentProcessor, (*this)); |
| +GrGLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLInstance() const{ |
| + return new GLComposeTwoFragmentProcessor(*this); |
| } |
| ///////////////////////////////////////////////////////////////////// |
| -void GrGLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) { |
| +void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) { |
| GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); |
| - const GrComposeTwoFragmentProcessor& cs = args.fFp.cast<GrComposeTwoFragmentProcessor>(); |
| + const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>(); |
| // Store alpha of input color and un-premultiply the input color by its alpha. We will |
| // re-multiply by this alpha after blending the output colors of the two child procs. |
| @@ -122,8 +120,8 @@ void GrGLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) { |
| SkXfermode::Mode mode = cs.getMode(); |
| fsBuilder->codeAppend("{"); |
| fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode)); |
| - GrGLBlend::AppendPorterDuffBlend(fsBuilder, outputColorSrc.c_str(), |
| - outputColorDst.c_str(), args.fOutputColor, mode); |
| + GrGLSLBlend::AppendMode(fsBuilder, outputColorSrc.c_str(), |
| + outputColorDst.c_str(), args.fOutputColor, mode); |
| fsBuilder->codeAppend("}"); |
| // re-multiply the output color by the input color's alpha |
| @@ -134,21 +132,183 @@ void GrGLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) { |
| const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromTwoProcessors( |
| const GrFragmentProcessor* src, const GrFragmentProcessor* dst, SkXfermode::Mode mode) { |
| - if (SkXfermode::kLastCoeffMode < mode) { |
| - return nullptr; |
| - } |
| switch (mode) { |
| case SkXfermode::kClear_Mode: |
| - return GrConstColorProcessor::Create(GrColor_TRANS_BLACK, |
| + return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, |
| GrConstColorProcessor::kIgnore_InputMode); |
| - break; |
| case SkXfermode::kSrc_Mode: |
| return SkRef(src); |
| - break; |
| case SkXfermode::kDst_Mode: |
| return SkRef(dst); |
| - break; |
| default: |
| - return new GrComposeTwoFragmentProcessor(src, dst, mode); |
| + return new ComposeTwoFragmentProcessor(src, dst, mode); |
| + } |
| +} |
| + |
| +////////////////////////////////////////////////////////////////////////////// |
| + |
| +class ComposeOneFragmentProcessor : public GrFragmentProcessor { |
| +public: |
| + enum Child { |
| + kDst_Child, |
| + kSrc_Child, |
| + }; |
| + |
| + ComposeOneFragmentProcessor(const GrFragmentProcessor* dst, SkXfermode::Mode mode, Child child) |
| + : fMode(mode) |
| + , fChild(child) { |
| + this->initClassID<ComposeTwoFragmentProcessor>(); |
|
egdaniel
2015/09/15 20:59:28
ComposeOneFrag
bsalomon
2015/09/15 21:12:07
eek... nice catch.
|
| + SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst); |
| + SkASSERT(0 == dstIndex); |
| + } |
| + |
| + const char* name() const override { return "ComposeOne"; } |
| + |
| + void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { |
| + 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.
|
| + } |
| + |
| + SkXfermode::Mode mode() const { return fMode; } |
| + |
| + Child child() const { return fChild; } |
| + |
| +protected: |
| + bool onIsEqual(const GrFragmentProcessor& that) const override { |
| + return fMode == that.cast<ComposeOneFragmentProcessor>().fMode; |
| + } |
| + |
| + void onComputeInvariantOutput(GrInvariantOutput* inout) const override { |
| + SkXfermode::Coeff skSrcCoeff, skDstCoeff; |
| + if (SkXfermode::ModeAsCoeff(fMode, &skSrcCoeff, &skDstCoeff)) { |
| + GrBlendCoeff srcCoeff = SkXfermodeCoeffToGrBlendCoeff(skSrcCoeff); |
| + GrBlendCoeff dstCoeff = SkXfermodeCoeffToGrBlendCoeff(skDstCoeff); |
| + GrInvariantOutput childOutput(0xFFFFFFFF, kRGBA_GrColorComponentFlags, false); |
| + this->childProcessor(0).computeInvariantOutput(&childOutput); |
| + GrColor blendColor; |
| + GrColorComponentFlags blendFlags; |
| + if (kDst_Child == fChild) { |
| + GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff, |
| + inout->color(), inout->validFlags(), |
| + childOutput.color(), childOutput.validFlags(), |
| + &blendColor, &blendFlags); |
| + } else { |
| + GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff, |
| + childOutput.color(), childOutput.validFlags(), |
| + inout->color(), inout->validFlags(), |
| + &blendColor, &blendFlags); |
| + } |
| + // will the shader code reference the input color? |
| + GrInvariantOutput::ReadInput readsInput = GrInvariantOutput::kWillNot_ReadInput; |
| + if (kDst_Child == fChild) { |
| + if (SkXfermode::kZero_Coeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff)) { |
| + readsInput = GrInvariantOutput::kWill_ReadInput; |
| + } |
| + } else { |
| + if (SkXfermode::kZero_Coeff != dstCoeff || GrBlendCoeffRefsDst(srcCoeff)) { |
| + readsInput = GrInvariantOutput::kWill_ReadInput; |
| + } |
| + } |
| + inout->setToOther(blendFlags, blendColor, readsInput); |
| + } else { |
| + inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); |
| + } |
| + } |
| + |
| +private: |
| + GrGLFragmentProcessor* onCreateGLInstance() const override; |
| + |
| + SkXfermode::Mode fMode; |
| + Child fChild; |
| + |
| + GR_DECLARE_FRAGMENT_PROCESSOR_TEST; |
| + |
| + typedef GrFragmentProcessor INHERITED; |
| +}; |
| + |
| +////////////////////////////////////////////////////////////////////////////// |
| + |
| +class GLComposeOneFragmentProcessor : public GrGLFragmentProcessor { |
| +public: |
| + GLComposeOneFragmentProcessor(const GrProcessor& processor) {} |
| + |
| + void emitCode(EmitArgs& args) override { |
| + GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); |
| + SkXfermode::Mode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode(); |
| + ComposeOneFragmentProcessor::Child child = |
| + args.fFp.cast<ComposeOneFragmentProcessor>().child(); |
| + // declare _dstColor and emit the code for the two child |
| + fsBuilder->codeAppendf("vec4 _child;"); |
| + this->emitChild(0, nullptr, "_child", args); |
| + |
| + const char* inputColor = args.fInputColor; |
| + // We don't try to optimize for this case at all |
| + if (!inputColor) { |
| + fsBuilder->codeAppendf("const vec4 ones = vec4(1);"); |
| + inputColor = "ones"; |
| + } |
| + |
| + // emit blend code |
| + fsBuilder->codeAppend("{"); |
| + fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode)); |
| + if (ComposeOneFragmentProcessor::kDst_Child == child) { |
| + GrGLSLBlend::AppendMode(fsBuilder, inputColor, "_child", args.fOutputColor, mode); |
| + } else { |
| + GrGLSLBlend::AppendMode(fsBuilder, "_child", inputColor, args.fOutputColor, mode); |
| + } |
| + fsBuilder->codeAppend("}"); |
| + } |
| + |
| +private: |
| + typedef GrGLFragmentProcessor INHERITED; |
| +}; |
| + |
| +///////////////////////////////////////////////////////////////////// |
| + |
| +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor); |
| + |
| +const GrFragmentProcessor* ComposeOneFragmentProcessor::TestCreate(GrProcessorTestData* d) { |
| + // Create one random frag procs. |
| + // For now, we'll prevent either children from being a shader with children to prevent the |
| + // possibility of an arbitrarily large tree of procs. |
| + SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d)); |
| + SkXfermode::Mode mode = static_cast<SkXfermode::Mode>( |
| + d->fRandom->nextRangeU(0, SkXfermode::kLastMode)); |
| + ComposeOneFragmentProcessor::Child child = d->fRandom->nextBool() ? |
| + ComposeOneFragmentProcessor::kDst_Child : |
| + ComposeOneFragmentProcessor::kSrc_Child; |
| + return new ComposeOneFragmentProcessor(dst, mode, child); |
| +} |
| + |
| +GrGLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLInstance() const { |
| + return new GLComposeOneFragmentProcessor(*this); |
| +} |
| + |
| +////////////////////////////////////////////////////////////////////////////// |
| + |
| +const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromDstProcessor( |
| + const GrFragmentProcessor* dst, SkXfermode::Mode mode) { |
| + switch (mode) { |
| + case SkXfermode::kClear_Mode: |
| + return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, |
| + GrConstColorProcessor::kIgnore_InputMode); |
| + case SkXfermode::kSrc_Mode: |
| + return nullptr; |
| + default: |
| + return new ComposeOneFragmentProcessor(dst, mode, |
| + ComposeOneFragmentProcessor::kDst_Child); |
| + } |
| +} |
| + |
| +const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromSrcProcessor( |
| + const GrFragmentProcessor* src, SkXfermode::Mode mode) { |
| + switch (mode) { |
| + case SkXfermode::kClear_Mode: |
| + return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, |
| + GrConstColorProcessor::kIgnore_InputMode); |
| + case SkXfermode::kDst_Mode: |
| + return nullptr; |
| + default: |
| + return new ComposeOneFragmentProcessor(src, mode, |
| + ComposeOneFragmentProcessor::kSrc_Child); |
| } |
| } |