TEST_P(CompileToAstTest, FromFile)
{
loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(),
- Semantics::OpenGL, Target::AST);
+ Source::GLSL, Semantics::OpenGL,
+ Target::AST);
}
// clang-format off
"nonVulkan.frag",
"spv.atomic.comp",
})),
- FileNameAsCustomTestName
+ FileNameAsCustomTestSuffix
);
// clang-format on
# Test related source files
${CMAKE_CURRENT_SOURCE_DIR}/AST.FromFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/BuiltInResource.FromFile.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Hlsl.FromFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Pp.FromFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Spv.FromFile.cpp
)
--- /dev/null
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+#include <gtest/gtest.h>
+
+#include "TestFixture.h"
+
+namespace glslangtest {
+namespace {
+
+struct FileNameEntryPointPair {
+ const char* fileName;
+ const char* entryPoint;
+};
+
+// We are using FileNameEntryPointPair objects as parameters for instantiating
+// the template, so the global FileNameAsCustomTestSuffix() won't work since
+// it assumes std::string as parameters. Thus, an overriding one here.
+std::string FileNameAsCustomTestSuffix(
+ const ::testing::TestParamInfo<FileNameEntryPointPair>& info) {
+ std::string name = info.param.fileName;
+ // A valid test case suffix cannot have '.' and '-' inside.
+ std::replace(name.begin(), name.end(), '.', '_');
+ std::replace(name.begin(), name.end(), '-', '_');
+ return name;
+}
+
+using HlslCompileTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>;
+
+// Compiling HLSL to SPIR-V under Vulkan semantics. Expected to successfully
+// generate SPIR-V.
+TEST_P(HlslCompileTest, FromFile)
+{
+ loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam().fileName,
+ Source::HLSL, Semantics::Vulkan,
+ Target::BothASTAndSpv, GetParam().entryPoint);
+}
+
+// clang-format off
+INSTANTIATE_TEST_CASE_P(
+ ToSpirv, HlslCompileTest,
+ ::testing::ValuesIn(std::vector<FileNameEntryPointPair>{
+ {"hlsl.frag", "PixelShaderFunction"},
+ }),
+ FileNameAsCustomTestSuffix
+);
+// clang-format on
+
+} // anonymous namespace
+} // namespace glslangtest
InitializationToken acquire(EShMessages new_messages)
{
if ((lastMessages ^ new_messages) &
- (EShMsgVulkanRules | EShMsgSpvRules)) {
+ (EShMsgVulkanRules | EShMsgSpvRules | EShMsgReadHlsl)) {
glslang::FinalizeProcess();
glslang::InitializeProcess();
}
"preprocessor.defined.vert",
"preprocessor.many.endif.vert",
})),
- FileNameAsCustomTestName
+ FileNameAsCustomTestSuffix
);
// clang-format on
TEST_P(CompileToSpirvTest, FromFile)
{
loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(),
- Semantics::Vulkan, Target::Spirv);
+ Source::GLSL, Semantics::Vulkan,
+ Target::Spv);
}
// GLSL-level Vulkan semantics test. Expected to error out before generating
TEST_P(VulkanSemantics, FromFile)
{
loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(),
- Semantics::Vulkan, Target::Spirv);
+ Source::GLSL, Semantics::Vulkan,
+ Target::Spv);
}
// clang-format off
"spv.specConstant.comp",
"spv.specConstantComposite.vert",
})),
- FileNameAsCustomTestName
+ FileNameAsCustomTestSuffix
);
INSTANTIATE_TEST_CASE_P(
"vulkan.vert",
"vulkan.comp",
})),
- FileNameAsCustomTestName
+ FileNameAsCustomTestSuffix
);
// clang-format on
namespace glslangtest {
-std::string FileNameAsCustomTestName(
+std::string FileNameAsCustomTestSuffix(
const ::testing::TestParamInfo<std::string>& info)
{
std::string name = info.param;
return name;
}
-EShLanguage GetGlslLanguageForStage(const std::string& stage)
+EShLanguage GetShaderStage(const std::string& stage)
{
if (stage == "vert") {
return EShLangVertex;
}
}
-EShMessages GetSpirvMessageOptionsForSemanticsAndTarget(Semantics semantics,
- Target target)
+EShMessages DeriveOptions(Source source, Semantics semantics, Target target)
{
EShMessages result = EShMsgDefault;
+ switch (source) {
+ case Source::GLSL:
+ break;
+ case Source::HLSL:
+ result = EShMsgReadHlsl;
+ break;
+ }
+
switch (target) {
case Target::AST:
- result = EShMsgAST;
+ result = static_cast<EShMessages>(result | EShMsgAST);
+ break;
+ case Target::Spv:
+ result = static_cast<EShMessages>(result | EShMsgSpvRules);
break;
- case Target::Spirv:
- result = EShMsgSpvRules;
+ case Target::BothASTAndSpv:
+ result = static_cast<EShMessages>(result | EShMsgSpvRules | EShMsgAST);
break;
};
// This function is used to provide custom test name suffixes based on the
// shader source file names. Otherwise, the test name suffixes will just be
// numbers, which are not quite obvious.
-std::string FileNameAsCustomTestName(
+std::string FileNameAsCustomTestSuffix(
const ::testing::TestParamInfo<std::string>& info);
+enum class Source {
+ GLSL,
+ HLSL,
+};
+
// Enum for shader compilation semantics.
enum class Semantics {
OpenGL,
// Enum for compilation target.
enum class Target {
AST,
- Spirv,
+ Spv,
+ BothASTAndSpv,
};
-EShLanguage GetGlslLanguageForStage(const std::string& stage);
+EShLanguage GetShaderStage(const std::string& stage);
-EShMessages GetSpirvMessageOptionsForSemanticsAndTarget(Semantics semantics,
- Target target);
+EShMessages DeriveOptions(Source, Semantics, Target);
// Reads the content of the file at the given |path|. On success, returns true
// and the contents; otherwise, returns false and an empty string.
const std::string spirv; // Optional SPIR-V disassembly text.
};
- // Compiles and linkes the given GLSL |source| code of the given shader
+ // Compiles and linkes the given source |code| of the given shader
// |stage| into the given |target| under the given |semantics|. Returns
// a GlslangResult instance containing all the information generated
// during the process. If |target| is Target::Spirv, also disassembles
// the result and returns disassembly text.
- GlslangResult compileGlsl(const std::string& source,
- const std::string& stage, Semantics semantics,
- Target target)
+ GlslangResult compile(const std::string& code, Source source,
+ const std::string& stage, Semantics semantics,
+ Target target, const std::string& entryPointName)
{
- const char* shaderStrings = source.data();
- const int shaderLengths = static_cast<int>(source.size());
- const EShLanguage language = GetGlslLanguageForStage(stage);
+ const char* shaderStrings = code.data();
+ const int shaderLengths = static_cast<int>(code.size());
+ const EShLanguage kind = GetShaderStage(stage);
- glslang::TShader shader(language);
+ glslang::TShader shader(kind);
shader.setStringsWithLengths(&shaderStrings, &shaderLengths, 1);
- const EShMessages messages =
- GetSpirvMessageOptionsForSemanticsAndTarget(semantics, target);
+ if (!entryPointName.empty()) shader.setEntryPoint(entryPointName.c_str());
+ const EShMessages messages = DeriveOptions(source, semantics, target);
// Reinitialize glslang if the semantics change.
GlslangInitializer::InitializationToken token =
GlobalTestSettings.initializer->acquire(messages);
spv::SpvBuildLogger logger;
- if (success && target == Target::Spirv) {
+ if (success && (target == Target::Spv || target == Target::BothASTAndSpv)) {
std::vector<uint32_t> spirv_binary;
- glslang::GlslangToSpv(*program.getIntermediate(language),
+ glslang::GlslangToSpv(*program.getIntermediate(kind),
spirv_binary, &logger);
std::ostringstream disassembly_stream;
void loadFileCompileAndCheck(const std::string& testDir,
const std::string& testName,
- Semantics semantics, Target target)
+ Source source,
+ Semantics semantics,
+ Target target,
+ const std::string& entryPointName="")
{
const std::string inputFname = testDir + "/" + testName;
const std::string expectedOutputFname =
tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
GlslangResult result =
- compileGlsl(input, GetSuffix(testName), semantics, target);
+ compile(input, source, GetSuffix(testName),
+ semantics, target, entryPointName);
// Generate the hybrid output in the way of glslangValidator.
std::ostringstream stream;
outputIfNotEmpty(result.linkingOutput);
outputIfNotEmpty(result.linkingError);
stream << result.spirvWarningsErrors;
- if (target == Target::Spirv) {
+ if (target == Target::Spv || target == Target::BothASTAndSpv) {
stream
<< (result.spirv.empty()
? "SPIR-V is not generated for failed compile or link\n"
expectedOutputFname);
}
- // Preprocesses the given GLSL |source| code. On success, returns true, the
+ // Preprocesses the given |source| code. On success, returns true, the
// preprocessed shader, and warning messages. Otherwise, returns false, an
// empty string, and error messages.
- std::tuple<bool, std::string, std::string> preprocessGlsl(
+ std::tuple<bool, std::string, std::string> preprocess(
const std::string& source)
{
const char* shaderStrings = source.data();
bool ppOk;
std::string output, error;
- std::tie(ppOk, output, error) = preprocessGlsl(input);
+ std::tie(ppOk, output, error) = preprocess(input);
if (!output.empty()) output += '\n';
if (!error.empty()) error += '\n';