Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright 2015 Google Inc. | |
| 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 #include "effects/GrAdvancedEquationXferProcessor.h" | |
| 9 | |
| 10 #include "GrDrawTargetCaps.h" | |
| 11 #include "GrGpu.h" | |
| 12 #include "gl/GrGLXferProcessor.h" | |
| 13 #include "gl/builders/GrGLFragmentShaderBuilder.h" | |
| 14 #include "gl/builders/GrGLProgramBuilder.h" | |
| 15 | |
| 16 class AdvancedEquationXPBase : public GrXferProcessor { | |
| 17 public: | |
| 18 static AdvancedEquationXPBase* Create(bool hasCoverage, GrBlendEquation equa tion); | |
| 19 AdvancedEquationXPBase(GrBlendEquation equation) : fEquation(equation) {} | |
| 20 | |
| 21 const char* name() const override { return "Blend Equation Advanced"; } | |
| 22 bool hasSecondaryOutput() const override { return false; } | |
| 23 | |
| 24 bool willNeedXferBarrier(const GrRenderTarget* rt, const GrDrawTargetCaps&, | |
| 25 GrXferBarrierType* outBarrierType) const override; | |
| 26 | |
| 27 protected: | |
| 28 void onGetGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const over ride; | |
| 29 | |
| 30 void onGetBlendInfo(BlendInfo*) const override; | |
| 31 | |
| 32 bool onIsEqual(const GrXferProcessor& xpBase) const override { | |
| 33 const AdvancedEquationXPBase& xp = xpBase.cast<AdvancedEquationXPBase>() ; | |
| 34 return fEquation == xp.fEquation; | |
| 35 } | |
| 36 | |
| 37 const GrBlendEquation fEquation; | |
| 38 | |
| 39 typedef GrXferProcessor INHERITED; | |
| 40 }; | |
| 41 | |
| 42 template<bool HasCoverage> class AdvancedEquationXP: public AdvancedEquationXPBa se { | |
| 43 public: | |
| 44 AdvancedEquationXP(GrBlendEquation equation) : INHERITED(equation) { | |
| 45 this->initClassID<AdvancedEquationXP>(); | |
| 46 } | |
| 47 | |
| 48 OptFlags getOptimizations(const GrProcOptInfo&, const GrProcOptInfo&, bool, GrColor*, | |
| 49 const GrDrawTargetCaps&) override; | |
| 50 | |
| 51 GrGLXferProcessor* createGLInstance() const override; | |
| 52 | |
| 53 private: | |
| 54 typedef AdvancedEquationXPBase INHERITED; | |
| 55 }; | |
| 56 | |
| 57 | |
| 58 bool GrAdvancedEquationXPFactory::IsSupported(const GrContext* context, SkXfermo de::Mode mode) { | |
| 59 if (!context->getGpu()->caps()->advancedBlendEquationSupport()) { | |
| 60 return false; | |
| 61 } | |
| 62 if (mode > SkXfermode::kLastMode) { | |
| 63 return false; | |
| 64 } | |
| 65 return mode == SkXfermode::kScreen_Mode || mode > SkXfermode::kLastCoeffMode ; | |
| 66 } | |
| 67 | |
| 68 GrXPFactory* GrAdvancedEquationXPFactory::Create(SkXfermode::Mode mode) { | |
| 69 switch (mode) { | |
| 70 default: break; | |
| 71 case SkXfermode::kScreen_Mode: return RefFactory<kScreen_GrBlendEquation >(); | |
| 72 case SkXfermode::kOverlay_Mode: return RefFactory<kOverlay_GrBlendEquati on>(); | |
| 73 case SkXfermode::kDarken_Mode: return RefFactory<kDarken_GrBlendEquation >(); | |
| 74 case SkXfermode::kLighten_Mode: return RefFactory<kLighten_GrBlendEquati on>(); | |
| 75 case SkXfermode::kColorDodge_Mode: return RefFactory<kColorDodge_GrBlend Equation>(); | |
| 76 case SkXfermode::kColorBurn_Mode: return RefFactory<kColorBurn_GrBlendEq uation>(); | |
| 77 case SkXfermode::kHardLight_Mode: return RefFactory<kHardLight_GrBlendEq uation>(); | |
| 78 case SkXfermode::kSoftLight_Mode: return RefFactory<kSoftLight_GrBlendEq uation>(); | |
| 79 case SkXfermode::kDifference_Mode: return RefFactory<kDifference_GrBlend Equation>(); | |
| 80 case SkXfermode::kExclusion_Mode: return RefFactory<kExclusion_GrBlendEq uation>(); | |
| 81 case SkXfermode::kMultiply_Mode: return RefFactory<kMultiply_GrBlendEqua tion>(); | |
| 82 case SkXfermode::kHue_Mode: return RefFactory<kHSLHue_GrBlendEquation>() ; | |
| 83 case SkXfermode::kSaturation_Mode: return RefFactory<kHSLSaturation_GrBl endEquation>(); | |
| 84 case SkXfermode::kColor_Mode: return RefFactory<kHSLColor_GrBlendEquatio n>(); | |
| 85 case SkXfermode::kLuminosity_Mode: return RefFactory<kHSLLuminosity_GrBl endEquation>(); | |
| 86 } | |
| 87 | |
| 88 return NULL; | |
| 89 } | |
| 90 | |
| 91 template<GrBlendEquation Equation> GrXPFactory* GrAdvancedEquationXPFactory::Ref Factory() { | |
| 92 GR_STATIC_ASSERT(GrBlendEquationIsAdvanced(Equation)); | |
| 93 static GrAdvancedEquationXPFactory* factory; | |
| 94 if (!factory) { | |
| 95 factory = SkNEW_ARGS(GrAdvancedEquationXPFactory, (Equation)); | |
| 96 } | |
| 97 return SkRef(factory); | |
| 98 } | |
| 99 | |
| 100 bool GrAdvancedEquationXPFactory::canTweakAlphaForCoverage() const { | |
| 101 /* | |
| 102 The general SVG blend equation is defined in the spec as follows: | |
| 103 | |
| 104 Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa) | |
| 105 Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa) | |
| 106 | |
| 107 (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha, | |
| 108 and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied | |
| 109 RGB colors.) | |
| 110 | |
| 111 For every "advanced" blend mode, X=Y=Z=1 and this equation reduces to the | |
| 112 PDF blend equation. | |
| 113 | |
| 114 It can be shown that when X=Y=Z=1, canTweakAlphaForCoverage() is true. | |
| 115 | |
| 116 | |
| 117 == Color == | |
| 118 | |
| 119 We substitute Y=Z=1 and define a blend() function that calculates Dca' in | |
| 120 terms of premultiplied alpha only: | |
| 121 | |
| 122 blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0, | |
| 123 Sca : if Da == 0, | |
| 124 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dc a * (1-Sa) : if Sa,Da != 0} | |
| 125 | |
| 126 And for coverage modulation, we use a post blend src-over model: | |
| 127 | |
| 128 Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 129 | |
| 130 (Where f is the fractional coverage.) | |
| 131 | |
| 132 Next we show that canTweakAlphaForCoverage() is true by proving the | |
| 133 following relationship: | |
| 134 | |
| 135 blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 136 | |
| 137 General case (f,Sa,Da != 0): | |
| 138 | |
| 139 f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 140 = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f ) * Dca [Sa,Da != 0, definition of blend()] | |
| 141 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca | |
| 142 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * S a + Dca - f*Dca | |
| 143 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca | |
| 144 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca | |
| 145 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) | |
| 146 = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0] | |
| 147 = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()] | |
| 148 | |
| 149 Corner cases (Sa=0, Da=0, and f=0): | |
| 150 | |
| 151 Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 152 = f * Dca + (1-f) * Dca [Sa=0, definition of blend()] | |
| 153 = Dca | |
| 154 = blend(0, Dca, 0, Da) [definition of blend()] | |
| 155 = blend(f*Sca, Dca, f*Sa, Da) [Sa=0] | |
| 156 | |
| 157 Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 158 = f * Sca + (1-f) * Dca [Da=0, definition of blend()] | |
| 159 = f * Sca [Da=0] | |
| 160 = blend(f*Sca, 0, f*Sa, 0) [definition of blend()] | |
| 161 = blend(f*Sca, Dca, f*Sa, Da) [Da=0] | |
| 162 | |
| 163 f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 164 = Dca [f=0] | |
| 165 = blend(0, Dca, 0, Da) [definition of blend()] | |
| 166 = blend(f*Sca, Dca, f*Sa, Da) [f=0] | |
| 167 | |
| 168 == Alpha == | |
| 169 | |
| 170 We substitute X=Y=Z=1 and define a blend() function that calculates Da': | |
| 171 | |
| 172 blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa) | |
| 173 = Sa * Da + Sa - Sa * Da + Da - Da * Sa | |
| 174 = Sa + Da - Sa * Da | |
| 175 | |
| 176 We use the same model for coverage modulation as we did with color: | |
| 177 | |
| 178 Da'' = f * blend(Sa, Da) + (1-f) * Da | |
| 179 | |
| 180 And show that canTweakAlphaForCoverage() is true by proving the following | |
| 181 relationship: | |
| 182 | |
| 183 blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da | |
| 184 | |
| 185 | |
| 186 f * blend(Sa, Da) + (1-f) * Da | |
| 187 = f * (Sa + Da - Sa * Da) + (1-f) * Da | |
| 188 = f*Sa + f*Da - f*Sa * Da + Da - f*Da | |
| 189 = f*Sa - f*Sa * Da + Da | |
| 190 = f*Sa + Da - f*Sa * Da | |
| 191 = blend(f*Sa, Da) | |
| 192 */ | |
| 193 | |
| 194 return true; | |
| 195 } | |
| 196 | |
| 197 bool GrAdvancedEquationXPFactory::supportsRGBCoverage(GrColor, uint32_t) const { | |
| 198 /* | |
| 199 We do coverage modulation by multiplying it into the src color before | |
| 200 blending. The GPU runs the blend equation *after* the fragment shader, so | |
| 201 it is not within our control to apply coverage at that point. This model | |
| 202 is mathematically correct, but it only works with scalar coverage. It's easy | |
| 203 to see why it won't work when coverage is unique per component: | |
| 204 | |
| 205 blend(fc*Sca, Dca, fa*Sa, Da) | |
| 206 = B((fc*Sca)/(fa*Sa), Dca/Da) * ... | |
| 207 != B(Sc, Dc) * ... | |
| 208 | |
| 209 The arguments for B() no longer reduce to (Sc, Dc). And when Sc == 0, the | |
| 210 arguments for B() work, but the equation still doesn't: | |
| 211 | |
| 212 fc * blend(0, Dca, Sa, Da) + (1-fc) * Dca | |
| 213 = ... | |
| 214 = B(0, Dca/Da) * fc*Sa * Da + fc*0 * (1-Da) + Dca * (1 - fc*Sa) | |
| 215 = blend(fc*0, Dca, fc*Sa, Da) | |
| 216 != blend(fc*0, Dca, fa*Sa, Da) | |
| 217 | |
| 218 (Note that this could work if we knew the dst was transparent black.) | |
| 219 */ | |
| 220 | |
| 221 return false; | |
|
Chris Dalton
2015/04/22 19:17:01
One thing I haven't done yet is a fallback for RGB
bsalomon
2015/04/24 16:22:22
Unfortunately, we don't know until later whether t
Chris Dalton
2015/04/24 18:45:01
Ok, then that isn't going to work :).
So consider
| |
| 222 } | |
| 223 | |
| 224 GrXferProcessor* GrAdvancedEquationXPFactory::onCreateXferProcessor( | |
| 225 const GrDrawTargetCaps& caps, | |
| 226 const GrProcOptInfo& col orPOI, | |
| 227 const GrProcOptInfo& cov eragePOI, | |
| 228 const GrDeviceCoordTextu re* dstCopy) const { | |
| 229 SkASSERT(!dstCopy || !dstCopy->texture()); | |
| 230 | |
| 231 if (!caps.advancedBlendEquationSupport()) { | |
| 232 return NULL; | |
| 233 } | |
| 234 if (coveragePOI.isFourChannelOutput()) { | |
| 235 // RGB coverage is not supported. (See supportsRGBCoverage()) | |
| 236 return NULL; | |
| 237 } | |
| 238 return AdvancedEquationXPBase::Create(!coveragePOI.isSolidWhite(), fEquation ); | |
| 239 } | |
| 240 | |
| 241 AdvancedEquationXPBase* AdvancedEquationXPBase::Create(bool hasCoverage, GrBlend Equation equation) { | |
| 242 if (hasCoverage) { | |
| 243 return SkNEW_ARGS(AdvancedEquationXP<true>, (equation)); | |
| 244 } else { | |
| 245 return SkNEW_ARGS(AdvancedEquationXP<false>, (equation)); | |
| 246 } | |
| 247 } | |
| 248 | |
| 249 bool AdvancedEquationXPBase::willNeedXferBarrier(const GrRenderTarget*, | |
| 250 const GrDrawTargetCaps& caps, | |
| 251 GrXferBarrierType* outBarrierTy pe) const { | |
| 252 if (GrDrawTargetCaps::kAdvancedCoherent_BlendEquationSupport != caps.blendEq uationSupport()) { | |
| 253 *outBarrierType = kBlend_GrXferBarrierType; | |
| 254 return true; | |
| 255 } | |
| 256 return false; | |
| 257 } | |
| 258 | |
| 259 void AdvancedEquationXPBase::onGetGLProcessorKey(const GrGLCaps&, GrProcessorKey Builder*) const { | |
| 260 // Our XP's don't emit variable fragment code. (HasCoverage is accounted for by the class ID.) | |
| 261 return; | |
| 262 } | |
| 263 | |
| 264 template</*HasCoverage = false*/> | |
| 265 GrXferProcessor::OptFlags AdvancedEquationXP<false>::getOptimizations(const GrPr ocOptInfo&, | |
| 266 const GrPr ocOptInfo&, | |
| 267 bool, GrCo lor*, | |
| 268 const GrDr awTargetCaps&) { | |
| 269 return kIgnoreCoverage_OptFlag; | |
| 270 } | |
| 271 | |
| 272 template</*HasCoverage = false*/> | |
| 273 GrGLXferProcessor* AdvancedEquationXP<false>::createGLInstance() const { | |
| 274 class GLAdvancedEquationXP : public GrGLXferProcessor { | |
| 275 private: | |
| 276 void onEmitCode(const EmitArgs& args) override { | |
| 277 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde r(); | |
| 278 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputC olor); | |
| 279 } | |
| 280 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) ov erride {} | |
| 281 }; | |
| 282 return SkNEW(GLAdvancedEquationXP); | |
| 283 } | |
| 284 | |
| 285 template</*HasCoverage = true*/> | |
| 286 GrXferProcessor::OptFlags AdvancedEquationXP<true>::getOptimizations(const GrPro cOptInfo&, | |
| 287 const GrPro cOptInfo&, | |
| 288 bool, GrCol or*, | |
| 289 const GrDra wTargetCaps&) { | |
| 290 return kNone_Opt; | |
| 291 } | |
| 292 | |
| 293 template</*HasCoverage = true*/> | |
| 294 GrGLXferProcessor* AdvancedEquationXP<true>::createGLInstance() const { | |
| 295 class GLAdvancedEquationXPWithCoverage : public GrGLXferProcessor { | |
| 296 private: | |
| 297 void onEmitCode(const EmitArgs& args) override { | |
| 298 // We do coverage modulation by multiplying it into the src color be fore blending. | |
| 299 // (See canTweakAlphaForCoverage()) | |
| 300 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde r(); | |
| 301 fsBuilder->codeAppendf("%s = %s * %s;", | |
| 302 args.fOutputPrimary, args.fInputColor, args.f InputCoverage); | |
| 303 } | |
| 304 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) ov erride {} | |
| 305 }; | |
| 306 return SkNEW(GLAdvancedEquationXPWithCoverage); | |
| 307 } | |
| 308 | |
| 309 void AdvancedEquationXPBase::onGetBlendInfo(BlendInfo* blendInfo) const { | |
| 310 SkASSERT(GrBlendEquationIsAdvanced(fEquation)); | |
| 311 blendInfo->fEquation = fEquation; | |
| 312 } | |
| 313 | |
| 314 | |
| 315 GR_DEFINE_XP_FACTORY_TEST(GrAdvancedEquationXPFactory); | |
| 316 | |
| 317 GrXPFactory* GrAdvancedEquationXPFactory::TestCreate(SkRandom* random, | |
| 318 GrContext* context, | |
| 319 const GrDrawTargetCaps& cap s, | |
| 320 GrTexture*[]) { | |
| 321 int mode = random->nextRangeU(SkXfermode::kLastCoeffMode, SkXfermode::kLastM ode); | |
| 322 if (SkXfermode::kLastCoeffMode == mode) { | |
| 323 mode = SkXfermode::kScreen_Mode; | |
| 324 } | |
| 325 return GrAdvancedEquationXPFactory::Create(static_cast<SkXfermode::Mode>(mod e)); | |
| 326 } | |
| OLD | NEW |