formats: vkuGetFormatInfo to use array

Puts the contents of a switch in a big array, then rewrites
vkuGetFormatInfo() to index into it based on the formats enum value.

This was done because the switch statement was large enough that
compilers wouldn't inline the function, leading to performance bubbles.

The logic for generating the logic of vkuGetFormatInfo is complex but
boils down to finding the groups of consecutive VkFormats, where the
end of a group has a value that is more than 1 away from the next format
value.

To follow C const initializer rules, VKU_FORMAT_COMPRESSED_COMPONENT
had to be turned into a macro.
This commit is contained in:
Charles Giessen 2025-03-05 12:15:59 -06:00 committed by Charles Giessen
parent 04e2efb904
commit 0d5b49b80f
2 changed files with 311 additions and 771 deletions

View file

@ -7,6 +7,7 @@
# SPDX-License-Identifier: Apache-2.0
import os
from collections import namedtuple
from vulkan_object import (Format)
from base_generator import BaseGenerator
@ -292,7 +293,7 @@ enum VKU_FORMAT_COMPONENT_TYPE {
};
// Compressed formats don't have a defined component size
const uint32_t VKU_FORMAT_COMPRESSED_COMPONENT = 0xFFFFFFFF;
#define VKU_FORMAT_COMPRESSED_COMPONENT 0xFFFFFFFF
struct VKU_FORMAT_COMPONENT_INFO {
enum VKU_FORMAT_COMPONENT_TYPE type;
@ -309,27 +310,57 @@ struct VKU_FORMAT_INFO {
struct VKU_FORMAT_COMPONENT_INFO components[VKU_FORMAT_MAX_COMPONENTS];
};
''')
out.append('inline const struct VKU_FORMAT_INFO vkuGetFormatInfo(VkFormat format) {\n')
out.append(' switch (format) {\n')
for f in self.vk.formats.values():
formats_in_order = {}
# Manually add in the entry for VK_FORMAT_UNDEFINED because it is missing from the self.vk.formats dict
formats_in_order[0] = Format('VK_FORMAT_UNDEFINED', 'NONE', 0,0, ['0','0','0'], None, None, None, [], [], None)
for e in self.vk.enums['VkFormat'].fields:
if e.name != 'VK_FORMAT_UNDEFINED':
formats_in_order[e.value] = self.vk.formats[e.name]
# Number of VkFormats should equal the fields of the VkFormat enum
assert(len(formats_in_order) == len(self.vk.enums['VkFormat'].fields))
formats_in_order = dict(sorted(formats_in_order.items()))
out.append(f'const struct VKU_FORMAT_INFO vku_formats[{len(self.vk.formats) + 1}] = {{\n')
for f in formats_in_order.values():
className = getClassName(f.className)
blockExtent = ', '.join(f.blockExtent) if f.blockExtent is not None else '1, 1, 1'
out.extend(f' case {f.name}: {{\n')
out.extend(f' struct VKU_FORMAT_INFO out = {{VKU_FORMAT_COMPATIBILITY_CLASS_{className}, {f.blockSize}, {f.texelsPerBlock}, {{{blockExtent}}}, {len(f.components)}, {{')
out.extend(f' {{ VKU_FORMAT_COMPATIBILITY_CLASS_{className}, {f.blockSize}, {f.texelsPerBlock}, {{{blockExtent}}}, {len(f.components)}, {{')
for index, component in enumerate(f.components):
bits = 'VKU_FORMAT_COMPRESSED_COMPONENT' if component.bits == 'compressed' else component.bits
out.append(f'{{VKU_FORMAT_COMPONENT_TYPE_{component.type}, {bits}}}')
if index + 1 != len(f.components):
out.append(', ')
out.append('}};\n')
out.append(' return out; }\n')
out.append('''
default: {
// return values for VK_FORMAT_UNDEFINED
struct VKU_FORMAT_INFO out = { VKU_FORMAT_COMPATIBILITY_CLASS_NONE, 0, 0, {0, 0, 0}, 0, {{VKU_FORMAT_COMPONENT_TYPE_NONE, 0}, {VKU_FORMAT_COMPONENT_TYPE_NONE, 0}, {VKU_FORMAT_COMPONENT_TYPE_NONE, 0}, {VKU_FORMAT_COMPONENT_TYPE_NONE, 0}} };
return out;
}
};
out.append('} },\n')
out.append('};\n')
# Find the "format groups", eg formats whose value are consecutive, as that is the way they are written into the 'formats' array.
# Value refers to the enum value. These are discontinuous.
# Index refers to the index of a format in the vku_formats array. These are from 0 to the len(formats_in_order).
format_values = list(formats_in_order.keys())
FormatGroup = namedtuple('FormatGroup', ['begin_format', 'end_format','array_index'])
format_groups = []
index = 0
while index < len(format_values):
start_value = format_values[index]
end_value = format_values[-1] # use last format as sentinel so the last group can get the right end value
previous_value = start_value - 1
# Find the end value for the current group
for format_value in format_values[index:]:
if previous_value + 1 != format_value:
end_value = previous_value
break
previous_value = format_value
format_groups.append(FormatGroup(formats_in_order[start_value].name, formats_in_order[end_value].name, index))
index += (end_value - start_value) + 1
out.append('inline const struct VKU_FORMAT_INFO vkuGetFormatInfo(VkFormat format) {\n')
for group in format_groups:
out.append(f' {"else " if group.array_index != 0 else ""}if ({group.begin_format} <= format && format <= {group.end_format} )')
out.append(f' {{ return vku_formats[format - {group.begin_format} + {group.array_index}]; }}\n')
out.append(''' // Default case - return VK_FORMAT_UNDEFINED
else {
return vku_formats[0];
}
}
struct VKU_FORMAT_PER_PLANE_COMPATIBILITY {