Add spvParseVulkanEnv (#3142)

This new API lets clients request a minimal spv_target_env value
that supports a given Vulkan and SPIR-V version, by a generic
numbering scheme (as already defined by Vulkan and SPIR-V specs).

This breaks a formal source dependency from Glslang to SPIRV-Tools.
When a new API is rolled out, such as Vulkan 1.2, Glslang currently
needs to reference a specific SPIRV-Tools enum by name.
This commit is contained in:
David Neto 2020-01-23 17:20:32 -05:00 committed by GitHub
parent dd37d73c5e
commit bb236c326d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 101 additions and 2 deletions

View File

@ -473,6 +473,19 @@ SPIRV_TOOLS_EXPORT const char* spvTargetEnvDescription(spv_target_env env);
// false and sets *env to SPV_ENV_UNIVERSAL_1_0.
SPIRV_TOOLS_EXPORT bool spvParseTargetEnv(const char* s, spv_target_env* env);
// Determines the target env value with the least features but which enables
// the given Vulkan and SPIR-V versions. If such a target is supported, returns
// true and writes the value to |env|, otherwise returns false.
//
// The Vulkan version is given as an unsigned 32-bit number as specified in
// Vulkan section "29.2.1 Version Numbers": the major version number appears
// in bits 22 to 21, and the minor version is in bits 12 to 21. The SPIR-V
// version is given in the SPIR-V version header word: major version in bits
// 16 to 23, and minor version in bits 8 to 15.
SPIRV_TOOLS_EXPORT bool spvParseVulkanEnv(uint32_t vulkan_ver,
uint32_t spirv_ver,
spv_target_env* env);
// Creates a context object. Returns null if env is invalid.
SPIRV_TOOLS_EXPORT spv_context spvContextCreate(spv_target_env env);

View File

@ -153,6 +153,34 @@ bool spvParseTargetEnv(const char* s, spv_target_env* env) {
return false;
}
#define VULKAN_VER(MAJOR, MINOR) ((MAJOR << 22) | (MINOR << 12))
#define SPIRV_VER(MAJOR, MINOR) ((MAJOR << 16) | (MINOR << 8))
struct VulkanEnv {
spv_target_env vulkan_env;
uint32_t vulkan_ver;
uint32_t spirv_ver;
};
// Maps each Vulkan target environment enum to the Vulkan version, and the
// maximum supported SPIR-V version for that Vulkan environment.
// Keep this ordered from least capable to most capable.
static const VulkanEnv ordered_vulkan_envs[] = {
{SPV_ENV_VULKAN_1_0, VULKAN_VER(1, 0), SPIRV_VER(1, 0)},
{SPV_ENV_VULKAN_1_1, VULKAN_VER(1, 1), SPIRV_VER(1, 3)},
{SPV_ENV_VULKAN_1_1_SPIRV_1_4, VULKAN_VER(1, 1), SPIRV_VER(1, 4)},
{SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)}};
bool spvParseVulkanEnv(uint32_t vulkan_ver, uint32_t spirv_ver,
spv_target_env* env) {
for (auto triple : ordered_vulkan_envs) {
if (triple.vulkan_ver >= vulkan_ver && triple.spirv_ver >= spirv_ver) {
*env = triple.vulkan_env;
return true;
}
}
return false;
}
bool spvIsVulkanEnv(spv_target_env env) {
switch (env) {
case SPV_ENV_UNIVERSAL_1_0:

View File

@ -63,11 +63,13 @@ struct ParseCase {
using TargetParseTest = ::testing::TestWithParam<ParseCase>;
TEST_P(TargetParseTest, InvalidTargetEnvProducesNull) {
TEST_P(TargetParseTest, Samples) {
spv_target_env env;
bool parsed = spvParseTargetEnv(GetParam().input, &env);
EXPECT_THAT(parsed, Eq(GetParam().success));
EXPECT_THAT(env, Eq(GetParam().env));
if (parsed) {
EXPECT_THAT(env, Eq(GetParam().env));
}
}
INSTANTIATE_TEST_SUITE_P(
@ -103,5 +105,61 @@ INSTANTIATE_TEST_SUITE_P(
{"abc", false, SPV_ENV_UNIVERSAL_1_0},
}));
// A test case for parsing an environment string.
struct ParseVulkanCase {
uint32_t vulkan;
uint32_t spirv;
bool success; // Expect to successfully parse?
spv_target_env env; // The parsed environment, if successful.
};
using TargetParseVulkanTest = ::testing::TestWithParam<ParseVulkanCase>;
TEST_P(TargetParseVulkanTest, Samples) {
spv_target_env env;
bool parsed = spvParseVulkanEnv(GetParam().vulkan, GetParam().spirv, &env);
EXPECT_THAT(parsed, Eq(GetParam().success));
if (parsed) {
EXPECT_THAT(env, Eq(GetParam().env));
}
}
#define VK(MAJ, MIN) ((MAJ << 22) | (MIN << 12))
#define SPV(MAJ, MIN) ((MAJ << 16) | (MIN << 8))
INSTANTIATE_TEST_SUITE_P(
TargetVulkanParsing, TargetParseVulkanTest,
ValuesIn(std::vector<ParseVulkanCase>{
// Vulkan 1.0 cases
{VK(1, 0), SPV(1, 0), true, SPV_ENV_VULKAN_1_0},
{VK(1, 0), SPV(1, 1), true, SPV_ENV_VULKAN_1_1},
{VK(1, 0), SPV(1, 2), true, SPV_ENV_VULKAN_1_1},
{VK(1, 0), SPV(1, 3), true, SPV_ENV_VULKAN_1_1},
{VK(1, 0), SPV(1, 4), true, SPV_ENV_VULKAN_1_1_SPIRV_1_4},
{VK(1, 0), SPV(1, 5), true, SPV_ENV_VULKAN_1_2},
{VK(1, 0), SPV(1, 6), false, SPV_ENV_UNIVERSAL_1_0},
// Vulkan 1.1 cases
{VK(1, 1), SPV(1, 0), true, SPV_ENV_VULKAN_1_1},
{VK(1, 1), SPV(1, 1), true, SPV_ENV_VULKAN_1_1},
{VK(1, 1), SPV(1, 2), true, SPV_ENV_VULKAN_1_1},
{VK(1, 1), SPV(1, 3), true, SPV_ENV_VULKAN_1_1},
{VK(1, 1), SPV(1, 4), true, SPV_ENV_VULKAN_1_1_SPIRV_1_4},
{VK(1, 1), SPV(1, 5), true, SPV_ENV_VULKAN_1_2},
{VK(1, 1), SPV(1, 6), false, SPV_ENV_UNIVERSAL_1_0},
// Vulkan 1.2 cases
{VK(1, 2), SPV(1, 0), true, SPV_ENV_VULKAN_1_2},
{VK(1, 2), SPV(1, 1), true, SPV_ENV_VULKAN_1_2},
{VK(1, 2), SPV(1, 2), true, SPV_ENV_VULKAN_1_2},
{VK(1, 2), SPV(1, 3), true, SPV_ENV_VULKAN_1_2},
{VK(1, 2), SPV(1, 4), true, SPV_ENV_VULKAN_1_2},
{VK(1, 2), SPV(1, 5), true, SPV_ENV_VULKAN_1_2},
{VK(1, 2), SPV(1, 6), false, SPV_ENV_UNIVERSAL_1_0},
// Vulkan 1.3 cases
{VK(1, 3), SPV(1, 0), false, SPV_ENV_UNIVERSAL_1_0},
// Vulkan 2.0 cases
{VK(2, 0), SPV(1, 0), false, SPV_ENV_UNIVERSAL_1_0},
// Vulkan 99.0 cases
{VK(99, 0), SPV(1, 0), false, SPV_ENV_UNIVERSAL_1_0},
}));
} // namespace
} // namespace spvtools