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 #include "GrGLSLBlend.h" 8 #include "glsl/GrGLSLFragmentShaderBuilder.h" 9 10 ////////////////////////////////////////////////////////////////////////////// 11 // Advanced (non-coeff) blend helpers 12 ////////////////////////////////////////////////////////////////////////////// 13 14 static void hard_light(GrGLSLFragmentBuilder* fsBuilder, 15 const char* final, 16 const char* src, 17 const char* dst) { 18 static const char kComponents[] = { 'r', 'g', 'b' }; 19 for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) { 20 char component = kComponents[i]; 21 fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src); 22 fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;", 23 final, component, src, component, dst, component); 24 fsBuilder->codeAppend("} else {"); 25 fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);", 26 final, component, src, dst, dst, dst, component, src, src, 27 component); 28 fsBuilder->codeAppend("}"); 29 } 30 fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);", 31 final, src, dst, dst, src); 32 } 33 34 // Does one component of color-dodge 35 static void color_dodge_component(GrGLSLFragmentBuilder* fsBuilder, 36 const char* final, 37 const char* src, 38 const char* dst, 39 const char component) { 40 fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component); 41 fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);", 42 final, component, src, component, dst); 43 fsBuilder->codeAppend("} else {"); 44 fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component); 45 fsBuilder->codeAppend("if (0.0 == d) {"); 46 fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", 47 final, component, src, dst, src, component, dst, dst, component, 48 src); 49 fsBuilder->codeAppend("} else {"); 50 fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);", 51 dst, dst, component, src); 52 fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", 53 final, component, src, src, component, dst, dst, component, src); 54 fsBuilder->codeAppend("}"); 55 fsBuilder->codeAppend("}"); 56 } 57 58 // Does one component of color-burn 59 static void color_burn_component(GrGLSLFragmentBuilder* fsBuilder, 60 const char* final, 61 const char* src, 62 const char* dst, 63 const char component) { 64 fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component); 65 fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", 66 final, component, src, dst, src, component, dst, dst, component, 67 src); 68 fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component); 69 fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);", 70 final, component, dst, component, src); 71 fsBuilder->codeAppend("} else {"); 72 fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);", 73 dst, dst, dst, component, src, src, component); 74 fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", 75 final, component, src, src, component, dst, dst, component, src); 76 fsBuilder->codeAppend("}"); 77 } 78 79 // Does one component of soft-light. Caller should have already checked that dst alpha > 0. 80 static void soft_light_component_pos_dst_alpha(GrGLSLFragmentBuilder* fsBuilder, 81 const char* final, 82 const char* src, 83 const char* dst, 84 const char component) { 85 // if (2S < Sa) 86 fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src); 87 // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1) 88 fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +" 89 "(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);", 90 final, component, dst, component, dst, component, src, src, 91 component, dst, dst, src, component, dst, component, src, src, 92 component); 93 // else if (4D < Da) 94 fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {", 95 dst, component, dst); 96 fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;", 97 dst, component, dst, component); 98 fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component); 99 fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst); 100 fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst); 101 // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2 102 fsBuilder->codeAppendf("%s.%c =" 103 "(DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +" 104 " 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c) -" 105 " DaCub*%s.%c) / DaSqd;", 106 final, component, src, component, dst, component, 107 src, src, component, dst, src, src, component, src, src, 108 component, src, component); 109 fsBuilder->codeAppendf("} else {"); 110 // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S 111 fsBuilder->codeAppendf("%s.%c = %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c -" 112 " sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c;", 113 final, component, dst, component, src, src, component, src, component, 114 dst, dst, component, src, src, component, dst, src, component); 115 fsBuilder->codeAppendf("}"); 116 } 117 118 // Adds a function that takes two colors and an alpha as input. It produces a color with the 119 // hue and saturation of the first color, the luminosity of the second color, and the input 120 // alpha. It has this signature: 121 // vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor). 122 static void add_lum_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setLumFunction) { 123 // Emit a helper that gets the luminance of a color. 124 SkString getFunction; 125 GrGLSLShaderVar getLumArgs[] = { 126 GrGLSLShaderVar("color", kVec3f_GrSLType), 127 }; 128 SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);"); 129 fsBuilder->emitFunction(kFloat_GrSLType, 130 "luminance", 131 SK_ARRAY_COUNT(getLumArgs), getLumArgs, 132 getLumBody.c_str(), 133 &getFunction); 134 135 // Emit the set luminance function. 136 GrGLSLShaderVar setLumArgs[] = { 137 GrGLSLShaderVar("hueSat", kVec3f_GrSLType), 138 GrGLSLShaderVar("alpha", kFloat_GrSLType), 139 GrGLSLShaderVar("lumColor", kVec3f_GrSLType), 140 }; 141 SkString setLumBody; 142 setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str()); 143 setLumBody.append("vec3 outColor = hueSat + diff;"); 144 setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str()); 145 setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);" 146 "float maxComp = max(max(outColor.r, outColor.g), outColor.b);" 147 "if (minComp < 0.0 && outLum != minComp) {" 148 "outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /" 149 "(outLum - minComp);" 150 "}" 151 "if (maxComp > alpha && maxComp != outLum) {" 152 "outColor = outLum +" 153 "((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /" 154 "(maxComp - outLum);" 155 "}" 156 "return outColor;"); 157 fsBuilder->emitFunction(kVec3f_GrSLType, 158 "set_luminance", 159 SK_ARRAY_COUNT(setLumArgs), setLumArgs, 160 setLumBody.c_str(), 161 setLumFunction); 162 } 163 164 // Adds a function that creates a color with the hue and luminosity of one input color and 165 // the saturation of another color. It will have this signature: 166 // float set_saturation(vec3 hueLumColor, vec3 satColor) 167 static void add_sat_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setSatFunction) { 168 // Emit a helper that gets the saturation of a color 169 SkString getFunction; 170 GrGLSLShaderVar getSatArgs[] = { GrGLSLShaderVar("color", kVec3f_GrSLType) }; 171 SkString getSatBody; 172 getSatBody.printf("return max(max(color.r, color.g), color.b) - " 173 "min(min(color.r, color.g), color.b);"); 174 fsBuilder->emitFunction(kFloat_GrSLType, 175 "saturation", 176 SK_ARRAY_COUNT(getSatArgs), getSatArgs, 177 getSatBody.c_str(), 178 &getFunction); 179 180 // Emit a helper that sets the saturation given sorted input channels. This used 181 // to use inout params for min, mid, and max components but that seems to cause 182 // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the 183 // adjusted min, mid, and max inputs, respectively. 184 SkString helperFunction; 185 GrGLSLShaderVar helperArgs[] = { 186 GrGLSLShaderVar("minComp", kFloat_GrSLType), 187 GrGLSLShaderVar("midComp", kFloat_GrSLType), 188 GrGLSLShaderVar("maxComp", kFloat_GrSLType), 189 GrGLSLShaderVar("sat", kFloat_GrSLType), 190 }; 191 static const char kHelperBody[] = "if (minComp < maxComp) {" 192 "vec3 result;" 193 "result.r = 0.0;" 194 "result.g = sat * (midComp - minComp) / (maxComp - minComp);" 195 "result.b = sat;" 196 "return result;" 197 "} else {" 198 "return vec3(0, 0, 0);" 199 "}"; 200 fsBuilder->emitFunction(kVec3f_GrSLType, 201 "set_saturation_helper", 202 SK_ARRAY_COUNT(helperArgs), helperArgs, 203 kHelperBody, 204 &helperFunction); 205 206 GrGLSLShaderVar setSatArgs[] = { 207 GrGLSLShaderVar("hueLumColor", kVec3f_GrSLType), 208 GrGLSLShaderVar("satColor", kVec3f_GrSLType), 209 }; 210 const char* helpFunc = helperFunction.c_str(); 211 SkString setSatBody; 212 setSatBody.appendf("float sat = %s(satColor);" 213 "if (hueLumColor.r <= hueLumColor.g) {" 214 "if (hueLumColor.g <= hueLumColor.b) {" 215 "hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);" 216 "} else if (hueLumColor.r <= hueLumColor.b) {" 217 "hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);" 218 "} else {" 219 "hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);" 220 "}" 221 "} else if (hueLumColor.r <= hueLumColor.b) {" 222 "hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);" 223 "} else if (hueLumColor.g <= hueLumColor.b) {" 224 "hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);" 225 "} else {" 226 "hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);" 227 "}" 228 "return hueLumColor;", 229 getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc, 230 helpFunc, helpFunc); 231 fsBuilder->emitFunction(kVec3f_GrSLType, 232 "set_saturation", 233 SK_ARRAY_COUNT(setSatArgs), setSatArgs, 234 setSatBody.c_str(), 235 setSatFunction); 236 } 237 238 static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor, 239 const char* dstColor, const char* outputColor, 240 SkXfermode::Mode mode) { 241 SkASSERT(srcColor); 242 SkASSERT(dstColor); 243 SkASSERT(outputColor); 244 // These all perform src-over on the alpha channel. 245 fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;", 246 outputColor, srcColor, srcColor, dstColor); 247 248 switch (mode) { 249 case SkXfermode::kOverlay_Mode: 250 // Overlay is Hard-Light with the src and dst reversed 251 hard_light(fsBuilder, outputColor, dstColor, srcColor); 252 break; 253 case SkXfermode::kDarken_Mode: 254 fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, " 255 "(1.0 - %s.a) * %s.rgb + %s.rgb);", 256 outputColor, 257 srcColor, dstColor, srcColor, 258 dstColor, srcColor, dstColor); 259 break; 260 case SkXfermode::kLighten_Mode: 261 fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, " 262 "(1.0 - %s.a) * %s.rgb + %s.rgb);", 263 outputColor, 264 srcColor, dstColor, srcColor, 265 dstColor, srcColor, dstColor); 266 break; 267 case SkXfermode::kColorDodge_Mode: 268 color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'r'); 269 color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'g'); 270 color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'b'); 271 break; 272 case SkXfermode::kColorBurn_Mode: 273 color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'r'); 274 color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'g'); 275 color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'b'); 276 break; 277 case SkXfermode::kHardLight_Mode: 278 hard_light(fsBuilder, outputColor, srcColor, dstColor); 279 break; 280 case SkXfermode::kSoftLight_Mode: 281 fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor); 282 fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, srcColor); 283 fsBuilder->codeAppendf("} else {"); 284 soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'r'); 285 soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'g'); 286 soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'b'); 287 fsBuilder->codeAppendf("}"); 288 break; 289 case SkXfermode::kDifference_Mode: 290 fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -" 291 "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);", 292 outputColor, srcColor, dstColor, srcColor, dstColor, 293 dstColor, srcColor); 294 break; 295 case SkXfermode::kExclusion_Mode: 296 fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - " 297 "2.0 * %s.rgb * %s.rgb;", 298 outputColor, dstColor, srcColor, dstColor, srcColor); 299 break; 300 case SkXfermode::kMultiply_Mode: 301 fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + " 302 "(1.0 - %s.a) * %s.rgb + " 303 "%s.rgb * %s.rgb;", 304 outputColor, srcColor, dstColor, dstColor, srcColor, 305 srcColor, dstColor); 306 break; 307 case SkXfermode::kHue_Mode: { 308 // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S 309 SkString setSat, setLum; 310 add_sat_function(fsBuilder, &setSat); 311 add_lum_function(fsBuilder, &setLum); 312 fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;", 313 dstColor, srcColor); 314 fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb)," 315 "dstSrcAlpha.a, dstSrcAlpha.rgb);", 316 outputColor, setLum.c_str(), setSat.c_str(), srcColor, 317 dstColor); 318 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", 319 outputColor, srcColor, dstColor, dstColor, srcColor); 320 break; 321 } 322 case SkXfermode::kSaturation_Mode: { 323 // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S 324 SkString setSat, setLum; 325 add_sat_function(fsBuilder, &setSat); 326 add_lum_function(fsBuilder, &setLum); 327 fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;", 328 dstColor, srcColor); 329 fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a)," 330 "dstSrcAlpha.a, dstSrcAlpha.rgb);", 331 outputColor, setLum.c_str(), setSat.c_str(), srcColor, 332 dstColor); 333 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", 334 outputColor, srcColor, dstColor, dstColor, srcColor); 335 break; 336 } 337 case SkXfermode::kColor_Mode: { 338 // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S 339 SkString setLum; 340 add_lum_function(fsBuilder, &setLum); 341 fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;", 342 srcColor, dstColor); 343 fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);", 344 outputColor, setLum.c_str(), dstColor, srcColor); 345 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", 346 outputColor, srcColor, dstColor, dstColor, srcColor); 347 break; 348 } 349 case SkXfermode::kLuminosity_Mode: { 350 // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S 351 SkString setLum; 352 add_lum_function(fsBuilder, &setLum); 353 fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;", 354 srcColor, dstColor); 355 fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);", 356 outputColor, setLum.c_str(), dstColor, srcColor); 357 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", 358 outputColor, srcColor, dstColor, dstColor, srcColor); 359 break; 360 } 361 default: 362 SkFAIL("Unknown Custom Xfer mode."); 363 break; 364 } 365 } 366 367 ////////////////////////////////////////////////////////////////////////////// 368 // Porter-Duff blend helper 369 ////////////////////////////////////////////////////////////////////////////// 370 371 static bool append_porterduff_term(GrGLSLFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff, 372 const char* colorName, const char* srcColorName, 373 const char* dstColorName, bool hasPrevious) { 374 if (SkXfermode::kZero_Coeff == coeff) { 375 return hasPrevious; 376 } else { 377 if (hasPrevious) { 378 fsBuilder->codeAppend(" + "); 379 } 380 fsBuilder->codeAppendf("%s", colorName); 381 switch (coeff) { 382 case SkXfermode::kOne_Coeff: 383 break; 384 case SkXfermode::kSC_Coeff: 385 fsBuilder->codeAppendf(" * %s", srcColorName); 386 break; 387 case SkXfermode::kISC_Coeff: 388 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); 389 break; 390 case SkXfermode::kDC_Coeff: 391 fsBuilder->codeAppendf(" * %s", dstColorName); 392 break; 393 case SkXfermode::kIDC_Coeff: 394 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); 395 break; 396 case SkXfermode::kSA_Coeff: 397 fsBuilder->codeAppendf(" * %s.a", srcColorName); 398 break; 399 case SkXfermode::kISA_Coeff: 400 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); 401 break; 402 case SkXfermode::kDA_Coeff: 403 fsBuilder->codeAppendf(" * %s.a", dstColorName); 404 break; 405 case SkXfermode::kIDA_Coeff: 406 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName); 407 break; 408 default: 409 SkFAIL("Unsupported Blend Coeff"); 410 } 411 return true; 412 } 413 } 414 415 ////////////////////////////////////////////////////////////////////////////// 416 417 void GrGLSLBlend::AppendMode(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor, 418 const char* dstColor, const char* outColor, 419 SkXfermode::Mode mode) { 420 421 SkXfermode::Coeff srcCoeff, dstCoeff; 422 if (SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff)) { 423 fsBuilder->codeAppendf("%s = ", outColor); 424 // append src blend 425 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor, 426 false); 427 // append dst blend 428 if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) { 429 fsBuilder->codeAppend("vec4(0, 0, 0, 0)"); 430 } 431 fsBuilder->codeAppend(";"); 432 } else { 433 emit_advanced_xfermode_code(fsBuilder, srcColor, dstColor, outColor, mode); 434 } 435 } 436 437 void GrGLSLBlend::AppendRegionOp(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor, 438 const char* dstColor, const char* outColor, 439 SkRegion::Op regionOp) { 440 SkXfermode::Coeff srcCoeff, dstCoeff; 441 switch (regionOp) { 442 case SkRegion::kReplace_Op: 443 srcCoeff = SkXfermode::kOne_Coeff; 444 dstCoeff = SkXfermode::kZero_Coeff; 445 break; 446 case SkRegion::kIntersect_Op: 447 srcCoeff = SkXfermode::kDC_Coeff; 448 dstCoeff = SkXfermode::kZero_Coeff; 449 break; 450 case SkRegion::kUnion_Op: 451 srcCoeff = SkXfermode::kOne_Coeff; 452 dstCoeff = SkXfermode::kISC_Coeff; 453 break; 454 case SkRegion::kXOR_Op: 455 srcCoeff = SkXfermode::kIDC_Coeff; 456 dstCoeff = SkXfermode::kISC_Coeff; 457 break; 458 case SkRegion::kDifference_Op: 459 srcCoeff = SkXfermode::kZero_Coeff; 460 dstCoeff = SkXfermode::kISC_Coeff; 461 break; 462 case SkRegion::kReverseDifference_Op: 463 srcCoeff = SkXfermode::kIDC_Coeff; 464 dstCoeff = SkXfermode::kZero_Coeff; 465 break; 466 default: 467 SkFAIL("Unsupported Op"); 468 // We should never get here but to make compiler happy 469 srcCoeff = SkXfermode::kZero_Coeff; 470 dstCoeff = SkXfermode::kZero_Coeff; 471 } 472 fsBuilder->codeAppendf("%s = ", outColor); 473 // append src blend 474 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor, 475 false); 476 // append dst blend 477 if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) { 478 fsBuilder->codeAppend("vec4(0, 0, 0, 0)"); 479 } 480 fsBuilder->codeAppend(";"); 481 } 482 483