130ba436f04e61d4505fb854d5fc56079636e0788joshualitt/*
230ba436f04e61d4505fb854d5fc56079636e0788joshualitt * Copyright 2014 Google Inc.
330ba436f04e61d4505fb854d5fc56079636e0788joshualitt *
430ba436f04e61d4505fb854d5fc56079636e0788joshualitt * Use of this source code is governed by a BSD-style license that can be
530ba436f04e61d4505fb854d5fc56079636e0788joshualitt * found in the LICENSE file.
630ba436f04e61d4505fb854d5fc56079636e0788joshualitt */
730ba436f04e61d4505fb854d5fc56079636e0788joshualitt
899938a8ef24e2dd5b39f78638742e9b50ab6d9bfBrian Salomon#include "GrShaderVar.h"
994efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon#include "GrShaderCaps.h"
10cdee009886babe6df7743a9b5b3e2cc0a5f21adfbsalomon#include "GrSwizzle.h"
112d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel#include "glsl/GrGLSLShaderBuilder.h"
1277320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman#include "glsl/GrGLSLColorSpaceXformHelper.h"
138dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel#include "glsl/GrGLSLProgramBuilder.h"
1430ba436f04e61d4505fb854d5fc56079636e0788joshualitt
152d721d33aad192cc8a7a1321504b39bdca2a57ceegdanielGrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program)
1630ba436f04e61d4505fb854d5fc56079636e0788joshualitt    : fProgramBuilder(program)
178dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel    , fInputs(GrGLSLProgramBuilder::kVarsPerBlock)
188dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel    , fOutputs(GrGLSLProgramBuilder::kVarsPerBlock)
1943466a1ade066f96823dbc7963767da3973afd91joshualitt    , fFeaturesAddedMask(0)
2043466a1ade066f96823dbc7963767da3973afd91joshualitt    , fCodeIndex(kCode)
2143466a1ade066f96823dbc7963767da3973afd91joshualitt    , fFinalized(false) {
2243466a1ade066f96823dbc7963767da3973afd91joshualitt    // We push back some dummy pointers which will later become our header
2343466a1ade066f96823dbc7963767da3973afd91joshualitt    for (int i = 0; i <= kCode; i++) {
2443466a1ade066f96823dbc7963767da3973afd91joshualitt        fShaderStrings.push_back();
2596fcdcc219d2a0d3579719b84b28bede76efba64halcanary        fCompilerStrings.push_back(nullptr);
2643466a1ade066f96823dbc7963767da3973afd91joshualitt        fCompilerStringLengths.push_back(0);
2743466a1ade066f96823dbc7963767da3973afd91joshualitt    }
2843466a1ade066f96823dbc7963767da3973afd91joshualitt
2943466a1ade066f96823dbc7963767da3973afd91joshualitt    this->main() = "void main() {";
3030ba436f04e61d4505fb854d5fc56079636e0788joshualitt}
3130ba436f04e61d4505fb854d5fc56079636e0788joshualitt
3299938a8ef24e2dd5b39f78638742e9b50ab6d9bfBrian Salomonvoid GrGLSLShaderBuilder::declAppend(const GrShaderVar& var) {
33b2f94d1f4a74f82ea4dd3feb1690ef6d05892afbegdaniel    SkString tempDecl;
3494efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    var.appendDecl(fProgramBuilder->shaderCaps(), &tempDecl);
35b2f94d1f4a74f82ea4dd3feb1690ef6d05892afbegdaniel    this->codeAppendf("%s;", tempDecl.c_str());
36b2f94d1f4a74f82ea4dd3feb1690ef6d05892afbegdaniel}
37b2f94d1f4a74f82ea4dd3feb1690ef6d05892afbegdaniel
3875864b09e11a1918f202093d042f23ca0b3c8530csmartdaltonvoid GrGLSLShaderBuilder::declareGlobal(const GrShaderVar& v) {
3975864b09e11a1918f202093d042f23ca0b3c8530csmartdalton    v.appendDecl(this->getProgramBuilder()->shaderCaps(), &this->definitions());
4075864b09e11a1918f202093d042f23ca0b3c8530csmartdalton    this->definitions().append(";");
4175864b09e11a1918f202093d042f23ca0b3c8530csmartdalton}
4275864b09e11a1918f202093d042f23ca0b3c8530csmartdalton
432d721d33aad192cc8a7a1321504b39bdca2a57ceegdanielvoid GrGLSLShaderBuilder::emitFunction(GrSLType returnType,
442d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                                       const char* name,
452d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                                       int argCnt,
4699938a8ef24e2dd5b39f78638742e9b50ab6d9bfBrian Salomon                                       const GrShaderVar* args,
472d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                                       const char* body,
482d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                                       SkString* outName) {
4943466a1ade066f96823dbc7963767da3973afd91joshualitt    this->functions().append(GrGLSLTypeString(returnType));
5030ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fProgramBuilder->nameVariable(outName, '\0', name);
5143466a1ade066f96823dbc7963767da3973afd91joshualitt    this->functions().appendf(" %s", outName->c_str());
5243466a1ade066f96823dbc7963767da3973afd91joshualitt    this->functions().append("(");
5330ba436f04e61d4505fb854d5fc56079636e0788joshualitt    for (int i = 0; i < argCnt; ++i) {
5494efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon        args[i].appendDecl(fProgramBuilder->shaderCaps(), &this->functions());
5530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        if (i < argCnt - 1) {
5643466a1ade066f96823dbc7963767da3973afd91joshualitt            this->functions().append(", ");
5730ba436f04e61d4505fb854d5fc56079636e0788joshualitt        }
5830ba436f04e61d4505fb854d5fc56079636e0788joshualitt    }
5943466a1ade066f96823dbc7963767da3973afd91joshualitt    this->functions().append(") {\n");
6043466a1ade066f96823dbc7963767da3973afd91joshualitt    this->functions().append(body);
6143466a1ade066f96823dbc7963767da3973afd91joshualitt    this->functions().append("}\n\n");
6230ba436f04e61d4505fb854d5fc56079636e0788joshualitt}
6330ba436f04e61d4505fb854d5fc56079636e0788joshualitt
64101b844d6ba031de5c4e95b43f9292f266799237Brian Salomonstatic inline void append_texture_swizzle(SkString* out, GrSwizzle swizzle) {
65101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon    if (swizzle != GrSwizzle::RGBA()) {
66101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon        out->appendf(".%s", swizzle.c_str());
67101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon    }
68101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon}
69101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon
702d721d33aad192cc8a7a1321504b39bdca2a57ceegdanielvoid GrGLSLShaderBuilder::appendTextureLookup(SkString* out,
7109aa1fce69b214714171db12c341aebd78dd29eaegdaniel                                              SamplerHandle samplerHandle,
722d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                                              const char* coordName,
732d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                                              GrSLType varyingType) const {
7499938a8ef24e2dd5b39f78638742e9b50ab6d9bfBrian Salomon    const GrShaderVar& sampler = fProgramBuilder->samplerVariable(samplerHandle);
75101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon    GrSLType samplerType = sampler.getType();
76990dbc88796f656418bcc4c196df30ed9bef6345egdaniel    if (samplerType == kTexture2DRectSampler_GrSLType) {
77e179a9167f71dfc41668b05d40082aae76367fa6bsalomon        if (varyingType == kVec2f_GrSLType) {
782b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            out->appendf("texture(%s, textureSize(%s) * %s)",
79101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon                         sampler.c_str(), sampler.c_str(), coordName);
80e179a9167f71dfc41668b05d40082aae76367fa6bsalomon        } else {
812b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            out->appendf("texture(%s, vec3(textureSize(%s) * %s.xy, %s.z))",
82101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon                         sampler.c_str(), sampler.c_str(), coordName, coordName);
83e179a9167f71dfc41668b05d40082aae76367fa6bsalomon        }
84e179a9167f71dfc41668b05d40082aae76367fa6bsalomon    } else {
852b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        out->appendf("texture(%s, %s)", sampler.c_str(), coordName);
86e179a9167f71dfc41668b05d40082aae76367fa6bsalomon    }
87101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon    append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
8830ba436f04e61d4505fb854d5fc56079636e0788joshualitt}
8930ba436f04e61d4505fb854d5fc56079636e0788joshualitt
9009aa1fce69b214714171db12c341aebd78dd29eaegdanielvoid GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle,
912d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                                              const char* coordName,
9277320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                                              GrSLType varyingType,
9377320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                                              GrGLSLColorSpaceXformHelper* colorXformHelper) {
94c624d9d212c4168fc6c202a8535ddff8a3bfb16aBrian Osman    if (colorXformHelper && colorXformHelper->isValid()) {
9577320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman        // With a color gamut transform, we need to wrap the lookup in another function call
9677320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman        SkString lookup;
9777320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman        this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
9877320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman        this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
9977320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    } else {
10077320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman        this->appendTextureLookup(&this->code(), samplerHandle, coordName, varyingType);
10177320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    }
10230ba436f04e61d4505fb854d5fc56079636e0788joshualitt}
10330ba436f04e61d4505fb854d5fc56079636e0788joshualitt
10477320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosmanvoid GrGLSLShaderBuilder::appendTextureLookupAndModulate(
10577320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                                                    const char* modulation,
10677320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                                                    SamplerHandle samplerHandle,
10777320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                                                    const char* coordName,
10877320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                                                    GrSLType varyingType,
10977320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                                                    GrGLSLColorSpaceXformHelper* colorXformHelper) {
11030ba436f04e61d4505fb854d5fc56079636e0788joshualitt    SkString lookup;
11109aa1fce69b214714171db12c341aebd78dd29eaegdaniel    this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
112c624d9d212c4168fc6c202a8535ddff8a3bfb16aBrian Osman    if (colorXformHelper && colorXformHelper->isValid()) {
11377320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman        SkString xform;
11477320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman        this->appendColorGamutXform(&xform, lookup.c_str(), colorXformHelper);
11577320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman        this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(xform)).c_str());
11677320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    } else {
11777320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman        this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str());
11877320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    }
11977320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman}
12077320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman
12177320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosmanvoid GrGLSLShaderBuilder::appendColorGamutXform(SkString* out,
12277320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                                                const char* srcColor,
12377320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                                                GrGLSLColorSpaceXformHelper* colorXformHelper) {
12477320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    // Our color is (r, g, b, a), but we want to multiply (r, g, b, 1) by our matrix, then
12577320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    // re-insert the original alpha. The supplied srcColor is likely to be of the form
1265192475bd8cb98e8e0c1192ab5ece7b8595701d6brianosman    // "texture(...)", and we don't want to evaluate that twice, so wrap everything in a function.
12799938a8ef24e2dd5b39f78638742e9b50ab6d9bfBrian Salomon    static const GrShaderVar gColorGamutXformArgs[] = {
12899938a8ef24e2dd5b39f78638742e9b50ab6d9bfBrian Salomon        GrShaderVar("color", kVec4f_GrSLType),
12999938a8ef24e2dd5b39f78638742e9b50ab6d9bfBrian Salomon        GrShaderVar("xform", kMat44f_GrSLType),
13077320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    };
13177320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    SkString functionBody;
1320bd783f951a004ccca175b166f2b30a0fd18a6f6Brian Osman    // Gamut xform, clamp to destination gamut. We only support/have premultiplied textures, so we
1330bd783f951a004ccca175b166f2b30a0fd18a6f6Brian Osman    // always just clamp to alpha.
1340bd783f951a004ccca175b166f2b30a0fd18a6f6Brian Osman    functionBody.append("\tcolor.rgb = clamp((xform * vec4(color.rgb, 1.0)).rgb, 0.0, color.a);\n");
13577320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    functionBody.append("\treturn color;");
13677320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    SkString colorGamutXformFuncName;
13777320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    this->emitFunction(kVec4f_GrSLType,
13877320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                       "colorGamutXform",
13977320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                       SK_ARRAY_COUNT(gColorGamutXformArgs),
14077320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                       gColorGamutXformArgs,
14177320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                       functionBody.c_str(),
14277320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                       &colorGamutXformFuncName);
14377320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman
144c624d9d212c4168fc6c202a8535ddff8a3bfb16aBrian Osman    GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler();
14577320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    out->appendf("%s(%s, %s)", colorGamutXformFuncName.c_str(), srcColor,
146c624d9d212c4168fc6c202a8535ddff8a3bfb16aBrian Osman                 uniformHandler->getUniformCStr(colorXformHelper->gamutXformUniform()));
14777320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman}
14877320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman
14977320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosmanvoid GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor,
15077320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman                                                GrGLSLColorSpaceXformHelper* colorXformHelper) {
15177320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    SkString xform;
15277320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    this->appendColorGamutXform(&xform, srcColor, colorXformHelper);
15377320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    this->codeAppend(xform.c_str());
15430ba436f04e61d4505fb854d5fc56079636e0788joshualitt}
15530ba436f04e61d4505fb854d5fc56079636e0788joshualitt
156f8a6ce8d8c54cab5456d3099fa07e460c889c2e6cdaltonvoid GrGLSLShaderBuilder::appendTexelFetch(SkString* out,
15709aa1fce69b214714171db12c341aebd78dd29eaegdaniel                                           SamplerHandle samplerHandle,
158f8a6ce8d8c54cab5456d3099fa07e460c889c2e6cdalton                                           const char* coordExpr) const {
15999938a8ef24e2dd5b39f78638742e9b50ab6d9bfBrian Salomon    const GrShaderVar& sampler = fProgramBuilder->samplerVariable(samplerHandle);
16094efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    SkASSERT(fProgramBuilder->shaderCaps()->texelFetchSupport());
161101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon    SkASSERT(GrSLTypeIsCombinedSamplerType(sampler.getType()));
162f8a6ce8d8c54cab5456d3099fa07e460c889c2e6cdalton
163101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon    out->appendf("texelFetch(%s, %s)", sampler.c_str(), coordExpr);
164f8a6ce8d8c54cab5456d3099fa07e460c889c2e6cdalton
165101b844d6ba031de5c4e95b43f9292f266799237Brian Salomon    append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
166f8a6ce8d8c54cab5456d3099fa07e460c889c2e6cdalton}
167f8a6ce8d8c54cab5456d3099fa07e460c889c2e6cdalton
16809aa1fce69b214714171db12c341aebd78dd29eaegdanielvoid GrGLSLShaderBuilder::appendTexelFetch(SamplerHandle samplerHandle, const char* coordExpr) {
16909aa1fce69b214714171db12c341aebd78dd29eaegdaniel    this->appendTexelFetch(&this->code(), samplerHandle, coordExpr);
170f8a6ce8d8c54cab5456d3099fa07e460c889c2e6cdalton}
171f8a6ce8d8c54cab5456d3099fa07e460c889c2e6cdalton
172f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomonvoid GrGLSLShaderBuilder::appendImageStorageLoad(SkString* out, ImageStorageHandle handle,
173f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon                                                 const char* coordExpr) {
174f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    const GrShaderVar& imageStorage = fProgramBuilder->imageStorageVariable(handle);
175f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    out->appendf("imageLoad(%s, %s)", imageStorage.c_str(), coordExpr);
176f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon}
177f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon
178f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomonvoid GrGLSLShaderBuilder::appendImageStorageLoad(ImageStorageHandle handle, const char* coordExpr) {
179f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    this->appendImageStorageLoad(&this->code(), handle, coordExpr);
180f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon}
181f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon
18233ad701bc30387127c427fb1e38c781d5de33491cdaltonbool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
18333ad701bc30387127c427fb1e38c781d5de33491cdalton    if (featureBit & fFeaturesAddedMask) {
18433ad701bc30387127c427fb1e38c781d5de33491cdalton        return false;
18530ba436f04e61d4505fb854d5fc56079636e0788joshualitt    }
18633ad701bc30387127c427fb1e38c781d5de33491cdalton    this->extensions().appendf("#extension %s: require\n", extensionName);
18733ad701bc30387127c427fb1e38c781d5de33491cdalton    fFeaturesAddedMask |= featureBit;
18833ad701bc30387127c427fb1e38c781d5de33491cdalton    return true;
18930ba436f04e61d4505fb854d5fc56079636e0788joshualitt}
19030ba436f04e61d4505fb854d5fc56079636e0788joshualitt
1912d721d33aad192cc8a7a1321504b39bdca2a57ceegdanielvoid GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
19247bb38283072dc87dc93220cd2f370ca109972ffjoshualitt    for (int i = 0; i < vars.count(); ++i) {
19394efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon        vars[i].appendDecl(fProgramBuilder->shaderCaps(), out);
19447bb38283072dc87dc93220cd2f370ca109972ffjoshualitt        out->append(";\n");
19547bb38283072dc87dc93220cd2f370ca109972ffjoshualitt    }
19647bb38283072dc87dc93220cd2f370ca109972ffjoshualitt}
19747bb38283072dc87dc93220cd2f370ca109972ffjoshualitt
1982d721d33aad192cc8a7a1321504b39bdca2a57ceegdanielvoid GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
19994efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    SkASSERT(fProgramBuilder->shaderCaps()->generation() >= k330_GrGLSLGeneration ||
20094efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon             fProgramBuilder->shaderCaps()->mustEnableAdvBlendEqs());
201e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton    fLayoutParams[interface].push_back() = param;
202e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton}
203e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton
2042d721d33aad192cc8a7a1321504b39bdca2a57ceegdanielvoid GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() {
205e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton    static const char* interfaceQualifierNames[] = {
206276cc4113a6440b842c0dacb6d668ee3b45a3b7dcsmartdalton        "in",
207e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton        "out"
208e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton    };
209e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton
210e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton    for (int interface = 0; interface <= kLastInterfaceQualifier; ++interface) {
211e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton        const SkTArray<SkString>& params = fLayoutParams[interface];
212e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton        if (params.empty()) {
213e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton            continue;
214e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton        }
215e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton        this->layoutQualifiers().appendf("layout(%s", params[0].c_str());
216e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton        for (int i = 1; i < params.count(); ++i) {
217e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton            this->layoutQualifiers().appendf(", %s", params[i].c_str());
218e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton        }
219e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton        this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]);
220e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton    }
221e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton
222276cc4113a6440b842c0dacb6d668ee3b45a3b7dcsmartdalton    GR_STATIC_ASSERT(0 == GrGLSLShaderBuilder::kIn_InterfaceQualifier);
223276cc4113a6440b842c0dacb6d668ee3b45a3b7dcsmartdalton    GR_STATIC_ASSERT(1 == GrGLSLShaderBuilder::kOut_InterfaceQualifier);
224e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton    GR_STATIC_ASSERT(SK_ARRAY_COUNT(interfaceQualifierNames) == kLastInterfaceQualifier + 1);
225e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton}
226e4017d8ca709bc0b4fc0f95c26eb592a8d5c597bcdalton
2272d721d33aad192cc8a7a1321504b39bdca2a57ceegdanielvoid GrGLSLShaderBuilder::finalize(uint32_t visibility) {
22843466a1ade066f96823dbc7963767da3973afd91joshualitt    SkASSERT(!fFinalized);
22994efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    this->versionDecl() = fProgramBuilder->shaderCaps()->versionDeclString();
230574a4c153d8a3f42b2806848f5c23cbf55e18bbbegdaniel    this->compileAndAppendLayoutQualifiers();
231c8a66eb6335b4d92e052ebb37442baaa6c1e386eegdaniel    SkASSERT(visibility);
2325e58ceea8569f0d90ff7e3daf5de2def50407212cdalton    fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms());
233574a4c153d8a3f42b2806848f5c23cbf55e18bbbegdaniel    this->appendDecls(fInputs, &this->inputs());
234574a4c153d8a3f42b2806848f5c23cbf55e18bbbegdaniel    this->appendDecls(fOutputs, &this->outputs());
235574a4c153d8a3f42b2806848f5c23cbf55e18bbbegdaniel    this->onFinalize();
23643466a1ade066f96823dbc7963767da3973afd91joshualitt    // append the 'footer' to code
23743466a1ade066f96823dbc7963767da3973afd91joshualitt    this->code().append("}");
23843466a1ade066f96823dbc7963767da3973afd91joshualitt
23943466a1ade066f96823dbc7963767da3973afd91joshualitt    for (int i = 0; i <= fCodeIndex; i++) {
24043466a1ade066f96823dbc7963767da3973afd91joshualitt        fCompilerStrings[i] = fShaderStrings[i].c_str();
24143466a1ade066f96823dbc7963767da3973afd91joshualitt        fCompilerStringLengths[i] = (int)fShaderStrings[i].size();
24243466a1ade066f96823dbc7963767da3973afd91joshualitt    }
24343466a1ade066f96823dbc7963767da3973afd91joshualitt
24443466a1ade066f96823dbc7963767da3973afd91joshualitt    fFinalized = true;
24543466a1ade066f96823dbc7963767da3973afd91joshualitt}
246