]> git.tdb.fi Git - libs/gl.git/blobdiff - tests/glsl/glslcompiler.cpp
Make it possible to specify a target API for GLSL test cases
[libs/gl.git] / tests / glsl / glslcompiler.cpp
index 01c1fba28e2e4fe90d0f2268a485538fd671f258..7deeb1f35190b403f8594e159562498e522e5b9e 100644 (file)
@@ -1,3 +1,4 @@
+#include <spirv-tools/libspirv.hpp>
 #include <msp/core/algorithm.h>
 #include <msp/fs/dir.h>
 #include <msp/fs/utils.h>
@@ -14,6 +15,7 @@ protected:
        {
                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;
@@ -58,13 +60,29 @@ private:
        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());
 }
@@ -74,6 +92,7 @@ const GlslCompilerHelper::TestCase &GlslCompilerHelper::load_test_case(const 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())
@@ -110,6 +129,21 @@ const GlslCompilerHelper::TestCase &GlslCompilerHelper::load_test_case(const str
                        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)
                {
@@ -234,7 +268,7 @@ GlslCompilerTest::GlslCompilerTest()
 
 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>");
@@ -291,13 +325,13 @@ GlslCompilerIdempotence::GlslCompilerIdempotence()
 
 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);
 
@@ -318,3 +352,41 @@ void GlslCompilerIdempotence::run_test_case(const TestCase *test_case)
        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));
+}