Edit

kc3-lang/angle/src/compiler/Compiler.cpp

Branch :

  • Show log

    Commit

  • Author : zmo@google.com
    Date : 2012-01-20 00:35:15
    Hash : b9f64aae
    Message : Use a global ref-counted singleton for long name map. This makes sure the same varying/uniform variables maps to the unique name in vertex/fragment shader. BUG= TEST=webgl conformance tests Review URL: https://codereview.appspot.com/5556065 git-svn-id: https://angleproject.googlecode.com/svn/trunk@950 736b8ea6-26fd-11df-bfd4-992fa37f6226

  • src/compiler/Compiler.cpp
  • //
    // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    #include "compiler/BuiltInFunctionEmulator.h"
    #include "compiler/DetectRecursion.h"
    #include "compiler/ForLoopUnroll.h"
    #include "compiler/Initialize.h"
    #include "compiler/MapLongVariableNames.h"
    #include "compiler/ParseHelper.h"
    #include "compiler/ShHandle.h"
    #include "compiler/ValidateLimitations.h"
    
    namespace {
    bool InitializeSymbolTable(
        const TBuiltInStrings& builtInStrings,
        ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
        TInfoSink& infoSink, TSymbolTable& symbolTable)
    {
        TIntermediate intermediate(infoSink);
        TExtensionBehavior extBehavior;
        InitExtensionBehavior(resources, extBehavior);
        // The builtins deliberately don't specify precisions for the function
        // arguments and return types. For that reason we don't try to check them.
        TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink);
    
        GlobalParseContext = &parseContext;
    
        assert(symbolTable.isEmpty());       
        //
        // Parse the built-ins.  This should only happen once per
        // language symbol table.
        //
        // Push the symbol table to give it an initial scope.  This
        // push should not have a corresponding pop, so that built-ins
        // are preserved, and the test for an empty table fails.
        //
        symbolTable.push();
    
        for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
        {
            const char* builtInShaders = i->c_str();
            int builtInLengths = static_cast<int>(i->size());
            if (builtInLengths <= 0)
              continue;
    
            if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
            {
                infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
                return false;
            }
        }
    
        IdentifyBuiltIns(type, spec, resources, symbolTable);
    
        return true;
    }
    
    class TScopedPoolAllocator {
    public:
        TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
            : mAllocator(allocator), mPushPopAllocator(pushPop) {
            if (mPushPopAllocator) mAllocator->push();
            SetGlobalPoolAllocator(mAllocator);
        }
        ~TScopedPoolAllocator() {
            SetGlobalPoolAllocator(NULL);
            if (mPushPopAllocator) mAllocator->pop();
        }
    
    private:
        TPoolAllocator* mAllocator;
        bool mPushPopAllocator;
    };
    }  // namespace
    
    TShHandleBase::TShHandleBase() {
        allocator.push();
        SetGlobalPoolAllocator(&allocator);
    }
    
    TShHandleBase::~TShHandleBase() {
        SetGlobalPoolAllocator(NULL);
        allocator.popAll();
    }
    
    TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
        : shaderType(type),
          shaderSpec(spec),
          builtInFunctionEmulator(type)
    {
        longNameMap = LongNameMap::GetInstance();
    }
    
    TCompiler::~TCompiler()
    {
        ASSERT(longNameMap);
        longNameMap->Release();
    }
    
    bool TCompiler::Init(const ShBuiltInResources& resources)
    {
        TScopedPoolAllocator scopedAlloc(&allocator, false);
    
        // Generate built-in symbol table.
        if (!InitBuiltInSymbolTable(resources))
            return false;
        InitExtensionBehavior(resources, extensionBehavior);
    
        return true;
    }
    
    bool TCompiler::compile(const char* const shaderStrings[],
                            const int numStrings,
                            int compileOptions)
    {
        TScopedPoolAllocator scopedAlloc(&allocator, true);
        clearResults();
    
        if (numStrings == 0)
            return true;
    
        // If compiling for WebGL, validate loop and indexing as well.
        if (shaderSpec == SH_WEBGL_SPEC)
            compileOptions |= SH_VALIDATE_LOOP_INDEXING;
    
        // First string is path of source file if flag is set. The actual source follows.
        const char* sourcePath = NULL;
        int firstSource = 0;
        if (compileOptions & SH_SOURCE_PATH)
        {
            sourcePath = shaderStrings[0];
            ++firstSource;
        }
    
        TIntermediate intermediate(infoSink);
        TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
                                   shaderType, shaderSpec, compileOptions, true,
                                   sourcePath, infoSink);
        GlobalParseContext = &parseContext;
    
        // We preserve symbols at the built-in level from compile-to-compile.
        // Start pushing the user-defined symbols at global level.
        symbolTable.push();
        if (!symbolTable.atGlobalLevel())
            infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
    
        // Parse shader.
        bool success =
            (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
            (parseContext.treeRoot != NULL);
        if (success) {
            TIntermNode* root = parseContext.treeRoot;
            success = intermediate.postProcess(root);
    
            if (success)
                success = detectRecursion(root);
    
            if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
                success = validateLimitations(root);
    
            // Unroll for-loop markup needs to happen after validateLimitations pass.
            if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
                ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
    
            // Built-in function emulation needs to happen after validateLimitations pass.
            if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
                builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
    
            // Call mapLongVariableNames() before collectAttribsUniforms() so in
            // collectAttribsUniforms() we already have the mapped symbol names and
            // we could composite mapped and original variable names.
            if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
                mapLongVariableNames(root);
    
            if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
                collectAttribsUniforms(root);
    
            if (success && (compileOptions & SH_INTERMEDIATE_TREE))
                intermediate.outputTree(root);
    
            if (success && (compileOptions & SH_OBJECT_CODE))
                translate(root);
        }
    
        // Cleanup memory.
        intermediate.remove(parseContext.treeRoot);
        // Ensure symbol table is returned to the built-in level,
        // throwing away all but the built-ins.
        while (!symbolTable.atBuiltInLevel())
            symbolTable.pop();
    
        return success;
    }
    
    bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
    {
        TBuiltIns builtIns;
    
        builtIns.initialize(shaderType, shaderSpec, resources);
        return InitializeSymbolTable(builtIns.getBuiltInStrings(),
            shaderType, shaderSpec, resources, infoSink, symbolTable);
    }
    
    void TCompiler::clearResults()
    {
        infoSink.info.erase();
        infoSink.obj.erase();
        infoSink.debug.erase();
    
        attribs.clear();
        uniforms.clear();
    
        builtInFunctionEmulator.Cleanup();
    }
    
    bool TCompiler::detectRecursion(TIntermNode* root)
    {
        DetectRecursion detect;
        root->traverse(&detect);
        switch (detect.detectRecursion()) {
            case DetectRecursion::kErrorNone:
                return true;
            case DetectRecursion::kErrorMissingMain:
                infoSink.info.message(EPrefixError, "Missing main()");
                return false;
            case DetectRecursion::kErrorRecursion:
                infoSink.info.message(EPrefixError, "Function recursion detected");
                return false;
            default:
                UNREACHABLE();
                return false;
        }
    }
    
    bool TCompiler::validateLimitations(TIntermNode* root) {
        ValidateLimitations validate(shaderType, infoSink.info);
        root->traverse(&validate);
        return validate.numErrors() == 0;
    }
    
    void TCompiler::collectAttribsUniforms(TIntermNode* root)
    {
        CollectAttribsUniforms collect(attribs, uniforms);
        root->traverse(&collect);
    }
    
    void TCompiler::mapLongVariableNames(TIntermNode* root)
    {
        ASSERT(longNameMap);
        MapLongVariableNames map(longNameMap);
        root->traverse(&map);
    }
    
    int TCompiler::getMappedNameMaxLength() const
    {
        return MAX_SHORTENED_IDENTIFIER_SIZE + 1;
    }
    
    const TExtensionBehavior& TCompiler::getExtensionBehavior() const
    {
        return extensionBehavior;
    }
    
    const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
    {
        return builtInFunctionEmulator;
    }