Edit

kc3-lang/angle/src/tests/test_utils/compiler_test.cpp

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2021-02-26 00:00:57
    Hash : 776c6015
    Message : Vulkan: Call glslang at compile time With this change, the ANGLE translator immediately compiles the generated GLSL into SPIR-V with glslang and discards the source. This is in preparation for generating SPIR-V directly, by making the frontend and backend already able to digest it. This change also allows the expensive glslang calls to be parallelized, improving the following perf test by about 20%: LinkProgramBenchmark.Run/vulkan_compile_and_link_multi_thread Previously, the test was run as such in the Vulkan backend: Main Thread 1 Thread 2 Compile1 ---> Compile2 ---------------------> Translator Translator <--- <--------------------- Link glslang for shader1 glslang for shader2 Done With this change, it is run as such: Main Thread 1 Thread 2 Compile1 ---> Compile2 ---------------------> Translator Translator glslang glslang <--- <--------------------- Link Done glslang_wrapper_utils no longer interacts with glslang! A rename will follow. Bug: angleproject:4889 Change-Id: If4303e8ba0ba43b1a2f47f8c0a9133d0bee1a19a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2721195 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/tests/test_utils/compiler_test.cpp
  • //
    // Copyright 2015 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.
    //
    // compiler_test.cpp:
    //     utilities for compiler unit tests.
    
    #include "tests/test_utils/compiler_test.h"
    
    #include "angle_gl.h"
    #include "compiler/translator/Compiler.h"
    #include "compiler/translator/FunctionLookup.h"
    #include "compiler/translator/tree_util/IntermTraverse.h"
    
    namespace sh
    {
    
    namespace
    {
    constexpr char kBinaryBlob[] = "<binary blob>";
    bool IsBinaryBlob(const std::string &code)
    {
        return code == kBinaryBlob;
    }
    
    ImmutableString GetSymbolTableMangledName(TIntermAggregate *node)
    {
        ASSERT(!node->isConstructor());
        switch (node->getOp())
        {
            case EOpCallInternalRawFunction:
            case EOpCallBuiltInFunction:
            case EOpCallFunctionInAST:
                return TFunctionLookup::GetMangledName(node->getFunction()->name().data(),
                                                       *node->getSequence());
            default:
                const char *opString = GetOperatorString(node->getOp());
                return TFunctionLookup::GetMangledName(opString, *node->getSequence());
        }
    }
    
    class FunctionCallFinder : public TIntermTraverser
    {
      public:
        FunctionCallFinder(const char *functionMangledName)
            : TIntermTraverser(true, false, false),
              mFunctionMangledName(functionMangledName),
              mNodeFound(nullptr)
        {}
    
        bool visitAggregate(Visit visit, TIntermAggregate *node) override
        {
            if (node->isFunctionCall() && GetSymbolTableMangledName(node) == mFunctionMangledName)
            {
                mNodeFound = node;
                return false;
            }
            return true;
        }
    
        bool isFound() const { return mNodeFound != nullptr; }
        const TIntermAggregate *getNode() const { return mNodeFound; }
    
      private:
        const char *mFunctionMangledName;
        TIntermAggregate *mNodeFound;
    };
    
    }  // anonymous namespace
    
    bool compileTestShader(GLenum type,
                           ShShaderSpec spec,
                           ShShaderOutput output,
                           const std::string &shaderString,
                           ShBuiltInResources *resources,
                           ShCompileOptions compileOptions,
                           std::string *translatedCode,
                           std::string *infoLog)
    {
        sh::TCompiler *translator = sh::ConstructCompiler(type, spec, output);
        if (!translator->Init(*resources))
        {
            SafeDelete(translator);
            return false;
        }
    
        const char *shaderStrings[] = {shaderString.c_str()};
    
        bool compilationSuccess =
            translator->compile(shaderStrings, 1, SH_OBJECT_CODE | compileOptions);
        TInfoSink &infoSink = translator->getInfoSink();
        if (translatedCode)
        {
            *translatedCode = infoSink.obj.isBinary() ? kBinaryBlob : infoSink.obj.c_str();
        }
        if (infoLog)
        {
            *infoLog = infoSink.info.c_str();
        }
        SafeDelete(translator);
        return compilationSuccess;
    }
    
    bool compileTestShader(GLenum type,
                           ShShaderSpec spec,
                           ShShaderOutput output,
                           const std::string &shaderString,
                           ShCompileOptions compileOptions,
                           std::string *translatedCode,
                           std::string *infoLog)
    {
        ShBuiltInResources resources;
        sh::InitBuiltInResources(&resources);
        return compileTestShader(type, spec, output, shaderString, &resources, compileOptions,
                                 translatedCode, infoLog);
    }
    
    MatchOutputCodeTest::MatchOutputCodeTest(GLenum shaderType,
                                             ShCompileOptions defaultCompileOptions,
                                             ShShaderOutput outputType)
        : mShaderType(shaderType), mDefaultCompileOptions(defaultCompileOptions)
    {
        sh::InitBuiltInResources(&mResources);
        mOutputCode[outputType] = std::string();
    }
    
    void MatchOutputCodeTest::addOutputType(const ShShaderOutput outputType)
    {
        mOutputCode[outputType] = std::string();
    }
    
    ShBuiltInResources *MatchOutputCodeTest::getResources()
    {
        return &mResources;
    }
    
    void MatchOutputCodeTest::compile(const std::string &shaderString)
    {
        compile(shaderString, mDefaultCompileOptions);
    }
    
    void MatchOutputCodeTest::compile(const std::string &shaderString,
                                      const ShCompileOptions compileOptions)
    {
        std::string infoLog;
        for (auto &code : mOutputCode)
        {
            bool compilationSuccess =
                compileWithSettings(code.first, shaderString, compileOptions, &code.second, &infoLog);
            if (!compilationSuccess)
            {
                FAIL() << "Shader compilation failed:\n" << infoLog;
            }
        }
    }
    
    bool MatchOutputCodeTest::compileWithSettings(ShShaderOutput output,
                                                  const std::string &shaderString,
                                                  const ShCompileOptions compileOptions,
                                                  std::string *translatedCode,
                                                  std::string *infoLog)
    {
        return compileTestShader(mShaderType, SH_GLES3_1_SPEC, output, shaderString, &mResources,
                                 compileOptions, translatedCode, infoLog);
    }
    
    bool MatchOutputCodeTest::foundInCodeRegex(ShShaderOutput output,
                                               const std::regex &regexToFind,
                                               std::smatch *match) const
    {
        const auto code = mOutputCode.find(output);
        EXPECT_NE(mOutputCode.end(), code);
        if (code == mOutputCode.end())
        {
            return std::string::npos;
        }
    
        // No meaningful check for binary blobs
        if (IsBinaryBlob(code->second))
        {
            return true;
        }
    
        if (match)
        {
            return std::regex_search(code->second, *match, regexToFind);
        }
        else
        {
            return std::regex_search(code->second, regexToFind);
        }
    }
    
    bool MatchOutputCodeTest::foundInCode(ShShaderOutput output, const char *stringToFind) const
    {
        const auto code = mOutputCode.find(output);
        EXPECT_NE(mOutputCode.end(), code);
        if (code == mOutputCode.end())
        {
            return std::string::npos;
        }
    
        // No meaningful check for binary blobs
        if (IsBinaryBlob(code->second))
        {
            return true;
        }
    
        return code->second.find(stringToFind) != std::string::npos;
    }
    
    bool MatchOutputCodeTest::foundInCodeInOrder(ShShaderOutput output,
                                                 std::vector<const char *> stringsToFind)
    {
        const auto code = mOutputCode.find(output);
        EXPECT_NE(mOutputCode.end(), code);
        if (code == mOutputCode.end())
        {
            return false;
        }
    
        // No meaningful check for binary blobs
        if (IsBinaryBlob(code->second))
        {
            return true;
        }
    
        size_t currentPos = 0;
        for (const char *stringToFind : stringsToFind)
        {
            auto position = code->second.find(stringToFind, currentPos);
            if (position == std::string::npos)
            {
                return false;
            }
            currentPos = position + strlen(stringToFind);
        }
        return true;
    }
    
    bool MatchOutputCodeTest::foundInCode(ShShaderOutput output,
                                          const char *stringToFind,
                                          const int expectedOccurrences) const
    {
        const auto code = mOutputCode.find(output);
        EXPECT_NE(mOutputCode.end(), code);
        if (code == mOutputCode.end())
        {
            return false;
        }
    
        // No meaningful check for binary blobs
        if (IsBinaryBlob(code->second))
        {
            return true;
        }
    
        size_t currentPos  = 0;
        int occurencesLeft = expectedOccurrences;
    
        const size_t searchStringLength = strlen(stringToFind);
    
        while (occurencesLeft-- > 0)
        {
            auto position = code->second.find(stringToFind, currentPos);
            if (position == std::string::npos)
            {
                return false;
            }
            // Search strings should not overlap.
            currentPos = position + searchStringLength;
        }
        // Make sure that there aren't extra occurrences.
        return code->second.find(stringToFind, currentPos) == std::string::npos;
    }
    
    bool MatchOutputCodeTest::foundInCode(const char *stringToFind) const
    {
        for (auto &code : mOutputCode)
        {
            if (!foundInCode(code.first, stringToFind))
            {
                return false;
            }
        }
        return true;
    }
    
    bool MatchOutputCodeTest::foundInCodeRegex(const std::regex &regexToFind, std::smatch *match) const
    {
        for (auto &code : mOutputCode)
        {
            if (!foundInCodeRegex(code.first, regexToFind, match))
            {
                return false;
            }
        }
        return true;
    }
    
    bool MatchOutputCodeTest::foundInCode(const char *stringToFind, const int expectedOccurrences) const
    {
        for (auto &code : mOutputCode)
        {
            if (!foundInCode(code.first, stringToFind, expectedOccurrences))
            {
                return false;
            }
        }
        return true;
    }
    
    bool MatchOutputCodeTest::foundInCodeInOrder(std::vector<const char *> stringsToFind)
    {
        for (auto &code : mOutputCode)
        {
            if (!foundInCodeInOrder(code.first, stringsToFind))
            {
                return false;
            }
        }
        return true;
    }
    
    bool MatchOutputCodeTest::notFoundInCode(const char *stringToFind) const
    {
        for (auto &code : mOutputCode)
        {
            // No meaningful check for binary blobs
            if (IsBinaryBlob(code.second))
            {
                continue;
            }
    
            if (foundInCode(code.first, stringToFind))
            {
                return false;
            }
        }
        return true;
    }
    
    const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionMangledName)
    {
        FunctionCallFinder finder(functionMangledName.c_str());
        root->traverse(&finder);
        return finder.getNode();
    }
    
    }  // namespace sh