Line data Source code
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 "GrShaderVar.h"
9 : #include "GrShaderCaps.h"
10 : #include "GrSwizzle.h"
11 : #include "glsl/GrGLSLShaderBuilder.h"
12 : #include "glsl/GrGLSLColorSpaceXformHelper.h"
13 : #include "glsl/GrGLSLProgramBuilder.h"
14 :
15 0 : GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program)
16 : : fProgramBuilder(program)
17 : , fInputs(GrGLSLProgramBuilder::kVarsPerBlock)
18 : , fOutputs(GrGLSLProgramBuilder::kVarsPerBlock)
19 : , fFeaturesAddedMask(0)
20 : , fCodeIndex(kCode)
21 0 : , fFinalized(false) {
22 : // We push back some dummy pointers which will later become our header
23 0 : for (int i = 0; i <= kCode; i++) {
24 0 : fShaderStrings.push_back();
25 0 : fCompilerStrings.push_back(nullptr);
26 0 : fCompilerStringLengths.push_back(0);
27 : }
28 :
29 0 : this->main() = "void main() {";
30 0 : }
31 :
32 0 : void GrGLSLShaderBuilder::declAppend(const GrShaderVar& var) {
33 0 : SkString tempDecl;
34 0 : var.appendDecl(fProgramBuilder->shaderCaps(), &tempDecl);
35 0 : this->codeAppendf("%s;", tempDecl.c_str());
36 0 : }
37 :
38 0 : void GrGLSLShaderBuilder::declareGlobal(const GrShaderVar& v) {
39 0 : v.appendDecl(this->getProgramBuilder()->shaderCaps(), &this->definitions());
40 0 : this->definitions().append(";");
41 0 : }
42 :
43 0 : void GrGLSLShaderBuilder::emitFunction(GrSLType returnType,
44 : const char* name,
45 : int argCnt,
46 : const GrShaderVar* args,
47 : const char* body,
48 : SkString* outName) {
49 0 : this->functions().append(GrGLSLTypeString(returnType));
50 0 : fProgramBuilder->nameVariable(outName, '\0', name);
51 0 : this->functions().appendf(" %s", outName->c_str());
52 0 : this->functions().append("(");
53 0 : for (int i = 0; i < argCnt; ++i) {
54 0 : args[i].appendDecl(fProgramBuilder->shaderCaps(), &this->functions());
55 0 : if (i < argCnt - 1) {
56 0 : this->functions().append(", ");
57 : }
58 : }
59 0 : this->functions().append(") {\n");
60 0 : this->functions().append(body);
61 0 : this->functions().append("}\n\n");
62 0 : }
63 :
64 0 : static inline void append_texture_swizzle(SkString* out, GrSwizzle swizzle) {
65 0 : if (swizzle != GrSwizzle::RGBA()) {
66 0 : out->appendf(".%s", swizzle.c_str());
67 : }
68 0 : }
69 :
70 0 : void GrGLSLShaderBuilder::appendTextureLookup(SkString* out,
71 : SamplerHandle samplerHandle,
72 : const char* coordName,
73 : GrSLType varyingType) const {
74 0 : const GrShaderVar& sampler = fProgramBuilder->samplerVariable(samplerHandle);
75 0 : GrSLType samplerType = sampler.getType();
76 0 : if (samplerType == kTexture2DRectSampler_GrSLType) {
77 0 : if (varyingType == kVec2f_GrSLType) {
78 0 : out->appendf("texture(%s, textureSize(%s) * %s)",
79 0 : sampler.c_str(), sampler.c_str(), coordName);
80 : } else {
81 0 : out->appendf("texture(%s, vec3(textureSize(%s) * %s.xy, %s.z))",
82 0 : sampler.c_str(), sampler.c_str(), coordName, coordName);
83 : }
84 : } else {
85 0 : out->appendf("texture(%s, %s)", sampler.c_str(), coordName);
86 : }
87 0 : append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
88 0 : }
89 :
90 0 : void GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle,
91 : const char* coordName,
92 : GrSLType varyingType,
93 : GrGLSLColorSpaceXformHelper* colorXformHelper) {
94 0 : if (colorXformHelper && colorXformHelper->isValid()) {
95 : // With a color gamut transform, we need to wrap the lookup in another function call
96 0 : SkString lookup;
97 0 : this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
98 0 : this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
99 : } else {
100 0 : this->appendTextureLookup(&this->code(), samplerHandle, coordName, varyingType);
101 : }
102 0 : }
103 :
104 0 : void GrGLSLShaderBuilder::appendTextureLookupAndModulate(
105 : const char* modulation,
106 : SamplerHandle samplerHandle,
107 : const char* coordName,
108 : GrSLType varyingType,
109 : GrGLSLColorSpaceXformHelper* colorXformHelper) {
110 0 : SkString lookup;
111 0 : this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
112 0 : if (colorXformHelper && colorXformHelper->isValid()) {
113 0 : SkString xform;
114 0 : this->appendColorGamutXform(&xform, lookup.c_str(), colorXformHelper);
115 0 : this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(xform)).c_str());
116 : } else {
117 0 : this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str());
118 : }
119 0 : }
120 :
121 0 : void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out,
122 : const char* srcColor,
123 : GrGLSLColorSpaceXformHelper* colorXformHelper) {
124 : // Our color is (r, g, b, a), but we want to multiply (r, g, b, 1) by our matrix, then
125 : // re-insert the original alpha. The supplied srcColor is likely to be of the form
126 : // "texture(...)", and we don't want to evaluate that twice, so wrap everything in a function.
127 : static const GrShaderVar gColorGamutXformArgs[] = {
128 : GrShaderVar("color", kVec4f_GrSLType),
129 : GrShaderVar("xform", kMat44f_GrSLType),
130 0 : };
131 0 : SkString functionBody;
132 : // Gamut xform, clamp to destination gamut. We only support/have premultiplied textures, so we
133 : // always just clamp to alpha.
134 0 : functionBody.append("\tcolor.rgb = clamp((xform * vec4(color.rgb, 1.0)).rgb, 0.0, color.a);\n");
135 0 : functionBody.append("\treturn color;");
136 0 : SkString colorGamutXformFuncName;
137 0 : this->emitFunction(kVec4f_GrSLType,
138 : "colorGamutXform",
139 : SK_ARRAY_COUNT(gColorGamutXformArgs),
140 : gColorGamutXformArgs,
141 : functionBody.c_str(),
142 0 : &colorGamutXformFuncName);
143 :
144 0 : GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler();
145 0 : out->appendf("%s(%s, %s)", colorGamutXformFuncName.c_str(), srcColor,
146 0 : uniformHandler->getUniformCStr(colorXformHelper->gamutXformUniform()));
147 0 : }
148 :
149 0 : void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor,
150 : GrGLSLColorSpaceXformHelper* colorXformHelper) {
151 0 : SkString xform;
152 0 : this->appendColorGamutXform(&xform, srcColor, colorXformHelper);
153 0 : this->codeAppend(xform.c_str());
154 0 : }
155 :
156 0 : void GrGLSLShaderBuilder::appendTexelFetch(SkString* out,
157 : SamplerHandle samplerHandle,
158 : const char* coordExpr) const {
159 0 : const GrShaderVar& sampler = fProgramBuilder->samplerVariable(samplerHandle);
160 0 : SkASSERT(fProgramBuilder->shaderCaps()->texelFetchSupport());
161 0 : SkASSERT(GrSLTypeIsCombinedSamplerType(sampler.getType()));
162 :
163 0 : out->appendf("texelFetch(%s, %s)", sampler.c_str(), coordExpr);
164 :
165 0 : append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
166 0 : }
167 :
168 0 : void GrGLSLShaderBuilder::appendTexelFetch(SamplerHandle samplerHandle, const char* coordExpr) {
169 0 : this->appendTexelFetch(&this->code(), samplerHandle, coordExpr);
170 0 : }
171 :
172 0 : void GrGLSLShaderBuilder::appendImageStorageLoad(SkString* out, ImageStorageHandle handle,
173 : const char* coordExpr) {
174 0 : const GrShaderVar& imageStorage = fProgramBuilder->imageStorageVariable(handle);
175 0 : out->appendf("imageLoad(%s, %s)", imageStorage.c_str(), coordExpr);
176 0 : }
177 :
178 0 : void GrGLSLShaderBuilder::appendImageStorageLoad(ImageStorageHandle handle, const char* coordExpr) {
179 0 : this->appendImageStorageLoad(&this->code(), handle, coordExpr);
180 0 : }
181 :
182 0 : bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
183 0 : if (featureBit & fFeaturesAddedMask) {
184 0 : return false;
185 : }
186 0 : this->extensions().appendf("#extension %s: require\n", extensionName);
187 0 : fFeaturesAddedMask |= featureBit;
188 0 : return true;
189 : }
190 :
191 0 : void GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
192 0 : for (int i = 0; i < vars.count(); ++i) {
193 0 : vars[i].appendDecl(fProgramBuilder->shaderCaps(), out);
194 0 : out->append(";\n");
195 : }
196 0 : }
197 :
198 0 : void GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
199 0 : SkASSERT(fProgramBuilder->shaderCaps()->generation() >= k330_GrGLSLGeneration ||
200 : fProgramBuilder->shaderCaps()->mustEnableAdvBlendEqs());
201 0 : fLayoutParams[interface].push_back() = param;
202 0 : }
203 :
204 0 : void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() {
205 : static const char* interfaceQualifierNames[] = {
206 : "in",
207 : "out"
208 : };
209 :
210 0 : for (int interface = 0; interface <= kLastInterfaceQualifier; ++interface) {
211 0 : const SkTArray<SkString>& params = fLayoutParams[interface];
212 0 : if (params.empty()) {
213 0 : continue;
214 : }
215 0 : this->layoutQualifiers().appendf("layout(%s", params[0].c_str());
216 0 : for (int i = 1; i < params.count(); ++i) {
217 0 : this->layoutQualifiers().appendf(", %s", params[i].c_str());
218 : }
219 0 : this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]);
220 : }
221 :
222 : GR_STATIC_ASSERT(0 == GrGLSLShaderBuilder::kIn_InterfaceQualifier);
223 : GR_STATIC_ASSERT(1 == GrGLSLShaderBuilder::kOut_InterfaceQualifier);
224 : GR_STATIC_ASSERT(SK_ARRAY_COUNT(interfaceQualifierNames) == kLastInterfaceQualifier + 1);
225 0 : }
226 :
227 0 : void GrGLSLShaderBuilder::finalize(uint32_t visibility) {
228 0 : SkASSERT(!fFinalized);
229 0 : this->versionDecl() = fProgramBuilder->shaderCaps()->versionDeclString();
230 0 : this->compileAndAppendLayoutQualifiers();
231 0 : SkASSERT(visibility);
232 0 : fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms());
233 0 : this->appendDecls(fInputs, &this->inputs());
234 0 : this->appendDecls(fOutputs, &this->outputs());
235 0 : this->onFinalize();
236 : // append the 'footer' to code
237 0 : this->code().append("}");
238 :
239 0 : for (int i = 0; i <= fCodeIndex; i++) {
240 0 : fCompilerStrings[i] = fShaderStrings[i].c_str();
241 0 : fCompilerStringLengths[i] = (int)fShaderStrings[i].size();
242 : }
243 :
244 0 : fFinalized = true;
245 0 : }
|