1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "Compiler.h" 16 17 #include "AnalyzeCallDepth.h" 18 #include "Initialize.h" 19 #include "InitializeParseContext.h" 20 #include "InitializeGlobals.h" 21 #include "ParseHelper.h" 22 #include "ValidateLimitations.h" 23 24 namespace 25 { 26 class TScopedPoolAllocator { 27 public: 28 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop) 29 : mAllocator(allocator), mPushPopAllocator(pushPop) 30 { 31 if (mPushPopAllocator) mAllocator->push(); 32 SetGlobalPoolAllocator(mAllocator); 33 } 34 ~TScopedPoolAllocator() 35 { 36 SetGlobalPoolAllocator(nullptr); 37 if (mPushPopAllocator) mAllocator->pop(); 38 } 39 40 private: 41 TPoolAllocator* mAllocator; 42 bool mPushPopAllocator; 43 }; 44 } // namespace 45 46 // 47 // Initialize built-in resources with minimum expected values. 48 // 49 ShBuiltInResources::ShBuiltInResources() 50 { 51 // Constants. 52 MaxVertexAttribs = 8; 53 MaxVertexUniformVectors = 128; 54 MaxVaryingVectors = 8; 55 MaxVertexTextureImageUnits = 0; 56 MaxCombinedTextureImageUnits = 8; 57 MaxTextureImageUnits = 8; 58 MaxFragmentUniformVectors = 16; 59 MaxDrawBuffers = 1; 60 MaxVertexOutputVectors = 16; 61 MaxFragmentInputVectors = 15; 62 MinProgramTexelOffset = -8; 63 MaxProgramTexelOffset = 7; 64 65 // Extensions. 66 OES_standard_derivatives = 0; 67 OES_fragment_precision_high = 0; 68 OES_EGL_image_external = 0; 69 70 MaxCallStackDepth = UINT_MAX; 71 } 72 73 TCompiler::TCompiler(GLenum type) 74 : shaderType(type), 75 maxCallStackDepth(UINT_MAX) 76 { 77 allocator.push(); 78 SetGlobalPoolAllocator(&allocator); 79 } 80 81 TCompiler::~TCompiler() 82 { 83 SetGlobalPoolAllocator(nullptr); 84 allocator.popAll(); 85 } 86 87 bool TCompiler::Init(const ShBuiltInResources& resources) 88 { 89 shaderVersion = 100; 90 maxCallStackDepth = resources.MaxCallStackDepth; 91 TScopedPoolAllocator scopedAlloc(&allocator, false); 92 93 // Generate built-in symbol table. 94 if (!InitBuiltInSymbolTable(resources)) 95 return false; 96 InitExtensionBehavior(resources, extensionBehavior); 97 98 return true; 99 } 100 101 bool TCompiler::compile(const char* const shaderStrings[], 102 const int numStrings, 103 int compileOptions) 104 { 105 TScopedPoolAllocator scopedAlloc(&allocator, true); 106 clearResults(); 107 108 if (numStrings == 0) 109 return true; 110 111 // First string is path of source file if flag is set. The actual source follows. 112 const char* sourcePath = nullptr; 113 int firstSource = 0; 114 if (compileOptions & SH_SOURCE_PATH) 115 { 116 sourcePath = shaderStrings[0]; 117 ++firstSource; 118 } 119 120 TIntermediate intermediate(infoSink); 121 TParseContext parseContext(symbolTable, extensionBehavior, intermediate, 122 shaderType, compileOptions, true, 123 sourcePath, infoSink); 124 SetGlobalParseContext(&parseContext); 125 126 // We preserve symbols at the built-in level from compile-to-compile. 127 // Start pushing the user-defined symbols at global level. 128 symbolTable.push(); 129 if (!symbolTable.atGlobalLevel()) 130 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); 131 132 // Parse shader. 133 bool success = 134 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) && 135 (parseContext.getTreeRoot() != nullptr); 136 137 shaderVersion = parseContext.getShaderVersion(); 138 139 if (success) { 140 TIntermNode* root = parseContext.getTreeRoot(); 141 success = intermediate.postProcess(root); 142 143 if (success) 144 success = validateCallDepth(root, infoSink); 145 146 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) 147 success = validateLimitations(root); 148 149 if (success && (compileOptions & SH_INTERMEDIATE_TREE)) 150 intermediate.outputTree(root); 151 152 if (success && (compileOptions & SH_OBJECT_CODE)) 153 success = translate(root); 154 } 155 156 // Ensure symbol table is returned to the built-in level, 157 // throwing away all but the built-ins. 158 while (!symbolTable.atBuiltInLevel()) 159 symbolTable.pop(); 160 161 return success; 162 } 163 164 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) 165 { 166 assert(symbolTable.isEmpty()); 167 symbolTable.push(); // COMMON_BUILTINS 168 symbolTable.push(); // ESSL1_BUILTINS 169 symbolTable.push(); // ESSL3_BUILTINS 170 171 TPublicType integer; 172 integer.type = EbtInt; 173 integer.primarySize = 1; 174 integer.secondarySize = 1; 175 integer.array = false; 176 177 TPublicType floatingPoint; 178 floatingPoint.type = EbtFloat; 179 floatingPoint.primarySize = 1; 180 floatingPoint.secondarySize = 1; 181 floatingPoint.array = false; 182 183 switch(shaderType) 184 { 185 case GL_FRAGMENT_SHADER: 186 symbolTable.setDefaultPrecision(integer, EbpMedium); 187 break; 188 case GL_VERTEX_SHADER: 189 symbolTable.setDefaultPrecision(integer, EbpHigh); 190 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh); 191 break; 192 default: assert(false && "Language not supported"); 193 } 194 195 InsertBuiltInFunctions(shaderType, resources, symbolTable); 196 197 IdentifyBuiltIns(shaderType, resources, symbolTable); 198 199 return true; 200 } 201 202 void TCompiler::clearResults() 203 { 204 infoSink.info.erase(); 205 infoSink.obj.erase(); 206 infoSink.debug.erase(); 207 } 208 209 bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink) 210 { 211 AnalyzeCallDepth validator(root); 212 213 unsigned int depth = validator.analyzeCallDepth(); 214 215 if(depth == 0) 216 { 217 infoSink.info.prefix(EPrefixError); 218 infoSink.info << "Missing main()"; 219 return false; 220 } 221 else if(depth == UINT_MAX) 222 { 223 infoSink.info.prefix(EPrefixError); 224 infoSink.info << "Function recursion detected"; 225 return false; 226 } 227 else if(depth > maxCallStackDepth) 228 { 229 infoSink.info.prefix(EPrefixError); 230 infoSink.info << "Function call stack too deep (depth was "; 231 infoSink.info << depth; 232 infoSink.info << " while maximum call stack depth is "; 233 infoSink.info << maxCallStackDepth; 234 infoSink.info << ")"; 235 return false; 236 } 237 238 return true; 239 } 240 241 bool TCompiler::validateLimitations(TIntermNode* root) { 242 ValidateLimitations validate(shaderType, infoSink.info); 243 root->traverse(&validate); 244 return validate.numErrors() == 0; 245 } 246 247 const TExtensionBehavior& TCompiler::getExtensionBehavior() const 248 { 249 return extensionBehavior; 250 } 251 252 bool InitCompilerGlobals() 253 { 254 if(!InitializePoolIndex()) 255 { 256 assert(0 && "InitCompilerGlobals(): Failed to initalize global pool"); 257 return false; 258 } 259 260 if(!InitializeParseContextIndex()) 261 { 262 assert(0 && "InitCompilerGlobals(): Failed to initalize parse context"); 263 return false; 264 } 265 266 return true; 267 } 268 269 void FreeCompilerGlobals() 270 { 271 FreeParseContextIndex(); 272 FreePoolIndex(); 273 } 274