1 /* 2 * Copyright 2023 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef skgpu_BlendFormula_DEFINED 9 #define skgpu_BlendFormula_DEFINED 10 11 #include "include/private/base/SkAssert.h" 12 #include "include/private/base/SkMacros.h" 13 #include "include/private/base/SkTo.h" 14 #include "src/gpu/Blend.h" 15 16 #include <cstdint> 17 18 enum class SkBlendMode; 19 20 namespace skgpu { 21 22 /** 23 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage. 24 */ 25 class BlendFormula { 26 public: 27 /** 28 * Values the shader can write to primary and secondary outputs. These are all modulated by 29 * coverage. We will ignore the multiplies when not using coverage. 30 */ 31 enum OutputType { 32 kNone_OutputType, //<! 0 33 kCoverage_OutputType, //<! inputCoverage 34 kModulate_OutputType, //<! inputColor * inputCoverage 35 kSAModulate_OutputType, //<! inputColor.a * inputCoverage 36 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage 37 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage 38 39 kLast_OutputType = kISCModulate_OutputType 40 }; 41 BlendFormula(OutputType primaryOut,OutputType secondaryOut,skgpu::BlendEquation equation,skgpu::BlendCoeff srcCoeff,skgpu::BlendCoeff dstCoeff)42 constexpr BlendFormula(OutputType primaryOut, 43 OutputType secondaryOut, 44 skgpu::BlendEquation equation, 45 skgpu::BlendCoeff srcCoeff, 46 skgpu::BlendCoeff dstCoeff) 47 : fPrimaryOutputType(primaryOut) 48 , fSecondaryOutputType(secondaryOut) 49 , fBlendEquation(SkTo<uint8_t>(equation)) 50 , fSrcCoeff(SkTo<uint8_t>(srcCoeff)) 51 , fDstCoeff(SkTo<uint8_t>(dstCoeff)) 52 , fProps(GetProperties(primaryOut, secondaryOut, equation, srcCoeff, dstCoeff)) {} 53 54 BlendFormula(const BlendFormula&) = default; 55 BlendFormula& operator=(const BlendFormula&) = default; 56 57 bool operator==(const BlendFormula& that) const { 58 return fPrimaryOutputType == that.fPrimaryOutputType && 59 fSecondaryOutputType == that. fSecondaryOutputType && 60 fBlendEquation == that.fBlendEquation && 61 fSrcCoeff == that.fSrcCoeff && 62 fDstCoeff == that.fDstCoeff && 63 fProps == that.fProps; 64 } 65 hasSecondaryOutput()66 bool hasSecondaryOutput() const { 67 return kNone_OutputType != fSecondaryOutputType; 68 } modifiesDst()69 bool modifiesDst() const { 70 return SkToBool(fProps & kModifiesDst_Property); 71 } unaffectedByDst()72 bool unaffectedByDst() const { 73 return SkToBool(fProps & kUnaffectedByDst_Property); 74 } 75 // We don't always fully optimize the blend formula (e.g., for opaque src-over), so we include 76 // an "IfOpaque" variant to help set AnalysisProperties::kUnaffectedByDstValue in those cases. unaffectedByDstIfOpaque()77 bool unaffectedByDstIfOpaque() const { 78 return SkToBool(fProps & kUnaffectedByDstIfOpaque_Property); 79 } usesInputColor()80 bool usesInputColor() const { 81 return SkToBool(fProps & kUsesInputColor_Property); 82 } canTweakAlphaForCoverage()83 bool canTweakAlphaForCoverage() const { 84 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property); 85 } 86 equation()87 skgpu::BlendEquation equation() const { 88 return static_cast<skgpu::BlendEquation>(fBlendEquation); 89 } 90 srcCoeff()91 skgpu::BlendCoeff srcCoeff() const { 92 return static_cast<skgpu::BlendCoeff>(fSrcCoeff); 93 } 94 dstCoeff()95 skgpu::BlendCoeff dstCoeff() const { 96 return static_cast<skgpu::BlendCoeff>(fDstCoeff); 97 } 98 primaryOutput()99 OutputType primaryOutput() const { 100 return fPrimaryOutputType; 101 } 102 secondaryOutput()103 OutputType secondaryOutput() const { 104 return fSecondaryOutputType; 105 } 106 107 private: 108 enum Properties { 109 kModifiesDst_Property = 1 << 0, 110 kUnaffectedByDst_Property = 1 << 1, 111 kUnaffectedByDstIfOpaque_Property = 1 << 2, 112 kUsesInputColor_Property = 1 << 3, 113 kCanTweakAlphaForCoverage_Property = 1 << 4, 114 115 kLast_Property = kCanTweakAlphaForCoverage_Property 116 }; SK_DECL_BITFIELD_OPS_FRIENDS(Properties)117 SK_DECL_BITFIELD_OPS_FRIENDS(Properties) 118 119 /** 120 * Deduce the properties of a BlendFormula. 121 */ 122 constexpr BlendFormula::Properties GetProperties(OutputType PrimaryOut, 123 OutputType SecondaryOut, 124 skgpu::BlendEquation BlendEquation, 125 skgpu::BlendCoeff SrcCoeff, 126 skgpu::BlendCoeff DstCoeff) { 127 return 128 // The provided formula should already be optimized before a BlendFormula is constructed. 129 // Assert that here while setting up the properties in the constexpr constructor. 130 SkASSERT((kNone_OutputType == PrimaryOut) == 131 !skgpu::BlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)), 132 SkASSERT(!skgpu::BlendCoeffRefsSrc2(SrcCoeff)), 133 SkASSERT((kNone_OutputType == SecondaryOut) == !skgpu::BlendCoeffRefsSrc2(DstCoeff)), 134 SkASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut), 135 SkASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut), 136 137 static_cast<Properties>( 138 (skgpu::BlendModifiesDst(BlendEquation, SrcCoeff, DstCoeff) 139 ? kModifiesDst_Property 140 : 0) | 141 (!skgpu::BlendCoeffsUseDstColor(SrcCoeff, DstCoeff, false/*srcColorIsOpaque*/) 142 ? kUnaffectedByDst_Property 143 : 0) | 144 (!skgpu::BlendCoeffsUseDstColor(SrcCoeff, DstCoeff, true/*srcColorIsOpaque*/) 145 ? kUnaffectedByDstIfOpaque_Property 146 : 0) | 147 ((PrimaryOut >= kModulate_OutputType && 148 skgpu::BlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)) || 149 (SecondaryOut >= kModulate_OutputType && 150 skgpu::BlendCoeffRefsSrc2(DstCoeff)) 151 ? kUsesInputColor_Property 152 : 0) | // We assert later that SrcCoeff doesn't ref src2. 153 ((kModulate_OutputType == PrimaryOut || kNone_OutputType == PrimaryOut) && 154 kNone_OutputType == SecondaryOut && 155 skgpu::BlendAllowsCoverageAsAlpha(BlendEquation, SrcCoeff, DstCoeff) 156 ? kCanTweakAlphaForCoverage_Property 157 : 0)); 158 } 159 160 struct { 161 // We allot the enums one more bit than they require because MSVC seems to sign-extend 162 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4) 163 OutputType fPrimaryOutputType : 4; 164 OutputType fSecondaryOutputType : 4; 165 uint32_t fBlendEquation : 6; 166 uint32_t fSrcCoeff : 6; 167 uint32_t fDstCoeff : 6; 168 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6); 169 }; 170 171 static_assert(kLast_OutputType < (1 << 3)); 172 static_assert(static_cast<int>(skgpu::BlendEquation::kLast) < (1 << 5)); 173 static_assert(static_cast<int>(skgpu::BlendCoeff::kLast) < (1 << 5)); 174 static_assert(kLast_Property < (1 << 6)); 175 }; 176 177 static_assert(4 == sizeof(BlendFormula)); 178 179 SK_MAKE_BITFIELD_OPS(BlendFormula::Properties) 180 181 BlendFormula GetBlendFormula(bool isOpaque, bool hasCoverage, SkBlendMode xfermode); 182 183 BlendFormula GetLCDBlendFormula(SkBlendMode xfermode); 184 185 } // namespace skgpu 186 187 #endif // skgpu_BlendFormula_DEFINED 188