diff --git a/test3/.gitignore b/test3/.gitignore new file mode 100644 index 0000000..b6eb3f1 --- /dev/null +++ b/test3/.gitignore @@ -0,0 +1,2 @@ +*.o +test3 \ No newline at end of file diff --git a/test3/Makefile b/test3/Makefile new file mode 100644 index 0000000..41b8b02 --- /dev/null +++ b/test3/Makefile @@ -0,0 +1,22 @@ +CC = gcc +LD = gcc +CFLAGS = -Wall -Wextra -pedantic -std=c11 -g -fPIC +# link kompute as a static library and the rest as dynamic +STATIC_LIBS = +DYNAMIC_LIBS = -lvulkan +LDFLAGS = -L/usr/local/lib \ + -Wl,-Bstatic ${STATIC_LIBS} \ + -Wl,-Bdynamic ${DYNAMIC_LIBS} \ + -Wl,--as-needed + +test3: main.o vk_result_to_str.o + $(LD) main.o vk_result_to_str.o -o test3 ${LDFLAGS} + +vk_result_to_str.o: vk_result_to_str.c + $(CC) ${CFLAGS} -c vk_result_to_str.c + +main.o: main.c + $(CC) ${CFLAGS} -c main.c + +clean: + rm -f test3 main.o vk_result_to_str.o diff --git a/test3/README b/test3/README new file mode 100644 index 0000000..b479d1d --- /dev/null +++ b/test3/README @@ -0,0 +1 @@ +Trying to implement test2 with just vulkan and in C \ No newline at end of file diff --git a/test3/main.c b/test3/main.c new file mode 100644 index 0000000..91b585c --- /dev/null +++ b/test3/main.c @@ -0,0 +1,328 @@ +#include +#include +#include +#include +#include +#include + +#include + +// check for half precision floating point support, for x86 this is equivalent to +// checking for SSE2 +#define SUPPORTS_NATIVE_FP16 (__x86_64__ == 1 && __SSE2__ == 1) +// print debug messages +#define DEBUG 1 +#define VERBOSE 0 + +// define half precision floating point +#if SUPPORTS_NATIVE_FP16 +// extension is needed due to -pedantic +__extension__ typedef _Float16 half; +#endif + +const char *vk_validation_layer[] = {"VK_LAYER_KHRONOS_validation"}; +const uint32_t vk_validation_layer_no = 1; + +// FIXME: including vulkan/vk_enum_string_helper.h does not compile +extern const char *vk_Result_to_str(VkResult input); + +// like printf but on stderr +int err(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = vfprintf(stderr, fmt, ap); + va_end(ap); + return ret; +} + +// print out all the instance extensions +// NOTE: these are different from device and shader extensions +int vk_enumerate_instance_extensions(void) +{ + uint32_t ex_no = 0; +#if VERBOSE > 0 + vkEnumerateInstanceExtensionProperties(NULL, &ex_no, NULL); + VkExtensionProperties *ex_arr = + malloc(sizeof(VkExtensionProperties) * ex_no); + if (ex_arr == NULL) { + err("ERROR: in %s: %s\n", __func__, strerror(errno)); + return -1; + } + vkEnumerateInstanceExtensionProperties(NULL, &ex_no, ex_arr); + printf("Available Properties: \n"); + for (uint32_t i = 0; i < ex_no; i++) { + printf("\t%s\n", ex_arr[i].extensionName); + } + free(ex_arr); +#endif + return ex_no; +} + +// on debug check for support of validation layers and activate one, a validation +// layer is useful to do more error checking at runtime like ckecking for invalid +// arguments, validation layers are available only if vulkan-sdk is installed +// (vulkan-devel on arch) +int vk_activate_validation_layer(VkInstanceCreateInfo *cinfo) +{ + uint32_t prop_no = 0; +#if DEBUG > 0 + vkEnumerateInstanceLayerProperties(&prop_no, NULL); + + VkLayerProperties *prop_arr = malloc(sizeof(VkLayerProperties) * prop_no); + if (prop_arr == NULL) { + err("ERROR: in %s: %s\n", __func__, strerror(errno)); + return -1; + } + vkEnumerateInstanceLayerProperties(&prop_no, prop_arr); + + for (uint32_t i = 0; i < prop_no; i++) { + if (strcmp(prop_arr[i].layerName, vk_validation_layer[0]) == 0) { + cinfo->enabledLayerCount = vk_validation_layer_no; + cinfo->ppEnabledLayerNames = vk_validation_layer; + free(prop_arr); + return 0; + } + } + free(prop_arr); + return 1; +#endif + return 0; +} + +VkInstance vk_init(void) +{ + // create a vulkan instance and fill it with the application data + VkResult res; + VkInstance vk_instance = VK_NULL_HANDLE; + + VkApplicationInfo vk_appinfo = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = NULL, + .pApplicationName = __FILE__, + .applicationVersion = VK_MAKE_VERSION(0, 1, 0), + .pEngineName = "no engine", + .engineVersion = VK_MAKE_VERSION(0, 0, 0), + .apiVersion = VK_API_VERSION_1_3, + }; + + vk_enumerate_instance_extensions(); + + // TODO: check for extension availability + // TODO: does the lifetime of VkInstanceCreateInfo has to be the same as the + // lifetime of VkInstance? + const char *vk_instance_extensions[] = { + VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, + }; + const uint32_t vk_instance_extensions_no = + (uint32_t)(sizeof(vk_instance_extensions) / sizeof(char *)); + + VkInstanceCreateInfo vk_instanceinfo = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &vk_appinfo, + .flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, + .enabledExtensionCount = vk_instance_extensions_no, + .ppEnabledExtensionNames = vk_instance_extensions, + .enabledLayerCount = 0, + }; + + int e = 0; + if ((e = vk_activate_validation_layer(&vk_instanceinfo))) { + err("Could not activate validation layers%s\n", + e > 0 ? ": No validation layers found" : ""); + } + + res = vkCreateInstance(&vk_instanceinfo, NULL, &vk_instance); + if (res != VK_SUCCESS) { + err("ERROR: Could not create vulkan instance %s", + vk_Result_to_str(res)); + return VK_NULL_HANDLE; + } else { +#if VERBOSE > 0 + printf("Created vulkan instance\n"); +#endif + } + return vk_instance; +} + +void vk_destroy(VkInstance vk_instance) +{ + // ... + vkDestroyInstance(vk_instance, NULL); +} + +VkPhysicalDevice vk_physical_device_get(VkInstance vk_instance) +{ + VkPhysicalDevice vk_phydev = VK_NULL_HANDLE; + + uint32_t vk_phydevs_no = 0; + VkPhysicalDevice *vk_phydevs; + vkEnumeratePhysicalDevices(vk_instance, &vk_phydevs_no, NULL); + + if (vk_phydevs_no == 0) { + return vk_phydev; + } + + vk_phydevs = malloc(sizeof(VkPhysicalDevice) * vk_phydevs_no); + if (vk_phydevs == NULL) { + err("ERROR: in %s: %s\n", __func__, strerror(errno)); + return NULL; + } + + vkEnumeratePhysicalDevices(vk_instance, &vk_phydevs_no, vk_phydevs); + + printf("Available Physical Devices: \n"); + for (uint32_t i = 0; i < vk_phydevs_no; i++) { + VkPhysicalDevice device = vk_phydevs[i]; + VkPhysicalDeviceProperties device_properties; + VkPhysicalDeviceFeatures device_features; + + vkGetPhysicalDeviceProperties(device, &device_properties); + vkGetPhysicalDeviceFeatures(device, &device_features); + + printf( + "\tDevice %d: %s, Discrete: %s\n", + i, + device_properties.deviceName, + device_properties.deviceType == + VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU + ? "true" + : "false" + ); + } + + // TODO: find the most suitable physical device, but for now every vulkan + // device has to be compatible with compute shaders + vk_phydev = vk_phydevs[0]; + + free(vk_phydevs); + return vk_phydev; +} + +void vk_physical_device_destroy(VkPhysicalDevice vk_phydev) +{ + if (vk_phydev != VK_NULL_HANDLE) { + // ... + } +} + +// return the index of the first queue family that supports compute on the device, +// returns a negative index on error +int vk_device_compute_queue_index(VkPhysicalDevice vk_phydev) +{ + uint32_t vk_qfamilies_no = 0; + VkQueueFamilyProperties *vk_qfamilies; + int supports = -1; + + vkGetPhysicalDeviceQueueFamilyProperties(vk_phydev, &vk_qfamilies_no, NULL); + + vk_qfamilies = malloc(sizeof(VkQueueFamilyProperties) * vk_qfamilies_no); + if (vk_qfamilies == NULL) { + err("ERROR: in %s: %s\n", __func__, strerror(errno)); + return -1; + } + + vkGetPhysicalDeviceQueueFamilyProperties( + vk_phydev, &vk_qfamilies_no, vk_qfamilies + ); + + for (uint32_t i = 0; i < vk_qfamilies_no; i++) { + if (vk_qfamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { + supports = i; + } + } + + free(vk_qfamilies); + return supports; +} + +VkDevice vk_logical_device_create(VkPhysicalDevice vk_phydev, int qfamily_idx) +{ + VkResult res; + VkDevice vk_logdev = VK_NULL_HANDLE; + float vk_queue_priority = 1.0f; + + // specify which command queues to use for the physical device + VkDeviceQueueCreateInfo vk_queueinfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .queueFamilyIndex = qfamily_idx, + .queueCount = 1, + .pQueuePriorities = &vk_queue_priority, + }; + + // specify which device features to use + // TODO: this + VkPhysicalDeviceFeatures vk_phydev_features = {0}; + + // actually create the logical device + // TODO: figure out what device extensions are + // FIXME: here validation layers are ignored but it is still better to define + // them for compatibility + VkDeviceCreateInfo vk_createinfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pQueueCreateInfos = &vk_queueinfo, + .queueCreateInfoCount = 1, + .pEnabledFeatures = &vk_phydev_features, + .ppEnabledExtensionNames = NULL, + .enabledExtensionCount = 0, + .ppEnabledLayerNames = NULL, + .enabledLayerCount = 0, + }; + + res = vkCreateDevice(vk_phydev, &vk_createinfo, NULL, &vk_logdev); + if (res != VK_SUCCESS) { + err("ERROR: Could not create vulkan logical device %s", + vk_Result_to_str(res)); + return VK_NULL_HANDLE; + } else { +#if VERBOSE > 0 + printf("Created vulkan logical device\n"); +#endif + } + + return vk_logdev; +} + +void vk_logical_device_destroy(VkDevice vk_logdev) +{ + vkDestroyDevice(vk_logdev, NULL); +} + +VkQueue vk_queue_get(VkDevice vk_logdev, int qfamily_idx) +{ + VkQueue vk_queue = VK_NULL_HANDLE; + vkGetDeviceQueue(vk_logdev, qfamily_idx, 0, &vk_queue); + return vk_queue; +} + +int main(void) +{ +#if VERBOSE > 0 + if (SUPPORTS_NATIVE_FP16) { + printf("Processor supports half precision floating point\n"); + } else { + printf("Processor doesn't support half precision floating point\n"); + return EXIT_FAILURE; + } +#endif + + VkInstance vk_instance = vk_init(); + if (vk_instance == VK_NULL_HANDLE) { + exit(EXIT_FAILURE); + } + VkPhysicalDevice vk_phydev = vk_physical_device_get(vk_instance); + int qfamily_idx = vk_device_compute_queue_index(vk_phydev); + if (qfamily_idx < 0) { + err("The device does not support compute queues\n"); + exit(EXIT_FAILURE); + } + VkDevice vk_logdev = vk_logical_device_create(vk_phydev, qfamily_idx); + + vk_logical_device_destroy(vk_logdev); + vk_physical_device_destroy(vk_phydev); + vk_destroy(vk_instance); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/test3/util/.gitignore b/test3/util/.gitignore new file mode 100644 index 0000000..c24d3d4 --- /dev/null +++ b/test3/util/.gitignore @@ -0,0 +1,3 @@ +__pycache__ +out +vk.xml \ No newline at end of file diff --git a/test3/util/Makefile b/test3/util/Makefile new file mode 100644 index 0000000..15d87ed --- /dev/null +++ b/test3/util/Makefile @@ -0,0 +1,6 @@ +out/vk_enum_to_str.c: vk.xml + python gen_enum_to_str.py --beta false --xml vk.xml --outdir out + +vk.xml: + wget -O vk.xml https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/main/xml/vk.xml + diff --git a/test3/util/gen_enum_to_str.py b/test3/util/gen_enum_to_str.py new file mode 100644 index 0000000..849364a --- /dev/null +++ b/test3/util/gen_enum_to_str.py @@ -0,0 +1,573 @@ +# Copyright © 2017 Intel Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Create enum to string functions for vulkan using vk.xml.""" + +import argparse +import functools +import os +import re +import textwrap +import xml.etree.ElementTree as et + +from mako.template import Template +from vk_extensions import Extension, filter_api, get_all_required + +COPYRIGHT = textwrap.dedent(u"""\ + * Copyright © 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE.""") + +C_TEMPLATE = Template(textwrap.dedent(u"""\ + /* Autogenerated file -- do not edit + * generated by ${file} + * + ${copyright} + */ + + #include + #include + #include + #include + #include "util/macros.h" + #include "vk_enum_to_str.h" + + % for enum in enums: + + % if enum.guard: +#ifdef ${enum.guard} + % endif + const char * + vk_${enum.name[2:]}_to_str(${enum.name} input) + { + switch((int64_t)input) { + % for v in sorted(enum.values.keys()): + case ${v}: + return "${enum.values[v]}"; + % endfor + case ${enum.max_enum_name}: return "${enum.max_enum_name}"; + default: + return "Unknown ${enum.name} value."; + } + } + + % if enum.guard: +#endif + % endif + %endfor + + % for enum in bitmasks: + + % if enum.guard: +#ifdef ${enum.guard} + % endif + const char * + vk_${enum.name[2:]}_to_str(${enum.name} input) + { + switch((int64_t)input) { + % for v in sorted(enum.values.keys()): + case ${v}: + return "${enum.values[v]}"; + % endfor + default: + return "Unknown ${enum.name} value."; + } + } + + % if enum.guard: +#endif + % endif + %endfor + + size_t vk_structure_type_size(const struct VkBaseInStructure *item) + { + switch((int)item->sType) { + % for struct in structs: + % if struct.extension is not None and struct.extension.define is not None: + #ifdef ${struct.extension.define} + case ${struct.stype}: return sizeof(${struct.name}); + #endif + % else: + case ${struct.stype}: return sizeof(${struct.name}); + % endif + %endfor + case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: return sizeof(VkLayerInstanceCreateInfo); + case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO: return sizeof(VkLayerDeviceCreateInfo); + default: + unreachable("Undefined struct type."); + } + } + + const char * + vk_ObjectType_to_ObjectName(VkObjectType type) + { + switch((int)type) { + % for object_type in sorted(object_types[0].enum_to_name.keys()): + case ${object_type}: + return "${object_types[0].enum_to_name[object_type]}"; + % endfor + default: + return "Unknown VkObjectType value."; + } + } + """)) + +H_TEMPLATE = Template(textwrap.dedent(u"""\ + /* Autogenerated file -- do not edit + * generated by ${file} + * + ${copyright} + */ + + #ifndef MESA_VK_ENUM_TO_STR_H + #define MESA_VK_ENUM_TO_STR_H + + #include + #include + + #ifdef __cplusplus + extern "C" { + #endif + + % for enum in enums: + % if enum.guard: +#ifdef ${enum.guard} + % endif + const char * vk_${enum.name[2:]}_to_str(${enum.name} input); + % if enum.guard: +#endif + % endif + % endfor + + % for enum in bitmasks: + % if enum.guard: +#ifdef ${enum.guard} + % endif + const char * vk_${enum.name[2:]}_to_str(${enum.name} input); + % if enum.guard: +#endif + % endif + % endfor + + size_t vk_structure_type_size(const struct VkBaseInStructure *item); + + const char * vk_ObjectType_to_ObjectName(VkObjectType type); + + #ifdef __cplusplus + } /* extern "C" */ + #endif + + #endif""")) + + +H_DEFINE_TEMPLATE = Template(textwrap.dedent(u"""\ + /* Autogenerated file -- do not edit + * generated by ${file} + * + ${copyright} + */ + + #ifndef MESA_VK_ENUM_DEFINES_H + #define MESA_VK_ENUM_DEFINES_H + + #include + #include + + #ifdef __cplusplus + extern "C" { + #endif + + % for ext in extensions: + #define _${ext.name}_number (${ext.number}) + % endfor + + % for enum in bitmasks: + % if enum.bitwidth > 32: + <% continue %> + % endif + % if enum.guard: +#ifdef ${enum.guard} + % endif + #define ${enum.all_bits_name()} ${hex(enum.all_bits_value())}u + % if enum.guard: +#endif + % endif + % endfor + + % for enum in bitmasks: + % if enum.bitwidth < 64: + <% continue %> + % endif + /* Redefine bitmask values of ${enum.name} */ + % if enum.guard: +#ifdef ${enum.guard} + % endif + % for n, v in enum.name_to_value.items(): + #define ${n} (${hex(v)}ULL) + % endfor + % if enum.guard: +#endif + % endif + % endfor + + static inline VkFormatFeatureFlags + vk_format_features2_to_features(VkFormatFeatureFlags2 features2) + { + return features2 & VK_ALL_FORMAT_FEATURE_FLAG_BITS; + } + + #ifdef __cplusplus + } /* extern "C" */ + #endif + + #endif""")) + + +class NamedFactory(object): + """Factory for creating enums.""" + + def __init__(self, type_): + self.registry = {} + self.type = type_ + + def __call__(self, name, **kwargs): + try: + return self.registry[name] + except KeyError: + n = self.registry[name] = self.type(name, **kwargs) + return n + + def get(self, name): + return self.registry.get(name) + + +class VkExtension(object): + """Simple struct-like class representing extensions""" + + def __init__(self, name, number=None, define=None): + self.name = name + self.number = number + self.define = define + + +def CamelCase_to_SHOUT_CASE(s): + return (s[:1] + re.sub(r'(? len(name): + self.values[value] = name + + # Now that the value has been fully added, resolve aliases, if any. + if name in self.name_to_alias_list: + for alias in self.name_to_alias_list[name]: + self.add_value(alias, value) + del self.name_to_alias_list[name] + + def add_value_from_xml(self, elem, extension=None): + self.extension = extension + if 'value' in elem.attrib: + self.add_value(elem.attrib['name'], + value=int(elem.attrib['value'], base=0)) + elif 'bitpos' in elem.attrib: + self.add_value(elem.attrib['name'], + value=(1 << int(elem.attrib['bitpos'], base=0))) + elif 'alias' in elem.attrib: + self.add_value(elem.attrib['name'], alias=elem.attrib['alias']) + else: + error = 'dir' in elem.attrib and elem.attrib['dir'] == '-' + if 'extnumber' in elem.attrib: + extnum = int(elem.attrib['extnumber']) + else: + extnum = extension.number + self.add_value(elem.attrib['name'], + extnum=extnum, + offset=int(elem.attrib['offset']), + error=error) + + def set_guard(self, g): + self.guard = g + + +class VkChainStruct(object): + """Simple struct-like class representing a single Vulkan struct identified with a VkStructureType""" + def __init__(self, name, stype): + self.name = name + self.stype = stype + self.extension = None + + +def struct_get_stype(xml_node): + for member in xml_node.findall('./member'): + name = member.findall('./name') + if len(name) > 0 and name[0].text == "sType": + return member.get('values') + return None + +class VkObjectType(object): + """Simple struct-like class representing a single Vulkan object type""" + def __init__(self, name): + self.name = name + self.enum_to_name = dict() + + +def parse_xml(enum_factory, ext_factory, struct_factory, bitmask_factory, + obj_type_factory, filename, beta): + """Parse the XML file. Accumulate results into the factories. + + This parser is a memory efficient iterative XML parser that returns a list + of VkEnum objects. + """ + + xml = et.parse(filename) + api = 'vulkan' + + required_types = get_all_required(xml, 'type', api, beta) + + for enum_type in xml.findall('./enums[@type="enum"]'): + if not filter_api(enum_type, api): + continue + + type_name = enum_type.attrib['name'] + if not type_name in required_types: + continue + + enum = enum_factory(type_name) + for value in enum_type.findall('./enum'): + if filter_api(value, api): + enum.add_value_from_xml(value) + + # For bitmask we only add the Enum selected for convenience. + for enum_type in xml.findall('./enums[@type="bitmask"]'): + if not filter_api(enum_type, api): + continue + + type_name = enum_type.attrib['name'] + if not type_name in required_types: + continue + + bitwidth = int(enum_type.attrib.get('bitwidth', 32)) + enum = bitmask_factory(type_name, bitwidth=bitwidth) + for value in enum_type.findall('./enum'): + if filter_api(value, api): + enum.add_value_from_xml(value) + + for feature in xml.findall('./feature'): + if not api in feature.attrib['api'].split(','): + continue + + for value in feature.findall('./require/enum[@extends]'): + extends = value.attrib['extends'] + enum = enum_factory.get(extends) + if enum is not None: + enum.add_value_from_xml(value) + enum = bitmask_factory.get(extends) + if enum is not None: + enum.add_value_from_xml(value) + + for struct_type in xml.findall('./types/type[@category="struct"]'): + if not filter_api(struct_type, api): + continue + + name = struct_type.attrib['name'] + if name not in required_types: + continue + + stype = struct_get_stype(struct_type) + if stype is not None: + struct_factory(name, stype=stype) + + platform_define = {} + for platform in xml.findall('./platforms/platform'): + name = platform.attrib['name'] + define = platform.attrib['protect'] + platform_define[name] = define + + for ext_elem in xml.findall('./extensions/extension'): + ext = Extension.from_xml(ext_elem) + if api not in ext.supported: + continue + + define = platform_define.get(ext.platform, None) + extension = ext_factory(ext.name, number=ext.number, define=define) + + for req_elem in ext_elem.findall('./require'): + if not filter_api(req_elem, api): + continue + + for value in req_elem.findall('./enum[@extends]'): + extends = value.attrib['extends'] + enum = enum_factory.get(extends) + if enum is not None: + enum.add_value_from_xml(value, extension) + enum = bitmask_factory.get(extends) + if enum is not None: + enum.add_value_from_xml(value, extension) + + for t in req_elem.findall('./type'): + struct = struct_factory.get(t.attrib['name']) + if struct is not None: + struct.extension = extension + + if define: + for value in ext_elem.findall('./require/type[@name]'): + enum = enum_factory.get(value.attrib['name']) + if enum is not None: + enum.set_guard(define) + enum = bitmask_factory.get(value.attrib['name']) + if enum is not None: + enum.set_guard(define) + + obj_type_enum = enum_factory.get("VkObjectType") + obj_types = obj_type_factory("VkObjectType") + for object_type in xml.findall('./types/type[@category="handle"]'): + for object_name in object_type.findall('./name'): + # Convert to int to avoid undefined enums + enum = object_type.attrib['objtypeenum'] + + # Annoyingly, object types are hard to filter by API so just + # look for whether or not we can find the enum name in the + # VkObjectType enum. + if enum not in obj_type_enum.name_to_value: + continue + + enum_val = obj_type_enum.name_to_value[enum] + obj_types.enum_to_name[enum_val] = object_name.text + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--beta', required=True, help='Enable beta extensions.') + parser.add_argument('--xml', required=True, + help='Vulkan API XML files', + action='append', + dest='xml_files') + parser.add_argument('--outdir', + help='Directory to put the generated files in', + required=True) + + args = parser.parse_args() + + enum_factory = NamedFactory(VkEnum) + ext_factory = NamedFactory(VkExtension) + struct_factory = NamedFactory(VkChainStruct) + obj_type_factory = NamedFactory(VkObjectType) + bitmask_factory = NamedFactory(VkEnum) + + for filename in args.xml_files: + parse_xml(enum_factory, ext_factory, struct_factory, bitmask_factory, + obj_type_factory, filename, args.beta) + enums = sorted(enum_factory.registry.values(), key=lambda e: e.name) + extensions = sorted(ext_factory.registry.values(), key=lambda e: e.name) + structs = sorted(struct_factory.registry.values(), key=lambda e: e.name) + bitmasks = sorted(bitmask_factory.registry.values(), key=lambda e: e.name) + object_types = sorted(obj_type_factory.registry.values(), key=lambda e: e.name) + + for template, file_ in [(C_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.c')), + (H_TEMPLATE, os.path.join(args.outdir, 'vk_enum_to_str.h')), + (H_DEFINE_TEMPLATE, os.path.join(args.outdir, 'vk_enum_defines.h'))]: + with open(file_, 'w', encoding='utf-8') as f: + f.write(template.render( + file=os.path.basename(__file__), + enums=enums, + extensions=extensions, + structs=structs, + bitmasks=bitmasks, + object_types=object_types, + copyright=COPYRIGHT)) + + +if __name__ == '__main__': + main() diff --git a/test3/util/test_sse.sh b/test3/util/test_sse.sh new file mode 100755 index 0000000..78b1ea9 --- /dev/null +++ b/test3/util/test_sse.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +gcc -msse3 -dM -E - < /dev/null | grep -E "SSE|AVX" | sort \ No newline at end of file diff --git a/test3/util/vk_extensions.py b/test3/util/vk_extensions.py new file mode 100644 index 0000000..5372eda --- /dev/null +++ b/test3/util/vk_extensions.py @@ -0,0 +1,356 @@ +import copy +import re +import xml.etree.ElementTree as et + +def get_api_list(s): + apis = [] + for a in s.split(','): + if a == 'disabled': + continue + assert a in ('vulkan', 'vulkansc') + apis.append(a) + return apis + +class Extension: + def __init__(self, name, number, ext_version): + self.name = name + self.type = None + self.number = number + self.platform = None + self.provisional = False + self.ext_version = int(ext_version) + self.supported = [] + + def from_xml(ext_elem): + name = ext_elem.attrib['name'] + number = int(ext_elem.attrib['number']) + supported = get_api_list(ext_elem.attrib['supported']) + if name == 'VK_ANDROID_native_buffer': + assert not supported + supported = ['vulkan'] + + if not supported: + return Extension(name, number, 0) + + version = None + for enum_elem in ext_elem.findall('.require/enum'): + if enum_elem.attrib['name'].endswith('_SPEC_VERSION'): + # Skip alias SPEC_VERSIONs + if 'value' in enum_elem.attrib: + assert version is None + version = int(enum_elem.attrib['value']) + + assert version is not None + ext = Extension(name, number, version) + ext.type = ext_elem.attrib['type'] + ext.platform = ext_elem.attrib.get('platform', None) + ext.provisional = ext_elem.attrib.get('provisional', False) + ext.supported = supported + + return ext + + def c_android_condition(self): + # if it's an EXT or vendor extension, it's allowed + if not self.name.startswith(ANDROID_EXTENSION_WHITELIST_PREFIXES): + return 'true' + + allowed_version = ALLOWED_ANDROID_VERSION.get(self.name, None) + if allowed_version is None: + return 'false' + + return 'ANDROID_API_LEVEL >= %d' % (allowed_version) + +class ApiVersion: + def __init__(self, version): + self.version = version + +class VkVersion: + def __init__(self, string): + split = string.split('.') + self.major = int(split[0]) + self.minor = int(split[1]) + if len(split) > 2: + assert len(split) == 3 + self.patch = int(split[2]) + else: + self.patch = None + + # Sanity check. The range bits are required by the definition of the + # VK_MAKE_VERSION macro + assert self.major < 1024 and self.minor < 1024 + assert self.patch is None or self.patch < 4096 + assert str(self) == string + + def __str__(self): + ver_list = [str(self.major), str(self.minor)] + if self.patch is not None: + ver_list.append(str(self.patch)) + return '.'.join(ver_list) + + def c_vk_version(self): + ver_list = [str(self.major), str(self.minor), str(self.patch or 0)] + return 'VK_MAKE_VERSION(' + ', '.join(ver_list) + ')' + + def __int_ver(self): + # This is just an expansion of VK_VERSION + return (self.major << 22) | (self.minor << 12) | (self.patch or 0) + + def __gt__(self, other): + # If only one of them has a patch version, "ignore" it by making + # other's patch version match self. + if (self.patch is None) != (other.patch is None): + other = copy.copy(other) + other.patch = self.patch + + return self.__int_ver() > other.__int_ver() + +# Sort the extension list the way we expect: KHR, then EXT, then vendors +# alphabetically. For digits, read them as a whole number sort that. +# eg.: VK_KHR_8bit_storage < VK_KHR_16bit_storage < VK_EXT_acquire_xlib_display +def extension_order(ext): + order = [] + for substring in re.split('(KHR|EXT|[0-9]+)', ext.name): + if substring == 'KHR': + order.append(1) + if substring == 'EXT': + order.append(2) + elif substring.isdigit(): + order.append(int(substring)) + else: + order.append(substring) + return order + +def get_all_exts_from_xml(xml, api='vulkan'): + """ Get a list of all Vulkan extensions. """ + + xml = et.parse(xml) + + extensions = [] + for ext_elem in xml.findall('.extensions/extension'): + ext = Extension.from_xml(ext_elem) + if api in ext.supported: + extensions.append(ext) + + return sorted(extensions, key=extension_order) + +def init_exts_from_xml(xml, extensions, platform_defines): + """ Walk the Vulkan XML and fill out extra extension information. """ + + xml = et.parse(xml) + + ext_name_map = {} + for ext in extensions: + ext_name_map[ext.name] = ext + + # KHR_display is missing from the list. + platform_defines.append('VK_USE_PLATFORM_DISPLAY_KHR') + for platform in xml.findall('./platforms/platform'): + platform_defines.append(platform.attrib['protect']) + + for ext_elem in xml.findall('.extensions/extension'): + ext_name = ext_elem.attrib['name'] + if ext_name not in ext_name_map: + continue + + ext = ext_name_map[ext_name] + ext.type = ext_elem.attrib['type'] + +class Requirements: + def __init__(self, core_version=None): + self.core_version = core_version + self.extensions = [] + self.guard = None + + def add_extension(self, ext): + for e in self.extensions: + if e == ext: + return; + assert e.name != ext.name + + self.extensions.append(ext) + +def filter_api(elem, api): + if 'api' not in elem.attrib: + return True + + return api in elem.attrib['api'].split(',') + +def get_all_required(xml, thing, api, beta): + things = {} + for feature in xml.findall('./feature'): + if not filter_api(feature, api): + continue + + version = VkVersion(feature.attrib['number']) + for t in feature.findall('./require/' + thing): + name = t.attrib['name'] + assert name not in things + things[name] = Requirements(core_version=version) + + for extension in xml.findall('.extensions/extension'): + ext = Extension.from_xml(extension) + if api not in ext.supported: + continue + + if beta != 'true' and ext.provisional: + continue + + for require in extension.findall('./require'): + if not filter_api(require, api): + continue + + for t in require.findall('./' + thing): + name = t.attrib['name'] + r = things.setdefault(name, Requirements()) + r.add_extension(ext) + + platform_defines = {} + for platform in xml.findall('./platforms/platform'): + name = platform.attrib['name'] + define = platform.attrib['protect'] + platform_defines[name] = define + + for req in things.values(): + if req.core_version is not None: + continue + + for ext in req.extensions: + if ext.platform in platform_defines: + req.guard = platform_defines[ext.platform] + break + + return things + +# Mapping between extension name and the android version in which the extension +# was whitelisted in Android CTS's dEQP-VK.info.device_extensions and +# dEQP-VK.api.info.android.no_unknown_extensions, excluding those blocked by +# android.graphics.cts.VulkanFeaturesTest#testVulkanBlockedExtensions. +ALLOWED_ANDROID_VERSION = { + # checkInstanceExtensions on oreo-cts-release + "VK_KHR_surface": 26, + "VK_KHR_display": 26, + "VK_KHR_android_surface": 26, + "VK_KHR_mir_surface": 26, + "VK_KHR_wayland_surface": 26, + "VK_KHR_win32_surface": 26, + "VK_KHR_xcb_surface": 26, + "VK_KHR_xlib_surface": 26, + "VK_KHR_get_physical_device_properties2": 26, + "VK_KHR_get_surface_capabilities2": 26, + "VK_KHR_external_memory_capabilities": 26, + "VK_KHR_external_semaphore_capabilities": 26, + "VK_KHR_external_fence_capabilities": 26, + # on pie-cts-release + "VK_KHR_device_group_creation": 28, + "VK_KHR_get_display_properties2": 28, + # on android10-tests-release + "VK_KHR_surface_protected_capabilities": 29, + # on android13-tests-release + "VK_KHR_portability_enumeration": 33, + + # checkDeviceExtensions on oreo-cts-release + "VK_KHR_swapchain": 26, + "VK_KHR_display_swapchain": 26, + "VK_KHR_sampler_mirror_clamp_to_edge": 26, + "VK_KHR_shader_draw_parameters": 26, + "VK_KHR_maintenance1": 26, + "VK_KHR_push_descriptor": 26, + "VK_KHR_descriptor_update_template": 26, + "VK_KHR_incremental_present": 26, + "VK_KHR_shared_presentable_image": 26, + "VK_KHR_storage_buffer_storage_class": 26, + "VK_KHR_16bit_storage": 26, + "VK_KHR_get_memory_requirements2": 26, + "VK_KHR_external_memory": 26, + "VK_KHR_external_memory_fd": 26, + "VK_KHR_external_memory_win32": 26, + "VK_KHR_external_semaphore": 26, + "VK_KHR_external_semaphore_fd": 26, + "VK_KHR_external_semaphore_win32": 26, + "VK_KHR_external_fence": 26, + "VK_KHR_external_fence_fd": 26, + "VK_KHR_external_fence_win32": 26, + "VK_KHR_win32_keyed_mutex": 26, + "VK_KHR_dedicated_allocation": 26, + "VK_KHR_variable_pointers": 26, + "VK_KHR_relaxed_block_layout": 26, + "VK_KHR_bind_memory2": 26, + "VK_KHR_maintenance2": 26, + "VK_KHR_image_format_list": 26, + "VK_KHR_sampler_ycbcr_conversion": 26, + # on oreo-mr1-cts-release + "VK_KHR_draw_indirect_count": 27, + # on pie-cts-release + "VK_KHR_device_group": 28, + "VK_KHR_multiview": 28, + "VK_KHR_maintenance3": 28, + "VK_KHR_create_renderpass2": 28, + "VK_KHR_driver_properties": 28, + # on android10-tests-release + "VK_KHR_shader_float_controls": 29, + "VK_KHR_shader_float16_int8": 29, + "VK_KHR_8bit_storage": 29, + "VK_KHR_depth_stencil_resolve": 29, + "VK_KHR_swapchain_mutable_format": 29, + "VK_KHR_shader_atomic_int64": 29, + "VK_KHR_vulkan_memory_model": 29, + "VK_KHR_swapchain_mutable_format": 29, + "VK_KHR_uniform_buffer_standard_layout": 29, + # on android11-tests-release + "VK_KHR_imageless_framebuffer": 30, + "VK_KHR_shader_subgroup_extended_types": 30, + "VK_KHR_buffer_device_address": 30, + "VK_KHR_separate_depth_stencil_layouts": 30, + "VK_KHR_timeline_semaphore": 30, + "VK_KHR_spirv_1_4": 30, + "VK_KHR_pipeline_executable_properties": 30, + "VK_KHR_shader_clock": 30, + # blocked by testVulkanBlockedExtensions + # "VK_KHR_performance_query": 30, + "VK_KHR_shader_non_semantic_info": 30, + "VK_KHR_copy_commands2": 30, + # on android12-tests-release + "VK_KHR_shader_terminate_invocation": 31, + "VK_KHR_ray_tracing_pipeline": 31, + "VK_KHR_ray_query": 31, + "VK_KHR_acceleration_structure": 31, + "VK_KHR_pipeline_library": 31, + "VK_KHR_deferred_host_operations": 31, + "VK_KHR_fragment_shading_rate": 31, + "VK_KHR_zero_initialize_workgroup_memory": 31, + "VK_KHR_workgroup_memory_explicit_layout": 31, + "VK_KHR_synchronization2": 31, + "VK_KHR_shader_integer_dot_product": 31, + # on android13-tests-release + "VK_KHR_dynamic_rendering": 33, + "VK_KHR_format_feature_flags2": 33, + "VK_KHR_global_priority": 33, + "VK_KHR_maintenance4": 33, + "VK_KHR_portability_subset": 33, + "VK_KHR_present_id": 33, + "VK_KHR_present_wait": 33, + "VK_KHR_shader_subgroup_uniform_control_flow": 33, + + # testNoUnknownExtensions on oreo-cts-release + "VK_GOOGLE_display_timing": 26, + # on pie-cts-release + "VK_ANDROID_external_memory_android_hardware_buffer": 28, + # on android11-tests-release + "VK_GOOGLE_decorate_string": 30, + "VK_GOOGLE_hlsl_functionality1": 30, + # on android13-tests-release + "VK_GOOGLE_surfaceless_query": 33, + + # this HAL extension is always allowed and will be filtered out by the + # loader + "VK_ANDROID_native_buffer": 26, +} + +# Extensions with these prefixes are checked in Android CTS, and thus must be +# whitelisted per the preceding dict. +ANDROID_EXTENSION_WHITELIST_PREFIXES = ( + "VK_KHX", + "VK_KHR", + "VK_GOOGLE", + "VK_ANDROID" +) diff --git a/test3/vk_result_to_str.c b/test3/vk_result_to_str.c new file mode 100644 index 0000000..54c319e --- /dev/null +++ b/test3/vk_result_to_str.c @@ -0,0 +1,108 @@ +#include + +#include + +// generated by util/gen_enum_to_str.py from the mesa project +const char *vk_Result_to_str(VkResult input) +{ + switch ((int64_t)input) { + case -1000338000: + return "VK_ERROR_COMPRESSION_EXHAUSTED_EXT"; + case -1000299000: + return "VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR"; + case -1000257000: + return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT"; + case -1000255000: + return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; + case -1000174001: + return "VK_ERROR_NOT_PERMITTED_KHR"; + case -1000161000: + return "VK_ERROR_FRAGMENTATION"; + case -1000158000: + return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; + case -1000072003: + return "VK_ERROR_INVALID_EXTERNAL_HANDLE"; + case -1000069000: + return "VK_ERROR_OUT_OF_POOL_MEMORY"; + case -1000023005: + return "VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR"; + case -1000023004: + return "VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR"; + case -1000023003: + return "VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR"; + case -1000023002: + return "VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR"; + case -1000023001: + return "VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR"; + case -1000023000: + return "VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR"; + case -1000012000: + return "VK_ERROR_INVALID_SHADER_NV"; + case -1000011001: + return "VK_ERROR_VALIDATION_FAILED_EXT"; + case -1000003001: + return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; + case -1000001004: + return "VK_ERROR_OUT_OF_DATE_KHR"; + case -1000000001: + return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case -1000000000: + return "VK_ERROR_SURFACE_LOST_KHR"; + case -13: + return "VK_ERROR_UNKNOWN"; + case -12: + return "VK_ERROR_FRAGMENTED_POOL"; + case -11: + return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case -10: + return "VK_ERROR_TOO_MANY_OBJECTS"; + case -9: + return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case -8: + return "VK_ERROR_FEATURE_NOT_PRESENT"; + case -7: + return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case -6: + return "VK_ERROR_LAYER_NOT_PRESENT"; + case -5: + return "VK_ERROR_MEMORY_MAP_FAILED"; + case -4: + return "VK_ERROR_DEVICE_LOST"; + case -3: + return "VK_ERROR_INITIALIZATION_FAILED"; + case -2: + return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case -1: + return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case 0: + return "VK_SUCCESS"; + case 1: + return "VK_NOT_READY"; + case 2: + return "VK_TIMEOUT"; + case 3: + return "VK_EVENT_SET"; + case 4: + return "VK_EVENT_RESET"; + case 5: + return "VK_INCOMPLETE"; + case 1000001003: + return "VK_SUBOPTIMAL_KHR"; + case 1000268000: + return "VK_THREAD_IDLE_KHR"; + case 1000268001: + return "VK_THREAD_DONE_KHR"; + case 1000268002: + return "VK_OPERATION_DEFERRED_KHR"; + case 1000268003: + return "VK_OPERATION_NOT_DEFERRED_KHR"; + case 1000297000: + return "VK_PIPELINE_COMPILE_REQUIRED"; + case 1000482000: + return "VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT"; + case VK_RESULT_MAX_ENUM: + return "VK_RESULT_MAX_ENUM"; + default: + return "Unknown VkResult value."; + } +} \ No newline at end of file