Blame gtests/TestFixture.h

Packit Service d7a8c4
//
Packit Service d7a8c4
// Copyright (C) 2016 Google, Inc.
Packit Service d7a8c4
//
Packit Service d7a8c4
// All rights reserved.
Packit Service d7a8c4
//
Packit Service d7a8c4
// Redistribution and use in source and binary forms, with or without
Packit Service d7a8c4
// modification, are permitted provided that the following conditions
Packit Service d7a8c4
// are met:
Packit Service d7a8c4
//
Packit Service d7a8c4
//    Redistributions of source code must retain the above copyright
Packit Service d7a8c4
//    notice, this list of conditions and the following disclaimer.
Packit Service d7a8c4
//
Packit Service d7a8c4
//    Redistributions in binary form must reproduce the above
Packit Service d7a8c4
//    copyright notice, this list of conditions and the following
Packit Service d7a8c4
//    disclaimer in the documentation and/or other materials provided
Packit Service d7a8c4
//    with the distribution.
Packit Service d7a8c4
//
Packit Service d7a8c4
//    Neither the name of Google Inc. nor the names of its
Packit Service d7a8c4
//    contributors may be used to endorse or promote products derived
Packit Service d7a8c4
//    from this software without specific prior written permission.
Packit Service d7a8c4
//
Packit Service d7a8c4
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit Service d7a8c4
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit Service d7a8c4
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
Packit Service d7a8c4
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
Packit Service d7a8c4
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit Service d7a8c4
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
Packit Service d7a8c4
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
Packit Service d7a8c4
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
Packit Service d7a8c4
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit Service d7a8c4
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
Packit Service d7a8c4
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Packit Service d7a8c4
// POSSIBILITY OF SUCH DAMAGE.
Packit Service d7a8c4
Packit Service d7a8c4
#ifndef GLSLANG_GTESTS_TEST_FIXTURE_H
Packit Service d7a8c4
#define GLSLANG_GTESTS_TEST_FIXTURE_H
Packit Service d7a8c4
Packit Service d7a8c4
#include <cstdint>
Packit Service d7a8c4
#include <fstream>
Packit Service d7a8c4
#include <sstream>
Packit Service d7a8c4
#include <streambuf>
Packit Service d7a8c4
#include <tuple>
Packit Service d7a8c4
#include <string>
Packit Service d7a8c4
Packit Service d7a8c4
#include <gtest/gtest.h>
Packit Service d7a8c4
Packit Service d7a8c4
#include "SPIRV/GlslangToSpv.h"
Packit Service d7a8c4
#include "SPIRV/disassemble.h"
Packit Service d7a8c4
#include "SPIRV/doc.h"
Packit Service d7a8c4
#include "SPIRV/SPVRemapper.h"
Packit Service d7a8c4
#include "StandAlone/ResourceLimits.h"
Packit Service d7a8c4
#include "glslang/Public/ShaderLang.h"
Packit Service d7a8c4
Packit Service d7a8c4
#include "Initializer.h"
Packit Service d7a8c4
#include "Settings.h"
Packit Service d7a8c4
Packit Service d7a8c4
namespace glslangtest {
Packit Service d7a8c4
Packit Service d7a8c4
// This function is used to provide custom test name suffixes based on the
Packit Service d7a8c4
// shader source file names. Otherwise, the test name suffixes will just be
Packit Service d7a8c4
// numbers, which are not quite obvious.
Packit Service d7a8c4
std::string FileNameAsCustomTestSuffix(
Packit Service d7a8c4
    const ::testing::TestParamInfo<std::string>& info);
Packit Service d7a8c4
Packit Service d7a8c4
enum class Source {
Packit Service d7a8c4
  GLSL,
Packit Service d7a8c4
  HLSL,
Packit Service d7a8c4
};
Packit Service d7a8c4
Packit Service d7a8c4
// Enum for shader compilation semantics.
Packit Service d7a8c4
enum class Semantics {
Packit Service d7a8c4
    OpenGL,
Packit Service d7a8c4
    Vulkan
Packit Service d7a8c4
};
Packit Service d7a8c4
Packit Service d7a8c4
// Enum for compilation target.
Packit Service d7a8c4
enum class Target {
Packit Service d7a8c4
    AST,
Packit Service d7a8c4
    Spv,
Packit Service d7a8c4
    BothASTAndSpv,
Packit Service d7a8c4
};
Packit Service d7a8c4
Packit Service d7a8c4
EShLanguage GetShaderStage(const std::string& stage);
Packit Service d7a8c4
Packit Service d7a8c4
EShMessages DeriveOptions(Source, Semantics, Target);
Packit Service d7a8c4
Packit Service d7a8c4
// Reads the content of the file at the given |path|. On success, returns true
Packit Service d7a8c4
// and the contents; otherwise, returns false and an empty string.
Packit Service d7a8c4
std::pair<bool, std::string> ReadFile(const std::string& path);
Packit Service d7a8c4
std::pair<bool, std::vector<std::uint32_t> > ReadSpvBinaryFile(const std::string& path);
Packit Service d7a8c4
Packit Service d7a8c4
// Writes the given |contents| into the file at the given |path|. Returns true
Packit Service d7a8c4
// on successful output.
Packit Service d7a8c4
bool WriteFile(const std::string& path, const std::string& contents);
Packit Service d7a8c4
Packit Service d7a8c4
// Returns the suffix of the given |name|.
Packit Service d7a8c4
std::string GetSuffix(const std::string& name);
Packit Service d7a8c4
Packit Service d7a8c4
// Base class for glslang integration tests. It contains many handy utility-like
Packit Service d7a8c4
// methods such as reading shader source files, compiling into AST/SPIR-V, and
Packit Service d7a8c4
// comparing with expected outputs.
Packit Service d7a8c4
//
Packit Service d7a8c4
// To write value-Parameterized tests:
Packit Service d7a8c4
//   using ValueParamTest = GlslangTest<::testing::TestWithParam<std::string>>;
Packit Service d7a8c4
// To use as normal fixture:
Packit Service d7a8c4
//   using FixtureTest = GlslangTest<::testing::Test>;
Packit Service d7a8c4
template <typename GT>
Packit Service d7a8c4
class GlslangTest : public GT {
Packit Service d7a8c4
public:
Packit Service d7a8c4
    GlslangTest()
Packit Service d7a8c4
        : defaultVersion(100),
Packit Service d7a8c4
          defaultProfile(ENoProfile),
Packit Service d7a8c4
          forceVersionProfile(false),
Packit Service d7a8c4
          isForwardCompatible(false) {
Packit Service d7a8c4
        // Perform validation by default.
Packit Service d7a8c4
        spirvOptions.validate = true;
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    // Tries to load the contents from the file at the given |path|. On success,
Packit Service d7a8c4
    // writes the contents into |contents|. On failure, errors out.
Packit Service d7a8c4
    void tryLoadFile(const std::string& path, const std::string& tag,
Packit Service d7a8c4
                     std::string* contents)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        bool fileReadOk;
Packit Service d7a8c4
        std::tie(fileReadOk, *contents) = ReadFile(path);
Packit Service d7a8c4
        ASSERT_TRUE(fileReadOk) << "Cannot open " << tag << " file: " << path;
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    // Tries to load the contents from the file at the given |path|. On success,
Packit Service d7a8c4
    // writes the contents into |contents|. On failure, errors out.
Packit Service d7a8c4
    void tryLoadSpvFile(const std::string& path, const std::string& tag,
Packit Service d7a8c4
                        std::vector<uint32_t>& contents)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        bool fileReadOk;
Packit Service d7a8c4
        std::tie(fileReadOk, contents) = ReadSpvBinaryFile(path);
Packit Service d7a8c4
        ASSERT_TRUE(fileReadOk) << "Cannot open " << tag << " file: " << path;
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    // Checks the equality of |expected| and |real|. If they are not equal,
Packit Service d7a8c4
    // write |real| to the given file named as |fname| if update mode is on.
Packit Service d7a8c4
    void checkEqAndUpdateIfRequested(const std::string& expected,
Packit Service d7a8c4
                                     const std::string& real,
Packit Service d7a8c4
                                     const std::string& fname,
Packit Service d7a8c4
                                     const std::string& errorsAndWarnings = "")
Packit Service d7a8c4
    {
Packit Service d7a8c4
        // In order to output the message we want under proper circumstances,
Packit Service d7a8c4
        // we need the following operator<< stuff.
Packit Service d7a8c4
        EXPECT_EQ(expected, real)
Packit Service d7a8c4
            << (GlobalTestSettings.updateMode
Packit Service d7a8c4
                    ? ("Mismatch found and update mode turned on - "
Packit Service d7a8c4
                       "flushing expected result output.\n")
Packit Service d7a8c4
                    : "")
Packit Service d7a8c4
            << "The following warnings/errors occurred:\n"
Packit Service d7a8c4
            << errorsAndWarnings;
Packit Service d7a8c4
Packit Service d7a8c4
        // Update the expected output file if requested.
Packit Service d7a8c4
        // It looks weird to duplicate the comparison between expected_output
Packit Service d7a8c4
        // and stream.str(). However, if creating a variable for the comparison
Packit Service d7a8c4
        // result, we cannot have pretty print of the string diff in the above.
Packit Service d7a8c4
        if (GlobalTestSettings.updateMode && expected != real) {
Packit Service d7a8c4
            EXPECT_TRUE(WriteFile(fname, real)) << "Flushing failed";
Packit Service d7a8c4
        }
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    struct ShaderResult {
Packit Service d7a8c4
        std::string shaderName;
Packit Service d7a8c4
        std::string output;
Packit Service d7a8c4
        std::string error;
Packit Service d7a8c4
    };
Packit Service d7a8c4
Packit Service d7a8c4
    // A struct for holding all the information returned by glslang compilation
Packit Service d7a8c4
    // and linking.
Packit Service d7a8c4
    struct GlslangResult {
Packit Service d7a8c4
        std::vector<ShaderResult> shaderResults;
Packit Service d7a8c4
        std::string linkingOutput;
Packit Service d7a8c4
        std::string linkingError;
Packit Service d7a8c4
        bool validationResult;
Packit Service d7a8c4
        std::string spirvWarningsErrors;
Packit Service d7a8c4
        std::string spirv;  // Optional SPIR-V disassembly text.
Packit Service d7a8c4
    };
Packit Service d7a8c4
Packit Service d7a8c4
    // Compiles and the given source |code| of the given shader |stage| into
Packit Service d7a8c4
    // the target under the semantics conveyed via |controls|. Returns true
Packit Service d7a8c4
    // and modifies |shader| on success.
Packit Service d7a8c4
    bool compile(glslang::TShader* shader, const std::string& code,
Packit Service d7a8c4
                 const std::string& entryPointName, EShMessages controls,
Packit Service d7a8c4
                 const TBuiltInResource* resources=nullptr,
Packit Service d7a8c4
                 const std::string* shaderName=nullptr)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const char* shaderStrings = code.data();
Packit Service d7a8c4
        const int shaderLengths = static_cast<int>(code.size());
Packit Service d7a8c4
        const char* shaderNames = nullptr;
Packit Service d7a8c4
Packit Service d7a8c4
        if ((controls & EShMsgDebugInfo) && shaderName != nullptr) {
Packit Service d7a8c4
            shaderNames = shaderName->data();
Packit Service d7a8c4
            shader->setStringsWithLengthsAndNames(
Packit Service d7a8c4
                    &shaderStrings, &shaderLengths, &shaderNames, 1);
Packit Service d7a8c4
        } else
Packit Service d7a8c4
            shader->setStringsWithLengths(&shaderStrings, &shaderLengths, 1);
Packit Service d7a8c4
        if (!entryPointName.empty()) shader->setEntryPoint(entryPointName.c_str());
Packit Service d7a8c4
        return shader->parse(
Packit Service d7a8c4
                (resources ? resources : &glslang::DefaultTBuiltInResource),
Packit Service d7a8c4
                defaultVersion, isForwardCompatible, controls);
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    // Compiles and links the given source |code| of the given shader
Packit Service d7a8c4
    // |stage| into the target under the semantics specified via |controls|.
Packit Service d7a8c4
    // Returns a GlslangResult instance containing all the information generated
Packit Service d7a8c4
    // during the process. If the target includes SPIR-V, also disassembles
Packit Service d7a8c4
    // the result and returns disassembly text.
Packit Service d7a8c4
    GlslangResult compileAndLink(
Packit Service d7a8c4
            const std::string& shaderName, const std::string& code,
Packit Service d7a8c4
            const std::string& entryPointName, EShMessages controls,
Packit Service d7a8c4
            glslang::EShTargetClientVersion clientTargetVersion,
Packit Service d7a8c4
            glslang::EShTargetLanguageVersion targetLanguageVersion,
Packit Service d7a8c4
            bool flattenUniformArrays = false,
Packit Service d7a8c4
            EShTextureSamplerTransformMode texSampTransMode = EShTexSampTransKeep,
Packit Service d7a8c4
            bool enableOptimizer = false,
Packit Service d7a8c4
            bool enableDebug = false,
Packit Service d7a8c4
            bool automap = true)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const EShLanguage stage = GetShaderStage(GetSuffix(shaderName));
Packit Service d7a8c4
Packit Service d7a8c4
        glslang::TShader shader(stage);
Packit Service d7a8c4
        if (automap) {
Packit Service d7a8c4
            shader.setAutoMapLocations(true);
Packit Service d7a8c4
            shader.setAutoMapBindings(true);
Packit Service d7a8c4
        }
Packit Service d7a8c4
        shader.setTextureSamplerTransformMode(texSampTransMode);
Packit Service d7a8c4
#ifdef ENABLE_HLSL
Packit Service d7a8c4
        shader.setFlattenUniformArrays(flattenUniformArrays);
Packit Service d7a8c4
#endif
Packit Service d7a8c4
Packit Service d7a8c4
        if (controls & EShMsgSpvRules) {
Packit Service d7a8c4
            if (controls & EShMsgVulkanRules) {
Packit Service d7a8c4
                shader.setEnvInput((controls & EShMsgReadHlsl) ? glslang::EShSourceHlsl
Packit Service d7a8c4
                                                               : glslang::EShSourceGlsl,
Packit Service d7a8c4
                                    stage, glslang::EShClientVulkan, 100);
Packit Service d7a8c4
                shader.setEnvClient(glslang::EShClientVulkan, clientTargetVersion);
Packit Service d7a8c4
                shader.setEnvTarget(glslang::EShTargetSpv, targetLanguageVersion);
Packit Service d7a8c4
            } else {
Packit Service d7a8c4
                shader.setEnvInput((controls & EShMsgReadHlsl) ? glslang::EShSourceHlsl
Packit Service d7a8c4
                                                               : glslang::EShSourceGlsl,
Packit Service d7a8c4
                                    stage, glslang::EShClientOpenGL, 100);
Packit Service d7a8c4
                shader.setEnvClient(glslang::EShClientOpenGL, clientTargetVersion);
Packit Service d7a8c4
                shader.setEnvTarget(glslang::EshTargetSpv, glslang::EShTargetSpv_1_0);
Packit Service d7a8c4
            }
Packit Service d7a8c4
        }
Packit Service d7a8c4
Packit Service d7a8c4
        bool success = compile(
Packit Service d7a8c4
                &shader, code, entryPointName, controls, nullptr, &shaderName);
Packit Service d7a8c4
Packit Service d7a8c4
        glslang::TProgram program;
Packit Service d7a8c4
        program.addShader(&shader);
Packit Service d7a8c4
        success &= program.link(controls);
Packit Service d7a8c4
Packit Service d7a8c4
        spv::SpvBuildLogger logger;
Packit Service d7a8c4
Packit Service d7a8c4
        if (success && (controls & EShMsgSpvRules)) {
Packit Service d7a8c4
            std::vector<uint32_t> spirv_binary;
Packit Service d7a8c4
            options().disableOptimizer = !enableOptimizer;
Packit Service d7a8c4
            options().generateDebugInfo = enableDebug;
Packit Service d7a8c4
            glslang::GlslangToSpv(*program.getIntermediate(stage),
Packit Service d7a8c4
                                  spirv_binary, &logger, &options());
Packit Service d7a8c4
Packit Service d7a8c4
            std::ostringstream disassembly_stream;
Packit Service d7a8c4
            spv::Parameterize();
Packit Service d7a8c4
            spv::Disassemble(disassembly_stream, spirv_binary);
Packit Service d7a8c4
            bool validation_result = !options().validate || logger.getAllMessages().empty();
Packit Service d7a8c4
            return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
Packit Service d7a8c4
                    program.getInfoLog(), program.getInfoDebugLog(),
Packit Service d7a8c4
                    validation_result, logger.getAllMessages(), disassembly_stream.str()};
Packit Service d7a8c4
        } else {
Packit Service d7a8c4
            return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
Packit Service d7a8c4
                    program.getInfoLog(), program.getInfoDebugLog(), true, "", ""};
Packit Service d7a8c4
        }
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    // Compiles and links the given source |code| of the given shader
Packit Service d7a8c4
    // |stage| into the target under the semantics specified via |controls|.
Packit Service d7a8c4
    // Returns a GlslangResult instance containing all the information generated
Packit Service d7a8c4
    // during the process. If the target includes SPIR-V, also disassembles
Packit Service d7a8c4
    // the result and returns disassembly text.
Packit Service d7a8c4
    GlslangResult compileLinkIoMap(
Packit Service d7a8c4
            const std::string shaderName, const std::string& code,
Packit Service d7a8c4
            const std::string& entryPointName, EShMessages controls,
Packit Service d7a8c4
            int baseSamplerBinding,
Packit Service d7a8c4
            int baseTextureBinding,
Packit Service d7a8c4
            int baseImageBinding,
Packit Service d7a8c4
            int baseUboBinding,
Packit Service d7a8c4
            int baseSsboBinding,
Packit Service d7a8c4
            bool autoMapBindings,
Packit Service d7a8c4
            bool flattenUniformArrays)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const EShLanguage stage = GetShaderStage(GetSuffix(shaderName));
Packit Service d7a8c4
Packit Service d7a8c4
        glslang::TShader shader(stage);
Packit Service d7a8c4
        shader.setShiftSamplerBinding(baseSamplerBinding);
Packit Service d7a8c4
        shader.setShiftTextureBinding(baseTextureBinding);
Packit Service d7a8c4
        shader.setShiftImageBinding(baseImageBinding);
Packit Service d7a8c4
        shader.setShiftUboBinding(baseUboBinding);
Packit Service d7a8c4
        shader.setShiftSsboBinding(baseSsboBinding);
Packit Service d7a8c4
        shader.setAutoMapBindings(autoMapBindings);
Packit Service d7a8c4
        shader.setAutoMapLocations(true);
Packit Service d7a8c4
#ifdef ENABLE_HLSL
Packit Service d7a8c4
        shader.setFlattenUniformArrays(flattenUniformArrays);
Packit Service d7a8c4
#endif
Packit Service d7a8c4
Packit Service d7a8c4
        bool success = compile(&shader, code, entryPointName, controls);
Packit Service d7a8c4
Packit Service d7a8c4
        glslang::TProgram program;
Packit Service d7a8c4
        program.addShader(&shader);
Packit Service d7a8c4
        
Packit Service d7a8c4
        success &= program.link(controls);
Packit Service d7a8c4
#ifndef GLSLANG_WEB
Packit Service d7a8c4
        success &= program.mapIO();
Packit Service d7a8c4
#endif
Packit Service d7a8c4
Packit Service d7a8c4
        spv::SpvBuildLogger logger;
Packit Service d7a8c4
Packit Service d7a8c4
        if (success && (controls & EShMsgSpvRules)) {
Packit Service d7a8c4
            std::vector<uint32_t> spirv_binary;
Packit Service d7a8c4
            glslang::GlslangToSpv(*program.getIntermediate(stage),
Packit Service d7a8c4
                                  spirv_binary, &logger, &options());
Packit Service d7a8c4
Packit Service d7a8c4
            std::ostringstream disassembly_stream;
Packit Service d7a8c4
            spv::Parameterize();
Packit Service d7a8c4
            spv::Disassemble(disassembly_stream, spirv_binary);
Packit Service d7a8c4
            bool validation_result = !options().validate || logger.getAllMessages().empty();
Packit Service d7a8c4
            return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
Packit Service d7a8c4
                    program.getInfoLog(), program.getInfoDebugLog(),
Packit Service d7a8c4
                    validation_result, logger.getAllMessages(), disassembly_stream.str()};
Packit Service d7a8c4
        } else {
Packit Service d7a8c4
            return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
Packit Service d7a8c4
                    program.getInfoLog(), program.getInfoDebugLog(), true, "", ""};
Packit Service d7a8c4
        }
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    // This is like compileAndLink but with remapping of the SPV binary
Packit Service d7a8c4
    // through spirvbin_t::remap().  While technically this could be merged
