| /* |
| * 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/SkColorData.h" |
| |
| 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 |