Edit

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

Branch :

  • Show log

    Commit

  • Author : zmo@google.com
    Date : 2011-09-16 00:53:26
    Hash : a3b4ab4c
    Message : Further work on the function emulation. This is to work around driver bugs. We added more functions, and removed some unnecessary ones. Remove the function group because we have flags for each function now. Use more macros instead of functions. Don't emit global precision because that will affect all later code. ANGLEBUG=196 TEST=build and test on Mac ATI/NVIDIA, fixes the failing webgl glsl conformance tests. Review URL: http://codereview.appspot.com/5011053 git-svn-id: https://angleproject.googlecode.com/svn/trunk@754 736b8ea6-26fd-11df-bfd4-992fa37f6226

  • src/compiler/Compiler.cpp
  • //
    // Copyright (c) 2002-2010 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/ParseHelper.h"
    #include "compiler/ShHandle.h"
    #include "compiler/ValidateLimitations.h"
    #include "compiler/MapLongVariableNames.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)
    {
    }
    
    TCompiler::~TCompiler()
    {
    }
    
    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)
    {
        MapLongVariableNames map(varyingLongNameMap);
        root->traverse(&map);
    }
    
    int TCompiler::getMappedNameMaxLength() const
    {
        return MAX_IDENTIFIER_NAME_SIZE + 1;
    }
    
    const TExtensionBehavior& TCompiler::getExtensionBehavior() const
    {
        return extensionBehavior;
    }
    
    const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
    {
        return builtInFunctionEmulator;
    }