Packit Service d7a8c4
    // with compileAndLink() above (with the remap step optionally being a no-op)
Packit Service d7a8c4
    // it is given separately here for ease of future extraction.
Packit Service d7a8c4
    GlslangResult compileLinkRemap(
Packit Service d7a8c4
            const std::string shaderName, const std::string& code,
Packit Service d7a8c4
            const std::string& entryPointName, EShMessages controls,
Packit Service d7a8c4
            const unsigned int remapOptions = spv::spirvbin_t::NONE)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const EShLanguage stage = GetShaderStage(GetSuffix(shaderName));
Packit Service d7a8c4
Packit Service d7a8c4
        glslang::TShader shader(stage);
Packit Service d7a8c4
        shader.setAutoMapBindings(true);
Packit Service d7a8c4
        shader.setAutoMapLocations(true);
Packit Service d7a8c4
Packit Service d7a8c4
        bool success = compile(&shader, code, entryPointName, controls);
Packit Service d7a8c4
Packit Service d7a8c4
        glslang::TProgram program;
Packit Service d7a8c4
        program.addShader(&shader);
Packit Service d7a8c4
        success &= program.link(controls);
Packit Service d7a8c4
Packit Service d7a8c4
        spv::SpvBuildLogger logger;
Packit Service d7a8c4
Packit Service d7a8c4
        if (success && (controls & EShMsgSpvRules)) {
Packit Service d7a8c4
            std::vector<uint32_t> spirv_binary;
Packit Service d7a8c4
            glslang::GlslangToSpv(*program.getIntermediate(stage),
Packit Service d7a8c4
                                  spirv_binary, &logger, &options());
Packit Service d7a8c4
Packit Service d7a8c4
            spv::spirvbin_t(0 /*verbosity*/).remap(spirv_binary, remapOptions);
Packit Service d7a8c4
Packit Service d7a8c4
            std::ostringstream disassembly_stream;
Packit Service d7a8c4
            spv::Parameterize();
Packit Service d7a8c4
            spv::Disassemble(disassembly_stream, spirv_binary);
Packit Service d7a8c4
            bool validation_result = !options().validate || logger.getAllMessages().empty();
Packit Service d7a8c4
            return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
Packit Service d7a8c4
                    program.getInfoLog(), program.getInfoDebugLog(),
Packit Service d7a8c4
                    validation_result, logger.getAllMessages(), disassembly_stream.str()};
