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