+#include <spirv-tools/libspirv.hpp>
#include <msp/core/algorithm.h>
#include <msp/fs/dir.h>
#include <msp/fs/utils.h>
{
std::string name;
std::string source;
+ Msp::GL::GraphicsApi target_api;
Msp::GL::SL::Compiler::Mode compile_mode;
std::map<std::string, int> spec_values;
std::map<Msp::GL::SL::Stage::Type, std::string> expected_output;
virtual void fail(const std::string &m) { Test::fail(m); }
};
+class GlslCompilerSpirV: public Msp::Test::RegisteredTest<GlslCompilerSpirV>, private GlslCompilerHelper
+{
+private:
+ spvtools::SpirvTools spirv_tools;
+
+public:
+ GlslCompilerSpirV();
+
+ static const char *get_name() { return "GLSL to SPIR-V compilation"; }
+
+private:
+ void run_test_case(const TestCase *);
+ void diagnostic(spv_message_level_t, const char *, const spv_position_t &, const char *);
+ virtual void fail(const std::string &m) { Test::fail(m); }
+};
+
using namespace std;
using namespace Msp;
void GlslCompilerHelper::load_all_test_cases(const FS::Path &tests_dir)
{
- list<string> test_files = FS::list_filtered(tests_dir, "\\.glsl$");
- test_files.sort();
+ vector<string> test_files = FS::list_filtered(tests_dir, "\\.glsl$");
+ sort(test_files);
for(const auto &fn: test_files)
load_test_case((tests_dir/fn).str());
}
IO::BufferedFile file(fn);
TestCase test_case;
test_case.name = FS::basename(fn);
+ test_case.target_api = GL::OPENGL;
test_case.compile_mode = GL::SL::Compiler::PROGRAM;
string *target = &test_case.source;
while(!file.eof())
continue;
}
+ pos = line.find("Target API:");
+ if(pos!=string::npos)
+ {
+ string api = strip(line.substr(pos+11));
+ if(api=="OpenGL")
+ test_case.target_api = GL::OPENGL;
+ else if(api=="OpenGL ES")
+ test_case.target_api = GL::OPENGL_ES;
+ else if(api=="Vulkan")
+ test_case.target_api = GL::VULKAN;
+ else
+ throw runtime_error("Unknown API "+api);
+ continue;
+ }
+
pos = line.find("Compile mode:");
if(pos!=string::npos)
{
void GlslCompilerTest::run_test_case(const TestCase *test_case)
{
- GL::SL::Compiler compiler(GL::SL::Features::latest());
+ GL::SL::Compiler compiler(GL::SL::Features::latest(test_case->target_api));
try
{
compiler.set_source(test_case->source, "<test>");
void GlslCompilerIdempotence::run_test_case(const TestCase *test_case)
{
- GL::SL::Compiler compiler(GL::SL::Features::latest());
+ GL::SL::Compiler compiler(GL::SL::Features::latest(test_case->target_api));
compiler.set_source(test_case->source, "<test>");
if(test_case->compile_mode==GL::SL::Compiler::PROGRAM)
compiler.specialize(test_case->spec_values);
compiler.compile(test_case->compile_mode);
- GL::SL::Compiler compiler2(GL::SL::Features::latest());
+ GL::SL::Compiler compiler2(GL::SL::Features::latest(test_case->target_api));
compiler2.set_source(compiler.get_combined_glsl(), "<loopback>");
compiler2.compile(test_case->compile_mode);
if(j!=stages2.end())
fail(format("Second pass produced extra stage %s", GL::SL::Stage::get_stage_name(*j)));
}
+
+
+GlslCompilerSpirV::GlslCompilerSpirV():
+ spirv_tools(SPV_ENV_UNIVERSAL_1_5)
+{
+ load_all_test_cases("glsl");
+ for(const auto &tc: test_cases)
+ if(tc.expect_success)
+ add(&GlslCompilerSpirV::run_test_case, &tc, tc.name);
+
+ using namespace std::placeholders;
+ spirv_tools.SetMessageConsumer(std::bind(std::mem_fn(&GlslCompilerSpirV::diagnostic), this, _1, _2, _3, _4));
+}
+
+void GlslCompilerSpirV::run_test_case(const TestCase *test_case)
+{
+ GL::SL::Compiler compiler(GL::SL::Features::latest(test_case->target_api));
+ compiler.set_source(test_case->source, "<test>");
+ compiler.compile(GL::SL::Compiler::SPIRV);
+
+ vector<uint32_t> code = compiler.get_combined_spirv();
+ if(!spirv_tools.Validate(code))
+ fail("Invalid SPIR-V generated");
+}
+
+void GlslCompilerSpirV::diagnostic(spv_message_level_t level, const char *, const spv_position_t &, const char *message)
+{
+ const char *prefix;
+ switch(level)
+ {
+ case SPV_MSG_DEBUG: prefix = "debug: "; break;
+ case SPV_MSG_INFO: prefix = "info: "; break;
+ case SPV_MSG_WARNING: prefix = "warning: "; break;
+ case SPV_MSG_ERROR: prefix = "error: "; break;
+ default: prefix = "";
+ }
+ info(format("%s%s", prefix, message));
+}