diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2021-07-22 10:17:30 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2021-07-22 10:17:30 +0000 |
commit | ca11beabae33eb59fb981b8adf50b1d47a2a98f0 (patch) | |
tree | 3e4691a396e6e54cd54224a190663d5cf976625b /lib/mesa/src/vulkan/util | |
parent | 27c8a50e8bbde7d28b1fc46d715a4c469e24f2c4 (diff) |
Import Mesa 21.1.5
Diffstat (limited to 'lib/mesa/src/vulkan/util')
26 files changed, 4373 insertions, 101 deletions
diff --git a/lib/mesa/src/vulkan/util/meson.build b/lib/mesa/src/vulkan/util/meson.build index f4f7d1730..1a3723990 100644 --- a/lib/mesa/src/vulkan/util/meson.build +++ b/lib/mesa/src/vulkan/util/meson.build @@ -18,15 +18,74 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +# Mesa-local imports in the Python files must be declared here for correct +# dependency tracking. +vk_extensions_depend_files = [ +] +vk_extensions_gen_depend_files = [ + files('vk_extensions.py'), + vk_extensions_depend_files, +] +vk_dispatch_table_gen_depend_files = [ + files('vk_extensions.py'), + vk_extensions_depend_files, +] +vk_entrypoints_gen_depend_files = [ + files('vk_dispatch_table_gen.py'), + vk_dispatch_table_gen_depend_files, +] + +vk_entrypoints_gen = files('vk_entrypoints_gen.py') +vk_extensions_gen = files('vk_extensions_gen.py') +vk_icd_gen = files('vk_icd_gen.py') + files_vulkan_util = files( 'vk_alloc.h', + 'vk_cmd_copy.c', 'vk_debug_report.c', 'vk_debug_report.h', + 'vk_deferred_operation.c', + 'vk_deferred_operation.h', + 'vk_descriptors.c', + 'vk_descriptors.h', + 'vk_device.c', + 'vk_device.h', 'vk_format.c', + 'vk_instance.c', + 'vk_instance.h', + 'vk_object.c', + 'vk_object.h', + 'vk_physical_device.c', + 'vk_physical_device.h', + 'vk_render_pass.c', + 'vk_shader_module.c', + 'vk_shader_module.h', 'vk_util.c', 'vk_util.h', ) +vk_common_entrypoints = custom_target( + 'vk_common_entrypoints', + input : [vk_entrypoints_gen, vk_api_xml], + output : ['vk_common_entrypoints.h', 'vk_common_entrypoints.c'], + command : [ + prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--proto', '--weak', + '--out-h', '@OUTPUT0@', '--out-c', '@OUTPUT1@', '--prefix', 'vk_common', + ], + depend_files : vk_entrypoints_gen_depend_files, +) + +vk_dispatch_table = custom_target( + 'vk_dispatch_table', + input : ['vk_dispatch_table_gen.py', vk_api_xml], + output : ['vk_dispatch_table.c', 'vk_dispatch_table.h'], + command : [ + prog_python, '@INPUT0@', '--xml', '@INPUT1@', + '--out-c', '@OUTPUT0@', '--out-h', '@OUTPUT1@' + ], + depend_files : vk_dispatch_table_gen_depend_files, +) + vk_enum_to_str = custom_target( 'vk_enum_to_str', input : ['gen_enum_to_str.py', vk_api_xml], @@ -37,21 +96,48 @@ vk_enum_to_str = custom_target( ], ) +vk_extensions = custom_target( + 'vk_extensions', + input : ['vk_extensions_gen.py', vk_api_xml], + output : ['vk_extensions.c', 'vk_extensions.h'], + command : [ + prog_python, '@INPUT0@', '--xml', '@INPUT1@', + '--out-c', '@OUTPUT0@', '--out-h', '@OUTPUT1@' + ], + depend_files : vk_extensions_gen_depend_files, +) + libvulkan_util = static_library( 'vulkan_util', - [files_vulkan_util, vk_enum_to_str], - include_directories : inc_common, - dependencies : vulkan_wsi_deps, - c_args : [c_vis_args, vulkan_wsi_args], + [files_vulkan_util, vk_common_entrypoints, vk_dispatch_table, + vk_enum_to_str, vk_extensions], + include_directories : [inc_include, inc_src, inc_gallium], + dependencies : [vulkan_wsi_deps, idep_mesautil], + # For glsl_type_singleton + link_with : libcompiler, + c_args : [vulkan_wsi_args], + gnu_symbol_visibility : 'hidden', build_by_default : false, ) idep_vulkan_util_headers = declare_dependency( - sources : vk_enum_to_str[1], + sources : [vk_dispatch_table[1], vk_enum_to_str[1], vk_extensions[1]], include_directories : include_directories('.') ) -idep_vulkan_util = declare_dependency( - link_with : libvulkan_util, - dependencies : idep_vulkan_util_headers -) +# This is likely a bug in the Meson VS backend, as MSVC with ninja works fine. +# See this discussion here: +# https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10506 +if get_option('backend').startswith('vs') + idep_vulkan_util = declare_dependency( + link_with : libvulkan_util, + dependencies : idep_vulkan_util_headers + ) +else + idep_vulkan_util = declare_dependency( + # Instruct users of this library to link with --whole-archive. Otherwise, + # our weak function overloads may not resolve properly. + link_whole : libvulkan_util, + dependencies : idep_vulkan_util_headers + ) +endif diff --git a/lib/mesa/src/vulkan/util/vk_cmd_copy.c b/lib/mesa/src/vulkan/util/vk_cmd_copy.c new file mode 100644 index 000000000..5c71dbb38 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_cmd_copy.c @@ -0,0 +1,285 @@ +/* + * Copyright © 2021 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. + */ + +#include "vk_common_entrypoints.h" +#include "vk_device.h" + +#define STACK_ARRAY_SIZE 8 + +#define STACK_ARRAY(type, name, size) \ + type _stack_##name[STACK_ARRAY_SIZE], *const name = \ + (size) <= STACK_ARRAY_SIZE ? _stack_##name : malloc((size) * sizeof(type)) + +#define STACK_ARRAY_FINISH(name) \ + if (name != _stack_##name) free(name) + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdCopyBuffer(VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferCopy *pRegions) +{ + /* We don't have a vk_command_buffer object but we can assume, since we're + * using common dispatch, that it's a vk_object of some sort. + */ + struct vk_object_base *disp = (struct vk_object_base *)commandBuffer; + + STACK_ARRAY(VkBufferCopy2KHR, region2s, regionCount); + + for (uint32_t r = 0; r < regionCount; r++) { + region2s[r] = (VkBufferCopy2KHR) { + .sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR, + .srcOffset = pRegions[r].srcOffset, + .dstOffset = pRegions[r].dstOffset, + .size = pRegions[r].size, + }; + } + + VkCopyBufferInfo2KHR info = { + .sType = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR, + .srcBuffer = srcBuffer, + .dstBuffer = dstBuffer, + .regionCount = regionCount, + .pRegions = region2s, + }; + + disp->device->dispatch_table.CmdCopyBuffer2KHR(commandBuffer, &info); + + STACK_ARRAY_FINISH(region2s); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdCopyImage(VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy *pRegions) +{ + /* We don't have a vk_command_buffer object but we can assume, since we're + * using common dispatch, that it's a vk_object of some sort. + */ + struct vk_object_base *disp = (struct vk_object_base *)commandBuffer; + + STACK_ARRAY(VkImageCopy2KHR, region2s, regionCount); + + for (uint32_t r = 0; r < regionCount; r++) { + region2s[r] = (VkImageCopy2KHR) { + .sType = VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR, + .srcSubresource = pRegions[r].srcSubresource, + .srcOffset = pRegions[r].srcOffset, + .dstSubresource = pRegions[r].dstSubresource, + .dstOffset = pRegions[r].dstOffset, + .extent = pRegions[r].extent, + }; + } + + VkCopyImageInfo2KHR info = { + .sType = VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR, + .srcImage = srcImage, + .srcImageLayout = srcImageLayout, + .dstImage = dstImage, + .dstImageLayout = dstImageLayout, + .regionCount = regionCount, + .pRegions = region2s, + }; + + disp->device->dispatch_table.CmdCopyImage2KHR(commandBuffer, &info); + + STACK_ARRAY_FINISH(region2s); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdCopyBufferToImage(VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy *pRegions) +{ + /* We don't have a vk_command_buffer object but we can assume, since we're + * using common dispatch, that it's a vk_object of some sort. + */ + struct vk_object_base *disp = (struct vk_object_base *)commandBuffer; + + STACK_ARRAY(VkBufferImageCopy2KHR, region2s, regionCount); + + for (uint32_t r = 0; r < regionCount; r++) { + region2s[r] = (VkBufferImageCopy2KHR) { + .sType = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR, + .bufferOffset = pRegions[r].bufferOffset, + .bufferRowLength = pRegions[r].bufferRowLength, + .bufferImageHeight = pRegions[r].bufferImageHeight, + .imageSubresource = pRegions[r].imageSubresource, + .imageOffset = pRegions[r].imageOffset, + .imageExtent = pRegions[r].imageExtent, + }; + } + + VkCopyBufferToImageInfo2KHR info = { + .sType = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR, + .srcBuffer = srcBuffer, + .dstImage = dstImage, + .dstImageLayout = dstImageLayout, + .regionCount = regionCount, + .pRegions = region2s, + }; + + disp->device->dispatch_table.CmdCopyBufferToImage2KHR(commandBuffer, &info); + + STACK_ARRAY_FINISH(region2s); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy *pRegions) +{ + /* We don't have a vk_command_buffer object but we can assume, since we're + * using common dispatch, that it's a vk_object of some sort. + */ + struct vk_object_base *disp = (struct vk_object_base *)commandBuffer; + + STACK_ARRAY(VkBufferImageCopy2KHR, region2s, regionCount); + + for (uint32_t r = 0; r < regionCount; r++) { + region2s[r] = (VkBufferImageCopy2KHR) { + .sType = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR, + .bufferOffset = pRegions[r].bufferOffset, + .bufferRowLength = pRegions[r].bufferRowLength, + .bufferImageHeight = pRegions[r].bufferImageHeight, + .imageSubresource = pRegions[r].imageSubresource, + .imageOffset = pRegions[r].imageOffset, + .imageExtent = pRegions[r].imageExtent, + }; + } + + VkCopyImageToBufferInfo2KHR info = { + .sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR, + .srcImage = srcImage, + .srcImageLayout = srcImageLayout, + .dstBuffer = dstBuffer, + .regionCount = regionCount, + .pRegions = region2s, + }; + + disp->device->dispatch_table.CmdCopyImageToBuffer2KHR(commandBuffer, &info); + + STACK_ARRAY_FINISH(region2s); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdBlitImage(VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit *pRegions, + VkFilter filter) +{ + /* We don't have a vk_command_buffer object but we can assume, since we're + * using common dispatch, that it's a vk_object of some sort. + */ + struct vk_object_base *disp = (struct vk_object_base *)commandBuffer; + + STACK_ARRAY(VkImageBlit2KHR, region2s, regionCount); + + for (uint32_t r = 0; r < regionCount; r++) { + region2s[r] = (VkImageBlit2KHR) { + .sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR, + .srcSubresource = pRegions[r].srcSubresource, + .srcOffsets = { + pRegions[r].srcOffsets[0], + pRegions[r].srcOffsets[1], + }, + .dstSubresource = pRegions[r].dstSubresource, + .dstOffsets = { + pRegions[r].dstOffsets[0], + pRegions[r].dstOffsets[1], + }, + }; + } + + VkBlitImageInfo2KHR info = { + .sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR, + .srcImage = srcImage, + .srcImageLayout = srcImageLayout, + .dstImage = dstImage, + .dstImageLayout = dstImageLayout, + .regionCount = regionCount, + .pRegions = region2s, + .filter = filter, + }; + + disp->device->dispatch_table.CmdBlitImage2KHR(commandBuffer, &info); + + STACK_ARRAY_FINISH(region2s); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdResolveImage(VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageResolve *pRegions) +{ + /* We don't have a vk_command_buffer object but we can assume, since we're + * using common dispatch, that it's a vk_object of some sort. + */ + struct vk_object_base *disp = (struct vk_object_base *)commandBuffer; + + STACK_ARRAY(VkImageResolve2KHR, region2s, regionCount); + + for (uint32_t r = 0; r < regionCount; r++) { + region2s[r] = (VkImageResolve2KHR) { + .sType = VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR, + .srcSubresource = pRegions[r].srcSubresource, + .srcOffset = pRegions[r].srcOffset, + .dstSubresource = pRegions[r].dstSubresource, + .dstOffset = pRegions[r].dstOffset, + .extent = pRegions[r].extent, + }; + } + + VkResolveImageInfo2KHR info = { + .sType = VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR, + .srcImage = srcImage, + .srcImageLayout = srcImageLayout, + .dstImage = dstImage, + .dstImageLayout = dstImageLayout, + .regionCount = regionCount, + .pRegions = region2s, + }; + + disp->device->dispatch_table.CmdResolveImage2KHR(commandBuffer, &info); + + STACK_ARRAY_FINISH(region2s); +} diff --git a/lib/mesa/src/vulkan/util/vk_debug_report.c b/lib/mesa/src/vulkan/util/vk_debug_report.c index 78dcfa6e2..db89e3d6f 100644 --- a/lib/mesa/src/vulkan/util/vk_debug_report.c +++ b/lib/mesa/src/vulkan/util/vk_debug_report.c @@ -24,88 +24,90 @@ #include "vk_debug_report.h" #include "vk_alloc.h" +#include "vk_common_entrypoints.h" +#include "vk_instance.h" #include "vk_util.h" -VkResult vk_debug_report_instance_init(struct vk_debug_report_instance *instance) -{ - if (pthread_mutex_init(&instance->callbacks_mutex, NULL) != 0) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - list_inithead(&instance->callbacks); - - return VK_SUCCESS; -} - -void vk_debug_report_instance_destroy(struct vk_debug_report_instance *instance) -{ - pthread_mutex_destroy(&instance->callbacks_mutex); -} - -VkResult -vk_create_debug_report_callback(struct vk_debug_report_instance *instance, - const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - const VkAllocationCallbacks* instance_allocator, - VkDebugReportCallbackEXT* pCallback) +struct vk_debug_report_callback { + struct vk_object_base base; + + /* Link in the 'callbacks' list in anv_instance struct. */ + struct list_head link; + VkDebugReportFlagsEXT flags; + PFN_vkDebugReportCallbackEXT callback; + void * data; +}; + +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_debug_report_callback, base, + VkDebugReportCallbackEXT, + VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT) + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_CreateDebugReportCallbackEXT(VkInstance _instance, + const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugReportCallbackEXT *pCallback) { + VK_FROM_HANDLE(vk_instance, instance, _instance); struct vk_debug_report_callback *cb = - vk_alloc2(instance_allocator, pAllocator, + vk_alloc2(&instance->alloc, pAllocator, sizeof(struct vk_debug_report_callback), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!cb) return VK_ERROR_OUT_OF_HOST_MEMORY; + vk_object_base_init(NULL, &cb->base, + VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT); + cb->flags = pCreateInfo->flags; cb->callback = pCreateInfo->pfnCallback; cb->data = pCreateInfo->pUserData; - pthread_mutex_lock(&instance->callbacks_mutex); - list_addtail(&cb->link, &instance->callbacks); - pthread_mutex_unlock(&instance->callbacks_mutex); + mtx_lock(&instance->debug_report.callbacks_mutex); + list_addtail(&cb->link, &instance->debug_report.callbacks); + mtx_unlock(&instance->debug_report.callbacks_mutex); - *pCallback = (VkDebugReportCallbackEXT)(uintptr_t)cb; + *pCallback = vk_debug_report_callback_to_handle(cb); return VK_SUCCESS; } -void -vk_destroy_debug_report_callback(struct vk_debug_report_instance *instance, - VkDebugReportCallbackEXT _callback, - const VkAllocationCallbacks* pAllocator, - const VkAllocationCallbacks* instance_allocator) +VKAPI_ATTR void VKAPI_CALL +vk_common_DestroyDebugReportCallbackEXT(VkInstance _instance, + VkDebugReportCallbackEXT _callback, + const VkAllocationCallbacks *pAllocator) { - if (_callback == VK_NULL_HANDLE) - return; + VK_FROM_HANDLE(vk_instance, instance, _instance); + VK_FROM_HANDLE(vk_debug_report_callback, callback, _callback); - struct vk_debug_report_callback *callback = - (struct vk_debug_report_callback *)(uintptr_t)_callback; + if (callback == NULL) + return; /* Remove from list and destroy given callback. */ - pthread_mutex_lock(&instance->callbacks_mutex); + mtx_lock(&instance->debug_report.callbacks_mutex); list_del(&callback->link); - vk_free2(instance_allocator, pAllocator, callback); - pthread_mutex_unlock(&instance->callbacks_mutex); + vk_object_base_finish(&callback->base); + vk_free2(&instance->alloc, pAllocator, callback); + mtx_unlock(&instance->debug_report.callbacks_mutex); } - -void -vk_debug_report(struct vk_debug_report_instance *instance, - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT object_type, - uint64_t handle, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char *pMessage) +static void +debug_report(struct vk_instance *instance, + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT object_type, + uint64_t handle, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char *pMessage) { /* Allow NULL for convinience, return if no callbacks registered. */ - if (!instance || list_is_empty(&instance->callbacks)) + if (!instance || list_is_empty(&instance->debug_report.callbacks)) return; - pthread_mutex_lock(&instance->callbacks_mutex); + mtx_lock(&instance->debug_report.callbacks_mutex); /* Section 33.2 of the Vulkan 1.0.59 spec says: * @@ -115,11 +117,41 @@ vk_debug_report(struct vk_debug_report_instance *instance, * is active." */ list_for_each_entry(struct vk_debug_report_callback, cb, - &instance->callbacks, link) { + &instance->debug_report.callbacks, link) { if (cb->flags & flags) cb->callback(flags, object_type, handle, location, messageCode, pLayerPrefix, pMessage, cb->data); } - pthread_mutex_unlock(&instance->callbacks_mutex); + mtx_unlock(&instance->debug_report.callbacks_mutex); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_DebugReportMessageEXT(VkInstance _instance, + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + debug_report(instance, flags, objectType, + object, location, messageCode, pLayerPrefix, pMessage); +} + +void +vk_debug_report(struct vk_instance *instance, + VkDebugReportFlagsEXT flags, + const struct vk_object_base *object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char *pMessage) +{ + VkDebugReportObjectTypeEXT object_type = + object ? object->type : VK_OBJECT_TYPE_UNKNOWN; + debug_report(instance, flags, object_type, (uint64_t)(uintptr_t)object, + location, messageCode, pLayerPrefix, pMessage); } diff --git a/lib/mesa/src/vulkan/util/vk_debug_report.h b/lib/mesa/src/vulkan/util/vk_debug_report.h index 625ecbb69..ca208bb5f 100644 --- a/lib/mesa/src/vulkan/util/vk_debug_report.h +++ b/lib/mesa/src/vulkan/util/vk_debug_report.h @@ -26,47 +26,23 @@ #ifndef VK_DEBUG_REPORT_H #define VK_DEBUG_REPORT_H -#include <pthread.h> +#include "vk_instance.h" -#include "util/list.h" -#include <vulkan/vulkan.h> - -struct vk_debug_report_callback { - /* Link in the 'callbacks' list in anv_instance struct. */ - struct list_head link; - VkDebugReportFlagsEXT flags; - PFN_vkDebugReportCallbackEXT callback; - void * data; -}; - -struct vk_debug_report_instance { - /* VK_EXT_debug_report debug callbacks */ - pthread_mutex_t callbacks_mutex; - struct list_head callbacks; -}; - -VkResult vk_debug_report_instance_init(struct vk_debug_report_instance *instance); -void vk_debug_report_instance_destroy(struct vk_debug_report_instance *instance); - -VkResult -vk_create_debug_report_callback(struct vk_debug_report_instance *instance, - const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - const VkAllocationCallbacks* instance_allocator, - VkDebugReportCallbackEXT* pCallback); -void -vk_destroy_debug_report_callback(struct vk_debug_report_instance *instance, - VkDebugReportCallbackEXT _callback, - const VkAllocationCallbacks* pAllocator, - const VkAllocationCallbacks* instance_allocator); +#ifdef __cplusplus +extern "C" { +#endif void -vk_debug_report(struct vk_debug_report_instance *instance, +vk_debug_report(struct vk_instance *instance, VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT object_type, - uint64_t handle, + const struct vk_object_base *object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char *pMessage); + +#ifdef __cplusplus +} #endif + +#endif /* VK_DEBUG_REPORT_H */ diff --git a/lib/mesa/src/vulkan/util/vk_deferred_operation.c b/lib/mesa/src/vulkan/util/vk_deferred_operation.c new file mode 100644 index 000000000..a9f6e0d26 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_deferred_operation.c @@ -0,0 +1,85 @@ +/* + * Copyright © 2020 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. + */ + +#include "vk_deferred_operation.h" + +#include "vk_alloc.h" +#include "vk_common_entrypoints.h" +#include "vk_device.h" + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_CreateDeferredOperationKHR(VkDevice _device, + const VkAllocationCallbacks *pAllocator, + VkDeferredOperationKHR *pDeferredOperation) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + struct vk_deferred_operation *op = + vk_alloc2(&device->alloc, pAllocator, sizeof(*op), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (op == NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + vk_object_base_init(device, &op->base, + VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR); + + *pDeferredOperation = vk_deferred_operation_to_handle(op); + + return VK_SUCCESS; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_DestroyDeferredOperationKHR(VkDevice _device, + VkDeferredOperationKHR operation, + const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(vk_device, device, _device); + VK_FROM_HANDLE(vk_deferred_operation, op, operation); + + if (op == NULL) + return; + + vk_object_base_finish(&op->base); + vk_free2(&device->alloc, pAllocator, op); +} + +VKAPI_ATTR uint32_t VKAPI_CALL +vk_common_GetDeferredOperationMaxConcurrencyKHR(UNUSED VkDevice device, + UNUSED VkDeferredOperationKHR operation) +{ + return 1; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_GetDeferredOperationResultKHR(UNUSED VkDevice device, + UNUSED VkDeferredOperationKHR operation) +{ + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_DeferredOperationJoinKHR(UNUSED VkDevice device, + UNUSED VkDeferredOperationKHR operation) +{ + return VK_SUCCESS; +} diff --git a/lib/mesa/src/vulkan/util/vk_deferred_operation.h b/lib/mesa/src/vulkan/util/vk_deferred_operation.h new file mode 100644 index 000000000..588db8085 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_deferred_operation.h @@ -0,0 +1,47 @@ +/* + * Copyright © 2020 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. + */ +#ifndef VK_DEFERRED_OPERATION_H +#define VK_DEFERRED_OPERATION_H + +#include "vk_object.h" + +#include "c11/threads.h" +#include "util/list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_deferred_operation { + struct vk_object_base base; +}; + +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_deferred_operation, base, + VkDeferredOperationKHR, + VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR) + +#ifdef __cplusplus +} +#endif + +#endif /* VK_DEFERRED_OPERATION_H */ diff --git a/lib/mesa/src/vulkan/util/vk_descriptors.c b/lib/mesa/src/vulkan/util/vk_descriptors.c new file mode 100644 index 000000000..7aee7e821 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_descriptors.c @@ -0,0 +1,56 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * 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. + */ + +#include <stdlib.h> +#include <string.h> +#include "vk_descriptors.h" +#include "util/macros.h" + +static int +binding_compare(const void* av, const void *bv) +{ + const VkDescriptorSetLayoutBinding *a = (const VkDescriptorSetLayoutBinding*)av; + const VkDescriptorSetLayoutBinding *b = (const VkDescriptorSetLayoutBinding*)bv; + + return (a->binding < b->binding) ? -1 : (a->binding > b->binding) ? 1 : 0; +} + +VkResult +vk_create_sorted_bindings(const VkDescriptorSetLayoutBinding *bindings, unsigned count, + VkDescriptorSetLayoutBinding **sorted_bindings) +{ + if (!count) { + *sorted_bindings = NULL; + return VK_SUCCESS; + } + + *sorted_bindings = malloc(count * sizeof(VkDescriptorSetLayoutBinding)); + if (!*sorted_bindings) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + memcpy(*sorted_bindings, bindings, count * sizeof(VkDescriptorSetLayoutBinding)); + qsort(*sorted_bindings, count, sizeof(VkDescriptorSetLayoutBinding), binding_compare); + + return VK_SUCCESS; +} diff --git a/lib/mesa/src/vulkan/util/vk_descriptors.h b/lib/mesa/src/vulkan/util/vk_descriptors.h new file mode 100644 index 000000000..a37eae8a7 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_descriptors.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * 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. + */ + +#ifndef VK_DESCRIPTORS_H +#define VK_DESCRIPTORS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <vulkan/vulkan.h> + +VkResult +vk_create_sorted_bindings(const VkDescriptorSetLayoutBinding *bindings, unsigned count, + VkDescriptorSetLayoutBinding **sorted_bindings); + +#ifdef __cplusplus +} +#endif + + + +#endif diff --git a/lib/mesa/src/vulkan/util/vk_device.c b/lib/mesa/src/vulkan/util/vk_device.c new file mode 100644 index 000000000..cfaebc58d --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_device.c @@ -0,0 +1,221 @@ +/* + * Copyright © 2020 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. + */ + +#include "vk_device.h" + +#include "vk_common_entrypoints.h" +#include "vk_instance.h" +#include "vk_physical_device.h" +#include "util/hash_table.h" +#include "util/ralloc.h" + +VkResult +vk_device_init(struct vk_device *device, + struct vk_physical_device *physical_device, + const struct vk_device_dispatch_table *dispatch_table, + const VkDeviceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *alloc) +{ + memset(device, 0, sizeof(*device)); + vk_object_base_init(device, &device->base, VK_OBJECT_TYPE_DEVICE); + if (alloc != NULL) + device->alloc = *alloc; + else + device->alloc = physical_device->instance->alloc; + + device->physical = physical_device; + + device->dispatch_table = *dispatch_table; + + /* Add common entrypoints without overwriting driver-provided ones. */ + vk_device_dispatch_table_from_entrypoints( + &device->dispatch_table, &vk_common_device_entrypoints, false); + + for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { + int idx; + for (idx = 0; idx < VK_DEVICE_EXTENSION_COUNT; idx++) { + if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], + vk_device_extensions[idx].extensionName) == 0) + break; + } + + if (idx >= VK_DEVICE_EXTENSION_COUNT) + return VK_ERROR_EXTENSION_NOT_PRESENT; + + if (!physical_device->supported_extensions.extensions[idx]) + return VK_ERROR_EXTENSION_NOT_PRESENT; + +#ifdef ANDROID + if (!vk_android_allowed_device_extensions.extensions[idx]) + return VK_ERROR_EXTENSION_NOT_PRESENT; +#endif + + device->enabled_extensions.extensions[idx] = true; + } + + p_atomic_set(&device->private_data_next_index, 0); + +#ifdef ANDROID + mtx_init(&device->swapchain_private_mtx, mtx_plain); + device->swapchain_private = NULL; +#endif /* ANDROID */ + + return VK_SUCCESS; +} + +void +vk_device_finish(UNUSED struct vk_device *device) +{ +#ifdef ANDROID + if (device->swapchain_private) { + hash_table_foreach(device->swapchain_private, entry) + util_sparse_array_finish(entry->data); + ralloc_free(device->swapchain_private); + } +#endif /* ANDROID */ + + vk_object_base_finish(&device->base); +} + +PFN_vkVoidFunction +vk_device_get_proc_addr(const struct vk_device *device, + const char *name) +{ + if (device == NULL || name == NULL) + return NULL; + + struct vk_instance *instance = device->physical->instance; + return vk_device_dispatch_table_get_if_supported(&device->dispatch_table, + name, + instance->app_info.api_version, + &instance->enabled_extensions, + &device->enabled_extensions); +} + +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL +vk_common_GetDeviceProcAddr(VkDevice _device, + const char *pName) +{ + VK_FROM_HANDLE(vk_device, device, _device); + return vk_device_get_proc_addr(device, pName); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetDeviceQueue(VkDevice _device, + uint32_t queueFamilyIndex, + uint32_t queueIndex, + VkQueue *pQueue) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + const VkDeviceQueueInfo2 info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, + .pNext = NULL, + /* flags = 0 because (Vulkan spec 1.2.170 - vkGetDeviceQueue): + * + * "vkGetDeviceQueue must only be used to get queues that were + * created with the flags parameter of VkDeviceQueueCreateInfo set + * to zero. To get queues that were created with a non-zero flags + * parameter use vkGetDeviceQueue2." + */ + .flags = 0, + .queueFamilyIndex = queueFamilyIndex, + .queueIndex = queueIndex, + }; + + device->dispatch_table.GetDeviceQueue2(_device, &info, pQueue); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetBufferMemoryRequirements(VkDevice _device, + VkBuffer buffer, + VkMemoryRequirements *pMemoryRequirements) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + VkBufferMemoryRequirementsInfo2 info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, + .buffer = buffer, + }; + VkMemoryRequirements2 reqs = { + .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, + }; + device->dispatch_table.GetBufferMemoryRequirements2(_device, &info, &reqs); + + *pMemoryRequirements = reqs.memoryRequirements; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_BindBufferMemory(VkDevice _device, + VkBuffer buffer, + VkDeviceMemory memory, + VkDeviceSize memoryOffset) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + VkBindBufferMemoryInfo bind = { + .sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, + .buffer = buffer, + .memory = memory, + .memoryOffset = memoryOffset, + }; + + return device->dispatch_table.BindBufferMemory2(_device, 1, &bind); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetImageMemoryRequirements(VkDevice _device, + VkImage image, + VkMemoryRequirements *pMemoryRequirements) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + VkImageMemoryRequirementsInfo2 info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, + .image = image, + }; + VkMemoryRequirements2 reqs = { + .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, + }; + device->dispatch_table.GetImageMemoryRequirements2(_device, &info, &reqs); + + *pMemoryRequirements = reqs.memoryRequirements; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_BindImageMemory(VkDevice _device, + VkImage image, + VkDeviceMemory memory, + VkDeviceSize memoryOffset) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + VkBindImageMemoryInfo bind = { + .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, + .image = image, + .memory = memory, + .memoryOffset = memoryOffset, + }; + + return device->dispatch_table.BindImageMemory2(_device, 1, &bind); +} diff --git a/lib/mesa/src/vulkan/util/vk_device.h b/lib/mesa/src/vulkan/util/vk_device.h new file mode 100644 index 000000000..e31688475 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_device.h @@ -0,0 +1,73 @@ +/* + * Copyright © 2020 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. + */ +#ifndef VK_DEVICE_H +#define VK_DEVICE_H + +#include "vk_dispatch_table.h" +#include "vk_extensions.h" +#include "vk_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_device { + struct vk_object_base base; + VkAllocationCallbacks alloc; + struct vk_physical_device *physical; + + struct vk_device_extension_table enabled_extensions; + + struct vk_device_dispatch_table dispatch_table; + + /* For VK_EXT_private_data */ + uint32_t private_data_next_index; + +#ifdef ANDROID + mtx_t swapchain_private_mtx; + struct hash_table *swapchain_private; +#endif +}; + +VK_DEFINE_HANDLE_CASTS(vk_device, base, VkDevice, + VK_OBJECT_TYPE_DEVICE) + +VkResult MUST_CHECK +vk_device_init(struct vk_device *device, + struct vk_physical_device *physical_device, + const struct vk_device_dispatch_table *dispatch_table, + const VkDeviceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *alloc); + +void +vk_device_finish(struct vk_device *device); + +PFN_vkVoidFunction +vk_device_get_proc_addr(const struct vk_device *device, + const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* VK_DEVICE_H */ diff --git a/lib/mesa/src/vulkan/util/vk_dispatch_table_gen.py b/lib/mesa/src/vulkan/util/vk_dispatch_table_gen.py new file mode 100644 index 000000000..7b566ba0f --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_dispatch_table_gen.py @@ -0,0 +1,929 @@ +# coding=utf-8 +COPYRIGHT = """\ +/* + * Copyright 2020 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 math +import os +import xml.etree.ElementTree as et + +from collections import OrderedDict, namedtuple +from mako.template import Template + +# Mesa-local imports must be declared in meson variable +# '{file_without_suffix}_depend_files'. +from vk_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(COPYRIGHT + """\ +/* This file generated from ${filename}, don't edit directly. */ + +#ifndef VK_DISPATCH_TABLE_H +#define VK_DISPATCH_TABLE_H + +#include "vulkan/vulkan.h" +#include "vulkan/vk_android_native_buffer.h" + +#include "vk_extensions.h" + +/* Windows api conflict */ +#ifdef _WIN32 +#ifdef CreateSemaphore +#undef CreateSemaphore +#endif +#ifdef CreateEvent +#undef CreateEvent +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +<%def name="dispatch_table(type, entrypoints)"> +struct vk_${type}_dispatch_table { +% for e in entrypoints: + % if e.alias: + <% continue %> + % endif + % if e.guard is not None: +#ifdef ${e.guard} + % endif + % if e.aliases: + union { + PFN_vk${e.name} ${e.name}; + % for a in e.aliases: + PFN_vk${a.name} ${a.name}; + % endfor + }; + % else: + PFN_vk${e.name} ${e.name}; + % endif + % if e.guard is not None: +#else + % if e.aliases: + union { + PFN_vkVoidFunction ${e.name}; + % for a in e.aliases: + PFN_vkVoidFunction ${a.name}; + % endfor + }; + % else: + PFN_vkVoidFunction ${e.name}; + % endif +#endif + % endif +% endfor +}; + +struct vk_${type}_entrypoint_table { +% for e in entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} + % endif + PFN_vk${e.name} ${e.name}; + % if e.guard is not None: +#else + PFN_vkVoidFunction ${e.name}; +# endif + % endif +% endfor +}; +</%def> + +${dispatch_table('instance', instance_entrypoints)} +${dispatch_table('physical_device', physical_device_entrypoints)} +${dispatch_table('device', device_entrypoints)} + +void +vk_instance_dispatch_table_load(struct vk_instance_dispatch_table *table, + PFN_vkGetInstanceProcAddr gpa, + VkInstance instance); +void +vk_physical_device_dispatch_table_load(struct vk_physical_device_dispatch_table *table, + PFN_vkGetInstanceProcAddr gpa, + VkInstance instance); +void +vk_device_dispatch_table_load(struct vk_device_dispatch_table *table, + PFN_vkGetDeviceProcAddr gpa, + VkDevice device); + +void vk_instance_dispatch_table_from_entrypoints( + struct vk_instance_dispatch_table *dispatch_table, + const struct vk_instance_entrypoint_table *entrypoint_table, + bool overwrite); + +void vk_physical_device_dispatch_table_from_entrypoints( + struct vk_physical_device_dispatch_table *dispatch_table, + const struct vk_physical_device_entrypoint_table *entrypoint_table, + bool overwrite); + +void vk_device_dispatch_table_from_entrypoints( + struct vk_device_dispatch_table *dispatch_table, + const struct vk_device_entrypoint_table *entrypoint_table, + bool overwrite); + +PFN_vkVoidFunction +vk_instance_dispatch_table_get(const struct vk_instance_dispatch_table *table, + const char *name); + +PFN_vkVoidFunction +vk_physical_device_dispatch_table_get(const struct vk_physical_device_dispatch_table *table, + const char *name); + +PFN_vkVoidFunction +vk_device_dispatch_table_get(const struct vk_device_dispatch_table *table, + const char *name); + +PFN_vkVoidFunction +vk_instance_dispatch_table_get_if_supported( + const struct vk_instance_dispatch_table *table, + const char *name, + uint32_t core_version, + const struct vk_instance_extension_table *instance_exts); + +PFN_vkVoidFunction +vk_physical_device_dispatch_table_get_if_supported( + const struct vk_physical_device_dispatch_table *table, + const char *name, + uint32_t core_version, + const struct vk_instance_extension_table *instance_exts); + +PFN_vkVoidFunction +vk_device_dispatch_table_get_if_supported( + const struct vk_device_dispatch_table *table, + const char *name, + uint32_t core_version, + const struct vk_instance_extension_table *instance_exts, + const struct vk_device_extension_table *device_exts); + +extern struct vk_physical_device_dispatch_table vk_physical_device_trampolines; +extern struct vk_device_dispatch_table vk_device_trampolines; + +#ifdef __cplusplus +} +#endif + +#endif /* VK_DISPATCH_TABLE_H */ +""", output_encoding='utf-8') + +TEMPLATE_C = Template(COPYRIGHT + """\ +/* This file generated from ${filename}, don't edit directly. */ + +#include "vk_device.h" +#include "vk_dispatch_table.h" +#include "vk_instance.h" +#include "vk_object.h" +#include "vk_physical_device.h" + +#include "util/macros.h" +#include "string.h" + +<%def name="load_dispatch_table(type, VkType, ProcAddr, entrypoints)"> +void +vk_${type}_dispatch_table_load(struct vk_${type}_dispatch_table *table, + PFN_vk${ProcAddr} gpa, + ${VkType} obj) +{ +% if type != 'physical_device': + table->${ProcAddr} = gpa; +% endif +% for e in entrypoints: + % if e.alias or e.name == '${ProcAddr}': + <% continue %> + % endif + % if e.guard is not None: +#ifdef ${e.guard} + % endif + table->${e.name} = (PFN_vk${e.name}) gpa(obj, "vk${e.name}"); + % for a in e.aliases: + if (table->${e.name} == NULL) { + table->${e.name} = (PFN_vk${e.name}) gpa(obj, "vk${a.name}"); + } + % endfor + % if e.guard is not None: +#endif + % endif +% endfor +} +</%def> + +${load_dispatch_table('instance', 'VkInstance', 'GetInstanceProcAddr', + instance_entrypoints)} + +${load_dispatch_table('physical_device', 'VkInstance', 'GetInstanceProcAddr', + physical_device_entrypoints)} + +${load_dispatch_table('device', 'VkDevice', 'GetDeviceProcAddr', + device_entrypoints)} + + +struct string_map_entry { + uint32_t name; + uint32_t hash; + uint32_t num; +}; + +/* 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. + */ + +<%def name="strmap(strmap, prefix)"> +static const char ${prefix}_strings[] = +% for s in strmap.sorted_strings: + "${s.string}\\0" +% endfor +; + +static const struct string_map_entry ${prefix}_string_map_entries[] = { +% for s in strmap.sorted_strings: + { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */ +% endfor +}; + +/* Hash table stats: + * size ${len(strmap.sorted_strings)} entries + * collisions entries: +% for i in range(10): + * ${i}${'+' if i == 9 else ' '} ${strmap.collisions[i]} +% endfor + */ + +#define none 0xffff +static const uint16_t ${prefix}_string_map[${strmap.hash_size}] = { +% for e in strmap.mapping: + ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' }, +% endfor +}; + +static int +${prefix}_string_map_lookup(const char *str) +{ + static const uint32_t prime_factor = ${strmap.prime_factor}; + static const uint32_t prime_step = ${strmap.prime_step}; + const struct string_map_entry *e; + uint32_t hash, h; + uint16_t i; + const char *p; + + hash = 0; + for (p = str; *p; p++) + hash = hash * prime_factor + *p; + + h = hash; + while (1) { + i = ${prefix}_string_map[h & ${strmap.hash_mask}]; + if (i == none) + return -1; + e = &${prefix}_string_map_entries[i]; + if (e->hash == hash && strcmp(str, ${prefix}_strings + e->name) == 0) + return e->num; + h += prime_step; + } + + return -1; +} +</%def> + +${strmap(instance_strmap, 'instance')} +${strmap(physical_device_strmap, 'physical_device')} +${strmap(device_strmap, 'device')} + +<% assert len(instance_entrypoints) < 2**8 %> +static const uint8_t instance_compaction_table[] = { +% for e in instance_entrypoints: + ${e.disp_table_index}, +% endfor +}; + +<% assert len(physical_device_entrypoints) < 2**8 %> +static const uint8_t physical_device_compaction_table[] = { +% for e in physical_device_entrypoints: + ${e.disp_table_index}, +% endfor +}; + +<% assert len(device_entrypoints) < 2**16 %> +static const uint16_t device_compaction_table[] = { +% for e in device_entrypoints: + ${e.disp_table_index}, +% endfor +}; + +static bool +vk_instance_entrypoint_is_enabled(int index, uint32_t core_version, + const struct vk_instance_extension_table *instance) +{ + switch (index) { +% for e in instance_entrypoints: + case ${e.entry_table_index}: + /* ${e.name} */ + % if e.core_version: + return ${e.core_version.c_vk_version()} <= core_version; + % elif e.extensions: + % for ext in e.extensions: + % if ext.type == 'instance': + if (instance->${ext.name[3:]}) return true; + % else: + /* All device extensions are considered enabled at the instance level */ + return true; + % endif + % endfor + return false; + % else: + return true; + % endif +% endfor + default: + return false; + } +} + +/** Return true if the core version or extension in which the given entrypoint + * is defined is enabled. + * + * If device is NULL, all device extensions are considered enabled. + */ +static bool +vk_physical_device_entrypoint_is_enabled(int index, uint32_t core_version, + const struct vk_instance_extension_table *instance) +{ + switch (index) { +% for e in physical_device_entrypoints: + case ${e.entry_table_index}: + /* ${e.name} */ + % if e.core_version: + return ${e.core_version.c_vk_version()} <= core_version; + % elif e.extensions: + % for ext in e.extensions: + % if ext.type == 'instance': + if (instance->${ext.name[3:]}) return true; + % else: + /* All device extensions are considered enabled at the instance level */ + return true; + % endif + % endfor + return false; + % else: + return true; + % endif +% endfor + default: + return false; + } +} + +/** Return true if the core version or extension in which the given entrypoint + * is defined is enabled. + * + * If device is NULL, all device extensions are considered enabled. + */ +static bool +vk_device_entrypoint_is_enabled(int index, uint32_t core_version, + const struct vk_instance_extension_table *instance, + const struct vk_device_extension_table *device) +{ + switch (index) { +% for e in device_entrypoints: + case ${e.entry_table_index}: + /* ${e.name} */ + % if e.core_version: + return ${e.core_version.c_vk_version()} <= core_version; + % elif e.extensions: + % for ext in e.extensions: + % if ext.type == 'instance': + if (instance->${ext.name[3:]}) return true; + % else: + if (!device || device->${ext.name[3:]}) return true; + % endif + % endfor + return false; + % else: + return true; + % endif +% endfor + default: + return false; + } +} + +<%def name="dispatch_table_from_entrypoints(type)"> +void vk_${type}_dispatch_table_from_entrypoints( + struct vk_${type}_dispatch_table *dispatch_table, + const struct vk_${type}_entrypoint_table *entrypoint_table, + bool overwrite) +{ + PFN_vkVoidFunction *disp = (PFN_vkVoidFunction *)dispatch_table; + PFN_vkVoidFunction *entry = (PFN_vkVoidFunction *)entrypoint_table; + + if (overwrite) { + memset(dispatch_table, 0, sizeof(*dispatch_table)); + for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) { +#ifdef _MSC_VER + const uintptr_t zero = 0; + if (entry[i] == NULL || memcmp(entry[i], &zero, sizeof(zero)) == 0) +#else + if (entry[i] == NULL) +#endif + continue; + unsigned disp_index = ${type}_compaction_table[i]; + assert(disp[disp_index] == NULL); + disp[disp_index] = entry[i]; + } + } else { + for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) { + unsigned disp_index = ${type}_compaction_table[i]; + if (disp[disp_index] == NULL) + disp[disp_index] = entry[i]; + } + } +} +</%def> + +${dispatch_table_from_entrypoints('instance')} +${dispatch_table_from_entrypoints('physical_device')} +${dispatch_table_from_entrypoints('device')} + +<%def name="lookup_funcs(type)"> +static PFN_vkVoidFunction +vk_${type}_dispatch_table_get_for_entry_index( + const struct vk_${type}_dispatch_table *table, int entry_index) +{ + assert(entry_index < ARRAY_SIZE(${type}_compaction_table)); + int disp_index = ${type}_compaction_table[entry_index]; + return ((PFN_vkVoidFunction *)table)[disp_index]; +} + +PFN_vkVoidFunction +vk_${type}_dispatch_table_get( + const struct vk_${type}_dispatch_table *table, const char *name) +{ + int entry_index = ${type}_string_map_lookup(name); + if (entry_index < 0) + return NULL; + + return vk_${type}_dispatch_table_get_for_entry_index(table, entry_index); +} +</%def> + +${lookup_funcs('instance')} +${lookup_funcs('physical_device')} +${lookup_funcs('device')} + +PFN_vkVoidFunction +vk_instance_dispatch_table_get_if_supported( + const struct vk_instance_dispatch_table *table, + const char *name, + uint32_t core_version, + const struct vk_instance_extension_table *instance_exts) +{ + int entry_index = instance_string_map_lookup(name); + if (entry_index < 0) + return NULL; + + if (!vk_instance_entrypoint_is_enabled(entry_index, core_version, + instance_exts)) + return NULL; + + return vk_instance_dispatch_table_get_for_entry_index(table, entry_index); +} + +PFN_vkVoidFunction +vk_physical_device_dispatch_table_get_if_supported( + const struct vk_physical_device_dispatch_table *table, + const char *name, + uint32_t core_version, + const struct vk_instance_extension_table *instance_exts) +{ + int entry_index = physical_device_string_map_lookup(name); + if (entry_index < 0) + return NULL; + + if (!vk_physical_device_entrypoint_is_enabled(entry_index, core_version, + instance_exts)) + return NULL; + + return vk_physical_device_dispatch_table_get_for_entry_index(table, entry_index); +} + +PFN_vkVoidFunction +vk_device_dispatch_table_get_if_supported( + const struct vk_device_dispatch_table *table, + const char *name, + uint32_t core_version, + const struct vk_instance_extension_table *instance_exts, + const struct vk_device_extension_table *device_exts) +{ + int entry_index = device_string_map_lookup(name); + if (entry_index < 0) + return NULL; + + if (!vk_device_entrypoint_is_enabled(entry_index, core_version, + instance_exts, device_exts)) + return NULL; + + return vk_device_dispatch_table_get_for_entry_index(table, entry_index); +} + +% for e in physical_device_entrypoints: + % if e.alias: + <% continue %> + % endif + % if e.guard is not None: +#ifdef ${e.guard} + % endif +static VKAPI_ATTR ${e.return_type} VKAPI_CALL +${e.prefixed_name('vk_tramp')}(${e.decl_params()}) +{ + <% assert e.params[0].type == 'VkPhysicalDevice' %> + VK_FROM_HANDLE(vk_physical_device, vk_physical_device, ${e.params[0].name}); + % if e.return_type == 'void': + vk_physical_device->dispatch_table.${e.name}(${e.call_params()}); + % else: + return vk_physical_device->dispatch_table.${e.name}(${e.call_params()}); + % endif +} + % if e.guard is not None: +#endif + % endif +% endfor + +struct vk_physical_device_dispatch_table vk_physical_device_trampolines = { +% for e in physical_device_entrypoints: + % if e.alias: + <% continue %> + % endif + % if e.guard is not None: +#ifdef ${e.guard} + % endif + .${e.name} = ${e.prefixed_name('vk_tramp')}, + % if e.guard is not None: +#endif + % endif +% endfor +}; + +% for e in device_entrypoints: + % if e.alias: + <% continue %> + % endif + % if e.guard is not None: +#ifdef ${e.guard} + % endif +static VKAPI_ATTR ${e.return_type} VKAPI_CALL +${e.prefixed_name('vk_tramp')}(${e.decl_params()}) +{ + % if e.params[0].type == 'VkDevice': + VK_FROM_HANDLE(vk_device, vk_device, ${e.params[0].name}); + % if e.return_type == 'void': + vk_device->dispatch_table.${e.name}(${e.call_params()}); + % else: + return vk_device->dispatch_table.${e.name}(${e.call_params()}); + % endif + % elif e.params[0].type in ('VkCommandBuffer', 'VkQueue'): + struct vk_object_base *vk_object = (struct vk_object_base *)${e.params[0].name}; + % if e.return_type == 'void': + vk_object->device->dispatch_table.${e.name}(${e.call_params()}); + % else: + return vk_object->device->dispatch_table.${e.name}(${e.call_params()}); + % endif + % else: + assert(!"Unhandled device child trampoline case: ${e.params[0].type}"); + % endif +} + % if e.guard is not None: +#endif + % endif +% endfor + +struct vk_device_dispatch_table vk_device_trampolines = { +% for e in device_entrypoints: + % if e.alias: + <% continue %> + % endif + % if e.guard is not None: +#ifdef ${e.guard} + % endif + .${e.name} = ${e.prefixed_name('vk_tramp')}, + % if e.guard is not None: +#endif + % endif +% endfor +}; +""", output_encoding='utf-8') + +U32_MASK = 2**32 - 1 + +PRIME_FACTOR = 5024183 +PRIME_STEP = 19 + +class StringIntMapEntry(object): + def __init__(self, string, num): + self.string = string + self.num = num + + # Calculate the same hash value that we will calculate in C. + h = 0 + for c in string: + h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK + self.hash = h + + self.offset = None + +def round_to_pow2(x): + return 2**int(math.ceil(math.log(x, 2))) + +class StringIntMap(object): + def __init__(self): + self.baked = False + self.strings = dict() + + def add_string(self, string, num): + assert not self.baked + assert string not in self.strings + assert 0 <= num < 2**31 + self.strings[string] = StringIntMapEntry(string, num) + + def bake(self): + self.sorted_strings = \ + sorted(self.strings.values(), key=lambda x: x.string) + offset = 0 + for entry in self.sorted_strings: + entry.offset = offset + offset += len(entry.string) + 1 + + # Save off some values that we'll need in C + self.hash_size = round_to_pow2(len(self.strings) * 1.25) + self.hash_mask = self.hash_size - 1 + self.prime_factor = PRIME_FACTOR + self.prime_step = PRIME_STEP + + self.mapping = [-1] * self.hash_size + self.collisions = [0] * 10 + for idx, s in enumerate(self.sorted_strings): + level = 0 + h = s.hash + while self.mapping[h & self.hash_mask] >= 0: + h = h + PRIME_STEP + level = level + 1 + self.collisions[min(level, 9)] += 1 + self.mapping[h & self.hash_mask] = idx + +EntrypointParam = namedtuple('EntrypointParam', 'type name decl') + +class EntrypointBase(object): + def __init__(self, name): + assert name.startswith('vk') + self.name = name[2:] + self.alias = None + self.guard = None + self.entry_table_index = None + # Extensions which require this entrypoint + self.core_version = None + self.extensions = [] + + def prefixed_name(self, prefix): + return prefix + '_' + self.name + +class Entrypoint(EntrypointBase): + def __init__(self, name, return_type, params, guard=None): + super(Entrypoint, self).__init__(name) + self.return_type = return_type + self.params = params + self.guard = guard + self.aliases = [] + self.disp_table_index = None + + def is_physical_device_entrypoint(self): + return self.params[0].type in ('VkPhysicalDevice', ) + + def is_device_entrypoint(self): + return self.params[0].type in ('VkDevice', 'VkCommandBuffer', 'VkQueue') + + def decl_params(self): + return ', '.join(p.decl for p in self.params) + + def call_params(self): + return ', '.join(p.name for p in self.params) + +class EntrypointAlias(EntrypointBase): + def __init__(self, name, entrypoint): + super(EntrypointAlias, self).__init__(name) + self.alias = entrypoint + entrypoint.aliases.append(self) + + def is_physical_device_entrypoint(self): + return self.alias.is_physical_device_entrypoint() + + def is_device_entrypoint(self): + return self.alias.is_device_entrypoint() + + def prefixed_name(self, prefix): + return self.alias.prefixed_name(prefix) + + @property + def params(self): + return self.alias.params + + @property + def return_type(self): + return self.alias.return_type + + @property + def disp_table_index(self): + return self.alias.disp_table_index + + def decl_params(self): + return self.alias.decl_params() + + def call_params(self): + return self.alias.call_params() + +def get_entrypoints(doc, entrypoints_to_defines): + """Extract the entry points from the registry.""" + entrypoints = OrderedDict() + + for command in doc.findall('./commands/command'): + if 'alias' in command.attrib: + alias = command.attrib['name'] + target = command.attrib['alias'] + entrypoints[alias] = EntrypointAlias(alias, entrypoints[target]) + else: + name = command.find('./proto/name').text + ret_type = command.find('./proto/type').text + params = [EntrypointParam( + type=p.find('./type').text, + name=p.find('./name').text, + decl=''.join(p.itertext()) + ) for p in command.findall('./param')] + guard = entrypoints_to_defines.get(name) + # They really need to be unique + assert name not in entrypoints + entrypoints[name] = Entrypoint(name, ret_type, params, guard) + + for feature in doc.findall('./feature'): + assert feature.attrib['api'] == 'vulkan' + version = VkVersion(feature.attrib['number']) + for command in feature.findall('./require/command'): + e = entrypoints[command.attrib['name']] + assert e.core_version is None + e.core_version = version + + for extension in doc.findall('.extensions/extension'): + if extension.attrib['supported'] != 'vulkan': + continue + + ext_name = extension.attrib['name'] + + ext = Extension(ext_name, 1, True) + ext.type = extension.attrib['type'] + + for command in extension.findall('./require/command'): + e = entrypoints[command.attrib['name']] + assert e.core_version is None + e.extensions.append(ext) + + return entrypoints.values() + + +def get_entrypoints_defines(doc): + """Maps entry points to extension defines.""" + entrypoints_to_defines = {} + + platform_define = {} + for platform in doc.findall('./platforms/platform'): + name = platform.attrib['name'] + define = platform.attrib['protect'] + platform_define[name] = define + + for extension in doc.findall('./extensions/extension[@platform]'): + platform = extension.attrib['platform'] + define = platform_define[platform] + + for entrypoint in extension.findall('./require/command'): + fullname = entrypoint.attrib['name'] + entrypoints_to_defines[fullname] = define + + return entrypoints_to_defines + +def get_entrypoints_from_xml(xml_files): + entrypoints = [] + + for filename in xml_files: + doc = et.parse(filename) + entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc)) + + return entrypoints + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--out-c', help='Output C file.') + parser.add_argument('--out-h', help='Output H file.') + parser.add_argument('--xml', + help='Vulkan API XML file.', + required=True, + action='append', + dest='xml_files') + args = parser.parse_args() + + entrypoints = get_entrypoints_from_xml(args.xml_files) + + device_entrypoints = [] + physical_device_entrypoints = [] + instance_entrypoints = [] + for e in entrypoints: + if e.is_device_entrypoint(): + device_entrypoints.append(e) + elif e.is_physical_device_entrypoint(): + physical_device_entrypoints.append(e) + else: + instance_entrypoints.append(e) + + for i, e in enumerate(e for e in device_entrypoints if not e.alias): + e.disp_table_index = i + + device_strmap = StringIntMap() + for i, e in enumerate(device_entrypoints): + e.entry_table_index = i + device_strmap.add_string("vk" + e.name, e.entry_table_index) + device_strmap.bake() + + for i, e in enumerate(e for e in physical_device_entrypoints if not e.alias): + e.disp_table_index = i + + physical_device_strmap = StringIntMap() + for i, e in enumerate(physical_device_entrypoints): + e.entry_table_index = i + physical_device_strmap.add_string("vk" + e.name, e.entry_table_index) + physical_device_strmap.bake() + + for i, e in enumerate(e for e in instance_entrypoints if not e.alias): + e.disp_table_index = i + + instance_strmap = StringIntMap() + for i, e in enumerate(instance_entrypoints): + e.entry_table_index = i + instance_strmap.add_string("vk" + e.name, e.entry_table_index) + instance_strmap.bake() + + # For outputting entrypoints.h we generate a anv_EntryPoint() prototype + # per entry point. + try: + if args.out_h: + with open(args.out_h, 'wb') as f: + f.write(TEMPLATE_H.render(instance_entrypoints=instance_entrypoints, + physical_device_entrypoints=physical_device_entrypoints, + device_entrypoints=device_entrypoints, + filename=os.path.basename(__file__))) + if args.out_c: + with open(args.out_c, 'wb') as f: + f.write(TEMPLATE_C.render(instance_entrypoints=instance_entrypoints, + physical_device_entrypoints=physical_device_entrypoints, + device_entrypoints=device_entrypoints, + instance_strmap=instance_strmap, + physical_device_strmap=physical_device_strmap, + device_strmap=device_strmap, + filename=os.path.basename(__file__))) + except Exception: + # In the event there's an error, this imports some helpers from mako + # to print a useful stack trace and prints it, then exits with + # status 1, if python is run with debug; otherwise it just raises + # the exception + if __debug__: + import sys + from mako import exceptions + sys.stderr.write(exceptions.text_error_template().render() + '\n') + sys.exit(1) + raise + + +if __name__ == '__main__': + main() diff --git a/lib/mesa/src/vulkan/util/vk_entrypoints_gen.py b/lib/mesa/src/vulkan/util/vk_entrypoints_gen.py new file mode 100644 index 000000000..a663d10e1 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_entrypoints_gen.py @@ -0,0 +1,258 @@ +# coding=utf-8 +COPYRIGHT=u""" +/* Copyright © 2015-2021 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. + */ +""" + +import argparse +import os + +from mako.template import Template + +# Mesa-local imports must be declared in meson variable +# '{file_without_suffix}_depend_files'. +from vk_dispatch_table_gen import get_entrypoints_from_xml + +TEMPLATE_H = Template(COPYRIGHT + """\ +/* This file generated from ${filename}, don't edit directly. */ + +#include "vk_dispatch_table.h" + +#ifndef ${guard} +#define ${guard} + +#ifdef __cplusplus +extern "C" { +#endif + +% for p in instance_prefixes: +extern const struct vk_instance_entrypoint_table ${p}_instance_entrypoints; +% endfor + +% for p in physical_device_prefixes: +extern const struct vk_physical_device_entrypoint_table ${p}_physical_device_entrypoints; +% endfor + +% for p in device_prefixes: +extern const struct vk_device_entrypoint_table ${p}_device_entrypoints; +% endfor + +% if gen_proto: +% for e in instance_entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} + % endif + % for p in physical_device_prefixes: + VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}); + % endfor + % if e.guard is not None: +#endif // ${e.guard} + % endif +% endfor + +% for e in physical_device_entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} + % endif + % for p in physical_device_prefixes: + VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}); + % endfor + % if e.guard is not None: +#endif // ${e.guard} + % endif +% endfor + +% for e in device_entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} + % endif + % for p in device_prefixes: + VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}); + % endfor + % if e.guard is not None: +#endif // ${e.guard} + % endif +% endfor +% endif + +#ifdef __cplusplus +} +#endif + +#endif /* ${guard} */ +""", output_encoding='utf-8') + +TEMPLATE_C = Template(COPYRIGHT + """ +/* This file generated from ${filename}, don't edit directly. */ + +#include "${header}" + +/* 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. + * + * MSVC uses different decorated names for 32-bit versus 64-bit. Declare + * all argument sizes for 32-bit because computing the actual size would be + * difficult. + */ + +<%def name="entrypoint_table(type, entrypoints, prefixes)"> +% if gen_weak: + % for e in entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} + % endif + % for p in prefixes: +#ifdef _MSC_VER + ${e.return_type} (*${p}_${e.name}_Null)(${e.decl_params()}) = 0; +#ifdef _M_IX86 + % for args_size in [4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 60, 104]: + #pragma comment(linker, "/alternatename:_${p}_${e.name}@${args_size}=_${p}_${e.name}_Null") + % endfor +#else + #pragma comment(linker, "/alternatename:${p}_${e.name}=${p}_${e.name}_Null") +#endif +#else + VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}) __attribute__ ((weak)); +#endif + % endfor + % if e.guard is not None: +#endif // ${e.guard} + % endif + % endfor +% endif + +% for p in prefixes: +const struct vk_${type}_entrypoint_table ${p}_${type}_entrypoints = { + % for e in entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} + % endif + .${e.name} = ${p}_${e.name}, + % if e.guard is not None: +#endif // ${e.guard} + % endif + % endfor +}; +% endfor +</%def> + +${entrypoint_table('instance', instance_entrypoints, instance_prefixes)} +${entrypoint_table('physical_device', physical_device_entrypoints, physical_device_prefixes)} +${entrypoint_table('device', device_entrypoints, device_prefixes)} +""", output_encoding='utf-8') + +def get_entrypoints_defines(doc): + """Maps entry points to extension defines.""" + entrypoints_to_defines = {} + + platform_define = {} + for platform in doc.findall('./platforms/platform'): + name = platform.attrib['name'] + define = platform.attrib['protect'] + platform_define[name] = define + + for extension in doc.findall('./extensions/extension[@platform]'): + platform = extension.attrib['platform'] + define = platform_define[platform] + + for entrypoint in extension.findall('./require/command'): + fullname = entrypoint.attrib['name'] + entrypoints_to_defines[fullname] = define + + return entrypoints_to_defines + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--out-c', required=True, help='Output C file.') + parser.add_argument('--out-h', required=True, help='Output H file.') + parser.add_argument('--xml', + help='Vulkan API XML file.', + required=True, action='append', dest='xml_files') + parser.add_argument('--proto', help='Generate entrypoint prototypes', + action='store_true', dest='gen_proto') + parser.add_argument('--weak', help='Generate weak entrypoint declarations', + action='store_true', dest='gen_weak') + parser.add_argument('--prefix', + help='Prefix to use for all dispatch tables.', + action='append', default=[], dest='prefixes') + parser.add_argument('--device-prefix', + help='Prefix to use for device dispatch tables.', + action='append', default=[], dest='device_prefixes') + args = parser.parse_args() + + instance_prefixes = args.prefixes + physical_device_prefixes = args.prefixes + device_prefixes = args.prefixes + args.device_prefixes + + entrypoints = get_entrypoints_from_xml(args.xml_files) + + device_entrypoints = [] + physical_device_entrypoints = [] + instance_entrypoints = [] + for e in entrypoints: + if e.is_device_entrypoint(): + device_entrypoints.append(e) + elif e.is_physical_device_entrypoint(): + physical_device_entrypoints.append(e) + else: + instance_entrypoints.append(e) + + assert os.path.dirname(args.out_c) == os.path.dirname(args.out_h) + + environment = { + 'gen_proto': args.gen_proto, + 'gen_weak': args.gen_weak, + 'header': os.path.basename(args.out_h), + 'instance_entrypoints': instance_entrypoints, + 'instance_prefixes': instance_prefixes, + 'physical_device_entrypoints': physical_device_entrypoints, + 'physical_device_prefixes': physical_device_prefixes, + 'device_entrypoints': device_entrypoints, + 'device_prefixes': device_prefixes, + 'filename': os.path.basename(__file__), + } + + # For outputting entrypoints.h we generate a anv_EntryPoint() prototype + # per entry point. + try: + with open(args.out_h, 'wb') as f: + guard = os.path.basename(args.out_h).replace('.', '_').upper() + f.write(TEMPLATE_H.render(guard=guard, **environment)) + with open(args.out_c, 'wb') as f: + f.write(TEMPLATE_C.render(**environment)) + + except Exception: + # In the event there's an error, this imports some helpers from mako + # to print a useful stack trace and prints it, then exits with + # status 1, if python is run with debug; otherwise it just raises + # the exception + if __debug__: + import sys + from mako import exceptions + sys.stderr.write(exceptions.text_error_template().render() + '\n') + sys.exit(1) + raise + +if __name__ == '__main__': + main() diff --git a/lib/mesa/src/vulkan/util/vk_extensions.py b/lib/mesa/src/vulkan/util/vk_extensions.py new file mode 100644 index 000000000..852951f05 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_extensions.py @@ -0,0 +1,214 @@ +import argparse +import copy +import re +import xml.etree.ElementTree as et + +def _bool_to_c_expr(b): + if b is True: + return 'true' + if b is False: + return 'false' + return b + +class Extension: + def __init__(self, name, ext_version, enable): + self.name = name + self.ext_version = int(ext_version) + self.enable = _bool_to_c_expr(enable) + + 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, enable): + self.version = version + self.enable = _bool_to_c_expr(enable) + +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): + patch = self.patch if self.patch is not None else 0 + ver_list = [str(self.major), str(self.minor), str(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 __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): + """ Get a list of all Vulkan extensions. """ + + xml = et.parse(xml) + + extensions = [] + for ext_elem in xml.findall('.extensions/extension'): + supported = ext_elem.attrib['supported'] == 'vulkan' + name = ext_elem.attrib['name'] + if not supported and name != 'VK_ANDROID_native_buffer': + continue + version = None + for enum_elem in ext_elem.findall('.require/enum'): + if enum_elem.attrib['name'].endswith('_SPEC_VERSION'): + assert version is None + version = int(enum_elem.attrib['value']) + ext = Extension(name, version, True) + extensions.append(Extension(name, version, True)) + + 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'] + +# Mapping between extension name and the android version in which the extension +# was whitelisted in Android CTS. +ALLOWED_ANDROID_VERSION = { + # Allowed Instance KHR Extensions + "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": 28, + "VK_KHR_external_semaphore_capabilities": 28, + "VK_KHR_external_fence_capabilities": 28, + "VK_KHR_device_group_creation": 28, + "VK_KHR_get_display_properties2": 29, + "VK_KHR_surface_protected_capabilities": 29, + + # Allowed Device KHR Extensions + "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_shader_float_controls": 29, + "VK_KHR_shader_float16_int8": 29, + "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": 28, + "VK_KHR_8bit_storage": 29, + "VK_KHR_16bit_storage": 28, + "VK_KHR_get_memory_requirements2": 28, + "VK_KHR_external_memory": 28, + "VK_KHR_external_memory_fd": 28, + "VK_KHR_external_memory_win32": 28, + "VK_KHR_external_semaphore": 28, + "VK_KHR_external_semaphore_fd": 28, + "VK_KHR_external_semaphore_win32": 28, + "VK_KHR_external_fence": 28, + "VK_KHR_external_fence_fd": 28, + "VK_KHR_external_fence_win32": 28, + "VK_KHR_win32_keyed_mutex": 28, + "VK_KHR_dedicated_allocation": 28, + "VK_KHR_variable_pointers": 28, + "VK_KHR_relaxed_block_layout": 28, + "VK_KHR_bind_memory2": 28, + "VK_KHR_maintenance2": 28, + "VK_KHR_image_format_list": 28, + "VK_KHR_sampler_ycbcr_conversion": 28, + "VK_KHR_device_group": 28, + "VK_KHR_multiview": 28, + "VK_KHR_maintenance3": 28, + "VK_KHR_draw_indirect_count": 28, + "VK_KHR_create_renderpass2": 28, + "VK_KHR_depth_stencil_resolve": 29, + "VK_KHR_driver_properties": 28, + "VK_KHR_swapchain_mutable_format": 29, + "VK_KHR_shader_atomic_int64": 29, + "VK_KHR_vulkan_memory_model": 29, + "VK_KHR_performance_query": 30, + + "VK_GOOGLE_display_timing": 26, + "VK_ANDROID_native_buffer": 26, + "VK_ANDROID_external_memory_android_hardware_buffer": 28, +} + +# 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/lib/mesa/src/vulkan/util/vk_extensions_gen.py b/lib/mesa/src/vulkan/util/vk_extensions_gen.py new file mode 100644 index 000000000..4f8f66c40 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_extensions_gen.py @@ -0,0 +1,254 @@ +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 xml.etree.ElementTree as et + +from mako.template import Template + +# Mesa-local imports must be declared in meson variable +# '{file_without_suffix}_depend_files'. +from vk_extensions import * + +_TEMPLATE_H = Template(COPYRIGHT + """ + +#ifndef ${driver.upper()}_EXTENSIONS_H +#define ${driver.upper()}_EXTENSIONS_H + +#include <stdbool.h> + +%for include in includes: +#include "${include}" +%endfor + +%if driver == 'vk': +#define VK_INSTANCE_EXTENSION_COUNT ${len(instance_extensions)} + +extern const VkExtensionProperties vk_instance_extensions[]; + +struct vk_instance_extension_table { + union { + bool extensions[VK_INSTANCE_EXTENSION_COUNT]; + struct { +%for ext in instance_extensions: + bool ${ext.name[3:]}; +%endfor + }; + }; +}; + + +#define VK_DEVICE_EXTENSION_COUNT ${len(device_extensions)} + +extern const VkExtensionProperties vk_device_extensions[]; + +struct vk_device_extension_table { + union { + bool extensions[VK_DEVICE_EXTENSION_COUNT]; + struct { +%for ext in device_extensions: + bool ${ext.name[3:]}; +%endfor + }; + }; +}; +%else: +#include "vk_extensions.h" +%endif + +struct ${driver}_physical_device; + +%if driver == 'vk': +#ifdef ANDROID +extern const struct vk_instance_extension_table vk_android_allowed_instance_extensions; +extern const struct vk_device_extension_table vk_android_allowed_device_extensions; +#endif +%else: +extern const struct vk_instance_extension_table ${driver}_instance_extensions_supported; + +void +${driver}_physical_device_get_supported_extensions(const struct ${driver}_physical_device *device, + struct vk_device_extension_table *extensions); +%endif + +#endif /* ${driver.upper()}_EXTENSIONS_H */ +""") + +_TEMPLATE_C = Template(COPYRIGHT + """ +%if driver == 'vk': +#include "vk_object.h" +%else: +#include "${driver}_private.h" +%endif + +#include "${driver}_extensions.h" + +%if driver == 'vk': +const VkExtensionProperties ${driver}_instance_extensions[${driver.upper()}_INSTANCE_EXTENSION_COUNT] = { +%for ext in instance_extensions: + {"${ext.name}", ${ext.ext_version}}, +%endfor +}; + +const VkExtensionProperties ${driver}_device_extensions[${driver.upper()}_DEVICE_EXTENSION_COUNT] = { +%for ext in device_extensions: + {"${ext.name}", ${ext.ext_version}}, +%endfor +}; + +#ifdef ANDROID +const struct vk_instance_extension_table vk_android_allowed_instance_extensions = { +%for ext in instance_extensions: + .${ext.name[3:]} = ${ext.c_android_condition()}, +%endfor +}; + +extern const struct vk_device_extension_table vk_android_allowed_device_extensions = { +%for ext in device_extensions: + .${ext.name[3:]} = ${ext.c_android_condition()}, +%endfor +}; +#endif +%endif + +%if driver != 'vk': +#include "vk_util.h" + +/* Convert the VK_USE_PLATFORM_* defines to booleans */ +%for platform_define in platform_defines: +#ifdef ${platform_define} +# undef ${platform_define} +# define ${platform_define} true +#else +# define ${platform_define} false +#endif +%endfor + +/* And ANDROID too */ +#ifdef ANDROID +# undef ANDROID +# define ANDROID true +#else +# define ANDROID false +# define ANDROID_API_LEVEL 0 +#endif + +#define ${driver.upper()}_HAS_SURFACE (VK_USE_PLATFORM_WIN32_KHR || \\ + VK_USE_PLATFORM_WAYLAND_KHR || \\ + VK_USE_PLATFORM_XCB_KHR || \\ + VK_USE_PLATFORM_XLIB_KHR || \\ + VK_USE_PLATFORM_DISPLAY_KHR) + +static const uint32_t MAX_API_VERSION = ${MAX_API_VERSION.c_vk_version()}; + +VKAPI_ATTR VkResult VKAPI_CALL ${driver}_EnumerateInstanceVersion( + uint32_t* pApiVersion) +{ + *pApiVersion = MAX_API_VERSION; + return VK_SUCCESS; +} + +const struct vk_instance_extension_table ${driver}_instance_extensions_supported = { +%for ext in instance_extensions: + .${ext.name[3:]} = ${ext.enable}, +%endfor +}; + +uint32_t +${driver}_physical_device_api_version(struct ${driver}_physical_device *device) +{ + uint32_t version = 0; + + uint32_t override = vk_get_version_override(); + if (override) + return MIN2(override, MAX_API_VERSION); + +%for version in API_VERSIONS: + if (!(${version.enable})) + return version; + version = ${version.version.c_vk_version()}; + +%endfor + return version; +} + +void +${driver}_physical_device_get_supported_extensions(const struct ${driver}_physical_device *device, + struct vk_device_extension_table *extensions) +{ + *extensions = (struct vk_device_extension_table) { +%for ext in device_extensions: + .${ext.name[3:]} = ${ext.enable}, +%endfor + }; +} +%endif +""") + +def gen_extensions(driver, xml_files, api_versions, max_api_version, + extensions, out_c, out_h, includes = []): + platform_defines = [] + for filename in xml_files: + init_exts_from_xml(filename, extensions, platform_defines) + + for ext in extensions: + assert ext.type == 'instance' or ext.type == 'device' + + template_env = { + 'driver': driver, + 'API_VERSIONS': api_versions, + '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'], + 'platform_defines': platform_defines, + 'includes': includes, + } + + if out_h: + with open(out_h, 'w') as f: + f.write(_TEMPLATE_H.render(**template_env)) + + if out_c: + with open(out_c, 'w') as f: + f.write(_TEMPLATE_C.render(**template_env)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--out-c', help='Output C file.') + parser.add_argument('--out-h', help='Output H file.') + parser.add_argument('--xml', + help='Vulkan API XML file.', + required=True, + action='append', + dest='xml_files') + args = parser.parse_args() + + extensions = [] + for filename in args.xml_files: + extensions += get_all_exts_from_xml(filename) + + gen_extensions('vk', args.xml_files, None, None, + extensions, args.out_c, args.out_h, []) diff --git a/lib/mesa/src/vulkan/util/vk_format.c b/lib/mesa/src/vulkan/util/vk_format.c index 4fdfb6d5a..f6e6bcec7 100644 --- a/lib/mesa/src/vulkan/util/vk_format.c +++ b/lib/mesa/src/vulkan/util/vk_format.c @@ -1,4 +1,5 @@ /* + * Copyright © 2016 Intel Corporation * Copyright © 2019 Google LLC * * Permission is hereby granted, free of charge, to any person obtaining a @@ -158,7 +159,9 @@ static const enum pipe_format vk_format_map[] = { [VK_FORMAT_R32G32B32A32_SINT] = PIPE_FORMAT_R32G32B32A32_SINT, [VK_FORMAT_R32G32B32A32_SFLOAT] = PIPE_FORMAT_R32G32B32A32_FLOAT, - /* Missing 64-bit uint/sint formats */ + [VK_FORMAT_R64_UINT] = PIPE_FORMAT_R64_UINT, + [VK_FORMAT_R64_SINT] = PIPE_FORMAT_R64_SINT, + /* Missing rest of 64-bit uint/sint formats */ [VK_FORMAT_R64_SFLOAT] = PIPE_FORMAT_R64_FLOAT, [VK_FORMAT_R64G64_SFLOAT] = PIPE_FORMAT_R64G64_FLOAT, [VK_FORMAT_R64G64B64_SFLOAT] = PIPE_FORMAT_R64G64B64_FLOAT, @@ -171,7 +174,7 @@ static const enum pipe_format vk_format_map[] = { [VK_FORMAT_X8_D24_UNORM_PACK32] = PIPE_FORMAT_Z24X8_UNORM, [VK_FORMAT_D32_SFLOAT] = PIPE_FORMAT_Z32_FLOAT, [VK_FORMAT_S8_UINT] = PIPE_FORMAT_S8_UINT, - /* Missing D16_UNORM_S8_UINT */ + [VK_FORMAT_D16_UNORM_S8_UINT] = PIPE_FORMAT_Z16_UNORM_S8_UINT, [VK_FORMAT_D24_UNORM_S8_UINT] = PIPE_FORMAT_Z24_UNORM_S8_UINT, [VK_FORMAT_D32_SFLOAT_S8_UINT] = PIPE_FORMAT_Z32_FLOAT_S8X24_UINT, @@ -183,6 +186,10 @@ static const enum pipe_format vk_format_map[] = { [VK_FORMAT_BC2_SRGB_BLOCK] = PIPE_FORMAT_DXT3_SRGBA, [VK_FORMAT_BC3_UNORM_BLOCK] = PIPE_FORMAT_DXT5_RGBA, [VK_FORMAT_BC3_SRGB_BLOCK] = PIPE_FORMAT_DXT5_SRGBA, + [VK_FORMAT_BC4_UNORM_BLOCK] = PIPE_FORMAT_RGTC1_UNORM, + [VK_FORMAT_BC4_SNORM_BLOCK] = PIPE_FORMAT_RGTC1_SNORM, + [VK_FORMAT_BC5_UNORM_BLOCK] = PIPE_FORMAT_RGTC2_UNORM, + [VK_FORMAT_BC5_SNORM_BLOCK] = PIPE_FORMAT_RGTC2_SNORM, [VK_FORMAT_BC6H_UFLOAT_BLOCK] = PIPE_FORMAT_BPTC_RGB_UFLOAT, [VK_FORMAT_BC6H_SFLOAT_BLOCK] = PIPE_FORMAT_BPTC_RGB_FLOAT, [VK_FORMAT_BC7_UNORM_BLOCK] = PIPE_FORMAT_BPTC_RGBA_UNORM, @@ -240,11 +247,95 @@ static const enum pipe_format vk_format_map[] = { enum pipe_format vk_format_to_pipe_format(enum VkFormat vkformat) { - if (vkformat >= ARRAY_SIZE(vk_format_map)) - return PIPE_FORMAT_NONE; + if (vkformat >= ARRAY_SIZE(vk_format_map)) { + switch (vkformat) { + case VK_FORMAT_G8B8G8R8_422_UNORM: + return PIPE_FORMAT_YUYV; + case VK_FORMAT_B8G8R8G8_422_UNORM: + return PIPE_FORMAT_UYVY; + case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: + return PIPE_FORMAT_IYUV; + case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: + return PIPE_FORMAT_NV12; + case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: + return PIPE_FORMAT_Y8_U8_V8_422_UNORM; + case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: + return PIPE_FORMAT_Y8_U8V8_422_UNORM; + case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: + return PIPE_FORMAT_Y8_U8_V8_444_UNORM; + case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: + return PIPE_FORMAT_Y16_U16_V16_420_UNORM; + case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: + return PIPE_FORMAT_P016; + case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: + return PIPE_FORMAT_Y16_U16_V16_422_UNORM; + case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: + return PIPE_FORMAT_Y16_U16V16_422_UNORM; + case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: + return PIPE_FORMAT_Y16_U16_V16_444_UNORM; + case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT: + return PIPE_FORMAT_B4G4R4A4_UNORM; + case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT: + return PIPE_FORMAT_R4G4B4A4_UNORM; + default: + return PIPE_FORMAT_NONE; + } + } /* Unpopulated entries in the table must be PIPE_FORMAT_NONE */ STATIC_ASSERT(PIPE_FORMAT_NONE == 0); return vk_format_map[vkformat]; } + +VkImageAspectFlags +vk_format_aspects(VkFormat format) +{ + switch (format) { + case VK_FORMAT_UNDEFINED: + return 0; + + case VK_FORMAT_S8_UINT: + return VK_IMAGE_ASPECT_STENCIL_BIT; + + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + return VK_IMAGE_ASPECT_DEPTH_BIT; + + case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: + case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: + case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: + case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: + case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: + return (VK_IMAGE_ASPECT_PLANE_0_BIT | + VK_IMAGE_ASPECT_PLANE_1_BIT | + VK_IMAGE_ASPECT_PLANE_2_BIT); + + case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: + case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: + case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: + return (VK_IMAGE_ASPECT_PLANE_0_BIT | + VK_IMAGE_ASPECT_PLANE_1_BIT); + + default: + return VK_IMAGE_ASPECT_COLOR_BIT; + } +} diff --git a/lib/mesa/src/vulkan/util/vk_format.h b/lib/mesa/src/vulkan/util/vk_format.h index ecc79f7f7..813ec4c36 100644 --- a/lib/mesa/src/vulkan/util/vk_format.h +++ b/lib/mesa/src/vulkan/util/vk_format.h @@ -1,4 +1,5 @@ /* + * Copyright © 2016 Intel Corporation * Copyright © 2019 Google LLC * * Permission is hereby granted, free of charge, to any person obtaining a @@ -30,4 +31,34 @@ enum pipe_format vk_format_to_pipe_format(enum VkFormat vkformat); +VkImageAspectFlags +vk_format_aspects(VkFormat format); + +static inline bool +vk_format_is_color(VkFormat format) +{ + return vk_format_aspects(format) == VK_IMAGE_ASPECT_COLOR_BIT; +} + +static inline bool +vk_format_is_depth_or_stencil(VkFormat format) +{ + const VkImageAspectFlags aspects = vk_format_aspects(format); + return aspects & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); +} + +static inline bool +vk_format_has_depth(VkFormat format) +{ + const VkImageAspectFlags aspects = vk_format_aspects(format); + return aspects & VK_IMAGE_ASPECT_DEPTH_BIT; +} + +static inline bool +vk_format_has_stencil(VkFormat format) +{ + const VkImageAspectFlags aspects = vk_format_aspects(format); + return aspects & VK_IMAGE_ASPECT_STENCIL_BIT; +} + #endif diff --git a/lib/mesa/src/vulkan/util/vk_icd_gen.py b/lib/mesa/src/vulkan/util/vk_icd_gen.py new file mode 100644 index 000000000..d5401e801 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_icd_gen.py @@ -0,0 +1,78 @@ +# 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 json +import os.path +import re +import xml.etree.ElementTree as et + +def get_xml_patch_version(xml_file): + xml = et.parse(xml_file) + for d in xml.findall('.types/type'): + if d.get('category', None) != 'define': + continue + + name = d.find('.name') + if name.text != 'VK_HEADER_VERSION': + continue; + + return name.tail.strip() + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--api-version', required=True, + help='Vulkan API version.') + parser.add_argument('--xml', required=False, + help='Vulkan registry XML for patch version') + parser.add_argument('--lib-path', required=True, + help='Path to installed library') + parser.add_argument('--out', required=False, + help='Output json file.') + args = parser.parse_args() + + version = args.api_version + if args.xml: + re.match(r'\d+\.\d+', version) + version = version + '.' + get_xml_patch_version(args.xml) + else: + re.match(r'\d+\.\d+\.\d+', version) + + json_data = { + 'file_format_version': '1.0.0', + 'ICD': { + 'library_path': args.lib_path, + 'api_version': version, + }, + } + + json_params = { + 'indent': 4, + 'sort_keys': True, + 'separators': (',', ': '), + } + + if args.out: + with open(args.out, 'w') as f: + json.dump(json_data, f, **json_params) + else: + print(json.dumps(json_data, **json_params)) diff --git a/lib/mesa/src/vulkan/util/vk_instance.c b/lib/mesa/src/vulkan/util/vk_instance.c new file mode 100644 index 000000000..5787be170 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_instance.c @@ -0,0 +1,230 @@ +/* + * Copyright © 2021 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. + */ + +#include "vk_instance.h" + +#include "vk_alloc.h" +#include "vk_common_entrypoints.h" +#include "vk_util.h" + +#include "compiler/glsl_types.h" + +VkResult +vk_instance_init(struct vk_instance *instance, + const struct vk_instance_extension_table *supported_extensions, + const struct vk_instance_dispatch_table *dispatch_table, + const VkInstanceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *alloc) +{ + memset(instance, 0, sizeof(*instance)); + vk_object_base_init(NULL, &instance->base, VK_OBJECT_TYPE_INSTANCE); + instance->alloc = *alloc; + + instance->app_info = (struct vk_app_info) { .api_version = 0 }; + if (pCreateInfo->pApplicationInfo) { + const VkApplicationInfo *app = pCreateInfo->pApplicationInfo; + + instance->app_info.app_name = + vk_strdup(&instance->alloc, app->pApplicationName, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); + instance->app_info.app_version = app->applicationVersion; + + instance->app_info.engine_name = + vk_strdup(&instance->alloc, app->pEngineName, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); + instance->app_info.engine_version = app->engineVersion; + + instance->app_info.api_version = app->apiVersion; + } + + if (instance->app_info.api_version == 0) + instance->app_info.api_version = VK_API_VERSION_1_0; + + for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { + int idx; + for (idx = 0; idx < VK_INSTANCE_EXTENSION_COUNT; idx++) { + if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], + vk_instance_extensions[idx].extensionName) == 0) + break; + } + + if (idx >= VK_INSTANCE_EXTENSION_COUNT) + return VK_ERROR_EXTENSION_NOT_PRESENT; + + if (!supported_extensions->extensions[idx]) + return VK_ERROR_EXTENSION_NOT_PRESENT; + +#ifdef ANDROID + if (!vk_android_allowed_instance_extensions.extensions[idx]) + return VK_ERROR_EXTENSION_NOT_PRESENT; +#endif + + instance->enabled_extensions.extensions[idx] = true; + } + + instance->dispatch_table = *dispatch_table; + + /* Add common entrypoints without overwriting driver-provided ones. */ + vk_instance_dispatch_table_from_entrypoints( + &instance->dispatch_table, &vk_common_instance_entrypoints, false); + + if (mtx_init(&instance->debug_report.callbacks_mutex, mtx_plain) != 0) + return VK_ERROR_INITIALIZATION_FAILED; + + list_inithead(&instance->debug_report.callbacks); + + glsl_type_singleton_init_or_ref(); + + return VK_SUCCESS; +} + +void +vk_instance_finish(struct vk_instance *instance) +{ + glsl_type_singleton_decref(); + mtx_destroy(&instance->debug_report.callbacks_mutex); + vk_free(&instance->alloc, (char *)instance->app_info.app_name); + vk_free(&instance->alloc, (char *)instance->app_info.engine_name); + vk_object_base_finish(&instance->base); +} + +VkResult +vk_enumerate_instance_extension_properties( + const struct vk_instance_extension_table *supported_extensions, + uint32_t *pPropertyCount, + VkExtensionProperties *pProperties) +{ + VK_OUTARRAY_MAKE_TYPED(VkExtensionProperties, out, pProperties, pPropertyCount); + + for (int i = 0; i < VK_INSTANCE_EXTENSION_COUNT; i++) { + if (!supported_extensions->extensions[i]) + continue; + +#ifdef ANDROID + if (!vk_android_allowed_instance_extensions.extensions[i]) + continue; +#endif + + vk_outarray_append_typed(VkExtensionProperties, &out, prop) { + *prop = vk_instance_extensions[i]; + } + } + + return vk_outarray_status(&out); +} + +PFN_vkVoidFunction +vk_instance_get_proc_addr(const struct vk_instance *instance, + const struct vk_instance_entrypoint_table *entrypoints, + const char *name) +{ + PFN_vkVoidFunction func; + + /* The Vulkan 1.0 spec for vkGetInstanceProcAddr has a table of exactly + * when we have to return valid function pointers, NULL, or it's left + * undefined. See the table for exact details. + */ + if (name == NULL) + return NULL; + +#define LOOKUP_VK_ENTRYPOINT(entrypoint) \ + if (strcmp(name, "vk" #entrypoint) == 0) \ + return (PFN_vkVoidFunction)entrypoints->entrypoint + + LOOKUP_VK_ENTRYPOINT(EnumerateInstanceExtensionProperties); + LOOKUP_VK_ENTRYPOINT(EnumerateInstanceLayerProperties); + LOOKUP_VK_ENTRYPOINT(EnumerateInstanceVersion); + LOOKUP_VK_ENTRYPOINT(CreateInstance); + + /* GetInstanceProcAddr() can also be called with a NULL instance. + * See https://gitlab.khronos.org/vulkan/vulkan/issues/2057 + */ + LOOKUP_VK_ENTRYPOINT(GetInstanceProcAddr); + +#undef LOOKUP_VK_ENTRYPOINT + + if (instance == NULL) + return NULL; + + func = vk_instance_dispatch_table_get_if_supported(&instance->dispatch_table, + name, + instance->app_info.api_version, + &instance->enabled_extensions); + if (func != NULL) + return func; + + func = vk_physical_device_dispatch_table_get_if_supported(&vk_physical_device_trampolines, + name, + instance->app_info.api_version, + &instance->enabled_extensions); + if (func != NULL) + return func; + + func = vk_device_dispatch_table_get_if_supported(&vk_device_trampolines, + name, + instance->app_info.api_version, + &instance->enabled_extensions, + NULL); + if (func != NULL) + return func; + + return NULL; +} + +PFN_vkVoidFunction +vk_instance_get_proc_addr_unchecked(const struct vk_instance *instance, + const char *name) +{ + PFN_vkVoidFunction func; + + if (instance == NULL || name == NULL) + return NULL; + + func = vk_instance_dispatch_table_get(&instance->dispatch_table, name); + if (func != NULL) + return func; + + func = vk_physical_device_dispatch_table_get( + &vk_physical_device_trampolines, name); + if (func != NULL) + return func; + + func = vk_device_dispatch_table_get(&vk_device_trampolines, name); + if (func != NULL) + return func; + + return NULL; +} + +PFN_vkVoidFunction +vk_instance_get_physical_device_proc_addr(const struct vk_instance *instance, + const char *name) +{ + if (instance == NULL || name == NULL) + return NULL; + + return vk_physical_device_dispatch_table_get_if_supported(&vk_physical_device_trampolines, + name, + instance->app_info.api_version, + &instance->enabled_extensions); +} diff --git a/lib/mesa/src/vulkan/util/vk_instance.h b/lib/mesa/src/vulkan/util/vk_instance.h new file mode 100644 index 000000000..5f195ca0d --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_instance.h @@ -0,0 +1,97 @@ +/* + * Copyright © 2021 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. + */ +#ifndef VK_INSTANCE_H +#define VK_INSTANCE_H + +#include "vk_dispatch_table.h" +#include "vk_extensions.h" +#include "vk_object.h" + +#include "c11/threads.h" +#include "util/list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_app_info { + const char* app_name; + uint32_t app_version; + const char* engine_name; + uint32_t engine_version; + uint32_t api_version; +}; + +struct vk_instance { + struct vk_object_base base; + VkAllocationCallbacks alloc; + + struct vk_app_info app_info; + struct vk_instance_extension_table enabled_extensions; + + struct vk_instance_dispatch_table dispatch_table; + + /* VK_EXT_debug_report debug callbacks */ + struct { + mtx_t callbacks_mutex; + struct list_head callbacks; + } debug_report; +}; + +VK_DEFINE_HANDLE_CASTS(vk_instance, base, VkInstance, + VK_OBJECT_TYPE_INSTANCE) + +VkResult MUST_CHECK +vk_instance_init(struct vk_instance *instance, + const struct vk_instance_extension_table *supported_extensions, + const struct vk_instance_dispatch_table *dispatch_table, + const VkInstanceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *alloc); + +void +vk_instance_finish(struct vk_instance *instance); + +VkResult +vk_enumerate_instance_extension_properties( + const struct vk_instance_extension_table *supported_extensions, + uint32_t *pPropertyCount, + VkExtensionProperties *pProperties); + +PFN_vkVoidFunction +vk_instance_get_proc_addr(const struct vk_instance *instance, + const struct vk_instance_entrypoint_table *entrypoints, + const char *name); + +PFN_vkVoidFunction +vk_instance_get_proc_addr_unchecked(const struct vk_instance *instance, + const char *name); + +PFN_vkVoidFunction +vk_instance_get_physical_device_proc_addr(const struct vk_instance *instance, + const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* VK_INSTANCE_H */ diff --git a/lib/mesa/src/vulkan/util/vk_object.c b/lib/mesa/src/vulkan/util/vk_object.c new file mode 100644 index 000000000..af2c72ba9 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_object.c @@ -0,0 +1,325 @@ +/* + * Copyright © 2020 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. + */ + +#include "vk_object.h" + +#include "vk_alloc.h" +#include "vk_common_entrypoints.h" +#include "vk_device.h" +#include "util/hash_table.h" +#include "util/ralloc.h" + +static void +vk_object_base_reinit(struct vk_object_base *base) +{ + base->_loader_data.loaderMagic = ICD_LOADER_MAGIC; + util_sparse_array_init(&base->private_data, sizeof(uint64_t), 8); +} + +void +vk_object_base_init(struct vk_device *device, + struct vk_object_base *base, + UNUSED VkObjectType obj_type) +{ + vk_object_base_reinit(base); + base->type = obj_type; + base->device = device; +} + +void +vk_object_base_finish(struct vk_object_base *base) +{ + util_sparse_array_finish(&base->private_data); +} + +void +vk_object_base_reset(struct vk_object_base *base) +{ + vk_object_base_finish(base); + vk_object_base_reinit(base); +} + +void * +vk_object_alloc(struct vk_device *device, + const VkAllocationCallbacks *alloc, + size_t size, + VkObjectType obj_type) +{ + void *ptr = vk_alloc2(&device->alloc, alloc, size, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (ptr == NULL) + return NULL; + + vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type); + + return ptr; +} + +void * +vk_object_zalloc(struct vk_device *device, + const VkAllocationCallbacks *alloc, + size_t size, + VkObjectType obj_type) +{ + void *ptr = vk_zalloc2(&device->alloc, alloc, size, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (ptr == NULL) + return NULL; + + vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type); + + return ptr; +} + +void * +vk_object_multialloc(struct vk_device *device, + struct vk_multialloc *ma, + const VkAllocationCallbacks *alloc, + VkObjectType obj_type) +{ + void *ptr = vk_multialloc_alloc2(ma, &device->alloc, alloc, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (ptr == NULL) + return NULL; + + vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type); + + return ptr; +} + +void * +vk_object_multizalloc(struct vk_device *device, + struct vk_multialloc *ma, + const VkAllocationCallbacks *alloc, + VkObjectType obj_type) +{ + void *ptr = vk_multialloc_alloc2(ma, &device->alloc, alloc, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (ptr == NULL) + return NULL; + + memset(ptr, 0, ma->size); + vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type); + + return ptr; +} + +void +vk_object_free(struct vk_device *device, + const VkAllocationCallbacks *alloc, + void *data) +{ + vk_object_base_finish((struct vk_object_base *)data); + vk_free2(&device->alloc, alloc, data); +} + +VkResult +vk_private_data_slot_create(struct vk_device *device, + const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlotEXT* pPrivateDataSlot) +{ + struct vk_private_data_slot *slot = + vk_alloc2(&device->alloc, pAllocator, sizeof(*slot), 8, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); + if (slot == NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + vk_object_base_init(device, &slot->base, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT); + slot->index = p_atomic_inc_return(&device->private_data_next_index); + + *pPrivateDataSlot = vk_private_data_slot_to_handle(slot); + + return VK_SUCCESS; +} + +void +vk_private_data_slot_destroy(struct vk_device *device, + VkPrivateDataSlotEXT privateDataSlot, + const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(vk_private_data_slot, slot, privateDataSlot); + if (slot == NULL) + return; + + vk_object_base_finish(&slot->base); + vk_free2(&device->alloc, pAllocator, slot); +} + +#ifdef ANDROID +static VkResult +get_swapchain_private_data_locked(struct vk_device *device, + uint64_t objectHandle, + struct vk_private_data_slot *slot, + uint64_t **private_data) +{ + if (unlikely(device->swapchain_private == NULL)) { + /* Even though VkSwapchain is a non-dispatchable object, we know a + * priori that Android swapchains are actually pointers so we can use + * the pointer hash table for them. + */ + device->swapchain_private = _mesa_pointer_hash_table_create(NULL); + if (device->swapchain_private == NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + struct hash_entry *entry = + _mesa_hash_table_search(device->swapchain_private, + (void *)(uintptr_t)objectHandle); + if (unlikely(entry == NULL)) { + struct util_sparse_array *swapchain_private = + ralloc(device->swapchain_private, struct util_sparse_array); + util_sparse_array_init(swapchain_private, sizeof(uint64_t), 8); + + entry = _mesa_hash_table_insert(device->swapchain_private, + (void *)(uintptr_t)objectHandle, + swapchain_private); + if (entry == NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + struct util_sparse_array *swapchain_private = entry->data; + *private_data = util_sparse_array_get(swapchain_private, slot->index); + + return VK_SUCCESS; +} +#endif /* ANDROID */ + +static VkResult +vk_object_base_private_data(struct vk_device *device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t **private_data) +{ + VK_FROM_HANDLE(vk_private_data_slot, slot, privateDataSlot); + +#ifdef ANDROID + /* There is an annoying spec corner here on Android. Because WSI is + * implemented in the Vulkan loader which doesn't know about the + * VK_EXT_private_data extension, we have to handle VkSwapchainKHR in the + * driver as a special case. On future versions of Android where the + * loader does understand VK_EXT_private_data, we'll never see a + * vkGet/SetPrivateDataEXT call on a swapchain because the loader will + * handle it. + */ + if (objectType == VK_OBJECT_TYPE_SWAPCHAIN_KHR) { + mtx_lock(&device->swapchain_private_mtx); + VkResult result = get_swapchain_private_data_locked(device, objectHandle, + slot, private_data); + mtx_unlock(&device->swapchain_private_mtx); + return result; + } +#endif /* ANDROID */ + + struct vk_object_base *obj = + vk_object_base_from_u64_handle(objectHandle, objectType); + *private_data = util_sparse_array_get(&obj->private_data, slot->index); + + return VK_SUCCESS; +} + +VkResult +vk_object_base_set_private_data(struct vk_device *device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t data) +{ + uint64_t *private_data; + VkResult result = vk_object_base_private_data(device, + objectType, objectHandle, + privateDataSlot, + &private_data); + if (unlikely(result != VK_SUCCESS)) + return result; + + *private_data = data; + return VK_SUCCESS; +} + +void +vk_object_base_get_private_data(struct vk_device *device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t *pData) +{ + uint64_t *private_data; + VkResult result = vk_object_base_private_data(device, + objectType, objectHandle, + privateDataSlot, + &private_data); + if (likely(result == VK_SUCCESS)) { + *pData = *private_data; + } else { + *pData = 0; + } +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_CreatePrivateDataSlotEXT(VkDevice _device, + const VkPrivateDataSlotCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkPrivateDataSlotEXT *pPrivateDataSlot) +{ + VK_FROM_HANDLE(vk_device, device, _device); + return vk_private_data_slot_create(device, pCreateInfo, pAllocator, + pPrivateDataSlot); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_DestroyPrivateDataSlotEXT(VkDevice _device, + VkPrivateDataSlotEXT privateDataSlot, + const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(vk_device, device, _device); + vk_private_data_slot_destroy(device, privateDataSlot, pAllocator); +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_SetPrivateDataEXT(VkDevice _device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t data) +{ + VK_FROM_HANDLE(vk_device, device, _device); + return vk_object_base_set_private_data(device, + objectType, objectHandle, + privateDataSlot, data); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetPrivateDataEXT(VkDevice _device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t *pData) +{ + VK_FROM_HANDLE(vk_device, device, _device); + vk_object_base_get_private_data(device, + objectType, objectHandle, + privateDataSlot, pData); +} diff --git a/lib/mesa/src/vulkan/util/vk_object.h b/lib/mesa/src/vulkan/util/vk_object.h new file mode 100644 index 000000000..c9c751ae2 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_object.h @@ -0,0 +1,177 @@ +/* + * Copyright © 2020 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. + */ +#ifndef VK_OBJECT_H +#define VK_OBJECT_H + +#include <vulkan/vulkan.h> +#include <vulkan/vk_icd.h> + +#include "c11/threads.h" +#include "util/macros.h" +#include "util/sparse_array.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct hash_table; + +struct vk_device; + +struct vk_object_base { + VK_LOADER_DATA _loader_data; + VkObjectType type; + + struct vk_device *device; + + /* For VK_EXT_private_data */ + struct util_sparse_array private_data; +}; + +void vk_object_base_init(UNUSED struct vk_device *device, + struct vk_object_base *base, + UNUSED VkObjectType obj_type); +void vk_object_base_finish(UNUSED struct vk_object_base *base); +void vk_object_base_reset(struct vk_object_base *base); + +static inline void +vk_object_base_assert_valid(ASSERTED struct vk_object_base *base, + ASSERTED VkObjectType obj_type) +{ + assert(base == NULL || base->type == obj_type); +} + +static inline struct vk_object_base * +vk_object_base_from_u64_handle(uint64_t handle, VkObjectType obj_type) +{ + struct vk_object_base *base = (struct vk_object_base *)(uintptr_t)handle; + vk_object_base_assert_valid(base, obj_type); + return base; +} + +#define VK_DEFINE_HANDLE_CASTS(__driver_type, __base, __VkType, __VK_TYPE) \ + static inline struct __driver_type * \ + __driver_type ## _from_handle(__VkType _handle) \ + { \ + struct vk_object_base *base = (struct vk_object_base *)_handle; \ + vk_object_base_assert_valid(base, __VK_TYPE); \ + STATIC_ASSERT(offsetof(struct __driver_type, __base) == 0); \ + return (struct __driver_type *) base; \ + } \ + \ + static inline __VkType \ + __driver_type ## _to_handle(struct __driver_type *_obj) \ + { \ + vk_object_base_assert_valid(&_obj->__base, __VK_TYPE); \ + return (__VkType) _obj; \ + } + +#define VK_DEFINE_NONDISP_HANDLE_CASTS(__driver_type, __base, __VkType, __VK_TYPE) \ + static inline struct __driver_type * \ + __driver_type ## _from_handle(__VkType _handle) \ + { \ + struct vk_object_base *base = \ + (struct vk_object_base *)(uintptr_t)_handle; \ + vk_object_base_assert_valid(base, __VK_TYPE); \ + STATIC_ASSERT(offsetof(struct __driver_type, __base) == 0); \ + return (struct __driver_type *)base; \ + } \ + \ + static inline __VkType \ + __driver_type ## _to_handle(struct __driver_type *_obj) \ + { \ + vk_object_base_assert_valid(&_obj->__base, __VK_TYPE); \ + return (__VkType)(uintptr_t) _obj; \ + } + +#define VK_FROM_HANDLE(__driver_type, __name, __handle) \ + struct __driver_type *__name = __driver_type ## _from_handle(__handle) + +/* Helpers for vk object (de)allocation and (de)initialization */ +void * +vk_object_alloc(struct vk_device *device, + const VkAllocationCallbacks *alloc, + size_t size, + VkObjectType vk_obj_type); + +void * +vk_object_zalloc(struct vk_device *device, + const VkAllocationCallbacks *alloc, + size_t size, + VkObjectType vk_obj_type); + +struct vk_multialloc; + +void * +vk_object_multialloc(struct vk_device *device, + struct vk_multialloc *ma, + const VkAllocationCallbacks *alloc, + VkObjectType vk_obj_type); + +void * +vk_object_multizalloc(struct vk_device *device, + struct vk_multialloc *ma, + const VkAllocationCallbacks *alloc, + VkObjectType vk_obj_type); + +void +vk_object_free(struct vk_device *device, + const VkAllocationCallbacks *alloc, + void *data); + + +struct vk_private_data_slot { + struct vk_object_base base; + uint32_t index; +}; +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_private_data_slot, base, + VkPrivateDataSlotEXT, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT); + +VkResult +vk_private_data_slot_create(struct vk_device *device, + const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlotEXT* pPrivateDataSlot); +void +vk_private_data_slot_destroy(struct vk_device *device, + VkPrivateDataSlotEXT privateDataSlot, + const VkAllocationCallbacks *pAllocator); +VkResult +vk_object_base_set_private_data(struct vk_device *device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t data); +void +vk_object_base_get_private_data(struct vk_device *device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t *pData); + +#ifdef __cplusplus +} +#endif + +#endif /* VK_OBJECT_H */ diff --git a/lib/mesa/src/vulkan/util/vk_physical_device.c b/lib/mesa/src/vulkan/util/vk_physical_device.c new file mode 100644 index 000000000..18cab2e87 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_physical_device.c @@ -0,0 +1,193 @@ +/* + * Copyright © 2021 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. + */ + +#include "vk_physical_device.h" + +#include "vk_common_entrypoints.h" +#include "vk_util.h" + +VkResult +vk_physical_device_init(struct vk_physical_device *pdevice, + struct vk_instance *instance, + const struct vk_device_extension_table *supported_extensions, + const struct vk_physical_device_dispatch_table *dispatch_table) +{ + memset(pdevice, 0, sizeof(*pdevice)); + vk_object_base_init(NULL, &pdevice->base, VK_OBJECT_TYPE_PHYSICAL_DEVICE); + pdevice->instance = instance; + + if (supported_extensions != NULL) + pdevice->supported_extensions = *supported_extensions; + + pdevice->dispatch_table = *dispatch_table; + + /* Add common entrypoints without overwriting driver-provided ones. */ + vk_physical_device_dispatch_table_from_entrypoints( + &pdevice->dispatch_table, &vk_common_physical_device_entrypoints, false); + + return VK_SUCCESS; +} + +void +vk_physical_device_finish(struct vk_physical_device *physical_device) +{ + vk_object_base_finish(&physical_device->base); +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkLayerProperties *pProperties) +{ + if (pProperties == NULL) { + *pPropertyCount = 0; + return VK_SUCCESS; + } + + /* None supported at this time */ + return VK_ERROR_LAYER_NOT_PRESENT; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, + const char *pLayerName, + uint32_t *pPropertyCount, + VkExtensionProperties *pProperties) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + VK_OUTARRAY_MAKE_TYPED(VkExtensionProperties, out, pProperties, pPropertyCount); + + for (int i = 0; i < VK_DEVICE_EXTENSION_COUNT; i++) { + if (!pdevice->supported_extensions.extensions[i]) + continue; + +#ifdef ANDROID + if (!vk_android_allowed_device_extensions.extensions[i]) + continue; +#endif + + vk_outarray_append_typed(VkExtensionProperties, &out, prop) { + *prop = vk_device_extensions[i]; + } + } + + return vk_outarray_status(&out); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures *pFeatures) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + + /* Don't zero-init this struct since the driver fills it out entirely */ + VkPhysicalDeviceFeatures2 features2; + features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features2.pNext = NULL; + + pdevice->dispatch_table.GetPhysicalDeviceFeatures2(physicalDevice, + &features2); + *pFeatures = features2.features; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties *pProperties) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + + /* Don't zero-init this struct since the driver fills it out entirely */ + VkPhysicalDeviceProperties2 props2; + props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + props2.pNext = NULL; + + pdevice->dispatch_table.GetPhysicalDeviceProperties2(physicalDevice, + &props2); + *pProperties = props2.properties; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties *pMemoryProperties) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + + /* Don't zero-init this struct since the driver fills it out entirely */ + VkPhysicalDeviceMemoryProperties2 props2; + props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; + props2.pNext = NULL; + + pdevice->dispatch_table.GetPhysicalDeviceMemoryProperties2(physicalDevice, + &props2); + *pMemoryProperties = props2.memoryProperties; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties *pFormatProperties) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + + /* Don't zero-init this struct since the driver fills it out entirely */ + VkFormatProperties2 props2; + props2.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; + props2.pNext = NULL; + + pdevice->dispatch_table.GetPhysicalDeviceFormatProperties2(physicalDevice, + format, &props2); + *pFormatProperties = props2.formatProperties; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags, + VkImageFormatProperties *pImageFormatProperties) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + + VkPhysicalDeviceImageFormatInfo2 info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .format = format, + .type = type, + .tiling = tiling, + .usage = usage, + .flags = flags + }; + + /* Don't zero-init this struct since the driver fills it out entirely */ + VkImageFormatProperties2 props2; + props2.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; + props2.pNext = NULL; + + VkResult result = + pdevice->dispatch_table.GetPhysicalDeviceImageFormatProperties2(physicalDevice, + &info, &props2); + *pImageFormatProperties = props2.imageFormatProperties; + + return result; +} diff --git a/lib/mesa/src/vulkan/util/vk_physical_device.h b/lib/mesa/src/vulkan/util/vk_physical_device.h new file mode 100644 index 000000000..fea39ae9d --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_physical_device.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2021 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. + */ +#ifndef VK_PHYSICAL_DEVICE_H +#define VK_PHYSICAL_DEVICE_H + +#include "vk_dispatch_table.h" +#include "vk_extensions.h" +#include "vk_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_physical_device { + struct vk_object_base base; + struct vk_instance *instance; + + struct vk_device_extension_table supported_extensions; + + struct vk_physical_device_dispatch_table dispatch_table; +}; + +VK_DEFINE_HANDLE_CASTS(vk_physical_device, base, VkPhysicalDevice, + VK_OBJECT_TYPE_PHYSICAL_DEVICE) + +VkResult MUST_CHECK +vk_physical_device_init(struct vk_physical_device *physical_device, + struct vk_instance *instance, + const struct vk_device_extension_table *supported_extensions, + const struct vk_physical_device_dispatch_table *dispatch_table); + +void +vk_physical_device_finish(struct vk_physical_device *physical_device); + +#ifdef __cplusplus +} +#endif + +#endif /* VK_PHYSICAL_DEVICE_H */ diff --git a/lib/mesa/src/vulkan/util/vk_render_pass.c b/lib/mesa/src/vulkan/util/vk_render_pass.c new file mode 100644 index 000000000..fa736ec9c --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_render_pass.c @@ -0,0 +1,291 @@ +/* + * Copyright © 2020 Valve 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. + */ + +#include "vk_alloc.h" +#include "vk_common_entrypoints.h" +#include "vk_device.h" +#include "vk_format.h" +#include "vk_util.h" + +#include "util/log.h" + +static void +translate_references(VkAttachmentReference2 **reference_ptr, + uint32_t reference_count, + const VkAttachmentReference *reference, + const VkRenderPassCreateInfo *pass_info, + bool is_input_attachment) +{ + VkAttachmentReference2 *reference2 = *reference_ptr; + *reference_ptr += reference_count; + for (uint32_t i = 0; i < reference_count; i++) { + reference2[i] = (VkAttachmentReference2) { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, + .pNext = NULL, + .attachment = reference[i].attachment, + .layout = reference[i].layout, + }; + + if (is_input_attachment && + reference2[i].attachment != VK_ATTACHMENT_UNUSED) { + assert(reference2[i].attachment < pass_info->attachmentCount); + const VkAttachmentDescription *att = + &pass_info->pAttachments[reference2[i].attachment]; + reference2[i].aspectMask = vk_format_aspects(att->format); + } + } +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_CreateRenderPass(VkDevice _device, + const VkRenderPassCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkRenderPass *pRenderPass) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + uint32_t reference_count = 0; + for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { + reference_count += pCreateInfo->pSubpasses[i].inputAttachmentCount; + reference_count += pCreateInfo->pSubpasses[i].colorAttachmentCount; + if (pCreateInfo->pSubpasses[i].pResolveAttachments) + reference_count += pCreateInfo->pSubpasses[i].colorAttachmentCount; + if (pCreateInfo->pSubpasses[i].pDepthStencilAttachment) + reference_count += 1; + } + + VK_MULTIALLOC(ma); + VK_MULTIALLOC_DECL(&ma, VkRenderPassCreateInfo2, create_info, 1); + VK_MULTIALLOC_DECL(&ma, VkSubpassDescription2, subpasses, + pCreateInfo->subpassCount); + VK_MULTIALLOC_DECL(&ma, VkAttachmentDescription2, attachments, + pCreateInfo->attachmentCount); + VK_MULTIALLOC_DECL(&ma, VkSubpassDependency2, dependencies, + pCreateInfo->dependencyCount); + VK_MULTIALLOC_DECL(&ma, VkAttachmentReference2, references, + reference_count); + if (!vk_multialloc_alloc2(&ma, &device->alloc, pAllocator, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND)) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + VkAttachmentReference2 *reference_ptr = references; + + const VkRenderPassMultiviewCreateInfo *multiview_info = NULL; + const VkRenderPassInputAttachmentAspectCreateInfo *aspect_info = NULL; + vk_foreach_struct(ext, pCreateInfo->pNext) { + switch (ext->sType) { + case VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO: + aspect_info = (const VkRenderPassInputAttachmentAspectCreateInfo *)ext; + /* We don't care about this information */ + break; + + case VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO: + multiview_info = (const VkRenderPassMultiviewCreateInfo*) ext; + break; + + default: + mesa_logd("%s: ignored VkStructureType %u\n", __func__, ext->sType); + break; + } + } + + for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { + attachments[i] = (VkAttachmentDescription2) { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, + .pNext = NULL, + .flags = pCreateInfo->pAttachments[i].flags, + .format = pCreateInfo->pAttachments[i].format, + .samples = pCreateInfo->pAttachments[i].samples, + .loadOp = pCreateInfo->pAttachments[i].loadOp, + .storeOp = pCreateInfo->pAttachments[i].storeOp, + .stencilLoadOp = pCreateInfo->pAttachments[i].stencilLoadOp, + .stencilStoreOp = pCreateInfo->pAttachments[i].stencilStoreOp, + .initialLayout = pCreateInfo->pAttachments[i].initialLayout, + .finalLayout = pCreateInfo->pAttachments[i].finalLayout, + }; + } + + for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { + subpasses[i] = (VkSubpassDescription2) { + .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, + .pNext = NULL, + .flags = pCreateInfo->pSubpasses[i].flags, + .pipelineBindPoint = pCreateInfo->pSubpasses[i].pipelineBindPoint, + .viewMask = 0, + .inputAttachmentCount = pCreateInfo->pSubpasses[i].inputAttachmentCount, + .colorAttachmentCount = pCreateInfo->pSubpasses[i].colorAttachmentCount, + .preserveAttachmentCount = pCreateInfo->pSubpasses[i].preserveAttachmentCount, + .pPreserveAttachments = pCreateInfo->pSubpasses[i].pPreserveAttachments, + }; + + if (multiview_info && multiview_info->subpassCount) { + assert(multiview_info->subpassCount == pCreateInfo->subpassCount); + subpasses[i].viewMask = multiview_info->pViewMasks[i]; + } + + subpasses[i].pInputAttachments = reference_ptr; + translate_references(&reference_ptr, + subpasses[i].inputAttachmentCount, + pCreateInfo->pSubpasses[i].pInputAttachments, + pCreateInfo, true); + subpasses[i].pColorAttachments = reference_ptr; + translate_references(&reference_ptr, + subpasses[i].colorAttachmentCount, + pCreateInfo->pSubpasses[i].pColorAttachments, + pCreateInfo, false); + subpasses[i].pResolveAttachments = NULL; + if (pCreateInfo->pSubpasses[i].pResolveAttachments) { + subpasses[i].pResolveAttachments = reference_ptr; + translate_references(&reference_ptr, + subpasses[i].colorAttachmentCount, + pCreateInfo->pSubpasses[i].pResolveAttachments, + pCreateInfo, false); + } + subpasses[i].pDepthStencilAttachment = NULL; + if (pCreateInfo->pSubpasses[i].pDepthStencilAttachment) { + subpasses[i].pDepthStencilAttachment = reference_ptr; + translate_references(&reference_ptr, 1, + pCreateInfo->pSubpasses[i].pDepthStencilAttachment, + pCreateInfo, false); + } + } + + assert(reference_ptr == references + reference_count); + + if (aspect_info != NULL) { + for (uint32_t i = 0; i < aspect_info->aspectReferenceCount; i++) { + const VkInputAttachmentAspectReference *ref = + &aspect_info->pAspectReferences[i]; + + assert(ref->subpass < pCreateInfo->subpassCount); + VkSubpassDescription2 *subpass = &subpasses[ref->subpass]; + + assert(ref->inputAttachmentIndex < subpass->inputAttachmentCount); + VkAttachmentReference2 *att = (VkAttachmentReference2 *) + &subpass->pInputAttachments[ref->inputAttachmentIndex]; + + att->aspectMask = ref->aspectMask; + } + } + + for (uint32_t i = 0; i < pCreateInfo->dependencyCount; i++) { + dependencies[i] = (VkSubpassDependency2) { + .sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, + .pNext = NULL, + .srcSubpass = pCreateInfo->pDependencies[i].srcSubpass, + .dstSubpass = pCreateInfo->pDependencies[i].dstSubpass, + .srcStageMask = pCreateInfo->pDependencies[i].srcStageMask, + .dstStageMask = pCreateInfo->pDependencies[i].dstStageMask, + .srcAccessMask = pCreateInfo->pDependencies[i].srcAccessMask, + .dstAccessMask = pCreateInfo->pDependencies[i].dstAccessMask, + .dependencyFlags = pCreateInfo->pDependencies[i].dependencyFlags, + .viewOffset = 0, + }; + + if (multiview_info && multiview_info->dependencyCount) { + assert(multiview_info->dependencyCount == pCreateInfo->dependencyCount); + dependencies[i].viewOffset = multiview_info->pViewOffsets[i]; + } + } + + *create_info = (VkRenderPassCreateInfo2) { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, + .pNext = pCreateInfo->pNext, + .flags = pCreateInfo->flags, + .attachmentCount = pCreateInfo->attachmentCount, + .pAttachments = attachments, + .subpassCount = pCreateInfo->subpassCount, + .pSubpasses = subpasses, + .dependencyCount = pCreateInfo->dependencyCount, + .pDependencies = dependencies, + }; + + if (multiview_info && multiview_info->correlationMaskCount > 0) { + create_info->correlatedViewMaskCount = multiview_info->correlationMaskCount; + create_info->pCorrelatedViewMasks = multiview_info->pCorrelationMasks; + } + + VkResult result = + device->dispatch_table.CreateRenderPass2(_device, create_info, + pAllocator, pRenderPass); + + vk_free2(&device->alloc, pAllocator, create_info); + + return result; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdBeginRenderPass(VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo* pRenderPassBegin, + VkSubpassContents contents) +{ + /* We don't have a vk_command_buffer object but we can assume, since we're + * using common dispatch, that it's a vk_object of some sort. + */ + struct vk_object_base *disp = (struct vk_object_base *)commandBuffer; + + VkSubpassBeginInfo info = { + .sType = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO, + .contents = contents, + }; + + disp->device->dispatch_table.CmdBeginRenderPass2(commandBuffer, + pRenderPassBegin, &info); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdEndRenderPass(VkCommandBuffer commandBuffer) +{ + /* We don't have a vk_command_buffer object but we can assume, since we're + * using common dispatch, that it's a vk_object of some sort. + */ + struct vk_object_base *disp = (struct vk_object_base *)commandBuffer; + + VkSubpassEndInfo info = { + .sType = VK_STRUCTURE_TYPE_SUBPASS_END_INFO, + }; + + disp->device->dispatch_table.CmdEndRenderPass2(commandBuffer, &info); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdNextSubpass(VkCommandBuffer commandBuffer, + VkSubpassContents contents) +{ + /* We don't have a vk_command_buffer object but we can assume, since we're + * using common dispatch, that it's a vk_object of some sort. + */ + struct vk_object_base *disp = (struct vk_object_base *)commandBuffer; + + VkSubpassBeginInfo begin_info = { + .sType = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO, + .contents = contents, + }; + + VkSubpassEndInfo end_info = { + .sType = VK_STRUCTURE_TYPE_SUBPASS_END_INFO, + }; + + disp->device->dispatch_table.CmdNextSubpass2(commandBuffer, &begin_info, + &end_info); +} diff --git a/lib/mesa/src/vulkan/util/vk_shader_module.c b/lib/mesa/src/vulkan/util/vk_shader_module.c new file mode 100644 index 000000000..fd3671744 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_shader_module.c @@ -0,0 +1,77 @@ +/* + * 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 (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. + */ + +#include "vk_shader_module.h" +#include "util/mesa-sha1.h" +#include "vk_common_entrypoints.h" +#include "vk_device.h" + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_CreateShaderModule(VkDevice _device, + const VkShaderModuleCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkShaderModule *pShaderModule) +{ + VK_FROM_HANDLE(vk_device, device, _device); + struct vk_shader_module *module; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO); + assert(pCreateInfo->flags == 0); + + module = vk_object_alloc(device, pAllocator, + sizeof(*module) + pCreateInfo->codeSize, + VK_OBJECT_TYPE_SHADER_MODULE); + if (module == NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + module->size = pCreateInfo->codeSize; + module->nir = NULL; + memcpy(module->data, pCreateInfo->pCode, module->size); + + _mesa_sha1_compute(module->data, module->size, module->sha1); + + *pShaderModule = vk_shader_module_to_handle(module); + + return VK_SUCCESS; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_DestroyShaderModule(VkDevice _device, + VkShaderModule _module, + const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(vk_device, device, _device); + VK_FROM_HANDLE(vk_shader_module, module, _module); + + if (!module) + return; + + /* NIR modules (which are only created internally by the driver) are not + * dynamically allocated so we should never call this for them. + * Instead the driver is responsible for freeing the NIR code when it is + * no longer needed. + */ + assert(module->nir == NULL); + + vk_object_free(device, pAllocator, module); +} diff --git a/lib/mesa/src/vulkan/util/vk_shader_module.h b/lib/mesa/src/vulkan/util/vk_shader_module.h new file mode 100644 index 000000000..d4e64dfc3 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_shader_module.h @@ -0,0 +1,63 @@ +/* + * 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 (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. + */ + +#ifndef VK_SHADER_MODULE_H +#define VK_SHADER_MODULE_H + +#include <vulkan/vulkan.h> +#include "vk_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct nir_shader; + +struct vk_shader_module { + struct vk_object_base base; + struct nir_shader *nir; + unsigned char sha1[20]; + uint32_t size; + char data[0]; +}; + +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_shader_module, base, VkShaderModule, + VK_OBJECT_TYPE_SHADER_MODULE) + +/* this should only be used for stack-allocated, temporary objects */ +#define vk_shader_module_handle_from_nir(_nir) \ + vk_shader_module_to_handle(&(struct vk_shader_module) { \ + .base.type = VK_OBJECT_TYPE_SHADER_MODULE, \ + .nir = _nir, \ + }) +#define vk_shader_module_from_nir(_nir) \ + (struct vk_shader_module) { \ + .base.type = VK_OBJECT_TYPE_SHADER_MODULE, \ + .nir = _nir, \ + } + +#ifdef __cplusplus +} +#endif + +#endif /* VK_SHADER_MODULE_H */ |