Packit Service d7a8c4
        } else {
Packit Service d7a8c4
            return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
Packit Service d7a8c4
                    program.getInfoLog(), program.getInfoDebugLog(), true, "", ""};
Packit Service d7a8c4
        }
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    // remap the binary in 'code' with the options in remapOptions
Packit Service d7a8c4
    GlslangResult remap(
Packit Service d7a8c4
            const std::string shaderName, const std::vector<uint32_t>& code,
Packit Service d7a8c4
            EShMessages controls,
Packit Service d7a8c4
            const unsigned int remapOptions = spv::spirvbin_t::NONE)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        if ((controls & EShMsgSpvRules)) {
Packit Service d7a8c4
            std::vector<uint32_t> spirv_binary(code); // scratch copy
Packit Service d7a8c4
Packit Service d7a8c4
            spv::spirvbin_t(0 /*verbosity*/).remap(spirv_binary, remapOptions);
Packit Service d7a8c4
            
Packit Service d7a8c4
            std::ostringstream disassembly_stream;
Packit Service d7a8c4
            spv::Parameterize();
Packit Service d7a8c4
            spv::Disassemble(disassembly_stream, spirv_binary);
Packit Service d7a8c4
Packit Service d7a8c4
            return {{{shaderName, "", ""},},
Packit Service d7a8c4
                    "", "",
Packit Service d7a8c4
                    true, "", disassembly_stream.str()};
Packit Service d7a8c4
        } else {
Packit Service d7a8c4
            return {{{shaderName, "", ""},}, "", "", true, "", ""};
Packit Service d7a8c4
        }
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    void outputResultToStream(std::ostringstream* stream,
Packit Service d7a8c4
                              const GlslangResult& result,
Packit Service d7a8c4
                              EShMessages controls)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const auto outputIfNotEmpty = [&stream](const std::string& str) {
Packit Service d7a8c4
            if (!str.empty()) *stream << str << "\n";
Packit Service d7a8c4
        };
