1 /*
2  * Copyright 2014 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 "GrSwizzle.h"
9 #include "glsl/GrGLSLShaderBuilder.h"
10 #include "glsl/GrGLSLCaps.h"
11 #include "glsl/GrGLSLShaderVar.h"
12 #include "glsl/GrGLSLTextureSampler.h"
13 #include "glsl/GrGLSLProgramBuilder.h"
14 
GrGLSLShaderBuilder(GrGLSLProgramBuilder * program)15 GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program)
16     : fProgramBuilder(program)
17     , fInputs(GrGLSLProgramBuilder::kVarsPerBlock)
18     , fOutputs(GrGLSLProgramBuilder::kVarsPerBlock)
19     , fFeaturesAddedMask(0)
20     , fCodeIndex(kCode)
21     , fFinalized(false) {
22     // We push back some dummy pointers which will later become our header
23     for (int i = 0; i <= kCode; i++) {
24         fShaderStrings.push_back();
25         fCompilerStrings.push_back(nullptr);
26         fCompilerStringLengths.push_back(0);
27     }
28 
29     this->main() = "void main() {";
30 }
31 
declAppend(const GrGLSLShaderVar & var)32 void GrGLSLShaderBuilder::declAppend(const GrGLSLShaderVar& var) {
33     SkString tempDecl;
34     var.appendDecl(fProgramBuilder->glslCaps(), &tempDecl);
35     this->codeAppendf("%s;", tempDecl.c_str());
36 }
37 
emitFunction(GrSLType returnType,const char * name,int argCnt,const GrGLSLShaderVar * args,const char * body,SkString * outName)38 void GrGLSLShaderBuilder::emitFunction(GrSLType returnType,
39                                        const char* name,
40                                        int argCnt,
41                                        const GrGLSLShaderVar* args,
42                                        const char* body,
43                                        SkString* outName) {
44     this->functions().append(GrGLSLTypeString(returnType));
45     fProgramBuilder->nameVariable(outName, '\0', name);
46     this->functions().appendf(" %s", outName->c_str());
47     this->functions().append("(");
48     for (int i = 0; i < argCnt; ++i) {
49         args[i].appendDecl(fProgramBuilder->glslCaps(), &this->functions());
50         if (i < argCnt - 1) {
51             this->functions().append(", ");
52         }
53     }
54     this->functions().append(") {\n");
55     this->functions().append(body);
56     this->functions().append("}\n\n");
57 }
58 
appendTextureLookup(SkString * out,const GrGLSLTextureSampler & sampler,const char * coordName,GrSLType varyingType) const59 void GrGLSLShaderBuilder::appendTextureLookup(SkString* out,
60                                               const GrGLSLTextureSampler& sampler,
61                                               const char* coordName,
62                                               GrSLType varyingType) const {
63     const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
64     GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler();
65     GrSLType samplerType = uniformHandler->getUniformVariable(sampler.fSamplerUniform).getType();
66     if (samplerType == kSampler2DRect_GrSLType) {
67         if (varyingType == kVec2f_GrSLType) {
68             out->appendf("%s(%s, textureSize(%s) * %s)",
69                          GrGLSLTexture2DFunctionName(varyingType, samplerType,
70                                                      glslCaps->generation()),
71                          uniformHandler->getUniformCStr(sampler.fSamplerUniform),
72                          uniformHandler->getUniformCStr(sampler.fSamplerUniform),
73                          coordName);
74         } else {
75             out->appendf("%s(%s, vec3(textureSize(%s) * %s.xy, %s.z))",
76                          GrGLSLTexture2DFunctionName(varyingType, samplerType,
77                                                      glslCaps->generation()),
78                          uniformHandler->getUniformCStr(sampler.fSamplerUniform),
79                          uniformHandler->getUniformCStr(sampler.fSamplerUniform),
80                          coordName,
81                          coordName);
82         }
83     } else {
84         out->appendf("%s(%s, %s)",
85                      GrGLSLTexture2DFunctionName(varyingType, samplerType, glslCaps->generation()),
86                      uniformHandler->getUniformCStr(sampler.fSamplerUniform),
87                      coordName);
88     }
89 
90     // This refers to any swizzling we may need to get from some backend internal format to the
91     // format used in GrPixelConfig. If this is implemented by the GrGpu object, then swizzle will
92     // be rgba. For shader prettiness we omit the swizzle rather than appending ".rgba".
93     const GrSwizzle& configSwizzle = glslCaps->configTextureSwizzle(sampler.config());
94 
95     if (configSwizzle != GrSwizzle::RGBA()) {
96         out->appendf(".%s", configSwizzle.c_str());
97     }
98 }
99 
appendTextureLookup(const GrGLSLTextureSampler & sampler,const char * coordName,GrSLType varyingType)100 void GrGLSLShaderBuilder::appendTextureLookup(const GrGLSLTextureSampler& sampler,
101                                               const char* coordName,
102                                               GrSLType varyingType) {
103     this->appendTextureLookup(&this->code(), sampler, coordName, varyingType);
104 }
105 
appendTextureLookupAndModulate(const char * modulation,const GrGLSLTextureSampler & sampler,const char * coordName,GrSLType varyingType)106 void GrGLSLShaderBuilder::appendTextureLookupAndModulate(const char* modulation,
107                                                          const GrGLSLTextureSampler& sampler,
108                                                          const char* coordName,
109                                                          GrSLType varyingType) {
110     SkString lookup;
111     this->appendTextureLookup(&lookup, sampler, coordName, varyingType);
112     this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str());
113 }
114 
addFeature(uint32_t featureBit,const char * extensionName)115 bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
116     if (featureBit & fFeaturesAddedMask) {
117         return false;
118     }
119     this->extensions().appendf("#extension %s: require\n", extensionName);
120     fFeaturesAddedMask |= featureBit;
121     return true;
122 }
123 
appendDecls(const VarArray & vars,SkString * out) const124 void GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
125     for (int i = 0; i < vars.count(); ++i) {
126         vars[i].appendDecl(fProgramBuilder->glslCaps(), out);
127         out->append(";\n");
128     }
129 }
130 
addLayoutQualifier(const char * param,InterfaceQualifier interface)131 void GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
132     SkASSERT(fProgramBuilder->glslCaps()->generation() >= k330_GrGLSLGeneration ||
133              fProgramBuilder->glslCaps()->mustEnableAdvBlendEqs());
134     fLayoutParams[interface].push_back() = param;
135 }
136 
compileAndAppendLayoutQualifiers()137 void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() {
138     static const char* interfaceQualifierNames[] = {
139         "out"
140     };
141 
142     for (int interface = 0; interface <= kLastInterfaceQualifier; ++interface) {
143         const SkTArray<SkString>& params = fLayoutParams[interface];
144         if (params.empty()) {
145             continue;
146         }
147         this->layoutQualifiers().appendf("layout(%s", params[0].c_str());
148         for (int i = 1; i < params.count(); ++i) {
149             this->layoutQualifiers().appendf(", %s", params[i].c_str());
150         }
151         this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]);
152     }
153 
154     GR_STATIC_ASSERT(0 == GrGLSLShaderBuilder::kOut_InterfaceQualifier);
155     GR_STATIC_ASSERT(SK_ARRAY_COUNT(interfaceQualifierNames) == kLastInterfaceQualifier + 1);
156 }
157 
finalize(uint32_t visibility)158 void GrGLSLShaderBuilder::finalize(uint32_t visibility) {
159     SkASSERT(!fFinalized);
160     this->versionDecl() = fProgramBuilder->glslCaps()->versionDeclString();
161     this->compileAndAppendLayoutQualifiers();
162     SkASSERT(visibility);
163     fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms());
164     this->appendDecls(fInputs, &this->inputs());
165     this->appendDecls(fOutputs, &this->outputs());
166     this->onFinalize();
167     // append the 'footer' to code
168     this->code().append("}");
169 
170     for (int i = 0; i <= fCodeIndex; i++) {
171         fCompilerStrings[i] = fShaderStrings[i].c_str();
172         fCompilerStringLengths[i] = (int)fShaderStrings[i].size();
173     }
174 
175     fFinalized = true;
176 }
177 
178