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 "src/gpu/glsl/GrGLSLProgramBuilder.h"
9
10 #include <memory>
11
12 #include "src/gpu/GrCaps.h"
13 #include "src/gpu/GrPipeline.h"
14 #include "src/gpu/GrRenderTarget.h"
15 #include "src/gpu/GrShaderCaps.h"
16 #include "src/gpu/GrTexture.h"
17 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
18 #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
19 #include "src/gpu/glsl/GrGLSLVarying.h"
20 #include "src/gpu/glsl/GrGLSLXferProcessor.h"
21 #include "src/sksl/SkSLCompiler.h"
22 #include "src/sksl/dsl/priv/DSLFPs.h"
23
24 const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
25
GrGLSLProgramBuilder(const GrProgramDesc & desc,const GrProgramInfo & programInfo)26 GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrProgramDesc& desc,
27 const GrProgramInfo& programInfo)
28 : fVS(this)
29 , fGS(this)
30 , fFS(this)
31 , fStageIndex(-1)
32 , fDesc(desc)
33 , fProgramInfo(programInfo)
34 , fGeometryProcessor(nullptr)
35 , fXferProcessor(nullptr)
36 , fNumFragmentSamplers(0) {}
37
38 GrGLSLProgramBuilder::~GrGLSLProgramBuilder() = default;
39
addFeature(GrShaderFlags shaders,uint32_t featureBit,const char * extensionName)40 void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders,
41 uint32_t featureBit,
42 const char* extensionName) {
43 if (shaders & kVertex_GrShaderFlag) {
44 fVS.addFeature(featureBit, extensionName);
45 }
46 if (shaders & kGeometry_GrShaderFlag) {
47 SkASSERT(this->geometryProcessor().willUseGeoShader());
48 fGS.addFeature(featureBit, extensionName);
49 }
50 if (shaders & kFragment_GrShaderFlag) {
51 fFS.addFeature(featureBit, extensionName);
52 }
53 }
54
emitAndInstallProcs()55 bool GrGLSLProgramBuilder::emitAndInstallProcs() {
56 // First we loop over all of the installed processors and collect coord transforms. These will
57 // be sent to the GrGLSLGeometryProcessor in its emitCode function
58 SkSL::dsl::Start(this->shaderCompiler());
59 SkString inputColor;
60 SkString inputCoverage;
61 if (!this->emitAndInstallPrimProc(&inputColor, &inputCoverage)) {
62 return false;
63 }
64 if (!this->emitAndInstallFragProcs(&inputColor, &inputCoverage)) {
65 return false;
66 }
67 if (!this->emitAndInstallXferProc(inputColor, inputCoverage)) {
68 return false;
69 }
70 fGeometryProcessor->emitTransformCode(&fVS, this->uniformHandler());
71 SkSL::dsl::End();
72
73 return this->checkSamplerCounts();
74 }
75
emitAndInstallPrimProc(SkString * outputColor,SkString * outputCoverage)76 bool GrGLSLProgramBuilder::emitAndInstallPrimProc(SkString* outputColor, SkString* outputCoverage) {
77 const GrGeometryProcessor& geomProc = this->geometryProcessor();
78
79 // Program builders have a bit of state we need to clear with each effect
80 AutoStageAdvance adv(this);
81 this->nameExpression(outputColor, "outputColor");
82 this->nameExpression(outputCoverage, "outputCoverage");
83
84 SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid());
85 GrShaderFlags rtAdjustVisibility;
86 if (geomProc.willUseGeoShader()) {
87 rtAdjustVisibility = kGeometry_GrShaderFlag;
88 } else if (geomProc.willUseTessellationShaders()) {
89 rtAdjustVisibility = kTessEvaluation_GrShaderFlag;
90 } else {
91 rtAdjustVisibility = kVertex_GrShaderFlag;
92 }
93 fUniformHandles.fRTAdjustmentUni = this->uniformHandler()->addUniform(
94 nullptr, rtAdjustVisibility, kFloat4_GrSLType, SkSL::Compiler::RTADJUST_NAME);
95
96 fFS.codeAppendf("// Stage %d, %s\n", fStageIndex, geomProc.name());
97 fVS.codeAppendf("// Primitive Processor %s\n", geomProc.name());
98
99 SkASSERT(!fGeometryProcessor);
100 fGeometryProcessor.reset(geomProc.createGLSLInstance(*this->shaderCaps()));
101
102 SkAutoSTArray<4, SamplerHandle> texSamplers(geomProc.numTextureSamplers());
103 for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
104 SkString name;
105 name.printf("TextureSampler_%d", i);
106 const auto& sampler = geomProc.textureSampler(i);
107 texSamplers[i] = this->emitSampler(geomProc.textureSampler(i).backendFormat(),
108 sampler.samplerState(),
109 sampler.swizzle(),
110 name.c_str());
111 if (!texSamplers[i].isValid()) {
112 return false;
113 }
114 }
115
116 GrGLSLGeometryProcessor::FPCoordTransformHandler transformHandler(this->pipeline(),
117 &fTransformedCoordVars);
118 GrGLSLGeometryProcessor::EmitArgs args(&fVS,
119 geomProc.willUseGeoShader() ? &fGS : nullptr,
120 &fFS,
121 this->varyingHandler(),
122 this->uniformHandler(),
123 this->shaderCaps(),
124 geomProc,
125 outputColor->c_str(),
126 outputCoverage->c_str(),
127 texSamplers.get(),
128 &transformHandler);
129 fGeometryProcessor->emitCode(args);
130
131 // We have to check that effects and the code they emit are consistent, ie if an effect
132 // asks for dst color, then the emit code needs to follow suit
133 SkDEBUGCODE(verify(geomProc);)
134
135 return true;
136 }
137
emitAndInstallFragProcs(SkString * color,SkString * coverage)138 bool GrGLSLProgramBuilder::emitAndInstallFragProcs(SkString* color, SkString* coverage) {
139 int transformedCoordVarsIdx = 0;
140 int fpCount = this->pipeline().numFragmentProcessors();
141 SkASSERT(fFPImpls.empty());
142 fFPImpls.reserve(fpCount);
143 for (int i = 0; i < fpCount; ++i) {
144 SkString* inOut = this->pipeline().isColorFragmentProcessor(i) ? color : coverage;
145 SkString output;
146 const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
147 fFPImpls.push_back(fp.makeProgramImpl());
148 output = this->emitFragProc(fp,
149 *fFPImpls.back(),
150 transformedCoordVarsIdx,
151 *inOut,
152 output);
153 if (output.isEmpty()) {
154 return false;
155 }
156 for (const auto& subFP : GrFragmentProcessor::FPRange(fp)) {
157 transformedCoordVarsIdx += subFP.numVaryingCoordsUsed();
158 }
159 *inOut = std::move(output);
160 }
161 return true;
162 }
163
emitFragProc(const GrFragmentProcessor & fp,GrGLSLFragmentProcessor & glslFP,int transformedCoordVarsIdx,const SkString & input,SkString output)164 SkString GrGLSLProgramBuilder::emitFragProc(const GrFragmentProcessor& fp,
165 GrGLSLFragmentProcessor& glslFP,
166 int transformedCoordVarsIdx,
167 const SkString& input,
168 SkString output) {
169 SkASSERT(input.size());
170 // Program builders have a bit of state we need to clear with each effect
171 AutoStageAdvance adv(this);
172 this->nameExpression(&output, "output");
173 fFS.codeAppendf("half4 %s;", output.c_str());
174
175 int samplerIdx = 0;
176 for (auto [subFP, subGLSLFP] : GrGLSLFragmentProcessor::ParallelRange(fp, glslFP)) {
177 if (auto* te = subFP.asTextureEffect()) {
178 SkString name;
179 name.printf("TextureSampler_%d", samplerIdx++);
180
181 GrSamplerState samplerState = te->samplerState();
182 const GrBackendFormat& format = te->view().proxy()->backendFormat();
183 GrSwizzle swizzle = te->view().swizzle();
184 SamplerHandle handle = this->emitSampler(format, samplerState, swizzle, name.c_str());
185 if (!handle.isValid()) {
186 return {};
187 }
188 static_cast<GrTextureEffect::Impl&>(subGLSLFP).setSamplerHandle(handle);
189 }
190 }
191 const GrShaderVar* coordVars = fTransformedCoordVars.begin() + transformedCoordVarsIdx;
192 GrGLSLFragmentProcessor::TransformedCoordVars coords(&fp, coordVars);
193 GrGLSLFragmentProcessor::EmitArgs args(&fFS,
194 this->uniformHandler(),
195 this->shaderCaps(),
196 fp,
197 "_input",
198 "_coords",
199 coords);
200 auto name = fFS.writeProcessorFunction(&glslFP, args);
201 fFS.codeAppendf("%s = %s(%s);", output.c_str(), name.c_str(), input.c_str());
202
203 // We have to check that effects and the code they emit are consistent, ie if an effect asks
204 // for dst color, then the emit code needs to follow suit
205 SkDEBUGCODE(verify(fp);)
206
207 return output;
208 }
209
emitAndInstallXferProc(const SkString & colorIn,const SkString & coverageIn)210 bool GrGLSLProgramBuilder::emitAndInstallXferProc(const SkString& colorIn,
211 const SkString& coverageIn) {
212 // Program builders have a bit of state we need to clear with each effect
213 AutoStageAdvance adv(this);
214
215 SkASSERT(!fXferProcessor);
216 const GrXferProcessor& xp = this->pipeline().getXferProcessor();
217 fXferProcessor.reset(xp.createGLSLInstance());
218
219 // Enable dual source secondary output if we have one
220 if (xp.hasSecondaryOutput()) {
221 fFS.enableSecondaryOutput();
222 }
223
224 if (this->shaderCaps()->mustDeclareFragmentShaderOutput()) {
225 fFS.enableCustomOutput();
226 }
227
228 SkString openBrace;
229 openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
230 fFS.codeAppend(openBrace.c_str());
231
232 SamplerHandle dstTextureSamplerHandle;
233 GrSurfaceOrigin dstTextureOrigin = kTopLeft_GrSurfaceOrigin;
234
235 const GrSurfaceProxyView& dstView = this->pipeline().dstProxyView();
236 if (this->pipeline().usesDstTexture()) {
237 GrTextureProxy* dstTextureProxy = dstView.asTextureProxy();
238 SkASSERT(dstTextureProxy);
239 const GrSwizzle& swizzle = dstView.swizzle();
240 dstTextureSamplerHandle = this->emitSampler(dstTextureProxy->backendFormat(),
241 GrSamplerState(), swizzle, "DstTextureSampler");
242 if (!dstTextureSamplerHandle.isValid()) {
243 return false;
244 }
245 dstTextureOrigin = dstView.origin();
246 SkASSERT(dstTextureProxy->textureType() != GrTextureType::kExternal);
247 } else if (this->pipeline().usesInputAttachment()) {
248 const GrSwizzle& swizzle = dstView.swizzle();
249 dstTextureSamplerHandle = this->emitInputSampler(swizzle, "DstTextureInput");
250 if (!dstTextureSamplerHandle.isValid()) {
251 return false;
252 }
253 }
254
255 SkString finalInColor = colorIn.size() ? colorIn : SkString("float4(1)");
256
257 GrGLSLXferProcessor::EmitArgs args(&fFS,
258 this->uniformHandler(),
259 this->shaderCaps(),
260 xp,
261 finalInColor.c_str(),
262 coverageIn.size() ? coverageIn.c_str() : "float4(1)",
263 fFS.getPrimaryColorOutputName(),
264 fFS.getSecondaryColorOutputName(),
265 this->pipeline().dstSampleType(),
266 dstTextureSamplerHandle,
267 dstTextureOrigin,
268 this->pipeline().writeSwizzle());
269 fXferProcessor->emitCode(args);
270
271 // We have to check that effects and the code they emit are consistent, ie if an effect
272 // asks for dst color, then the emit code needs to follow suit
273 SkDEBUGCODE(verify(xp);)
274 fFS.codeAppend("}");
275 return true;
276 }
277
emitSampler(const GrBackendFormat & backendFormat,GrSamplerState state,const GrSwizzle & swizzle,const char * name)278 GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitSampler(
279 const GrBackendFormat& backendFormat, GrSamplerState state, const GrSwizzle& swizzle,
280 const char* name) {
281 ++fNumFragmentSamplers;
282 return this->uniformHandler()->addSampler(backendFormat, state, swizzle, name,
283 this->shaderCaps());
284 }
285
emitInputSampler(const GrSwizzle & swizzle,const char * name)286 GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitInputSampler(const GrSwizzle& swizzle,
287 const char* name) {
288 return this->uniformHandler()->addInputSampler(swizzle, name);
289 }
290
checkSamplerCounts()291 bool GrGLSLProgramBuilder::checkSamplerCounts() {
292 const GrShaderCaps& shaderCaps = *this->shaderCaps();
293 if (fNumFragmentSamplers > shaderCaps.maxFragmentSamplers()) {
294 GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n");
295 return false;
296 }
297 return true;
298 }
299
300 #ifdef SK_DEBUG
verify(const GrGeometryProcessor & geomProc)301 void GrGLSLProgramBuilder::verify(const GrGeometryProcessor& geomProc) {
302 SkASSERT(!fFS.fHasReadDstColorThisStage_DebugOnly);
303 SkASSERT(fFS.fUsedProcessorFeaturesThisStage_DebugOnly == geomProc.requestedFeatures());
304 }
305
verify(const GrFragmentProcessor & fp)306 void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
307 SkASSERT(!fFS.fHasReadDstColorThisStage_DebugOnly);
308 SkASSERT(fFS.fUsedProcessorFeaturesThisStage_DebugOnly == fp.requestedFeatures());
309 }
310
verify(const GrXferProcessor & xp)311 void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
312 SkASSERT(xp.willReadDstColor() == fFS.fHasReadDstColorThisStage_DebugOnly);
313 SkASSERT(fFS.fUsedProcessorFeaturesThisStage_DebugOnly == xp.requestedFeatures());
314 }
315 #endif
316
nameVariable(char prefix,const char * name,bool mangle)317 SkString GrGLSLProgramBuilder::nameVariable(char prefix, const char* name, bool mangle) {
318 SkString out;
319 if ('\0' == prefix) {
320 out = name;
321 } else {
322 out.printf("%c%s", prefix, name);
323 }
324 if (mangle) {
325 // Names containing "__" are reserved; add "x" if needed to avoid consecutive underscores.
326 const char *underscoreSplitter = out.endsWith('_') ? "x" : "";
327
328 out.appendf("%s_Stage%d%s", underscoreSplitter, fStageIndex, fFS.getMangleString().c_str());
329 }
330 return out;
331 }
332
nameExpression(SkString * output,const char * baseName)333 void GrGLSLProgramBuilder::nameExpression(SkString* output, const char* baseName) {
334 // Name a variable to hold stage result. If we already have a valid output name, use that as-is;
335 // otherwise, create a new mangled one.
336 if (output->isEmpty()) {
337 *output = this->nameVariable(/*prefix=*/'\0', baseName);
338 }
339 }
340
appendUniformDecls(GrShaderFlags visibility,SkString * out) const341 void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
342 this->uniformHandler()->appendUniformDecls(visibility, out);
343 }
344
addRTHeightUniform(const char * name)345 void GrGLSLProgramBuilder::addRTHeightUniform(const char* name) {
346 SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
347 GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
348 fUniformHandles.fRTHeightUni =
349 uniformHandler->internalAddUniformArray(nullptr, kFragment_GrShaderFlag, kHalf_GrSLType,
350 name, false, 0, nullptr);
351 }
352
finalizeShaders()353 void GrGLSLProgramBuilder::finalizeShaders() {
354 this->varyingHandler()->finalize();
355 fVS.finalize(kVertex_GrShaderFlag);
356 if (this->geometryProcessor().willUseGeoShader()) {
357 SkASSERT(this->shaderCaps()->geometryShaderSupport());
358 fGS.finalize(kGeometry_GrShaderFlag);
359 }
360 fFS.finalize(kFragment_GrShaderFlag);
361 }
362