Packit Service d7a8c4
Packit Service d7a8c4
        for (const auto& shaderResult : result.shaderResults) {
Packit Service d7a8c4
            *stream << shaderResult.shaderName << "\n";
Packit Service d7a8c4
            outputIfNotEmpty(shaderResult.output);
Packit Service d7a8c4
            outputIfNotEmpty(shaderResult.error);
Packit Service d7a8c4
        }
Packit Service d7a8c4
        outputIfNotEmpty(result.linkingOutput);
Packit Service d7a8c4
        outputIfNotEmpty(result.linkingError);
Packit Service d7a8c4
        if (!result.validationResult) {
Packit Service d7a8c4
          *stream << "Validation failed\n";
Packit Service d7a8c4
        }
Packit Service d7a8c4
Packit Service d7a8c4
        if (controls & EShMsgSpvRules) {
Packit Service d7a8c4
            *stream
Packit Service d7a8c4
                << (result.spirv.empty()
Packit Service d7a8c4
                        ? "SPIR-V is not generated for failed compile or link\n"
Packit Service d7a8c4
                        : result.spirv);
Packit Service d7a8c4
        }
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    void loadFileCompileAndCheck(const std::string& testDir,
Packit Service d7a8c4
                                 const std::string& testName,
Packit Service d7a8c4
                                 Source source,
Packit Service d7a8c4
                                 Semantics semantics,
Packit Service d7a8c4
                                 glslang::EShTargetClientVersion clientTargetVersion,
Packit Service d7a8c4
                                 glslang::EShTargetLanguageVersion targetLanguageVersion,
Packit Service d7a8c4
                                 Target target,
Packit Service d7a8c4
                                 bool automap = true,
Packit Service d7a8c4
                                 const std::string& entryPointName="",
Packit Service d7a8c4
                                 const std::string& baseDir="/baseResults/",
Packit Service d7a8c4
                                 const bool enableOptimizer = false,
Packit Service d7a8c4
                                 const bool enableDebug = false)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const std::string inputFname = testDir + "/" + testName;
