Line data Source code
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 "glsl/GrGLSLProgramBuilder.h"
9 :
10 : #include "GrCaps.h"
11 : #include "GrPipeline.h"
12 : #include "GrShaderCaps.h"
13 : #include "GrTexturePriv.h"
14 : #include "glsl/GrGLSLFragmentProcessor.h"
15 : #include "glsl/GrGLSLGeometryProcessor.h"
16 : #include "glsl/GrGLSLVarying.h"
17 : #include "glsl/GrGLSLXferProcessor.h"
18 :
19 : const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
20 :
21 0 : GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrPipeline& pipeline,
22 : const GrPrimitiveProcessor& primProc,
23 0 : GrProgramDesc* desc)
24 : : fVS(this)
25 : , fGS(this)
26 : , fFS(this)
27 : , fStageIndex(-1)
28 : , fPipeline(pipeline)
29 : , fPrimProc(primProc)
30 : , fDesc(desc)
31 : , fGeometryProcessor(nullptr)
32 : , fXferProcessor(nullptr)
33 : , fNumVertexSamplers(0)
34 : , fNumGeometrySamplers(0)
35 : , fNumFragmentSamplers(0)
36 : , fNumVertexImageStorages(0)
37 : , fNumGeometryImageStorages(0)
38 0 : , fNumFragmentImageStorages(0) {
39 0 : }
40 :
41 0 : void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders,
42 : uint32_t featureBit,
43 : const char* extensionName) {
44 0 : if (shaders & kVertex_GrShaderFlag) {
45 0 : fVS.addFeature(featureBit, extensionName);
46 : }
47 0 : if (shaders & kGeometry_GrShaderFlag) {
48 0 : SkASSERT(this->primitiveProcessor().willUseGeoShader());
49 0 : fGS.addFeature(featureBit, extensionName);
50 : }
51 0 : if (shaders & kFragment_GrShaderFlag) {
52 0 : fFS.addFeature(featureBit, extensionName);
53 : }
54 0 : }
55 :
56 0 : bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
57 : GrGLSLExpr4* inputCoverage) {
58 : // First we loop over all of the installed processors and collect coord transforms. These will
59 : // be sent to the GrGLSLPrimitiveProcessor in its emitCode function
60 0 : const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
61 :
62 0 : this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage);
63 :
64 0 : this->emitAndInstallFragProcs(inputColor, inputCoverage);
65 0 : this->emitAndInstallXferProc(*inputColor, *inputCoverage);
66 0 : this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
67 :
68 0 : return this->checkSamplerCounts() && this->checkImageStorageCounts();
69 : }
70 :
71 0 : void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
72 : GrGLSLExpr4* outputColor,
73 : GrGLSLExpr4* outputCoverage) {
74 : // Program builders have a bit of state we need to clear with each effect
75 0 : AutoStageAdvance adv(this);
76 0 : this->nameExpression(outputColor, "outputColor");
77 0 : this->nameExpression(outputCoverage, "outputCoverage");
78 :
79 0 : const char* distanceVectorName = nullptr;
80 0 : if (this->fPipeline.usesDistanceVectorField() && proc.implementsDistanceVector()) {
81 : // Each individual user (FP) of the distance vector must be able to handle having this
82 : // variable be undeclared. There is no single default value that will yield a reasonable
83 : // result for all users.
84 0 : distanceVectorName = fFS.distanceVectorName();
85 0 : fFS.codeAppend( "// Normalized vector to the closest geometric edge (in device space)\n");
86 0 : fFS.codeAppend( "// Distance to the edge encoded in the z-component\n");
87 0 : fFS.codeAppendf("vec4 %s;", distanceVectorName);
88 : }
89 :
90 0 : SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid());
91 0 : GrShaderFlags rtAdjustVisibility = kVertex_GrShaderFlag;
92 0 : if (proc.willUseGeoShader()) {
93 0 : rtAdjustVisibility |= kGeometry_GrShaderFlag;
94 : }
95 0 : fUniformHandles.fRTAdjustmentUni = this->uniformHandler()->addUniform(rtAdjustVisibility,
96 : kVec4f_GrSLType,
97 : kHigh_GrSLPrecision,
98 0 : "rtAdjustment");
99 : const char* rtAdjustName =
100 0 : this->uniformHandler()->getUniformCStr(fUniformHandles.fRTAdjustmentUni);
101 :
102 : // Enclose custom code in a block to avoid namespace conflicts
103 0 : SkString openBrace;
104 0 : openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
105 0 : fFS.codeAppend(openBrace.c_str());
106 0 : fVS.codeAppendf("// Primitive Processor %s\n", proc.name());
107 :
108 0 : SkASSERT(!fGeometryProcessor);
109 0 : fGeometryProcessor = proc.createGLSLInstance(*this->shaderCaps());
110 :
111 0 : SkSTArray<4, SamplerHandle> texSamplers(proc.numTextureSamplers());
112 0 : SkSTArray<2, SamplerHandle> bufferSamplers(proc.numBuffers());
113 0 : SkSTArray<2, ImageStorageHandle> imageStorages(proc.numImageStorages());
114 0 : this->emitSamplersAndImageStorages(proc, &texSamplers, &bufferSamplers, &imageStorages);
115 :
116 : GrGLSLPrimitiveProcessor::FPCoordTransformHandler transformHandler(fPipeline,
117 0 : &fTransformedCoordVars);
118 : GrGLSLGeometryProcessor::EmitArgs args(&fVS,
119 0 : proc.willUseGeoShader() ? &fGS : nullptr,
120 : &fFS,
121 0 : this->varyingHandler(),
122 0 : this->uniformHandler(),
123 : this->shaderCaps(),
124 : proc,
125 : outputColor->c_str(),
126 : outputCoverage->c_str(),
127 : distanceVectorName,
128 : rtAdjustName,
129 0 : texSamplers.begin(),
130 0 : bufferSamplers.begin(),
131 0 : imageStorages.begin(),
132 0 : &transformHandler);
133 0 : fGeometryProcessor->emitCode(args);
134 :
135 : // We have to check that effects and the code they emit are consistent, ie if an effect
136 : // asks for dst color, then the emit code needs to follow suit
137 0 : SkDEBUGCODE(verify(proc);)
138 :
139 0 : fFS.codeAppend("}");
140 0 : }
141 :
142 0 : void GrGLSLProgramBuilder::emitAndInstallFragProcs(GrGLSLExpr4* color, GrGLSLExpr4* coverage) {
143 0 : int transformedCoordVarsIdx = 0;
144 0 : GrGLSLExpr4** inOut = &color;
145 0 : for (int i = 0; i < this->pipeline().numFragmentProcessors(); ++i) {
146 0 : if (i == this->pipeline().numColorFragmentProcessors()) {
147 0 : inOut = &coverage;
148 : }
149 0 : GrGLSLExpr4 output;
150 0 : const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
151 0 : this->emitAndInstallFragProc(fp, i, transformedCoordVarsIdx, **inOut, &output);
152 0 : GrFragmentProcessor::Iter iter(&fp);
153 0 : while (const GrFragmentProcessor* fp = iter.next()) {
154 0 : transformedCoordVarsIdx += fp->numCoordTransforms();
155 0 : }
156 0 : **inOut = output;
157 : }
158 0 : }
159 :
160 : // TODO Processors cannot output zeros because an empty string is all 1s
161 : // the fix is to allow effects to take the GrGLSLExpr4 directly
162 0 : void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
163 : int index,
164 : int transformedCoordVarsIdx,
165 : const GrGLSLExpr4& input,
166 : GrGLSLExpr4* output) {
167 : // Program builders have a bit of state we need to clear with each effect
168 0 : AutoStageAdvance adv(this);
169 0 : this->nameExpression(output, "output");
170 :
171 : // Enclose custom code in a block to avoid namespace conflicts
172 0 : SkString openBrace;
173 0 : openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name());
174 0 : fFS.codeAppend(openBrace.c_str());
175 :
176 0 : GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance();
177 :
178 0 : SkSTArray<4, SamplerHandle> textureSamplerArray(fp.numTextureSamplers());
179 0 : SkSTArray<2, SamplerHandle> bufferSamplerArray(fp.numBuffers());
180 0 : SkSTArray<2, ImageStorageHandle> imageStorageArray(fp.numImageStorages());
181 0 : GrFragmentProcessor::Iter iter(&fp);
182 0 : while (const GrFragmentProcessor* subFP = iter.next()) {
183 0 : this->emitSamplersAndImageStorages(*subFP, &textureSamplerArray, &bufferSamplerArray,
184 0 : &imageStorageArray);
185 0 : }
186 :
187 0 : const GrShaderVar* coordVars = fTransformedCoordVars.begin() + transformedCoordVarsIdx;
188 0 : GrGLSLFragmentProcessor::TransformedCoordVars coords(&fp, coordVars);
189 0 : GrGLSLFragmentProcessor::TextureSamplers textureSamplers(&fp, textureSamplerArray.begin());
190 0 : GrGLSLFragmentProcessor::BufferSamplers bufferSamplers(&fp, bufferSamplerArray.begin());
191 0 : GrGLSLFragmentProcessor::ImageStorages imageStorages(&fp, imageStorageArray.begin());
192 : GrGLSLFragmentProcessor::EmitArgs args(&fFS,
193 0 : this->uniformHandler(),
194 : this->shaderCaps(),
195 : fp,
196 : output->c_str(),
197 0 : input.isOnes() ? nullptr : input.c_str(),
198 : coords,
199 : textureSamplers,
200 : bufferSamplers,
201 : imageStorages,
202 0 : this->primitiveProcessor().implementsDistanceVector());
203 :
204 0 : fragProc->emitCode(args);
205 :
206 : // We have to check that effects and the code they emit are consistent, ie if an effect
207 : // asks for dst color, then the emit code needs to follow suit
208 0 : SkDEBUGCODE(verify(fp);)
209 0 : fFragmentProcessors.push_back(fragProc);
210 :
211 0 : fFS.codeAppend("}");
212 0 : }
213 :
214 0 : void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrGLSLExpr4& colorIn,
215 : const GrGLSLExpr4& coverageIn) {
216 : // Program builders have a bit of state we need to clear with each effect
217 0 : AutoStageAdvance adv(this);
218 :
219 0 : SkASSERT(!fXferProcessor);
220 0 : const GrXferProcessor& xp = fPipeline.getXferProcessor();
221 0 : fXferProcessor = xp.createGLSLInstance();
222 :
223 : // Enable dual source secondary output if we have one
224 0 : if (xp.hasSecondaryOutput()) {
225 0 : fFS.enableSecondaryOutput();
226 : }
227 :
228 0 : if (this->shaderCaps()->mustDeclareFragmentShaderOutput()) {
229 0 : fFS.enableCustomOutput();
230 : }
231 :
232 0 : SkString openBrace;
233 0 : openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
234 0 : fFS.codeAppend(openBrace.c_str());
235 :
236 0 : SamplerHandle dstTextureSamplerHandle;
237 0 : GrSurfaceOrigin dstTextureOrigin = kTopLeft_GrSurfaceOrigin;
238 0 : if (GrTexture* dstTexture = fPipeline.dstTexture()) {
239 : // GrProcessor::TextureSampler sampler(dstTexture);
240 0 : SkString name("DstTextureSampler");
241 : dstTextureSamplerHandle =
242 0 : this->emitSampler(dstTexture->texturePriv().samplerType(), dstTexture->config(),
243 0 : "DstTextureSampler", kFragment_GrShaderFlag);
244 0 : dstTextureOrigin = dstTexture->origin();
245 0 : SkASSERT(kTextureExternalSampler_GrSLType != dstTexture->texturePriv().samplerType());
246 : }
247 :
248 : GrGLSLXferProcessor::EmitArgs args(&fFS,
249 0 : this->uniformHandler(),
250 : this->shaderCaps(),
251 : xp,
252 : colorIn.c_str(),
253 : coverageIn.c_str(),
254 : fFS.getPrimaryColorOutputName(),
255 : fFS.getSecondaryColorOutputName(),
256 : dstTextureSamplerHandle,
257 0 : dstTextureOrigin);
258 0 : fXferProcessor->emitCode(args);
259 :
260 : // We have to check that effects and the code they emit are consistent, ie if an effect
261 : // asks for dst color, then the emit code needs to follow suit
262 0 : SkDEBUGCODE(verify(xp);)
263 0 : fFS.codeAppend("}");
264 0 : }
265 :
266 0 : void GrGLSLProgramBuilder::emitSamplersAndImageStorages(
267 : const GrResourceIOProcessor& processor,
268 : SkTArray<SamplerHandle>* outTexSamplerHandles,
269 : SkTArray<SamplerHandle>* outBufferSamplerHandles,
270 : SkTArray<ImageStorageHandle>* outImageStorageHandles) {
271 0 : SkString name;
272 0 : int numTextureSamplers = processor.numTextureSamplers();
273 0 : for (int t = 0; t < numTextureSamplers; ++t) {
274 0 : const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(t);
275 0 : name.printf("TextureSampler_%d", outTexSamplerHandles->count());
276 0 : GrSLType samplerType = sampler.texture()->texturePriv().samplerType();
277 0 : if (kTextureExternalSampler_GrSLType == samplerType) {
278 : const char* externalFeatureString =
279 0 : this->shaderCaps()->externalTextureExtensionString();
280 : // We shouldn't ever create a GrGLTexture that requires external sampler type
281 0 : SkASSERT(externalFeatureString);
282 0 : this->addFeature(sampler.visibility(),
283 : 1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature,
284 0 : externalFeatureString);
285 : }
286 0 : outTexSamplerHandles->emplace_back(this->emitSampler(
287 0 : samplerType, sampler.texture()->config(), name.c_str(), sampler.visibility()));
288 : }
289 0 : if (int numBuffers = processor.numBuffers()) {
290 0 : SkASSERT(this->shaderCaps()->texelBufferSupport());
291 0 : GrShaderFlags texelBufferVisibility = kNone_GrShaderFlags;
292 :
293 0 : for (int b = 0; b < numBuffers; ++b) {
294 0 : const GrResourceIOProcessor::BufferAccess& access = processor.bufferAccess(b);
295 0 : name.printf("BufferSampler_%d", outBufferSamplerHandles->count());
296 : outBufferSamplerHandles->emplace_back(
297 0 : this->emitSampler(kBufferSampler_GrSLType, access.texelConfig(), name.c_str(),
298 0 : access.visibility()));
299 0 : texelBufferVisibility |= access.visibility();
300 : }
301 :
302 0 : if (const char* extension = this->shaderCaps()->texelBufferExtensionString()) {
303 : this->addFeature(texelBufferVisibility,
304 : 1 << GrGLSLShaderBuilder::kTexelBuffer_GLSLPrivateFeature,
305 0 : extension);
306 : }
307 : }
308 0 : int numImageStorages = processor.numImageStorages();
309 0 : for (int i = 0; i < numImageStorages; ++i) {
310 : const GrResourceIOProcessor::ImageStorageAccess& imageStorageAccess =
311 0 : processor.imageStorageAccess(i);
312 0 : name.printf("Image_%d", outImageStorageHandles->count());
313 : outImageStorageHandles->emplace_back(
314 0 : this->emitImageStorage(imageStorageAccess, name.c_str()));
315 : }
316 0 : }
317 :
318 0 : GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitSampler(GrSLType samplerType,
319 : GrPixelConfig config,
320 : const char* name,
321 : GrShaderFlags visibility) {
322 0 : if (visibility & kVertex_GrShaderFlag) {
323 0 : ++fNumVertexSamplers;
324 : }
325 0 : if (visibility & kGeometry_GrShaderFlag) {
326 0 : SkASSERT(this->primitiveProcessor().willUseGeoShader());
327 0 : ++fNumGeometrySamplers;
328 : }
329 0 : if (visibility & kFragment_GrShaderFlag) {
330 0 : ++fNumFragmentSamplers;
331 : }
332 0 : GrSLPrecision precision = this->shaderCaps()->samplerPrecision(config, visibility);
333 0 : GrSwizzle swizzle = this->shaderCaps()->configTextureSwizzle(config);
334 0 : return this->uniformHandler()->addSampler(visibility, swizzle, samplerType, precision, name);
335 : }
336 :
337 0 : GrGLSLProgramBuilder::ImageStorageHandle GrGLSLProgramBuilder::emitImageStorage(
338 : const GrResourceIOProcessor::ImageStorageAccess& access, const char* name) {
339 0 : if (access.visibility() & kVertex_GrShaderFlag) {
340 0 : ++fNumVertexImageStorages;
341 : }
342 0 : if (access.visibility() & kGeometry_GrShaderFlag) {
343 0 : SkASSERT(this->primitiveProcessor().willUseGeoShader());
344 0 : ++fNumGeometryImageStorages;
345 : }
346 0 : if (access.visibility() & kFragment_GrShaderFlag) {
347 0 : ++fNumFragmentImageStorages;
348 : }
349 0 : GrSLType uniformType = access.texture()->texturePriv().imageStorageType();
350 0 : return this->uniformHandler()->addImageStorage(access.visibility(), uniformType,
351 : access.format(), access.memoryModel(),
352 0 : access.restrict(), access.ioType(), name);
353 : }
354 :
355 0 : void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
356 : // Swizzle the fragment shader outputs if necessary.
357 0 : GrSwizzle swizzle;
358 0 : swizzle.setFromKey(this->desc()->header().fOutputSwizzle);
359 0 : if (swizzle != GrSwizzle::RGBA()) {
360 0 : fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(),
361 : fFS.getPrimaryColorOutputName(),
362 0 : swizzle.c_str());
363 0 : if (hasSecondaryOutput) {
364 0 : fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(),
365 : fFS.getSecondaryColorOutputName(),
366 0 : swizzle.c_str());
367 : }
368 : }
369 0 : }
370 :
371 0 : bool GrGLSLProgramBuilder::checkSamplerCounts() {
372 0 : const GrShaderCaps& shaderCaps = *this->shaderCaps();
373 0 : if (fNumVertexSamplers > shaderCaps.maxVertexSamplers()) {
374 0 : GrCapsDebugf(this->caps(), "Program would use too many vertex samplers\n");
375 0 : return false;
376 : }
377 0 : if (fNumGeometrySamplers > shaderCaps.maxGeometrySamplers()) {
378 0 : GrCapsDebugf(this->caps(), "Program would use too many geometry samplers\n");
379 0 : return false;
380 : }
381 0 : if (fNumFragmentSamplers > shaderCaps.maxFragmentSamplers()) {
382 0 : GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n");
383 0 : return false;
384 : }
385 : // If the same sampler is used in two different shaders, it counts as two combined samplers.
386 0 : int numCombinedSamplers = fNumVertexSamplers + fNumGeometrySamplers + fNumFragmentSamplers;
387 0 : if (numCombinedSamplers > shaderCaps.maxCombinedSamplers()) {
388 0 : GrCapsDebugf(this->caps(), "Program would use too many combined samplers\n");
389 0 : return false;
390 : }
391 0 : return true;
392 : }
393 :
394 0 : bool GrGLSLProgramBuilder::checkImageStorageCounts() {
395 0 : const GrShaderCaps& shaderCaps = *this->shaderCaps();
396 0 : if (fNumVertexImageStorages > shaderCaps.maxVertexImageStorages()) {
397 0 : GrCapsDebugf(this->caps(), "Program would use too many vertex images\n");
398 0 : return false;
399 : }
400 0 : if (fNumGeometryImageStorages > shaderCaps.maxGeometryImageStorages()) {
401 0 : GrCapsDebugf(this->caps(), "Program would use too many geometry images\n");
402 0 : return false;
403 : }
404 0 : if (fNumFragmentImageStorages > shaderCaps.maxFragmentImageStorages()) {
405 0 : GrCapsDebugf(this->caps(), "Program would use too many fragment images\n");
406 0 : return false;
407 : }
408 : // If the same image is used in two different shaders, it counts as two combined images.
409 0 : int numCombinedImages = fNumVertexImageStorages + fNumGeometryImageStorages +
410 0 : fNumFragmentImageStorages;
411 0 : if (numCombinedImages > shaderCaps.maxCombinedImageStorages()) {
412 0 : GrCapsDebugf(this->caps(), "Program would use too many combined images\n");
413 0 : return false;
414 : }
415 0 : return true;
416 : }
417 :
418 : #ifdef SK_DEBUG
419 0 : void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
420 0 : SkASSERT(fFS.usedProcessorFeatures() == gp.requiredFeatures());
421 0 : }
422 :
423 0 : void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
424 0 : SkASSERT(fFS.usedProcessorFeatures() == xp.requiredFeatures());
425 0 : SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
426 0 : }
427 :
428 0 : void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
429 0 : SkASSERT(fFS.usedProcessorFeatures() == fp.requiredFeatures());
430 0 : }
431 : #endif
432 :
433 0 : void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) {
434 0 : if ('\0' == prefix) {
435 0 : *out = name;
436 : } else {
437 0 : out->printf("%c%s", prefix, name);
438 : }
439 0 : if (mangle) {
440 0 : if (out->endsWith('_')) {
441 : // Names containing "__" are reserved.
442 0 : out->append("x");
443 : }
444 0 : out->appendf("_Stage%d%s", fStageIndex, fFS.getMangleString().c_str());
445 : }
446 0 : }
447 :
448 0 : void GrGLSLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) {
449 : // create var to hold stage result. If we already have a valid output name, just use that
450 : // otherwise create a new mangled one. This name is only valid if we are reordering stages
451 : // and have to tell stage exactly where to put its output.
452 0 : SkString outName;
453 0 : if (output->isValid()) {
454 0 : outName = output->c_str();
455 : } else {
456 0 : this->nameVariable(&outName, '\0', baseName);
457 : }
458 0 : fFS.codeAppendf("vec4 %s;", outName.c_str());
459 0 : *output = outName;
460 0 : }
461 :
462 0 : void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
463 0 : this->uniformHandler()->appendUniformDecls(visibility, out);
464 0 : }
465 :
466 0 : void GrGLSLProgramBuilder::addRTHeightUniform(const char* name) {
467 0 : SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
468 0 : GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
469 : fUniformHandles.fRTHeightUni =
470 : uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag,
471 : kFloat_GrSLType, kDefault_GrSLPrecision,
472 0 : name, false, 0, nullptr);
473 0 : }
474 :
475 0 : void GrGLSLProgramBuilder::cleanupFragmentProcessors() {
476 0 : for (int i = 0; i < fFragmentProcessors.count(); ++i) {
477 0 : delete fFragmentProcessors[i];
478 : }
479 0 : }
480 :
481 0 : void GrGLSLProgramBuilder::finalizeShaders() {
482 0 : this->varyingHandler()->finalize();
483 0 : fVS.finalize(kVertex_GrShaderFlag);
484 0 : if (this->primitiveProcessor().willUseGeoShader()) {
485 0 : SkASSERT(this->shaderCaps()->geometryShaderSupport());
486 0 : fGS.finalize(kGeometry_GrShaderFlag);
487 : }
488 0 : fFS.finalize(kFragment_GrShaderFlag);
489 0 : }
|