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