Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrGLSLProgramBuilder.cpp
Go to the documentation of this file.
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 */
8
11#include "include/gpu/GrTypes.h"
27#include "src/sksl/SkSLString.h"
28
29#include <functional>
30#include <memory>
31#include <tuple>
32#include <unordered_map>
33#include <utility>
34
35
36using namespace skia_private;
37
39
41 const GrProgramInfo& programInfo)
42 : fVS(this)
43 , fFS(this)
44 , fDesc(desc)
45 , fProgramInfo(programInfo)
46 , fNumFragmentSamplers(0) {}
47
49
51 uint32_t featureBit,
52 const char* extensionName) {
53 if (shaders & kVertex_GrShaderFlag) {
54 fVS.addFeature(featureBit, extensionName);
55 }
56 if (shaders & kFragment_GrShaderFlag) {
57 fFS.addFeature(featureBit, extensionName);
58 }
59}
60
62 // First we loop over all of the installed processors and collect coord transforms. These will
63 // be sent to the ProgramImpl in its emitCode function
64 SkString inputColor;
65 SkString inputCoverage;
66 if (!this->emitAndInstallPrimProc(&inputColor, &inputCoverage)) {
67 return false;
68 }
69 if (!this->emitAndInstallDstTexture()) {
70 return false;
71 }
72 if (!this->emitAndInstallFragProcs(&inputColor, &inputCoverage)) {
73 return false;
74 }
75 if (!this->emitAndInstallXferProc(inputColor, inputCoverage)) {
76 return false;
77 }
78 fGPImpl->emitTransformCode(&fVS, this->uniformHandler());
79
80 return this->checkSamplerCounts();
81}
82
83bool GrGLSLProgramBuilder::emitAndInstallPrimProc(SkString* outputColor, SkString* outputCoverage) {
84 const GrGeometryProcessor& geomProc = this->geometryProcessor();
85
86 // Program builders have a bit of state we need to clear with each effect
87 this->advanceStage();
88 this->nameExpression(outputColor, "outputColor");
89 this->nameExpression(outputCoverage, "outputCoverage");
90
94
95 fFS.codeAppendf("// Stage %d, %s\n", fStageIndex, geomProc.name());
96 fVS.codeAppendf("// Primitive Processor %s\n", geomProc.name());
97
99 fGPImpl = geomProc.makeProgramImpl(*this->shaderCaps());
100
102 for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
104 name.printf("TextureSampler_%d", i);
105 const auto& sampler = geomProc.textureSampler(i);
106 texSamplers[i] = this->emitSampler(sampler.backendFormat(),
107 sampler.samplerState(),
108 sampler.swizzle(),
109 name.c_str());
110 if (!texSamplers[i].isValid()) {
111 return false;
112 }
113 }
114
116 &fFS,
117 this->varyingHandler(),
118 this->uniformHandler(),
119 this->shaderCaps(),
120 geomProc,
121 outputColor->c_str(),
122 outputCoverage->c_str(),
123 texSamplers.get());
124 std::tie(fFPCoordsMap, fLocalCoordsVar) = fGPImpl->emitCode(args, this->pipeline());
125
126 // We have to check that effects and the code they emit are consistent, ie if an effect
127 // asks for dst color, then the emit code needs to follow suit
128 SkDEBUGCODE(verify(geomProc);)
129
130 return true;
131}
132
133bool GrGLSLProgramBuilder::emitAndInstallFragProcs(SkString* color, SkString* coverage) {
134 int fpCount = this->pipeline().numFragmentProcessors();
135 SkASSERT(fFPImpls.empty());
136 fFPImpls.reserve(fpCount);
137 for (int i = 0; i < fpCount; ++i) {
141 fFPImpls.push_back(fp.makeProgramImpl());
142 output = this->emitRootFragProc(fp, *fFPImpls.back(), *inOut, output);
143 if (output.isEmpty()) {
144 return false;
145 }
146 *inOut = std::move(output);
147 }
148 return true;
149}
150
153 int* samplerIndex) {
154 bool ok = true;
155 fp.visitWithImpls([&](const GrFragmentProcessor& fp, GrFragmentProcessor::ProgramImpl& impl) {
156 if (const GrTextureEffect* te = fp.asTextureEffect()) {
157 SkString name = SkStringPrintf("TextureSampler_%d", *samplerIndex);
158 *samplerIndex += 1;
159
160 GrSamplerState samplerState = te->samplerState();
161 const GrBackendFormat& format = te->view().proxy()->backendFormat();
162 skgpu::Swizzle swizzle = te->view().swizzle();
163 SamplerHandle handle = this->emitSampler(format, samplerState, swizzle, name.c_str());
164 if (!handle.isValid()) {
165 ok = false;
166 return;
167 }
168 static_cast<GrTextureEffect::Impl&>(impl).setSamplerHandle(handle);
169 }
170 }, impl);
171
172 return ok;
173}
174
177 const char* inputColor,
178 const char* destColor,
179 const char* coords) const {
180 if (fp.isBlendFunction()) {
181 if (this->fragmentProcessorHasCoordsParam(&fp)) {
182 return SkSL::String::printf("%s(%s, %s, %s)", impl.functionName(), inputColor,
183 destColor, coords);
184 } else {
185 return SkSL::String::printf("%s(%s, %s)", impl.functionName(), inputColor, destColor);
186 }
187 }
188
189 if (this->fragmentProcessorHasCoordsParam(&fp)) {
190 return SkSL::String::printf("%s(%s, %s)", impl.functionName(), inputColor, coords);
191 } else {
192 return SkSL::String::printf("%s(%s)", impl.functionName(), inputColor);
193 }
194}
195
196SkString GrGLSLProgramBuilder::emitRootFragProc(const GrFragmentProcessor& fp,
198 const SkString& input,
199 SkString output) {
200 SkASSERT(input.size());
201
202 // Program builders have a bit of state we need to clear with each effect
203 this->advanceStage();
204 this->nameExpression(&output, "output");
205 fFS.codeAppendf("half4 %s;", output.c_str());
206 int samplerIndex = 0;
207 if (!this->emitTextureSamplersForFPs(fp, impl, &samplerIndex)) {
208 return {};
209 }
210
211 this->writeFPFunction(fp, impl);
212
214 "%s = %s;",
215 output.c_str(),
216 this->invokeFP(fp, impl, input.c_str(), "half4(1)", fLocalCoordsVar.c_str()).c_str());
217
218 // We have to check that effects and the code they emit are consistent, ie if an effect asks
219 // for dst color, then the emit code needs to follow suit
220 SkDEBUGCODE(verify(fp);)
221
222 return output;
223}
224
225void GrGLSLProgramBuilder::writeChildFPFunctions(const GrFragmentProcessor& fp,
227 fSubstageIndices.push_back(0);
228 for (int i = 0; i < impl.numChildProcessors(); ++i) {
230 if (!childImpl) {
231 continue;
232 }
233
234 const GrFragmentProcessor* childFP = fp.childProcessor(i);
235 SkASSERT(childFP);
236
237 this->writeFPFunction(*childFP, *childImpl);
238 ++fSubstageIndices.back();
239 }
240 fSubstageIndices.pop_back();
241}
242
245 constexpr const char* kDstColor = "_dst";
246 const char* const inputColor = fp.isBlendFunction() ? "_src" : "_input";
247 const char* sampleCoords = "_coords";
248 fFS.nextStage();
249 // Conceptually, an FP is always sampled at a particular coordinate. However, if it is only
250 // sampled by a chain of uniform matrix expressions (or legacy coord transforms), the value that
251 // would have been passed to _coords is lifted to the vertex shader and
252 // varying. In that case it uses that variable and we do not pass a second argument for _coords.
254 int numParams = 0;
255
256 params[numParams++] = GrShaderVar(inputColor, SkSLType::kHalf4);
257
258 if (fp.isBlendFunction()) {
259 // Blend functions take a dest color as input.
260 params[numParams++] = GrShaderVar(kDstColor, SkSLType::kHalf4);
261 }
262
263 auto fpCoordsIter = fFPCoordsMap.find(&fp);
264 if (fpCoordsIter == fFPCoordsMap.end()) {
265 // This FP isn't in our coords map at all, so its coords (if any) couldn't have been lifted
266 // to a varying.
267 if (fp.usesSampleCoords()) {
268 params[numParams++] = GrShaderVar(sampleCoords, SkSLType::kFloat2);
269 }
270 } else if (fpCoordsIter->second.hasCoordsParam) {
271 // This FP is in our map, and it takes an explicit coords param.
272 params[numParams++] = GrShaderVar(sampleCoords, SkSLType::kFloat2);
273 } else {
274 // Either doesn't use coords at all or sampled through a chain of passthrough/matrix
275 // samples usages. In the latter case the coords are emitted in the vertex shader as a
276 // varying, so this only has to access it. Add a float2 _coords variable that maps to the
277 // associated varying and replaces the absent 2nd argument to the fp's function.
278 GrShaderVar varying = fpCoordsIter->second.coordsVarying;
279
280 switch (varying.getType()) {
281 case SkSLType::kVoid:
282 SkASSERT(!fp.usesSampleCoordsDirectly());
283 break;
285 // Just point the local coords to the varying
286 sampleCoords = varying.getName().c_str();
287 break;
289 // Must perform the perspective divide in the frag shader based on the
290 // varying, and since we won't actually have a function parameter for local
291 // coords, add it as a local variable.
292 fFS.codeAppendf("float2 %s = %s.xy / %s.z;\n",
293 sampleCoords,
294 varying.getName().c_str(),
295 varying.getName().c_str());
296 break;
297 default:
298 SkDEBUGFAILF("Unexpected varying type for coord: %s %d\n",
299 varying.getName().c_str(),
300 (int)varying.getType());
301 break;
302 }
303 }
304
305 SkASSERT(numParams <= (int)std::size(params));
306
307 // First, emit every child's function. This needs to happen (even for children that aren't
308 // sampled), so that all of the expected uniforms are registered.
309 this->writeChildFPFunctions(fp, impl);
311 this->uniformHandler(),
312 this->shaderCaps(),
313 fp,
314 inputColor,
315 kDstColor,
316 sampleCoords);
317
318 impl.emitCode(args);
320
322 impl.functionName(),
323 SkSpan(params, numParams),
324 fFS.code().c_str());
326}
327
328bool GrGLSLProgramBuilder::emitAndInstallDstTexture() {
330
331 const GrSurfaceProxyView& dstView = this->pipeline().dstProxyView();
332 if (this->pipeline().usesDstTexture()) {
333 // Set up a sampler handle for the destination texture.
334 GrTextureProxy* dstTextureProxy = dstView.asTextureProxy();
335 SkASSERT(dstTextureProxy);
336 const skgpu::Swizzle& swizzle = dstView.swizzle();
337 fDstTextureSamplerHandle = this->emitSampler(dstTextureProxy->backendFormat(),
338 GrSamplerState(), swizzle, "DstTextureSampler");
339 if (!fDstTextureSamplerHandle.isValid()) {
340 return false;
341 }
342 fDstTextureOrigin = dstView.origin();
343 SkASSERT(dstTextureProxy->textureType() != GrTextureType::kExternal);
344
345 // Declare a _dstColor global variable which samples from the dest-texture sampler at the
346 // top of the fragment shader.
347 const char* dstTextureCoordsName;
349 /*owner=*/nullptr,
352 "DstTextureCoords",
353 &dstTextureCoordsName);
354 fFS.codeAppend("// Read color from copy of the destination\n");
355 if (dstTextureProxy->textureType() == GrTextureType::k2D) {
356 fFS.codeAppendf("float2 _dstTexCoord = (sk_FragCoord.xy - %s.xy) * %s.zw;\n",
357 dstTextureCoordsName, dstTextureCoordsName);
359 fFS.codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;\n");
360 }
361 } else {
362 SkASSERT(dstTextureProxy->textureType() == GrTextureType::kRectangle);
363 fFS.codeAppendf("float2 _dstTexCoord = sk_FragCoord.xy - %s.xy;\n",
364 dstTextureCoordsName);
366 // When the texture type is kRectangle, instead of a scale stored in the zw of the
367 // uniform, we store the height in z so we can flip the coord here.
368 fFS.codeAppendf("_dstTexCoord.y = %s.z - _dstTexCoord.y;\n", dstTextureCoordsName);
369 }
370 }
371 const char* dstColor = fFS.dstColor();
372 SkString dstColorDecl = SkStringPrintf("half4 %s;", dstColor);
373 fFS.definitionAppend(dstColorDecl.c_str());
374 fFS.codeAppendf("%s = ", dstColor);
376 fFS.codeAppend(";\n");
377 } else if (this->pipeline().usesDstInputAttachment()) {
378 // Set up an input attachment for the destination texture.
379 const skgpu::Swizzle& swizzle = dstView.swizzle();
380 fDstTextureSamplerHandle = this->emitInputSampler(swizzle, "DstTextureInput");
381 if (!fDstTextureSamplerHandle.isValid()) {
382 return false;
383 }
384
385 // Populate the _dstColor variable by loading from the input attachment at the top of the
386 // fragment shader.
387 fFS.codeAppend("// Read color from input attachment\n");
388 const char* dstColor = fFS.dstColor();
389 SkString dstColorDecl = SkStringPrintf("half4 %s;", dstColor);
390 fFS.definitionAppend(dstColorDecl.c_str());
391 fFS.codeAppendf("%s = ", dstColor);
393 fFS.codeAppend(";\n");
394 }
395
396 return true;
397}
398
399bool GrGLSLProgramBuilder::emitAndInstallXferProc(const SkString& colorIn,
400 const SkString& coverageIn) {
401 // Program builders have a bit of state we need to clear with each effect
402 this->advanceStage();
403
405 const GrXferProcessor& xp = this->pipeline().getXferProcessor();
407
408 // Enable dual source secondary output if we have one
409 if (xp.hasSecondaryOutput()) {
410 fFS.enableSecondaryOutput();
411 }
412
413 SkString openBrace;
414 openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
415 fFS.codeAppend(openBrace.c_str());
416
417 SkString finalInColor = colorIn.size() ? colorIn : SkString("float4(1)");
418
420 &fFS,
421 this->uniformHandler(),
422 this->shaderCaps(),
423 xp,
424 finalInColor.c_str(),
425 coverageIn.size() ? coverageIn.c_str() : "float4(1)",
426 fFS.getPrimaryColorOutputName(),
427 fFS.getSecondaryColorOutputName(),
430 this->pipeline().writeSwizzle());
431 fXPImpl->emitCode(args);
432
433 // We have to check that effects and the code they emit are consistent, ie if an effect
434 // asks for dst color, then the emit code needs to follow suit
435 SkDEBUGCODE(verify(xp);)
436 fFS.codeAppend("}");
437 return true;
438}
439
440GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitSampler(
441 const GrBackendFormat& backendFormat, GrSamplerState state, const skgpu::Swizzle& swizzle,
442 const char* name) {
443 ++fNumFragmentSamplers;
444 return this->uniformHandler()->addSampler(backendFormat, state, swizzle, name,
445 this->shaderCaps());
446}
447
448GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitInputSampler(
449 const skgpu::Swizzle& swizzle, const char* name) {
450 return this->uniformHandler()->addInputSampler(swizzle, name);
451}
452
453bool GrGLSLProgramBuilder::checkSamplerCounts() {
454 const GrShaderCaps& shaderCaps = *this->shaderCaps();
455 if (fNumFragmentSamplers > shaderCaps.fMaxFragmentSamplers) {
456 GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n");
457 return false;
458 }
459 return true;
460}
461
462#ifdef SK_DEBUG
463void GrGLSLProgramBuilder::verify(const GrGeometryProcessor& geomProc) {
464 SkASSERT(!fFS.fHasReadDstColorThisStage_DebugOnly);
465}
466
467void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
468 SkASSERT(fp.willReadDstColor() == fFS.fHasReadDstColorThisStage_DebugOnly);
469}
470
471void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
472 SkASSERT(xp.willReadDstColor() == fFS.fHasReadDstColorThisStage_DebugOnly);
473}
474#endif
475
476SkString GrGLSLProgramBuilder::getMangleSuffix() const {
477 SkASSERT(fStageIndex >= 0);
479 suffix.printf("_S%d", fStageIndex);
480 for (auto c : fSubstageIndices) {
481 suffix.appendf("_c%d", c);
482 }
483 return suffix;
484}
485
486SkString GrGLSLProgramBuilder::nameVariable(char prefix, const char* name, bool mangle) {
487 SkString out;
488 if ('\0' == prefix) {
489 out = name;
490 } else {
491 out.printf("%c%s", prefix, name);
492 }
493 if (mangle) {
494 SkString suffix = this->getMangleSuffix();
495 // Names containing "__" are reserved; add "x" if needed to avoid consecutive underscores.
496 const char *underscoreSplitter = out.endsWith('_') ? "x" : "";
497 out.appendf("%s%s", underscoreSplitter, suffix.c_str());
498 }
499 return out;
500}
501
502void GrGLSLProgramBuilder::nameExpression(SkString* output, const char* baseName) {
503 // Name a variable to hold stage result. If we already have a valid output name, use that as-is;
504 // otherwise, create a new mangled one.
505 if (output->isEmpty()) {
506 *output = this->nameVariable(/*prefix=*/'\0', baseName);
507 }
508}
509
511 this->uniformHandler()->appendUniformDecls(visibility, out);
512}
513
518 uniformHandler->internalAddUniformArray(nullptr,
521 name,
522 false,
523 0,
524 nullptr);
525}
526
528 auto iter = fFPCoordsMap.find(fp);
529 return (iter != fFPCoordsMap.end()) ? iter->second.hasCoordsParam
530 : fp->usesSampleCoords();
531}
532
#define GrCapsDebugf(caps,...)
GrShaderFlags
@ kVertex_GrShaderFlag
@ kFragment_GrShaderFlag
@ kBottomLeft_GrSurfaceOrigin
Definition GrTypes.h:149
@ kTopLeft_GrSurfaceOrigin
Definition GrTypes.h:148
SkColor4f color
#define SkDEBUGFAILF(fmt,...)
Definition SkAssert.h:119
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static bool ok(int result)
SK_API SkString static SkString SkStringPrintf()
Definition SkString.h:287
virtual void emitCode(EmitArgs &)=0
ProgramImpl * childProcessor(int index) const
SkString nameVariable(char prefix, const char *name, bool mangle=true)
virtual GrGLSLUniformHandler * uniformHandler()=0
GrSurfaceOrigin fDstTextureOrigin
bool fragmentProcessorHasCoordsParam(const GrFragmentProcessor *) const
std::vector< std::unique_ptr< GrFragmentProcessor::ProgramImpl > > fFPImpls
virtual const GrCaps * caps() const =0
std::unique_ptr< GrGeometryProcessor::ProgramImpl > fGPImpl
const GrShaderCaps * shaderCaps() const
SamplerHandle fDstTextureSamplerHandle
void addFeature(GrShaderFlags shaders, uint32_t featureBit, const char *extensionName)
GrGLSLVertexBuilder fVS
const GrGeometryProcessor & geometryProcessor() const
GrGLSLUniformHandler::SamplerHandle SamplerHandle
bool emitTextureSamplersForFPs(const GrFragmentProcessor &fp, GrFragmentProcessor::ProgramImpl &impl, int *samplerIndex)
void appendUniformDecls(GrShaderFlags visibility, SkString *) const
virtual GrGLSLVaryingHandler * varyingHandler()=0
std::string invokeFP(const GrFragmentProcessor &fp, const GrFragmentProcessor::ProgramImpl &impl, const char *inputColor, const char *destColor, const char *coords) const
std::unique_ptr< GrXferProcessor::ProgramImpl > fXPImpl
virtual ~GrGLSLProgramBuilder()
static const int kVarsPerBlock
GrGLSLBuiltinUniformHandles fUniformHandles
GrGLSLFragmentShaderBuilder fFS
void addRTFlipUniform(const char *name)
GrGLSLProgramBuilder(const GrProgramDesc &, const GrProgramInfo &)
void writeFPFunction(const GrFragmentProcessor &fp, GrFragmentProcessor::ProgramImpl &impl)
const GrPipeline & pipeline() const
void emitFunction(SkSLType returnType, const char *mangledName, SkSpan< const GrShaderVar > args, const char *body)
this code().appendVAList(format
void definitionAppend(const char *str)
bool addFeature(uint32_t featureBit, const char *extensionName)
void finalize(uint32_t visibility)
void codeAppend(const char *str)
void appendTextureLookup(SkString *out, SamplerHandle, const char *coordName) const
SkString getMangledFunctionName(const char *baseName)
void codeAppendf(const char format[],...) SK_PRINTF_LIKE(2
void appendInputLoad(SamplerHandle)
virtual void appendUniformDecls(GrShaderFlags visibility, SkString *) const =0
virtual UniformHandle internalAddUniformArray(const GrProcessor *owner, uint32_t visibility, SkSLType type, const char *name, bool mangleName, int arrayCount, const char **outName)=0
UniformHandle addUniform(const GrProcessor *owner, uint32_t visibility, SkSLType type, const char *name, const char **outName=nullptr)
virtual SamplerHandle addSampler(const GrBackendFormat &, GrSamplerState, const skgpu::Swizzle &, const char *name, const GrShaderCaps *)=0
virtual SamplerHandle addInputSampler(const skgpu::Swizzle &swizzle, const char *name)
virtual std::unique_ptr< ProgramImpl > makeProgramImpl(const GrShaderCaps &) const =0
const TextureSampler & textureSampler(int index) const
int numFragmentProcessors() const
Definition GrPipeline.h:99
bool isColorFragmentProcessor(int idx) const
Definition GrPipeline.h:101
const GrFragmentProcessor & getFragmentProcessor(int idx) const
Definition GrPipeline.h:157
const GrSurfaceProxyView & dstProxyView() const
Definition GrPipeline.h:138
const GrXferProcessor & getXferProcessor() const
Definition GrPipeline.h:116
virtual const char * name() const =0
SkSLType getType() const
Definition GrShaderVar.h:97
const char * c_str() const
Definition GrShaderVar.h:94
const SkString & getName() const
Definition GrShaderVar.h:91
skgpu::Swizzle swizzle() const
GrTextureProxy * asTextureProxy() const
GrSurfaceOrigin origin() const
const GrBackendFormat & backendFormat() const
void setSamplerHandle(GrGLSLShaderBuilder::SamplerHandle handle)
GrTextureType textureType() const
bool hasSecondaryOutput() const
virtual std::unique_ptr< ProgramImpl > makeProgramImpl() const =0
bool willReadDstColor() const
static constexpr const char RTADJUST_NAME[]
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:534
size_t size() const
Definition SkString.h:131
const char * c_str() const
Definition SkString.h:133
const EmbeddedViewParams * params
AtkStateType state
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const char * name
Definition fuchsia.cc:50
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
const uint32_t fp
GrGLSLProgramDataManager::UniformHandle fRTFlipUni
GrGLSLProgramDataManager::UniformHandle fDstTextureCoordsUni
GrGLSLProgramDataManager::UniformHandle fRTAdjustmentUni
int fMaxFragmentSamplers