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 24namespace 25{ 26class TScopedPoolAllocator { 27public: 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 40private: 41 TPoolAllocator* mAllocator; 42 bool mPushPopAllocator; 43}; 44} // namespace 45 46// 47// Initialize built-in resources with minimum expected values. 48// 49ShBuiltInResources::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 73TCompiler::TCompiler(GLenum type) 74 : shaderType(type), 75 maxCallStackDepth(UINT_MAX) 76{ 77 allocator.push(); 78 SetGlobalPoolAllocator(&allocator); 79} 80 81TCompiler::~TCompiler() 82{ 83 SetGlobalPoolAllocator(nullptr); 84 allocator.popAll(); 85} 86 87bool 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 101bool 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 164bool 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 202void TCompiler::clearResults() 203{ 204 infoSink.info.erase(); 205 infoSink.obj.erase(); 206 infoSink.debug.erase(); 207} 208 209bool 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"; 231 return false; 232 } 233 234 return true; 235} 236 237bool TCompiler::validateLimitations(TIntermNode* root) { 238 ValidateLimitations validate(shaderType, infoSink.info); 239 root->traverse(&validate); 240 return validate.numErrors() == 0; 241} 242 243const TExtensionBehavior& TCompiler::getExtensionBehavior() const 244{ 245 return extensionBehavior; 246} 247 248bool InitCompilerGlobals() 249{ 250 if(!InitializePoolIndex()) 251 { 252 assert(0 && "InitCompilerGlobals(): Failed to initalize global pool"); 253 return false; 254 } 255 256 if(!InitializeParseContextIndex()) 257 { 258 assert(0 && "InitCompilerGlobals(): Failed to initalize parse context"); 259 return false; 260 } 261 262 return true; 263} 264 265void FreeCompilerGlobals() 266{ 267 FreeParseContextIndex(); 268 FreePoolIndex(); 269} 270