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 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 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 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 59 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 100 void GrGLSLShaderBuilder::appendTextureLookup(const GrGLSLTextureSampler& sampler, 101 const char* coordName, 102 GrSLType varyingType) { 103 this->appendTextureLookup(&this->code(), sampler, coordName, varyingType); 104 } 105 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 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 124 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 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 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 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