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 12namespace { 13bool 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 54class TScopedPoolAllocator { 55public: 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 66private: 67 TPoolAllocator* mAllocator; 68 bool mPushPopAllocator; 69}; 70} // namespace 71 72TShHandleBase::TShHandleBase() { 73 allocator.push(); 74 SetGlobalPoolAllocator(&allocator); 75} 76 77TShHandleBase::~TShHandleBase() { 78 SetGlobalPoolAllocator(NULL); 79 allocator.popAll(); 80} 81 82TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec) 83 : shaderType(type), 84 shaderSpec(spec) 85{ 86} 87 88TCompiler::~TCompiler() 89{ 90} 91 92bool 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 104bool 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 160bool 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 169void TCompiler::clearResults() 170{ 171 infoSink.info.erase(); 172 infoSink.obj.erase(); 173 infoSink.debug.erase(); 174 175 attribs.clear(); 176 uniforms.clear(); 177} 178 179bool TCompiler::validateLimitations(TIntermNode* root) { 180 ValidateLimitations validate(shaderType, infoSink.info); 181 root->traverse(&validate); 182 return validate.numErrors() == 0; 183} 184 185void TCompiler::collectAttribsUniforms(TIntermNode* root) 186{ 187 CollectAttribsUniforms collect(attribs, uniforms); 188 root->traverse(&collect); 189} 190