| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef skgpu_BlendFormula_DEFINED | |
| #define skgpu_BlendFormula_DEFINED | |
| #include "include/private/SkAssert.h" | |
| #include "include/private/SkMacros.h" | |
| #include "include/private/SkTo.h" | |
| #include "src/gpu/Blend.h" | |
| #include <cstdint> | |
| enum class SkBlendMode; | |
| namespace skgpu { | |
| /** | |
| * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage. | |
| */ | |
| class BlendFormula { | |
| public: | |
| /** | |
| * Values the shader can write to primary and secondary outputs. These are all modulated by | |
| * coverage. We will ignore the multiplies when not using coverage. | |
| */ | |
| enum OutputType { | |
| kNone_OutputType, //<! 0 | |
| kCoverage_OutputType, //<! inputCoverage | |
| kModulate_OutputType, //<! inputColor * inputCoverage | |
| kSAModulate_OutputType, //<! inputColor.a * inputCoverage | |
| kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage | |
| kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage | |
| kLast_OutputType = kISCModulate_OutputType | |
| }; | |
| constexpr BlendFormula(OutputType primaryOut, | |
| OutputType secondaryOut, | |
| skgpu::BlendEquation equation, | |
| skgpu::BlendCoeff srcCoeff, | |
| skgpu::BlendCoeff dstCoeff) | |
| : fPrimaryOutputType(primaryOut) | |
| , fSecondaryOutputType(secondaryOut) | |
| , fBlendEquation(SkTo<uint8_t>(equation)) | |
| , fSrcCoeff(SkTo<uint8_t>(srcCoeff)) | |
| , fDstCoeff(SkTo<uint8_t>(dstCoeff)) | |
| , fProps(GetProperties(primaryOut, secondaryOut, equation, srcCoeff, dstCoeff)) {} | |
| BlendFormula(const BlendFormula&) = default; | |
| BlendFormula& operator=(const BlendFormula&) = default; | |
| bool operator==(const BlendFormula& that) const { | |
| return fPrimaryOutputType == that.fPrimaryOutputType && | |
| fSecondaryOutputType == that. fSecondaryOutputType && | |
| fBlendEquation == that.fBlendEquation && | |
| fSrcCoeff == that.fSrcCoeff && | |
| fDstCoeff == that.fDstCoeff && | |
| fProps == that.fProps; | |
| } | |
| bool hasSecondaryOutput() const { | |
| return kNone_OutputType != fSecondaryOutputType; | |
| } | |
| bool modifiesDst() const { | |
| return SkToBool(fProps & kModifiesDst_Property); | |
| } | |
| bool unaffectedByDst() const { | |
| return SkToBool(fProps & kUnaffectedByDst_Property); | |
| } | |
| // We don't always fully optimize the blend formula (e.g., for opaque src-over), so we include | |
| // an "IfOpaque" variant to help set AnalysisProperties::kUnaffectedByDstValue in those cases. | |
| bool unaffectedByDstIfOpaque() const { | |
| return SkToBool(fProps & kUnaffectedByDstIfOpaque_Property); | |
| } | |
| bool usesInputColor() const { | |
| return SkToBool(fProps & kUsesInputColor_Property); | |
| } | |
| bool canTweakAlphaForCoverage() const { | |
| return SkToBool(fProps & kCanTweakAlphaForCoverage_Property); | |
| } | |
| skgpu::BlendEquation equation() const { | |
| return static_cast<skgpu::BlendEquation>(fBlendEquation); | |
| } | |
| skgpu::BlendCoeff srcCoeff() const { | |
| return static_cast<skgpu::BlendCoeff>(fSrcCoeff); | |
| } | |
| skgpu::BlendCoeff dstCoeff() const { | |
| return static_cast<skgpu::BlendCoeff>(fDstCoeff); | |
| } | |
| OutputType primaryOutput() const { | |
| return fPrimaryOutputType; | |
| } | |
| OutputType secondaryOutput() const { | |
| return fSecondaryOutputType; | |
| } | |
| private: | |
| enum Properties { | |
| kModifiesDst_Property = 1 << 0, | |
| kUnaffectedByDst_Property = 1 << 1, | |
| kUnaffectedByDstIfOpaque_Property = 1 << 2, | |
| kUsesInputColor_Property = 1 << 3, | |
| kCanTweakAlphaForCoverage_Property = 1 << 4, | |
| kLast_Property = kCanTweakAlphaForCoverage_Property | |
| }; | |
| SK_DECL_BITFIELD_OPS_FRIENDS(Properties) | |
| /** | |
| * Deduce the properties of a BlendFormula. | |
| */ | |
| constexpr BlendFormula::Properties GetProperties(OutputType PrimaryOut, | |
| OutputType SecondaryOut, | |
| skgpu::BlendEquation BlendEquation, | |
| skgpu::BlendCoeff SrcCoeff, | |
| skgpu::BlendCoeff DstCoeff) { | |
| return | |
| // The provided formula should already be optimized before a BlendFormula is constructed. | |
| // Assert that here while setting up the properties in the constexpr constructor. | |
| SkASSERT((kNone_OutputType == PrimaryOut) == | |
| !skgpu::BlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)), | |
| SkASSERT(!skgpu::BlendCoeffRefsSrc2(SrcCoeff)), | |
| SkASSERT((kNone_OutputType == SecondaryOut) == !skgpu::BlendCoeffRefsSrc2(DstCoeff)), | |
| SkASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut), | |
| SkASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut), | |
| static_cast<Properties>( | |
| (skgpu::BlendModifiesDst(BlendEquation, SrcCoeff, DstCoeff) | |
| ? kModifiesDst_Property | |
| : 0) | | |
| (!skgpu::BlendCoeffsUseDstColor(SrcCoeff, DstCoeff, false/*srcColorIsOpaque*/) | |
| ? kUnaffectedByDst_Property | |
| : 0) | | |
| (!skgpu::BlendCoeffsUseDstColor(SrcCoeff, DstCoeff, true/*srcColorIsOpaque*/) | |
| ? kUnaffectedByDstIfOpaque_Property | |
| : 0) | | |
| ((PrimaryOut >= kModulate_OutputType && | |
| skgpu::BlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)) || | |
| (SecondaryOut >= kModulate_OutputType && | |
| skgpu::BlendCoeffRefsSrc2(DstCoeff)) | |
| ? kUsesInputColor_Property | |
| : 0) | // We assert later that SrcCoeff doesn't ref src2. | |
| ((kModulate_OutputType == PrimaryOut || kNone_OutputType == PrimaryOut) && | |
| kNone_OutputType == SecondaryOut && | |
| skgpu::BlendAllowsCoverageAsAlpha(BlendEquation, SrcCoeff, DstCoeff) | |
| ? kCanTweakAlphaForCoverage_Property | |
| : 0)); | |
| } | |
| struct { | |
| // We allot the enums one more bit than they require because MSVC seems to sign-extend | |
| // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4) | |
| OutputType fPrimaryOutputType : 4; | |
| OutputType fSecondaryOutputType : 4; | |
| uint32_t fBlendEquation : 6; | |
| uint32_t fSrcCoeff : 6; | |
| uint32_t fDstCoeff : 6; | |
| Properties fProps : 32 - (4 + 4 + 6 + 6 + 6); | |
| }; | |
| static_assert(kLast_OutputType < (1 << 3)); | |
| static_assert(static_cast<int>(skgpu::BlendEquation::kLast) < (1 << 5)); | |
| static_assert(static_cast<int>(skgpu::BlendCoeff::kLast) < (1 << 5)); | |
| static_assert(kLast_Property < (1 << 6)); | |
| }; | |
| static_assert(4 == sizeof(BlendFormula)); | |
| SK_MAKE_BITFIELD_OPS(BlendFormula::Properties) | |
| BlendFormula GetBlendFormula(bool isOpaque, bool hasCoverage, SkBlendMode xfermode); | |
| BlendFormula GetLCDBlendFormula(SkBlendMode xfermode); | |
| } // namespace skgpu | |
| #endif // skgpu_BlendFormula_DEFINED |