| /* | |
| * Copyright 2013 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef skgpu_Blend_DEFINED | |
| #define skgpu_Blend_DEFINED | |
| #include "include/core/SkSpan.h" | |
| #include "include/core/SkTypes.h" | |
| #include "include/private/SkDebug.h" | |
| #include "src/core/SkColorData.h" | |
| #include <cstdint> | |
| enum class SkBlendMode; | |
| class SkString; | |
| namespace skgpu { | |
| /** | |
| * Equations for alpha-blending. | |
| */ | |
| enum class BlendEquation : uint8_t { | |
| // Basic blend equations. | |
| kAdd, //<! Cs*S + Cd*D | |
| kSubtract, //<! Cs*S - Cd*D | |
| kReverseSubtract, //<! Cd*D - Cs*S | |
| // Advanced blend equations. These are described in the SVG and PDF specs. | |
| kScreen, | |
| kOverlay, | |
| kDarken, | |
| kLighten, | |
| kColorDodge, | |
| kColorBurn, | |
| kHardLight, | |
| kSoftLight, | |
| kDifference, | |
| kExclusion, | |
| kMultiply, | |
| kHSLHue, | |
| kHSLSaturation, | |
| kHSLColor, | |
| kHSLLuminosity, | |
| kIllegal, | |
| kFirstAdvanced = kScreen, | |
| kLast = kIllegal, | |
| }; | |
| static const int kBlendEquationCnt = static_cast<int>(BlendEquation::kLast) + 1; | |
| /** | |
| * Coefficients for alpha-blending. | |
| */ | |
| enum class BlendCoeff : uint8_t { | |
| kZero, //<! 0 | |
| kOne, //<! 1 | |
| kSC, //<! src color | |
| kISC, //<! one minus src color | |
| kDC, //<! dst color | |
| kIDC, //<! one minus dst color | |
| kSA, //<! src alpha | |
| kISA, //<! one minus src alpha | |
| kDA, //<! dst alpha | |
| kIDA, //<! one minus dst alpha | |
| kConstC, //<! constant color | |
| kIConstC, //<! one minus constant color | |
| kS2C, | |
| kIS2C, | |
| kS2A, | |
| kIS2A, | |
| kIllegal, | |
| kLast = kIllegal, | |
| }; | |
| struct BlendInfo { | |
| SkDEBUGCODE(SkString dump() const;) | |
| bool operator==(const BlendInfo& other) const { | |
| return fEquation == other.fEquation && | |
| fSrcBlend == other.fSrcBlend && | |
| fDstBlend == other.fDstBlend && | |
| fBlendConstant == other.fBlendConstant && | |
| fWritesColor == other.fWritesColor; | |
| } | |
| skgpu::BlendEquation fEquation = skgpu::BlendEquation::kAdd; | |
| skgpu::BlendCoeff fSrcBlend = skgpu::BlendCoeff::kOne; | |
| skgpu::BlendCoeff fDstBlend = skgpu::BlendCoeff::kZero; | |
| SkPMColor4f fBlendConstant = SK_PMColor4fTRANSPARENT; | |
| bool fWritesColor = true; | |
| }; | |
| static const int kBlendCoeffCnt = static_cast<int>(BlendCoeff::kLast) + 1; | |
| static constexpr bool BlendCoeffRefsSrc(const BlendCoeff coeff) { | |
| return BlendCoeff::kSC == coeff || BlendCoeff::kISC == coeff || BlendCoeff::kSA == coeff || | |
| BlendCoeff::kISA == coeff; | |
| } | |
| static constexpr bool BlendCoeffRefsDst(const BlendCoeff coeff) { | |
| return BlendCoeff::kDC == coeff || BlendCoeff::kIDC == coeff || BlendCoeff::kDA == coeff || | |
| BlendCoeff::kIDA == coeff; | |
| } | |
| static constexpr bool BlendCoeffRefsSrc2(const BlendCoeff coeff) { | |
| return BlendCoeff::kS2C == coeff || BlendCoeff::kIS2C == coeff || | |
| BlendCoeff::kS2A == coeff || BlendCoeff::kIS2A == coeff; | |
| } | |
| static constexpr bool BlendCoeffsUseSrcColor(BlendCoeff srcCoeff, BlendCoeff dstCoeff) { | |
| return BlendCoeff::kZero != srcCoeff || BlendCoeffRefsSrc(dstCoeff); | |
| } | |
| static constexpr bool BlendCoeffsUseDstColor(BlendCoeff srcCoeff, | |
| BlendCoeff dstCoeff, | |
| bool srcColorIsOpaque) { | |
| return BlendCoeffRefsDst(srcCoeff) || | |
| (dstCoeff != BlendCoeff::kZero && !(dstCoeff == BlendCoeff::kISA && srcColorIsOpaque)); | |
| } | |
| static constexpr bool BlendEquationIsAdvanced(BlendEquation equation) { | |
| return equation >= BlendEquation::kFirstAdvanced && | |
| equation != BlendEquation::kIllegal; | |
| } | |
| static constexpr bool BlendModifiesDst(BlendEquation equation, | |
| BlendCoeff srcCoeff, | |
| BlendCoeff dstCoeff) { | |
| return (BlendEquation::kAdd != equation && BlendEquation::kReverseSubtract != equation) || | |
| BlendCoeff::kZero != srcCoeff || BlendCoeff::kOne != dstCoeff; | |
| } | |
| static constexpr bool BlendCoeffRefsConstant(const BlendCoeff coeff) { | |
| return coeff == BlendCoeff::kConstC || coeff == BlendCoeff::kIConstC; | |
| } | |
| static constexpr bool BlendShouldDisable(BlendEquation equation, | |
| BlendCoeff srcCoeff, | |
| BlendCoeff dstCoeff) { | |
| return (BlendEquation::kAdd == equation || BlendEquation::kSubtract == equation) && | |
| BlendCoeff::kOne == srcCoeff && BlendCoeff::kZero == dstCoeff; | |
| } | |
| /** | |
| * Advanced blend equations can always tweak alpha for coverage. (See GrCustomXfermode.cpp) | |
| * | |
| * For "add" and "reverse subtract" the blend equation with f=coverage is: | |
| * | |
| * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D | |
| * = f * S * srcCoeff + D * (f * dstCoeff + (1 - f)) | |
| * | |
| * (Let srcCoeff be negative for reverse subtract.) We can tweak alpha for coverage when the | |
| * following relationship holds: | |
| * | |
| * (f*S) * srcCoeff' + D * dstCoeff' == f * S * srcCoeff + D * (f * dstCoeff + (1 - f)) | |
| * | |
| * (Where srcCoeff' and dstCoeff' have any reference to S pre-multiplied by f.) | |
| * | |
| * It's easy to see this works for the src term as long as srcCoeff' == srcCoeff (meaning srcCoeff | |
| * does not reference S). For the dst term, this will work as long as the following is true: | |
| *| | |
| * dstCoeff' == f * dstCoeff + (1 - f) | |
| * dstCoeff' == 1 - f * (1 - dstCoeff) | |
| * | |
| * By inspection we can see this will work as long as dstCoeff has a 1, and any other term in | |
| * dstCoeff references S. | |
| * | |
| * Moreover, if the blend doesn't modify the dst at all then it is ok to arbitrarily modify the src | |
| * color so folding in coverage is allowed. | |
| */ | |
| static constexpr bool BlendAllowsCoverageAsAlpha(BlendEquation equation, | |
| BlendCoeff srcCoeff, | |
| BlendCoeff dstCoeff) { | |
| return BlendEquationIsAdvanced(equation) || | |
| !BlendModifiesDst(equation, srcCoeff, dstCoeff) || | |
| ((BlendEquation::kAdd == equation || BlendEquation::kReverseSubtract == equation) && | |
| !BlendCoeffRefsSrc(srcCoeff) && | |
| (BlendCoeff::kOne == dstCoeff || BlendCoeff::kISC == dstCoeff || | |
| BlendCoeff::kISA == dstCoeff)); | |
| } | |
| /** | |
| * Returns the name of the SkSL built-in blend function for a SkBlendMode. | |
| */ | |
| const char* BlendFuncName(SkBlendMode mode); | |
| /** | |
| * If a blend can be represented by `blend_porter_duff`, returns the associated blend constants as | |
| * an array of four floats. If not, returns an empty span. | |
| */ | |
| SkSpan<const float> GetPorterDuffBlendConstants(SkBlendMode mode); | |
| /** | |
| * Returns a pair of "blend function + uniform data" for a particular SkBlendMode. | |
| * This allows us to use fewer unique functions when generating shaders, e.g. every Porter-Duff | |
| * blend can use the same function. | |
| */ | |
| struct ReducedBlendModeInfo { | |
| const char* fFunction; | |
| SkSpan<const float> fUniformData; | |
| }; | |
| ReducedBlendModeInfo GetReducedBlendModeInfo(SkBlendMode mode); | |
| } // namespace skgpu | |
| #endif // skgpu_Blend_DEFINED |