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/GrAdvancedEquationXPFactory.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 bool GrAdvancedEquationXPFactory::IsSupported(const GrContext* context, SkXfermo de::Mode mode) { | |
| 17 if (!context->getGpu()->caps()->advancedBlendEquationSupport()) { | |
| 18 return false; | |
| 19 } | |
| 20 if (mode > SkXfermode::kLastMode) { | |
| 21 return false; | |
| 22 } | |
| 23 return mode == SkXfermode::kScreen_Mode || mode > SkXfermode::kLastCoeffMode ; | |
| 24 } | |
| 25 | |
| 26 template<GrBlendEquation Equation> GrXPFactory* GrAdvancedEquationXPFactory::Tak eFactoryRef() { | |
| 27 GR_STATIC_ASSERT(GrBlendEquationIsAdvanced(Equation)); | |
| 28 static GrAdvancedEquationXPFactory* factory; | |
| 29 if (!factory) { | |
| 30 factory = SkNEW_ARGS(GrAdvancedEquationXPFactory, (Equation)); | |
| 31 } | |
| 32 return SkRef(factory); | |
| 33 } | |
| 34 | |
| 35 GrXPFactory* GrAdvancedEquationXPFactory::Create(const GrContext* context, SkXfe rmode::Mode mode) { | |
| 36 if (!context->getGpu()->caps()->advancedBlendEquationSupport()) { | |
| 37 return NULL; | |
| 38 } | |
| 39 | |
| 40 switch (mode) { | |
| 41 default: break; | |
| 42 case SkXfermode::kScreen_Mode: return TakeFactoryRef<kScreen_GrBlendEqua tion>(); | |
| 43 case SkXfermode::kOverlay_Mode: return TakeFactoryRef<kOverlay_GrBlendEq uation>(); | |
| 44 case SkXfermode::kDarken_Mode: return TakeFactoryRef<kDarken_GrBlendEqua tion>(); | |
| 45 case SkXfermode::kLighten_Mode: return TakeFactoryRef<kLighten_GrBlendEq uation>(); | |
| 46 case SkXfermode::kColorDodge_Mode: return TakeFactoryRef<kColorDodge_GrB lendEquation>(); | |
| 47 case SkXfermode::kColorBurn_Mode: return TakeFactoryRef<kColorBurn_GrBle ndEquation>(); | |
| 48 case SkXfermode::kHardLight_Mode: return TakeFactoryRef<kHardLight_GrBle ndEquation>(); | |
| 49 case SkXfermode::kSoftLight_Mode: return TakeFactoryRef<kSoftLight_GrBle ndEquation>(); | |
| 50 case SkXfermode::kDifference_Mode: return TakeFactoryRef<kDifference_GrB lendEquation>(); | |
| 51 case SkXfermode::kExclusion_Mode: return TakeFactoryRef<kExclusion_GrBle ndEquation>(); | |
| 52 case SkXfermode::kMultiply_Mode: return TakeFactoryRef<kMultiply_GrBlend Equation>(); | |
| 53 case SkXfermode::kHue_Mode: return TakeFactoryRef<kHSLHue_GrBlendEquatio n>(); | |
| 54 case SkXfermode::kSaturation_Mode: return TakeFactoryRef<kHSLSaturation_ GrBlendEquation>(); | |
| 55 case SkXfermode::kColor_Mode: return TakeFactoryRef<kHSLColor_GrBlendEqu ation>(); | |
| 56 case SkXfermode::kLuminosity_Mode: return TakeFactoryRef<kHSLLuminosity_ GrBlendEquation>(); | |
| 57 } | |
| 58 | |
| 59 return NULL; | |
| 60 } | |
| 61 | |
| 62 bool GrAdvancedEquationXPFactory::canTweakAlphaForCoverage() const { | |
| 63 /* | |
| 64 The general SVG blend equation is defined in the spec as follows: | |
| 65 | |
| 66 Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa) | |
| 67 Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa) | |
| 68 | |
| 69 (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha, | |
| 70 and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied | |
| 71 RGB colors.) | |
| 72 | |
| 73 For every "advanced" blend mode, X=Y=Z=1 and this equation reduces to the | |
| 74 PDF blend equation. | |
| 75 | |
| 76 It can be shown that when X=Y=Z=1, canTweakAlphaForCoverage() is true. | |
|
Mark Kilgard
2015/04/03 18:30:03
great to see this analysis
| |
| 77 | |
| 78 | |
| 79 == Color == | |
| 80 | |
| 81 We substitute Y=Z=1 and define a blend() function that calculates Dca' in | |
| 82 terms of premultiplied alpha only: | |
| 83 | |
| 84 blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0, | |
| 85 Sca : if Da == 0, | |
| 86 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dc a * (1-Sa) : if Sa,Da != 0} | |
| 87 | |
| 88 And for coverage modulation, Skia uses a post blend src-over model: | |
| 89 | |
| 90 Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 91 | |
| 92 (Where f is the fractional coverage.) | |
| 93 | |
| 94 Next we show that canTweakAlphaForCoverage() is true by proving the | |
| 95 following relationship: | |
| 96 | |
| 97 blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 98 | |
| 99 Corner cases (Sa=0, Da=0, and f=0): | |
| 100 | |
| 101 Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 102 = f * Dca + (1-f) * Dca [Sa=0, definition of blend()] | |
| 103 = Dca | |
| 104 = blend(0, Dca, 0, Da) [definition of blend()] | |
| 105 = blend(f*Sca, Dca, f*Sa, Da) [Sa=0] | |
| 106 | |
| 107 Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 108 = f * Sca + (1-f) * Dca [Da=0, definition of blend()] | |
| 109 = f * Sca [Da=0] | |
| 110 = blend(f*Sca, 0, f*Sa, 0) [definition of blend()] | |
| 111 = blend(f*Sca, Dca, f*Sa, Da) [Da=0] | |
| 112 | |
| 113 f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 114 = Dca [f=0] | |
| 115 = blend(0, Dca, 0, Da) [definition of blend()] | |
| 116 = blend(f*Sca, Dca, f*Sa, Da) [f=0] | |
| 117 | |
| 118 General case (f,Sa,Da != 0): | |
| 119 | |
| 120 f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca | |
| 121 = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f ) * Dca [Sa,Da != 0, definition of blend()] | |
| 122 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca | |
| 123 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * S a + Dca - f*Dca | |
| 124 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca | |
| 125 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca | |
| 126 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) | |
| 127 = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0] | |
| 128 = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()] | |
|
Mark Kilgard
2015/04/03 18:30:04
great analysis
I think you should motivate the "C
Chris Dalton
2015/04/17 08:37:18
Done.
| |
| 129 | |
| 130 | |
| 131 == Alpha == | |
| 132 | |
| 133 We substitute X=Y=Z=1 and define a blend() function that calculates Da': | |
| 134 | |
| 135 blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa) | |
| 136 = Sa * Da + Sa - Sa * Da + Da - Da * Sa | |
| 137 = Sa + Da - Sa * Da | |
| 138 | |
| 139 We use the same model for coverage modulation as we did with color: | |
| 140 | |
| 141 Da'' = f * blend(Sa, Da) + (1-f) * Da | |
| 142 | |
| 143 And show that canTweakAlphaForCoverage() is true by proving the following | |
| 144 relationship: | |
| 145 | |
| 146 blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da | |
| 147 | |
| 148 | |
| 149 f * blend(Sa, Da) + (1-f) * Da | |
| 150 = f * (Sa + Da - Sa * Da) + (1-f) * Da | |
| 151 = f*Sa + f*Da - f*Sa * Da + Da - f*Da | |
| 152 = f*Sa - f*Sa * Da + Da | |
| 153 = f*Sa + Da - f*Sa * Da | |
| 154 = blend(f*Sa, Da) | |
| 155 */ | |
| 156 | |
| 157 return true; | |
| 158 } | |
| 159 | |
| 160 bool GrAdvancedEquationXPFactory::supportsRGBCoverage(GrColor knownColor, | |
| 161 uint32_t knownColorFlags) const { | |
| 162 /* | |
| 163 We do coverage modulation by multiplying it into the src color before | |
| 164 blending. The GPU runs the blend equation *after* the fragment shader, so | |
| 165 it is not within our control to apply coverage at that point. This model | |
| 166 is mathematically correct, but the proof lies in the following property: | |
| 167 | |
| 168 f*Sca / f*Sa == Sc | |
| 169 | |
| 170 (That is, the general case, f,Sa,Da != 0. See canTweakAlphaForCoverage().) | |
| 171 | |
| 172 But when coverage is unique per channel, this property no longer holds: | |
|
Mark Kilgard
2015/04/03 18:30:03
"when coverage is unique per channel" ??
huh? Wh
Chris Dalton
2015/04/17 08:37:19
Yeah, "RGB coverage" in the context of GrXferProce
| |
| 173 | |
| 174 fc*Sca / fa*Sa == fc/fa * Sc != Sc [fc!=fa] | |
| 175 | |
| 176 The only time it is still true is when Sc == 0. | |
|
Chris Dalton
2015/03/31 10:51:49
This is most likely wrong. I'll update the comment
| |
| 177 | |
| 178 (It would also work out if we could know the dst color was trans black.) | |
|
Mark Kilgard
2015/04/03 18:30:03
I'm assume by "trans black" you mean transparent b
| |
| 179 */ | |
| 180 | |
| 181 return kRGB_GrColorComponentFlags == (knownColorFlags & kRGB_GrColorComponen tFlags) && | |
| 182 0 == (knownColor & ~(0xffu << GrColor_SHIFT_A)); // RGB=0 | |
|
Mark Kilgard
2015/04/03 18:30:03
Is there not some constant to use instead of 0xffu
Chris Dalton
2015/04/17 08:37:19
That code is completely gone now.
| |
| 183 } | |
| 184 | |
| 185 bool GrAdvancedEquationXPFactory::willBlendCoherently(const GrDrawTargetCaps& ca ps) const { | |
| 186 return GrDrawTargetCaps::kAdvancedCoherent_BlendEquationSupport == caps.blen dEquationSupport(); | |
| 187 } | |
| 188 | |
| 189 GrXferProcessor* GrAdvancedEquationXPFactory::onCreateXferProcessor( | |
| 190 const GrDrawTargetCaps& caps, | |
| 191 const GrProcOptInfo& col orPOI, | |
| 192 const GrProcOptInfo& cov eragePOI, | |
|
Mark Kilgard
2015/04/03 18:30:03
wish I knew what "XP" stands for
can I assume POI
Chris Dalton
2015/04/17 08:37:19
XP = Xfer Processor = An object that controls the
| |
| 193 const GrDeviceCoordTextu re* dstCopy) const { | |
| 194 SkASSERT(caps.advancedBlendEquationSupport()); | |
| 195 SkASSERT(!dstCopy || !dstCopy->texture()); | |
| 196 | |
| 197 if (coveragePOI.isFourChannelOutput() && !this->supportsRGBCoverage(colorPOI .color(), | |
| 198 colorPOI .validFlags())) { | |
| 199 return NULL; | |
| 200 } | |
| 201 if (!coveragePOI.isSolidWhite()) { | |
| 202 return SkRef(&fXferProcessorWithCoverage); | |
| 203 } | |
| 204 return SkRef(&fXferProcessor); | |
| 205 } | |
| 206 | |
| 207 void GrAdvancedEquationXPFactory::XferProcessorBase::onGetGLProcessorKey(const G rGLCaps&, | |
| 208 GrProcessor KeyBuilder*) const { | |
| 209 // Our XP's don't emit variable fragment code. (HasCoverage is accounted for by the class ID.) | |
| 210 return; | |
| 211 } | |
| 212 | |
| 213 template</*HasCoverage = true*/> | |
| 214 GrGLXferProcessor* GrAdvancedEquationXPFactory::XferProcessor<true>::createGLIns tance() const { | |
| 215 class GLXferProcessorWithCoverage : public GrGLXferProcessor { | |
| 216 private: | |
| 217 void onEmitCode(const EmitArgs& args) override { | |
| 218 // We do coverage modulation by multiplying it into the src color be fore blending. | |
| 219 // (See canTweakAlphaForCoverage()) | |
| 220 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde r(); | |
| 221 fsBuilder->codeAppendf("%s = %s * %s;", | |
| 222 args.fOutputPrimary, args.fInputColor, args.f InputCoverage); | |
| 223 } | |
| 224 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) ov erride {} | |
| 225 }; | |
| 226 return SkNEW(GLXferProcessorWithCoverage); | |
| 227 } | |
| 228 | |
| 229 template</*HasCoverage = false*/> | |
| 230 GrGLXferProcessor* GrAdvancedEquationXPFactory::XferProcessor<false>::createGLIn stance() const { | |
| 231 class GLXferProcessor : public GrGLXferProcessor { | |
| 232 private: | |
| 233 void onEmitCode(const EmitArgs& args) override { | |
| 234 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde r(); | |
| 235 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputC olor); | |
| 236 } | |
| 237 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) ov erride {} | |
| 238 }; | |
| 239 return SkNEW(GLXferProcessor); | |
| 240 } | |
| 241 | |
| 242 void GrAdvancedEquationXPFactory::XferProcessorBase::onGetBlendInfo(BlendInfo* b lendInfo) const { | |
| 243 SkASSERT(GrBlendEquationIsAdvanced(fEquation)); | |
| 244 blendInfo->fEquation = fEquation; | |
| 245 } | |
| 246 | |
| 247 | |
| 248 GR_DEFINE_XP_FACTORY_TEST(GrAdvancedEquationXPFactory); | |
| 249 | |
| 250 GrXPFactory* GrAdvancedEquationXPFactory::TestCreate(SkRandom* random, | |
| 251 GrContext* context, | |
| 252 const GrDrawTargetCaps& cap s, | |
| 253 GrTexture*[]) { | |
| 254 int mode = random->nextRangeU(SkXfermode::kLastCoeffMode, SkXfermode::kLastM ode); | |
| 255 if (mode == SkXfermode::kLastCoeffMode) { | |
| 256 mode = SkXfermode::kScreen_Mode; | |
| 257 } | |
| 258 return GrAdvancedEquationXPFactory::Create(context, static_cast<SkXfermode:: Mode>(mode)); | |
| 259 } | |
| OLD | NEW |