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 "src/gpu/GrXferProcessor.h" 9 10#include "src/gpu/GrCaps.h" 11#include "src/gpu/GrPipeline.h" 12#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 13#include "src/gpu/glsl/GrGLSLProgramDataManager.h" 14 15GrXferProcessor::GrXferProcessor(ClassID classID) 16 : INHERITED(classID) 17 , fWillReadDstColor(false) 18 , fIsLCD(false) {} 19 20GrXferProcessor::GrXferProcessor(ClassID classID, bool willReadDstColor, 21 GrProcessorAnalysisCoverage coverage) 22 : INHERITED(classID) 23 , fWillReadDstColor(willReadDstColor) 24 , fIsLCD(GrProcessorAnalysisCoverage::kLCD == coverage) {} 25 26bool GrXferProcessor::hasSecondaryOutput() const { 27 if (!this->willReadDstColor()) { 28 return this->onHasSecondaryOutput(); 29 } 30 return false; 31} 32 33void GrXferProcessor::addToKey(const GrShaderCaps& caps, 34 GrProcessorKeyBuilder* b, 35 const GrSurfaceOrigin* originIfDstTexture, 36 bool usesInputAttachmentForDstRead) const { 37 uint32_t key = this->willReadDstColor() ? 0x1 : 0x0; 38 if (key) { 39 if (originIfDstTexture) { 40 key |= 0x2; 41 if (kTopLeft_GrSurfaceOrigin == *originIfDstTexture) { 42 key |= 0x4; 43 } 44 if (usesInputAttachmentForDstRead) { 45 key |= 0x8; 46 } 47 } 48 } 49 if (fIsLCD) { 50 key |= 0x10; 51 } 52 b->add32(key); 53 this->onAddToKey(caps, b); 54} 55 56#ifdef SK_DEBUG 57static const char* equation_string(GrBlendEquation eq) { 58 switch (eq) { 59 case kAdd_GrBlendEquation: 60 return "add"; 61 case kSubtract_GrBlendEquation: 62 return "subtract"; 63 case kReverseSubtract_GrBlendEquation: 64 return "reverse_subtract"; 65 case kScreen_GrBlendEquation: 66 return "screen"; 67 case kOverlay_GrBlendEquation: 68 return "overlay"; 69 case kDarken_GrBlendEquation: 70 return "darken"; 71 case kLighten_GrBlendEquation: 72 return "lighten"; 73 case kColorDodge_GrBlendEquation: 74 return "color_dodge"; 75 case kColorBurn_GrBlendEquation: 76 return "color_burn"; 77 case kHardLight_GrBlendEquation: 78 return "hard_light"; 79 case kSoftLight_GrBlendEquation: 80 return "soft_light"; 81 case kDifference_GrBlendEquation: 82 return "difference"; 83 case kExclusion_GrBlendEquation: 84 return "exclusion"; 85 case kMultiply_GrBlendEquation: 86 return "multiply"; 87 case kHSLHue_GrBlendEquation: 88 return "hsl_hue"; 89 case kHSLSaturation_GrBlendEquation: 90 return "hsl_saturation"; 91 case kHSLColor_GrBlendEquation: 92 return "hsl_color"; 93 case kHSLLuminosity_GrBlendEquation: 94 return "hsl_luminosity"; 95 case kIllegal_GrBlendEquation: 96 SkASSERT(false); 97 return "<illegal>"; 98 } 99 return ""; 100} 101 102static const char* coeff_string(GrBlendCoeff coeff) { 103 switch (coeff) { 104 case kZero_GrBlendCoeff: 105 return "zero"; 106 case kOne_GrBlendCoeff: 107 return "one"; 108 case kSC_GrBlendCoeff: 109 return "src_color"; 110 case kISC_GrBlendCoeff: 111 return "inv_src_color"; 112 case kDC_GrBlendCoeff: 113 return "dst_color"; 114 case kIDC_GrBlendCoeff: 115 return "inv_dst_color"; 116 case kSA_GrBlendCoeff: 117 return "src_alpha"; 118 case kISA_GrBlendCoeff: 119 return "inv_src_alpha"; 120 case kDA_GrBlendCoeff: 121 return "dst_alpha"; 122 case kIDA_GrBlendCoeff: 123 return "inv_dst_alpha"; 124 case kConstC_GrBlendCoeff: 125 return "const_color"; 126 case kIConstC_GrBlendCoeff: 127 return "inv_const_color"; 128 case kS2C_GrBlendCoeff: 129 return "src2_color"; 130 case kIS2C_GrBlendCoeff: 131 return "inv_src2_color"; 132 case kS2A_GrBlendCoeff: 133 return "src2_alpha"; 134 case kIS2A_GrBlendCoeff: 135 return "inv_src2_alpha"; 136 case kIllegal_GrBlendCoeff: 137 SkASSERT(false); 138 return "<illegal>"; 139 } 140 return ""; 141} 142 143SkString GrXferProcessor::BlendInfo::dump() const { 144 SkString out; 145 out.printf("write_color(%d) equation(%s) src_coeff(%s) dst_coeff:(%s) const(0x%08x)", 146 fWriteColor, equation_string(fEquation), coeff_string(fSrcBlend), 147 coeff_string(fDstBlend), fBlendConstant.toBytes_RGBA()); 148 return out; 149} 150#endif 151 152/////////////////////////////////////////////////////////////////////////////// 153 154GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties( 155 const GrXPFactory* factory, 156 const GrProcessorAnalysisColor& color, 157 const GrProcessorAnalysisCoverage& coverage, 158 const GrCaps& caps, 159 GrClampType clampType) { 160 AnalysisProperties result; 161 if (factory) { 162 result = factory->analysisProperties(color, coverage, caps, clampType); 163 } else { 164 result = GrPorterDuffXPFactory::SrcOverAnalysisProperties(color, coverage, caps, clampType); 165 } 166 if (coverage == GrProcessorAnalysisCoverage::kNone) { 167 result |= AnalysisProperties::kCompatibleWithCoverageAsAlpha; 168 } 169 SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture)); 170 if ((result & AnalysisProperties::kReadsDstInShader) && 171 !caps.shaderCaps()->dstReadInShaderSupport()) { 172 result |= AnalysisProperties::kRequiresDstTexture | 173 AnalysisProperties::kRequiresNonOverlappingDraws; 174 } 175 return result; 176} 177 178sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* factory, 179 const GrProcessorAnalysisColor& color, 180 GrProcessorAnalysisCoverage coverage, 181 const GrCaps& caps, 182 GrClampType clampType) { 183 if (factory) { 184 return factory->makeXferProcessor(color, coverage, caps, clampType); 185 } else { 186 return GrPorterDuffXPFactory::MakeSrcOverXferProcessor(color, coverage, caps); 187 } 188} 189 190////////////////////////////////////////////////////////////////////////////// 191 192using ProgramImpl = GrXferProcessor::ProgramImpl; 193 194// This is only called for cases where we are doing LCD coverage and not using in shader blending. 195// For these cases we assume the the src alpha is 1, thus we can just use the max for the alpha 196// coverage since src alpha will always be greater than or equal to dst alpha. 197static void adjust_for_lcd_coverage(GrGLSLXPFragmentBuilder* fragBuilder, 198 const char* srcCoverage, 199 const GrXferProcessor& proc) { 200 if (srcCoverage && proc.isLCD()) { 201 fragBuilder->codeAppendf("%s.a = max(max(%s.r, %s.g), %s.b);", 202 srcCoverage, 203 srcCoverage, 204 srcCoverage, 205 srcCoverage); 206 } 207} 208 209void ProgramImpl::emitCode(const EmitArgs& args) { 210 if (!args.fXP.willReadDstColor()) { 211 adjust_for_lcd_coverage(args.fXPFragBuilder, args.fInputCoverage, args.fXP); 212 this->emitOutputsForBlendState(args); 213 } else { 214 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder; 215 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 216 const char* dstColor = fragBuilder->dstColor(); 217 218 bool needsLocalOutColor = false; 219 220 if (args.fDstTextureSamplerHandle.isValid()) { 221 if (args.fInputCoverage) { 222 // We don't think any shaders actually output negative coverage, but just as a 223 // safety check for floating point precision errors, we compare with <= here. We 224 // just check the RGB values of the coverage, since the alpha may not have been set 225 // when using LCD. If we are using single-channel coverage, alpha will be equal to 226 // RGB anyway. 227 // 228 // The discard here also helps for batching text-draws together, which need to read 229 // from a dst copy for blends. However, this only helps the case where the outer 230 // bounding boxes of each letter overlap and not two actually parts of the text. 231 fragBuilder->codeAppendf("if (all(lessThanEqual(%s.rgb, half3(0)))) {" 232 " discard;" 233 "}", 234 args.fInputCoverage); 235 } 236 } else { 237 needsLocalOutColor = args.fShaderCaps->requiresLocalOutputColorForFBFetch(); 238 } 239 240 const char* outColor = "_localColorOut"; 241 if (!needsLocalOutColor) { 242 outColor = args.fOutputPrimary; 243 } else { 244 fragBuilder->codeAppendf("half4 %s;", outColor); 245 } 246 247 this->emitBlendCodeForDstRead(fragBuilder, 248 uniformHandler, 249 args.fInputColor, 250 args.fInputCoverage, 251 dstColor, 252 outColor, 253 args.fOutputSecondary, 254 args.fXP); 255 if (needsLocalOutColor) { 256 fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, outColor); 257 } 258 } 259 260 // Swizzle the fragment shader outputs if necessary. 261 this->emitWriteSwizzle(args.fXPFragBuilder, 262 args.fWriteSwizzle, 263 args.fOutputPrimary, 264 args.fOutputSecondary); 265} 266 267void ProgramImpl::emitWriteSwizzle(GrGLSLXPFragmentBuilder* x, 268 const GrSwizzle& swizzle, 269 const char* outColor, 270 const char* outColorSecondary) const { 271 if (GrSwizzle::RGBA() != swizzle) { 272 x->codeAppendf("%s = %s.%s;", outColor, outColor, swizzle.asString().c_str()); 273 if (outColorSecondary) { 274 x->codeAppendf("%s = %s.%s;", 275 outColorSecondary, 276 outColorSecondary, 277 swizzle.asString().c_str()); 278 } 279 } 280} 281 282void ProgramImpl::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) { 283 this->onSetData(pdm, xp); 284} 285 286void ProgramImpl::DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder, 287 const char* srcCoverage, 288 const char* dstColor, 289 const char* outColor, 290 const char* outColorSecondary, 291 const GrXferProcessor& proc) { 292 if (srcCoverage) { 293 if (proc.isLCD()) { 294 fragBuilder->codeAppendf("half3 lerpRGB = mix(%s.aaa, %s.aaa, %s.rgb);", 295 dstColor, 296 outColor, 297 srcCoverage); 298 } 299 fragBuilder->codeAppendf("%s = %s * %s + (half4(1.0) - %s) * %s;", 300 outColor, 301 srcCoverage, 302 outColor, 303 srcCoverage, 304 dstColor); 305 if (proc.isLCD()) { 306 fragBuilder->codeAppendf("%s.a = max(max(lerpRGB.r, lerpRGB.b), lerpRGB.g);", outColor); 307 } 308 } 309} 310