master
Alessandro Mauri 12 months ago
parent 68bea8a225
commit ee79b4c195
  1. 2
      test3/.gitignore
  2. 22
      test3/Makefile
  3. 1
      test3/README
  4. 328
      test3/main.c
  5. 3
      test3/util/.gitignore
  6. 6
      test3/util/Makefile
  7. 573
      test3/util/gen_enum_to_str.py
  8. 3
      test3/util/test_sse.sh
  9. 356
      test3/util/vk_extensions.py
  10. 108
      test3/vk_result_to_str.c

2
test3/.gitignore vendored

@ -0,0 +1,2 @@
*.o
test3

@ -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

@ -0,0 +1 @@
Trying to implement test2 with just vulkan and in C

@ -0,0 +1,328 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <vulkan/vulkan.h>
// 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;
}

@ -0,0 +1,3 @@
__pycache__
out
vk.xml

@ -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

@ -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 <string.h>
#include <vulkan/vulkan_core.h>
#include <vulkan/vk_android_native_buffer.h>
#include <vulkan/vk_layer.h>
#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 <vulkan/vulkan.h>
#include <vulkan/vk_android_native_buffer.h>
#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 <vulkan/vulkan_core.h>
#include <vulkan/vk_android_native_buffer.h>
#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'(?<![A-Z])([A-Z])', r'_\1', s[1:])).upper()
def compute_max_enum_name(s):
if s == "VkSwapchainImageUsageFlagBitsANDROID":
return "VK_SWAPCHAIN_IMAGE_USAGE_FLAG_BITS_MAX_ENUM"
max_enum_name = CamelCase_to_SHOUT_CASE(s)
last_prefix = max_enum_name.rsplit('_', 1)[-1]
# Those special prefixes need to be always at the end
if last_prefix in ['AMD', 'EXT', 'INTEL', 'KHR', 'NV', 'LUNARG', 'QCOM', 'MSFT'] :
max_enum_name = "_".join(max_enum_name.split('_')[:-1])
max_enum_name = max_enum_name + "_MAX_ENUM_" + last_prefix
else:
max_enum_name = max_enum_name + "_MAX_ENUM"
return max_enum_name
class VkEnum(object):
"""Simple struct-like class representing a single Vulkan Enum."""
def __init__(self, name, bitwidth=32, values=None):
self.name = name
self.max_enum_name = compute_max_enum_name(name)
self.bitwidth = bitwidth
self.extension = None
# Maps numbers to names
self.values = values or dict()
self.name_to_value = dict()
self.guard = None
self.name_to_alias_list = {}
def all_bits_name(self):
assert self.name.startswith('Vk')
assert re.search(r'FlagBits[A-Z]*$', self.name)
return 'VK_ALL_' + CamelCase_to_SHOUT_CASE(self.name[2:])
def all_bits_value(self):
return functools.reduce(lambda a,b: a | b, self.values.keys(), 0)
def add_value(self, name, value=None,
extnum=None, offset=None, alias=None,
error=False):
if alias is not None:
assert value is None and offset is None
if alias not in self.name_to_value:
# We don't have this alias yet. Just record the alias and
# we'll deal with it later.
alias_list = self.name_to_alias_list.setdefault(alias, [])
alias_list.append(name);
return
# Use the value from the alias
value = self.name_to_value[alias]
assert value is not None or extnum is not None
if value is None:
value = 1000000000 + (extnum - 1) * 1000 + offset
if error:
value = -value
self.name_to_value[name] = value
if value not in self.values:
self.values[value] = name
elif len(self.values[value]) > 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()

@ -0,0 +1,3 @@
#!/bin/sh
gcc -msse3 -dM -E - < /dev/null | grep -E "SSE|AVX" | sort

@ -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"
)

@ -0,0 +1,108 @@
#include <stdint.h>
#include <vulkan/vulkan.h>
// 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.";
}
}
Loading…
Cancel
Save