| // Copyright (c) 2015-2016 The Khronos Group Inc. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "source/spirv_target_env.h" | |
| #include <array> | |
| #include <cassert> | |
| #include <cctype> | |
| #include <cstring> | |
| #include <string> | |
| #include "source/latest_version_spirv_header.h" | |
| #include "source/spirv_constant.h" | |
| #include "spirv-tools/libspirv.h" | |
| const char* spvTargetEnvDescription(spv_target_env env) { | |
| switch (env) { | |
| case SPV_ENV_UNIVERSAL_1_0: | |
| return "SPIR-V 1.0"; | |
| case SPV_ENV_VULKAN_1_0: | |
| return "SPIR-V 1.0 (under Vulkan 1.0 semantics)"; | |
| case SPV_ENV_UNIVERSAL_1_1: | |
| return "SPIR-V 1.1"; | |
| case SPV_ENV_OPENCL_1_2: | |
| return "SPIR-V 1.0 (under OpenCL 1.2 Full Profile semantics)"; | |
| case SPV_ENV_OPENCL_EMBEDDED_1_2: | |
| return "SPIR-V 1.0 (under OpenCL 1.2 Embedded Profile semantics)"; | |
| case SPV_ENV_OPENCL_2_0: | |
| return "SPIR-V 1.0 (under OpenCL 2.0 Full Profile semantics)"; | |
| case SPV_ENV_OPENCL_EMBEDDED_2_0: | |
| return "SPIR-V 1.0 (under OpenCL 2.0 Embedded Profile semantics)"; | |
| case SPV_ENV_OPENCL_2_1: | |
| return "SPIR-V 1.0 (under OpenCL 2.1 Full Profile semantics)"; | |
| case SPV_ENV_OPENCL_EMBEDDED_2_1: | |
| return "SPIR-V 1.0 (under OpenCL 2.1 Embedded Profile semantics)"; | |
| case SPV_ENV_OPENCL_2_2: | |
| return "SPIR-V 1.2 (under OpenCL 2.2 Full Profile semantics)"; | |
| case SPV_ENV_OPENCL_EMBEDDED_2_2: | |
| return "SPIR-V 1.2 (under OpenCL 2.2 Embedded Profile semantics)"; | |
| case SPV_ENV_OPENGL_4_0: | |
| return "SPIR-V 1.0 (under OpenGL 4.0 semantics)"; | |
| case SPV_ENV_OPENGL_4_1: | |
| return "SPIR-V 1.0 (under OpenGL 4.1 semantics)"; | |
| case SPV_ENV_OPENGL_4_2: | |
| return "SPIR-V 1.0 (under OpenGL 4.2 semantics)"; | |
| case SPV_ENV_OPENGL_4_3: | |
| return "SPIR-V 1.0 (under OpenGL 4.3 semantics)"; | |
| case SPV_ENV_OPENGL_4_5: | |
| return "SPIR-V 1.0 (under OpenGL 4.5 semantics)"; | |
| case SPV_ENV_UNIVERSAL_1_2: | |
| return "SPIR-V 1.2"; | |
| case SPV_ENV_UNIVERSAL_1_3: | |
| return "SPIR-V 1.3"; | |
| case SPV_ENV_VULKAN_1_1: | |
| return "SPIR-V 1.3 (under Vulkan 1.1 semantics)"; | |
| case SPV_ENV_WEBGPU_0: | |
| assert(false && "Deprecated target environment value."); | |
| break; | |
| case SPV_ENV_UNIVERSAL_1_4: | |
| return "SPIR-V 1.4"; | |
| case SPV_ENV_VULKAN_1_1_SPIRV_1_4: | |
| return "SPIR-V 1.4 (under Vulkan 1.1 semantics)"; | |
| case SPV_ENV_UNIVERSAL_1_5: | |
| return "SPIR-V 1.5"; | |
| case SPV_ENV_VULKAN_1_2: | |
| return "SPIR-V 1.5 (under Vulkan 1.2 semantics)"; | |
| case SPV_ENV_UNIVERSAL_1_6: | |
| return "SPIR-V 1.6"; | |
| case SPV_ENV_VULKAN_1_3: | |
| return "SPIR-V 1.6 (under Vulkan 1.3 semantics)"; | |
| case SPV_ENV_VULKAN_1_4: | |
| return "SPIR-V 1.6 (under Vulkan 1.4 semantics)"; | |
| case SPV_ENV_MAX: | |
| assert(false && "Invalid target environment value."); | |
| break; | |
| } | |
| return ""; | |
| } | |
| uint32_t spvVersionForTargetEnv(spv_target_env env) { | |
| switch (env) { | |
| case SPV_ENV_UNIVERSAL_1_0: | |
| case SPV_ENV_VULKAN_1_0: | |
| case SPV_ENV_OPENCL_1_2: | |
| case SPV_ENV_OPENCL_EMBEDDED_1_2: | |
| case SPV_ENV_OPENCL_2_0: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_0: | |
| case SPV_ENV_OPENCL_2_1: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_1: | |
| case SPV_ENV_OPENGL_4_0: | |
| case SPV_ENV_OPENGL_4_1: | |
| case SPV_ENV_OPENGL_4_2: | |
| case SPV_ENV_OPENGL_4_3: | |
| case SPV_ENV_OPENGL_4_5: | |
| return SPV_SPIRV_VERSION_WORD(1, 0); | |
| case SPV_ENV_UNIVERSAL_1_1: | |
| return SPV_SPIRV_VERSION_WORD(1, 1); | |
| case SPV_ENV_UNIVERSAL_1_2: | |
| case SPV_ENV_OPENCL_2_2: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_2: | |
| return SPV_SPIRV_VERSION_WORD(1, 2); | |
| case SPV_ENV_UNIVERSAL_1_3: | |
| case SPV_ENV_VULKAN_1_1: | |
| return SPV_SPIRV_VERSION_WORD(1, 3); | |
| case SPV_ENV_WEBGPU_0: | |
| assert(false && "Deprecated target environment value."); | |
| break; | |
| case SPV_ENV_UNIVERSAL_1_4: | |
| case SPV_ENV_VULKAN_1_1_SPIRV_1_4: | |
| return SPV_SPIRV_VERSION_WORD(1, 4); | |
| case SPV_ENV_UNIVERSAL_1_5: | |
| case SPV_ENV_VULKAN_1_2: | |
| return SPV_SPIRV_VERSION_WORD(1, 5); | |
| case SPV_ENV_UNIVERSAL_1_6: | |
| case SPV_ENV_VULKAN_1_3: | |
| case SPV_ENV_VULKAN_1_4: | |
| return SPV_SPIRV_VERSION_WORD(1, 6); | |
| case SPV_ENV_MAX: | |
| assert(false && "Invalid target environment value."); | |
| break; | |
| } | |
| return SPV_SPIRV_VERSION_WORD(0, 0); | |
| } | |
| // When a new SPIR-V version is released, update this table. | |
| static_assert(spv::Version == 0x10600); | |
| constexpr auto ordered_universal_envs = std::array<spv_target_env, 7>{ | |
| SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2, | |
| SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5, | |
| SPV_ENV_UNIVERSAL_1_6, | |
| }; | |
| // When a new SPIR-V version is released, update this table. | |
| // Users see this ordered list when running 'spirv-val --help'. Order | |
| // matters for readability. | |
| static_assert(spv::Version == 0x10600); | |
| inline constexpr std::pair<const char*, spv_target_env> spvTargetEnvNameMap[] = | |
| { | |
| // Do not reorder blindly. The algorithm to find the target looks for | |
| // the first entry where the key is a prefix of the string provided by | |
| // the user. For example, if the user provides `vulkan1.2spv1.5`, it | |
| // will match `vulkan1.2`. If this feature is to work correctly, the | |
| // keys must be ordered so that a string is before its prefix. For | |
| // example, `vulkan1.1spv1.4` must be before `vulkan1.1`. Otherwise, | |
| // `vulkan1.1` will be returned when looking for `vulkan1.1spv1.4`. | |
| {"vulkan1.0", SPV_ENV_VULKAN_1_0}, | |
| {"vulkan1.1spv1.4", SPV_ENV_VULKAN_1_1_SPIRV_1_4}, | |
| {"vulkan1.1", SPV_ENV_VULKAN_1_1}, | |
| {"vulkan1.2", SPV_ENV_VULKAN_1_2}, | |
| {"vulkan1.3", SPV_ENV_VULKAN_1_3}, | |
| {"vulkan1.4", SPV_ENV_VULKAN_1_4}, | |
| {"spv1.0", SPV_ENV_UNIVERSAL_1_0}, | |
| {"spv1.1", SPV_ENV_UNIVERSAL_1_1}, | |
| {"spv1.2", SPV_ENV_UNIVERSAL_1_2}, | |
| {"spv1.3", SPV_ENV_UNIVERSAL_1_3}, | |
| {"spv1.4", SPV_ENV_UNIVERSAL_1_4}, | |
| {"spv1.5", SPV_ENV_UNIVERSAL_1_5}, | |
| {"spv1.6", SPV_ENV_UNIVERSAL_1_6}, | |
| {"opencl1.2embedded", SPV_ENV_OPENCL_EMBEDDED_1_2}, | |
| {"opencl1.2", SPV_ENV_OPENCL_1_2}, | |
| {"opencl2.0embedded", SPV_ENV_OPENCL_EMBEDDED_2_0}, | |
| {"opencl2.0", SPV_ENV_OPENCL_2_0}, | |
| {"opencl2.1embedded", SPV_ENV_OPENCL_EMBEDDED_2_1}, | |
| {"opencl2.1", SPV_ENV_OPENCL_2_1}, | |
| {"opencl2.2embedded", SPV_ENV_OPENCL_EMBEDDED_2_2}, | |
| {"opencl2.2", SPV_ENV_OPENCL_2_2}, | |
| {"opengl4.0", SPV_ENV_OPENGL_4_0}, | |
| {"opengl4.1", SPV_ENV_OPENGL_4_1}, | |
| {"opengl4.2", SPV_ENV_OPENGL_4_2}, | |
| {"opengl4.3", SPV_ENV_OPENGL_4_3}, | |
| {"opengl4.5", SPV_ENV_OPENGL_4_5}, | |
| }; | |
| bool spvParseTargetEnv(const char* s, spv_target_env* env) { | |
| auto match = [s](const char* b) { | |
| return s && (0 == strncmp(s, b, strlen(b))); | |
| }; | |
| for (auto& name_env : spvTargetEnvNameMap) { | |
| if (match(name_env.first)) { | |
| if (env) { | |
| *env = name_env.second; | |
| } | |
| return true; | |
| } | |
| } | |
| if (env) *env = SPV_ENV_UNIVERSAL_1_0; | |
| return false; | |
| } | |
| bool spvReadEnvironmentFromText(const std::vector<char>& text, | |
| spv_target_env* env) { | |
| // Version is expected to match "; Version: 1.X" | |
| // Version string must occur in header, that is, initial lines of comments | |
| // Once a non-comment line occurs, the header has ended | |
| for (std::size_t i = 0; i < text.size(); ++i) { | |
| char c = text[i]; | |
| if (c == ';') { | |
| // Try to match against the expected version string | |
| constexpr const char* kVersionPrefix = "; Version: 1."; | |
| constexpr const auto kPrefixLength = 13; | |
| // 'minor_digit_pos' is the expected position of the version digit. | |
| const auto minor_digit_pos = i + kPrefixLength; | |
| if (minor_digit_pos >= text.size()) return false; | |
| // Match the prefix. | |
| auto j = 1; | |
| for (; j < kPrefixLength; ++j) { | |
| if (kVersionPrefix[j] != text[i + j]) break; | |
| } | |
| // j will match the prefix length if all characters before matched | |
| if (j == kPrefixLength) { | |
| // This expects only one digit in the minor number. | |
| static_assert(((spv::Version >> 8) & 0xff) < 10); | |
| char minor = text[minor_digit_pos]; | |
| char next_char = | |
| minor_digit_pos + 1 < text.size() ? text[minor_digit_pos + 1] : 0; | |
| if (std::isdigit(minor) && !std::isdigit(next_char)) { | |
| const auto index = minor - '0'; | |
| assert(index >= 0); | |
| if (static_cast<size_t>(index) < ordered_universal_envs.size()) { | |
| *env = ordered_universal_envs[index]; | |
| return true; | |
| } | |
| } | |
| } | |
| // If no match, determine whether the header has ended (in which case, | |
| // assumption has failed.) | |
| // Skip until the next line. | |
| i += j; | |
| for (; i < text.size(); ++i) { | |
| if (text[i] == '\n') break; | |
| } | |
| } else if (!std::isspace(c)) { | |
| // Allow blanks, but end the search if we find something else. | |
| break; | |
| } | |
| } | |
| 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)}, | |
| {SPV_ENV_VULKAN_1_3, VULKAN_VER(1, 3), SPIRV_VER(1, 6)}, | |
| {SPV_ENV_VULKAN_1_4, VULKAN_VER(1, 4), SPIRV_VER(1, 6)}}; | |
| 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: | |
| case SPV_ENV_OPENCL_1_2: | |
| case SPV_ENV_OPENCL_EMBEDDED_1_2: | |
| case SPV_ENV_OPENCL_2_0: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_0: | |
| case SPV_ENV_OPENCL_2_1: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_1: | |
| case SPV_ENV_OPENGL_4_0: | |
| case SPV_ENV_OPENGL_4_1: | |
| case SPV_ENV_OPENGL_4_2: | |
| case SPV_ENV_OPENGL_4_3: | |
| case SPV_ENV_OPENGL_4_5: | |
| case SPV_ENV_UNIVERSAL_1_1: | |
| case SPV_ENV_UNIVERSAL_1_2: | |
| case SPV_ENV_OPENCL_2_2: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_2: | |
| case SPV_ENV_UNIVERSAL_1_3: | |
| case SPV_ENV_UNIVERSAL_1_4: | |
| case SPV_ENV_UNIVERSAL_1_5: | |
| case SPV_ENV_UNIVERSAL_1_6: | |
| return false; | |
| case SPV_ENV_VULKAN_1_0: | |
| case SPV_ENV_VULKAN_1_1: | |
| case SPV_ENV_VULKAN_1_1_SPIRV_1_4: | |
| case SPV_ENV_VULKAN_1_2: | |
| case SPV_ENV_VULKAN_1_3: | |
| case SPV_ENV_VULKAN_1_4: | |
| return true; | |
| case SPV_ENV_WEBGPU_0: | |
| assert(false && "Deprecated target environment value."); | |
| break; | |
| case SPV_ENV_MAX: | |
| assert(false && "Invalid target environment value."); | |
| break; | |
| } | |
| return false; | |
| } | |
| bool spvIsOpenCLEnv(spv_target_env env) { | |
| switch (env) { | |
| case SPV_ENV_UNIVERSAL_1_0: | |
| case SPV_ENV_VULKAN_1_0: | |
| case SPV_ENV_UNIVERSAL_1_1: | |
| case SPV_ENV_OPENGL_4_0: | |
| case SPV_ENV_OPENGL_4_1: | |
| case SPV_ENV_OPENGL_4_2: | |
| case SPV_ENV_OPENGL_4_3: | |
| case SPV_ENV_OPENGL_4_5: | |
| case SPV_ENV_UNIVERSAL_1_2: | |
| case SPV_ENV_UNIVERSAL_1_3: | |
| case SPV_ENV_VULKAN_1_1: | |
| case SPV_ENV_UNIVERSAL_1_4: | |
| case SPV_ENV_VULKAN_1_1_SPIRV_1_4: | |
| case SPV_ENV_UNIVERSAL_1_5: | |
| case SPV_ENV_VULKAN_1_2: | |
| case SPV_ENV_UNIVERSAL_1_6: | |
| case SPV_ENV_VULKAN_1_3: | |
| case SPV_ENV_VULKAN_1_4: | |
| return false; | |
| case SPV_ENV_OPENCL_1_2: | |
| case SPV_ENV_OPENCL_EMBEDDED_1_2: | |
| case SPV_ENV_OPENCL_2_0: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_0: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_1: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_2: | |
| case SPV_ENV_OPENCL_2_1: | |
| case SPV_ENV_OPENCL_2_2: | |
| return true; | |
| case SPV_ENV_WEBGPU_0: | |
| assert(false && "Deprecated target environment value."); | |
| break; | |
| case SPV_ENV_MAX: | |
| assert(false && "Invalid target environment value."); | |
| break; | |
| } | |
| return false; | |
| } | |
| bool spvIsOpenGLEnv(spv_target_env env) { | |
| switch (env) { | |
| case SPV_ENV_UNIVERSAL_1_0: | |
| case SPV_ENV_VULKAN_1_0: | |
| case SPV_ENV_UNIVERSAL_1_1: | |
| case SPV_ENV_UNIVERSAL_1_2: | |
| case SPV_ENV_UNIVERSAL_1_3: | |
| case SPV_ENV_VULKAN_1_1: | |
| case SPV_ENV_OPENCL_1_2: | |
| case SPV_ENV_OPENCL_EMBEDDED_1_2: | |
| case SPV_ENV_OPENCL_2_0: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_0: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_1: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_2: | |
| case SPV_ENV_OPENCL_2_1: | |
| case SPV_ENV_OPENCL_2_2: | |
| case SPV_ENV_UNIVERSAL_1_4: | |
| case SPV_ENV_VULKAN_1_1_SPIRV_1_4: | |
| case SPV_ENV_UNIVERSAL_1_5: | |
| case SPV_ENV_VULKAN_1_2: | |
| case SPV_ENV_UNIVERSAL_1_6: | |
| case SPV_ENV_VULKAN_1_3: | |
| case SPV_ENV_VULKAN_1_4: | |
| return false; | |
| case SPV_ENV_OPENGL_4_0: | |
| case SPV_ENV_OPENGL_4_1: | |
| case SPV_ENV_OPENGL_4_2: | |
| case SPV_ENV_OPENGL_4_3: | |
| case SPV_ENV_OPENGL_4_5: | |
| return true; | |
| case SPV_ENV_WEBGPU_0: | |
| assert(false && "Deprecated target environment value."); | |
| break; | |
| case SPV_ENV_MAX: | |
| assert(false && "Invalid target environment value."); | |
| break; | |
| } | |
| return false; | |
| } | |
| bool spvIsValidEnv(spv_target_env env) { | |
| switch (env) { | |
| case SPV_ENV_UNIVERSAL_1_0: | |
| case SPV_ENV_VULKAN_1_0: | |
| case SPV_ENV_UNIVERSAL_1_1: | |
| case SPV_ENV_UNIVERSAL_1_2: | |
| case SPV_ENV_UNIVERSAL_1_3: | |
| case SPV_ENV_VULKAN_1_1: | |
| case SPV_ENV_OPENCL_1_2: | |
| case SPV_ENV_OPENCL_EMBEDDED_1_2: | |
| case SPV_ENV_OPENCL_2_0: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_0: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_1: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_2: | |
| case SPV_ENV_OPENCL_2_1: | |
| case SPV_ENV_OPENCL_2_2: | |
| case SPV_ENV_UNIVERSAL_1_4: | |
| case SPV_ENV_VULKAN_1_1_SPIRV_1_4: | |
| case SPV_ENV_UNIVERSAL_1_5: | |
| case SPV_ENV_VULKAN_1_2: | |
| case SPV_ENV_UNIVERSAL_1_6: | |
| case SPV_ENV_VULKAN_1_3: | |
| case SPV_ENV_VULKAN_1_4: | |
| case SPV_ENV_OPENGL_4_0: | |
| case SPV_ENV_OPENGL_4_1: | |
| case SPV_ENV_OPENGL_4_2: | |
| case SPV_ENV_OPENGL_4_3: | |
| case SPV_ENV_OPENGL_4_5: | |
| return true; | |
| case SPV_ENV_WEBGPU_0: | |
| case SPV_ENV_MAX: | |
| break; | |
| } | |
| return false; | |
| } | |
| std::string spvLogStringForEnv(spv_target_env env) { | |
| switch (env) { | |
| case SPV_ENV_OPENCL_1_2: | |
| case SPV_ENV_OPENCL_2_0: | |
| case SPV_ENV_OPENCL_2_1: | |
| case SPV_ENV_OPENCL_2_2: | |
| case SPV_ENV_OPENCL_EMBEDDED_1_2: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_0: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_1: | |
| case SPV_ENV_OPENCL_EMBEDDED_2_2: { | |
| return "OpenCL"; | |
| } | |
| case SPV_ENV_OPENGL_4_0: | |
| case SPV_ENV_OPENGL_4_1: | |
| case SPV_ENV_OPENGL_4_2: | |
| case SPV_ENV_OPENGL_4_3: | |
| case SPV_ENV_OPENGL_4_5: { | |
| return "OpenGL"; | |
| } | |
| case SPV_ENV_VULKAN_1_0: | |
| case SPV_ENV_VULKAN_1_1: | |
| case SPV_ENV_VULKAN_1_1_SPIRV_1_4: | |
| case SPV_ENV_VULKAN_1_2: | |
| case SPV_ENV_VULKAN_1_3: | |
| case SPV_ENV_VULKAN_1_4: { | |
| return "Vulkan"; | |
| } | |
| case SPV_ENV_UNIVERSAL_1_0: | |
| case SPV_ENV_UNIVERSAL_1_1: | |
| case SPV_ENV_UNIVERSAL_1_2: | |
| case SPV_ENV_UNIVERSAL_1_3: | |
| case SPV_ENV_UNIVERSAL_1_4: | |
| case SPV_ENV_UNIVERSAL_1_5: | |
| case SPV_ENV_UNIVERSAL_1_6: { | |
| return "Universal"; | |
| } | |
| case SPV_ENV_WEBGPU_0: | |
| assert(false && "Deprecated target environment value."); | |
| break; | |
| case SPV_ENV_MAX: | |
| assert(false && "Invalid target environment value."); | |
| break; | |
| } | |
| return "Unknown"; | |
| } | |
| std::string spvTargetEnvList(const int pad, const int wrap) { | |
| std::string ret; | |
| size_t max_line_len = wrap - pad; // The first line isn't padded | |
| std::string line; | |
| std::string sep = ""; | |
| for (auto& name_env : spvTargetEnvNameMap) { | |
| std::string word = sep + name_env.first; | |
| if (line.length() + word.length() > max_line_len) { | |
| // Adding one word wouldn't fit, commit the line in progress and | |
| // start a new one. | |
| ret += line + "\n"; | |
| line.assign(pad, ' '); | |
| // The first line is done. The max length now comprises the | |
| // padding. | |
| max_line_len = wrap; | |
| } | |
| line += word; | |
| sep = "|"; | |
| } | |
| ret += line; | |
| return ret; | |
| } |