Packit Service d7a8c4
        const std::string expectedOutputFname =
Packit Service d7a8c4
            testDir + baseDir + testName + ".out";
Packit Service d7a8c4
        std::string input, expectedOutput;
Packit Service d7a8c4
Packit Service d7a8c4
        tryLoadFile(inputFname, "input", &input);
Packit Service d7a8c4
        tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
Packit Service d7a8c4
Packit Service d7a8c4
        EShMessages controls = DeriveOptions(source, semantics, target);
Packit Service d7a8c4
        if (enableOptimizer)
Packit Service d7a8c4
            controls = static_cast<EShMessages>(controls & ~EShMsgHlslLegalization);
Packit Service d7a8c4
        if (enableDebug)
Packit Service d7a8c4
            controls = static_cast<EShMessages>(controls | EShMsgDebugInfo);
Packit Service d7a8c4
        GlslangResult result = compileAndLink(testName, input, entryPointName, controls, clientTargetVersion,
Packit Service d7a8c4
            targetLanguageVersion, false, EShTexSampTransKeep, enableOptimizer, enableDebug, automap);
Packit Service d7a8c4
Packit Service d7a8c4
        // Generate the hybrid output in the way of glslangValidator.
Packit Service d7a8c4
        std::ostringstream stream;
Packit Service d7a8c4
        outputResultToStream(&stream, result, controls);
