summaryrefslogtreecommitdiffstats
path: root/source/core
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-03-07 16:31:56 -0500
committerGitHub <noreply@github.com>2019-03-07 16:31:56 -0500
commitf33aee2be9017934140da9fdfb0dcde15568b3a8 (patch)
tree15e0a6bdf137c103806269cdd2c490467560642c /source/core
parent3f6609a61465a09ad83ecbab5f59ec9475e5cc81 (diff)
Fix problems with synthesized tests and inconsitent render-test command lines (#885)
* * Check for inconsistent command line options for renderer * Moved RenderApiUtil into core so can be used in slang-test * Make it use the ShaderdLibrary for API testsing * Added some simplifying functions to StringUtil for spliting/comparisons * Refactored the synthesis of rendering tests so that inconsistent combinations are not produced * Add missing slang-render-api-util.cpp & .h * Stop warning on linux about _canLoadSharedLibrary not being used.
Diffstat (limited to 'source/core')
-rw-r--r--source/core/core.vcxproj2
-rw-r--r--source/core/core.vcxproj.filters6
-rw-r--r--source/core/slang-render-api-util.cpp286
-rw-r--r--source/core/slang-render-api-util.h78
-rw-r--r--source/core/slang-string-util.cpp52
-rw-r--r--source/core/slang-string-util.h8
6 files changed, 432 insertions, 0 deletions
diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj
index bebf7350c..b89e2acff 100644
--- a/source/core/core.vcxproj
+++ b/source/core/core.vcxproj
@@ -190,6 +190,7 @@
<ClInclude Include="slang-memory-arena.h" />
<ClInclude Include="slang-object-scope-manager.h" />
<ClInclude Include="slang-random-generator.h" />
+ <ClInclude Include="slang-render-api-util.h" />
<ClInclude Include="slang-shared-library.h" />
<ClInclude Include="slang-std-writers.h" />
<ClInclude Include="slang-string-slice-pool.h" />
@@ -211,6 +212,7 @@
<ClCompile Include="slang-memory-arena.cpp" />
<ClCompile Include="slang-object-scope-manager.cpp" />
<ClCompile Include="slang-random-generator.cpp" />
+ <ClCompile Include="slang-render-api-util.cpp" />
<ClCompile Include="slang-shared-library.cpp" />
<ClCompile Include="slang-std-writers.cpp" />
<ClCompile Include="slang-string-slice-pool.cpp" />
diff --git a/source/core/core.vcxproj.filters b/source/core/core.vcxproj.filters
index dd33b61f9..2faaa7137 100644
--- a/source/core/core.vcxproj.filters
+++ b/source/core/core.vcxproj.filters
@@ -69,6 +69,9 @@
<ClInclude Include="slang-random-generator.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="slang-render-api-util.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="slang-shared-library.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -128,6 +131,9 @@
<ClCompile Include="slang-random-generator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="slang-render-api-util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="slang-shared-library.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/source/core/slang-render-api-util.cpp b/source/core/slang-render-api-util.cpp
new file mode 100644
index 000000000..80f2225d9
--- /dev/null
+++ b/source/core/slang-render-api-util.cpp
@@ -0,0 +1,286 @@
+
+#include "slang-render-api-util.h"
+
+#include "../../slang.h"
+
+#include "../../source/core/list.h"
+#include "../../source/core/slang-string-util.h"
+
+#include "platform.h"
+
+namespace Slang {
+
+// NOTE! Must keep in same order as RenderApiType and have same amount of entries
+/* static */const RenderApiUtil::Info RenderApiUtil::s_infos[] =
+{
+ { RenderApiType::OpenGl, "gl,ogl,opengl", "glsl,glsl-rewrite,glsl-cross"},
+ { RenderApiType::Vulkan, "vk,vulkan", ""},
+ { RenderApiType::D3D12, "dx12,d3d12", ""},
+ { RenderApiType::D3D11, "dx11,d3d11", "hlsl,hlsl-rewrite,slang"},
+};
+
+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;
+}
+
+UnownedStringSlice RenderApiUtil::getApiName(RenderApiType type)
+{
+ int index = int(type);
+ if (index < 0 || index >= int(RenderApiType::CountOf))
+ {
+ return UnownedStringSlice();
+ }
+ SLANG_ASSERT(s_infos[index].type == type);
+ return StringUtil::getAtInSplit(UnownedStringSlice(s_infos[index].names), ',', 0);
+}
+
+/* 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 */ Slang::Result RenderApiUtil::findApiFlagsByName(const Slang::UnownedStringSlice& name, RenderApiFlags* flagsOut)
+{
+ // Special case 'all'
+ if (name == "all")
+ {
+ *flagsOut = RenderApiFlags(RenderApiFlag::AllOf);
+ return SLANG_OK;
+ }
+ if (name == "none")
+ {
+ *flagsOut = RenderApiFlags(0);
+ return SLANG_OK;
+ }
+ RenderApiType type = findApiTypeByName(name);
+ if (type == RenderApiType::Unknown)
+ {
+ return SLANG_FAIL;
+ }
+ *flagsOut = RenderApiFlags(1) << int(type);
+ return SLANG_OK;
+}
+
+static bool isNameStartChar(char c)
+{
+ return (c >= 'a' && c <='z') || (c >= 'A' && c <= 'Z') || (c == '_');
+}
+
+static bool isNameNextChar(char c)
+{
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c >= '0' && c <= '9');
+}
+
+namespace { // anonymous
+enum class Token
+{
+ eError,
+ eOp,
+ eId,
+ eEnd,
+};
+}
+
+static Token nextToken(Slang::UnownedStringSlice& textInOut, Slang::UnownedStringSlice& lexemeOut)
+{
+ using namespace Slang;
+ if (textInOut.size() <= 0)
+ {
+ return Token::eEnd;
+ }
+ const char* start = textInOut.begin();
+ const char* end = textInOut.end();
+
+ const char firstChar = start[0];
+ if (firstChar == '-' || firstChar == '+')
+ {
+ lexemeOut = UnownedStringSlice(start, start + 1);
+ textInOut = UnownedStringSlice(start + 1, end);
+ return Token::eOp;
+ }
+
+ if (!isNameStartChar(firstChar))
+ {
+ lexemeOut = UnownedStringSlice(start, start + 1);
+ return Token::eError;
+ }
+ const char* cur = start + 1;
+ while (cur < end && isNameNextChar(*cur))
+ {
+ cur++;
+ }
+
+ lexemeOut = UnownedStringSlice(start, cur);
+ textInOut = UnownedStringSlice(cur, end);
+ return Token::eId;
+}
+
+/* static */Slang::Result RenderApiUtil::parseApiFlags(const Slang::UnownedStringSlice& textIn, RenderApiFlags initialFlags, RenderApiFlags* apiFlagsOut)
+{
+ using namespace Slang;
+
+ UnownedStringSlice text(textIn);
+ UnownedStringSlice lexeme;
+
+ RenderApiFlags apiFlags = 0;
+
+ switch (nextToken(text, lexeme))
+ {
+ case Token::eOp:
+ {
+ // If we start with an op - we use the passed in values as the default
+ // Rewind back to the start
+ text = textIn;
+ apiFlags = initialFlags;
+ break;
+ }
+ case Token::eId:
+ {
+ // If we start with an Id - we use that as the starting state
+ SLANG_RETURN_ON_FAIL(findApiFlagsByName(lexeme, &apiFlags));
+ break;
+ }
+ default: return SLANG_FAIL;
+ }
+
+ while (true)
+ {
+ // Must have an op followed by an id unless we are at the end
+ switch (nextToken(text, lexeme))
+ {
+ case Token::eEnd:
+ {
+ *apiFlagsOut = apiFlags;
+ return SLANG_OK;
+ }
+ case Token::eOp: break;
+ default: return SLANG_FAIL;
+ }
+
+ const char op = lexeme[0];
+ if (nextToken(text, lexeme) != Token::eId)
+ {
+ return SLANG_FAIL;
+ }
+
+ RenderApiFlags flags;
+ SLANG_RETURN_ON_FAIL(findApiFlagsByName(lexeme, &flags));
+
+ if (op == '+')
+ {
+ apiFlags |= flags;
+ }
+ else
+ {
+ apiFlags &= ~flags;
+ }
+ }
+}
+
+/* static */RenderApiType RenderApiUtil::findRenderApiType(const Slang::UnownedStringSlice& text)
+{
+ using namespace Slang;
+ for (int j = 0; j < SLANG_COUNT_OF(RenderApiUtil::s_infos); j++)
+ {
+ const auto& apiInfo = RenderApiUtil::s_infos[j];
+ if (StringUtil::indexOfInSplit(UnownedStringSlice(apiInfo.names), ',', text) >= 0)
+ {
+ return apiInfo.type;
+ }
+ }
+ // Didn't find any
+ return RenderApiType::Unknown;
+}
+
+/* static */RenderApiType RenderApiUtil::findImplicitLanguageRenderApiType(const Slang::UnownedStringSlice& text)
+{
+ using namespace Slang;
+ for (int j = 0; j < SLANG_COUNT_OF(RenderApiUtil::s_infos); j++)
+ {
+ const auto& apiInfo = RenderApiUtil::s_infos[j];
+ if (StringUtil::indexOfInSplit(UnownedStringSlice(apiInfo.languageNames), ',', text) >= 0)
+ {
+ return apiInfo.type;
+ }
+ }
+ // Didn't find any
+ return RenderApiType::Unknown;
+}
+
+#if SLANG_WINDOWS_FAMILY
+static bool _canLoadSharedLibrary(const char* libName)
+{
+ SharedLibrary::Handle handle;
+ SlangResult res = SharedLibrary::load(libName, handle);
+ if (SLANG_FAILED(res))
+ {
+ return false;
+ }
+ SharedLibrary::unload(handle);
+ return true;
+}
+#endif
+
+/* static */bool RenderApiUtil::calcHasApi(RenderApiType type)
+{
+#if SLANG_WINDOWS_FAMILY
+ switch (type)
+ {
+ case RenderApiType::OpenGl: return _canLoadSharedLibrary("opengl32.dll");
+ case RenderApiType::Vulkan: return _canLoadSharedLibrary("vulkan-1.dll");
+ case RenderApiType::D3D11: return _canLoadSharedLibrary("d3d11.dll");
+ case RenderApiType::D3D12: return _canLoadSharedLibrary("d3d12.dll");
+ default: break;
+ }
+#elif SLANG_UNIX_FAMILY
+ // Assume on unix target we have Opengl and Vulkan for now
+ switch (type)
+ {
+ case RenderApiType::OpenGl:
+ case RenderApiType::Vulkan:
+ {
+ return true;
+ }
+ default: break;
+ }
+#endif
+ return false;
+}
+
+} // namespace Slang
diff --git a/source/core/slang-render-api-util.h b/source/core/slang-render-api-util.h
new file mode 100644
index 000000000..42e88a6ac
--- /dev/null
+++ b/source/core/slang-render-api-util.h
@@ -0,0 +1,78 @@
+#ifndef SLANG_RENDER_API_UTIL_H
+#define SLANG_RENDER_API_UTIL_H
+
+#include "../../source/core/slang-string.h"
+
+#include "../../slang-com-helper.h"
+
+namespace Slang
+{
+
+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
+ };
+};
+typedef uint32_t RenderApiFlags;
+
+struct RenderApiUtil
+{
+ struct Info
+ {
+ RenderApiType type; ///< The type
+ const char* names; ///< Comma separated list of names associated with the type
+ const char* languageNames; ///< Comma separated list of target language 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();
+
+ /// Get the name
+ static UnownedStringSlice getApiName(RenderApiType type);
+
+ /// Returns RenderApiType::Unknown if not found
+ static RenderApiType findApiTypeByName(const Slang::UnownedStringSlice& name);
+ /// FlagsOut will have flag/flags specified by a name if returns with successful result code.
+ static Slang::Result findApiFlagsByName(const Slang::UnownedStringSlice& name, RenderApiFlags* flagsOut);
+
+ /// Parse api flags string, returning SLANG_OK on success.
+ /// If first character is + or - the flags will be applied to initialFlags, else initialFlags is ignored.
+ /// For example "all-dx12" would be all apis, except dx12
+ /// -vk would be whatever is in initial flags, but not vulkan.
+ static Slang::Result parseApiFlags(const Slang::UnownedStringSlice& text, RenderApiFlags initialFlags, RenderApiFlags* apiBitsOut);
+
+ /// Gets the API type from a string, or returns RenderApiType::Unknown if not found
+ static RenderApiType findRenderApiType(const Slang::UnownedStringSlice& text);
+
+ static RenderApiType findImplicitLanguageRenderApiType(const Slang::UnownedStringSlice& text);
+
+ /// 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)];
+};
+
+} // namespace Slang
+
+#endif // SLANG_RENDER_API_UTIL_H
diff --git a/source/core/slang-string-util.cpp b/source/core/slang-string-util.cpp
index 5d3e2188d..b7c6780e1 100644
--- a/source/core/slang-string-util.cpp
+++ b/source/core/slang-string-util.cpp
@@ -39,6 +39,58 @@ static const Guid IID_ISlangBlob = SLANG_UUID_ISlangBlob;
}
}
+/* static */int StringUtil::indexOfInSplit(const UnownedStringSlice& in, char splitChar, const UnownedStringSlice& find)
+{
+ const char* start = in.begin();
+ const char* end = in.end();
+
+ for (int i = 0; start < end; ++i)
+ {
+ // Move cur so it's either at the end or at next split character
+ const char* cur = start;
+ while (cur < end && *cur != splitChar)
+ {
+ cur++;
+ }
+
+ // See if we have a match
+ if (UnownedStringSlice(start, cur) == find)
+ {
+ return i;
+ }
+
+ // Skip the split character, if at end we are okay anyway
+ start = cur + 1;
+ }
+ return -1;
+}
+
+UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char splitChar, int index)
+{
+ const char* start = in.begin();
+ const char* end = in.end();
+
+ for (int i = 0; start < end; ++i)
+ {
+ // Move cur so it's either at the end or at next split character
+ const char* cur = start;
+ while (cur < end && *cur != splitChar)
+ {
+ cur++;
+ }
+
+ if (i == index)
+ {
+ return UnownedStringSlice(start, cur);
+ }
+
+ // Skip the split character, if at end we are okay anyway
+ start = cur + 1;
+ }
+
+ return UnownedStringSlice();
+}
+
/* static */size_t StringUtil::calcFormattedSize(const char* format, va_list args)
{
#if SLANG_WINDOWS_FAMILY
diff --git a/source/core/slang-string-util.h b/source/core/slang-string-util.h
index 3547fd97c..3288899fc 100644
--- a/source/core/slang-string-util.h
+++ b/source/core/slang-string-util.h
@@ -41,6 +41,14 @@ struct StringUtil
/// Slices contents will directly address into in, so contents will only stay valid as long as in does.
static void split(const UnownedStringSlice& in, char splitChar, List<UnownedStringSlice>& slicesOut);
+ /// Equivalent to doing a split and then finding the index of 'find' on the array
+ /// Returns -1 if not found
+ static int indexOfInSplit(const UnownedStringSlice& in, char splitChar, const UnownedStringSlice& find);
+
+ /// Given the entry at the split index specified.
+ /// Will return slice with begin() == nullptr if not found or input has begin() == nullptr)
+ static UnownedStringSlice getAtInSplit(const UnownedStringSlice& in, char splitChar, int index);
+
/// Returns the size in bytes needed to hold the formatted string using the specified args, NOT including a terminating 0
/// NOTE! The caller *should* assume this will consume the va_list (use va_copy to make a copy to be consumed)
static size_t calcFormattedSize(const char* format, va_list args);