OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "glsl/GrGLSLProgramBuilder.h" | 8 #include "glsl/GrGLSLProgramBuilder.h" |
9 | 9 |
| 10 #include "GrPipeline.h" |
| 11 #include "glsl/GrGLSLFragmentProcessor.h" |
| 12 #include "glsl/GrGLSLGeometryProcessor.h" |
| 13 #include "glsl/GrGLSLXferProcessor.h" |
| 14 |
10 const int GrGLSLProgramBuilder::kVarsPerBlock = 8; | 15 const int GrGLSLProgramBuilder::kVarsPerBlock = 8; |
11 | 16 |
12 GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args) | 17 GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args) |
13 : fVS(this) | 18 : fVS(this) |
14 , fGS(this) | 19 , fGS(this) |
15 , fFS(this, args.fDesc->header().fFragPosKey) | 20 , fFS(this, args.fDesc->header().fFragPosKey) |
16 , fStageIndex(-1) | 21 , fStageIndex(-1) |
17 , fArgs(args) { | 22 , fArgs(args) |
| 23 , fGeometryProcessor(nullptr) |
| 24 , fXferProcessor(nullptr) { |
| 25 } |
| 26 |
| 27 bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, |
| 28 GrGLSLExpr4* inputCoverage, |
| 29 int maxTextures) { |
| 30 // First we loop over all of the installed processors and collect coord tran
sforms. These will |
| 31 // be sent to the GrGLSLPrimitiveProcessor in its emitCode function |
| 32 const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); |
| 33 int totalTextures = primProc.numTextures(); |
| 34 |
| 35 for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) { |
| 36 const GrFragmentProcessor& processor = this->pipeline().getFragmentProce
ssor(i); |
| 37 |
| 38 if (!primProc.hasTransformedLocalCoords()) { |
| 39 SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransfor
ms.push_back(); |
| 40 processor.gatherCoordTransforms(&procCoords); |
| 41 } |
| 42 |
| 43 totalTextures += processor.numTextures(); |
| 44 if (totalTextures >= maxTextures) { |
| 45 GrCapsDebugf(this->caps(), "Program would use too many texture units
\n"); |
| 46 return false; |
| 47 } |
| 48 } |
| 49 |
| 50 this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage); |
| 51 |
| 52 int numProcs = this->pipeline().numFragmentProcessors(); |
| 53 this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors
(), inputColor); |
| 54 this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(),
numProcs, |
| 55 inputCoverage); |
| 56 this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColo
r, *inputCoverage, |
| 57 this->pipeline().ignoresCoverage()); |
| 58 this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOu
tput()); |
| 59 return true; |
| 60 } |
| 61 |
| 62 void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
oc, |
| 63 GrGLSLExpr4* outputColor, |
| 64 GrGLSLExpr4* outputCoverage) { |
| 65 // Program builders have a bit of state we need to clear with each effect |
| 66 AutoStageAdvance adv(this); |
| 67 this->nameExpression(outputColor, "outputColor"); |
| 68 this->nameExpression(outputCoverage, "outputCoverage"); |
| 69 |
| 70 // Enclose custom code in a block to avoid namespace conflicts |
| 71 SkString openBrace; |
| 72 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name()); |
| 73 fFS.codeAppend(openBrace.c_str()); |
| 74 fVS.codeAppendf("// Primitive Processor %s\n", proc.name()); |
| 75 |
| 76 SkASSERT(!fGeometryProcessor); |
| 77 fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps()); |
| 78 |
| 79 SkSTArray<4, GrGLSLTextureSampler> samplers(proc.numTextures()); |
| 80 this->emitSamplers(proc, &samplers); |
| 81 |
| 82 GrGLSLGeometryProcessor::EmitArgs args(&fVS, |
| 83 &fFS, |
| 84 this->varyingHandler(), |
| 85 this->uniformHandler(), |
| 86 this->glslCaps(), |
| 87 proc, |
| 88 outputColor->c_str(), |
| 89 outputCoverage->c_str(), |
| 90 samplers, |
| 91 fCoordTransforms, |
| 92 &fOutCoords); |
| 93 fGeometryProcessor->emitCode(args); |
| 94 |
| 95 // We have to check that effects and the code they emit are consistent, ie i
f an effect |
| 96 // asks for dst color, then the emit code needs to follow suit |
| 97 verify(proc); |
| 98 |
| 99 fFS.codeAppend("}"); |
| 100 } |
| 101 |
| 102 void GrGLSLProgramBuilder::emitAndInstallFragProcs(int procOffset, |
| 103 int numProcs, |
| 104 GrGLSLExpr4* inOut) { |
| 105 for (int i = procOffset; i < numProcs; ++i) { |
| 106 GrGLSLExpr4 output; |
| 107 const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i)
; |
| 108 this->emitAndInstallFragProc(fp, i, *inOut, &output); |
| 109 *inOut = output; |
| 110 } |
| 111 } |
| 112 |
| 113 // TODO Processors cannot output zeros because an empty string is all 1s |
| 114 // the fix is to allow effects to take the GrGLSLExpr4 directly |
| 115 void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, |
| 116 int index, |
| 117 const GrGLSLExpr4& input, |
| 118 GrGLSLExpr4* output) { |
| 119 // Program builders have a bit of state we need to clear with each effect |
| 120 AutoStageAdvance adv(this); |
| 121 this->nameExpression(output, "output"); |
| 122 |
| 123 // Enclose custom code in a block to avoid namespace conflicts |
| 124 SkString openBrace; |
| 125 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name()); |
| 126 fFS.codeAppend(openBrace.c_str()); |
| 127 |
| 128 GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance(); |
| 129 |
| 130 SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures()); |
| 131 this->emitSamplers(fp, &samplers); |
| 132 |
| 133 GrGLSLFragmentProcessor::EmitArgs args(&fFS, |
| 134 this->uniformHandler(), |
| 135 this->glslCaps(), |
| 136 fp, |
| 137 output->c_str(), |
| 138 input.isOnes() ? nullptr : input.c_st
r(), |
| 139 fOutCoords[index], |
| 140 samplers); |
| 141 fragProc->emitCode(args); |
| 142 |
| 143 // We have to check that effects and the code they emit are consistent, ie i
f an effect |
| 144 // asks for dst color, then the emit code needs to follow suit |
| 145 verify(fp); |
| 146 fFragmentProcessors.push_back(fragProc); |
| 147 |
| 148 fFS.codeAppend("}"); |
| 149 } |
| 150 |
| 151 void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, |
| 152 const GrGLSLExpr4& colorIn, |
| 153 const GrGLSLExpr4& coverageIn, |
| 154 bool ignoresCoverage) { |
| 155 // Program builders have a bit of state we need to clear with each effect |
| 156 AutoStageAdvance adv(this); |
| 157 |
| 158 SkASSERT(!fXferProcessor); |
| 159 fXferProcessor = xp.createGLSLInstance(); |
| 160 |
| 161 // Enable dual source secondary output if we have one |
| 162 if (xp.hasSecondaryOutput()) { |
| 163 fFS.enableSecondaryOutput(); |
| 164 } |
| 165 |
| 166 if (this->glslCaps()->mustDeclareFragmentShaderOutput()) { |
| 167 fFS.enableCustomOutput(); |
| 168 } |
| 169 |
| 170 SkString openBrace; |
| 171 openBrace.printf("{ // Xfer Processor: %s\n", xp.name()); |
| 172 fFS.codeAppend(openBrace.c_str()); |
| 173 |
| 174 SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures()); |
| 175 this->emitSamplers(xp, &samplers); |
| 176 |
| 177 GrGLSLXferProcessor::EmitArgs args(&fFS, |
| 178 this->uniformHandler(), |
| 179 this->glslCaps(), |
| 180 xp, colorIn.c_str(), |
| 181 ignoresCoverage ? nullptr : coverageIn.c_
str(), |
| 182 fFS.getPrimaryColorOutputName(), |
| 183 fFS.getSecondaryColorOutputName(), |
| 184 samplers); |
| 185 fXferProcessor->emitCode(args); |
| 186 |
| 187 // We have to check that effects and the code they emit are consistent, ie i
f an effect |
| 188 // asks for dst color, then the emit code needs to follow suit |
| 189 verify(xp); |
| 190 fFS.codeAppend("}"); |
| 191 } |
| 192 |
| 193 void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) { |
| 194 // Swizzle the fragment shader outputs if necessary. |
| 195 GrSwizzle swizzle; |
| 196 swizzle.setFromKey(this->desc().header().fOutputSwizzle); |
| 197 if (swizzle != GrSwizzle::RGBA()) { |
| 198 fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(), |
| 199 fFS.getPrimaryColorOutputName(), |
| 200 swizzle.c_str()); |
| 201 if (hasSecondaryOutput) { |
| 202 fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(), |
| 203 fFS.getSecondaryColorOutputName(), |
| 204 swizzle.c_str()); |
| 205 } |
| 206 } |
| 207 } |
| 208 |
| 209 void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { |
| 210 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); |
| 211 } |
| 212 |
| 213 void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) { |
| 214 SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor()); |
| 215 } |
| 216 |
| 217 void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) { |
| 218 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); |
18 } | 219 } |
19 | 220 |
20 void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char*
name, bool mangle) { | 221 void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char*
name, bool mangle) { |
21 if ('\0' == prefix) { | 222 if ('\0' == prefix) { |
22 *out = name; | 223 *out = name; |
23 } else { | 224 } else { |
24 out->printf("%c%s", prefix, name); | 225 out->printf("%c%s", prefix, name); |
25 } | 226 } |
26 if (mangle) { | 227 if (mangle) { |
27 if (out->endsWith('_')) { | 228 if (out->endsWith('_')) { |
28 // Names containing "__" are reserved. | 229 // Names containing "__" are reserved. |
29 out->append("x"); | 230 out->append("x"); |
30 } | 231 } |
31 out->appendf("_Stage%d%s", fStageIndex, fFS.getMangleString().c_str()); | 232 out->appendf("_Stage%d%s", fStageIndex, fFS.getMangleString().c_str()); |
32 } | 233 } |
33 } | 234 } |
34 | 235 |
| 236 void GrGLSLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseN
ame) { |
| 237 // create var to hold stage result. If we already have a valid output name,
just use that |
| 238 // otherwise create a new mangled one. This name is only valid if we are re
ordering stages |
| 239 // and have to tell stage exactly where to put its output. |
| 240 SkString outName; |
| 241 if (output->isValid()) { |
| 242 outName = output->c_str(); |
| 243 } else { |
| 244 this->nameVariable(&outName, '\0', baseName); |
| 245 } |
| 246 fFS.codeAppendf("vec4 %s;", outName.c_str()); |
| 247 *output = outName; |
| 248 } |
| 249 |
35 void GrGLSLProgramBuilder::appendUniformDecls(ShaderVisibility visibility, | 250 void GrGLSLProgramBuilder::appendUniformDecls(ShaderVisibility visibility, |
36 SkString* out) const { | 251 SkString* out) const { |
37 this->uniformHandler()->appendUniformDecls(visibility, out); | 252 this->uniformHandler()->appendUniformDecls(visibility, out); |
38 } | 253 } |
39 | 254 |
40 void GrGLSLProgramBuilder::addRTAdjustmentUniform(GrSLPrecision precision, | 255 void GrGLSLProgramBuilder::addRTAdjustmentUniform(GrSLPrecision precision, |
41 const char* name, | 256 const char* name, |
42 const char** outName) { | 257 const char** outName) { |
43 SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid()); | 258 SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid()); |
44 fUniformHandles.fRTAdjustmentUni = | 259 fUniformHandles.fRTAdjustmentUni = |
45 this->uniformHandler()->addUniform(GrGLSLUniformHandler::kVertex_Vis
ibility, | 260 this->uniformHandler()->addUniform(GrGLSLUniformHandler::kVertex_Vis
ibility, |
46 kVec4f_GrSLType, | 261 kVec4f_GrSLType, |
47 precision, | 262 precision, |
48 name, | 263 name, |
49 outName); | 264 outName); |
50 } | 265 } |
51 | 266 |
52 void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** out
Name) { | 267 void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** out
Name) { |
53 SkASSERT(!fUniformHandles.fRTHeightUni.isValid()); | 268 SkASSERT(!fUniformHandles.fRTHeightUni.isValid()); |
54 GrGLSLUniformHandler* uniformHandler = this->uniformHandler(); | 269 GrGLSLUniformHandler* uniformHandler = this->uniformHandler(); |
55 fUniformHandles.fRTHeightUni = | 270 fUniformHandles.fRTHeightUni = |
56 uniformHandler->internalAddUniformArray(GrGLSLUniformHandler::kFragm
ent_Visibility, | 271 uniformHandler->internalAddUniformArray(GrGLSLUniformHandler::kFragm
ent_Visibility, |
57 kFloat_GrSLType, kDefault_Gr
SLPrecision, | 272 kFloat_GrSLType, kDefault_Gr
SLPrecision, |
58 name, false, 0, outName); | 273 name, false, 0, outName); |
59 } | 274 } |
60 | 275 |
| 276 void GrGLSLProgramBuilder::cleanupFragmentProcessors() { |
| 277 for (int i = 0; i < fFragmentProcessors.count(); ++i) { |
| 278 delete fFragmentProcessors[i]; |
| 279 } |
| 280 } |
| 281 |
OLD | NEW |