Packit Service d7a8c4
Packit Service d7a8c4
        checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
Packit Service d7a8c4
                                    expectedOutputFname, result.spirvWarningsErrors);
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    void loadFileCompileAndCheckWithOptions(const std::string &testDir,
Packit Service d7a8c4
                                            const std::string &testName,
Packit Service d7a8c4
                                            Source source,
Packit Service d7a8c4
                                            Semantics semantics,
Packit Service d7a8c4
                                            glslang::EShTargetClientVersion clientTargetVersion,
Packit Service d7a8c4
                                            glslang::EShTargetLanguageVersion targetLanguageVersion,
Packit Service d7a8c4
                                            Target target, bool automap = true, const std::string &entryPointName = "",
Packit Service d7a8c4
                                            const std::string &baseDir = "/baseResults/",
Packit Service d7a8c4
                                            const EShMessages additionalOptions = EShMessages::EShMsgDefault)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const std::string inputFname = testDir + "/" + testName;
Packit Service d7a8c4
        const std::string expectedOutputFname = testDir + baseDir + testName + ".out";
Packit Service d7a8c4
        std::string input, expectedOutput;
Packit Service d7a8c4
Packit Service d7a8c4
        tryLoadFile(inputFname, "input", &input);
Packit Service d7a8c4
        tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
Packit Service d7a8c4
Packit Service d7a8c4
        EShMessages controls = DeriveOptions(source, semantics, target);
Packit Service d7a8c4
        controls = static_cast<EShMessages>(controls | additionalOptions);
Packit Service d7a8c4
        GlslangResult result = compileAndLink(testName, input, entryPointName, controls, clientTargetVersion,
Packit Service d7a8c4
            targetLanguageVersion, false, EShTexSampTransKeep, false, automap);
Packit Service d7a8c4
Packit Service d7a8c4
        // Generate the hybrid output in the way of glslangValidator.
Packit Service d7a8c4
        std::ostringstream stream;
Packit Service d7a8c4
        outputResultToStream(&stream, result, controls);
Packit Service d7a8c4
Packit Service d7a8c4
        checkEqAndUpdateIfRequested(expectedOutput, stream.str(), expectedOutputFname);
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    void loadFileCompileFlattenUniformsAndCheck(const std::string& testDir,
Packit Service d7a8c4
                                                const std::string& testName,
Packit Service d7a8c4
                                                Source source,
Packit Service d7a8c4
                                                Semantics semantics,
Packit Service d7a8c4
                                                Target target,
Packit Service d7a8c4
                                                const std::string& entryPointName="")
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const std::string inputFname = testDir + "/" + testName;
Packit Service d7a8c4
        const std::string expectedOutputFname =
Packit Service d7a8c4
            testDir + "/baseResults/" + testName + ".out";
Packit Service d7a8c4
        std::string input, expectedOutput;
Packit Service d7a8c4
Packit Service d7a8c4
        tryLoadFile(inputFname, "input", &input);
Packit Service d7a8c4
        tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
Packit Service d7a8c4
Packit Service d7a8c4
        const EShMessages controls = DeriveOptions(source, semantics, target);
Packit Service d7a8c4
        GlslangResult result = compileAndLink(testName, input, entryPointName, controls,
Packit Service d7a8c4
                                              glslang::EShTargetVulkan_1_0, glslang::EShTargetSpv_1_0, true);
Packit Service d7a8c4
Packit Service d7a8c4
        // Generate the hybrid output in the way of glslangValidator.
Packit Service d7a8c4
        std::ostringstream stream;
Packit Service d7a8c4
        outputResultToStream(&stream, result, controls);
Packit Service d7a8c4
Packit Service d7a8c4
        checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
