diff options
author | egdaniel <egdaniel@google.com> | 2014-12-03 10:40:13 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-12-03 10:40:13 -0800 |
commit | 378092f3d10b1dd62967f419c35cfefec7c10ee7 (patch) | |
tree | 2053505fc4cccddb5a366ef26897128b2a65b0cd | |
parent | 5ab7e80f2b477c55be9861ab1c56e33e19aa97a6 (diff) |
Add XferProcessor factory in GrPaint and GrDrawState.
In this CL the XP should have zero effect on the actual rendering pipeline.
BUG=skia:
Review URL: https://codereview.chromium.org/751283002
-rw-r--r-- | gyp/gpu.gypi | 3 | ||||
-rw-r--r-- | include/core/SkXfermode.h | 27 | ||||
-rw-r--r-- | include/gpu/GrBackendProcessorFactory.h | 11 | ||||
-rw-r--r-- | include/gpu/GrInvariantOutput.h | 2 | ||||
-rw-r--r-- | include/gpu/GrPaint.h | 30 | ||||
-rw-r--r-- | include/gpu/GrXferProcessor.h | 62 | ||||
-rw-r--r-- | src/core/SkXfermode.cpp | 34 | ||||
-rwxr-xr-x | src/gpu/GrBitmapTextContext.cpp | 7 | ||||
-rwxr-xr-x | src/gpu/GrDistanceFieldTextContext.cpp | 8 | ||||
-rw-r--r-- | src/gpu/GrDrawState.cpp | 11 | ||||
-rw-r--r-- | src/gpu/GrDrawState.h | 4 | ||||
-rw-r--r-- | src/gpu/GrOptDrawState.cpp | 5 | ||||
-rw-r--r-- | src/gpu/GrOptDrawState.h | 5 | ||||
-rw-r--r-- | src/gpu/GrPaint.cpp | 9 | ||||
-rw-r--r-- | src/gpu/GrProcOptInfo.h | 1 | ||||
-rw-r--r-- | src/gpu/GrProcessor.cpp | 15 | ||||
-rw-r--r-- | src/gpu/SkGr.cpp | 25 | ||||
-rw-r--r-- | src/gpu/effects/GrPorterDuffXferProcessor.cpp | 76 | ||||
-rw-r--r-- | src/gpu/effects/GrPorterDuffXferProcessor.h | 78 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProcessor.h | 12 |
20 files changed, 387 insertions, 38 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index 943e610520..4c5657dbd9 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -35,6 +35,7 @@ '<(skia_include_path)/gpu/GrTextureAccess.h', '<(skia_include_path)/gpu/GrTypes.h', '<(skia_include_path)/gpu/GrUserConfig.h', + '<(skia_include_path)/gpu/GrXferProcessor.h', '<(skia_include_path)/gpu/gl/GrGLConfig.h', '<(skia_include_path)/gpu/gl/GrGLExtensions.h', @@ -195,6 +196,8 @@ '<(skia_src_path)/gpu/effects/GrMatrixConvolutionEffect.h', '<(skia_src_path)/gpu/effects/GrOvalEffect.cpp', '<(skia_src_path)/gpu/effects/GrOvalEffect.h', + '<(skia_src_path)/gpu/effects/GrPorterDuffXferProcessor.cpp', + '<(skia_src_path)/gpu/effects/GrPorterDuffXferProcessor.h', '<(skia_src_path)/gpu/effects/GrRRectEffect.cpp', '<(skia_src_path)/gpu/effects/GrRRectEffect.h', '<(skia_src_path)/gpu/effects/GrSimpleTextureEffect.cpp', diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index 6d723e8fc2..35e9837483 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -15,6 +15,7 @@ class GrFragmentProcessor; class GrTexture; +class GrXPFactory; class SkString; /** \class SkXfermode @@ -198,16 +199,28 @@ public: fragment shader. If NULL, the effect should request access to destination color (setWillReadDstColor()), and use that in the fragment shader (builder->dstColor()). */ + // TODO: Once all custom xp's have been created the background parameter will be required here. + // We will always use the XPFactory if there is no background texture and the fragment if + // there is one. virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture* background = NULL) const; - /** Returns true if the xfermode can be expressed as coeffs (src, dst), or as an effect - (effect). This helper calls the asCoeff() and asFragmentProcessor() virtuals. If the - xfermode is NULL, it is treated as kSrcOver_Mode. It is legal to call this with all params - NULL to simply test the return value. effect, src, and dst must all be NULL or all - non-NULL. + /** A subclass may implement this factory function to work with the GPU backend. It is legal + to call this with xpf NULL to simply test the return value. If xpf is non-NULL then the + xfermode may optionally allocate a factory to return to the caller as *xpf. The caller + will install it and own a ref to it. Since the xfermode may or may not assign *xpf, the + caller should set *xpf to NULL beforehand. XP's cannot use a background texture since they + have no coord transforms. + */ + virtual bool asXPFactory(GrXPFactory** xpf) const; + + /** Returns true if the xfermode can be expressed as an xfer processor factory (xpFactory), + or a fragment processor. This helper calls the asCoeff(), asXPFactory(), + and asFragmentProcessor() virtuals. If the xfermode is NULL, it is treated as kSrcOver_Mode. + It is legal to call this with all params NULL to simply test the return value. + fp, xpf, src, and dst must all be NULL or all non-NULL. */ - static bool asFragmentProcessorOrCoeff(SkXfermode*, GrFragmentProcessor**, Coeff* src, - Coeff* dst, GrTexture* background = NULL); + static bool AsFragmentProcessorOrXPFactory(SkXfermode*, GrFragmentProcessor**, + GrXPFactory**, Coeff* src, Coeff* dst); SK_TO_STRING_PUREVIRT() SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() diff --git a/include/gpu/GrBackendProcessorFactory.h b/include/gpu/GrBackendProcessorFactory.h index 9dda1659d0..acbc12c192 100644 --- a/include/gpu/GrBackendProcessorFactory.h +++ b/include/gpu/GrBackendProcessorFactory.h @@ -115,8 +115,10 @@ private: class GrFragmentProcessor; class GrGeometryProcessor; +class GrXferProcessor; class GrGLFragmentProcessor; class GrGLGeometryProcessor; +class GrGLXferProcessor; /** * Backend processor factory cannot actually create anything, it is up to subclasses to implement @@ -132,6 +134,15 @@ public: virtual GrGLFragmentProcessor* createGLInstance(const GrFragmentProcessor&) const = 0; }; +class GrBackendXferProcessorFactory : public GrBackendProcessorFactory { +public: + /** + * Creates a GrGLProcessor instance that is used both to generate code for the GrProcessor in a + * GLSL program and to manage updating uniforms for the program when it is used. + */ + virtual GrGLXferProcessor* createGLInstance(const GrXferProcessor&) const = 0; +}; + class GrBackendGeometryProcessorFactory : public GrBackendProcessorFactory { public: /** diff --git a/include/gpu/GrInvariantOutput.h b/include/gpu/GrInvariantOutput.h index 0805ac7933..4f61999dcd 100644 --- a/include/gpu/GrInvariantOutput.h +++ b/include/gpu/GrInvariantOutput.h @@ -142,6 +142,8 @@ private: return (fValidFlags == kRGBA_GrColorComponentFlags && 0xFFFFFFFF == fColor); } + bool isSingleComponent() const { return fIsSingleComponent; } + bool willUseInputColor() const { return fWillUseInputColor; } void resetWillUseInputColor() { fWillUseInputColor = true; } diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h index 6a40a71ffc..f31830bb2b 100644 --- a/include/gpu/GrPaint.h +++ b/include/gpu/GrPaint.h @@ -12,6 +12,7 @@ #include "GrColor.h" #include "GrFragmentStage.h" +#include "GrXferProcessor.h" #include "SkXfermode.h" @@ -78,6 +79,11 @@ public: void setDither(bool dither) { fDither = dither; } bool isDither() const { return fDither; } + const GrXPFactory* setXPFactory(const GrXPFactory* xpFactory) { + fXPFactory.reset(SkRef(xpFactory)); + return xpFactory; + } + /** * Appends an additional color processor to the color computation. */ @@ -109,6 +115,8 @@ public: int numCoverageStages() const { return fCoverageStages.count(); } int numTotalStages() const { return this->numColorStages() + this->numCoverageStages(); } + const GrXPFactory* getXPFactory() const { return fXPFactory.get(); } + const GrFragmentStage& getColorStage(int s) const { return fColorStages[s]; } const GrFragmentStage& getCoverageStage(int s) const { return fCoverageStages[s]; } @@ -123,6 +131,8 @@ public: fColorStages = paint.fColorStages; fCoverageStages = paint.fCoverageStages; + fXPFactory.reset(SkRef(paint.getXPFactory())); + return *this; } @@ -197,15 +207,16 @@ private: friend class GrContext; // To access above two functions friend class GrStencilAndCoverTextContext; // To access above two functions - SkSTArray<4, GrFragmentStage> fColorStages; - SkSTArray<2, GrFragmentStage> fCoverageStages; + SkAutoTUnref<const GrXPFactory> fXPFactory; + SkSTArray<4, GrFragmentStage> fColorStages; + SkSTArray<2, GrFragmentStage> fCoverageStages; - GrBlendCoeff fSrcBlendCoeff; - GrBlendCoeff fDstBlendCoeff; - bool fAntiAlias; - bool fDither; + GrBlendCoeff fSrcBlendCoeff; + GrBlendCoeff fDstBlendCoeff; + bool fAntiAlias; + bool fDither; - GrColor fColor; + GrColor fColor; void resetBlend() { fSrcBlendCoeff = kOne_GrBlendCoeff; @@ -221,10 +232,7 @@ private: fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff); } - void resetStages() { - fColorStages.reset(); - fCoverageStages.reset(); - } + void resetStages(); }; #endif diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h new file mode 100644 index 0000000000..139ac96a99 --- /dev/null +++ b/include/gpu/GrXferProcessor.h @@ -0,0 +1,62 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrXferProcessor_DEFINED +#define GrXferProcessor_DEFINED + +#include "GrColor.h" +#include "GrFragmentProcessor.h" +#include "GrTypes.h" +#include "SkXfermode.h" + +/** + * GrXferProcessor is responsible for implementing the xfer mode that blends the src color and dst + * color. It does this by emitting fragment shader code and controlling the fixed-function blend + * state. The inputs to its shader code are the final computed src color and fractional pixel + * coverage. The GrXferProcessor's shader code writes the fragment shader output color that goes + * into the fixed-function blend. When dual-source blending is available, it may also write a + * seconday fragment shader output color. When allowed by the backend API, the GrXferProcessor may + * read the destination color. The GrXferProcessor is responsible for setting the blend coefficients + * and blend constant color. + * + * A GrXferProcessor is never installed directly into our draw state, but instead is created from a + * GrXPFactory once we have finalized the state of our draw. + */ +class GrXferProcessor : public GrFragmentProcessor { +private: + + typedef GrFragmentProcessor INHERITED; +}; + +/** + * We install a GrXPFactory (XPF) early on in the pipeline before all the final draw information is + * known (e.g. whether there is fractional pixel coverage, will coverage be 1 or 4 channel, is the + * draw opaque, etc.). Once the state of the draw is finalized, we use the XPF along with all the + * draw information to create a GrXferProcessor (XP) which can implement the desired blending for + * the draw. + * + * Before the XP is created, the XPF is able to answer queries about what functionality the XPs it + * creates will have. For example, can it create an XP that supports RGB coverage or will the XP + * blend with the destination color. + */ +class GrXPFactory : public GrProgramElement { +public: + virtual const GrXferProcessor* createXferProcessor() const = 0; + + /** + * This function returns true if the GrXferProcessor generated from this factory will be able to + * correctly blend when using RGB coverage. The knownColor and knownColorFlags represent the + * final computed color from the color stages. + */ + virtual bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const = 0; + +private: + typedef GrProgramElement INHERITED; +}; + +#endif + diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index e0abb4ebdd..ef44b1e747 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -6,7 +6,6 @@ * found in the LICENSE file. */ - #include "SkXfermode.h" #include "SkXfermode_opts_SSE2.h" #include "SkXfermode_proccoeff.h" @@ -680,16 +679,41 @@ bool SkXfermode::asFragmentProcessor(GrFragmentProcessor**, GrTexture*) const { return false; } -bool SkXfermode::asFragmentProcessorOrCoeff(SkXfermode* xfermode, GrFragmentProcessor** fp, - Coeff* src, Coeff* dst, GrTexture* background) { +bool SkXfermode::asXPFactory(GrXPFactory**) const { + return false; +} + + +#if SK_SUPPORT_GPU +#include "effects/GrPorterDuffXferProcessor.h" + +bool SkXfermode::AsFragmentProcessorOrXPFactory(SkXfermode* xfermode, + GrFragmentProcessor** fp, + GrXPFactory** xpf, + Coeff* src, Coeff* dst) { if (NULL == xfermode) { - return ModeAsCoeff(kSrcOver_Mode, src, dst); + SkAssertResult(ModeAsCoeff(kSrcOver_Mode, src, dst)); + *xpf = GrPorterDuffXPFactory::Create(*src, *dst); + return true; } else if (xfermode->asCoeff(src, dst)) { + *xpf = GrPorterDuffXPFactory::Create(*src, *dst); + return true; + } else if (xfermode->asXPFactory(xpf)) { + *src = SkXfermode::kOne_Coeff; + *dst = SkXfermode::kZero_Coeff; return true; } else { - return xfermode->asFragmentProcessor(fp, background); + return xfermode->asFragmentProcessor(fp); } } +#else +bool SkXfermode::AsFragmentProcessorOrXPFactory(SkXfermode* xfermode, + GrFragmentProcessor** fp, + GrXPFactory** xpf, + Coeff* src, Coeff* dst) { + return false; +} +#endif SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{ // no-op. subclasses should override this diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp index 3b0bddb8e7..f5e2c298f1 100755 --- a/src/gpu/GrBitmapTextContext.cpp +++ b/src/gpu/GrBitmapTextContext.cpp @@ -561,9 +561,10 @@ void GrBitmapTextContext::flush() { break; // LCD text case kA565_GrMaskFormat: { - if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || - kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || - fPaint.numColorStages()) { + // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD + // processor if the xp can support it. For now we will simply assume that if + // fUseLCDText is true, then we have a known color output. + if (!drawState.getXPFactory()->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) { SkDebugf("LCD Text will not draw correctly.\n"); } SkASSERT(!drawState.hasColorVertexAttribute()); diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp index f5983ac723..f296244d3e 100755 --- a/src/gpu/GrDistanceFieldTextContext.cpp +++ b/src/gpu/GrDistanceFieldTextContext.cpp @@ -628,9 +628,11 @@ void GrDistanceFieldTextContext::flush() { // Set draw state if (fUseLCDText) { GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor); - if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || - kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || - fPaint.numColorStages()) { + + // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD + // processor if the xp can support it. For now we will simply assume that if + // fUseLCDText is true, then we have a known color output. + if (!drawState.getXPFactory()->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) { SkDebugf("LCD Text will not draw correctly.\n"); } SkASSERT(!drawState.hasColorVertexAttribute()); diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp index ff58c4899a..0fd098740c 100644 --- a/src/gpu/GrDrawState.cpp +++ b/src/gpu/GrDrawState.cpp @@ -11,8 +11,10 @@ #include "GrOptDrawState.h" #include "GrPaint.h" #include "GrProcOptInfo.h" +#include "GrXferProcessor.h" +#include "effects/GrPorterDuffXferProcessor.h" -//////////////////////////////////////////////////////////////////////////////s +/////////////////////////////////////////////////////////////////////////////// bool GrDrawState::isEqual(const GrDrawState& that) const { bool usingVertexColors = this->hasColorVertexAttribute(); @@ -92,6 +94,7 @@ GrDrawState& GrDrawState::operator=(const GrDrawState& that) { fCoverage = that.fCoverage; fDrawFace = that.fDrawFace; fGeometryProcessor.reset(SkSafeRef(that.fGeometryProcessor.get())); + fXPFactory.reset(SkRef(that.getXPFactory())); fColorStages = that.fColorStages; fCoverageStages = that.fCoverageStages; @@ -113,6 +116,8 @@ void GrDrawState::onReset(const SkMatrix* initialViewMatrix) { fRenderTarget.reset(NULL); fGeometryProcessor.reset(NULL); + fXPFactory.reset(GrPorterDuffXPFactory::Create(kOne_GrBlendCoeff, + kZero_GrBlendCoeff)); fColorStages.reset(); fCoverageStages.reset(); @@ -169,6 +174,9 @@ void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRende fCoverageStages.push_back(paint.getCoverageStage(i)); } + fXPFactory.reset(SkRef(paint.getXPFactory())); + + this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff()); this->setRenderTarget(rt); fViewMatrix = vm; @@ -187,7 +195,6 @@ void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRende this->setState(GrDrawState::kDither_StateBit, paint.isDither()); this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias()); - this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff()); this->setCoverage(0xFF); fColorProcInfoValid = false; fCoverageProcInfoValid = false; diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index a236d1a559..39163ff5ee 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -203,6 +203,9 @@ public: bool hasGeometryProcessor() const { return SkToBool(fGeometryProcessor.get()); } const GrGeometryProcessor* getGeometryProcessor() const { return fGeometryProcessor.get(); } + + const GrXPFactory* getXPFactory() const { return fXPFactory.get(); } + const GrFragmentStage& getColorStage(int idx) const { return fColorStages[idx]; } const GrFragmentStage& getCoverageStage(int idx) const { return fCoverageStages[idx]; } @@ -721,6 +724,7 @@ private: GrBlendCoeff fSrcBlend; GrBlendCoeff fDstBlend; SkAutoTUnref<const GrGeometryProcessor> fGeometryProcessor; + SkAutoTUnref<const GrXPFactory> fXPFactory; FragmentStageArray fColorStages; FragmentStageArray fCoverageStages; uint32_t fHints; diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp index 41a34c4ed2..6f6f0af888 100644 --- a/src/gpu/GrOptDrawState.cpp +++ b/src/gpu/GrOptDrawState.cpp @@ -100,6 +100,11 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, drawState.hasGeometryProcessor()); fGeometryProcessor.reset(drawState.getGeometryProcessor()); + // Create XferProcessor from DS's XPFactory + const GrXferProcessor* xpProcessor = drawState.getXPFactory()->createXferProcessor(); + fXferProcessor.reset(xpProcessor); + xpProcessor->unref(); + // Copy Stages from DS to ODS for (int i = firstColorStageIdx; i < drawState.numColorStages(); ++i) { SkNEW_APPEND_TO_TARRAY(&fFragmentStages, diff --git a/src/gpu/GrOptDrawState.h b/src/gpu/GrOptDrawState.h index 542172fd64..ac7ec16402 100644 --- a/src/gpu/GrOptDrawState.h +++ b/src/gpu/GrOptDrawState.h @@ -84,6 +84,9 @@ public: bool hasGeometryProcessor() const { return SkToBool(fGeometryProcessor.get()); } const GrGeometryProcessor* getGeometryProcessor() const { return fGeometryProcessor.get(); } + + const GrXferProcessor* getXferProcessor() const { return fXferProcessor.get(); } + const GrPendingFragmentStage& getColorStage(int idx) const { SkASSERT(idx < this->numColorStages()); return fFragmentStages[idx]; @@ -230,6 +233,7 @@ private: typedef GrPendingIOResource<GrRenderTarget, kWrite_GrIOType> RenderTarget; typedef SkSTArray<8, GrPendingFragmentStage> FragmentStageArray; typedef GrPendingProgramElement<const GrGeometryProcessor> ProgramGeometryProcessor; + typedef GrPendingProgramElement<const GrXferProcessor> ProgramXferProcessor; RenderTarget fRenderTarget; ScissorState fScissorState; GrColor fColor; @@ -243,6 +247,7 @@ private: GrBlendCoeff fDstBlend; uint32_t fFlags; ProgramGeometryProcessor fGeometryProcessor; + ProgramXferProcessor fXferProcessor; FragmentStageArray fFragmentStages; // This function is equivalent to the offset into fFragmentStages where coverage stages begin. diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp index 7d89535a11..bd5b2860f4 100644 --- a/src/gpu/GrPaint.cpp +++ b/src/gpu/GrPaint.cpp @@ -10,6 +10,7 @@ #include "GrBlend.h" #include "GrProcOptInfo.h" +#include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrSimpleTextureEffect.h" void GrPaint::addColorTextureProcessor(GrTexture* texture, const SkMatrix& matrix) { @@ -48,6 +49,13 @@ bool GrPaint::isOpaqueAndConstantColor(GrColor* color) const { return false; } +void GrPaint::resetStages() { + fColorStages.reset(); + fCoverageStages.reset(); + fXPFactory.reset(GrPorterDuffXPFactory::Create(kOne_GrBlendCoeff, + kZero_GrBlendCoeff)); +} + bool GrPaint::getOpaqueAndKnownColor(GrColor* solidColor, uint32_t* solidColorKnownComponents) const { @@ -114,3 +122,4 @@ bool GrPaint::getOpaqueAndKnownColor(GrColor* solidColor, } return opaque; } + diff --git a/src/gpu/GrProcOptInfo.h b/src/gpu/GrProcOptInfo.h index 5252e85354..bb657d27c0 100644 --- a/src/gpu/GrProcOptInfo.h +++ b/src/gpu/GrProcOptInfo.h @@ -35,6 +35,7 @@ public: bool isSolidWhite() const { return fInOut.isSolidWhite(); } bool isOpaque() const { return fInOut.isOpaque(); } + bool isSingleComponent() const { return fInOut.isSingleComponent(); } GrColor color() const { return fInOut.color(); } uint8_t validFlags() const { return fInOut.validFlags(); } diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp index d850d6894a..8aeef04b48 100644 --- a/src/gpu/GrProcessor.cpp +++ b/src/gpu/GrProcessor.cpp @@ -28,6 +28,13 @@ GrProcessorTestFactory<GrFragmentProcessor>::GetFactories() { } template<> +SkTArray<GrProcessorTestFactory<GrXferProcessor>*, true>* +GrProcessorTestFactory<GrXferProcessor>::GetFactories() { + static SkTArray<GrProcessorTestFactory<GrXferProcessor>*, true> gFactories; + return &gFactories; +} + +template<> SkTArray<GrProcessorTestFactory<GrGeometryProcessor>*, true>* GrProcessorTestFactory<GrGeometryProcessor>::GetFactories() { static SkTArray<GrProcessorTestFactory<GrGeometryProcessor>*, true> gFactories; @@ -41,6 +48,7 @@ GrProcessorTestFactory<GrGeometryProcessor>::GetFactories() { */ static const int kFPFactoryCount = 37; static const int kGPFactoryCount = 14; +static const int kXPFactoryCount = 0; template<> void GrProcessorTestFactory<GrFragmentProcessor>::VerifyFactoryCount() { @@ -56,6 +64,13 @@ void GrProcessorTestFactory<GrGeometryProcessor>::VerifyFactoryCount() { } } +template<> +void GrProcessorTestFactory<GrXferProcessor>::VerifyFactoryCount() { + if (kXPFactoryCount != GetFactories()->count()) { + SkFAIL("Wrong number of xfer processor factories!"); + } +} + #endif namespace GrProcessorUnitTest { diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index d71b05ad7d..dadf9f23ee 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -6,15 +6,18 @@ */ #include "SkGr.h" + +#include "GrDrawTargetCaps.h" +#include "GrGpu.h" +#include "GrXferProcessor.h" #include "SkColorFilter.h" #include "SkConfig8888.h" #include "SkData.h" #include "SkMessageBus.h" #include "SkPixelRef.h" #include "SkTextureCompressor.h" -#include "GrGpu.h" #include "effects/GrDitherEffect.h" -#include "GrDrawTargetCaps.h" +#include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrYUVtoRGBEffect.h" #ifndef SK_IGNORE_ETC1_SUPPORT @@ -465,19 +468,27 @@ void SkPaint2GrPaintNoShader(GrContext* context, const SkPaint& skPaint, GrColor SkXfermode::Coeff dm; SkXfermode* mode = skPaint.getXfermode(); - GrFragmentProcessor* xferProcessor = NULL; - if (SkXfermode::asFragmentProcessorOrCoeff(mode, &xferProcessor, &sm, &dm)) { - if (xferProcessor) { - grPaint->addColorProcessor(xferProcessor)->unref(); + GrFragmentProcessor* fragmentProcessor = NULL; + GrXPFactory* xpFactory = NULL; + if (SkXfermode::AsFragmentProcessorOrXPFactory(mode, &fragmentProcessor, &xpFactory, + &sm, &dm)) { + if (fragmentProcessor) { + SkASSERT(NULL == xpFactory); + grPaint->addColorProcessor(fragmentProcessor)->unref(); + xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kOne_Coeff, + SkXfermode::kZero_Coeff); sm = SkXfermode::kOne_Coeff; dm = SkXfermode::kZero_Coeff; } } else { - //SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");) // Fall back to src-over + xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kOne_Coeff, + SkXfermode::kISA_Coeff); sm = SkXfermode::kOne_Coeff; dm = SkXfermode::kISA_Coeff; } + SkASSERT(xpFactory); + grPaint->setXPFactory(xpFactory)->unref(); grPaint->setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm)); //set the color of the paint to the one of the parameter diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp new file mode 100644 index 0000000000..fdbcbbe656 --- /dev/null +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrPorterDuffXferProcessor.h" + +#include "GrBackendProcessorFactory.h" +#include "GrDrawState.h" +#include "GrInvariantOutput.h" +#include "GrProcessor.h" +#include "GrTBackendProcessorFactory.h" +#include "GrTypes.h" +#include "GrXferProcessor.h" +#include "gl/GrGLProcessor.h" +#include "gl/builders/GrGLFragmentShaderBuilder.h" +#include "gl/builders/GrGLProgramBuilder.h" + +class GrGLPorterDuffXferProcessor : public GrGLXferProcessor { +public: + GrGLPorterDuffXferProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&) + : INHERITED(factory) {} + + virtual ~GrGLPorterDuffXferProcessor() {} + + virtual void emitCode(GrGLFPBuilder* builder, + const GrFragmentProcessor& fp, + const char* outputColor, + const char* inputColor, + const TransformedCoordsArray& coords, + const TextureSamplerArray& samplers) SK_OVERRIDE { + GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); + fsBuilder->codeAppendf("%s = %s;", outputColor, inputColor); + } + + virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}; + + static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyBuilder* b) {}; + +private: + typedef GrGLXferProcessor INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend) + : fSrcBlend(srcBlend), fDstBlend(dstBlend) {} + +GrPorterDuffXferProcessor::~GrPorterDuffXferProcessor() { +} + +const GrBackendFragmentProcessorFactory& GrPorterDuffXferProcessor::getFactory() const { + return GrTBackendFragmentProcessorFactory<GrPorterDuffXferProcessor>::getInstance(); +} + +void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const { + inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput); +} + +/////////////////////////////////////////////////////////////////////////////// + +const GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor() const { + return GrPorterDuffXferProcessor::Create(fSrc, fDst); +} + +bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, + uint32_t knownColorFlags) const { + if (kOne_GrBlendCoeff == fSrc && kISA_GrBlendCoeff == fDst && + kRGBA_GrColorComponentFlags == knownColorFlags) { + return true; + } + return false; +} + diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.h b/src/gpu/effects/GrPorterDuffXferProcessor.h new file mode 100644 index 0000000000..474285d829 --- /dev/null +++ b/src/gpu/effects/GrPorterDuffXferProcessor.h @@ -0,0 +1,78 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrPorterDuffXferProcessor_DEFINED +#define GrPorterDuffXferProcessor_DEFINED + +#include "GrTypes.h" +#include "GrXferProcessor.h" +#include "SkXfermode.h" + +class GrBackendFragmentProcessorFactory; +class GrDrawState; +class GrGLPorterDuffXferProcessor; +class GrInvariantOutput; + +class GrPorterDuffXferProcessor : public GrXferProcessor { +public: + static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend) { + return SkNEW_ARGS(GrPorterDuffXferProcessor, (srcBlend, dstBlend)); + } + + virtual ~GrPorterDuffXferProcessor(); + + virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE; + + typedef GrGLPorterDuffXferProcessor GLProcessor; + static const char* Name() { return "Porter Duff"; } + +private: + GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend); + + virtual bool onIsEqual(const GrFragmentProcessor& fpBase) const SK_OVERRIDE { + const GrPorterDuffXferProcessor& xp = fpBase.cast<GrPorterDuffXferProcessor>(); + if (fSrcBlend != xp.fSrcBlend || fDstBlend != xp.fDstBlend) { + return false; + } + return true; + } + + virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE; + + GrBlendCoeff fSrcBlend; + GrBlendCoeff fDstBlend; + + typedef GrXferProcessor INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class GrPorterDuffXPFactory : public GrXPFactory { +public: + static GrXPFactory* Create(SkXfermode::Coeff src, SkXfermode::Coeff dst) { + return SkNEW_ARGS(GrPorterDuffXPFactory, ((GrBlendCoeff)(src), (GrBlendCoeff)(dst))); + } + + static GrXPFactory* Create(GrBlendCoeff src, GrBlendCoeff dst) { + return SkNEW_ARGS(GrPorterDuffXPFactory, (src, dst)); + } + + const GrXferProcessor* createXferProcessor() const SK_OVERRIDE; + + bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const SK_OVERRIDE; + +private: + GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) + : fSrc(src), fDst(dst) {} + + GrBlendCoeff fSrc; + GrBlendCoeff fDst; + + typedef GrXPFactory INHERITED; +}; + +#endif diff --git a/src/gpu/gl/GrGLProcessor.h b/src/gpu/gl/GrGLProcessor.h index 4bc3dd019b..ca4fa2459f 100644 --- a/src/gpu/gl/GrGLProcessor.h +++ b/src/gpu/gl/GrGLProcessor.h @@ -125,4 +125,16 @@ private: typedef GrGLProcessor INHERITED; }; +class GrGLXferProcessor : public GrGLFragmentProcessor { +public: + GrGLXferProcessor(const GrBackendProcessorFactory& factory) + : INHERITED(factory) { + } + + virtual ~GrGLXferProcessor() {} + +private: + typedef GrGLFragmentProcessor INHERITED; +}; + #endif |