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 OES_EGL_image_external_essl3 = 0; 70 71 MaxCallStackDepth = UINT_MAX; 72 } 73 74 TCompiler::TCompiler(GLenum type) 75 : shaderType(type), 76 maxCallStackDepth(UINT_MAX) 77 { 78 allocator.push(); 79 SetGlobalPoolAllocator(&allocator); 80 } 81 82 TCompiler::~TCompiler() 83 { 84 SetGlobalPoolAllocator(nullptr); 85 allocator.popAll(); 86 } 87 88 bool TCompiler::Init(const ShBuiltInResources& resources) 89 { 90 shaderVersion = 100; 91 maxCallStackDepth = resources.MaxCallStackDepth; 92 TScopedPoolAllocator scopedAlloc(&allocator, false); 93 94 // Generate built-in symbol table. 95 if (!InitBuiltInSymbolTable(resources)) 96 return false; 97 InitExtensionBehavior(resources, extensionBehavior); 98 99 return true; 100 } 101 102 bool TCompiler::compile(const char* const shaderStrings[], 103 const int numStrings, 104 int compileOptions) 105 { 106 TScopedPoolAllocator scopedAlloc(&allocator, true); 107 clearResults(); 108 109 if (numStrings == 0) 110 return true; 111 112 // First string is path of source file if flag is set. The actual source follows. 113 const char* sourcePath = nullptr; 114 int firstSource = 0; 115 if (compileOptions & SH_SOURCE_PATH) 116 { 117 sourcePath = shaderStrings[0]; 118 ++firstSource; 119 } 120 121 TIntermediate intermediate(infoSink); 122 TParseContext parseContext(symbolTable, extensionBehavior, intermediate, 123 shaderType, compileOptions, true, 124 sourcePath, infoSink); 125 SetGlobalParseContext(&parseContext); 126 127 // We preserve symbols at the built-in level from compile-to-compile. 128 // Start pushing the user-defined symbols at global level. 129 symbolTable.push(); 130 if (!symbolTable.atGlobalLevel()) 131 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); 132 133 // Parse shader. 134 bool success = 135 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) && 136 (parseContext.getTreeRoot() != nullptr); 137 138 shaderVersion = parseContext.getShaderVersion(); 139 140 if (success) { 141 TIntermNode* root = parseContext.getTreeRoot(); 142 success = intermediate.postProcess(root); 143 144 if (success) 145 success = validateCallDepth(root, infoSink); 146 147 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) 148 success = validateLimitations(root); 149 150 if (success && (compileOptions & SH_INTERMEDIATE_TREE)) 151 intermediate.outputTree(root); 152 153 if (success && (compileOptions & SH_OBJECT_CODE)) 154 success = translate(root); 155 } 156 157 // Ensure symbol table is returned to the built-in level, 158 // throwing away all but the built-ins. 159 while (!symbolTable.atBuiltInLevel()) 160 symbolTable.pop(); 161 162 return success; 163 } 164 165 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) 166 { 167 assert(symbolTable.isEmpty()); 168 symbolTable.push(); // COMMON_BUILTINS 169 symbolTable.push(); // ESSL1_BUILTINS 170 symbolTable.push(); // ESSL3_BUILTINS 171 172 TPublicType integer; 173 integer.type = EbtInt; 174 integer.primarySize = 1; 175 integer.secondarySize = 1; 176 integer.array = false; 177 178 TPublicType floatingPoint; 179 floatingPoint.type = EbtFloat; 180 floatingPoint.primarySize = 1; 181 floatingPoint.secondarySize = 1; 182 floatingPoint.array = false; 183 184 switch(shaderType) 185 { 186 case GL_FRAGMENT_SHADER: 187 symbolTable.setDefaultPrecision(integer, EbpMedium); 188 break; 189 case GL_VERTEX_SHADER: 190 symbolTable.setDefaultPrecision(integer, EbpHigh); 191 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh); 192 break; 193 default: assert(false && "Language not supported"); 194 } 195 196 InsertBuiltInFunctions(shaderType, resources, symbolTable); 197 198 IdentifyBuiltIns(shaderType, resources, symbolTable); 199 200 return true; 201 } 202 203 void TCompiler::clearResults() 204 { 205 infoSink.info.erase(); 206 infoSink.obj.erase(); 207 infoSink.debug.erase(); 208 } 209 210 bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink) 211 { 212 AnalyzeCallDepth validator(root); 213 214 unsigned int depth = validator.analyzeCallDepth(); 215 216 if(depth == 0) 217 { 218 infoSink.info.prefix(EPrefixError); 219 infoSink.info << "Missing main()"; 220 return false; 221 } 222 else if(depth == UINT_MAX) 223 { 224 infoSink.info.prefix(EPrefixError); 225 infoSink.info << "Function recursion detected"; 226 return false; 227 } 228 else if(depth > maxCallStackDepth) 229 { 230 infoSink.info.prefix(EPrefixError); 231 infoSink.info << "Function call stack too deep (depth was "; 232 infoSink.info << depth; 233 infoSink.info << " while maximum call stack depth is "; 234 infoSink.info << maxCallStackDepth; 235 infoSink.info << ")"; 236 return false; 237 } 238 239 return true; 240 } 241 242 bool TCompiler::validateLimitations(TIntermNode* root) { 243 ValidateLimitations validate(shaderType, infoSink.info); 244 root->traverse(&validate); 245 return validate.numErrors() == 0; 246 } 247 248 const TExtensionBehavior& TCompiler::getExtensionBehavior() const 249 { 250 return extensionBehavior; 251 } 252 253 bool InitCompilerGlobals() 254 { 255 if(!InitializePoolIndex()) 256 { 257 assert(0 && "InitCompilerGlobals(): Failed to initalize global pool"); 258 return false; 259 } 260 261 if(!InitializeParseContextIndex()) 262 { 263 assert(0 && "InitCompilerGlobals(): Failed to initalize parse context"); 264 return false; 265 } 266 267 return true; 268 } 269 270 void FreeCompilerGlobals() 271 { 272 FreeParseContextIndex(); 273 FreePoolIndex(); 274 } 275