Index: src/core/SkComposeShader.cpp |
diff --git a/src/core/SkComposeShader.cpp b/src/core/SkComposeShader.cpp |
index 853e15772143116fbddd79a8556cddec74db275c..095dca2332cc364c4e85bb50eca700ecd7945dc6 100644 |
--- a/src/core/SkComposeShader.cpp |
+++ b/src/core/SkComposeShader.cpp |
@@ -194,6 +194,156 @@ void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor re |
} |
} |
+#if SK_SUPPORT_GPU |
+ |
+#include "SkGr.h" |
+#include "GrProcessor.h" |
+#include "gl/GrGLBlend.h" |
+#include "gl/builders/GrGLProgramBuilder.h" |
+#include "effects/GrConstColorProcessor.h" |
+ |
+///////////////////////////////////////////////////////////////////// |
+ |
+class GrComposeEffect : public GrFragmentProcessor { |
+public: |
+ |
+ static GrFragmentProcessor* Create(const GrFragmentProcessor* fpA, |
+ const GrFragmentProcessor* fpB, SkXfermode::Mode mode) { |
+ return SkNEW_ARGS(GrComposeEffect, (fpA, fpB, mode)); |
+ } |
+ const char* name() const override { return "ComposeShader"; } |
+ void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; |
+ |
+ SkXfermode::Mode getMode() const { return fMode; } |
+ |
+protected: |
+ bool onIsEqual(const GrFragmentProcessor&) const override; |
+ void onComputeInvariantOutput(GrInvariantOutput* inout) const override; |
+ |
+private: |
+ GrComposeEffect(const GrFragmentProcessor* fpA, const GrFragmentProcessor* fpB, |
+ SkXfermode::Mode mode) |
+ : fMode(mode) { |
+ this->initClassID<GrComposeEffect>(); |
+ SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(fpA); |
+ SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(fpB); |
+ SkASSERT(0 == shaderAChildIndex); |
+ SkASSERT(1 == shaderBChildIndex); |
+ } |
+ |
+ GrGLFragmentProcessor* onCreateGLInstance() const override; |
+ |
+ SkXfermode::Mode fMode; |
+ |
+ typedef GrFragmentProcessor INHERITED; |
+}; |
+ |
+///////////////////////////////////////////////////////////////////// |
+ |
+class GrGLComposeEffect : public GrGLFragmentProcessor { |
+public: |
+ GrGLComposeEffect(const GrProcessor& processor) {} |
+ |
+ void emitCode(EmitArgs&) override; |
+ |
+private: |
+ typedef GrGLFragmentProcessor INHERITED; |
+}; |
+ |
+bool GrComposeEffect::onIsEqual(const GrFragmentProcessor& other) const { |
+ const GrComposeEffect& cs = other.cast<GrComposeEffect>(); |
+ return fMode == cs.fMode; |
+} |
+ |
+void GrComposeEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { |
+ inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); |
+} |
+ |
+void GrComposeEffect::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { |
+ b->add32(fMode); |
+} |
+ |
+GrGLFragmentProcessor* GrComposeEffect::onCreateGLInstance() const{ |
+ return SkNEW_ARGS(GrGLComposeEffect, (*this)); |
+} |
+ |
+///////////////////////////////////////////////////////////////////// |
+ |
+void GrGLComposeEffect::emitCode(EmitArgs& args) { |
+ |
+ GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); |
+ const GrComposeEffect& cs = args.fFp.cast<GrComposeEffect>(); |
+ |
+ // 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. |
+ // This is because we don't want the paint's alpha to affect either child proc's output |
+ // before the blend; we want to apply the paint's alpha AFTER the blend. This mirrors the |
+ // software implementation of SkComposeShader. |
+ SkString inputAlpha("inputAlpha"); |
+ fsBuilder->codeAppendf("float %s = %s.a;", inputAlpha.c_str(), args.fInputColor); |
+ fsBuilder->codeAppendf("%s /= %s.a;", args.fInputColor, args.fInputColor); |
+ |
+ // emit the code of the two child shaders |
+ SkString mangledOutputColorA; |
+ this->emitChild(0, args.fInputColor, &mangledOutputColorA, args); |
+ SkString mangledOutputColorB; |
+ this->emitChild(1, args.fInputColor, &mangledOutputColorB, args); |
+ |
+ // emit blend code |
+ SkXfermode::Mode mode = cs.getMode(); |
+ fsBuilder->codeAppend("{"); |
+ fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode)); |
+ GrGLBlend::AppendPorterDuffBlend(fsBuilder, mangledOutputColorB.c_str(), |
+ mangledOutputColorA.c_str(), args.fOutputColor, mode); |
+ fsBuilder->codeAppend("}"); |
+ |
+ // re-multiply the output color by the input color's alpha |
+ fsBuilder->codeAppendf("%s *= %s;", args.fOutputColor, inputAlpha.c_str()); |
+} |
+ |
+///////////////////////////////////////////////////////////////////// |
+ |
+const GrFragmentProcessor* SkComposeShader::asFragmentProcessor(GrContext* context, |
+ const SkMatrix& viewM, |
+ const SkMatrix* localMatrix, |
+ SkFilterQuality fq, |
+ GrProcessorDataManager* procDataManager |
+ ) const { |
+ // Fragment processor will only support coefficient modes. This is because |
+ // GrGLBlend::AppendPorterDuffBlend(), which emits the blend code in the shader, |
+ // only supports those modes. |
+ SkXfermode::Mode mode; |
+ if (!(SkXfermode::AsMode(fMode, &mode) && mode <= SkXfermode::kLastCoeffMode)) { |
+ return nullptr; |
+ } |
+ |
+ switch (mode) { |
+ case SkXfermode::kClear_Mode: |
+ return GrConstColorProcessor::Create(GrColor_TRANS_BLACK, |
+ GrConstColorProcessor::kIgnore_InputMode); |
+ break; |
+ case SkXfermode::kSrc_Mode: |
+ return fShaderB->asFragmentProcessor(context, viewM, localMatrix, fq, procDataManager); |
+ break; |
+ case SkXfermode::kDst_Mode: |
+ return fShaderA->asFragmentProcessor(context, viewM, localMatrix, fq, procDataManager); |
+ break; |
+ default: |
+ SkAutoTUnref<const GrFragmentProcessor> fpA(fShaderA->asFragmentProcessor(context, |
+ viewM, localMatrix, fq, procDataManager)); |
+ if (!fpA.get()) { |
+ return nullptr; |
+ } |
+ SkAutoTUnref<const GrFragmentProcessor> fpB(fShaderB->asFragmentProcessor(context, |
+ viewM, localMatrix, fq, procDataManager)); |
+ if (!fpB.get()) { |
+ return nullptr; |
+ } |
+ return GrComposeEffect::Create(fpA, fpB, mode); |
+ } |
+} |
+#endif |
+ |
#ifndef SK_IGNORE_TO_STRING |
void SkComposeShader::toString(SkString* str) const { |
str->append("SkComposeShader: ("); |