Edit

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

Branch :

  • Show log

    Commit

  • Author : apatrick@chromium.org
    Date : 2011-01-26 19:30:57
    Hash : 0f4cefe9
    Message : Map D3D calls and HLSL shaders back to GLES2 calls and GLSL ES shaders in PIX. This makes debugging and profiling using PIX a lot more convenient. The top level of events are the GLES calls with their arguments. Those can be expanded to see the D3D calls that were issued for a particular GLES call. When PIX is attached, the shaders are saved out to temporary files and referenced from the translated HLSL shaders via #line directives. This enabled source level debugging of the original GLSL from PIX for pixel and vertex shaders. The HLSL is also saved to a temporary file so that intrinsic functions like texture2D can be stepped into. It also avoids creating a text file in the current working directory, which has continued to be an issue. I made the dependency on d3d9.dll static again so it can be accessed by GetModuleHandle witihin DllMain. I added an EVENT macro that issues D3DPERF_BeginEvent and D3DPERF_EndEvent around a C++ block. I replaced TRACE with EVENT for all the entry points. I removed the tracing of shader source since the source is visible in PIX. The means by which the filename of the temporary shader file is passed into the shader compiler is a little clunky. I did it that way to avoid changing the function signatures and breaking folks using the translator. I plan to make the compiler respect #pragma optimize so that optimization can be disabled for debugging purposes. For now it just disables shader optimization in debug builds of ANGLE. Review URL: http://codereview.appspot.com/3945043 git-svn-id: https://angleproject.googlecode.com/svn/trunk@541 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/Initialize.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;
        TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, 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) 
    {
    }
    
    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,
                                   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 && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
                success = validateLimitations(root);
    
            if (success && (compileOptions & SH_INTERMEDIATE_TREE))
                intermediate.outputTree(root);
    
            if (success && (compileOptions & SH_OBJECT_CODE))
                translate(root);
    
            if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
                collectAttribsUniforms(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();
    }
    
    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);
    }