From d4f91cf4e25012aa868b4d8f009b299aea78b522 Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Fri, 10 Nov 2023 11:29:52 -0700 Subject: vulkaninfo: Autogenerate Format list The rewrite of vulkaninfo to use autogen did not include generating all possible VkFormats. This commit fixes that by generating the lists of formats and their corresponding extension/feature version requirements needed to correctly query their support. Use of std::set is explicit here since we want the output order to be consistent. std::set will use the enum values to sort it, giving a nice orderly output. Before, std::vector maintained the order in a similar fashion, but since it didn't de-duplicate, it could potentially print the same format many times. --- scripts/vulkaninfo_generator.py | 84 ++++++++++++++++++++++++++++++++++--- vulkaninfo/generated/vulkaninfo.hpp | 14 +++++++ vulkaninfo/vulkaninfo.cpp | 51 +++++++++++++++------- vulkaninfo/vulkaninfo.h | 58 +++++-------------------- 4 files changed, 138 insertions(+), 69 deletions(-) diff --git a/scripts/vulkaninfo_generator.py b/scripts/vulkaninfo_generator.py index 2062115d..71a2aed2 100644 --- a/scripts/vulkaninfo_generator.py +++ b/scripts/vulkaninfo_generator.py @@ -225,6 +225,7 @@ class VulkanInfoGenerator(OutputGenerator): self.enums = [] self.flags = [] self.bitmasks = [] + self.format_ranges = [] self.all_structures = [] self.aliases = OrderedDict() @@ -260,6 +261,8 @@ class VulkanInfoGenerator(OutputGenerator): self.vulkan_versions.append(VulkanVersion(ver)) def endFile(self): + self.findFormatRanges() + # gather the types that are needed to generate types_to_gen = set() for s in enums_to_gen: @@ -340,6 +343,13 @@ class VulkanInfoGenerator(OutputGenerator): for s in (x for x in self.all_structures if x.name in struct_short_versions_to_gen): out += PrintStructShort(s) + out += 'auto format_ranges = std::array{\n' + for f in self.format_ranges: + out += f' FormatRange{{{f.minimum_instance_version}, {f.extension_name if f.extension_name is not None else "nullptr"}, ' + out += f'static_cast({f.first_format}), static_cast({f.last_format})}},\n' + out += '};\n' + + gen.write(out, file=self.outFile) gen.OutputGenerator.endFile(self) @@ -395,6 +405,62 @@ class VulkanInfoGenerator(OutputGenerator): if value.get('exclude') is None or name not in value.get('exclude'): self.extension_sets[key].add(name) + # finds all the ranges of formats from core (1.0), core versions (1.1+), and extensions + def findFormatRanges(self): + for enums in self.registry.reg.findall('enums'): + if enums.get('name') == 'VkFormat': + min_val = 2**32 + max_val = 0 + for enum in enums.findall('enum'): + if enum.get('value') is None: + continue + value = int(enum.get('value')) + min_val = min(min_val, value) + max_val = max(max_val, value) + if min_val < 2**32 and max_val > 0: + self.format_ranges.append(VulkanFormatRange(0,None, min_val, max_val)) + + for feature in self.registry.reg.findall('feature'): + for require in feature.findall('require'): + comment = require.get('comment') + original_ext = None + if comment is not None and comment.find('Promoted from') >= 0: + # may need tweaking in the future - some ext names aren't just the upper case version + original_ext = comment.split(' ')[2].upper() + '_EXTENSION_NAME' + min_val = 2**32 + max_val = 0 + for enum in require.findall('enum'): + if enum.get('extends') == 'VkFormat': + value = CalcEnumValue(int(enum.get('extnumber')), int(enum.get('offset'))) + min_val = min(min_val, value) + max_val = max(max_val, value) + if min_val < 2**32 and max_val > 0: + self.format_ranges.append(VulkanFormatRange(feature.get('number').split('.')[1],None, min_val, max_val)) + # If the formats came from an extension, add a format range for that extension so it'll be printed if the ext is supported but not the core version + if original_ext is not None: + self.format_ranges.append(VulkanFormatRange(0,original_ext, min_val, max_val)) + + for extension in self.registry.reg.find('extensions').findall('extension'): + if extension.get('supported') in ['disabled', 'vulkansc']: + continue + + min_val = 2**32 + max_val = 0 + enum_name_string = '' + for require in extension.findall('require'): + for enum in require.findall('enum'): + if enum.get('value') is not None and enum.get('value').find(extension.get('name')): + enum_name_string = enum.get('name') + if enum.get('extends') == 'VkFormat': + if enum.get('offset') is None: + continue + value = CalcEnumValue(int(extension.get('number')), int(enum.get('offset'))) + min_val = min(min_val, value) + max_val = max(max_val, value) + if min_val < 2**32 and max_val > 0: + self.format_ranges.append(VulkanFormatRange(0, enum_name_string, min_val, max_val)) + + def GatherTypesToGen(structure_list, structures, exclude = []): if exclude == None: @@ -438,6 +504,10 @@ def AddGuardFooter(obj): else: return "" +def CalcEnumValue(num, offset): + base = 1000000000 + block_size = 1000 + return base + (num - 1) * block_size + offset def PrintEnumToString(enum, gen): out = '' @@ -871,12 +941,7 @@ class VulkanEnum: continue if childExtends is not None and childExtNum is not None and childOffset is not None: - enumNegative = False - extNum = int(childExtNum) - extOffset = int(childOffset) - extBase = 1000000000 - extBlockSize = 1000 - childValue = extBase + (extNum - 1) * extBlockSize + extOffset + childValue = CalcEnumValue(int(childExtNum), int(childOffset)) if ('dir' in child.keys()): childValue = -childValue duplicate = False @@ -1079,3 +1144,10 @@ class VulkanVersion: for enum in req.findall('enum'): self.names.add(enum.get('name')) self.names = sorted(self.names) + +class VulkanFormatRange: + def __init__(self, min_inst_version, ext_name, first, last): + self.minimum_instance_version = min_inst_version + self.extension_name = ext_name + self.first_format = first + self.last_format = last diff --git a/vulkaninfo/generated/vulkaninfo.hpp b/vulkaninfo/generated/vulkaninfo.hpp index e32a57cb..cb2ec147 100644 --- a/vulkaninfo/generated/vulkaninfo.hpp +++ b/vulkaninfo/generated/vulkaninfo.hpp @@ -5212,4 +5212,18 @@ bool operator==(const VkSurfaceFormatKHR & a, const VkSurfaceFormatKHR b) { std::ostream &operator<<(std::ostream &o, VkExtent3D &obj) { return o << "(" << obj.width << ',' << obj.height << ',' << obj.depth << ")"; } +auto format_ranges = std::array{ + FormatRange{0, nullptr, static_cast(0), static_cast(184)}, + FormatRange{1, nullptr, static_cast(1000156000), static_cast(1000156033)}, + FormatRange{0, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, static_cast(1000156000), static_cast(1000156033)}, + FormatRange{3, nullptr, static_cast(1000330000), static_cast(1000330003)}, + FormatRange{0, VK_EXT_YCBCR_2PLANE_444_FORMATS_EXTENSION_NAME, static_cast(1000330000), static_cast(1000330003)}, + FormatRange{3, nullptr, static_cast(1000340000), static_cast(1000340001)}, + FormatRange{0, VK_EXT_4444_FORMATS_EXTENSION_NAME, static_cast(1000340000), static_cast(1000340001)}, + FormatRange{3, nullptr, static_cast(1000066000), static_cast(1000066013)}, + FormatRange{0, VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME, static_cast(1000066000), static_cast(1000066013)}, + FormatRange{0, VK_IMG_FORMAT_PVRTC_EXTENSION_NAME, static_cast(1000054000), static_cast(1000054007)}, + FormatRange{0, VK_NV_OPTICAL_FLOW_EXTENSION_NAME, static_cast(1000464000), static_cast(1000464000)}, + FormatRange{0, VK_KHR_MAINTENANCE_5_EXTENSION_NAME, static_cast(1000470000), static_cast(1000470001)}, +}; diff --git a/vulkaninfo/vulkaninfo.cpp b/vulkaninfo/vulkaninfo.cpp index daa7c9dd..4ebe3514 100644 --- a/vulkaninfo/vulkaninfo.cpp +++ b/vulkaninfo/vulkaninfo.cpp @@ -32,6 +32,20 @@ #endif #include "vulkaninfo.hpp" +// Used to sort the formats into buckets by their properties. +std::unordered_map> FormatPropMap(AppGpu &gpu) { + std::unordered_map> map; + for (const auto fmtRange : format_ranges) { + if (gpu.FormatRangeSupported(fmtRange)) { + for (int32_t fmt = fmtRange.first_format; fmt <= fmtRange.last_format; ++fmt) { + PropFlags pf = get_format_properties(gpu, static_cast(fmt)); + map[pf].insert(static_cast(fmt)); + } + } + } + return map; +} + // =========== Dump Functions ========= // void DumpExtensions(Printer &p, std::string section_name, std::vector extensions, bool do_indent = false) { @@ -533,7 +547,7 @@ void GpuDumpFeatures(Printer &p, AppGpu &gpu) { } } -void GpuDumpTextFormatProperty(Printer &p, const AppGpu &gpu, PropFlags formats, std::vector format_list, +void GpuDumpTextFormatProperty(Printer &p, const AppGpu &gpu, PropFlags formats, const std::set &format_list, uint32_t counter) { p.SetElementIndex(counter); ObjectWrapper obj_common_group(p, "Common Format Group"); @@ -576,9 +590,8 @@ void GpuDevDump(Printer &p, AppGpu &gpu) { if (p.Type() == OutputType::text) { auto fmtPropMap = FormatPropMap(gpu); - int counter = 0; - std::vector unsupported_formats; + std::set unsupported_formats; for (auto &prop : fmtPropMap) { VkFormatProperties props = prop.first.props; VkFormatProperties3 props3 = prop.first.props3; @@ -595,20 +608,23 @@ void GpuDevDump(Printer &p, AppGpu &gpu) { p.SetAsType().PrintString(VkFormatString(fmt)); } } else { - for (auto &format : gpu.supported_format_ranges) { - if (gpu.FormatRangeSupported(format)) { - for (int32_t fmt_counter = format.first_format; fmt_counter <= format.last_format; ++fmt_counter) { - VkFormat fmt = static_cast(fmt_counter); - auto formats = get_format_properties(gpu, fmt); - p.SetTitleAsType(); - if (gpu.CheckPhysicalDeviceExtensionIncluded(VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME)) { - DumpVkFormatProperties3(p, VkFormatString(fmt), formats.props3); - } else { - DumpVkFormatProperties(p, VkFormatString(fmt), formats.props); - } + std::set formats_to_print; + for (auto &format_range : format_ranges) { + if (gpu.FormatRangeSupported(format_range)) { + for (int32_t fmt_counter = format_range.first_format; fmt_counter <= format_range.last_format; ++fmt_counter) { + formats_to_print.insert(static_cast(fmt_counter)); } } } + for (const auto &fmt : formats_to_print) { + auto formats = get_format_properties(gpu, fmt); + p.SetTitleAsType(); + if (gpu.CheckPhysicalDeviceExtensionIncluded(VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME)) { + DumpVkFormatProperties3(p, VkFormatString(fmt), formats.props3); + } else { + DumpVkFormatProperties(p, VkFormatString(fmt), formats.props); + } + } } p.AddNewline(); @@ -680,10 +696,14 @@ void DumpGpuProfileCapabilities(Printer &p, AppGpu &gpu) { } { ObjectWrapper obj(p, "formats"); - for (auto &format : gpu.supported_format_ranges) { + std::set already_printed_formats; + for (const auto &format : format_ranges) { if (gpu.FormatRangeSupported(format)) { for (int32_t fmt_counter = format.first_format; fmt_counter <= format.last_format; ++fmt_counter) { VkFormat fmt = static_cast(fmt_counter); + if (already_printed_formats.count(fmt) > 0) { + continue; + } auto formats = get_format_properties(gpu, fmt); // don't print format properties that are unsupported @@ -704,6 +724,7 @@ void DumpGpuProfileCapabilities(Printer &p, AppGpu &gpu) { gpu.inst.ext_funcs.vkGetPhysicalDeviceFormatProperties2KHR(gpu.phys_device, fmt, &format_props2); chain_iterator_format_properties2(p, gpu, format_props2.pNext); } + already_printed_formats.insert(fmt); } } } diff --git a/vulkaninfo/vulkaninfo.h b/vulkaninfo/vulkaninfo.h index 1390863b..13d3b1e9 100644 --- a/vulkaninfo/vulkaninfo.h +++ b/vulkaninfo/vulkaninfo.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -1673,8 +1674,6 @@ struct AppGpu { std::array heapBudget; std::array heapUsage; - std::vector supported_format_ranges; - std::unique_ptr chain_for_phys_device_props2; std::unique_ptr chain_for_phys_device_mem_props2; std::unique_ptr chain_for_phys_device_features2; @@ -1873,36 +1872,6 @@ struct AppGpu { } } // TODO buffer - memory type compatibility - - supported_format_ranges = { - { - // Standard formats in Vulkan 1.0 - VK_MAKE_VERSION(1, 0, 0), NULL, - static_cast(0), // first core VkFormat - static_cast(184) // last core VkFormat - }, - { - // YCBCR extension, standard in Vulkan 1.1 - VK_MAKE_VERSION(1, 1, 0), - VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, - VK_FORMAT_G8B8G8R8_422_UNORM, - VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, - }, - { - // PVRTC extension, not standardized - 0, - VK_IMG_FORMAT_PVRTC_EXTENSION_NAME, - VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, - VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, - }, - { - // ASTC extension, not standardized - 0, - VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME, - VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT, - VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT, - }, - }; } ~AppGpu() { inst.dll.fp_vkDestroyDevice(dev, nullptr); } @@ -1916,10 +1885,9 @@ struct AppGpu { } // Helper function to determine whether a format range is currently supported. - bool FormatRangeSupported(FormatRange &format_range) const { - // True if standard and supported by both this instance and this GPU - if (format_range.minimum_instance_version > 0 && inst.instance_version >= format_range.minimum_instance_version && - props.apiVersion >= format_range.minimum_instance_version) { + bool FormatRangeSupported(const FormatRange &format_range) const { + // Formats from base vulkan spec + if (format_range.minimum_instance_version == 0 && format_range.extension_name == nullptr) { return true; } @@ -1928,6 +1896,12 @@ struct AppGpu { return inst.CheckExtensionEnabled(format_range.extension_name); } + // True if standard and supported by both this instance and this GPU + if (inst.instance_version >= VK_MAKE_API_VERSION(0, 1, format_range.minimum_instance_version, 0) && + props.apiVersion >= VK_MAKE_API_VERSION(0, 1, format_range.minimum_instance_version, 0)) { + return true; + } + // Otherwise, not supported. return false; } @@ -2025,15 +1999,3 @@ struct hash { } }; } // namespace std - -// Used to sort the formats into buckets by their properties. -std::unordered_map> FormatPropMap(AppGpu &gpu) { - std::unordered_map> map; - for (auto fmtRange : gpu.supported_format_ranges) { - for (int32_t fmt = fmtRange.first_format; fmt <= fmtRange.last_format; ++fmt) { - PropFlags pf = get_format_properties(gpu, static_cast(fmt)); - map[pf].push_back(static_cast(fmt)); - } - } - return map; -} -- cgit v1.2.3