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, half3(0)))) {" 56 " discard;" 57 "}", args.fInputCoverage); 58 } 59 60 const char* dstTopLeftName; 61 const char* dstCoordScaleName; 62 63 fDstTopLeftUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 64 kHalf2_GrSLType, 65 "DstTextureUpperLeft", 66 &dstTopLeftName); 67 fDstScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 68 kHalf2_GrSLType, 69 "DstTextureCoordScale", 70 &dstCoordScaleName); 71 72 fragBuilder->codeAppend("// Read color from copy of the destination.\n"); 73 fragBuilder->codeAppendf("half2 _dstTexCoord = (sk_FragCoord.xy - %s) * %s;", 74 dstTopLeftName, dstCoordScaleName); 75 76 if (flipY) { 77 fragBuilder->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;"); 78 } 79 80 fragBuilder->codeAppendf("half4 %s = ", dstColor); 81 fragBuilder->appendTextureLookup(args.fDstTextureSamplerHandle, "_dstTexCoord", 82 kHalf2_GrSLType); 83 fragBuilder->codeAppend(";"); 84 } else { 85 needsLocalOutColor = args.fShaderCaps->requiresLocalOutputColorForFBFetch(); 86 } 87 88 const char* outColor = "_localColorOut"; 89 if (!needsLocalOutColor) { 90 outColor = args.fOutputPrimary; 91 } else { 92 fragBuilder->codeAppendf("half4 %s;", outColor); 93 } 94 95 this->emitBlendCodeForDstRead(fragBuilder, 96 uniformHandler, 97 args.fInputColor, 98 args.fInputCoverage, 99 dstColor, 100 outColor, 101 args.fOutputSecondary, 102 args.fXP); 103 if (needsLocalOutColor) { 104 fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, outColor); 105 } 106 } 107 108 void GrGLSLXferProcessor::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp, 109 const GrTexture* dstTexture, const SkIPoint& dstTextureOffset) { 110 if (dstTexture) { 111 if (fDstTopLeftUni.isValid()) { 112 pdm.set2f(fDstTopLeftUni, static_cast<float>(dstTextureOffset.fX), 113 static_cast<float>(dstTextureOffset.fY)); 114 pdm.set2f(fDstScaleUni, 1.f / dstTexture->width(), 1.f / dstTexture->height()); 115 } else { 116 SkASSERT(!fDstScaleUni.isValid()); 117 } 118 } else { 119 SkASSERT(!fDstTopLeftUni.isValid()); 120 SkASSERT(!fDstScaleUni.isValid()); 121 } 122 this->onSetData(pdm, xp); 123 } 124 125 void GrGLSLXferProcessor::DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder, 126 const char* srcCoverage, 127 const char* dstColor, 128 const char* outColor, 129 const char* outColorSecondary, 130 const GrXferProcessor& proc) { 131 if (proc.dstReadUsesMixedSamples()) { 132 if (srcCoverage) { 133 // TODO: Once we are no longer using legacy mesh ops, it will not be possible to even 134 // create a mixed sample with lcd so we can uncomment the below assert. In practice 135 // today this never happens except for GLPrograms test which can make one. skia:6661 136 // SkASSERT(!proc.isLCD()); 137 fragBuilder->codeAppendf("%s *= %s;", outColor, srcCoverage); 138 fragBuilder->codeAppendf("%s = %s;", outColorSecondary, srcCoverage); 139 } else { 140 fragBuilder->codeAppendf("%s = half4(1.0);", outColorSecondary); 141 } 142 } else if (srcCoverage) { 143 if (proc.isLCD()) { 144 fragBuilder->codeAppendf("half lerpRed = mix(%s.a, %s.a, %s.r);", 145 dstColor, outColor, srcCoverage); 146 fragBuilder->codeAppendf("half lerpBlue = mix(%s.a, %s.a, %s.g);", 147 dstColor, outColor, srcCoverage); 148 fragBuilder->codeAppendf("half lerpGreen = mix(%s.a, %s.a, %s.b);", 149 dstColor, outColor, srcCoverage); 150 } 151 fragBuilder->codeAppendf("%s = %s * %s + (half4(1.0) - %s) * %s;", 152 outColor, srcCoverage, outColor, srcCoverage, dstColor); 153 if (proc.isLCD()) { 154 fragBuilder->codeAppendf("%s.a = max(max(lerpRed, lerpBlue), lerpGreen);", outColor); 155 } 156 } 157 } 158 159