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/GrCustomXfermode.h" 9#include "effects/GrCustomXfermodePriv.h" 10 11#include "GrCoordTransform.h" 12#include "GrContext.h" 13#include "GrFragmentProcessor.h" 14#include "GrInvariantOutput.h" 15#include "GrProcessor.h" 16#include "GrTexture.h" 17#include "GrTextureAccess.h" 18#include "SkXfermode.h" 19#include "gl/GrGLCaps.h" 20#include "gl/GrGLGpu.h" 21#include "gl/GrGLProcessor.h" 22#include "gl/GrGLProgramDataManager.h" 23#include "gl/builders/GrGLProgramBuilder.h" 24 25bool GrCustomXfermode::IsSupportedMode(SkXfermode::Mode mode) { 26 return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode; 27} 28 29/////////////////////////////////////////////////////////////////////////////// 30// Static helpers 31/////////////////////////////////////////////////////////////////////////////// 32 33static GrBlendEquation hw_blend_equation(SkXfermode::Mode mode) { 34 enum { kOffset = kOverlay_GrBlendEquation - SkXfermode::kOverlay_Mode }; 35 return static_cast<GrBlendEquation>(mode + kOffset); 36 37 GR_STATIC_ASSERT(kOverlay_GrBlendEquation == SkXfermode::kOverlay_Mode + kOffset); 38 GR_STATIC_ASSERT(kDarken_GrBlendEquation == SkXfermode::kDarken_Mode + kOffset); 39 GR_STATIC_ASSERT(kLighten_GrBlendEquation == SkXfermode::kLighten_Mode + kOffset); 40 GR_STATIC_ASSERT(kColorDodge_GrBlendEquation == SkXfermode::kColorDodge_Mode + kOffset); 41 GR_STATIC_ASSERT(kColorBurn_GrBlendEquation == SkXfermode::kColorBurn_Mode + kOffset); 42 GR_STATIC_ASSERT(kHardLight_GrBlendEquation == SkXfermode::kHardLight_Mode + kOffset); 43 GR_STATIC_ASSERT(kSoftLight_GrBlendEquation == SkXfermode::kSoftLight_Mode + kOffset); 44 GR_STATIC_ASSERT(kDifference_GrBlendEquation == SkXfermode::kDifference_Mode + kOffset); 45 GR_STATIC_ASSERT(kExclusion_GrBlendEquation == SkXfermode::kExclusion_Mode + kOffset); 46 GR_STATIC_ASSERT(kMultiply_GrBlendEquation == SkXfermode::kMultiply_Mode + kOffset); 47 GR_STATIC_ASSERT(kHSLHue_GrBlendEquation == SkXfermode::kHue_Mode + kOffset); 48 GR_STATIC_ASSERT(kHSLSaturation_GrBlendEquation == SkXfermode::kSaturation_Mode + kOffset); 49 GR_STATIC_ASSERT(kHSLColor_GrBlendEquation == SkXfermode::kColor_Mode + kOffset); 50 GR_STATIC_ASSERT(kHSLLuminosity_GrBlendEquation == SkXfermode::kLuminosity_Mode + kOffset); 51 GR_STATIC_ASSERT(kGrBlendEquationCnt == SkXfermode::kLastMode + 1 + kOffset); 52} 53 54static void hard_light(GrGLFragmentBuilder* fsBuilder, 55 const char* final, 56 const char* src, 57 const char* dst) { 58 static const char kComponents[] = {'r', 'g', 'b'}; 59 for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) { 60 char component = kComponents[i]; 61 fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src); 62 fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;", 63 final, component, src, component, dst, component); 64 fsBuilder->codeAppend("} else {"); 65 fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);", 66 final, component, src, dst, dst, dst, component, src, src, 67 component); 68 fsBuilder->codeAppend("}"); 69 } 70 fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);", 71 final, src, dst, dst, src); 72} 73 74// Does one component of color-dodge 75static void color_dodge_component(GrGLFragmentBuilder* fsBuilder, 76 const char* final, 77 const char* src, 78 const char* dst, 79 const char component) { 80 fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component); 81 fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);", 82 final, component, src, component, dst); 83 fsBuilder->codeAppend("} else {"); 84 fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component); 85 fsBuilder->codeAppend("if (0.0 == d) {"); 86 fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", 87 final, component, src, dst, src, component, dst, dst, component, 88 src); 89 fsBuilder->codeAppend("} else {"); 90 fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);", 91 dst, dst, component, src); 92 fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", 93 final, component, src, src, component, dst, dst, component, src); 94 fsBuilder->codeAppend("}"); 95 fsBuilder->codeAppend("}"); 96} 97 98// Does one component of color-burn 99static void color_burn_component(GrGLFragmentBuilder* fsBuilder, 100 const char* final, 101 const char* src, 102 const char* dst, 103 const char component) { 104 fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component); 105 fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", 106 final, component, src, dst, src, component, dst, dst, component, 107 src); 108 fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component); 109 fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);", 110 final, component, dst, component, src); 111 fsBuilder->codeAppend("} else {"); 112 fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);", 113 dst, dst, dst, component, src, src, component); 114 fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);", 115 final, component, src, src, component, dst, dst, component, src); 116 fsBuilder->codeAppend("}"); 117} 118 119// Does one component of soft-light. Caller should have already checked that dst alpha > 0. 120static void soft_light_component_pos_dst_alpha(GrGLFragmentBuilder* fsBuilder, 121 const char* final, 122 const char* src, 123 const char* dst, 124 const char component) { 125 // if (2S < Sa) 126 fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src); 127 // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1) 128 fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +" 129 "(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);", 130 final, component, dst, component, dst, component, src, src, 131 component, dst, dst, src, component, dst, component, src, src, 132 component); 133 // else if (4D < Da) 134 fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {", 135 dst, component, dst); 136 fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;", 137 dst, component, dst, component); 138 fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component); 139 fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst); 140 fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst); 141 // (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 142 fsBuilder->codeAppendf("%s.%c =" 143 "(-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +" 144 " 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c)) /" 145 "DaSqd;", 146 final, component, src, component, src, component, dst, component, 147 src, src, component, dst, src, src, component, src, src, 148 component); 149 fsBuilder->codeAppendf("} else {"); 150 // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S 151 fsBuilder->codeAppendf("%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c +" 152 "%s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c;", 153 final, component, dst, dst, component, src, src, component, dst, 154 src, component, dst, component, src, src, component, src, 155 component); 156 fsBuilder->codeAppendf("}"); 157} 158 159// Adds a function that takes two colors and an alpha as input. It produces a color with the 160// hue and saturation of the first color, the luminosity of the second color, and the input 161// alpha. It has this signature: 162// vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor). 163static void add_lum_function(GrGLFragmentBuilder* fsBuilder, SkString* setLumFunction) { 164 // Emit a helper that gets the luminance of a color. 165 SkString getFunction; 166 GrGLShaderVar getLumArgs[] = { 167 GrGLShaderVar("color", kVec3f_GrSLType), 168 }; 169 SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);"); 170 fsBuilder->emitFunction(kFloat_GrSLType, 171 "luminance", 172 SK_ARRAY_COUNT(getLumArgs), getLumArgs, 173 getLumBody.c_str(), 174 &getFunction); 175 176 // Emit the set luminance function. 177 GrGLShaderVar setLumArgs[] = { 178 GrGLShaderVar("hueSat", kVec3f_GrSLType), 179 GrGLShaderVar("alpha", kFloat_GrSLType), 180 GrGLShaderVar("lumColor", kVec3f_GrSLType), 181 }; 182 SkString setLumBody; 183 setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str()); 184 setLumBody.append("vec3 outColor = hueSat + diff;"); 185 setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str()); 186 setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);" 187 "float maxComp = max(max(outColor.r, outColor.g), outColor.b);" 188 "if (minComp < 0.0 && outLum != minComp) {" 189 "outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /" 190 "(outLum - minComp);" 191 "}" 192 "if (maxComp > alpha && maxComp != outLum) {" 193 "outColor = outLum +" 194 "((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /" 195 "(maxComp - outLum);" 196 "}" 197 "return outColor;"); 198 fsBuilder->emitFunction(kVec3f_GrSLType, 199 "set_luminance", 200 SK_ARRAY_COUNT(setLumArgs), setLumArgs, 201 setLumBody.c_str(), 202 setLumFunction); 203} 204 205// Adds a function that creates a color with the hue and luminosity of one input color and 206// the saturation of another color. It will have this signature: 207// float set_saturation(vec3 hueLumColor, vec3 satColor) 208static void add_sat_function(GrGLFragmentBuilder* fsBuilder, SkString* setSatFunction) { 209 // Emit a helper that gets the saturation of a color 210 SkString getFunction; 211 GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) }; 212 SkString getSatBody; 213 getSatBody.printf("return max(max(color.r, color.g), color.b) - " 214 "min(min(color.r, color.g), color.b);"); 215 fsBuilder->emitFunction(kFloat_GrSLType, 216 "saturation", 217 SK_ARRAY_COUNT(getSatArgs), getSatArgs, 218 getSatBody.c_str(), 219 &getFunction); 220 221 // Emit a helper that sets the saturation given sorted input channels. This used 222 // to use inout params for min, mid, and max components but that seems to cause 223 // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the 224 // adjusted min, mid, and max inputs, respectively. 225 SkString helperFunction; 226 GrGLShaderVar helperArgs[] = { 227 GrGLShaderVar("minComp", kFloat_GrSLType), 228 GrGLShaderVar("midComp", kFloat_GrSLType), 229 GrGLShaderVar("maxComp", kFloat_GrSLType), 230 GrGLShaderVar("sat", kFloat_GrSLType), 231 }; 232 static const char kHelperBody[] = "if (minComp < maxComp) {" 233 "vec3 result;" 234 "result.r = 0.0;" 235 "result.g = sat * (midComp - minComp) / (maxComp - minComp);" 236 "result.b = sat;" 237 "return result;" 238 "} else {" 239 "return vec3(0, 0, 0);" 240 "}"; 241 fsBuilder->emitFunction(kVec3f_GrSLType, 242 "set_saturation_helper", 243 SK_ARRAY_COUNT(helperArgs), helperArgs, 244 kHelperBody, 245 &helperFunction); 246 247 GrGLShaderVar setSatArgs[] = { 248 GrGLShaderVar("hueLumColor", kVec3f_GrSLType), 249 GrGLShaderVar("satColor", kVec3f_GrSLType), 250 }; 251 const char* helpFunc = helperFunction.c_str(); 252 SkString setSatBody; 253 setSatBody.appendf("float sat = %s(satColor);" 254 "if (hueLumColor.r <= hueLumColor.g) {" 255 "if (hueLumColor.g <= hueLumColor.b) {" 256 "hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);" 257 "} else if (hueLumColor.r <= hueLumColor.b) {" 258 "hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);" 259 "} else {" 260 "hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);" 261 "}" 262 "} else if (hueLumColor.r <= hueLumColor.b) {" 263 "hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);" 264 "} else if (hueLumColor.g <= hueLumColor.b) {" 265 "hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);" 266 "} else {" 267 "hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);" 268 "}" 269 "return hueLumColor;", 270 getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc, 271 helpFunc, helpFunc); 272 fsBuilder->emitFunction(kVec3f_GrSLType, 273 "set_saturation", 274 SK_ARRAY_COUNT(setSatArgs), setSatArgs, 275 setSatBody.c_str(), 276 setSatFunction); 277 278} 279 280static void emit_custom_xfermode_code(SkXfermode::Mode mode, 281 GrGLFragmentBuilder* fsBuilder, 282 const char* outputColor, 283 const char* inputColor, 284 const char* dstColor) { 285 // We don't try to optimize for this case at all 286 if (NULL == inputColor) { 287 fsBuilder->codeAppendf("const vec4 ones = vec4(1);"); 288 inputColor = "ones"; 289 } 290 fsBuilder->codeAppendf("// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode)); 291 292 // These all perform src-over on the alpha channel. 293 fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;", 294 outputColor, inputColor, inputColor, dstColor); 295 296 switch (mode) { 297 case SkXfermode::kOverlay_Mode: 298 // Overlay is Hard-Light with the src and dst reversed 299 hard_light(fsBuilder, outputColor, dstColor, inputColor); 300 break; 301 case SkXfermode::kDarken_Mode: 302 fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, " 303 "(1.0 - %s.a) * %s.rgb + %s.rgb);", 304 outputColor, 305 inputColor, dstColor, inputColor, 306 dstColor, inputColor, dstColor); 307 break; 308 case SkXfermode::kLighten_Mode: 309 fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, " 310 "(1.0 - %s.a) * %s.rgb + %s.rgb);", 311 outputColor, 312 inputColor, dstColor, inputColor, 313 dstColor, inputColor, dstColor); 314 break; 315 case SkXfermode::kColorDodge_Mode: 316 color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'r'); 317 color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'g'); 318 color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'b'); 319 break; 320 case SkXfermode::kColorBurn_Mode: 321 color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'r'); 322 color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'g'); 323 color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'b'); 324 break; 325 case SkXfermode::kHardLight_Mode: 326 hard_light(fsBuilder, outputColor, inputColor, dstColor); 327 break; 328 case SkXfermode::kSoftLight_Mode: 329 fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor); 330 fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, inputColor); 331 fsBuilder->codeAppendf("} else {"); 332 soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'r'); 333 soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'g'); 334 soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'b'); 335 fsBuilder->codeAppendf("}"); 336 break; 337 case SkXfermode::kDifference_Mode: 338 fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -" 339 "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);", 340 outputColor, inputColor, dstColor, inputColor, dstColor, 341 dstColor, inputColor); 342 break; 343 case SkXfermode::kExclusion_Mode: 344 fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - " 345 "2.0 * %s.rgb * %s.rgb;", 346 outputColor, dstColor, inputColor, dstColor, inputColor); 347 break; 348 case SkXfermode::kMultiply_Mode: 349 fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + " 350 "(1.0 - %s.a) * %s.rgb + " 351 "%s.rgb * %s.rgb;", 352 outputColor, inputColor, dstColor, dstColor, inputColor, 353 inputColor, dstColor); 354 break; 355 case SkXfermode::kHue_Mode: { 356 // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S 357 SkString setSat, setLum; 358 add_sat_function(fsBuilder, &setSat); 359 add_lum_function(fsBuilder, &setLum); 360 fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;", 361 dstColor, inputColor); 362 fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb)," 363 "dstSrcAlpha.a, dstSrcAlpha.rgb);", 364 outputColor, setLum.c_str(), setSat.c_str(), inputColor, 365 dstColor); 366 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", 367 outputColor, inputColor, dstColor, dstColor, inputColor); 368 break; 369 } 370 case SkXfermode::kSaturation_Mode: { 371 // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S 372 SkString setSat, setLum; 373 add_sat_function(fsBuilder, &setSat); 374 add_lum_function(fsBuilder, &setLum); 375 fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;", 376 dstColor, inputColor); 377 fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a)," 378 "dstSrcAlpha.a, dstSrcAlpha.rgb);", 379 outputColor, setLum.c_str(), setSat.c_str(), inputColor, 380 dstColor); 381 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", 382 outputColor, inputColor, dstColor, dstColor, inputColor); 383 break; 384 } 385 case SkXfermode::kColor_Mode: { 386 // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S 387 SkString setLum; 388 add_lum_function(fsBuilder, &setLum); 389 fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;", 390 inputColor, dstColor); 391 fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);", 392 outputColor, setLum.c_str(), dstColor, inputColor); 393 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", 394 outputColor, inputColor, dstColor, dstColor, inputColor); 395 break; 396 } 397 case SkXfermode::kLuminosity_Mode: { 398 // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S 399 SkString setLum; 400 add_lum_function(fsBuilder, &setLum); 401 fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;", 402 inputColor, dstColor); 403 fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);", 404 outputColor, setLum.c_str(), dstColor, inputColor); 405 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;", 406 outputColor, inputColor, dstColor, dstColor, inputColor); 407 break; 408 } 409 default: 410 SkFAIL("Unknown Custom Xfer mode."); 411 break; 412 } 413} 414 415/////////////////////////////////////////////////////////////////////////////// 416// Fragment Processor 417/////////////////////////////////////////////////////////////////////////////// 418 419GrFragmentProcessor* GrCustomXfermode::CreateFP(SkXfermode::Mode mode, GrTexture* background) { 420 if (!GrCustomXfermode::IsSupportedMode(mode)) { 421 return NULL; 422 } else { 423 return SkNEW_ARGS(GrCustomXferFP, (mode, background)); 424 } 425} 426 427/////////////////////////////////////////////////////////////////////////////// 428 429class GLCustomXferFP : public GrGLFragmentProcessor { 430public: 431 GLCustomXferFP(const GrFragmentProcessor&) {} 432 ~GLCustomXferFP() override {}; 433 434 void emitCode(GrGLFPBuilder* builder, 435 const GrFragmentProcessor& fp, 436 const char* outputColor, 437 const char* inputColor, 438 const TransformedCoordsArray& coords, 439 const TextureSamplerArray& samplers) override { 440 SkXfermode::Mode mode = fp.cast<GrCustomXferFP>().mode(); 441 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 442 const char* dstColor = "bgColor"; 443 fsBuilder->codeAppendf("vec4 %s = ", dstColor); 444 fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType()); 445 fsBuilder->codeAppendf(";"); 446 447 emit_custom_xfermode_code(mode, fsBuilder, outputColor, inputColor, dstColor); 448 } 449 450 void setData(const GrGLProgramDataManager&, const GrProcessor&) override {} 451 452 static void GenKey(const GrFragmentProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { 453 // The background may come from the dst or from a texture. 454 uint32_t key = proc.numTextures(); 455 SkASSERT(key <= 1); 456 key |= proc.cast<GrCustomXferFP>().mode() << 1; 457 b->add32(key); 458 } 459 460private: 461 typedef GrGLFragmentProcessor INHERITED; 462}; 463 464/////////////////////////////////////////////////////////////////////////////// 465 466GrCustomXferFP::GrCustomXferFP(SkXfermode::Mode mode, GrTexture* background) 467 : fMode(mode) { 468 this->initClassID<GrCustomXferFP>(); 469 470 SkASSERT(background); 471 fBackgroundTransform.reset(kLocal_GrCoordSet, background, 472 GrTextureParams::kNone_FilterMode); 473 this->addCoordTransform(&fBackgroundTransform); 474 fBackgroundAccess.reset(background); 475 this->addTextureAccess(&fBackgroundAccess); 476} 477 478void GrCustomXferFP::getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { 479 GLCustomXferFP::GenKey(*this, caps, b); 480} 481 482GrGLFragmentProcessor* GrCustomXferFP::createGLInstance() const { 483 return SkNEW_ARGS(GLCustomXferFP, (*this)); 484} 485 486bool GrCustomXferFP::onIsEqual(const GrFragmentProcessor& other) const { 487 const GrCustomXferFP& s = other.cast<GrCustomXferFP>(); 488 return fMode == s.fMode; 489} 490 491void GrCustomXferFP::onComputeInvariantOutput(GrInvariantOutput* inout) const { 492 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); 493} 494 495GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCustomXferFP); 496GrFragmentProcessor* GrCustomXferFP::TestCreate(SkRandom* rand, 497 GrContext*, 498 const GrDrawTargetCaps&, 499 GrTexture* textures[]) { 500 int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode); 501 502 return SkNEW_ARGS(GrCustomXferFP, (static_cast<SkXfermode::Mode>(mode), textures[0])); 503} 504 505/////////////////////////////////////////////////////////////////////////////// 506// Xfer Processor 507/////////////////////////////////////////////////////////////////////////////// 508 509class CustomXP : public GrXferProcessor { 510public: 511 static GrXferProcessor* Create(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy, 512 bool willReadDstColor) { 513 if (!GrCustomXfermode::IsSupportedMode(mode)) { 514 return NULL; 515 } else { 516 return SkNEW_ARGS(CustomXP, (mode, dstCopy, willReadDstColor)); 517 } 518 } 519 520 ~CustomXP() override {}; 521 522 const char* name() const override { return "Custom Xfermode"; } 523 524 GrGLXferProcessor* createGLInstance() const override; 525 526 bool hasSecondaryOutput() const override { return false; } 527 528 SkXfermode::Mode mode() const { return fMode; } 529 bool hasHWBlendEquation() const { return -1 != static_cast<int>(fHWBlendEquation); } 530 531 GrBlendEquation hwBlendEquation() const { 532 SkASSERT(this->hasHWBlendEquation()); 533 return fHWBlendEquation; 534 } 535 536private: 537 CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy, bool willReadDstColor); 538 539 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, 540 const GrProcOptInfo& coveragePOI, 541 bool doesStencilWrite, 542 GrColor* overrideColor, 543 const GrDrawTargetCaps& caps) override; 544 545 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; 546 547 bool onWillNeedXferBarrier(const GrRenderTarget* rt, 548 const GrDrawTargetCaps& caps, 549 GrXferBarrierType* outBarrierType) const override; 550 551 void onGetBlendInfo(BlendInfo*) const override; 552 553 bool onIsEqual(const GrXferProcessor& xpBase) const override; 554 555 SkXfermode::Mode fMode; 556 GrBlendEquation fHWBlendEquation; 557 558 typedef GrXferProcessor INHERITED; 559}; 560 561/////////////////////////////////////////////////////////////////////////////// 562 563GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) { 564 if (!GrCustomXfermode::IsSupportedMode(mode)) { 565 return NULL; 566 } else { 567 return SkNEW_ARGS(GrCustomXPFactory, (mode)); 568 } 569} 570 571/////////////////////////////////////////////////////////////////////////////// 572 573class GLCustomXP : public GrGLXferProcessor { 574public: 575 GLCustomXP(const GrXferProcessor&) {} 576 ~GLCustomXP() override {} 577 578 static void GenKey(const GrXferProcessor& p, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) { 579 const CustomXP& xp = p.cast<CustomXP>(); 580 uint32_t key = xp.numTextures(); 581 SkASSERT(key <= 1); 582 key |= xp.readsCoverage() << 1; 583 if (xp.hasHWBlendEquation()) { 584 SkASSERT(caps.advBlendEqInteraction() > 0); // 0 will mean !xp.hasHWBlendEquation(). 585 key |= caps.advBlendEqInteraction() << 2; 586 } 587 if (!xp.hasHWBlendEquation() || caps.mustEnableSpecificAdvBlendEqs()) { 588 GR_STATIC_ASSERT(GrGLSLCaps::kLast_AdvBlendEqInteraction < 4); 589 key |= xp.mode() << 4; 590 } 591 b->add32(key); 592 } 593 594private: 595 void onEmitCode(const EmitArgs& args) override { 596 const CustomXP& xp = args.fXP.cast<CustomXP>(); 597 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 598 599 if (xp.hasHWBlendEquation()) { 600 // The blend mode will be implemented in hardware; only output the src color. 601 fsBuilder->enableAdvancedBlendEquationIfNeeded(xp.hwBlendEquation()); 602 if (xp.readsCoverage()) { 603 // Do coverage modulation by multiplying it into the src color before blending. 604 // (See getOptimizations()) 605 fsBuilder->codeAppendf("%s = %s * %s;", 606 args.fOutputPrimary, args.fInputCoverage, args.fInputColor); 607 } else { 608 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor); 609 } 610 } else { 611 const char* dstColor = fsBuilder->dstColor(); 612 emit_custom_xfermode_code(xp.mode(), fsBuilder, args.fOutputPrimary, args.fInputColor, 613 dstColor); 614 if (xp.readsCoverage()) { 615 fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;", 616 args.fOutputPrimary, args.fOutputPrimary, 617 args.fInputCoverage, args.fInputCoverage, dstColor); 618 } 619 } 620 } 621 622 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {} 623 624 typedef GrGLFragmentProcessor INHERITED; 625}; 626 627/////////////////////////////////////////////////////////////////////////////// 628 629CustomXP::CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy, 630 bool willReadDstColor) 631 : INHERITED(dstCopy, willReadDstColor), 632 fMode(mode), 633 fHWBlendEquation(static_cast<GrBlendEquation>(-1)) { 634 this->initClassID<CustomXP>(); 635} 636 637void CustomXP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { 638 GLCustomXP::GenKey(*this, caps, b); 639} 640 641GrGLXferProcessor* CustomXP::createGLInstance() const { 642 SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation()); 643 return SkNEW_ARGS(GLCustomXP, (*this)); 644} 645 646bool CustomXP::onIsEqual(const GrXferProcessor& other) const { 647 const CustomXP& s = other.cast<CustomXP>(); 648 return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation; 649} 650 651GrXferProcessor::OptFlags CustomXP::onGetOptimizations(const GrProcOptInfo& colorPOI, 652 const GrProcOptInfo& coveragePOI, 653 bool doesStencilWrite, 654 GrColor* overrideColor, 655 const GrDrawTargetCaps& caps) { 656 /* 657 Most the optimizations we do here are based on tweaking alpha for coverage. 658 659 The general SVG blend equation is defined in the spec as follows: 660 661 Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa) 662 Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa) 663 664 (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha, 665 and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied 666 RGB colors.) 667 668 For every blend mode supported by this class, i.e. the "advanced" blend 669 modes, X=Y=Z=1 and this equation reduces to the PDF blend equation. 670 671 It can be shown that when X=Y=Z=1, these equations can modulate alpha for 672 coverage. 673 674 675 == Color == 676 677 We substitute Y=Z=1 and define a blend() function that calculates Dca' in 678 terms of premultiplied alpha only: 679 680 blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0, 681 Sca : if Da == 0, 682 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if Sa,Da != 0} 683 684 And for coverage modulation, we use a post blend src-over model: 685 686 Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 687 688 (Where f is the fractional coverage.) 689 690 Next we show that canTweakAlphaForCoverage() is true by proving the 691 following relationship: 692 693 blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 694 695 General case (f,Sa,Da != 0): 696 697 f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 698 = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca [Sa,Da != 0, definition of blend()] 699 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca 700 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca 701 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca 702 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca 703 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) 704 = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0] 705 = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()] 706 707 Corner cases (Sa=0, Da=0, and f=0): 708 709 Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 710 = f * Dca + (1-f) * Dca [Sa=0, definition of blend()] 711 = Dca 712 = blend(0, Dca, 0, Da) [definition of blend()] 713 = blend(f*Sca, Dca, f*Sa, Da) [Sa=0] 714 715 Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 716 = f * Sca + (1-f) * Dca [Da=0, definition of blend()] 717 = f * Sca [Da=0] 718 = blend(f*Sca, 0, f*Sa, 0) [definition of blend()] 719 = blend(f*Sca, Dca, f*Sa, Da) [Da=0] 720 721 f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca 722 = Dca [f=0] 723 = blend(0, Dca, 0, Da) [definition of blend()] 724 = blend(f*Sca, Dca, f*Sa, Da) [f=0] 725 726 == Alpha == 727 728 We substitute X=Y=Z=1 and define a blend() function that calculates Da': 729 730 blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa) 731 = Sa * Da + Sa - Sa * Da + Da - Da * Sa 732 = Sa + Da - Sa * Da 733 734 We use the same model for coverage modulation as we did with color: 735 736 Da'' = f * blend(Sa, Da) + (1-f) * Da 737 738 And show that canTweakAlphaForCoverage() is true by proving the following 739 relationship: 740 741 blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da 742 743 744 f * blend(Sa, Da) + (1-f) * Da 745 = f * (Sa + Da - Sa * Da) + (1-f) * Da 746 = f*Sa + f*Da - f*Sa * Da + Da - f*Da 747 = f*Sa - f*Sa * Da + Da 748 = f*Sa + Da - f*Sa * Da 749 = blend(f*Sa, Da) 750 */ 751 752 OptFlags flags = kNone_Opt; 753 if (colorPOI.allStagesMultiplyInput()) { 754 flags |= kCanTweakAlphaForCoverage_OptFlag; 755 } 756 if (coveragePOI.isSolidWhite()) { 757 flags |= kIgnoreCoverage_OptFlag; 758 } 759 if (caps.advancedBlendEquationSupport() && !coveragePOI.isFourChannelOutput()) { 760 // This blend mode can be implemented in hardware. 761 fHWBlendEquation = hw_blend_equation(fMode); 762 } 763 return flags; 764} 765 766bool CustomXP::onWillNeedXferBarrier(const GrRenderTarget* rt, 767 const GrDrawTargetCaps& caps, 768 GrXferBarrierType* outBarrierType) const { 769 if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) { 770 *outBarrierType = kBlend_GrXferBarrierType; 771 return true; 772 } 773 return false; 774} 775 776void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const { 777 if (this->hasHWBlendEquation()) { 778 blendInfo->fEquation = this->hwBlendEquation(); 779 } 780} 781 782/////////////////////////////////////////////////////////////////////////////// 783 784GrCustomXPFactory::GrCustomXPFactory(SkXfermode::Mode mode) 785 : fMode(mode) { 786 this->initClassID<GrCustomXPFactory>(); 787} 788 789GrXferProcessor* 790GrCustomXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps, 791 const GrProcOptInfo& colorPOI, 792 const GrProcOptInfo& coveragePOI, 793 const GrDeviceCoordTexture* dstCopy) const { 794 return CustomXP::Create(fMode, dstCopy, this->willReadDstColor(caps, colorPOI, coveragePOI)); 795} 796 797bool GrCustomXPFactory::willReadDstColor(const GrDrawTargetCaps& caps, 798 const GrProcOptInfo& colorPOI, 799 const GrProcOptInfo& coveragePOI) const { 800 if (!caps.advancedBlendEquationSupport()) { 801 // No hardware support for advanced blend equations; we will need to do it in the shader. 802 return true; 803 } 804 if (coveragePOI.isFourChannelOutput()) { 805 // Advanced blend equations can't tweak alpha for RGB coverage. 806 return true; 807 } 808 return false; 809} 810 811void GrCustomXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, 812 const GrProcOptInfo& coveragePOI, 813 GrXPFactory::InvariantOutput* output) const { 814 output->fWillBlendWithDst = true; 815 output->fBlendedColorFlags = 0; 816} 817 818GR_DEFINE_XP_FACTORY_TEST(GrCustomXPFactory); 819GrXPFactory* GrCustomXPFactory::TestCreate(SkRandom* rand, 820 GrContext*, 821 const GrDrawTargetCaps&, 822 GrTexture*[]) { 823 int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode); 824 825 return SkNEW_ARGS(GrCustomXPFactory, (static_cast<SkXfermode::Mode>(mode))); 826} 827 828