This ports radv to using the anv entrypoint/extension generator code. No differences on enabled extensions list in vulkaninfo. Acked-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl> Signed-off-by: Dave Airlie <airlied@redhat.com>tags/17.3-branchpoint
@@ -1,6 +1,7 @@ | |||
# Generated source files | |||
/radv_entrypoints.c | |||
/radv_entrypoints.h | |||
/radv_extensions.c | |||
/radv_timestamp.h | |||
/dev_icd.json | |||
/vk_format_table.c |
@@ -107,12 +107,19 @@ libvulkan_radeon_la_SOURCES = $(VULKAN_GEM_FILES) | |||
vulkan_api_xml = $(top_srcdir)/src/vulkan/registry/vk.xml | |||
radv_entrypoints.c: radv_entrypoints_gen.py $(vulkan_api_xml) | |||
radv_entrypoints.c: radv_entrypoints_gen.py radv_extensions.py $(vulkan_api_xml) | |||
$(MKDIR_GEN) | |||
$(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_entrypoints_gen.py \ | |||
--xml $(vulkan_api_xml) --outdir $(builddir) | |||
radv_entrypoints.h: radv_entrypoints.c | |||
radv_extensions.c: radv_extensions.py \ | |||
$(vulkan_api_xml) | |||
$(MKDIR_GEN) | |||
$(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_extensions.py \ | |||
--xml $(vulkan_api_xml) \ | |||
--out $@ | |||
vk_format_table.c: vk_format_table.py \ | |||
vk_format_parse.py \ | |||
vk_format_layout.csv |
@@ -77,5 +77,6 @@ VULKAN_WSI_X11_FILES := \ | |||
VULKAN_GENERATED_FILES := \ | |||
radv_entrypoints.c \ | |||
radv_entrypoints.h | |||
radv_entrypoints.h \ | |||
radv_extensions.c | |||
@@ -76,198 +76,6 @@ radv_get_device_uuid(struct radeon_info *info, void *uuid) | |||
ac_compute_device_uuid(info, uuid, VK_UUID_SIZE); | |||
} | |||
static const VkExtensionProperties instance_extensions[] = { | |||
{ | |||
.extensionName = VK_KHR_SURFACE_EXTENSION_NAME, | |||
.specVersion = 25, | |||
}, | |||
#ifdef VK_USE_PLATFORM_XCB_KHR | |||
{ | |||
.extensionName = VK_KHR_XCB_SURFACE_EXTENSION_NAME, | |||
.specVersion = 6, | |||
}, | |||
#endif | |||
#ifdef VK_USE_PLATFORM_XLIB_KHR | |||
{ | |||
.extensionName = VK_KHR_XLIB_SURFACE_EXTENSION_NAME, | |||
.specVersion = 6, | |||
}, | |||
#endif | |||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR | |||
{ | |||
.extensionName = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, | |||
.specVersion = 6, | |||
}, | |||
#endif | |||
{ | |||
.extensionName = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
}; | |||
static const VkExtensionProperties common_device_extensions[] = { | |||
{ | |||
.extensionName = VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_MAINTENANCE1_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_SWAPCHAIN_EXTENSION_NAME, | |||
.specVersion = 68, | |||
}, | |||
{ | |||
.extensionName = VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_MAINTENANCE2_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHX_MULTIVIEW_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
}; | |||
static const VkExtensionProperties rasterization_order_extension[] ={ | |||
{ | |||
.extensionName = VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
}; | |||
static const VkExtensionProperties ext_sema_device_extensions[] = { | |||
{ | |||
.extensionName = VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
{ | |||
.extensionName = VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, | |||
.specVersion = 1, | |||
}, | |||
}; | |||
static VkResult | |||
radv_extensions_register(struct radv_instance *instance, | |||
struct radv_extensions *extensions, | |||
const VkExtensionProperties *new_ext, | |||
uint32_t num_ext) | |||
{ | |||
size_t new_size; | |||
VkExtensionProperties *new_ptr; | |||
assert(new_ext && num_ext > 0); | |||
if (!new_ext) | |||
return VK_ERROR_INITIALIZATION_FAILED; | |||
new_size = (extensions->num_ext + num_ext) * sizeof(VkExtensionProperties); | |||
new_ptr = vk_realloc(&instance->alloc, extensions->ext_array, | |||
new_size, 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); | |||
/* Old array continues to be valid, update nothing */ | |||
if (!new_ptr) | |||
return VK_ERROR_OUT_OF_HOST_MEMORY; | |||
memcpy(&new_ptr[extensions->num_ext], new_ext, | |||
num_ext * sizeof(VkExtensionProperties)); | |||
extensions->ext_array = new_ptr; | |||
extensions->num_ext += num_ext; | |||
return VK_SUCCESS; | |||
} | |||
static void | |||
radv_extensions_finish(struct radv_instance *instance, | |||
struct radv_extensions *extensions) | |||
{ | |||
assert(extensions); | |||
if (!extensions) | |||
radv_loge("Attemted to free invalid extension struct\n"); | |||
if (extensions->ext_array) | |||
vk_free(&instance->alloc, extensions->ext_array); | |||
} | |||
static bool | |||
is_extension_enabled(const VkExtensionProperties *extensions, | |||
size_t num_ext, | |||
const char *name) | |||
{ | |||
assert(extensions && name); | |||
for (uint32_t i = 0; i < num_ext; i++) { | |||
if (strcmp(name, extensions[i].extensionName) == 0) | |||
return true; | |||
} | |||
return false; | |||
} | |||
static const char * | |||
get_chip_name(enum radeon_family family) | |||
{ | |||
@@ -364,31 +172,6 @@ radv_physical_device_init(struct radv_physical_device *device, | |||
disk_cache_format_hex_id(buf, device->cache_uuid, VK_UUID_SIZE); | |||
device->disk_cache = disk_cache_create("radv", buf, shader_env_flags); | |||
result = radv_extensions_register(instance, | |||
&device->extensions, | |||
common_device_extensions, | |||
ARRAY_SIZE(common_device_extensions)); | |||
if (result != VK_SUCCESS) | |||
goto fail; | |||
if (device->rad_info.chip_class >= VI && device->rad_info.max_se >= 2) { | |||
result = radv_extensions_register(instance, | |||
&device->extensions, | |||
rasterization_order_extension, | |||
ARRAY_SIZE(rasterization_order_extension)); | |||
if (result != VK_SUCCESS) | |||
goto fail; | |||
} | |||
if (device->rad_info.has_syncobj) { | |||
result = radv_extensions_register(instance, | |||
&device->extensions, | |||
ext_sema_device_extensions, | |||
ARRAY_SIZE(ext_sema_device_extensions)); | |||
if (result != VK_SUCCESS) | |||
goto fail; | |||
} | |||
fprintf(stderr, "WARNING: radv is not a conformant vulkan implementation, testing use only.\n"); | |||
device->name = get_chip_name(device->rad_info.family); | |||
@@ -416,7 +199,6 @@ fail: | |||
static void | |||
radv_physical_device_finish(struct radv_physical_device *device) | |||
{ | |||
radv_extensions_finish(device->instance, &device->extensions); | |||
radv_finish_wsi(device); | |||
device->ws->destroy(device->ws); | |||
disk_cache_destroy(device->disk_cache); | |||
@@ -515,9 +297,8 @@ VkResult radv_CreateInstance( | |||
} | |||
for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { | |||
if (!is_extension_enabled(instance_extensions, | |||
ARRAY_SIZE(instance_extensions), | |||
pCreateInfo->ppEnabledExtensionNames[i])) | |||
const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i]; | |||
if (!radv_instance_extension_supported(ext_name)) | |||
return vk_error(VK_ERROR_EXTENSION_NOT_PRESENT); | |||
} | |||
@@ -851,7 +632,7 @@ void radv_GetPhysicalDeviceProperties( | |||
}; | |||
*pProperties = (VkPhysicalDeviceProperties) { | |||
.apiVersion = VK_MAKE_VERSION(1, 0, 42), | |||
.apiVersion = radv_physical_device_api_version(pdevice), | |||
.driverVersion = vk_get_driver_version(), | |||
.vendorID = ATI_VENDOR_ID, | |||
.deviceID = pdevice->rad_info.pci_id, | |||
@@ -1141,9 +922,8 @@ VkResult radv_CreateDevice( | |||
struct radv_device *device; | |||
for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { | |||
if (!is_extension_enabled(physical_device->extensions.ext_array, | |||
physical_device->extensions.num_ext, | |||
pCreateInfo->ppEnabledExtensionNames[i])) | |||
const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i]; | |||
if (!radv_physical_device_extension_supported(physical_device, ext_name)) | |||
return vk_error(VK_ERROR_EXTENSION_NOT_PRESENT); | |||
} | |||
@@ -1331,47 +1111,6 @@ void radv_DestroyDevice( | |||
vk_free(&device->alloc, device); | |||
} | |||
VkResult radv_EnumerateInstanceExtensionProperties( | |||
const char* pLayerName, | |||
uint32_t* pPropertyCount, | |||
VkExtensionProperties* pProperties) | |||
{ | |||
if (pProperties == NULL) { | |||
*pPropertyCount = ARRAY_SIZE(instance_extensions); | |||
return VK_SUCCESS; | |||
} | |||
*pPropertyCount = MIN2(*pPropertyCount, ARRAY_SIZE(instance_extensions)); | |||
typed_memcpy(pProperties, instance_extensions, *pPropertyCount); | |||
if (*pPropertyCount < ARRAY_SIZE(instance_extensions)) | |||
return VK_INCOMPLETE; | |||
return VK_SUCCESS; | |||
} | |||
VkResult radv_EnumerateDeviceExtensionProperties( | |||
VkPhysicalDevice physicalDevice, | |||
const char* pLayerName, | |||
uint32_t* pPropertyCount, | |||
VkExtensionProperties* pProperties) | |||
{ | |||
RADV_FROM_HANDLE(radv_physical_device, pdevice, physicalDevice); | |||
if (pProperties == NULL) { | |||
*pPropertyCount = pdevice->extensions.num_ext; | |||
return VK_SUCCESS; | |||
} | |||
*pPropertyCount = MIN2(*pPropertyCount, pdevice->extensions.num_ext); | |||
typed_memcpy(pProperties, pdevice->extensions.ext_array, *pPropertyCount); | |||
if (*pPropertyCount < pdevice->extensions.num_ext) | |||
return VK_INCOMPLETE; | |||
return VK_SUCCESS; | |||
} | |||
VkResult radv_EnumerateInstanceLayerProperties( | |||
uint32_t* pPropertyCount, | |||
VkLayerProperties* pProperties) |
@@ -25,214 +25,184 @@ | |||
import argparse | |||
import functools | |||
import os | |||
import textwrap | |||
import xml.etree.cElementTree as et | |||
from mako.template import Template | |||
MAX_API_VERSION = 1.0 | |||
SUPPORTED_EXTENSIONS = [ | |||
'VK_AMD_draw_indirect_count', | |||
'VK_NV_dedicated_allocation', | |||
'VK_KHR_descriptor_update_template', | |||
'VK_KHR_get_physical_device_properties2', | |||
'VK_KHR_incremental_present', | |||
'VK_KHR_maintenance1', | |||
'VK_KHR_push_descriptor', | |||
'VK_KHR_sampler_mirror_clamp_to_edge', | |||
'VK_KHR_shader_draw_parameters', | |||
'VK_KHR_surface', | |||
'VK_KHR_swapchain', | |||
'VK_KHR_wayland_surface', | |||
'VK_KHR_xcb_surface', | |||
'VK_KHR_xlib_surface', | |||
'VK_KHR_get_memory_requirements2', | |||
'VK_KHR_dedicated_allocation', | |||
'VK_KHR_external_memory_capabilities', | |||
'VK_KHR_external_memory', | |||
'VK_KHR_external_memory_fd', | |||
'VK_KHR_storage_buffer_storage_class', | |||
'VK_KHR_variable_pointers', | |||
'VK_KHR_external_semaphore_capabilities', | |||
'VK_KHR_external_semaphore', | |||
'VK_KHR_external_semaphore_fd', | |||
'VK_KHR_bind_memory2', | |||
'VK_KHR_maintenance2', | |||
] | |||
from radv_extensions import * | |||
# We generate a static hash table for entry point lookup | |||
# (vkGetProcAddress). We use a linear congruential generator for our hash | |||
# function and a power-of-two size table. The prime numbers are determined | |||
# experimentally. | |||
TEMPLATE_H = Template(textwrap.dedent("""\ | |||
/* This file generated from ${filename}, don't edit directly. */ | |||
struct radv_dispatch_table { | |||
union { | |||
void *entrypoints[${len(entrypoints)}]; | |||
struct { | |||
% for _, name, _, _, _, guard in entrypoints: | |||
% if guard is not None: | |||
#ifdef ${guard} | |||
PFN_vk${name} ${name}; | |||
#else | |||
void *${name}; | |||
# endif | |||
% else: | |||
PFN_vk${name} ${name}; | |||
% endif | |||
% endfor | |||
}; | |||
}; | |||
}; | |||
% for type_, name, args, num, h, guard in entrypoints: | |||
% if guard is not None: | |||
#ifdef ${guard} | |||
% endif | |||
${type_} radv_${name}(${args}); | |||
% if guard is not None: | |||
#endif // ${guard} | |||
% endif | |||
% endfor | |||
"""), output_encoding='utf-8') | |||
TEMPLATE_C = Template(textwrap.dedent(u"""\ | |||
/* | |||
* Copyright © 2015 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 (including the next | |||
* paragraph) 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. | |||
*/ | |||
/* This file generated from ${filename}, don't edit directly. */ | |||
#include "radv_private.h" | |||
struct radv_entrypoint { | |||
uint32_t name; | |||
uint32_t hash; | |||
}; | |||
/* We use a big string constant to avoid lots of reloctions from the entry | |||
* point table to lots of little strings. The entries in the entry point table | |||
* store the index into this big string. | |||
*/ | |||
static const char strings[] = | |||
% for _, name, _, _, _, _ in entrypoints: | |||
"vk${name}\\0" | |||
% endfor | |||
; | |||
static const struct radv_entrypoint entrypoints[] = { | |||
% for _, _, _, num, h, _ in entrypoints: | |||
{ ${offsets[num]}, ${'{:0=#8x}'.format(h)} }, | |||
% endfor | |||
}; | |||
/* Weak aliases for all potential implementations. These will resolve to | |||
* NULL if they're not defined, which lets the resolve_entrypoint() function | |||
* either pick the correct entry point. | |||
*/ | |||
% for layer in ['radv']: | |||
% for type_, name, args, _, _, guard in entrypoints: | |||
% if guard is not None: | |||
#ifdef ${guard} | |||
% endif | |||
${type_} ${layer}_${name}(${args}) __attribute__ ((weak)); | |||
% if guard is not None: | |||
#endif // ${guard} | |||
% endif | |||
% endfor | |||
TEMPLATE_H = Template("""\ | |||
/* This file generated from ${filename}, don't edit directly. */ | |||
const struct radv_dispatch_table ${layer}_layer = { | |||
% for _, name, args, _, _, guard in entrypoints: | |||
% if guard is not None: | |||
#ifdef ${guard} | |||
% endif | |||
.${name} = ${layer}_${name}, | |||
struct radv_dispatch_table { | |||
union { | |||
void *entrypoints[${len(entrypoints)}]; | |||
struct { | |||
% for _, name, _, _, _, guard in entrypoints: | |||
% if guard is not None: | |||
#endif // ${guard} | |||
% endif | |||
% endfor | |||
}; | |||
% endfor | |||
static void * __attribute__ ((noinline)) | |||
radv_resolve_entrypoint(uint32_t index) | |||
{ | |||
return radv_layer.entrypoints[index]; | |||
} | |||
/* Hash table stats: | |||
* size ${hash_size} entries | |||
* collisions entries: | |||
% for i in xrange(10): | |||
* ${i}${'+' if i == 9 else ''} ${collisions[i]} | |||
% endfor | |||
*/ | |||
#define none ${'{:#x}'.format(none)} | |||
static const uint16_t map[] = { | |||
% for i in xrange(0, hash_size, 8): | |||
% for j in xrange(i, i + 8): | |||
## This is 6 because the 0x is counted in the length | |||
% if mapping[j] & 0xffff == 0xffff: | |||
none, | |||
#ifdef ${guard} | |||
PFN_vk${name} ${name}; | |||
#else | |||
void *${name}; | |||
# endif | |||
% else: | |||
${'{:0=#6x}'.format(mapping[j] & 0xffff)}, | |||
PFN_vk${name} ${name}; | |||
% endif | |||
% endfor | |||
% endfor | |||
}; | |||
void * | |||
radv_lookup_entrypoint(const char *name) | |||
{ | |||
static const uint32_t prime_factor = ${prime_factor}; | |||
static const uint32_t prime_step = ${prime_step}; | |||
const struct radv_entrypoint *e; | |||
uint32_t hash, h, i; | |||
const char *p; | |||
hash = 0; | |||
for (p = name; *p; p++) | |||
hash = hash * prime_factor + *p; | |||
h = hash; | |||
do { | |||
i = map[h & ${hash_mask}]; | |||
if (i == none) | |||
return NULL; | |||
e = &entrypoints[i]; | |||
h += prime_step; | |||
} while (e->hash != hash); | |||
if (strcmp(name, strings + e->name) != 0) | |||
return NULL; | |||
return radv_resolve_entrypoint(i); | |||
}"""), output_encoding='utf-8') | |||
}; | |||
}; | |||
}; | |||
% for type_, name, args, num, h, guard in entrypoints: | |||
% if guard is not None: | |||
#ifdef ${guard} | |||
% endif | |||
${type_} radv_${name}(${args}); | |||
% if guard is not None: | |||
#endif // ${guard} | |||
% endif | |||
% endfor | |||
""", output_encoding='utf-8') | |||
TEMPLATE_C = Template(u"""\ | |||
/* | |||
* Copyright © 2015 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 (including the next | |||
* paragraph) 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. | |||
*/ | |||
/* This file generated from ${filename}, don't edit directly. */ | |||
#include "radv_private.h" | |||
struct radv_entrypoint { | |||
uint32_t name; | |||
uint32_t hash; | |||
}; | |||
/* We use a big string constant to avoid lots of reloctions from the entry | |||
* point table to lots of little strings. The entries in the entry point table | |||
* store the index into this big string. | |||
*/ | |||
static const char strings[] = | |||
% for _, name, _, _, _, _ in entrypoints: | |||
"vk${name}\\0" | |||
% endfor | |||
; | |||
static const struct radv_entrypoint entrypoints[] = { | |||
% for _, name, _, num, h, _ in entrypoints: | |||
[${num}] = { ${offsets[num]}, ${'{:0=#8x}'.format(h)} }, /* vk${name} */ | |||
% endfor | |||
}; | |||
/* Weak aliases for all potential implementations. These will resolve to | |||
* NULL if they're not defined, which lets the resolve_entrypoint() function | |||
* either pick the correct entry point. | |||
*/ | |||
% for layer in ['radv']: | |||
% for type_, name, args, _, _, guard in entrypoints: | |||
% if guard is not None: | |||
#ifdef ${guard} | |||
% endif | |||
${type_} ${layer}_${name}(${args}) __attribute__ ((weak)); | |||
% if guard is not None: | |||
#endif // ${guard} | |||
% endif | |||
% endfor | |||
const struct radv_dispatch_table ${layer}_layer = { | |||
% for _, name, args, _, _, guard in entrypoints: | |||
% if guard is not None: | |||
#ifdef ${guard} | |||
% endif | |||
.${name} = ${layer}_${name}, | |||
% if guard is not None: | |||
#endif // ${guard} | |||
% endif | |||
% endfor | |||
}; | |||
% endfor | |||
static void * __attribute__ ((noinline)) | |||
radv_resolve_entrypoint(uint32_t index) | |||
{ | |||
return radv_layer.entrypoints[index]; | |||
} | |||
/* Hash table stats: | |||
* size ${hash_size} entries | |||
* collisions entries: | |||
% for i in xrange(10): | |||
* ${i}${'+' if i == 9 else ''} ${collisions[i]} | |||
% endfor | |||
*/ | |||
#define none ${'{:#x}'.format(none)} | |||
static const uint16_t map[] = { | |||
% for i in xrange(0, hash_size, 8): | |||
% for j in xrange(i, i + 8): | |||
## This is 6 because the 0x is counted in the length | |||
% if mapping[j] & 0xffff == 0xffff: | |||
none, | |||
% else: | |||
${'{:0=#6x}'.format(mapping[j] & 0xffff)}, | |||
% endif | |||
% endfor | |||
% endfor | |||
}; | |||
void * | |||
radv_lookup_entrypoint(const char *name) | |||
{ | |||
static const uint32_t prime_factor = ${prime_factor}; | |||
static const uint32_t prime_step = ${prime_step}; | |||
const struct radv_entrypoint *e; | |||
uint32_t hash, h, i; | |||
const char *p; | |||
hash = 0; | |||
for (p = name; *p; p++) | |||
hash = hash * prime_factor + *p; | |||
h = hash; | |||
do { | |||
i = map[h & ${hash_mask}]; | |||
if (i == none) | |||
return NULL; | |||
e = &entrypoints[i]; | |||
h += prime_step; | |||
} while (e->hash != hash); | |||
if (strcmp(name, strings + e->name) != 0) | |||
return NULL; | |||
return radv_resolve_entrypoint(i); | |||
}""", output_encoding='utf-8') | |||
NONE = 0xffff | |||
HASH_SIZE = 256 | |||
@@ -249,28 +219,29 @@ def cal_hash(name): | |||
lambda h, c: (h * PRIME_FACTOR + ord(c)) & U32_MASK, name, 0) | |||
def get_entrypoints(doc, entrypoints_to_defines): | |||
def get_entrypoints(doc, entrypoints_to_defines, start_index): | |||
"""Extract the entry points from the registry.""" | |||
entrypoints = [] | |||
enabled_commands = set() | |||
for feature in doc.findall('./feature'): | |||
assert feature.attrib['api'] == 'vulkan' | |||
if float(feature.attrib['number']) > MAX_API_VERSION: | |||
if VkVersion(feature.attrib['number']) > MAX_API_VERSION: | |||
continue | |||
for command in feature.findall('./require/command'): | |||
enabled_commands.add(command.attrib['name']) | |||
supported = set(ext.name for ext in EXTENSIONS) | |||
for extension in doc.findall('.extensions/extension'): | |||
if extension.attrib['name'] not in SUPPORTED_EXTENSIONS: | |||
if extension.attrib['name'] not in supported: | |||
continue | |||
assert extension.attrib['supported'] == 'vulkan' | |||
for command in extension.findall('./require/command'): | |||
enabled_commands.add(command.attrib['name']) | |||
index = 0 | |||
index = start_index | |||
for command in doc.findall('./commands/command'): | |||
type = command.find('./proto/type').text | |||
fullname = command.find('./proto/name').text | |||
@@ -339,12 +310,22 @@ def main(): | |||
parser = argparse.ArgumentParser() | |||
parser.add_argument('--outdir', help='Where to write the files.', | |||
required=True) | |||
parser.add_argument('--xml', help='Vulkan API XML file.', required=True) | |||
parser.add_argument('--xml', | |||
help='Vulkan API XML file.', | |||
required=True, | |||
action='append', | |||
dest='xml_files') | |||
args = parser.parse_args() | |||
doc = et.parse(args.xml) | |||
entrypoints = get_entrypoints(doc, get_entrypoints_defines(doc)) | |||
entrypoints = [] | |||
for filename in args.xml_files: | |||
doc = et.parse(filename) | |||
entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc), | |||
start_index=len(entrypoints)) | |||
# For outputting entrypoints.h we generate a radv_EntryPoint() prototype | |||
# per entry point. | |||
with open(os.path.join(args.outdir, 'radv_entrypoints.h'), 'wb') as f: | |||
f.write(TEMPLATE_H.render(entrypoints=entrypoints, | |||
filename=os.path.basename(__file__))) |
@@ -0,0 +1,278 @@ | |||
COPYRIGHT = """\ | |||
/* | |||
* 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, sub license, 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 (including the | |||
* next paragraph) 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 NON-INFRINGEMENT. | |||
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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. | |||
*/ | |||
""" | |||
import argparse | |||
import copy | |||
import re | |||
import xml.etree.cElementTree as et | |||
from mako.template import Template | |||
MAX_API_VERSION = '1.0.57' | |||
class Extension: | |||
def __init__(self, name, ext_version, enable): | |||
self.name = name | |||
self.ext_version = int(ext_version) | |||
if enable is True: | |||
self.enable = 'true'; | |||
elif enable is False: | |||
self.enable = 'false'; | |||
else: | |||
self.enable = enable; | |||
# On Android, we disable all surface and swapchain extensions. Android's Vulkan | |||
# loader implements VK_KHR_surface and VK_KHR_swapchain, and applications | |||
# cannot access the driver's implementation. Moreoever, if the driver exposes | |||
# the those extension strings, then tests dEQP-VK.api.info.instance.extensions | |||
# and dEQP-VK.api.info.device fail due to the duplicated strings. | |||
EXTENSIONS = [ | |||
Extension('VK_KHR_bind_memory2', 1, True), | |||
Extension('VK_KHR_dedicated_allocation', 1, True), | |||
Extension('VK_KHR_descriptor_update_template', 1, True), | |||
Extension('VK_KHR_external_memory', 1, True), | |||
Extension('VK_KHR_external_memory_capabilities', 1, True), | |||
Extension('VK_KHR_external_memory_fd', 1, True), | |||
Extension('VK_KHR_external_semaphore', 1, 'device->rad_info.has_syncobj'), | |||
Extension('VK_KHR_external_semaphore_capabilities', 1, True), | |||
Extension('VK_KHR_external_semaphore_fd', 1, 'device->rad_info.has_syncobj'), | |||
Extension('VK_KHR_get_memory_requirements2', 1, True), | |||
Extension('VK_KHR_get_physical_device_properties2', 1, True), | |||
Extension('VK_KHR_image_format_list', 1, True), | |||
Extension('VK_KHR_incremental_present', 1, True), | |||
Extension('VK_KHR_maintenance1', 1, True), | |||
Extension('VK_KHR_maintenance2', 1, True), | |||
Extension('VK_KHR_push_descriptor', 1, True), | |||
Extension('VK_KHR_relaxed_block_layout', 1, True), | |||
Extension('VK_KHR_sampler_mirror_clamp_to_edge', 1, True), | |||
Extension('VK_KHR_shader_draw_parameters', 1, True), | |||
Extension('VK_KHR_storage_buffer_storage_class', 1, True), | |||
Extension('VK_KHR_surface', 25, 'RADV_HAS_SURFACE'), | |||
Extension('VK_KHR_swapchain', 68, 'RADV_HAS_SURFACE'), | |||
Extension('VK_KHR_variable_pointers', 1, True), | |||
Extension('VK_KHR_wayland_surface', 6, 'VK_USE_PLATFORM_WAYLAND_KHR'), | |||
Extension('VK_KHR_xcb_surface', 6, 'VK_USE_PLATFORM_XCB_KHR'), | |||
Extension('VK_KHR_xlib_surface', 6, 'VK_USE_PLATFORM_XLIB_KHR'), | |||
Extension('VK_KHX_multiview', 1, True), | |||
Extension('VK_EXT_debug_report', 8, True), | |||
Extension('VK_AMD_draw_indirect_count', 1, True), | |||
Extension('VK_AMD_rasterization_order', 1, 'device->rad_info.chip_class >= VI && device->rad_info.max_se >= 2'), | |||
] | |||
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)] | |||
return 'VK_MAKE_VERSION(' + ', '.join(ver_list) + ')' | |||
def __int_ver(self): | |||
# This is just an expansion of VK_VERSION | |||
patch = self.patch if self.patch is not None else 0 | |||
return (self.major << 22) | (self.minor << 12) | patch | |||
def __cmp__(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().__cmp__(other.__int_ver()) | |||
MAX_API_VERSION = VkVersion(MAX_API_VERSION) | |||
def _init_exts_from_xml(xml): | |||
""" 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 | |||
for ext_elem in xml.findall('.extensions/extension'): | |||
ext_name = ext_elem.attrib['name'] | |||
if ext_name not in ext_name_map: | |||
continue | |||
# Workaround for VK_ANDROID_native_buffer. Its <extension> element in | |||
# vk.xml lists it as supported="disabled" and provides only a stub | |||
# definition. Its <extension> element in Mesa's custom | |||
# vk_android_native_buffer.xml, though, lists it as | |||
# supported='android-vendor' and fully defines the extension. We want | |||
# to skip the <extension> element in vk.xml. | |||
if ext_elem.attrib['supported'] == 'disabled': | |||
assert ext_name == 'VK_ANDROID_native_buffer' | |||
continue | |||
ext = ext_name_map[ext_name] | |||
ext.type = ext_elem.attrib['type'] | |||
_TEMPLATE = Template(COPYRIGHT + """ | |||
#include "radv_private.h" | |||
#include "vk_util.h" | |||
/* Convert the VK_USE_PLATFORM_* defines to booleans */ | |||
%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']: | |||
#ifdef VK_USE_PLATFORM_${platform}_KHR | |||
# undef VK_USE_PLATFORM_${platform}_KHR | |||
# define VK_USE_PLATFORM_${platform}_KHR true | |||
#else | |||
# define VK_USE_PLATFORM_${platform}_KHR false | |||
#endif | |||
%endfor | |||
/* And ANDROID too */ | |||
#ifdef ANDROID | |||
# undef ANDROID | |||
# define ANDROID true | |||
#else | |||
# define ANDROID false | |||
#endif | |||
#define RADV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\ | |||
VK_USE_PLATFORM_XCB_KHR || \\ | |||
VK_USE_PLATFORM_XLIB_KHR) | |||
bool | |||
radv_instance_extension_supported(const char *name) | |||
{ | |||
%for ext in instance_extensions: | |||
if (strcmp(name, "${ext.name}") == 0) | |||
return ${ext.enable}; | |||
%endfor | |||
return false; | |||
} | |||
VkResult radv_EnumerateInstanceExtensionProperties( | |||
const char* pLayerName, | |||
uint32_t* pPropertyCount, | |||
VkExtensionProperties* pProperties) | |||
{ | |||
VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount); | |||
%for ext in instance_extensions: | |||
if (${ext.enable}) { | |||
vk_outarray_append(&out, prop) { | |||
*prop = (VkExtensionProperties) { | |||
.extensionName = "${ext.name}", | |||
.specVersion = ${ext.ext_version}, | |||
}; | |||
} | |||
} | |||
%endfor | |||
return vk_outarray_status(&out); | |||
} | |||
uint32_t | |||
radv_physical_device_api_version(struct radv_physical_device *dev) | |||
{ | |||
return ${MAX_API_VERSION.c_vk_version()}; | |||
} | |||
bool | |||
radv_physical_device_extension_supported(struct radv_physical_device *device, | |||
const char *name) | |||
{ | |||
%for ext in device_extensions: | |||
if (strcmp(name, "${ext.name}") == 0) | |||
return ${ext.enable}; | |||
%endfor | |||
return false; | |||
} | |||
VkResult radv_EnumerateDeviceExtensionProperties( | |||
VkPhysicalDevice physicalDevice, | |||
const char* pLayerName, | |||
uint32_t* pPropertyCount, | |||
VkExtensionProperties* pProperties) | |||
{ | |||
RADV_FROM_HANDLE(radv_physical_device, device, physicalDevice); | |||
VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount); | |||
(void)device; | |||
%for ext in device_extensions: | |||
if (${ext.enable}) { | |||
vk_outarray_append(&out, prop) { | |||
*prop = (VkExtensionProperties) { | |||
.extensionName = "${ext.name}", | |||
.specVersion = ${ext.ext_version}, | |||
}; | |||
} | |||
} | |||
%endfor | |||
return vk_outarray_status(&out); | |||
} | |||
""") | |||
if __name__ == '__main__': | |||
parser = argparse.ArgumentParser() | |||
parser.add_argument('--out', help='Output C file.', required=True) | |||
parser.add_argument('--xml', | |||
help='Vulkan API XML file.', | |||
required=True, | |||
action='append', | |||
dest='xml_files') | |||
args = parser.parse_args() | |||
for filename in args.xml_files: | |||
_init_exts_from_xml(filename) | |||
for ext in EXTENSIONS: | |||
assert ext.type == 'instance' or ext.type == 'device' | |||
template_env = { | |||
'MAX_API_VERSION': MAX_API_VERSION, | |||
'instance_extensions': [e for e in EXTENSIONS if e.type == 'instance'], | |||
'device_extensions': [e for e in EXTENSIONS if e.type == 'device'], | |||
} | |||
with open(args.out, 'w') as f: | |||
f.write(_TEMPLATE.render(**template_env)) |
@@ -253,11 +253,6 @@ void radv_loge_v(const char *format, va_list va); | |||
void *radv_lookup_entrypoint(const char *name); | |||
struct radv_extensions { | |||
VkExtensionProperties *ext_array; | |||
uint32_t num_ext; | |||
}; | |||
struct radv_physical_device { | |||
VK_LOADER_DATA _loader_data; | |||
@@ -273,7 +268,6 @@ struct radv_physical_device { | |||
int local_fd; | |||
struct wsi_device wsi_device; | |||
struct radv_extensions extensions; | |||
bool has_rbplus; /* if RB+ register exist */ | |||
bool rbplus_allowed; /* if RB+ is allowed */ | |||
@@ -301,6 +295,11 @@ struct radv_instance { | |||
VkResult radv_init_wsi(struct radv_physical_device *physical_device); | |||
void radv_finish_wsi(struct radv_physical_device *physical_device); | |||
bool radv_instance_extension_supported(const char *name); | |||
uint32_t radv_physical_device_api_version(struct radv_physical_device *dev); | |||
bool radv_physical_device_extension_supported(struct radv_physical_device *dev, | |||
const char *name); | |||
struct cache_entry; | |||
struct radv_pipeline_cache { |