Index: src/gpu/effects/GrXfermodeFragmentProcessor.cpp |
diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp |
index ab944d86fcbcb19f1bc157bf753fa135da503e76..942251c980942659b1795a86f85d15734b761dfd 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,184 @@ 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<ComposeOneFragmentProcessor>(); |
+ 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 { |
+ GR_STATIC_ASSERT((SkXfermode::kLastMode & SK_MaxU16) == SkXfermode::kLastMode); |
+ b->add32(fMode | (fChild << 16)); |
+ } |
+ |
+ 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 (kZero_GrBlendCoeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff)) { |
+ readsInput = GrInvariantOutput::kWill_ReadInput; |
+ } |
+ } else { |
+ if (kZero_GrBlendCoeff != 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); |
} |
} |