Packit Service d7a8c4
                                    expectedOutputFname, result.spirvWarningsErrors);
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    void loadFileCompileIoMapAndCheck(const std::string& testDir,
Packit Service d7a8c4
                                      const std::string& testName,
Packit Service d7a8c4
                                      Source source,
Packit Service d7a8c4
                                      Semantics semantics,
Packit Service d7a8c4
                                      Target target,
Packit Service d7a8c4
                                      const std::string& entryPointName,
Packit Service d7a8c4
                                      int baseSamplerBinding,
Packit Service d7a8c4
                                      int baseTextureBinding,
Packit Service d7a8c4
                                      int baseImageBinding,
Packit Service d7a8c4
                                      int baseUboBinding,
Packit Service d7a8c4
                                      int baseSsboBinding,
Packit Service d7a8c4
                                      bool autoMapBindings,
Packit Service d7a8c4
                                      bool flattenUniformArrays)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const std::string inputFname = testDir + "/" + testName;
Packit Service d7a8c4
        const std::string expectedOutputFname =
Packit Service d7a8c4
            testDir + "/baseResults/" + testName + ".out";
Packit Service d7a8c4
        std::string input, expectedOutput;
Packit Service d7a8c4
Packit Service d7a8c4
        tryLoadFile(inputFname, "input", &input);
Packit Service d7a8c4
        tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
Packit Service d7a8c4
Packit Service d7a8c4
        const EShMessages controls = DeriveOptions(source, semantics, target);
Packit Service d7a8c4
        GlslangResult result = compileLinkIoMap(testName, input, entryPointName, controls,
Packit Service d7a8c4
                                                baseSamplerBinding, baseTextureBinding, baseImageBinding,
Packit Service d7a8c4
                                                baseUboBinding, baseSsboBinding,
Packit Service d7a8c4
                                                autoMapBindings,
Packit Service d7a8c4
                                                flattenUniformArrays);
Packit Service d7a8c4
Packit Service d7a8c4
        // Generate the hybrid output in the way of glslangValidator.
Packit Service d7a8c4
        std::ostringstream stream;
Packit Service d7a8c4
        outputResultToStream(&stream, result, controls);
Packit Service d7a8c4
Packit Service d7a8c4
        checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
Packit Service d7a8c4
                                    expectedOutputFname, result.spirvWarningsErrors);
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    void loadFileCompileRemapAndCheck(const std::string& testDir,
Packit Service d7a8c4
                                      const std::string& testName,
Packit Service d7a8c4
                                      Source source,
Packit Service d7a8c4
                                      Semantics semantics,
Packit Service d7a8c4
                                      Target target,
Packit Service d7a8c4
                                      const std::string& entryPointName="",
Packit Service d7a8c4
                                      const unsigned int remapOptions = spv::spirvbin_t::NONE)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const std::string inputFname = testDir + "/" + testName;
Packit Service d7a8c4
        const std::string expectedOutputFname =
Packit Service d7a8c4
            testDir + "/baseResults/" + testName + ".out";
Packit Service d7a8c4
        std::string input, expectedOutput;
Packit Service d7a8c4
Packit Service d7a8c4
        tryLoadFile(inputFname, "input", &input);
Packit Service d7a8c4
        tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
Packit Service d7a8c4
Packit Service d7a8c4
        const EShMessages controls = DeriveOptions(source, semantics, target);
Packit Service d7a8c4
        GlslangResult result = compileLinkRemap(testName, input, entryPointName, controls, remapOptions);
Packit Service d7a8c4
Packit Service d7a8c4
        // Generate the hybrid output in the way of glslangValidator.
Packit Service d7a8c4
        std::ostringstream stream;
Packit Service d7a8c4
        outputResultToStream(&stream, result, controls);
Packit Service d7a8c4
Packit Service d7a8c4
        checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
Packit Service d7a8c4
                                    expectedOutputFname, result.spirvWarningsErrors);
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    void loadFileRemapAndCheck(const std::string& testDir,
Packit Service d7a8c4
                               const std::string& testName,
Packit Service d7a8c4
                               Source source,
Packit Service d7a8c4
                               Semantics semantics,
Packit Service d7a8c4
                               Target target,
Packit Service d7a8c4
                               const unsigned int remapOptions = spv::spirvbin_t::NONE)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const std::string inputFname = testDir + "/" + testName;
Packit Service d7a8c4
        const std::string expectedOutputFname =
Packit Service d7a8c4
            testDir + "/baseResults/" + testName + ".out";
Packit Service d7a8c4
        std::vector<std::uint32_t> input;
Packit Service d7a8c4
        std::string expectedOutput;
Packit Service d7a8c4
Packit Service d7a8c4
        tryLoadSpvFile(inputFname, "input", input);
Packit Service d7a8c4
        tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
Packit Service d7a8c4
Packit Service d7a8c4
        const EShMessages controls = DeriveOptions(source, semantics, target);
Packit Service d7a8c4
        GlslangResult result = remap(testName, input, controls, remapOptions);
Packit Service d7a8c4
Packit Service d7a8c4
        // Generate the hybrid output in the way of glslangValidator.
Packit Service d7a8c4
        std::ostringstream stream;
Packit Service d7a8c4
        outputResultToStream(&stream, result, controls);
Packit Service d7a8c4
Packit Service d7a8c4
        checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
Packit Service d7a8c4
                                    expectedOutputFname, result.spirvWarningsErrors);
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    // Preprocesses the given |source| code. On success, returns true, the
Packit Service d7a8c4
    // preprocessed shader, and warning messages. Otherwise, returns false, an
Packit Service d7a8c4
    // empty string, and error messages.
Packit Service d7a8c4
    std::tuple<bool, std::string, std::string> preprocess(
Packit Service d7a8c4
        const std::string& source)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const char* shaderStrings = source.data();
