diff options
40 files changed, 1126 insertions, 1095 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index 70a518f34d..d0e8983c7d 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -72,6 +72,7 @@ '<(skia_src_path)/gpu/GrBatchFlushState.h', '<(skia_src_path)/gpu/GrBatchTest.cpp', '<(skia_src_path)/gpu/GrBatchTest.h', + '<(skia_src_path)/gpu/GrBlend.cpp', '<(skia_src_path)/gpu/GrBlurUtils.cpp', '<(skia_src_path)/gpu/GrBlurUtils.h', '<(skia_src_path)/gpu/GrBufferAllocPool.cpp', @@ -138,6 +139,7 @@ '<(skia_src_path)/gpu/GrProcessor.cpp', '<(skia_src_path)/gpu/GrProcessorUnitTest.cpp', '<(skia_src_path)/gpu/GrProcessorDataManager.cpp', + '<(skia_src_path)/gpu/GrProcessorUnitTest.cpp', '<(skia_src_path)/gpu/GrProcOptInfo.cpp', '<(skia_src_path)/gpu/GrProcOptInfo.h', '<(skia_src_path)/gpu/GrGpuResourceRef.cpp', @@ -245,7 +247,6 @@ '<(skia_src_path)/gpu/effects/GrExtractAlphaFragmentProcessor.cpp', '<(skia_src_path)/gpu/effects/GrCoverageSetOpXP.cpp', '<(skia_src_path)/gpu/effects/GrCustomXfermode.cpp', - '<(skia_src_path)/gpu/effects/GrCustomXfermodePriv.h', '<(skia_src_path)/gpu/effects/GrBezierEffect.cpp', '<(skia_src_path)/gpu/effects/GrBezierEffect.h', '<(skia_src_path)/gpu/effects/GrConvolutionEffect.cpp', @@ -285,8 +286,8 @@ '<(skia_src_path)/gpu/gl/GrGLAssembleInterface.cpp', '<(skia_src_path)/gpu/gl/GrGLAssembleInterface.h', - '<(skia_src_path)/gpu/gl/GrGLBlend.cpp', - '<(skia_src_path)/gpu/gl/GrGLBlend.h', + '<(skia_src_path)/gpu/gl/GrGLSLBlend.cpp', + '<(skia_src_path)/gpu/gl/GrGLSLBlend.h', '<(skia_src_path)/gpu/gl/GrGLBufferImpl.cpp', '<(skia_src_path)/gpu/gl/GrGLBufferImpl.h', '<(skia_src_path)/gpu/gl/GrGLCaps.cpp', diff --git a/include/core/SkColorFilter.h b/include/core/SkColorFilter.h index 51c07f1cdb..a92f9aeff2 100644 --- a/include/core/SkColorFilter.h +++ b/include/core/SkColorFilter.h @@ -136,7 +136,7 @@ public: * If the subclass returns false, then it should not modify the array at all. */ virtual bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>*) const { + SkTDArray<const GrFragmentProcessor*>*) const { return false; } diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index 0b8f936bed..a438c5b4ca 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -194,15 +194,15 @@ public: */ static bool IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType); - /** Implemented by a subclass to support use as an image filter in the GPU backend. When used as - an image filter the xfer mode blends the source color against a background texture rather - than the destination. It is implemented as a fragment processor. This can be called with - both params set to NULL to query whether it would succeed. Otherwise, both params are - required. Upon success the function returns true and the caller owns a ref to the fragment - parameter. Upon failure false is returned and the processor param is not written to. + /** Used to do in-shader blending between two colors computed in the shader via a + GrFragmentProcessor. The input to the returned FP is the src color. The dst color is + provided by the dst param which becomes a child FP of the returned FP. If the params are + null then this is just a query of whether the SkXfermode could support this functionality. + It is legal for the function to succeed but return a null output. This indicates that + the output of the blend is simply the src color. */ - virtual bool asFragmentProcessor(GrFragmentProcessor**, GrProcessorDataManager*, - GrTexture* background) const; + virtual bool asFragmentProcessor(const GrFragmentProcessor** output, GrProcessorDataManager*, + const GrFragmentProcessor* dst) const; /** 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 @@ -226,7 +226,7 @@ protected: SkXfermode() {} /** The default implementation of xfer32/xfer16/xferA8 in turn call this method, 1 color at a time (upscaled to a SkPMColor). The default - implmentation of this method just returns dst. If performance is + implementation of this method just returns dst. If performance is important, your subclass should override xfer32/xfer16/xferA8 directly. This method will not be called directly by the client, so it need not diff --git a/include/effects/SkColorCubeFilter.h b/include/effects/SkColorCubeFilter.h index 6af4668151..d1c566e5d2 100644 --- a/include/effects/SkColorCubeFilter.h +++ b/include/effects/SkColorCubeFilter.h @@ -26,7 +26,7 @@ public: #if SK_SUPPORT_GPU bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>*) const override; + SkTDArray<const GrFragmentProcessor*>*) const override; #endif SK_TO_STRING_OVERRIDE() diff --git a/include/effects/SkColorMatrixFilter.h b/include/effects/SkColorMatrixFilter.h index 9f16643bd6..3c80c61ef9 100644 --- a/include/effects/SkColorMatrixFilter.h +++ b/include/effects/SkColorMatrixFilter.h @@ -27,7 +27,7 @@ public: #if SK_SUPPORT_GPU bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>*) const override; + SkTDArray<const GrFragmentProcessor*>*) const override; #endif struct State { diff --git a/include/effects/SkLumaColorFilter.h b/include/effects/SkLumaColorFilter.h index 6dd364fe4e..00ba856a70 100644 --- a/include/effects/SkLumaColorFilter.h +++ b/include/effects/SkLumaColorFilter.h @@ -29,7 +29,7 @@ public: #if SK_SUPPORT_GPU bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>*) const override; + SkTDArray<const GrFragmentProcessor*>*) const override; #endif SK_TO_STRING_OVERRIDE() diff --git a/include/effects/SkModeColorFilter.h b/include/effects/SkModeColorFilter.h index a90990ab91..c3be8ce46a 100644 --- a/include/effects/SkModeColorFilter.h +++ b/include/effects/SkModeColorFilter.h @@ -40,7 +40,7 @@ public: #if SK_SUPPORT_GPU bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>*) const override; + SkTDArray<const GrFragmentProcessor*>*) const override; #endif SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkModeColorFilter) diff --git a/include/gpu/GrBlend.h b/include/gpu/GrBlend.h index 51c19f9721..5100bb0539 100644 --- a/include/gpu/GrBlend.h +++ b/include/gpu/GrBlend.h @@ -6,12 +6,12 @@ * found in the LICENSE file. */ -#include "GrTypes.h" -#include "../private/SkTLogic.h" - #ifndef GrBlend_DEFINED #define GrBlend_DEFINED +#include "GrColor.h" +#include "../private/SkTLogic.h" + /** * Equations for alpha-blending. */ @@ -46,7 +46,7 @@ static const int kGrBlendEquationCnt = kLast_GrBlendEquation + 1; /** - * Coeffecients for alpha-blending. + * Coefficients for alpha-blending. */ enum GrBlendCoeff { kZero_GrBlendCoeff, //<! 0 @@ -73,6 +73,19 @@ enum GrBlendCoeff { static const int kGrBlendCoeffCnt = kLast_GrBlendCoeff + 1; +/** + * Given a known blend equation in the form of srcCoeff * srcColor + dstCoeff * dstColor where + * there may be partial knowledge of the srcColor and dstColor component values, determine what + * components of the blended output color are known. Coeffs must not refer to the constant or + * secondary src color. + */ +void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff, + GrColor srcColor, + GrColorComponentFlags srcColorFlags, + GrColor dstColor, + GrColorComponentFlags dstColorFlags, + GrColor* outColor, + GrColorComponentFlags* outFlags); template<GrBlendCoeff Coeff> struct GrTBlendCoeffRefsSrc : skstd::bool_constant<kSC_GrBlendCoeff == Coeff || @@ -95,7 +108,6 @@ inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) { } } - template<GrBlendCoeff Coeff> struct GrTBlendCoeffRefsDst : skstd::bool_constant<kDC_GrBlendCoeff == Coeff || kIDC_GrBlendCoeff == Coeff || diff --git a/include/gpu/GrColor.h b/include/gpu/GrColor.h index 9ccc638fc9..7e2b3b263f 100644 --- a/include/gpu/GrColor.h +++ b/include/gpu/GrColor.h @@ -77,7 +77,7 @@ static inline GrColor GrColorPackA4(unsigned a) { #define GrColor_ILLEGAL (~(0xFF << GrColor_SHIFT_A)) #define GrColor_WHITE 0xFFFFFFFF -#define GrColor_TRANS_BLACK 0x0 +#define GrColor_TRANSPARENT_BLACK 0x0 /** * Assert in debug builds that a GrColor is premultiplied. @@ -95,6 +95,31 @@ static inline void GrColorIsPMAssert(GrColor SkDEBUGCODE(c)) { #endif } +/** Inverts each color channel. */ +static inline GrColor GrInvertColor(GrColor c) { + U8CPU a = GrColorUnpackA(c); + U8CPU r = GrColorUnpackR(c); + U8CPU g = GrColorUnpackG(c); + U8CPU b = GrColorUnpackB(c); + return GrColorPackRGBA(0xff - r, 0xff - g, 0xff - b, 0xff - a); +} + +static inline GrColor GrColorMul(GrColor c0, GrColor c1) { + U8CPU r = SkMulDiv255Round(GrColorUnpackR(c0), GrColorUnpackR(c1)); + U8CPU g = SkMulDiv255Round(GrColorUnpackG(c0), GrColorUnpackG(c1)); + U8CPU b = SkMulDiv255Round(GrColorUnpackB(c0), GrColorUnpackB(c1)); + U8CPU a = SkMulDiv255Round(GrColorUnpackA(c0), GrColorUnpackA(c1)); + return GrColorPackRGBA(r, g, b, a); +} + +static inline GrColor GrColorSatAdd(GrColor c0, GrColor c1) { + unsigned r = SkTMin<unsigned>(GrColorUnpackR(c0) + GrColorUnpackR(c1), 0xff); + unsigned g = SkTMin<unsigned>(GrColorUnpackG(c0) + GrColorUnpackG(c1), 0xff); + unsigned b = SkTMin<unsigned>(GrColorUnpackB(c0) + GrColorUnpackB(c1), 0xff); + unsigned a = SkTMin<unsigned>(GrColorUnpackA(c0) + GrColorUnpackA(c1), 0xff); + return GrColorPackRGBA(r, g, b, a); +} + /** Converts a GrColor to an rgba array of GrGLfloat */ static inline void GrColorToRGBAFloat(GrColor color, float rgba[4]) { static const float ONE_OVER_255 = 1.f / 255.f; @@ -115,8 +140,20 @@ static inline bool GrColorIsOpaque(GrColor color) { return (color & (0xFFU << GrColor_SHIFT_A)) == (0xFFU << GrColor_SHIFT_A); } +static inline GrColor GrPremulColor(GrColor color) { + unsigned r = GrColorUnpackR(color); + unsigned g = GrColorUnpackG(color); + unsigned b = GrColorUnpackB(color); + unsigned a = GrColorUnpackA(color); + return GrColorPackRGBA(SkMulDiv255Round(r, a), + SkMulDiv255Round(g, a), + SkMulDiv255Round(b, a), + a); +} + /** Returns an unpremuled version of the GrColor. */ -static inline GrColor GrUnPreMulColor(GrColor color) { +static inline GrColor GrUnpremulColor(GrColor color) { + GrColorIsPMAssert(color); unsigned r = GrColorUnpackR(color); unsigned g = GrColorUnpackG(color); unsigned b = GrColorUnpackB(color); diff --git a/include/gpu/GrInvariantOutput.h b/include/gpu/GrInvariantOutput.h index 29f83ed15d..83deac39f7 100644 --- a/include/gpu/GrInvariantOutput.h +++ b/include/gpu/GrInvariantOutput.h @@ -12,7 +12,7 @@ struct GrInitInvariantOutput { GrInitInvariantOutput() - : fValidFlags(0) + : fValidFlags(kNone_GrColorComponentFlags) , fColor(0) , fIsSingleComponent(false) , fIsLCDCoverage(false) {} @@ -24,7 +24,7 @@ struct GrInitInvariantOutput { } void setUnknownFourComponents() { - fValidFlags = 0; + fValidFlags = kNone_GrColorComponentFlags; fIsSingleComponent = false; } @@ -41,16 +41,17 @@ struct GrInitInvariantOutput { } void setUnknownSingleComponent() { - fValidFlags = 0; + fValidFlags = kNone_GrColorComponentFlags; fIsSingleComponent = true; } void setUsingLCDCoverage() { fIsLCDCoverage = true; } - uint32_t fValidFlags; - GrColor fColor; - bool fIsSingleComponent; - bool fIsLCDCoverage; // Temorary data member until texture pixel configs are updated + GrColorComponentFlags fValidFlags; + GrColor fColor; + bool fIsSingleComponent; + bool fIsLCDCoverage; // Temorary data member until texture pixel configs are + // updated }; class GrInvariantOutput { @@ -107,7 +108,7 @@ public: this->internalSetToTransparentBlack(); } else { // We don't need to change fIsSingleComponent in this case - fValidFlags = 0; + fValidFlags = kNone_GrColorComponentFlags; } SkDEBUGCODE(this->validate()); } @@ -171,7 +172,7 @@ public: } } else { fIsSingleComponent = false; - fValidFlags = 0; + fValidFlags = kNone_GrColorComponentFlags; } SkDEBUGCODE(this->validate()); } @@ -189,16 +190,16 @@ public: fColor = GrColorPackRGBA(a, a, a, a); fValidFlags = kRGBA_GrColorComponentFlags; } else { - fValidFlags = 0; + fValidFlags = kNone_GrColorComponentFlags; } fIsSingleComponent = true; } SkDEBUGCODE(this->validate()); } - void invalidateComponents(uint8_t invalidateFlags, ReadInput readsInput) { + void invalidateComponents(GrColorComponentFlags invalidateFlags, ReadInput readsInput) { SkDEBUGCODE(this->validate()); - fValidFlags &= ~invalidateFlags; + fValidFlags = (fValidFlags & ~invalidateFlags); fIsSingleComponent = false; fNonMulStageFound = true; if (kWillNot_ReadInput == readsInput) { @@ -207,7 +208,7 @@ public: SkDEBUGCODE(this->validate()); } - void setToOther(uint8_t validFlags, GrColor color, ReadInput readsInput) { + void setToOther(GrColorComponentFlags validFlags, GrColor color, ReadInput readsInput) { SkDEBUGCODE(this->validate()); fValidFlags = validFlags; fColor = color; @@ -247,7 +248,7 @@ public: } GrColor color() const { return fColor; } - uint8_t validFlags() const { return fValidFlags; } + GrColorComponentFlags validFlags() const { return fValidFlags; } /** * If isSingleComponent is true, then the flag values for r, g, b, and a must all be the @@ -289,7 +290,7 @@ private: } void internalSetToUnknown() { - fValidFlags = 0; + fValidFlags = kNone_GrColorComponentFlags; fIsSingleComponent = false; } @@ -322,7 +323,7 @@ private: SkDEBUGCODE(bool validPreMulColor() const;) GrColor fColor; - uint32_t fValidFlags; + GrColorComponentFlags fValidFlags; bool fIsSingleComponent; bool fNonMulStageFound; bool fWillUseInputColor; diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h index 68b93a1f8a..99a361bca1 100644 --- a/include/gpu/SkGr.h +++ b/include/gpu/SkGr.h @@ -38,8 +38,9 @@ GR_STATIC_ASSERT((int)kSA_GrBlendCoeff == (int)SkXfermode::kSA_Coeff); GR_STATIC_ASSERT((int)kISA_GrBlendCoeff == (int)SkXfermode::kISA_Coeff); GR_STATIC_ASSERT((int)kDA_GrBlendCoeff == (int)SkXfermode::kDA_Coeff); GR_STATIC_ASSERT((int)kIDA_GrBlendCoeff == (int)SkXfermode::kIDA_Coeff); +GR_STATIC_ASSERT(SkXfermode::kCoeffCount == 10); -#define sk_blend_to_grblend(X) ((GrBlendCoeff)(X)) +#define SkXfermodeCoeffToGrBlendCoeff(X) ((GrBlendCoeff)(X)) /////////////////////////////////////////////////////////////////////////////// @@ -67,6 +68,16 @@ static inline GrColor SkColor2GrColorJustAlpha(SkColor c) { return GrColorPackRGBA(a, a, a, a); } +static inline SkPMColor GrColorToSkPMColor(GrColor c) { + GrColorIsPMAssert(c); + return SkPackARGB32(GrColorUnpackA(c), GrColorUnpackR(c), GrColorUnpackG(c), GrColorUnpackB(c)); +} + +static inline GrColor SkPMColorToGrColor(SkPMColor c) { + return GrColorPackRGBA(SkGetPackedR32(c), SkGetPackedG32(c), SkGetPackedB32(c), + SkGetPackedA32(c)); +} + //////////////////////////////////////////////////////////////////////////////// /** diff --git a/include/gpu/effects/GrCustomXfermode.h b/include/gpu/effects/GrCustomXfermode.h index 557397077e..bcbd5833ca 100644 --- a/include/gpu/effects/GrCustomXfermode.h +++ b/include/gpu/effects/GrCustomXfermode.h @@ -10,21 +10,14 @@ #include "SkXfermode.h" -class GrFragmentProcessor; class GrTexture; /** * Custom Xfer modes are used for blending when the blend mode cannot be represented using blend - * coefficients. It is assumed that all blending is done within the processors' emit code. For each - * blend mode there should be a matching fragment processor (used when blending with a background - * texture) and xfer processor. + * coefficients. */ namespace GrCustomXfermode { - bool IsSupportedMode(SkXfermode::Mode mode); - - GrFragmentProcessor* CreateFP(GrProcessorDataManager*, SkXfermode::Mode mode, - GrTexture* background); - + bool IsSupportedMode(SkXfermode::Mode mode); GrXPFactory* CreateXPFactory(SkXfermode::Mode mode); }; diff --git a/include/gpu/effects/GrXfermodeFragmentProcessor.h b/include/gpu/effects/GrXfermodeFragmentProcessor.h index d93b400b8b..e2d1c0a544 100644 --- a/include/gpu/effects/GrXfermodeFragmentProcessor.h +++ b/include/gpu/effects/GrXfermodeFragmentProcessor.h @@ -13,6 +13,16 @@ class GrFragmentProcessor; namespace GrXfermodeFragmentProcessor { + /** The color input to the returned processor is treated as the src and the passed in processor + is the dst. */ + const GrFragmentProcessor* CreateFromDstProcessor(const GrFragmentProcessor* dst, + SkXfermode::Mode mode); + + /** The color input to the returned processor is treated as the dst and the passed in processor + is the src. */ + const GrFragmentProcessor* CreateFromSrcProcessor(const GrFragmentProcessor* src, + SkXfermode::Mode mode); + const GrFragmentProcessor* CreateFromTwoProcessors(const GrFragmentProcessor* src, const GrFragmentProcessor* dst, SkXfermode::Mode mode); diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp index c67869fd65..4605a1d7ab 100644 --- a/src/core/SkColorFilter.cpp +++ b/src/core/SkColorFilter.cpp @@ -68,7 +68,7 @@ public: #if SK_SUPPORT_GPU bool asFragmentProcessors(GrContext* context, GrProcessorDataManager* procDataManager, - SkTDArray<GrFragmentProcessor*>* array) const override { + SkTDArray<const GrFragmentProcessor*>* array) const override { bool hasFrags = fInner->asFragmentProcessors(context, procDataManager, array); hasFrags |= fOuter->asFragmentProcessors(context, procDataManager, array); return hasFrags; diff --git a/src/core/SkComposeShader.cpp b/src/core/SkComposeShader.cpp index 41b978b5c8..024064b50a 100644 --- a/src/core/SkComposeShader.cpp +++ b/src/core/SkComposeShader.cpp @@ -207,17 +207,15 @@ const GrFragmentProcessor* SkComposeShader::asFragmentProcessor(GrContext* conte 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. + // Fragment processor will only support SkXfermode::Mode modes currently. SkXfermode::Mode mode; - if (!(SkXfermode::AsMode(fMode, &mode) && SkXfermode::kLastCoeffMode >= mode)) { + if (!(SkXfermode::AsMode(fMode, &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: diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 8548fe8aac..3fb44b4d3b 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -651,8 +651,8 @@ bool SkXfermode::asMode(Mode* mode) const { return false; } -bool SkXfermode::asFragmentProcessor(GrFragmentProcessor**, GrProcessorDataManager*, - GrTexture*) const { +bool SkXfermode::asFragmentProcessor(const GrFragmentProcessor**, GrProcessorDataManager*, + const GrFragmentProcessor*) const { return false; } @@ -920,19 +920,18 @@ void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst, #if SK_SUPPORT_GPU #include "effects/GrCustomXfermode.h" +#include "effects/GrXfermodeFragmentProcessor.h" -bool SkProcCoeffXfermode::asFragmentProcessor(GrFragmentProcessor** fp, +bool SkProcCoeffXfermode::asFragmentProcessor(const GrFragmentProcessor** fp, GrProcessorDataManager* procDataManager, - GrTexture* background) const { - if (GrCustomXfermode::IsSupportedMode(fMode)) { - if (fp) { - SkASSERT(procDataManager); - *fp = GrCustomXfermode::CreateFP(procDataManager, fMode, background); - SkASSERT(*fp); - } - return true; + const GrFragmentProcessor* dst) const { + if (fp) { + SkASSERT(dst); + SkASSERT(procDataManager); + *fp = GrXfermodeFragmentProcessor::CreateFromDstProcessor(dst, fMode); + SkASSERT(*fp || kSrc_Mode == fMode); } - return false; + return true; } bool SkProcCoeffXfermode::asXPFactory(GrXPFactory** xp) const { diff --git a/src/core/SkXfermode_proccoeff.h b/src/core/SkXfermode_proccoeff.h index bbd274d26d..e34f22a493 100644 --- a/src/core/SkXfermode_proccoeff.h +++ b/src/core/SkXfermode_proccoeff.h @@ -44,8 +44,8 @@ public: bool isOpaque(SkXfermode::SrcColorOpacity opacityType) const override; #if SK_SUPPORT_GPU - bool asFragmentProcessor(GrFragmentProcessor**, GrProcessorDataManager*, - GrTexture* background) const override; + bool asFragmentProcessor(const GrFragmentProcessor**, GrProcessorDataManager*, + const GrFragmentProcessor*) const override; bool asXPFactory(GrXPFactory**) const override; #endif diff --git a/src/effects/SkArithmeticMode.cpp b/src/effects/SkArithmeticMode.cpp index 7db6b47d66..35ac8a84ba 100644 --- a/src/effects/SkArithmeticMode.cpp +++ b/src/effects/SkArithmeticMode.cpp @@ -31,8 +31,8 @@ public: SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar) #if SK_SUPPORT_GPU - bool asFragmentProcessor(GrFragmentProcessor**, GrProcessorDataManager*, - GrTexture* background) const override; + bool asFragmentProcessor(const GrFragmentProcessor**, GrProcessorDataManager*, + const GrFragmentProcessor* dst) const override; bool asXPFactory(GrXPFactory**) const override; #endif @@ -235,9 +235,9 @@ SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2, ////////////////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU -bool SkArithmeticMode_scalar::asFragmentProcessor(GrFragmentProcessor** fp, +bool SkArithmeticMode_scalar::asFragmentProcessor(const GrFragmentProcessor** fp, GrProcessorDataManager* procDataManager, - GrTexture* background) const { + const GrFragmentProcessor* dst) const { if (fp) { *fp = GrArithmeticFP::Create(procDataManager, SkScalarToFloat(fK[0]), @@ -245,7 +245,7 @@ bool SkArithmeticMode_scalar::asFragmentProcessor(GrFragmentProcessor** fp, SkScalarToFloat(fK[2]), SkScalarToFloat(fK[3]), fEnforcePMColor, - background); + dst); } return true; } diff --git a/src/effects/SkArithmeticMode_gpu.cpp b/src/effects/SkArithmeticMode_gpu.cpp index fd20b73cdc..5f149d0712 100644 --- a/src/effects/SkArithmeticMode_gpu.cpp +++ b/src/effects/SkArithmeticMode_gpu.cpp @@ -21,16 +21,16 @@ static const bool gUseUnpremul = false; static void add_arithmetic_code(GrGLFragmentBuilder* fsBuilder, - const char* inputColor, + const char* srcColor, const char* dstColor, const char* outputColor, const char* kUni, bool enforcePMColor) { // We don't try to optimize for this case at all - if (nullptr == inputColor) { + if (nullptr == srcColor) { fsBuilder->codeAppend("const vec4 src = vec4(1);"); } else { - fsBuilder->codeAppendf("vec4 src = %s;", inputColor); + fsBuilder->codeAppendf("vec4 src = %s;", srcColor); if (gUseUnpremul) { fsBuilder->codeAppend("src.rgb = clamp(src.rgb / src.a, 0.0, 1.0);"); } @@ -54,26 +54,21 @@ static void add_arithmetic_code(GrGLFragmentBuilder* fsBuilder, class GLArithmeticFP : public GrGLFragmentProcessor { public: - GLArithmeticFP(const GrProcessor&) - : fEnforcePMColor(true) { - } + GLArithmeticFP(const GrProcessor&) : fEnforcePMColor(true) {} ~GLArithmeticFP() override {} void emitCode(EmitArgs& args) override { GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); - fsBuilder->codeAppend("vec4 bgColor = "); - fsBuilder->appendTextureLookup(args.fSamplers[0], args.fCoords[0].c_str(), - args.fCoords[0].getType()); - fsBuilder->codeAppendf(";"); - const char* dstColor = "bgColor"; + fsBuilder->codeAppend("vec4 _dstColor;"); + this->emitChild(0, nullptr, "_dstColor", args); fKUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "k"); + kVec4f_GrSLType, kDefault_GrSLPrecision, + "k"); const char* kUni = args.fBuilder->getUniformCStr(fKUni); - add_arithmetic_code(fsBuilder, args.fInputColor, dstColor, args.fOutputColor, kUni, + add_arithmetic_code(fsBuilder, args.fInputColor, "_dstColor", args.fOutputColor, kUni, fEnforcePMColor); } @@ -100,17 +95,13 @@ private: /////////////////////////////////////////////////////////////////////////////// GrArithmeticFP::GrArithmeticFP(GrProcessorDataManager*, float k1, float k2, float k3, float k4, - bool enforcePMColor, GrTexture* background) + bool enforcePMColor, const GrFragmentProcessor* dst) : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) { this->initClassID<GrArithmeticFP>(); - SkASSERT(background); - - fBackgroundTransform.reset(kLocal_GrCoordSet, background, - GrTextureParams::kNone_FilterMode); - this->addCoordTransform(&fBackgroundTransform); - fBackgroundAccess.reset(background); - this->addTextureAccess(&fBackgroundAccess); + SkASSERT(dst); + SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst); + SkASSERT(0 == dstIndex); } void GrArithmeticFP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { @@ -144,7 +135,8 @@ const GrFragmentProcessor* GrArithmeticFP::TestCreate(GrProcessorTestData* d) { float k4 = d->fRandom->nextF(); bool enforcePMColor = d->fRandom->nextBool(); - return new GrArithmeticFP(d->fProcDataManager, k1, k2, k3, k4, enforcePMColor, d->fTextures[0]); + SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d)); + return new GrArithmeticFP(d->fProcDataManager, k1, k2, k3, k4, enforcePMColor, dst); } GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP); diff --git a/src/effects/SkArithmeticMode_gpu.h b/src/effects/SkArithmeticMode_gpu.h index 7b343ee35f..d415cc4a49 100644 --- a/src/effects/SkArithmeticMode_gpu.h +++ b/src/effects/SkArithmeticMode_gpu.h @@ -31,10 +31,10 @@ class GrGLArtithmeticFP; class GrArithmeticFP : public GrFragmentProcessor { public: - static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager, float k1, float k2, - float k3, float k4, bool enforcePMColor, - GrTexture* background) { - return new GrArithmeticFP(procDataManager, k1, k2, k3, k4, enforcePMColor, background); + static const GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager, + float k1, float k2, float k3, float k4, + bool enforcePMColor, const GrFragmentProcessor* dst) { + return new GrArithmeticFP(procDataManager, k1, k2, k3, k4, enforcePMColor, dst); } ~GrArithmeticFP() override {}; @@ -57,12 +57,10 @@ private: void onComputeInvariantOutput(GrInvariantOutput* inout) const override; GrArithmeticFP(GrProcessorDataManager*, float k1, float k2, float k3, float k4, - bool enforcePMColor, GrTexture* background); + bool enforcePMColor, const GrFragmentProcessor* dst); float fK1, fK2, fK3, fK4; bool fEnforcePMColor; - GrCoordTransform fBackgroundTransform; - GrTextureAccess fBackgroundAccess; GR_DECLARE_FRAGMENT_PROCESSOR_TEST; typedef GrFragmentProcessor INHERITED; diff --git a/src/effects/SkColorCubeFilter.cpp b/src/effects/SkColorCubeFilter.cpp index c5d4fc5a35..da5635cf71 100644 --- a/src/effects/SkColorCubeFilter.cpp +++ b/src/effects/SkColorCubeFilter.cpp @@ -304,7 +304,7 @@ void GrColorCubeEffect::GLProcessor::GenKey(const GrProcessor& proc, } bool SkColorCubeFilter::asFragmentProcessors(GrContext* context, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>* array) const { + SkTDArray<const GrFragmentProcessor*>* array) const { static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey key; GrUniqueKey::Builder builder(&key, kDomain, 2); diff --git a/src/effects/SkColorFilters.cpp b/src/effects/SkColorFilters.cpp index c38328ccbb..ece3295107 100644 --- a/src/effects/SkColorFilters.cpp +++ b/src/effects/SkColorFilters.cpp @@ -65,305 +65,36 @@ SkFlattenable* SkModeColorFilter::CreateProc(SkReadBuffer& buffer) { /////////////////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU #include "GrBlend.h" -#include "GrFragmentProcessor.h" #include "GrInvariantOutput.h" -#include "GrProcessorUnitTest.h" +#include "effects/GrXfermodeFragmentProcessor.h" +#include "effects/GrConstColorProcessor.h" #include "SkGr.h" -#include "gl/GrGLFragmentProcessor.h" -#include "gl/builders/GrGLProgramBuilder.h" - -namespace { -/** - * A definition of blend equation for one coefficient. Generates a - * blend_coeff * value "expression". - */ -template<typename ColorExpr> -static inline ColorExpr blend_term(SkXfermode::Coeff coeff, - const ColorExpr& src, - const ColorExpr& dst, - const ColorExpr& value) { - switch (coeff) { - default: - SkFAIL("Unexpected xfer coeff."); - case SkXfermode::kZero_Coeff: /** 0 */ - return ColorExpr(0); - case SkXfermode::kOne_Coeff: /** 1 */ - return value; - case SkXfermode::kSC_Coeff: - return src * value; - case SkXfermode::kISC_Coeff: - return (ColorExpr(1) - src) * dst; - case SkXfermode::kDC_Coeff: - return dst * value; - case SkXfermode::kIDC_Coeff: - return (ColorExpr(1) - dst) * value; - case SkXfermode::kSA_Coeff: /** src alpha */ - return src.a() * value; - case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */ - return (typename ColorExpr::AExpr(1) - src.a()) * value; - case SkXfermode::kDA_Coeff: /** dst alpha */ - return dst.a() * value; - case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */ - return (typename ColorExpr::AExpr(1) - dst.a()) * value; - } -} -/** - * Creates a color filter expression which modifies the color by - * the specified color filter. - */ -template <typename ColorExpr> -static inline ColorExpr color_filter_expression(const SkXfermode::Mode& mode, - const ColorExpr& filterColor, - const ColorExpr& inColor) { - SkXfermode::Coeff colorCoeff; - SkXfermode::Coeff filterColorCoeff; - SkAssertResult(SkXfermode::ModeAsCoeff(mode, &filterColorCoeff, &colorCoeff)); - return blend_term(colorCoeff, filterColor, inColor, inColor) + - blend_term(filterColorCoeff, filterColor, inColor, filterColor); -} - -} - -class ModeColorFilterEffect : public GrFragmentProcessor { -public: - static GrFragmentProcessor* Create(const GrColor& c, SkXfermode::Mode mode) { - // TODO: Make the effect take the coeffs rather than mode since we already do the - // conversion here. - SkXfermode::Coeff srcCoeff, dstCoeff; - if (!SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff)) { -// SkDebugf("Failing to create color filter for mode %d\n", mode); - return nullptr; - } - return new ModeColorFilterEffect(c, mode); - } - - bool willUseFilterColor() const { - SkXfermode::Coeff dstCoeff; - SkXfermode::Coeff srcCoeff; - SkAssertResult(SkXfermode::ModeAsCoeff(fMode, &srcCoeff, &dstCoeff)); - if (SkXfermode::kZero_Coeff == srcCoeff) { - return GrBlendCoeffRefsSrc(sk_blend_to_grblend(dstCoeff)); - } - return true; - } - - const char* name() const override { return "ModeColorFilterEffect"; } - - SkXfermode::Mode mode() const { return fMode; } - GrColor color() const { return fColor; } - - class GLProcessor : public GrGLFragmentProcessor { - public: - GLProcessor(const GrProcessor&) { - } - - virtual void emitCode(EmitArgs& args) override { - SkXfermode::Mode mode = args.fFp.cast<ModeColorFilterEffect>().mode(); - - SkASSERT(SkXfermode::kDst_Mode != mode); - const char* colorFilterColorUniName = nullptr; - if (args.fFp.cast<ModeColorFilterEffect>().willUseFilterColor()) { - fFilterColorUni = args.fBuilder->addUniform( - GrGLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "FilterColor", - &colorFilterColorUniName); - } - - GrGLSLExpr4 filter = - color_filter_expression(mode, GrGLSLExpr4(colorFilterColorUniName), - GrGLSLExpr4(args.fInputColor)); - - args.fBuilder->getFragmentShaderBuilder()-> - codeAppendf("\t%s = %s;\n", args.fOutputColor, filter.c_str()); - } - - static void GenKey(const GrProcessor& fp, const GrGLSLCaps&, - GrProcessorKeyBuilder* b) { - const ModeColorFilterEffect& colorModeFilter = fp.cast<ModeColorFilterEffect>(); - // The SL code does not depend on filter color at the moment, so no need to represent it - // in the key. - b->add32(colorModeFilter.mode()); - } - - protected: - virtual void onSetData(const GrGLProgramDataManager& pdman, - const GrProcessor& fp) override { - if (fFilterColorUni.isValid()) { - const ModeColorFilterEffect& colorModeFilter = fp.cast<ModeColorFilterEffect>(); - GrGLfloat c[4]; - GrColorToRGBAFloat(colorModeFilter.color(), c); - pdman.set4fv(fFilterColorUni, 1, c); - } - } - - private: - - GrGLProgramDataManager::UniformHandle fFilterColorUni; - typedef GrGLFragmentProcessor INHERITED; - }; - - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - -private: - ModeColorFilterEffect(GrColor color, SkXfermode::Mode mode) - : fMode(mode), - fColor(color) { - this->initClassID<ModeColorFilterEffect>(); - } - - GrGLFragmentProcessor* onCreateGLInstance() const override { return new GLProcessor(*this); } - - virtual void onGetGLProcessorKey(const GrGLSLCaps& caps, - GrProcessorKeyBuilder* b) const override { - GLProcessor::GenKey(*this, caps, b); - } - - bool onIsEqual(const GrFragmentProcessor& other) const override { - const ModeColorFilterEffect& s = other.cast<ModeColorFilterEffect>(); - return fMode == s.fMode && fColor == s.fColor; - } - - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - SkXfermode::Mode fMode; - GrColor fColor; - - typedef GrFragmentProcessor INHERITED; -}; - -namespace { - -/** Function color_component_to_int tries to reproduce the GLSL rounding. The spec doesn't specify - * to which direction the 0.5 goes. - */ -static inline int color_component_to_int(float value) { - return sk_float_round2int(SkTMax(0.f, SkTMin(1.f, value)) * 255.f); -} - -/** MaskedColorExpr is used to evaluate the color and valid color component flags through the - * blending equation. It has members similar to GrGLSLExpr so that it can be used with the - * templated helpers above. - */ -class MaskedColorExpr { -public: - MaskedColorExpr(const float color[], uint32_t flags) - : fFlags(flags) { - fColor[0] = color[0]; - fColor[1] = color[1]; - fColor[2] = color[2]; - fColor[3] = color[3]; - } - - MaskedColorExpr(float v, uint32_t flags = kRGBA_GrColorComponentFlags) - : fFlags(flags) { - fColor[0] = v; - fColor[1] = v; - fColor[2] = v; - fColor[3] = v; - } - - MaskedColorExpr operator*(const MaskedColorExpr& other) const { - float tmp[4]; - tmp[0] = fColor[0] * other.fColor[0]; - tmp[1] = fColor[1] * other.fColor[1]; - tmp[2] = fColor[2] * other.fColor[2]; - tmp[3] = fColor[3] * other.fColor[3]; - - return MaskedColorExpr(tmp, fFlags & other.fFlags); - } - - MaskedColorExpr operator+(const MaskedColorExpr& other) const { - float tmp[4]; - tmp[0] = fColor[0] + other.fColor[0]; - tmp[1] = fColor[1] + other.fColor[1]; - tmp[2] = fColor[2] + other.fColor[2]; - tmp[3] = fColor[3] + other.fColor[3]; - - return MaskedColorExpr(tmp, fFlags & other.fFlags); - } - - MaskedColorExpr operator-(const MaskedColorExpr& other) const { - float tmp[4]; - tmp[0] = fColor[0] - other.fColor[0]; - tmp[1] = fColor[1] - other.fColor[1]; - tmp[2] = fColor[2] - other.fColor[2]; - tmp[3] = fColor[3] - other.fColor[3]; - - return MaskedColorExpr(tmp, fFlags & other.fFlags); - } - - MaskedColorExpr a() const { - uint32_t flags = (fFlags & kA_GrColorComponentFlag) ? kRGBA_GrColorComponentFlags : 0; - return MaskedColorExpr(fColor[3], flags); - } - - GrColor getColor() const { - return GrColorPackRGBA(color_component_to_int(fColor[0]), - color_component_to_int(fColor[1]), - color_component_to_int(fColor[2]), - color_component_to_int(fColor[3])); - } - - uint32_t getValidComponents() const { return fFlags; } - - typedef MaskedColorExpr AExpr; -private: - float fColor[4]; - uint32_t fFlags; -}; - -} - -void ModeColorFilterEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { - float inputColor[4]; - GrColorToRGBAFloat(inout->color(), inputColor); - float filterColor[4]; - GrColorToRGBAFloat(fColor, filterColor); - MaskedColorExpr result = - color_filter_expression(fMode, - MaskedColorExpr(filterColor, kRGBA_GrColorComponentFlags), - MaskedColorExpr(inputColor, inout->validFlags())); - - // Check if we will use the input color - SkXfermode::Coeff dstCoeff; - SkXfermode::Coeff srcCoeff; - SkAssertResult(SkXfermode::ModeAsCoeff(fMode, &srcCoeff, &dstCoeff)); - GrInvariantOutput::ReadInput readInput = GrInvariantOutput::kWill_ReadInput; - // These could be calculated from the blend equation with template trickery.. - if (SkXfermode::kZero_Coeff == dstCoeff && - !GrBlendCoeffRefsDst(sk_blend_to_grblend(srcCoeff))) { - readInput = GrInvariantOutput::kWillNot_ReadInput; - } - inout->setToOther(result.getValidComponents(), result.getColor(), readInput); -} - -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ModeColorFilterEffect); -const GrFragmentProcessor* ModeColorFilterEffect::TestCreate(GrProcessorTestData* d) { - SkXfermode::Mode mode = SkXfermode::kDst_Mode; - while (SkXfermode::kDst_Mode == mode) { - mode = static_cast<SkXfermode::Mode>(d->fRandom->nextRangeU(0, SkXfermode::kLastCoeffMode)); - } - - // pick a random premul color - uint8_t alpha = d->fRandom->nextULessThan(256); - GrColor color = GrColorPackRGBA(d->fRandom->nextRangeU(0, alpha), - d->fRandom->nextRangeU(0, alpha), - d->fRandom->nextRangeU(0, alpha), - alpha); - return ModeColorFilterEffect::Create(color, mode); -} bool SkModeColorFilter::asFragmentProcessors(GrContext*, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>* array) const { + SkTDArray<const GrFragmentProcessor*>* array) const { if (SkXfermode::kDst_Mode != fMode) { - GrFragmentProcessor* frag = ModeColorFilterEffect::Create(SkColor2GrColor(fColor), fMode); - if (frag) { + SkAutoTUnref<const GrFragmentProcessor> constFP( + GrConstColorProcessor::Create(SkColor2GrColor(fColor), + GrConstColorProcessor::kIgnore_InputMode)); + const GrFragmentProcessor* fp = + GrXfermodeFragmentProcessor::CreateFromSrcProcessor(constFP, fMode); + if (fp) { +#ifdef SK_DEBUG + // With a solid color input this should always be able to compute the blended color + // (at least for coeff modes) + if (fMode <= SkXfermode::kLastCoeffMode) { + static SkRandom gRand; + GrInvariantOutput io(GrPremulColor(gRand.nextU()), kRGBA_GrColorComponentFlags, + false); + fp->computeInvariantOutput(&io); + SkASSERT(io.validFlags() == kRGBA_GrColorComponentFlags); + } +#endif if (array) { - *array->append() = frag; + *array->append() = fp; } else { - frag->unref(); - SkDEBUGCODE(frag = nullptr;) + fp->unref(); + SkDEBUGCODE(fp = nullptr;) } return true; } diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp index 1eedef1343..6131b264e7 100644 --- a/src/effects/SkColorMatrixFilter.cpp +++ b/src/effects/SkColorMatrixFilter.cpp @@ -537,7 +537,7 @@ const GrFragmentProcessor* ColorMatrixEffect::TestCreate(GrProcessorTestData* d) } bool SkColorMatrixFilter::asFragmentProcessors(GrContext*, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>* array) const { + SkTDArray<const GrFragmentProcessor*>* array) const { GrFragmentProcessor* frag = ColorMatrixEffect::Create(fMatrix); if (frag) { if (array) { diff --git a/src/effects/SkLumaColorFilter.cpp b/src/effects/SkLumaColorFilter.cpp index e161d170b2..7e16f3ac89 100644 --- a/src/effects/SkLumaColorFilter.cpp +++ b/src/effects/SkLumaColorFilter.cpp @@ -109,7 +109,7 @@ private: }; bool SkLumaColorFilter::asFragmentProcessors(GrContext*, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>* array) const { + SkTDArray<const GrFragmentProcessor*>* array) const { GrFragmentProcessor* frag = LumaColorFilterEffect::Create(); if (frag) { diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp index 1a2b1343b6..85e3a317bb 100644 --- a/src/effects/SkTableColorFilter.cpp +++ b/src/effects/SkTableColorFilter.cpp @@ -49,7 +49,7 @@ public: #if SK_SUPPORT_GPU bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>*) const override; + SkTDArray<const GrFragmentProcessor*>*) const override; #endif void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override; @@ -521,7 +521,7 @@ bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const { void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { // If we kept the table in the effect then we could actually run known inputs through the // table. - uint8_t invalidateFlags = 0; + GrColorComponentFlags invalidateFlags = kNone_GrColorComponentFlags; if (fFlags & SkTable_ColorFilter::kR_Flag) { invalidateFlags |= kR_GrColorComponentFlag; } @@ -563,7 +563,7 @@ const GrFragmentProcessor* ColorTableEffect::TestCreate(GrProcessorTestData* d) (flags & (1 << 3)) ? luts[3] : nullptr )); - SkTDArray<GrFragmentProcessor*> array; + SkTDArray<const GrFragmentProcessor*> array; if (filter->asFragmentProcessors(d->fContext, d->fProcDataManager, &array)) { SkASSERT(1 == array.count()); // TableColorFilter only returns 1 return array[0]; @@ -573,7 +573,7 @@ const GrFragmentProcessor* ColorTableEffect::TestCreate(GrProcessorTestData* d) bool SkTable_ColorFilter::asFragmentProcessors(GrContext* context, GrProcessorDataManager*, - SkTDArray<GrFragmentProcessor*>* array) const { + SkTDArray<const GrFragmentProcessor*>* array) const { SkBitmap bitmap; this->asComponentTable(&bitmap); diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp index 9ffbe62bdc..e357b0f23d 100644 --- a/src/effects/SkXfermodeImageFilter.cpp +++ b/src/effects/SkXfermodeImageFilter.cpp @@ -16,6 +16,7 @@ #include "GrContext.h" #include "GrDrawContext.h" #include "effects/GrTextureDomain.h" +#include "effects/GrSimpleTextureEffect.h" #include "SkGr.h" #endif @@ -153,7 +154,7 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, GrTexture* foregroundTex = foreground.getTexture(); GrContext* context = foregroundTex->getContext(); - GrFragmentProcessor* xferProcessor = nullptr; + const GrFragmentProcessor* xferFP = nullptr; GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; @@ -166,8 +167,11 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, } GrPaint paint; - if (!fMode || !fMode->asFragmentProcessor(&xferProcessor, paint.getProcessorDataManager(), - backgroundTex)) { + SkMatrix bgMatrix; + bgMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); + SkAutoTUnref<const GrFragmentProcessor> bgFP( + GrSimpleTextureEffect::Create(paint.getProcessorDataManager(), backgroundTex, bgMatrix)); + if (!fMode || !fMode->asFragmentProcessor(&xferFP, paint.getProcessorDataManager(), bgFP)) { // canFilterImageGPU() should've taken care of this SkASSERT(false); return false; @@ -190,7 +194,9 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, ); paint.addColorFragmentProcessor(foregroundDomain.get()); - paint.addColorFragmentProcessor(xferProcessor)->unref(); + if (xferFP) { + paint.addColorFragmentProcessor(xferFP)->unref(); + } SkAutoTUnref<GrDrawContext> drawContext(context->drawContext()); if (!drawContext) { diff --git a/src/gpu/GrBlend.cpp b/src/gpu/GrBlend.cpp new file mode 100644 index 0000000000..72a89d838d --- /dev/null +++ b/src/gpu/GrBlend.cpp @@ -0,0 +1,124 @@ +/* +* Copyright 2015 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#include "GrBlend.h" + +/** + * MaskedColor is used to evaluate the color and valid color component flags through the + * blending equation. Could possibly extend this to be used more broadly. + */ +class MaskedColor { +public: + MaskedColor(GrColor color, GrColorComponentFlags flags) + : fColor(color) + , fFlags(flags) {} + + MaskedColor() {} + + void set(GrColor color, GrColorComponentFlags flags) { + fColor = color; + fFlags = flags; + } + + static MaskedColor Invert(const MaskedColor& in) { + return MaskedColor(GrInvertColor(in.fColor), in.fFlags); + } + + static MaskedColor ExtractAlpha(const MaskedColor& in) { + GrColorComponentFlags flags = (in.fFlags & kA_GrColorComponentFlag) ? + kRGBA_GrColorComponentFlags : kNone_GrColorComponentFlags; + return MaskedColor(GrColorPackA4(GrColorUnpackA(in.fColor)), flags); + } + + static MaskedColor ExtractInverseAlpha(const MaskedColor& in) { + GrColorComponentFlags flags = (in.fFlags & kA_GrColorComponentFlag) ? + kRGBA_GrColorComponentFlags : kNone_GrColorComponentFlags; + return MaskedColor(GrColorPackA4(0xFF - GrColorUnpackA(in.fColor)), flags); + } + + static MaskedColor Mul(const MaskedColor& a, const MaskedColor& b) { + GrColorComponentFlags outFlags = (a.fFlags & b.fFlags) | a.componentsWithValue(0) | + b.componentsWithValue(0); + return MaskedColor(GrColorMul(a.fColor, b.fColor), outFlags); + } + + static MaskedColor SatAdd(const MaskedColor& a, const MaskedColor& b) { + GrColorComponentFlags outFlags = (a.fFlags & b.fFlags) | a.componentsWithValue(0xFF) | + b.componentsWithValue(0xFF); + return MaskedColor(GrColorSatAdd(a.fColor, b.fColor), outFlags); + } + + GrColor color() const { return fColor; } + + GrColorComponentFlags validFlags () const { return fFlags; } + +private: + GrColorComponentFlags componentsWithValue(unsigned value) const { + GrColorComponentFlags flags = kNone_GrColorComponentFlags; + if ((kR_GrColorComponentFlag & fFlags) && value == GrColorUnpackR(fColor)) { + flags |= kR_GrColorComponentFlag; + } + if ((kG_GrColorComponentFlag & fFlags) && value == GrColorUnpackG(fColor)) { + flags |= kG_GrColorComponentFlag; + } + if ((kB_GrColorComponentFlag & fFlags) && value == GrColorUnpackB(fColor)) { + flags |= kB_GrColorComponentFlag; + } + if ((kA_GrColorComponentFlag & fFlags) && value == GrColorUnpackA(fColor)) { + flags |= kA_GrColorComponentFlag; + } + return flags; + } + + GrColor fColor; + GrColorComponentFlags fFlags; +}; + +static MaskedColor get_term(GrBlendCoeff coeff, const MaskedColor& src, const MaskedColor& dst, + const MaskedColor& value) { + switch (coeff) { + case kZero_GrBlendCoeff: + return MaskedColor(0, kRGBA_GrColorComponentFlags); + case kOne_GrBlendCoeff: + return value; + case kDC_GrBlendCoeff: + return MaskedColor::Mul(dst, value); + case kIDC_GrBlendCoeff: + return MaskedColor::Mul(MaskedColor::Invert(dst), value); + case kDA_GrBlendCoeff: + return MaskedColor::Mul(MaskedColor::ExtractAlpha(dst), value); + case kIDA_GrBlendCoeff: + return MaskedColor::Mul(MaskedColor::ExtractInverseAlpha(dst), value); + case kSC_GrBlendCoeff: + return MaskedColor::Mul(src, value); + case kISC_GrBlendCoeff: + return MaskedColor::Mul(MaskedColor::Invert(src), value); + case kSA_GrBlendCoeff: + return MaskedColor::Mul(MaskedColor::ExtractAlpha(src), value); + case kISA_GrBlendCoeff: + return MaskedColor::Mul(MaskedColor::ExtractInverseAlpha(src), value); + default: + SkFAIL("Illegal coefficient"); + return MaskedColor(); + } +} + +void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff, + GrColor srcColor, GrColorComponentFlags srcColorFlags, + GrColor dstColor, GrColorComponentFlags dstColorFlags, + GrColor* outColor, + GrColorComponentFlags* outFlags) { + MaskedColor src(srcColor, srcColorFlags); + MaskedColor dst(dstColor, dstColorFlags); + + MaskedColor srcTerm = get_term(srcCoeff, src, dst, src); + MaskedColor dstTerm = get_term(dstCoeff, src, dst, dst); + + MaskedColor output = MaskedColor::SatAdd(srcTerm, dstTerm); + *outColor = output.color(); + *outFlags = output.validFlags(); +} diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp index b3544b03cb..782b82ba5c 100644 --- a/src/gpu/GrProcessor.cpp +++ b/src/gpu/GrProcessor.cpp @@ -50,7 +50,7 @@ GrProcessorTestFactory<GrGeometryProcessor>::GetFactories() { * we verify the count is as expected. If a new factory is added, then these numbers must be * manually adjusted. */ -static const int kFPFactoryCount = 40; +static const int kFPFactoryCount = 39; static const int kGPFactoryCount = 14; static const int kXPFactoryCount = 5; diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 471c9721cf..ee06f3eef6 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -734,7 +734,7 @@ bool SkPaint2GrPaintNoShader(GrContext* context, GrRenderTarget* rt, const SkPai SkColor filtered = colorFilter->filterColor(skPaint.getColor()); grPaint->setColor(SkColor2GrColor(filtered)); } else { - SkTDArray<GrFragmentProcessor*> array; + SkTDArray<const GrFragmentProcessor*> array; // return false if failed? if (colorFilter->asFragmentProcessors(context, grPaint->getProcessorDataManager(), &array)) { diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp index f626e7a211..0d31034013 100644 --- a/src/gpu/effects/GrCustomXfermode.cpp +++ b/src/gpu/effects/GrCustomXfermode.cpp @@ -6,7 +6,6 @@ */ #include "effects/GrCustomXfermode.h" -#include "effects/GrCustomXfermodePriv.h" #include "GrCoordTransform.h" #include "GrContext.h" @@ -18,6 +17,7 @@ #include "SkXfermode.h" #include "gl/GrGLCaps.h" #include "gl/GrGLGpu.h" +#include "gl/GrGLSLBlend.h" #include "gl/GrGLFragmentProcessor.h" #include "gl/GrGLProgramDataManager.h" #include "gl/builders/GrGLProgramBuilder.h" @@ -67,452 +67,6 @@ static bool can_use_hw_blend_equation(GrBlendEquation equation, return true; } -static void hard_light(GrGLFragmentBuilder* fsBuilder, - const char* final, - const char* src, - const char* dst) { - static const char kComponents[] = {'r', 'g', 'b'}; - for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) { - char component = kComponents[i]; - fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src); - fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;", - final, component, src, component, dst, component); - fsBuilder->codeAppend("} else {"); - fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);", - final, component, src, dst, dst, dst, component, src, src, - component); - fsBuilder->codeAppend("}"); - } - fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);", - final, src, dst, dst, src); -} - -// Does one component of color-dodge -static void color_dodge_component(GrGLFragmentBuilder* fsBuilder, - const char* final, - const char* src, - const char* dst, - const char component) { - fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component); - fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);", - final, component, src, component, dst); - fsBuilder->codeAppend("} else {"); - fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component); - fsBuilder->codeAppend("if (0.0 == d) {"); - fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", - final, component, src, dst, src, component, dst, dst, component, - src); - fsBuilder->codeAppend("} else {"); - fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);", - dst, dst, component, src); - fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", - final, component, src, src, component, dst, dst, component, src); - fsBuilder->codeAppend("}"); - fsBuilder->codeAppend("}"); -} - -// Does one component of color-burn -static void color_burn_component(GrGLFragmentBuilder* fsBuilder, - const char* final, - const char* src, - const char* dst, - const char component) { - fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component); - fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", - final, component, src, dst, src, component, dst, dst, component, - src); - fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component); - fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);", - final, component, dst, component, src); - fsBuilder->codeAppend("} else {"); - fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);", - dst, dst, dst, component, src, src, component); - fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", - final, component, src, src, component, dst, dst, component, src); - fsBuilder->codeAppend("}"); -} - -// Does one component of soft-light. Caller should have already checked that dst alpha > 0. -static void soft_light_component_pos_dst_alpha(GrGLFragmentBuilder* fsBuilder, - const char* final, - const char* src, - const char* dst, - const char component) { - // if (2S < Sa) - fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src); - // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1) - fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +" - "(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);", - final, component, dst, component, dst, component, src, src, - component, dst, dst, src, component, dst, component, src, src, - component); - // else if (4D < Da) - fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {", - dst, component, dst); - fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;", - dst, component, dst, component); - fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component); - fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst); - fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst); - // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2 - fsBuilder->codeAppendf("%s.%c =" - "(DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +" - " 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c) -" - " DaCub*%s.%c) / DaSqd;", - final, component, src, component, dst, component, - src, src, component, dst, src, src, component, src, src, - component, src, component); - fsBuilder->codeAppendf("} else {"); - // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S - fsBuilder->codeAppendf("%s.%c = %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c -" - " sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c;", - final, component, dst, component, src, src, component, src, component, - dst, dst, component, src, src, component, dst, src, component); - fsBuilder->codeAppendf("}"); -} - -// Adds a function that takes two colors and an alpha as input. It produces a color with the -// hue and saturation of the first color, the luminosity of the second color, and the input -// alpha. It has this signature: -// vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor). -static void add_lum_function(GrGLFragmentBuilder* fsBuilder, SkString* setLumFunction) { - // Emit a helper that gets the luminance of a color. - SkString getFunction; - GrGLShaderVar getLumArgs[] = { - GrGLShaderVar("color", kVec3f_GrSLType), - }; - SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);"); - fsBuilder->emitFunction(kFloat_GrSLType, - "luminance", - SK_ARRAY_COUNT(getLumArgs), getLumArgs, - getLumBody.c_str(), - &getFunction); - - // Emit the set luminance function. - GrGLShaderVar setLumArgs[] = { - GrGLShaderVar("hueSat", kVec3f_GrSLType), - GrGLShaderVar("alpha", kFloat_GrSLType), - GrGLShaderVar("lumColor", kVec3f_GrSLType), - }; - SkString setLumBody; - setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str()); - setLumBody.append("vec3 outColor = hueSat + diff;"); - setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str()); - setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);" - "float maxComp = max(max(outColor.r, outColor.g), outColor.b);" - "if (minComp < 0.0 && outLum != minComp) {" - "outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /" - "(outLum - minComp);" - "}" - "if (maxComp > alpha && maxComp != outLum) {" - "outColor = outLum +" - "((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /" - "(maxComp - outLum);" - "}" - "return outColor;"); - fsBuilder->emitFunction(kVec3f_GrSLType, - "set_luminance", - SK_ARRAY_COUNT(setLumArgs), setLumArgs, - setLumBody.c_str(), - setLumFunction); -} - -// Adds a function that creates a color with the hue and luminosity of one input color and -// the saturation of another color. It will have this signature: -// float set_saturation(vec3 hueLumColor, vec3 satColor) -static void add_sat_function(GrGLFragmentBuilder* fsBuilder, SkString* setSatFunction) { - // Emit a helper that gets the saturation of a color - SkString getFunction; - GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) }; - SkString getSatBody; - getSatBody.printf("return max(max(color.r, color.g), color.b) - " - "min(min(color.r, color.g), color.b);"); - fsBuilder->emitFunction(kFloat_GrSLType, - "saturation", - SK_ARRAY_COUNT(getSatArgs), getSatArgs, - getSatBody.c_str(), - &getFunction); - - // Emit a helper that sets the saturation given sorted input channels. This used - // to use inout params for min, mid, and max components but that seems to cause - // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the - // adjusted min, mid, and max inputs, respectively. - SkString helperFunction; - GrGLShaderVar helperArgs[] = { - GrGLShaderVar("minComp", kFloat_GrSLType), - GrGLShaderVar("midComp", kFloat_GrSLType), - GrGLShaderVar("maxComp", kFloat_GrSLType), - GrGLShaderVar("sat", kFloat_GrSLType), - }; - static const char kHelperBody[] = "if (minComp < maxComp) {" - "vec3 result;" - "result.r = 0.0;" - "result.g = sat * (midComp - minComp) / (maxComp - minComp);" - "result.b = sat;" - "return result;" - "} else {" - "return vec3(0, 0, 0);" - "}"; - fsBuilder->emitFunction(kVec3f_GrSLType, - "set_saturation_helper", - SK_ARRAY_COUNT(helperArgs), helperArgs, - kHelperBody, - &helperFunction); - - GrGLShaderVar setSatArgs[] = { - GrGLShaderVar("hueLumColor", kVec3f_GrSLType), - GrGLShaderVar("satColor", kVec3f_GrSLType), - }; - const char* helpFunc = helperFunction.c_str(); - SkString setSatBody; - setSatBody.appendf("float sat = %s(satColor);" - "if (hueLumColor.r <= hueLumColor.g) {" - "if (hueLumColor.g <= hueLumColor.b) {" - "hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);" - "} else if (hueLumColor.r <= hueLumColor.b) {" - "hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);" - "} else {" - "hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);" - "}" - "} else if (hueLumColor.r <= hueLumColor.b) {" - "hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);" - "} else if (hueLumColor.g <= hueLumColor.b) {" - "hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);" - "} else {" - "hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);" - "}" - "return hueLumColor;", - getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc, - helpFunc, helpFunc); - fsBuilder->emitFunction(kVec3f_GrSLType, - "set_saturation", - SK_ARRAY_COUNT(setSatArgs), setSatArgs, - setSatBody.c_str(), - setSatFunction); - -} - -static void emit_custom_xfermode_code(SkXfermode::Mode mode, - GrGLFragmentBuilder* fsBuilder, - const char* outputColor, - const char* inputColor, - const char* dstColor) { - // We don't try to optimize for this case at all - if (nullptr == inputColor) { - fsBuilder->codeAppendf("const vec4 ones = vec4(1);"); - inputColor = "ones"; - } - fsBuilder->codeAppendf("// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode)); - - // These all perform src-over on the alpha channel. - fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;", - outputColor, inputColor, inputColor, dstColor); - - switch (mode) { - case SkXfermode::kOverlay_Mode: - // Overlay is Hard-Light with the src and dst reversed - hard_light(fsBuilder, outputColor, dstColor, inputColor); - break; - case SkXfermode::kDarken_Mode: - fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, " - "(1.0 - %s.a) * %s.rgb + %s.rgb);", - outputColor, - inputColor, dstColor, inputColor, - dstColor, inputColor, dstColor); - break; - case SkXfermode::kLighten_Mode: - fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, " - "(1.0 - %s.a) * %s.rgb + %s.rgb);", - outputColor, - inputColor, dstColor, inputColor, - dstColor, inputColor, dstColor); - break; - case SkXfermode::kColorDodge_Mode: - color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'r'); - color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'g'); - color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'b'); - break; - case SkXfermode::kColorBurn_Mode: - color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'r'); - color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'g'); - color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'b'); - break; - case SkXfermode::kHardLight_Mode: - hard_light(fsBuilder, outputColor, inputColor, dstColor); - break; - case SkXfermode::kSoftLight_Mode: - fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor); - fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, inputColor); - fsBuilder->codeAppendf("} else {"); - soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'r'); - soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'g'); - soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'b'); - fsBuilder->codeAppendf("}"); - break; - case SkXfermode::kDifference_Mode: - fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -" - "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);", - outputColor, inputColor, dstColor, inputColor, dstColor, - dstColor, inputColor); - break; - case SkXfermode::kExclusion_Mode: - fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - " - "2.0 * %s.rgb * %s.rgb;", - outputColor, dstColor, inputColor, dstColor, inputColor); - break; - case SkXfermode::kMultiply_Mode: - fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + " - "(1.0 - %s.a) * %s.rgb + " - "%s.rgb * %s.rgb;", - outputColor, inputColor, dstColor, dstColor, inputColor, - inputColor, dstColor); - break; - case SkXfermode::kHue_Mode: { - // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S - SkString setSat, setLum; - add_sat_function(fsBuilder, &setSat); - add_lum_function(fsBuilder, &setLum); - fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;", - dstColor, inputColor); - fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb)," - "dstSrcAlpha.a, dstSrcAlpha.rgb);", - outputColor, setLum.c_str(), setSat.c_str(), inputColor, - dstColor); - fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", - outputColor, inputColor, dstColor, dstColor, inputColor); - break; - } - case SkXfermode::kSaturation_Mode: { - // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S - SkString setSat, setLum; - add_sat_function(fsBuilder, &setSat); - add_lum_function(fsBuilder, &setLum); - fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;", - dstColor, inputColor); - fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a)," - "dstSrcAlpha.a, dstSrcAlpha.rgb);", - outputColor, setLum.c_str(), setSat.c_str(), inputColor, - dstColor); - fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", - outputColor, inputColor, dstColor, dstColor, inputColor); - break; - } - case SkXfermode::kColor_Mode: { - // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S - SkString setLum; - add_lum_function(fsBuilder, &setLum); - fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;", - inputColor, dstColor); - fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);", - outputColor, setLum.c_str(), dstColor, inputColor); - fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", - outputColor, inputColor, dstColor, dstColor, inputColor); - break; - } - case SkXfermode::kLuminosity_Mode: { - // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S - SkString setLum; - add_lum_function(fsBuilder, &setLum); - fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;", - inputColor, dstColor); - fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);", - outputColor, setLum.c_str(), dstColor, inputColor); - fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", - outputColor, inputColor, dstColor, dstColor, inputColor); - break; - } - default: - SkFAIL("Unknown Custom Xfer mode."); - break; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Fragment Processor -/////////////////////////////////////////////////////////////////////////////// - -GrFragmentProcessor* GrCustomXfermode::CreateFP(GrProcessorDataManager* procDataManager, - SkXfermode::Mode mode, GrTexture* background) { - if (!GrCustomXfermode::IsSupportedMode(mode)) { - return nullptr; - } else { - return new GrCustomXferFP(procDataManager, mode, background); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -class GLCustomXferFP : public GrGLFragmentProcessor { -public: - GLCustomXferFP(const GrFragmentProcessor&) {} - ~GLCustomXferFP() override {}; - - void emitCode(EmitArgs& args) override { - SkXfermode::Mode mode = args.fFp.cast<GrCustomXferFP>().mode(); - GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); - const char* dstColor = "bgColor"; - fsBuilder->codeAppendf("vec4 %s = ", dstColor); - fsBuilder->appendTextureLookup(args.fSamplers[0], args.fCoords[0].c_str(), - args.fCoords[0].getType()); - fsBuilder->codeAppendf(";"); - - emit_custom_xfermode_code(mode, fsBuilder, args.fOutputColor, args.fInputColor, dstColor); - } - - static void GenKey(const GrFragmentProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { - // The background may come from the dst or from a texture. - uint32_t key = proc.numTextures(); - SkASSERT(key <= 1); - key |= proc.cast<GrCustomXferFP>().mode() << 1; - b->add32(key); - } - -protected: - void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override {} - -private: - typedef GrGLFragmentProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -GrCustomXferFP::GrCustomXferFP(GrProcessorDataManager*, SkXfermode::Mode mode, GrTexture* background) - : fMode(mode) { - this->initClassID<GrCustomXferFP>(); - - SkASSERT(background); - fBackgroundTransform.reset(kLocal_GrCoordSet, background, - GrTextureParams::kNone_FilterMode); - this->addCoordTransform(&fBackgroundTransform); - fBackgroundAccess.reset(background); - this->addTextureAccess(&fBackgroundAccess); -} - -void GrCustomXferFP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { - GLCustomXferFP::GenKey(*this, caps, b); -} - -GrGLFragmentProcessor* GrCustomXferFP::onCreateGLInstance() const { - return new GLCustomXferFP(*this); -} - -bool GrCustomXferFP::onIsEqual(const GrFragmentProcessor& other) const { - const GrCustomXferFP& s = other.cast<GrCustomXferFP>(); - return fMode == s.fMode; -} - -void GrCustomXferFP::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); -} - -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCustomXferFP); -const GrFragmentProcessor* GrCustomXferFP::TestCreate(GrProcessorTestData* d) { - int mode = d->fRandom->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode); - - return new GrCustomXferFP(d->fProcDataManager, static_cast<SkXfermode::Mode>(mode), - d->fTextures[0]); -} - /////////////////////////////////////////////////////////////////////////////// // Xfer Processor /////////////////////////////////////////////////////////////////////////////// @@ -567,16 +121,6 @@ private: /////////////////////////////////////////////////////////////////////////////// -GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) { - if (!GrCustomXfermode::IsSupportedMode(mode)) { - return nullptr; - } else { - return new GrCustomXPFactory(mode); - } -} - -/////////////////////////////////////////////////////////////////////////////// - class GLCustomXP : public GrGLXferProcessor { public: GLCustomXP(const GrXferProcessor&) {} @@ -621,7 +165,7 @@ private: SkASSERT(!xp.hasHWBlendEquation()); GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder(); - emit_custom_xfermode_code(xp.mode(), fsBuilder, outColor, srcColor, dstColor); + GrGLSLBlend::AppendMode(fsBuilder, srcColor, dstColor, outColor, xp.mode()); } void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {} @@ -770,20 +314,54 @@ void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const { } /////////////////////////////////////////////////////////////////////////////// +class CustomXPFactory : public GrXPFactory { +public: + CustomXPFactory(SkXfermode::Mode mode); + + bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override { + return true; + } + + void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, + GrXPFactory::InvariantBlendedColor*) const override; + +private: + GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, + const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool hasMixedSamples, + const DstTexture*) const override; + + bool willReadDstColor(const GrCaps& caps, + const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool hasMixedSamples) const override; + + bool onIsEqual(const GrXPFactory& xpfBase) const override { + const CustomXPFactory& xpf = xpfBase.cast<CustomXPFactory>(); + return fMode == xpf.fMode; + } + + GR_DECLARE_XP_FACTORY_TEST; + + SkXfermode::Mode fMode; + GrBlendEquation fHWBlendEquation; -GrCustomXPFactory::GrCustomXPFactory(SkXfermode::Mode mode) + typedef GrXPFactory INHERITED; +}; + +CustomXPFactory::CustomXPFactory(SkXfermode::Mode mode) : fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) { SkASSERT(GrCustomXfermode::IsSupportedMode(fMode)); - this->initClassID<GrCustomXPFactory>(); + this->initClassID<CustomXPFactory>(); } -GrXferProcessor* -GrCustomXPFactory::onCreateXferProcessor(const GrCaps& caps, - const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - bool hasMixedSamples, - const DstTexture* dstTexture) const { +GrXferProcessor* CustomXPFactory::onCreateXferProcessor(const GrCaps& caps, + const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool hasMixedSamples, + const DstTexture* dstTexture) const { if (can_use_hw_blend_equation(fHWBlendEquation, coveragePOI, caps)) { SkASSERT(!dstTexture || !dstTexture->texture()); return new CustomXP(fMode, fHWBlendEquation); @@ -791,24 +369,33 @@ GrCustomXPFactory::onCreateXferProcessor(const GrCaps& caps, return new CustomXP(dstTexture, hasMixedSamples, fMode); } -bool GrCustomXPFactory::willReadDstColor(const GrCaps& caps, - const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - bool hasMixedSamples) const { +bool CustomXPFactory::willReadDstColor(const GrCaps& caps, + const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool hasMixedSamples) const { return !can_use_hw_blend_equation(fHWBlendEquation, coveragePOI, caps); } -void GrCustomXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - InvariantBlendedColor* blendedColor) const { +void CustomXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI, + InvariantBlendedColor* blendedColor) const { blendedColor->fWillBlendWithDst = true; blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; } -GR_DEFINE_XP_FACTORY_TEST(GrCustomXPFactory); -const GrXPFactory* GrCustomXPFactory::TestCreate(GrProcessorTestData* d) { +GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory); +const GrXPFactory* CustomXPFactory::TestCreate(GrProcessorTestData* d) { int mode = d->fRandom->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode); - return new GrCustomXPFactory(static_cast<SkXfermode::Mode>(mode)); + return new CustomXPFactory(static_cast<SkXfermode::Mode>(mode)); } +/////////////////////////////////////////////////////////////////////////////// + +GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) { + if (!GrCustomXfermode::IsSupportedMode(mode)) { + return nullptr; + } else { + return new CustomXPFactory(mode); + } +} diff --git a/src/gpu/effects/GrCustomXfermodePriv.h b/src/gpu/effects/GrCustomXfermodePriv.h deleted file mode 100644 index 05e07b64ce..0000000000 --- a/src/gpu/effects/GrCustomXfermodePriv.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrCustomXfermodePriv_DEFINED -#define GrCustomXfermodePriv_DEFINED - -#include "GrCaps.h" -#include "GrCoordTransform.h" -#include "GrFragmentProcessor.h" -#include "GrTextureAccess.h" -#include "GrXferProcessor.h" -#include "SkXfermode.h" - -class GrGLCaps; -class GrGLFragmentProcessor; -class GrInvariantOutput; -class GrProcessorKeyBuilder; -class GrTexture; - -/////////////////////////////////////////////////////////////////////////////// -// Fragment Processor -/////////////////////////////////////////////////////////////////////////////// - -class GrCustomXferFP : public GrFragmentProcessor { -public: - GrCustomXferFP(GrProcessorDataManager*, SkXfermode::Mode mode, GrTexture* background); - - const char* name() const override { return "Custom Xfermode"; } - - SkXfermode::Mode mode() const { return fMode; } - const GrTextureAccess& backgroundAccess() const { return fBackgroundAccess; } - -private: - GrGLFragmentProcessor* onCreateGLInstance() const override; - - void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; - - bool onIsEqual(const GrFragmentProcessor& other) const override; - - void onComputeInvariantOutput(GrInvariantOutput* inout) const override; - - GR_DECLARE_FRAGMENT_PROCESSOR_TEST; - - SkXfermode::Mode fMode; - GrCoordTransform fBackgroundTransform; - GrTextureAccess fBackgroundAccess; - - typedef GrFragmentProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Xfer Processor -/////////////////////////////////////////////////////////////////////////////// - -class GrCustomXPFactory : public GrXPFactory { -public: - GrCustomXPFactory(SkXfermode::Mode mode); - - bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override { - return true; - } - - void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, - GrXPFactory::InvariantBlendedColor*) const override; - -private: - GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, - const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - bool hasMixedSamples, - const DstTexture*) const override; - - bool willReadDstColor(const GrCaps& caps, - const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - bool hasMixedSamples) const override; - - bool onIsEqual(const GrXPFactory& xpfBase) const override { - const GrCustomXPFactory& xpf = xpfBase.cast<GrCustomXPFactory>(); - return fMode == xpf.fMode; - } - - GR_DECLARE_XP_FACTORY_TEST; - - SkXfermode::Mode fMode; - GrBlendEquation fHWBlendEquation; - - typedef GrXPFactory INHERITED; -}; -#endif - diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp index 4c50e47ab9..1312d35335 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -13,7 +13,7 @@ #include "GrProcOptInfo.h" #include "GrTypes.h" #include "GrXferProcessor.h" -#include "gl/GrGLBlend.h" +#include "gl/GrGLSLBlend.h" #include "gl/GrGLXferProcessor.h" #include "gl/builders/GrGLFragmentShaderBuilder.h" #include "gl/builders/GrGLProgramBuilder.h" @@ -547,7 +547,7 @@ private: const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>(); GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder(); - GrGLBlend::AppendPorterDuffBlend(fsBuilder, srcColor, dstColor, outColor, xp.getXfermode()); + GrGLSLBlend::AppendMode(fsBuilder, srcColor, dstColor, outColor, xp.getXfermode()); } void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {} @@ -651,7 +651,7 @@ GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode, return nullptr; } - GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); + GrColor blendConstant = GrUnpremulColor(colorPOI.color()); uint8_t alpha = GrColorUnpackA(blendConstant); blendConstant |= (0xff << GrColor_SHIFT_A); diff --git a/src/gpu/effects/GrSimpleTextureEffect.h b/src/gpu/effects/GrSimpleTextureEffect.h index 7f66f90b6d..d99c30e9d0 100644 --- a/src/gpu/effects/GrSimpleTextureEffect.h +++ b/src/gpu/effects/GrSimpleTextureEffect.h @@ -15,18 +15,16 @@ class GrInvariantOutput; /** * The output color of this effect is a modulation of the input color and a sample from a texture. * It allows explicit specification of the filtering and wrap modes (GrTextureParams). It can use - * local coords, positions, or a custom vertex attribute as input texture coords. The input coords - * can have a matrix applied in the VS in both the local and position cases but not with a custom - * attribute coords at this time. It will add a varying to input interpolate texture coords to the - * FS. + * local coords or device space coords as input texture coords. The input coords may be transformed + * by a matrix. */ class GrSimpleTextureEffect : public GrSingleTextureEffect { public: /* unfiltered, clamp mode */ - static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager, - GrTexture* tex, - const SkMatrix& matrix, - GrCoordSet coordSet = kLocal_GrCoordSet) { + static const GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager, + GrTexture* tex, + const SkMatrix& matrix, + GrCoordSet coordSet = kLocal_GrCoordSet) { return new GrSimpleTextureEffect(procDataManager, tex, matrix, GrTextureParams::kNone_FilterMode, coordSet); } diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp index ab944d86fc..942251c980 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); } } diff --git a/src/gpu/gl/GrGLBlend.cpp b/src/gpu/gl/GrGLBlend.cpp deleted file mode 100644 index 4179ec0b53..0000000000 --- a/src/gpu/gl/GrGLBlend.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "GrGLBlend.h" -#include "gl/builders/GrGLFragmentShaderBuilder.h" - -static bool append_porterduff_term(GrGLFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff, - const char* colorName, const char* srcColorName, - const char* dstColorName, bool hasPrevious) { - if (SkXfermode::kZero_Coeff == coeff) { - return hasPrevious; - } else { - if (hasPrevious) { - fsBuilder->codeAppend(" + "); - } - fsBuilder->codeAppendf("%s", colorName); - switch (coeff) { - case SkXfermode::kOne_Coeff: - break; - case SkXfermode::kSC_Coeff: - fsBuilder->codeAppendf(" * %s", srcColorName); - break; - case SkXfermode::kISC_Coeff: - fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); - break; - case SkXfermode::kDC_Coeff: - fsBuilder->codeAppendf(" * %s", dstColorName); - break; - case SkXfermode::kIDC_Coeff: - fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); - break; - case SkXfermode::kSA_Coeff: - fsBuilder->codeAppendf(" * %s.a", srcColorName); - break; - case SkXfermode::kISA_Coeff: - fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); - break; - case SkXfermode::kDA_Coeff: - fsBuilder->codeAppendf(" * %s.a", dstColorName); - break; - case SkXfermode::kIDA_Coeff: - fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName); - break; - default: - SkFAIL("Unsupported Blend Coeff"); - } - return true; - } -} - -void GrGLBlend::AppendPorterDuffBlend(GrGLFragmentBuilder* fsBuilder, const char* srcColor, - const char* dstColor, const char* outColor, - SkXfermode::Mode mode) { - - SkXfermode::Coeff srcCoeff, dstCoeff; - SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff); - - fsBuilder->codeAppendf("%s = ", outColor); - // append src blend - bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor, - false); - // append dst blend - if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) { - fsBuilder->codeAppend("vec4(0, 0, 0, 0)"); - } - fsBuilder->codeAppend(";"); -} diff --git a/src/gpu/gl/GrGLSLBlend.cpp b/src/gpu/gl/GrGLSLBlend.cpp new file mode 100644 index 0000000000..b6224e8230 --- /dev/null +++ b/src/gpu/gl/GrGLSLBlend.cpp @@ -0,0 +1,435 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "GrGLSLBlend.h" +#include "gl/builders/GrGLFragmentShaderBuilder.h" + +////////////////////////////////////////////////////////////////////////////// +// Advanced (non-coeff) blend helpers +////////////////////////////////////////////////////////////////////////////// + +static void hard_light(GrGLFragmentBuilder* fsBuilder, + const char* final, + const char* src, + const char* dst) { + static const char kComponents[] = { 'r', 'g', 'b' }; + for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) { + char component = kComponents[i]; + fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src); + fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;", + final, component, src, component, dst, component); + fsBuilder->codeAppend("} else {"); + fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);", + final, component, src, dst, dst, dst, component, src, src, + component); + fsBuilder->codeAppend("}"); + } + fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);", + final, src, dst, dst, src); +} + +// Does one component of color-dodge +static void color_dodge_component(GrGLFragmentBuilder* fsBuilder, + const char* final, + const char* src, + const char* dst, + const char component) { + fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component); + fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);", + final, component, src, component, dst); + fsBuilder->codeAppend("} else {"); + fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component); + fsBuilder->codeAppend("if (0.0 == d) {"); + fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", + final, component, src, dst, src, component, dst, dst, component, + src); + fsBuilder->codeAppend("} else {"); + fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);", + dst, dst, component, src); + fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", + final, component, src, src, component, dst, dst, component, src); + fsBuilder->codeAppend("}"); + fsBuilder->codeAppend("}"); +} + +// Does one component of color-burn +static void color_burn_component(GrGLFragmentBuilder* fsBuilder, + const char* final, + const char* src, + const char* dst, + const char component) { + fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component); + fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", + final, component, src, dst, src, component, dst, dst, component, + src); + fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component); + fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);", + final, component, dst, component, src); + fsBuilder->codeAppend("} else {"); + fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);", + dst, dst, dst, component, src, src, component); + fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", + final, component, src, src, component, dst, dst, component, src); + fsBuilder->codeAppend("}"); +} + +// Does one component of soft-light. Caller should have already checked that dst alpha > 0. +static void soft_light_component_pos_dst_alpha(GrGLFragmentBuilder* fsBuilder, + const char* final, + const char* src, + const char* dst, + const char component) { + // if (2S < Sa) + fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src); + // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1) + fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +" + "(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);", + final, component, dst, component, dst, component, src, src, + component, dst, dst, src, component, dst, component, src, src, + component); + // else if (4D < Da) + fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {", + dst, component, dst); + fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;", + dst, component, dst, component); + fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component); + fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst); + fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst); + // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2 + fsBuilder->codeAppendf("%s.%c =" + "(DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +" + " 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c) -" + " DaCub*%s.%c) / DaSqd;", + final, component, src, component, dst, component, + src, src, component, dst, src, src, component, src, src, + component, src, component); + fsBuilder->codeAppendf("} else {"); + // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S + fsBuilder->codeAppendf("%s.%c = %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c -" + " sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c;", + final, component, dst, component, src, src, component, src, component, + dst, dst, component, src, src, component, dst, src, component); + fsBuilder->codeAppendf("}"); +} + +// Adds a function that takes two colors and an alpha as input. It produces a color with the +// hue and saturation of the first color, the luminosity of the second color, and the input +// alpha. It has this signature: +// vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor). +static void add_lum_function(GrGLFragmentBuilder* fsBuilder, SkString* setLumFunction) { + // Emit a helper that gets the luminance of a color. + SkString getFunction; + GrGLShaderVar getLumArgs[] = { + GrGLShaderVar("color", kVec3f_GrSLType), + }; + SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);"); + fsBuilder->emitFunction(kFloat_GrSLType, + "luminance", + SK_ARRAY_COUNT(getLumArgs), getLumArgs, + getLumBody.c_str(), + &getFunction); + + // Emit the set luminance function. + GrGLShaderVar setLumArgs[] = { + GrGLShaderVar("hueSat", kVec3f_GrSLType), + GrGLShaderVar("alpha", kFloat_GrSLType), + GrGLShaderVar("lumColor", kVec3f_GrSLType), + }; + SkString setLumBody; + setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str()); + setLumBody.append("vec3 outColor = hueSat + diff;"); + setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str()); + setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);" + "float maxComp = max(max(outColor.r, outColor.g), outColor.b);" + "if (minComp < 0.0 && outLum != minComp) {" + "outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /" + "(outLum - minComp);" + "}" + "if (maxComp > alpha && maxComp != outLum) {" + "outColor = outLum +" + "((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /" + "(maxComp - outLum);" + "}" + "return outColor;"); + fsBuilder->emitFunction(kVec3f_GrSLType, + "set_luminance", + SK_ARRAY_COUNT(setLumArgs), setLumArgs, + setLumBody.c_str(), + setLumFunction); +} + +// Adds a function that creates a color with the hue and luminosity of one input color and +// the saturation of another color. It will have this signature: +// float set_saturation(vec3 hueLumColor, vec3 satColor) +static void add_sat_function(GrGLFragmentBuilder* fsBuilder, SkString* setSatFunction) { + // Emit a helper that gets the saturation of a color + SkString getFunction; + GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) }; + SkString getSatBody; + getSatBody.printf("return max(max(color.r, color.g), color.b) - " + "min(min(color.r, color.g), color.b);"); + fsBuilder->emitFunction(kFloat_GrSLType, + "saturation", + SK_ARRAY_COUNT(getSatArgs), getSatArgs, + getSatBody.c_str(), + &getFunction); + + // Emit a helper that sets the saturation given sorted input channels. This used + // to use inout params for min, mid, and max components but that seems to cause + // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the + // adjusted min, mid, and max inputs, respectively. + SkString helperFunction; + GrGLShaderVar helperArgs[] = { + GrGLShaderVar("minComp", kFloat_GrSLType), + GrGLShaderVar("midComp", kFloat_GrSLType), + GrGLShaderVar("maxComp", kFloat_GrSLType), + GrGLShaderVar("sat", kFloat_GrSLType), + }; + static const char kHelperBody[] = "if (minComp < maxComp) {" + "vec3 result;" + "result.r = 0.0;" + "result.g = sat * (midComp - minComp) / (maxComp - minComp);" + "result.b = sat;" + "return result;" + "} else {" + "return vec3(0, 0, 0);" + "}"; + fsBuilder->emitFunction(kVec3f_GrSLType, + "set_saturation_helper", + SK_ARRAY_COUNT(helperArgs), helperArgs, + kHelperBody, + &helperFunction); + + GrGLShaderVar setSatArgs[] = { + GrGLShaderVar("hueLumColor", kVec3f_GrSLType), + GrGLShaderVar("satColor", kVec3f_GrSLType), + }; + const char* helpFunc = helperFunction.c_str(); + SkString setSatBody; + setSatBody.appendf("float sat = %s(satColor);" + "if (hueLumColor.r <= hueLumColor.g) {" + "if (hueLumColor.g <= hueLumColor.b) {" + "hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);" + "} else if (hueLumColor.r <= hueLumColor.b) {" + "hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);" + "} else {" + "hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);" + "}" + "} else if (hueLumColor.r <= hueLumColor.b) {" + "hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);" + "} else if (hueLumColor.g <= hueLumColor.b) {" + "hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);" + "} else {" + "hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);" + "}" + "return hueLumColor;", + getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc, + helpFunc, helpFunc); + fsBuilder->emitFunction(kVec3f_GrSLType, + "set_saturation", + SK_ARRAY_COUNT(setSatArgs), setSatArgs, + setSatBody.c_str(), + setSatFunction); +} + +static void emit_advanced_xfermode_code(GrGLFragmentBuilder* fsBuilder, const char* srcColor, + const char* dstColor, const char* outputColor, + SkXfermode::Mode mode) { + SkASSERT(srcColor); + SkASSERT(dstColor); + SkASSERT(outputColor); + // These all perform src-over on the alpha channel. + fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;", + outputColor, srcColor, srcColor, dstColor); + + switch (mode) { + case SkXfermode::kOverlay_Mode: + // Overlay is Hard-Light with the src and dst reversed + hard_light(fsBuilder, outputColor, dstColor, srcColor); + break; + case SkXfermode::kDarken_Mode: + fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, " + "(1.0 - %s.a) * %s.rgb + %s.rgb);", + outputColor, + srcColor, dstColor, srcColor, + dstColor, srcColor, dstColor); + break; + case SkXfermode::kLighten_Mode: + fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, " + "(1.0 - %s.a) * %s.rgb + %s.rgb);", + outputColor, + srcColor, dstColor, srcColor, + dstColor, srcColor, dstColor); + break; + case SkXfermode::kColorDodge_Mode: + color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'r'); + color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'g'); + color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'b'); + break; + case SkXfermode::kColorBurn_Mode: + color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'r'); + color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'g'); + color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'b'); + break; + case SkXfermode::kHardLight_Mode: + hard_light(fsBuilder, outputColor, srcColor, dstColor); + break; + case SkXfermode::kSoftLight_Mode: + fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor); + fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, srcColor); + fsBuilder->codeAppendf("} else {"); + soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'r'); + soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'g'); + soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'b'); + fsBuilder->codeAppendf("}"); + break; + case SkXfermode::kDifference_Mode: + fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -" + "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);", + outputColor, srcColor, dstColor, srcColor, dstColor, + dstColor, srcColor); + break; + case SkXfermode::kExclusion_Mode: + fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - " + "2.0 * %s.rgb * %s.rgb;", + outputColor, dstColor, srcColor, dstColor, srcColor); + break; + case SkXfermode::kMultiply_Mode: + fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + " + "(1.0 - %s.a) * %s.rgb + " + "%s.rgb * %s.rgb;", + outputColor, srcColor, dstColor, dstColor, srcColor, + srcColor, dstColor); + break; + case SkXfermode::kHue_Mode: { + // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S + SkString setSat, setLum; + add_sat_function(fsBuilder, &setSat); + add_lum_function(fsBuilder, &setLum); + fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;", + dstColor, srcColor); + fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb)," + "dstSrcAlpha.a, dstSrcAlpha.rgb);", + outputColor, setLum.c_str(), setSat.c_str(), srcColor, + dstColor); + fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", + outputColor, srcColor, dstColor, dstColor, srcColor); + break; + } + case SkXfermode::kSaturation_Mode: { + // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S + SkString setSat, setLum; + add_sat_function(fsBuilder, &setSat); + add_lum_function(fsBuilder, &setLum); + fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;", + dstColor, srcColor); + fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a)," + "dstSrcAlpha.a, dstSrcAlpha.rgb);", + outputColor, setLum.c_str(), setSat.c_str(), srcColor, + dstColor); + fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", + outputColor, srcColor, dstColor, dstColor, srcColor); + break; + } + case SkXfermode::kColor_Mode: { + // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S + SkString setLum; + add_lum_function(fsBuilder, &setLum); + fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;", + srcColor, dstColor); + fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);", + outputColor, setLum.c_str(), dstColor, srcColor); + fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", + outputColor, srcColor, dstColor, dstColor, srcColor); + break; + } + case SkXfermode::kLuminosity_Mode: { + // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S + SkString setLum; + add_lum_function(fsBuilder, &setLum); + fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;", + srcColor, dstColor); + fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);", + outputColor, setLum.c_str(), dstColor, srcColor); + fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", + outputColor, srcColor, dstColor, dstColor, srcColor); + break; + } + default: + SkFAIL("Unknown Custom Xfer mode."); + break; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Porter-Duff blend helper +////////////////////////////////////////////////////////////////////////////// + +static bool append_porterduff_term(GrGLFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff, + const char* colorName, const char* srcColorName, + const char* dstColorName, bool hasPrevious) { + if (SkXfermode::kZero_Coeff == coeff) { + return hasPrevious; + } else { + if (hasPrevious) { + fsBuilder->codeAppend(" + "); + } + fsBuilder->codeAppendf("%s", colorName); + switch (coeff) { + case SkXfermode::kOne_Coeff: + break; + case SkXfermode::kSC_Coeff: + fsBuilder->codeAppendf(" * %s", srcColorName); + break; + case SkXfermode::kISC_Coeff: + fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); + break; + case SkXfermode::kDC_Coeff: + fsBuilder->codeAppendf(" * %s", dstColorName); + break; + case SkXfermode::kIDC_Coeff: + fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); + break; + case SkXfermode::kSA_Coeff: + fsBuilder->codeAppendf(" * %s.a", srcColorName); + break; + case SkXfermode::kISA_Coeff: + fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); + break; + case SkXfermode::kDA_Coeff: + fsBuilder->codeAppendf(" * %s.a", dstColorName); + break; + case SkXfermode::kIDA_Coeff: + fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName); + break; + default: + SkFAIL("Unsupported Blend Coeff"); + } + return true; + } +} + +////////////////////////////////////////////////////////////////////////////// + +void GrGLSLBlend::AppendMode(GrGLFragmentBuilder* fsBuilder, const char* srcColor, + const char* dstColor, const char* outColor, + SkXfermode::Mode mode) { + + SkXfermode::Coeff srcCoeff, dstCoeff; + if (SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff)) { + fsBuilder->codeAppendf("%s = ", outColor); + // append src blend + bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor, + false); + // append dst blend + if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) { + fsBuilder->codeAppend("vec4(0, 0, 0, 0)"); + } + fsBuilder->codeAppend(";"); + } else { + emit_advanced_xfermode_code(fsBuilder, srcColor, dstColor, outColor, mode); + } +} diff --git a/src/gpu/gl/GrGLBlend.h b/src/gpu/gl/GrGLSLBlend.h index af447b47bf..b763f450d8 100644 --- a/src/gpu/gl/GrGLBlend.h +++ b/src/gpu/gl/GrGLSLBlend.h @@ -12,13 +12,13 @@ class GrGLFragmentBuilder; -namespace GrGLBlend { +namespace GrGLSLBlend { /* * Appends GLSL code to fsBuilder that assigns a specified blend of the srcColor and dstColor * variables to the outColor variable. */ - void AppendPorterDuffBlend(GrGLFragmentBuilder* fsBuilder, const char* srcColor, - const char* dstColor, const char* outColor, SkXfermode::Mode mode); + void AppendMode(GrGLFragmentBuilder* fsBuilder, const char* srcColor, + const char* dstColor, const char* outColor, SkXfermode::Mode mode); }; #endif diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp index ba64a7c9cb..8e60a71916 100644 --- a/tests/GLProgramsTest.cpp +++ b/tests/GLProgramsTest.cpp @@ -248,7 +248,7 @@ static void set_random_color_coverage_stages(GrPipelineBuilder* pipelineBuilder, for (int s = 0; s < numProcs;) { SkAutoTUnref<const GrFragmentProcessor> fp( - GrProcessorTestFactory<GrFragmentProcessor>::Create(d)); + GrProcessorTestFactory<GrFragmentProcessor>::Create(d)); SkASSERT(fp); // finally add the stage to the correct pipeline in the drawstate diff --git a/tests/GpuColorFilterTest.cpp b/tests/GpuColorFilterTest.cpp index 5ecc623756..7e99063a1d 100644 --- a/tests/GpuColorFilterTest.cpp +++ b/tests/GpuColorFilterTest.cpp @@ -101,7 +101,7 @@ static void test_getConstantColorComponents(skiatest::Reporter* reporter, GrCont for (size_t i = 0; i < SK_ARRAY_COUNT(filterTests); ++i) { const GetConstantComponentTestCase& test = filterTests[i]; SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(test.filterColor, test.filterMode)); - SkTDArray<GrFragmentProcessor*> array; + SkTDArray<const GrFragmentProcessor*> array; bool hasFrag = cf->asFragmentProcessors(grContext, paint.getProcessorDataManager(), &array); REPORTER_ASSERT(reporter, hasFrag); REPORTER_ASSERT(reporter, 1 == array.count()); diff --git a/tests/GrGetCoeffBlendKnownComponentsTest.cpp b/tests/GrGetCoeffBlendKnownComponentsTest.cpp new file mode 100644 index 0000000000..e733103a77 --- /dev/null +++ b/tests/GrGetCoeffBlendKnownComponentsTest.cpp @@ -0,0 +1,102 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Test.h" + +#if SK_SUPPORT_GPU + +#include "GrBlend.h" +#include "SkGr.h" +#include "SkRandom.h" +#include "SkXfermode.h" + +static GrColor make_baseline_color(GrColor src, GrColor dst, const SkXfermode* xm) { + SkPMColor skSrc = GrColorToSkPMColor(src); + SkPMColor skDst = GrColorToSkPMColor(dst); + if (xm) { + xm->xfer32(&skDst, &skSrc, 1, nullptr); + } else { + // null means src-over + skDst = SkPMSrcOver(skSrc, skDst); + } + return SkPMColorToGrColor(skDst); +} + +DEF_TEST(GrGetCoeffBlendKnownComponents, reporter) { + SkRandom random; + for (int i = 0; i < SkXfermode::kLastCoeffMode; ++i) { + SkXfermode::Mode mode = (SkXfermode::Mode)i; + SkAutoTUnref<SkXfermode> xm(SkXfermode::Create(mode)); + SkXfermode::Coeff srcCoeff, dstCoeff; + SkAssertResult(SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff)); + for (int j = 0; j < 1000; ++j) { + GrColor src = GrPremulColor(random.nextU()); + GrColor dst = GrPremulColor(random.nextU()); + GrColor outColor; + GrColorComponentFlags outFlags; + GrGetCoeffBlendKnownComponents(SkXfermodeCoeffToGrBlendCoeff(srcCoeff), + SkXfermodeCoeffToGrBlendCoeff(dstCoeff), + src, kRGBA_GrColorComponentFlags, + dst, kRGBA_GrColorComponentFlags, + &outColor, &outFlags); + GrColor baselineColor = make_baseline_color(src, dst, xm); + if (SkAbs32(GrColorUnpackA(baselineColor) - GrColorUnpackA(outColor)) > 1 || + SkAbs32(GrColorUnpackR(baselineColor) - GrColorUnpackR(outColor)) > 1 || + SkAbs32(GrColorUnpackG(baselineColor) - GrColorUnpackG(outColor)) > 1 || + SkAbs32(GrColorUnpackB(baselineColor) - GrColorUnpackB(outColor)) > 1) { + ERRORF(reporter, "Blended color is 0x%08x, expected 0x%08x", outColor, + baselineColor); + } + GrColorIsPMAssert(outColor); + } + } + GrColor outColor; + GrColorComponentFlags outFlags; + GrGetCoeffBlendKnownComponents(kZero_GrBlendCoeff, kZero_GrBlendCoeff, + 0xFFFFFFFF, kNone_GrColorComponentFlags, + 0xFFFFFFFF, kNone_GrColorComponentFlags, + &outColor, &outFlags); + REPORTER_ASSERT(reporter, GrColor_TRANSPARENT_BLACK == outColor && + kRGBA_GrColorComponentFlags == outFlags); + GrGetCoeffBlendKnownComponents( + kOne_GrBlendCoeff, kOne_GrBlendCoeff, + 0x80FF0100, (kG_GrColorComponentFlag | kB_GrColorComponentFlag | kA_GrColorComponentFlag), + 0x7F00FFFF, (kR_GrColorComponentFlag | kG_GrColorComponentFlag | kA_GrColorComponentFlag), + &outColor, &outFlags); + REPORTER_ASSERT(reporter, GrColor_WHITE == outColor && kRGBA_GrColorComponentFlags == outFlags); + + GrGetCoeffBlendKnownComponents( + kOne_GrBlendCoeff, kISA_GrBlendCoeff, + 0x0000000, kRGBA_GrColorComponentFlags, + 0x80010203, kRGBA_GrColorComponentFlags, + &outColor, &outFlags); + REPORTER_ASSERT(reporter, 0x80010203 == outColor && kRGBA_GrColorComponentFlags == outFlags); + + GrGetCoeffBlendKnownComponents(kZero_GrBlendCoeff, kISA_GrBlendCoeff, + 0x0000000, kA_GrColorComponentFlag, + 0x80010203, kRGBA_GrColorComponentFlags, + &outColor, &outFlags); + REPORTER_ASSERT(reporter, 0x80010203 == outColor && kRGBA_GrColorComponentFlags == outFlags); + + GrGetCoeffBlendKnownComponents( + kIDC_GrBlendCoeff, kSC_GrBlendCoeff, + 0x0, kNone_GrColorComponentFlags, + 0x0, kRGBA_GrColorComponentFlags, + &outColor, &outFlags); + REPORTER_ASSERT(reporter, kNone_GrColorComponentFlags == outFlags); + + GrGetCoeffBlendKnownComponents( + kOne_GrBlendCoeff, kISA_GrBlendCoeff, + 0xFF808080, (kG_GrColorComponentFlag | kB_GrColorComponentFlag | kA_GrColorComponentFlag), + 0xFF606060, kRGBA_GrColorComponentFlags, + &outColor, &outFlags); + REPORTER_ASSERT(reporter, + (kG_GrColorComponentFlag | kB_GrColorComponentFlag | kA_GrColorComponentFlag) == outFlags && + (outColor & 0xFFFFFF00) == 0xFF808000); +} + +#endif |