OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 "GrGLProgramBuilder.h" | 8 #include "GrGLProgramBuilder.h" |
9 | 9 |
10 #include "GrAutoLocaleSetter.h" | 10 #include "GrAutoLocaleSetter.h" |
(...skipping 24 matching lines...) Expand all Loading... |
35 // uniforms, varyings, textures, etc | 35 // uniforms, varyings, textures, etc |
36 SkAutoTDelete<GrGLProgramBuilder> builder(new GrGLProgramBuilder(gpu, args))
; | 36 SkAutoTDelete<GrGLProgramBuilder> builder(new GrGLProgramBuilder(gpu, args))
; |
37 | 37 |
38 GrGLProgramBuilder* pb = builder.get(); | 38 GrGLProgramBuilder* pb = builder.get(); |
39 | 39 |
40 // TODO: Once all stages can handle taking a float or vec4 and correctly han
dling them we can | 40 // TODO: Once all stages can handle taking a float or vec4 and correctly han
dling them we can |
41 // seed correctly here | 41 // seed correctly here |
42 GrGLSLExpr4 inputColor; | 42 GrGLSLExpr4 inputColor; |
43 GrGLSLExpr4 inputCoverage; | 43 GrGLSLExpr4 inputCoverage; |
44 | 44 |
45 if (!pb->emitAndInstallProcs(&inputColor, &inputCoverage)) { | 45 if (!pb->emitAndInstallProcs(&inputColor, |
| 46 &inputCoverage, |
| 47 gpu->glCaps().maxFragmentTextureUnits())) { |
| 48 pb->cleanupFragmentProcessors(); |
46 return nullptr; | 49 return nullptr; |
47 } | 50 } |
48 | 51 |
49 return pb->finalize(); | 52 return pb->finalize(); |
50 } | 53 } |
51 | 54 |
52 ///////////////////////////////////////////////////////////////////////////// | 55 ///////////////////////////////////////////////////////////////////////////// |
53 | 56 |
54 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args) | 57 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args) |
55 : INHERITED(args) | 58 : INHERITED(args) |
56 , fGeometryProcessor(nullptr) | |
57 , fXferProcessor(nullptr) | |
58 , fGpu(gpu) | 59 , fGpu(gpu) |
59 , fSamplerUniforms(4) | 60 , fSamplerUniforms(4) |
60 , fVaryingHandler(this) | 61 , fVaryingHandler(this) |
61 , fUniformHandler(this) { | 62 , fUniformHandler(this) { |
62 } | 63 } |
63 | 64 |
64 const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const { | 65 const GrCaps* GrGLProgramBuilder::caps() const { |
65 return this->fGpu->ctxInfo().caps()->glslCaps(); | 66 return fGpu->caps(); |
66 } | 67 } |
67 | 68 |
68 bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr
4* inputCoverage) { | 69 const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const { |
69 // First we loop over all of the installed processors and collect coord tran
sforms. These will | 70 return fGpu->ctxInfo().caps()->glslCaps(); |
70 // be sent to the GrGLSLPrimitiveProcessor in its emitCode function | |
71 const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); | |
72 int totalTextures = primProc.numTextures(); | |
73 const int maxTextureUnits = fGpu->glCaps().maxFragmentTextureUnits(); | |
74 | |
75 for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) { | |
76 const GrFragmentProcessor& processor = this->pipeline().getFragmentProce
ssor(i); | |
77 | |
78 if (!primProc.hasTransformedLocalCoords()) { | |
79 SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransfor
ms.push_back(); | |
80 processor.gatherCoordTransforms(&procCoords); | |
81 } | |
82 | |
83 totalTextures += processor.numTextures(); | |
84 if (totalTextures >= maxTextureUnits) { | |
85 GrCapsDebugf(fGpu->caps(), "Program would use too many texture units
\n"); | |
86 return false; | |
87 } | |
88 } | |
89 | |
90 this->emitAndInstallProc(primProc, inputColor, inputCoverage); | |
91 | |
92 fFragmentProcessors.reset(new GrGLInstalledFragProcs); | |
93 int numProcs = this->pipeline().numFragmentProcessors(); | |
94 this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors
(), inputColor); | |
95 this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(),
numProcs, | |
96 inputCoverage); | |
97 this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColo
r, *inputCoverage, | |
98 this->pipeline().ignoresCoverage()); | |
99 this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOu
tput()); | |
100 return true; | |
101 } | |
102 | |
103 void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset, | |
104 int numProcs, | |
105 GrGLSLExpr4* inOut) { | |
106 for (int i = procOffset; i < numProcs; ++i) { | |
107 GrGLSLExpr4 output; | |
108 const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i)
; | |
109 this->emitAndInstallProc(fp, i, *inOut, &output); | |
110 *inOut = output; | |
111 } | |
112 } | |
113 | |
114 void GrGLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseNam
e) { | |
115 // create var to hold stage result. If we already have a valid output name,
just use that | |
116 // otherwise create a new mangled one. This name is only valid if we are re
ordering stages | |
117 // and have to tell stage exactly where to put its output. | |
118 SkString outName; | |
119 if (output->isValid()) { | |
120 outName = output->c_str(); | |
121 } else { | |
122 this->nameVariable(&outName, '\0', baseName); | |
123 } | |
124 fFS.codeAppendf("vec4 %s;", outName.c_str()); | |
125 *output = outName; | |
126 } | |
127 | |
128 // TODO Processors cannot output zeros because an empty string is all 1s | |
129 // the fix is to allow effects to take the GrGLSLExpr4 directly | |
130 void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp, | |
131 int index, | |
132 const GrGLSLExpr4& input, | |
133 GrGLSLExpr4* output) { | |
134 // Program builders have a bit of state we need to clear with each effect | |
135 AutoStageAdvance adv(this); | |
136 this->nameExpression(output, "output"); | |
137 | |
138 // Enclose custom code in a block to avoid namespace conflicts | |
139 SkString openBrace; | |
140 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name()); | |
141 fFS.codeAppend(openBrace.c_str()); | |
142 | |
143 this->emitAndInstallProc(fp, index, output->c_str(), input.isOnes() ? nullpt
r : input.c_str()); | |
144 | |
145 fFS.codeAppend("}"); | |
146 } | |
147 | |
148 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc, | |
149 GrGLSLExpr4* outputColor, | |
150 GrGLSLExpr4* outputCoverage) { | |
151 // Program builders have a bit of state we need to clear with each effect | |
152 AutoStageAdvance adv(this); | |
153 this->nameExpression(outputColor, "outputColor"); | |
154 this->nameExpression(outputCoverage, "outputCoverage"); | |
155 | |
156 // Enclose custom code in a block to avoid namespace conflicts | |
157 SkString openBrace; | |
158 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name()); | |
159 fFS.codeAppend(openBrace.c_str()); | |
160 fVS.codeAppendf("// Primitive Processor %s\n", proc.name()); | |
161 | |
162 this->emitAndInstallProc(proc, outputColor->c_str(), outputCoverage->c_str()
); | |
163 | |
164 fFS.codeAppend("}"); | |
165 } | |
166 | |
167 void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp, | |
168 int index, | |
169 const char* outColor, | |
170 const char* inColor) { | |
171 GrGLInstalledFragProc* ifp = new GrGLInstalledFragProc; | |
172 | |
173 ifp->fGLProc.reset(fp.createGLSLInstance()); | |
174 | |
175 SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures()); | |
176 this->emitSamplers(fp, &samplers, ifp); | |
177 | |
178 GrGLSLFragmentProcessor::EmitArgs args(&fFS, | |
179 &fUniformHandler, | |
180 this->glslCaps(), | |
181 fp, | |
182 outColor, | |
183 inColor, | |
184 fOutCoords[index], | |
185 samplers); | |
186 ifp->fGLProc->emitCode(args); | |
187 | |
188 // We have to check that effects and the code they emit are consistent, ie i
f an effect | |
189 // asks for dst color, then the emit code needs to follow suit | |
190 verify(fp); | |
191 fFragmentProcessors->fProcs.push_back(ifp); | |
192 } | |
193 | |
194 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp, | |
195 const char* outColor, | |
196 const char* outCoverage) { | |
197 SkASSERT(!fGeometryProcessor); | |
198 fGeometryProcessor = new GrGLInstalledGeoProc; | |
199 | |
200 fGeometryProcessor->fGLProc.reset(gp.createGLSLInstance(*fGpu->glCaps().glsl
Caps())); | |
201 | |
202 SkSTArray<4, GrGLSLTextureSampler> samplers(gp.numTextures()); | |
203 this->emitSamplers(gp, &samplers, fGeometryProcessor); | |
204 | |
205 GrGLSLGeometryProcessor::EmitArgs args(&fVS, | |
206 &fFS, | |
207 &fVaryingHandler, | |
208 &fUniformHandler, | |
209 this->glslCaps(), | |
210 gp, | |
211 outColor, | |
212 outCoverage, | |
213 samplers, | |
214 fCoordTransforms, | |
215 &fOutCoords); | |
216 fGeometryProcessor->fGLProc->emitCode(args); | |
217 | |
218 // We have to check that effects and the code they emit are consistent, ie i
f an effect | |
219 // asks for dst color, then the emit code needs to follow suit | |
220 verify(gp); | |
221 } | |
222 | |
223 void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, | |
224 const GrGLSLExpr4& colorIn, | |
225 const GrGLSLExpr4& coverageIn, | |
226 bool ignoresCoverage) { | |
227 // Program builders have a bit of state we need to clear with each effect | |
228 AutoStageAdvance adv(this); | |
229 | |
230 SkASSERT(!fXferProcessor); | |
231 fXferProcessor = new GrGLInstalledXferProc; | |
232 | |
233 fXferProcessor->fGLProc.reset(xp.createGLSLInstance()); | |
234 | |
235 // Enable dual source secondary output if we have one | |
236 if (xp.hasSecondaryOutput()) { | |
237 fFS.enableSecondaryOutput(); | |
238 } | |
239 | |
240 if (this->glslCaps()->mustDeclareFragmentShaderOutput()) { | |
241 fFS.enableCustomOutput(); | |
242 } | |
243 | |
244 SkString openBrace; | |
245 openBrace.printf("{ // Xfer Processor: %s\n", xp.name()); | |
246 fFS.codeAppend(openBrace.c_str()); | |
247 | |
248 SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures()); | |
249 this->emitSamplers(xp, &samplers, fXferProcessor); | |
250 | |
251 GrGLSLXferProcessor::EmitArgs args(&fFS, | |
252 &fUniformHandler, | |
253 this->glslCaps(), | |
254 xp, colorIn.c_str(), | |
255 ignoresCoverage ? nullptr : coverageIn.c_
str(), | |
256 fFS.getPrimaryColorOutputName(), | |
257 fFS.getSecondaryColorOutputName(), | |
258 samplers); | |
259 fXferProcessor->fGLProc->emitCode(args); | |
260 | |
261 // We have to check that effects and the code they emit are consistent, ie i
f an effect | |
262 // asks for dst color, then the emit code needs to follow suit | |
263 verify(xp); | |
264 fFS.codeAppend("}"); | |
265 } | |
266 | |
267 void GrGLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) { | |
268 // Swizzle the fragment shader outputs if necessary. | |
269 GrSwizzle swizzle; | |
270 swizzle.setFromKey(this->desc().header().fOutputSwizzle); | |
271 if (swizzle != GrSwizzle::RGBA()) { | |
272 fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(), | |
273 fFS.getPrimaryColorOutputName(), | |
274 swizzle.c_str()); | |
275 if (hasSecondaryOutput) { | |
276 fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(), | |
277 fFS.getSecondaryColorOutputName(), | |
278 swizzle.c_str()); | |
279 } | |
280 } | |
281 } | |
282 | |
283 void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { | |
284 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); | |
285 } | |
286 | |
287 void GrGLProgramBuilder::verify(const GrXferProcessor& xp) { | |
288 SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor()); | |
289 } | |
290 | |
291 void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) { | |
292 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); | |
293 } | 71 } |
294 | 72 |
295 static GrSLType get_sampler_type(const GrTextureAccess& access) { | 73 static GrSLType get_sampler_type(const GrTextureAccess& access) { |
296 GrGLTexture* glTexture = static_cast<GrGLTexture*>(access.getTexture()); | 74 GrGLTexture* glTexture = static_cast<GrGLTexture*>(access.getTexture()); |
297 if (glTexture->target() == GR_GL_TEXTURE_EXTERNAL) { | 75 if (glTexture->target() == GR_GL_TEXTURE_EXTERNAL) { |
298 return kSamplerExternal_GrSLType; | 76 return kSamplerExternal_GrSLType; |
299 } else { | 77 } else { |
300 SkASSERT(glTexture->target() == GR_GL_TEXTURE_2D); | 78 SkASSERT(glTexture->target() == GR_GL_TEXTURE_2D); |
301 return kSampler2D_GrSLType; | 79 return kSampler2D_GrSLType; |
302 } | 80 } |
303 } | 81 } |
304 | 82 |
305 template <class Proc> | |
306 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor, | 83 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor, |
307 GrGLSLTextureSampler::TextureSamplerArray*
outSamplers, | 84 GrGLSLTextureSampler::TextureSamplerArray*
outSamplers) { |
308 GrGLInstalledProc<Proc>* ip) { | |
309 SkDEBUGCODE(ip->fSamplersIdx = fSamplerUniforms.count();) | |
310 int numTextures = processor.numTextures(); | 85 int numTextures = processor.numTextures(); |
311 UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextur
es); | 86 UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextur
es); |
312 SkString name; | 87 SkString name; |
313 for (int t = 0; t < numTextures; ++t) { | 88 for (int t = 0; t < numTextures; ++t) { |
314 name.printf("Sampler%d", t); | 89 name.printf("Sampler%d", t); |
315 GrSLType samplerType = get_sampler_type(processor.textureAccess(t)); | 90 GrSLType samplerType = get_sampler_type(processor.textureAccess(t)); |
316 localSamplerUniforms[t] = | 91 localSamplerUniforms[t] = |
317 fUniformHandler.addUniform(GrGLSLUniformHandler::kFragment_Visibilit
y, | 92 fUniformHandler.addUniform(GrGLSLUniformHandler::kFragment_Visibilit
y, |
318 samplerType, kDefault_GrSLPrecision, | 93 samplerType, kDefault_GrSLPrecision, |
319 name.c_str()); | 94 name.c_str()); |
(...skipping 29 matching lines...) Expand all Loading... |
349 *shaderIds->append() = shaderId; | 124 *shaderIds->append() = shaderId; |
350 | 125 |
351 return true; | 126 return true; |
352 } | 127 } |
353 | 128 |
354 GrGLProgram* GrGLProgramBuilder::finalize() { | 129 GrGLProgram* GrGLProgramBuilder::finalize() { |
355 // verify we can get a program id | 130 // verify we can get a program id |
356 GrGLuint programID; | 131 GrGLuint programID; |
357 GL_CALL_RET(programID, CreateProgram()); | 132 GL_CALL_RET(programID, CreateProgram()); |
358 if (0 == programID) { | 133 if (0 == programID) { |
| 134 this->cleanupFragmentProcessors(); |
359 return nullptr; | 135 return nullptr; |
360 } | 136 } |
361 | 137 |
362 // compile shaders and bind attributes / uniforms | 138 // compile shaders and bind attributes / uniforms |
363 SkTDArray<GrGLuint> shadersToDelete; | 139 SkTDArray<GrGLuint> shadersToDelete; |
364 fVS.finalize(GrGLSLUniformHandler::kVertex_Visibility); | 140 fVS.finalize(GrGLSLUniformHandler::kVertex_Visibility); |
365 if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &sha
dersToDelete)) { | 141 if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &sha
dersToDelete)) { |
366 this->cleanupProgram(programID, shadersToDelete); | 142 this->cleanupProgram(programID, shadersToDelete); |
367 return nullptr; | 143 return nullptr; |
368 } | 144 } |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 GL_CALL_RET(location, GetProgramResourceLocation( | 243 GL_CALL_RET(location, GetProgramResourceLocation( |
468 programID, | 244 programID, |
469 GR_GL_FRAGMENT_INPUT, | 245 GR_GL_FRAGMENT_INPUT, |
470 fVaryingHandler.fPathProcVaryingInfos[i].
fVariable.c_str())); | 246 fVaryingHandler.fPathProcVaryingInfos[i].
fVariable.c_str())); |
471 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location; | 247 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location; |
472 } | 248 } |
473 } | 249 } |
474 | 250 |
475 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGL
uint>& shaderIDs) { | 251 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGL
uint>& shaderIDs) { |
476 GL_CALL(DeleteProgram(programID)); | 252 GL_CALL(DeleteProgram(programID)); |
477 cleanupShaders(shaderIDs); | 253 this->cleanupShaders(shaderIDs); |
| 254 this->cleanupFragmentProcessors(); |
478 } | 255 } |
479 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) { | 256 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) { |
480 for (int i = 0; i < shaderIDs.count(); ++i) { | 257 for (int i = 0; i < shaderIDs.count(); ++i) { |
481 GL_CALL(DeleteShader(shaderIDs[i])); | 258 GL_CALL(DeleteShader(shaderIDs[i])); |
482 } | 259 } |
483 } | 260 } |
484 | 261 |
485 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) { | 262 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) { |
486 return new GrGLProgram(fGpu, | 263 return new GrGLProgram(fGpu, |
487 this->desc(), | 264 this->desc(), |
488 fUniformHandles, | 265 fUniformHandles, |
489 programID, | 266 programID, |
490 fUniformHandler.fUniforms, | 267 fUniformHandler.fUniforms, |
491 fVaryingHandler.fPathProcVaryingInfos, | 268 fVaryingHandler.fPathProcVaryingInfos, |
492 fGeometryProcessor, | 269 fGeometryProcessor, |
493 fXferProcessor, | 270 fXferProcessor, |
494 fFragmentProcessors.get(), | 271 fFragmentProcessors, |
495 &fSamplerUniforms); | 272 &fSamplerUniforms); |
496 } | 273 } |
497 | 274 |
498 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
499 | |
500 GrGLInstalledFragProcs::~GrGLInstalledFragProcs() { | |
501 int numProcs = fProcs.count(); | |
502 for (int i = 0; i < numProcs; ++i) { | |
503 delete fProcs[i]; | |
504 } | |
505 } | |
OLD | NEW |