1 // 2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #include "compiler/Initialize.h" 8 #include "compiler/ParseHelper.h" 9 #include "compiler/ShHandle.h" 10 #include "compiler/ValidateLimitations.h" 11 12 namespace { 13 bool InitializeSymbolTable( 14 const TBuiltInStrings& builtInStrings, 15 ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources, 16 TInfoSink& infoSink, TSymbolTable& symbolTable) 17 { 18 TIntermediate intermediate(infoSink); 19 TExtensionBehavior extBehavior; 20 TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, infoSink); 21 22 GlobalParseContext = &parseContext; 23 24 assert(symbolTable.isEmpty()); 25 // 26 // Parse the built-ins. This should only happen once per 27 // language symbol table. 28 // 29 // Push the symbol table to give it an initial scope. This 30 // push should not have a corresponding pop, so that built-ins 31 // are preserved, and the test for an empty table fails. 32 // 33 symbolTable.push(); 34 35 for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i) 36 { 37 const char* builtInShaders = i->c_str(); 38 int builtInLengths = static_cast<int>(i->size()); 39 if (builtInLengths <= 0) 40 continue; 41 42 if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0) 43 { 44 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins"); 45 return false; 46 } 47 } 48 49 IdentifyBuiltIns(type, spec, resources, symbolTable); 50 51 return true; 52 } 53 54 class TScopedPoolAllocator { 55 public: 56 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop) 57 : mAllocator(allocator), mPushPopAllocator(pushPop) { 58 if (mPushPopAllocator) mAllocator->push(); 59 SetGlobalPoolAllocator(mAllocator); 60 } 61 ~TScopedPoolAllocator() { 62 SetGlobalPoolAllocator(NULL); 63 if (mPushPopAllocator) mAllocator->pop(); 64 } 65 66 private: 67 TPoolAllocator* mAllocator; 68 bool mPushPopAllocator; 69 }; 70 } // namespace 71 72 TShHandleBase::TShHandleBase() { 73 allocator.push(); 74 SetGlobalPoolAllocator(&allocator); 75 } 76 77 TShHandleBase::~TShHandleBase() { 78 SetGlobalPoolAllocator(NULL); 79 allocator.popAll(); 80 } 81 82 TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec) 83 : shaderType(type), 84 shaderSpec(spec) 85 { 86 } 87 88 TCompiler::~TCompiler() 89 { 90 } 91 92 bool TCompiler::Init(const ShBuiltInResources& resources) 93 { 94 TScopedPoolAllocator scopedAlloc(&allocator, false); 95 96 // Generate built-in symbol table. 97 if (!InitBuiltInSymbolTable(resources)) 98 return false; 99 InitExtensionBehavior(resources, extensionBehavior); 100 101 return true; 102 } 103 104 bool TCompiler::compile(const char* const shaderStrings[], 105 const int numStrings, 106 int compileOptions) 107 { 108 TScopedPoolAllocator scopedAlloc(&allocator, true); 109 clearResults(); 110 111 if (numStrings == 0) 112 return true; 113 114 // If compiling for WebGL, validate loop and indexing as well. 115 if (shaderSpec == SH_WEBGL_SPEC) 116 compileOptions |= SH_VALIDATE_LOOP_INDEXING; 117 118 TIntermediate intermediate(infoSink); 119 TParseContext parseContext(symbolTable, extensionBehavior, intermediate, 120 shaderType, shaderSpec, infoSink); 121 GlobalParseContext = &parseContext; 122 123 // We preserve symbols at the built-in level from compile-to-compile. 124 // Start pushing the user-defined symbols at global level. 125 symbolTable.push(); 126 if (!symbolTable.atGlobalLevel()) 127 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); 128 129 // Parse shader. 130 bool success = 131 (PaParseStrings(numStrings, shaderStrings, NULL, &parseContext) == 0) && 132 (parseContext.treeRoot != NULL); 133 if (success) { 134 TIntermNode* root = parseContext.treeRoot; 135 success = intermediate.postProcess(root); 136 137 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) 138 success = validateLimitations(root); 139 140 if (success && (compileOptions & SH_INTERMEDIATE_TREE)) 141 intermediate.outputTree(root); 142 143 if (success && (compileOptions & SH_OBJECT_CODE)) 144 translate(root); 145 146 if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) 147 collectAttribsUniforms(root); 148 } 149 150 // Cleanup memory. 151 intermediate.remove(parseContext.treeRoot); 152 // Ensure symbol table is returned to the built-in level, 153 // throwing away all but the built-ins. 154 while (!symbolTable.atBuiltInLevel()) 155 symbolTable.pop(); 156 157 return success; 158 } 159 160 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources) 161 { 162 TBuiltIns builtIns; 163 164 builtIns.initialize(shaderType, shaderSpec, resources); 165 return InitializeSymbolTable(builtIns.getBuiltInStrings(), 166 shaderType, shaderSpec, resources, infoSink, symbolTable); 167 } 168 169 void TCompiler::clearResults() 170 { 171 infoSink.info.erase(); 172 infoSink.obj.erase(); 173 infoSink.debug.erase(); 174 175 attribs.clear(); 176 uniforms.clear(); 177 } 178 179 bool TCompiler::validateLimitations(TIntermNode* root) { 180 ValidateLimitations validate(shaderType, infoSink.info); 181 root->traverse(&validate); 182 return validate.numErrors() == 0; 183 } 184 185 void TCompiler::collectAttribsUniforms(TIntermNode* root) 186 { 187 CollectAttribsUniforms collect(attribs, uniforms); 188 root->traverse(&collect); 189 } 190