1 /* 2 * Copyright 2014 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 "glsl/GrGLSLXferProcessor.h" 9 10 #include "GrShaderCaps.h" 11 #include "GrTexture.h" 12 #include "GrXferProcessor.h" 13 #include "glsl/GrGLSLFragmentShaderBuilder.h" 14 #include "glsl/GrGLSLProgramDataManager.h" 15 #include "glsl/GrGLSLUniformHandler.h" 16 17 // This is only called for cases where we are doing LCD coverage and not using in shader blending. 18 // For these cases we assume the the src alpha is 1, thus we can just use the max for the alpha 19 // coverage since src alpha will always be greater than or equal to dst alpha. 20 static void adjust_for_lcd_coverage(GrGLSLXPFragmentBuilder* fragBuilder, 21 const char* srcCoverage, 22 const GrXferProcessor& proc) { 23 if (srcCoverage && proc.isLCD()) { 24 fragBuilder->codeAppendf("%s.a = max(max(%s.r, %s.g), %s.b);", 25 srcCoverage, srcCoverage, srcCoverage, srcCoverage); 26 } 27 } 28 29 30 void GrGLSLXferProcessor::emitCode(const EmitArgs& args) { 31 if (!args.fXP.willReadDstColor()) { 32 adjust_for_lcd_coverage(args.fXPFragBuilder, args.fInputCoverage, args.fXP); 33 this->emitOutputsForBlendState(args); 34 return; 35 } 36 37 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder; 38 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 39 const char* dstColor = fragBuilder->dstColor(); 40 41 bool needsLocalOutColor = false; 42 43 if (args.fDstTextureSamplerHandle.isValid()) { 44 bool flipY = kBottomLeft_GrSurfaceOrigin == args.fDstTextureOrigin; 45 46 if (args.fInputCoverage) { 47 // We don't think any shaders actually output negative coverage, but just as a safety 48 // check for floating point precision errors we compare with <= here. We just check the 49 // rgb values of the coverage since the alpha may not have been set when using lcd. If 50 // we are using single channel coverage alpha will equal to rgb anyways. 51 // 52 // The discard here also helps for batching text draws together which need to read from 53 // a dst copy for blends. Though this only helps the case where the outer bounding boxes 54 // of each letter overlap and not two actually parts of the text. 55 fragBuilder->codeAppendf("if (all(lessThanEqual(%s.rgb, vec3(0)))) {" 56 " discard;" 57 "}", args.fInputCoverage); 58 } 59 60 const char* dstTopLeftName; 61 const char* dstCoordScaleName; 62 63 fDstTopLeftUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 64 kVec2f_GrSLType, 65 kDefault_GrSLPrecision, 66 "DstTextureUpperLeft", 67 &dstTopLeftName); 68 fDstScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 69 kVec2f_GrSLType, 70 kDefault_GrSLPrecision, 71 "DstTextureCoordScale", 72 &dstCoordScaleName); 73 74 fragBuilder->codeAppend("// Read color from copy of the destination.\n"); 75 fragBuilder->codeAppendf("vec2 _dstTexCoord = (sk_FragCoord.xy - %s) * %s;", 76 dstTopLeftName, dstCoordScaleName); 77 78 if (flipY) { 79 fragBuilder->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;"); 80 } 81 82 fragBuilder->codeAppendf("vec4 %s = ", dstColor); 83 fragBuilder->appendTextureLookup(args.fDstTextureSamplerHandle, "_dstTexCoord", 84 kVec2f_GrSLType); 85 fragBuilder->codeAppend(";"); 86 } else { 87 needsLocalOutColor = args.fShaderCaps->requiresLocalOutputColorForFBFetch(); 88 } 89 90 const char* outColor = "_localColorOut"; 91 if (!needsLocalOutColor) { 92 outColor = args.fOutputPrimary; 93 } else { 94 fragBuilder->codeAppendf("vec4 %s;", outColor); 95 } 96 97 this->emitBlendCodeForDstRead(fragBuilder, 98 uniformHandler, 99 args.fInputColor, 100 args.fInputCoverage, 101 dstColor, 102 outColor, 103 args.fOutputSecondary, 104 args.fXP); 105 if (needsLocalOutColor) { 106 fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, outColor); 107 } 108 } 109 110 void GrGLSLXferProcessor::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp, 111 const GrTexture* dstTexture, const SkIPoint& dstTextureOffset) { 112 if (dstTexture) { 113 if (fDstTopLeftUni.isValid()) { 114 pdm.set2f(fDstTopLeftUni, static_cast<float>(dstTextureOffset.fX), 115 static_cast<float>(dstTextureOffset.fY)); 116 pdm.set2f(fDstScaleUni, 1.f / dstTexture->width(), 1.f / dstTexture->height()); 117 } else { 118 SkASSERT(!fDstScaleUni.isValid()); 119 } 120 } else { 121 SkASSERT(!fDstTopLeftUni.isValid()); 122 SkASSERT(!fDstScaleUni.isValid()); 123 } 124 this->onSetData(pdm, xp); 125 } 126 127 void GrGLSLXferProcessor::DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder, 128 const char* srcCoverage, 129 const char* dstColor, 130 const char* outColor, 131 const char* outColorSecondary, 132 const GrXferProcessor& proc) { 133 if (proc.dstReadUsesMixedSamples()) { 134 if (srcCoverage) { 135 // TODO: Once we are no longer using legacy mesh ops, it will not be possible to even 136 // create a mixed sample with lcd so we can uncomment the below assert. In practice 137 // today this never happens except for GLPrograms test which can make one. skia:6661 138 // SkASSERT(!proc.isLCD()); 139 fragBuilder->codeAppendf("%s *= %s;", outColor, srcCoverage); 140 fragBuilder->codeAppendf("%s = %s;", outColorSecondary, srcCoverage); 141 } else { 142 fragBuilder->codeAppendf("%s = vec4(1.0);", outColorSecondary); 143 } 144 } else if (srcCoverage) { 145 if (proc.isLCD()) { 146 fragBuilder->codeAppendf("float lerpRed = mix(%s.a, %s.a, %s.r);", 147 dstColor, outColor, srcCoverage); 148 fragBuilder->codeAppendf("float lerpBlue = mix(%s.a, %s.a, %s.g);", 149 dstColor, outColor, srcCoverage); 150 fragBuilder->codeAppendf("float lerpGreen = mix(%s.a, %s.a, %s.b);", 151 dstColor, outColor, srcCoverage); 152 } 153 fragBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;", 154 outColor, srcCoverage, outColor, srcCoverage, dstColor); 155 if (proc.isLCD()) { 156 fragBuilder->codeAppendf("%s.a = max(max(lerpRed, lerpBlue), lerpGreen);", outColor); 157 } 158 } 159 } 160 161