Packit Service d7a8c4
        const int shaderLengths = static_cast<int>(source.size());
Packit Service d7a8c4
Packit Service d7a8c4
        glslang::TShader shader(EShLangVertex);
Packit Service d7a8c4
        shader.setStringsWithLengths(&shaderStrings, &shaderLengths, 1);
Packit Service d7a8c4
        std::string ppShader;
Packit Service d7a8c4
        glslang::TShader::ForbidIncluder includer;
Packit Service d7a8c4
        const bool success = shader.preprocess(
Packit Service d7a8c4
            &glslang::DefaultTBuiltInResource, defaultVersion, defaultProfile,
Packit Service d7a8c4
            forceVersionProfile, isForwardCompatible, (EShMessages)(EShMsgOnlyPreprocessor | EShMsgCascadingErrors),
Packit Service d7a8c4
            &ppShader, includer);
Packit Service d7a8c4
Packit Service d7a8c4
        std::string log = shader.getInfoLog();
Packit Service d7a8c4
        log += shader.getInfoDebugLog();
Packit Service d7a8c4
        if (success) {
Packit Service d7a8c4
            return std::make_tuple(true, ppShader, log);
Packit Service d7a8c4
        } else {
Packit Service d7a8c4
            return std::make_tuple(false, "", log);
Packit Service d7a8c4
        }
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    void loadFilePreprocessAndCheck(const std::string& testDir,
Packit Service d7a8c4
                                    const std::string& testName)
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const std::string inputFname = testDir + "/" + testName;
Packit Service d7a8c4
        const std::string expectedOutputFname =
Packit Service d7a8c4
            testDir + "/baseResults/" + testName + ".out";
Packit Service d7a8c4
        const std::string expectedErrorFname =
Packit Service d7a8c4
            testDir + "/baseResults/" + testName + ".err";
Packit Service d7a8c4
        std::string input, expectedOutput, expectedError;
Packit Service d7a8c4
Packit Service d7a8c4
        tryLoadFile(inputFname, "input", &input);
Packit Service d7a8c4
        tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
Packit Service d7a8c4
        tryLoadFile(expectedErrorFname, "expected error", &expectedError);
Packit Service d7a8c4
Packit Service d7a8c4
        bool ppOk;
Packit Service d7a8c4
        std::string output, error;
Packit Service d7a8c4
        std::tie(ppOk, output, error) = preprocess(input);
Packit Service d7a8c4
        if (!output.empty()) output += '\n';
Packit Service d7a8c4
        if (!error.empty()) error += '\n';
Packit Service d7a8c4
Packit Service d7a8c4
        checkEqAndUpdateIfRequested(expectedOutput, output,
Packit Service d7a8c4
                                    expectedOutputFname);
Packit Service d7a8c4
        checkEqAndUpdateIfRequested(expectedError, error,
Packit Service d7a8c4
                                    expectedErrorFname);
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    void loadCompileUpgradeTextureToSampledTextureAndDropSamplersAndCheck(const std::string& testDir,
Packit Service d7a8c4
                                                                          const std::string& testName,
Packit Service d7a8c4
                                                                          Source source,
Packit Service d7a8c4
                                                                          Semantics semantics,
Packit Service d7a8c4
                                                                          Target target,
Packit Service d7a8c4
                                                                          const std::string& entryPointName = "")
Packit Service d7a8c4
    {
Packit Service d7a8c4
        const std::string inputFname = testDir + "/" + testName;
Packit Service d7a8c4
        const std::string expectedOutputFname = testDir + "/baseResults/" + testName + ".out";
Packit Service d7a8c4
        std::string input, expectedOutput;
Packit Service d7a8c4
Packit Service d7a8c4
        tryLoadFile(inputFname, "input", &input);
Packit Service d7a8c4
        tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
Packit Service d7a8c4
Packit Service d7a8c4
        const EShMessages controls = DeriveOptions(source, semantics, target);
Packit Service d7a8c4
        GlslangResult result = compileAndLink(testName, input, entryPointName, controls,
Packit Service d7a8c4
                                              glslang::EShTargetVulkan_1_0, glslang::EShTargetSpv_1_0, false,
Packit Service d7a8c4
                                              EShTexSampTransUpgradeTextureRemoveSampler);
Packit Service d7a8c4
Packit Service d7a8c4
        // Generate the hybrid output in the way of glslangValidator.
Packit Service d7a8c4
        std::ostringstream stream;
Packit Service d7a8c4
        outputResultToStream(&stream, result, controls);
Packit Service d7a8c4
Packit Service d7a8c4
        checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
Packit Service d7a8c4
                                    expectedOutputFname, result.spirvWarningsErrors);
Packit Service d7a8c4
    }
Packit Service d7a8c4
Packit Service d7a8c4
    glslang::SpvOptions& options() { return spirvOptions; }
Packit Service d7a8c4
Packit Service d7a8c4
private:
Packit Service d7a8c4
    const int defaultVersion;
Packit Service d7a8c4
    const EProfile defaultProfile;
Packit Service d7a8c4
    const bool forceVersionProfile;
Packit Service d7a8c4
    const bool isForwardCompatible;
Packit Service d7a8c4
    glslang::SpvOptions spirvOptions;
Packit Service d7a8c4
};
Packit Service d7a8c4
Packit Service d7a8c4
}  // namespace glslangtest
Packit Service d7a8c4
Packit Service d7a8c4
#endif  // GLSLANG_GTESTS_TEST_FIXTURE_H