summaryrefslogtreecommitdiff
path: root/tools/slang-test
diff options
context:
space:
mode:
Diffstat (limited to 'tools/slang-test')
-rw-r--r--tools/slang-test/main.cpp153
-rw-r--r--tools/slang-test/render-api-util.cpp210
-rw-r--r--tools/slang-test/render-api-util.h61
-rw-r--r--tools/slang-test/slang-test.vcxproj2
-rw-r--r--tools/slang-test/slang-test.vcxproj.filters6
5 files changed, 423 insertions, 9 deletions
diff --git a/tools/slang-test/main.cpp b/tools/slang-test/main.cpp
index 0f469e8d9..e67db42e4 100644
--- a/tools/slang-test/main.cpp
+++ b/tools/slang-test/main.cpp
@@ -4,10 +4,12 @@
#include "../../source/core/token-reader.h"
#include "../../source/core/slang-result.h"
+#include "../../source/core/slang-string-util.h"
using namespace Slang;
#include "os.h"
+#include "render-api-util.h"
#define STB_IMAGE_IMPLEMENTATION
#include "external/stb/stb_image.h"
@@ -70,6 +72,9 @@ struct Options
// Exclude test that match one these categories
Dictionary<TestCategory*, TestCategory*> excludeCategories;
+
+ // By default we can test against all apis
+ int enabledApis = int(RenderApiFlag::AllOf);
};
Options options;
@@ -188,6 +193,22 @@ Result parseOptions(int* argc, char** argv)
options.excludeCategories.Add(category, category);
}
}
+ else if (strcmp(arg, "-api") == 0)
+ {
+ if (argCursor == argEnd)
+ {
+ fprintf(stderr, "error: expected comma separated list of apis '%s'\n", arg);
+ return SLANG_FAIL;
+ }
+ const char* apiList = *argCursor++;
+
+ SlangResult res = RenderApiUtil::parseApiFlags(UnownedStringSlice(apiList), &options.enabledApis);
+ if (SLANG_FAILED(res))
+ {
+ fprintf(stderr, "error: unable to parse api list '%s'\n", apiList);
+ return res;
+ }
+ }
else
{
fprintf(stderr, "unknown option '%s'\n", arg);
@@ -195,6 +216,13 @@ Result parseOptions(int* argc, char** argv)
}
}
+ {
+ // Find out what apis are available
+ const int availableApis = RenderApiUtil::getAvailableApis();
+ // Only allow apis we know are available
+ options.enabledApis &= availableApis;
+ }
+
// any arguments left over were positional arguments
argCount = (int)((char**)writeCursor - argv);
argCursor = argv;
@@ -636,6 +664,44 @@ void maybeDumpOutput(
fflush(stderr);
}
+// Finds the specialized or default path for expected data for a test.
+// If neither are found, will return an empty string
+String findExpectedPath(const TestInput& input, const char* postFix)
+{
+ StringBuilder specializedBuf;
+
+ // Try the specialized name first
+ specializedBuf << input.outputStem;
+ if (postFix)
+ {
+ specializedBuf << postFix;
+ }
+ if (File::Exists(specializedBuf))
+ {
+ return specializedBuf;
+ }
+
+
+ // Try the default name
+ StringBuilder defaultBuf;
+ defaultBuf.Clear();
+ defaultBuf << input.filePath;
+ if (postFix)
+ {
+ defaultBuf << postFix;
+ }
+
+ if (File::Exists(defaultBuf))
+ {
+ return defaultBuf;
+ }
+
+ // Couldn't find either
+ printf("referenceOutput '%s' or '%s' not found.\n", defaultBuf.Buffer(), specializedBuf.Buffer());
+
+ return "";
+}
+
TestResult runSimpleTest(TestInput& input)
{
// need to execute the stand-alone Slang compiler on the file, and compare its output to what we expect
@@ -1124,12 +1190,19 @@ TestResult runGLSLComparisonTest(TestInput& input)
return kTestResult_Pass;
}
-TestResult runComputeComparisonImpl(TestInput& input, const char * langOption, String referenceOutput)
+
+TestResult runComputeComparisonImpl(TestInput& input, const char * langOption)
{
// TODO: delete any existing files at the output path(s) to avoid stale outputs leading to a false pass
auto filePath999 = input.filePath;
auto outputStem = input.outputStem;
+ const String referenceOutput = findExpectedPath(input, ".expected.txt");
+ if (referenceOutput.Length() <= 0)
+ {
+ return kTestResult_Fail;
+ }
+
OSProcessSpawner spawner;
spawner.pushExecutablePath(String(options.binDir) + "render-test" + osGetExecutableSuffix());
@@ -1211,22 +1284,22 @@ TestResult runComputeComparisonImpl(TestInput& input, const char * langOption, S
TestResult runSlangComputeComparisonTest(TestInput& input)
{
- return runComputeComparisonImpl(input, "-slang -compute", input.outputStem + ".expected.txt");
+ return runComputeComparisonImpl(input, "-slang -compute");
}
TestResult runSlangComputeComparisonTestEx(TestInput& input)
{
- return runComputeComparisonImpl(input, "", input.outputStem + ".expected.txt");
+ return runComputeComparisonImpl(input, "");
}
TestResult runHLSLComputeTest(TestInput& input)
{
- return runComputeComparisonImpl(input, "-hlsl-rewrite -compute", input.outputStem + ".expected.txt");
+ return runComputeComparisonImpl(input, "-hlsl-rewrite -compute");
}
TestResult runSlangRenderComputeComparisonTest(TestInput& input)
{
- return runComputeComparisonImpl(input, "-slang -gcompute", input.outputStem + ".expected.txt");
+ return runComputeComparisonImpl(input, "-slang -gcompute");
}
TestResult doRenderComparisonTestRun(TestInput& input, char const* langOption, char const* outputKind, String* outOutput)
@@ -1411,12 +1484,48 @@ TestResult skipTest(TestInput& /*input*/)
return kTestResult_Ignored;
}
+static bool hasD3D12Option(const TestOptions& testOptions)
+{
+ return (testOptions.args.IndexOf("-dx12") != UInt(-1) ||
+ testOptions.args.IndexOf("-d3d12") != UInt(-1));
+}
+
+bool hasD3D12Option(const FileTestList& testList)
+{
+ const int numTests = int(testList.tests.Count());
+ for (int i = 0; i < numTests; i++)
+ {
+ if (hasD3D12Option(testList.tests[i]))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isRenderTest(const String& command)
+{
+ return command == "COMPARE_COMPUTE" ||
+ command == "COMPARE_COMPUTE_EX" ||
+ command == "HLSL_COMPUTE" ||
+ command == "COMPARE_RENDER_COMPUTE" ||
+ command == "COMPARE_HLSL_RENDER" ||
+ command == "COMPARE_HLSL_CROSS_COMPILE_RENDER" ||
+ command == "COMPARE_HLSL_GLSL_RENDER";
+}
+
TestResult runTest(
String const& filePath,
String const& outputStem,
TestOptions const& testOptions,
FileTestList const& testList)
{
+ // If this is d3d12 test
+ if (hasD3D12Option(testOptions) && (options.enabledApis & RenderApiFlag::D3D12) == 0)
+ {
+ return kTestResult_Ignored;
+ }
+
// based on command name, dispatch to an appropriate callback
struct TestCommands
{
@@ -1426,11 +1535,11 @@ TestResult runTest(
static const TestCommands kTestCommands[] =
{
- { "SIMPLE", &runSimpleTest },
- { "REFLECTION", &runReflectionTest },
+ { "SIMPLE", &runSimpleTest},
+ { "REFLECTION", &runReflectionTest},
#if SLANG_TEST_SUPPORT_HLSL
- { "COMPARE_HLSL", &runHLSLComparisonTest },
- { "COMPARE_HLSL_RENDER", &runHLSLRenderComparisonTest },
+ { "COMPARE_HLSL", &runHLSLComparisonTest},
+ { "COMPARE_HLSL_RENDER", &runHLSLRenderComparisonTest},
{ "COMPARE_HLSL_CROSS_COMPILE_RENDER", &runHLSLCrossCompileRenderComparisonTest},
{ "COMPARE_HLSL_GLSL_RENDER", &runHLSLAndGLSLRenderComparisonTest },
{ "COMPARE_COMPUTE", runSlangComputeComparisonTest},
@@ -1623,6 +1732,9 @@ bool testPassesCategoryMask(
return false;
}
+
+
+
void runTestsOnFile(
TestContext* context,
String filePath)
@@ -1643,6 +1755,29 @@ void runTestsOnFile(
return;
}
+ // If dx12 is available synthesize Dx12 test
+ if ((options.enabledApis & RenderApiFlag::D3D12) != 0)
+ {
+ // If doesn't have option generate dx12 options from dx11
+ if (!hasD3D12Option(testList))
+ {
+ const int numTests = int(testList.tests.Count());
+ for (int i = 0; i < numTests; i++)
+ {
+ const TestOptions& testOptions = testList.tests[i];
+ // If it's a render test, and there is on d3d option, add one
+ if (isRenderTest(testOptions.command) && !hasD3D12Option(testOptions))
+ {
+ // Add with -dx12 option
+ TestOptions testOptionsCopy(testOptions);
+ testOptionsCopy.args.Add("-dx12");
+
+ testList.tests.Add(testOptionsCopy);
+ }
+ }
+ }
+ }
+
// We have found a test to run!
int subTestCount = 0;
for( auto& tt : testList.tests )
diff --git a/tools/slang-test/render-api-util.cpp b/tools/slang-test/render-api-util.cpp
new file mode 100644
index 000000000..b8697c54b
--- /dev/null
+++ b/tools/slang-test/render-api-util.cpp
@@ -0,0 +1,210 @@
+
+#include "render-api-util.h"
+
+#include "../../source/core/slang-defines.h"
+
+#include "../../source/core/list.h"
+#include "../../source/core/slang-string-util.h"
+
+/* static */const RenderApiUtil::Info RenderApiUtil::s_infos[] =
+{
+ { RenderApiType::OpenGl, "gl,ogl,opengl"},
+ { RenderApiType::Vulkan, "vk,vulkan"},
+ { RenderApiType::D3D12, "dx12,d3d12"},
+ { RenderApiType::D3D11, "dx11,d3d11"},
+};
+
+static int _calcAvailableApis()
+{
+ int flags = 0;
+ for (int i = 0; i < int(RenderApiType::CountOf); i++)
+ {
+ if (RenderApiUtil::calcHasApi(RenderApiType(i)))
+ {
+ flags |= (1 << i);
+ }
+ }
+
+ return flags;
+}
+
+/* static */int RenderApiUtil::getAvailableApis()
+{
+ static int s_availableApis = _calcAvailableApis();
+ return s_availableApis;
+}
+
+/* static */RenderApiType RenderApiUtil::findApiTypeByName(const Slang::UnownedStringSlice& name)
+{
+ using namespace Slang;
+ List<UnownedStringSlice> namesList;
+ for (int j = 0; j < SLANG_COUNT_OF(RenderApiUtil::s_infos); j++)
+ {
+ const auto& apiInfo = RenderApiUtil::s_infos[j];
+ const UnownedStringSlice names(apiInfo.names);
+
+ if (names.indexOf(',') >= 0)
+ {
+ StringUtil::split(names, ',', namesList);
+ if (namesList.IndexOf(name) != UInt(-1))
+ {
+ return apiInfo.type;
+ }
+ }
+ else if (names == name)
+ {
+ return apiInfo.type;
+ }
+ }
+ return RenderApiType::Unknown;
+}
+
+/* static */int RenderApiUtil::findApiFlagsByName(const Slang::UnownedStringSlice& name)
+{
+ // Special case 'all'
+ if (name == "all")
+ {
+ return int(RenderApiFlag::AllOf);
+ }
+ RenderApiType type = findApiTypeByName(name);
+ return (type == RenderApiType::Unknown) ? 0 : (1 << int(type));
+}
+
+/* static */Slang::Result RenderApiUtil::parseApiFlags(const Slang::UnownedStringSlice& text, int* apiBitsOut)
+{
+ using namespace Slang;
+
+ int apiBits = 0;
+
+ List<UnownedStringSlice> slices;
+ StringUtil::split(text, ',', slices);
+
+ for (int i = 0; i < int(slices.Count()); ++i)
+ {
+ UnownedStringSlice slice = slices[i];
+ bool add = true;
+ if (slice.size() <= 0)
+ {
+ return SLANG_FAIL;
+ }
+ if (slice[0] == '+')
+ {
+ // Drop the +
+ slice = UnownedStringSlice(slice.begin() + 1, slice.end());
+ }
+ else if (slice[0] == '-')
+ {
+ add = false;
+ // Drop the +
+ slice = UnownedStringSlice(slice.begin() + 1, slice.end());
+ }
+
+ // We need to find the bits...
+ int bits = findApiFlagsByName(slice);
+ // 0 means an error
+ if (bits == 0)
+ {
+ return SLANG_FAIL;
+ }
+
+ if (add)
+ {
+ apiBits |= bits;
+ }
+ else
+ {
+ apiBits &= ~bits;
+ }
+ }
+
+ *apiBitsOut = apiBits;
+ return SLANG_OK;
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!! Platform specific stuff !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+
+#if SLANG_WINDOWS_FAMILY
+
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <Windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#undef NOMINMAX
+
+namespace { // anonymous
+
+class WinModule
+{
+public:
+
+ /// Initialize. Returns the module on success
+ HMODULE init(const char* name)
+ {
+ if (m_module)
+ {
+ ::FreeModule(m_module);
+ m_module = nullptr;
+ }
+ return m_module = ::LoadLibraryA(name);
+ }
+
+ /// convert to HMODULE
+ SLANG_FORCE_INLINE operator HMODULE() const { return m_module; }
+
+ /// True if loaded
+ bool isLoaded() const { return m_module != nullptr; }
+
+ explicit WinModule(const char* name) :
+ m_module(nullptr)
+ {
+ init(name);
+ }
+
+ /// Ctor
+ WinModule() :m_module(nullptr) {}
+ /// Dtor
+ ~WinModule()
+ {
+ if (m_module)
+ {
+ ::FreeLibrary(m_module);
+ }
+ }
+
+protected:
+ HMODULE m_module;
+};
+
+} // anonymous
+
+#else
+#endif
+
+/* static */bool RenderApiUtil::calcHasApi(RenderApiType type)
+{
+#if SLANG_WINDOWS_FAMILY
+ switch (type)
+ {
+ case RenderApiType::OpenGl: return WinModule("opengl32.dll").isLoaded();
+ case RenderApiType::Vulkan: return WinModule("vulkan-1.dll").isLoaded();
+ case RenderApiType::D3D11: return WinModule("d3d11.dll").isLoaded();
+ case RenderApiType::D3D12: return WinModule("d3d12.dll").isLoaded();
+
+ default: return false;
+ }
+
+#else
+
+ switch (type)
+ {
+ case RenderApiType::OpenGl:
+ case RenderApiType::Vulkan:
+ {
+ return true;
+ }
+ default: return false;
+ }
+#endif
+
+}
diff --git a/tools/slang-test/render-api-util.h b/tools/slang-test/render-api-util.h
new file mode 100644
index 000000000..0f941f05d
--- /dev/null
+++ b/tools/slang-test/render-api-util.h
@@ -0,0 +1,61 @@
+#ifndef SLANG_RENDER_API_UTIL_H
+#define SLANG_RENDER_API_UTIL_H
+
+#include "../../source/core/slang-string.h"
+#include "../../source/core/slang-result.h"
+
+
+enum class RenderApiType
+{
+ Unknown = -1,
+ OpenGl = 0,
+ Vulkan,
+ D3D12,
+ D3D11,
+ CountOf,
+};
+
+// Use a struct wrapped Enum instead of enum class, cos we want to be able to manipulate as integrals
+struct RenderApiFlag
+{
+ enum Enum
+ {
+ OpenGl = 1 << int(RenderApiType::OpenGl),
+ Vulkan = 1 << int(RenderApiType::Vulkan),
+ D3D12 = 1 << int(RenderApiType::D3D12),
+ D3D11 = 1 << int(RenderApiType::D3D11),
+ AllOf = (1 << int(RenderApiType::CountOf)) - 1 ///< All bits set
+ };
+};
+
+struct RenderApiUtil
+{
+ struct Info
+ {
+ RenderApiType type; ///< The type
+ const char* names; ///< Comma separated list of names associated with the type
+ };
+
+ /// Returns true if the API is available.
+ static bool calcHasApi(RenderApiType type);
+
+ /// Returns a combination of RenderApiFlag bits which if set indicates that the API is available.
+ static int getAvailableApis();
+
+ /// Returns -1 if unknown
+ static RenderApiType findApiTypeByName(const Slang::UnownedStringSlice& name);
+ /// Returns 0 if none found.
+ static int findApiFlagsByName(const Slang::UnownedStringSlice& name);
+
+ /// Parse api flags string (comma delimited list of api names, or 'all' for all)
+ /// For example "all,-dx12" would be all apis, except dx12
+ static Slang::Result parseApiFlags(const Slang::UnownedStringSlice& text, int* apiBitsOut);
+
+ /// Get information about a render API
+ static const Info& getInfo(RenderApiType type) { return s_infos[int(type)]; }
+
+ /// Static information about each render api
+ static const Info s_infos[int(RenderApiType::CountOf)];
+};
+
+#endif // SLANG_RENDER_API_UTIL_H \ No newline at end of file
diff --git a/tools/slang-test/slang-test.vcxproj b/tools/slang-test/slang-test.vcxproj
index fc4e88493..34d9bed40 100644
--- a/tools/slang-test/slang-test.vcxproj
+++ b/tools/slang-test/slang-test.vcxproj
@@ -160,9 +160,11 @@
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="os.cpp" />
+ <ClCompile Include="render-api-util.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="os.h" />
+ <ClInclude Include="render-api-util.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\source\core\core.vcxproj">
diff --git a/tools/slang-test/slang-test.vcxproj.filters b/tools/slang-test/slang-test.vcxproj.filters
index 3549e6046..e9342cfd6 100644
--- a/tools/slang-test/slang-test.vcxproj.filters
+++ b/tools/slang-test/slang-test.vcxproj.filters
@@ -21,10 +21,16 @@
<ClCompile Include="os.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="render-api-util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="os.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="render-api-util.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
</Project> \ No newline at end of file