diff options
Diffstat (limited to 'lib/mesa/src/vulkan')
41 files changed, 6011 insertions, 801 deletions
diff --git a/lib/mesa/src/vulkan/Android.mk b/lib/mesa/src/vulkan/Android.mk index 4b1695abc..295c57d3c 100644 --- a/lib/mesa/src/vulkan/Android.mk +++ b/lib/mesa/src/vulkan/Android.mk @@ -38,7 +38,8 @@ intermediates := $(call local-generated-sources-dir) LOCAL_C_INCLUDES := \ $(MESA_TOP)/include/vulkan \ $(MESA_TOP)/src/vulkan/util \ - $(MESA_TOP)/src/gallium/include + $(MESA_TOP)/src/gallium/include \ + $(intermediates)/util \ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 27; echo $$?), 0) LOCAL_C_INCLUDES += \ @@ -55,7 +56,7 @@ LOCAL_SRC_FILES := $(VULKAN_UTIL_FILES) $(VULKAN_WSI_FILES) vulkan_api_xml = $(MESA_TOP)/src/vulkan/registry/vk.xml -$(firstword $(LOCAL_GENERATED_SOURCES)): $(MESA_TOP)/src/vulkan/util/gen_enum_to_str.py \ +$(intermediates)/util/vk_enum_to_str.c: $(MESA_TOP)/src/vulkan/util/gen_enum_to_str.py \ $(vulkan_api_xml) @echo "target Generated: $(PRIVATE_MODULE) <= $(notdir $(@))" @mkdir -p $(dir $@) @@ -63,7 +64,50 @@ $(firstword $(LOCAL_GENERATED_SOURCES)): $(MESA_TOP)/src/vulkan/util/gen_enum_to --xml $(vulkan_api_xml) \ --outdir $(dir $@) -$(lastword $(LOCAL_GENERATED_SOURCES)): $(firstword $(LOCAL_GENERATED_SOURCES)) +$(intermediates)/util/vk_enum_to_str.h: $(intermediates)/util/vk_enum_to_str.c + +$(intermediates)/util/vk_common_entrypoints.c: $(MESA_TOP)/src/vulkan/util/vk_entrypoints_gen.py \ + $(vulkan_api_xml) + @echo "target Generated: $(PRIVATE_MODULE) <= $(notdir $(@))" + @mkdir -p $(dir $@) + $(hide) $(MESA_PYTHON2) $< \ + --xml $(vulkan_api_xml) \ + --proto --weak --prefix vk_common \ + --out-c $@ --out-h $(dir $@)/vk_common_entrypoints.h + +$(intermediates)/util/vk_common_entrypoints.h: $(intermediates)/util/vk_common_entrypoints.c + +$(intermediates)/util/vk_dispatch_table.c: $(MESA_TOP)/src/vulkan/util/vk_dispatch_table_gen.py \ + $(vulkan_api_xml) + @echo "target Generated: $(PRIVATE_MODULE) <= $(notdir $(@))" + @mkdir -p $(dir $@) + $(hide) $(MESA_PYTHON2) $< \ + --xml $(vulkan_api_xml) \ + --out-c $@ + +$(intermediates)/util/vk_dispatch_table.h: $(MESA_TOP)/src/vulkan/util/vk_dispatch_table_gen.py \ + $(vulkan_api_xml) + @echo "target Generated: $(PRIVATE_MODULE) <= $(notdir $(@))" + @mkdir -p $(dir $@) + $(hide) $(MESA_PYTHON2) $< \ + --xml $(vulkan_api_xml) \ + --out-h $@ + +$(intermediates)/util/vk_extensions.c: $(MESA_TOP)/src/vulkan/util/vk_extensions_gen.py \ + $(vulkan_api_xml) + @echo "target Generated: $(PRIVATE_MODULE) <= $(notdir $(@))" + @mkdir -p $(dir $@) + $(hide) $(MESA_PYTHON2) $< \ + --xml $(vulkan_api_xml) \ + --out-c $@ + +$(intermediates)/util/vk_extensions.h: $(MESA_TOP)/src/vulkan/util/vk_extensions_gen.py \ + $(vulkan_api_xml) + @echo "target Generated: $(PRIVATE_MODULE) <= $(notdir $(@))" + @mkdir -p $(dir $@) + $(hide) $(MESA_PYTHON2) $< \ + --xml $(vulkan_api_xml) \ + --out-h $@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(intermediates)/util diff --git a/lib/mesa/src/vulkan/meson.build b/lib/mesa/src/vulkan/meson.build index e1e8f753b..3f95551f2 100644 --- a/lib/mesa/src/vulkan/meson.build +++ b/lib/mesa/src/vulkan/meson.build @@ -22,6 +22,7 @@ vk_api_xml = files('registry/vk.xml') vulkan_icd_symbols = files('vulkan-icd-symbols.txt') inc_vulkan_wsi = include_directories('wsi') +inc_vulkan_util = include_directories('util') vulkan_wsi_args = [] vulkan_wsi_deps = [] @@ -32,10 +33,10 @@ if with_platform_x11 vulkan_wsi_deps += [ dep_xcb, dep_x11_xcb, - dep_xcb_dri2, dep_xcb_dri3, dep_xcb_present, dep_xcb_sync, + dep_xcb_xrandr, dep_xshmfence, ] vulkan_wsi_list += ['xcb', 'x11'] @@ -45,14 +46,17 @@ if with_platform_wayland vulkan_wsi_deps += dep_wayland_client vulkan_wsi_list += ['wayland'] endif -if with_platform_drm +if with_platform_windows + vulkan_wsi_args += ['-DVK_USE_PLATFORM_WIN32_KHR'] +endif +if system_has_kms_drm and not with_platform_android vulkan_wsi_args += '-DVK_USE_PLATFORM_DISPLAY_KHR' vulkan_wsi_deps += [dep_libdrm] vulkan_wsi_list += ['drm'] endif if with_xlib_lease vulkan_wsi_args += '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT' - vulkan_wsi_deps += [dep_xcb_xrandr, dep_xlib_xrandr] + vulkan_wsi_deps += [dep_xlib_xrandr] vulkan_wsi_list += ['xlib_xrandr'] endif @@ -62,3 +66,6 @@ subdir('wsi') if with_vulkan_overlay_layer subdir('overlay-layer') endif +if with_vulkan_device_select_layer + subdir('device-select-layer') +endif diff --git a/lib/mesa/src/vulkan/overlay-layer/meson.build b/lib/mesa/src/vulkan/overlay-layer/meson.build index 5f9224048..3225b3f51 100644 --- a/lib/mesa/src/vulkan/overlay-layer/meson.build +++ b/lib/mesa/src/vulkan/overlay-layer/meson.build @@ -18,8 +18,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -glslang = find_program('glslangValidator') - overlay_shaders = [ 'overlay.frag', 'overlay.vert', @@ -28,7 +26,7 @@ overlay_spv = [] foreach s : ['overlay.frag', 'overlay.vert'] overlay_spv += custom_target( s + '.spv.h', input : s, output : s + '.spv.h', - command : [glslang, '-V', '-x', '-o', '@OUTPUT@', '@INPUT@']) + command : [prog_glslang, '-V', '-x', '-o', '@OUTPUT@', '@INPUT@']) endforeach vklayer_files = files( @@ -38,11 +36,12 @@ vklayer_files = files( vklayer_mesa_overlay = shared_library( 'VkLayer_MESA_overlay', - vklayer_files, overlay_spv, - c_args : [c_vis_args, no_override_init_args, vulkan_wsi_args], - cpp_args : [cpp_vis_args, vulkan_wsi_args], + vklayer_files, overlay_spv, sha1_h, + c_args : [no_override_init_args, vulkan_wsi_args], + cpp_args : [vulkan_wsi_args], + gnu_symbol_visibility : 'hidden', dependencies : [idep_vulkan_util, idep_mesautil, vulkan_wsi_deps, libimgui_core_dep, dep_dl], - include_directories : inc_common, + include_directories : [inc_include, inc_src], link_args : cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions', '-Wl,-z,relro']), install : true ) diff --git a/lib/mesa/src/vulkan/overlay-layer/overlay.cpp b/lib/mesa/src/vulkan/overlay-layer/overlay.cpp index 565f5884b..6500c477b 100644 --- a/lib/mesa/src/vulkan/overlay-layer/overlay.cpp +++ b/lib/mesa/src/vulkan/overlay-layer/overlay.cpp @@ -43,11 +43,13 @@ #include "util/simple_mtx.h" #include "vk_enum_to_str.h" +#include "vk_dispatch_table.h" #include "vk_util.h" /* Mapped from VkInstace/VkPhysicalDevice */ struct instance_data { struct vk_instance_dispatch_table vtable; + struct vk_physical_device_dispatch_table pd_vtable; VkInstance instance; struct overlay_params params; @@ -125,6 +127,8 @@ struct overlay_draw { VkCommandBuffer command_buffer; + VkSemaphore cross_engine_semaphore; + VkSemaphore semaphore; VkFence fence; @@ -417,14 +421,14 @@ static void device_map_queues(struct device_data *data, struct instance_data *instance_data = data->instance; uint32_t n_family_props; - instance_data->vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device, - &n_family_props, - NULL); + instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device, + &n_family_props, + NULL); VkQueueFamilyProperties *family_props = (VkQueueFamilyProperties *)malloc(sizeof(VkQueueFamilyProperties) * n_family_props); - instance_data->vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device, - &n_family_props, - family_props); + instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device, + &n_family_props, + family_props); uint32_t queue_index = 0; for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) { @@ -544,6 +548,8 @@ struct overlay_draw *get_overlay_draw(struct swapchain_data *data) VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info, NULL, &draw->semaphore)); + VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info, + NULL, &draw->cross_engine_semaphore)); list_addtail(&draw->link, &data->draws); @@ -924,12 +930,16 @@ static void compute_swapchain_display(struct swapchain_data *data) ImGui::NewFrame(); position_layer(data); ImGui::Begin("Mesa overlay"); - ImGui::Text("Device: %s", device_data->properties.deviceName); + if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_device]) + ImGui::Text("Device: %s", device_data->properties.deviceName); - const char *format_name = vk_Format_to_str(data->format); - format_name = format_name ? (format_name + strlen("VK_FORMAT_")) : "unknown"; - ImGui::Text("Swapchain format: %s", format_name); - ImGui::Text("Frames: %" PRIu64, data->n_frames); + if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_format]) { + const char *format_name = vk_Format_to_str(data->format); + format_name = format_name ? (format_name + strlen("VK_FORMAT_")) : "unknown"; + ImGui::Text("Swapchain format: %s", format_name); + } + if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_frame]) + ImGui::Text("Frames: %" PRIu64, data->n_frames); if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_fps]) ImGui::Text("FPS: %.2f" , data->fps); @@ -999,7 +1009,7 @@ static uint32_t vk_memory_type(struct device_data *data, uint32_t type_bits) { VkPhysicalDeviceMemoryProperties prop; - data->instance->vtable.GetPhysicalDeviceMemoryProperties(data->physical_device, &prop); + data->instance->pd_vtable.GetPhysicalDeviceMemoryProperties(data->physical_device, &prop); for (uint32_t i = 0; i < prop.memoryTypeCount; i++) if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<<i)) return i; @@ -1322,7 +1332,7 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data if (device_data->graphic_queue->family_index != present_queue->family_index) { /* Transfer the image back to the present queue family - * image layout was already changed to present by the render pass + * image layout was already changed to present by the render pass */ imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imb.pNext = nullptr; @@ -1349,26 +1359,55 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data device_data->vtable.EndCommandBuffer(draw->command_buffer); - VkPipelineStageFlags *stages_wait = (VkPipelineStageFlags*) malloc(sizeof(VkPipelineStageFlags) * n_wait_semaphores); - for (unsigned i = 0; i < n_wait_semaphores; i++) - { - // wait in the fragment stage until the swapchain image is ready - stages_wait[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + /* When presenting on a different queue than where we're drawing the + * overlay *AND* when the application does not provide a semaphore to + * vkQueuePresent, insert our own cross engine synchronization + * semaphore. + */ + if (n_wait_semaphores == 0 && device_data->graphic_queue->queue != present_queue->queue) { + VkPipelineStageFlags stages_wait = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 0; + submit_info.pWaitDstStageMask = &stages_wait; + submit_info.waitSemaphoreCount = 0; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &draw->cross_engine_semaphore; + + device_data->vtable.QueueSubmit(present_queue->queue, 1, &submit_info, VK_NULL_HANDLE); + + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pWaitDstStageMask = &stages_wait; + submit_info.pCommandBuffers = &draw->command_buffer; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &draw->cross_engine_semaphore; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &draw->semaphore; + + device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence); + } else { + VkPipelineStageFlags *stages_wait = (VkPipelineStageFlags*) malloc(sizeof(VkPipelineStageFlags) * n_wait_semaphores); + for (unsigned i = 0; i < n_wait_semaphores; i++) + { + // wait in the fragment stage until the swapchain image is ready + stages_wait[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } + + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &draw->command_buffer; + submit_info.pWaitDstStageMask = stages_wait; + submit_info.waitSemaphoreCount = n_wait_semaphores; + submit_info.pWaitSemaphores = wait_semaphores; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &draw->semaphore; + + device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence); + + free(stages_wait); } - - VkSubmitInfo submit_info = {}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &draw->command_buffer; - submit_info.pWaitDstStageMask = stages_wait; - submit_info.waitSemaphoreCount = n_wait_semaphores; - submit_info.pWaitSemaphores = wait_semaphores; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &draw->semaphore; - - device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence); - - free(stages_wait); return draw; } @@ -1750,6 +1789,7 @@ static void shutdown_swapchain_data(struct swapchain_data *data) struct device_data *device_data = data->device; list_for_each_entry_safe(struct overlay_draw, draw, &data->draws, link) { + device_data->vtable.DestroySemaphore(device_data->device, draw->cross_engine_semaphore, NULL); device_data->vtable.DestroySemaphore(device_data->device, draw->semaphore, NULL); device_data->vtable.DestroyFence(device_data->device, draw->fence, NULL); device_data->vtable.DestroyBuffer(device_data->device, draw->vertex_buffer, NULL); @@ -1827,6 +1867,12 @@ static void overlay_DestroySwapchainKHR( VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { + if (swapchain == VK_NULL_HANDLE) { + struct device_data *device_data = FIND(struct device_data, device); + device_data->vtable.DestroySwapchainKHR(device, swapchain, pAllocator); + return; + } + struct swapchain_data *swapchain_data = FIND(struct swapchain_data, swapchain); @@ -2426,26 +2472,40 @@ static VkResult overlay_CreateDevice( chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; VkPhysicalDeviceFeatures device_features = {}; - VkDeviceCreateInfo device_info = *pCreateInfo; + VkPhysicalDeviceFeatures *device_features_ptr = NULL; + + VkDeviceCreateInfo *device_info = (VkDeviceCreateInfo *) + clone_chain((const struct VkBaseInStructure *)pCreateInfo); + + VkPhysicalDeviceFeatures2 *device_features2 = (VkPhysicalDeviceFeatures2 *) + vk_find_struct(device_info, PHYSICAL_DEVICE_FEATURES_2); + if (device_features2) { + /* Can't use device_info->pEnabledFeatures when VkPhysicalDeviceFeatures2 is present */ + device_features_ptr = &device_features2->features; + } else { + if (device_info->pEnabledFeatures) + device_features = *(device_info->pEnabledFeatures); + device_features_ptr = &device_features; + device_info->pEnabledFeatures = &device_features; + } - if (pCreateInfo->pEnabledFeatures) - device_features = *(pCreateInfo->pEnabledFeatures); if (instance_data->pipeline_statistics_enabled) { - device_features.inheritedQueries = true; - device_features.pipelineStatisticsQuery = true; + device_features_ptr->inheritedQueries = true; + device_features_ptr->pipelineStatisticsQuery = true; } - device_info.pEnabledFeatures = &device_features; - VkResult result = fpCreateDevice(physicalDevice, &device_info, pAllocator, pDevice); + VkResult result = fpCreateDevice(physicalDevice, device_info, pAllocator, pDevice); + free_chain((struct VkBaseOutStructure *)device_info); if (result != VK_SUCCESS) return result; struct device_data *device_data = new_device_data(*pDevice, instance_data); device_data->physical_device = physicalDevice; - vk_load_device_commands(*pDevice, fpGetDeviceProcAddr, &device_data->vtable); + vk_device_dispatch_table_load(&device_data->vtable, + fpGetDeviceProcAddr, *pDevice); - instance_data->vtable.GetPhysicalDeviceProperties(device_data->physical_device, - &device_data->properties); + instance_data->pd_vtable.GetPhysicalDeviceProperties(device_data->physical_device, + &device_data->properties); VkLayerDeviceCreateInfo *load_data_info = get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK); @@ -2490,9 +2550,12 @@ static VkResult overlay_CreateInstance( if (result != VK_SUCCESS) return result; struct instance_data *instance_data = new_instance_data(*pInstance); - vk_load_instance_commands(instance_data->instance, - fpGetInstanceProcAddr, - &instance_data->vtable); + vk_instance_dispatch_table_load(&instance_data->vtable, + fpGetInstanceProcAddr, + instance_data->instance); + vk_physical_device_dispatch_table_load(&instance_data->pd_vtable, + fpGetInstanceProcAddr, + instance_data->instance); instance_data_map_physical_devices(instance_data, true); parse_overlay_env(&instance_data->params, getenv("VK_LAYER_MESA_OVERLAY_CONFIG")); @@ -2529,6 +2592,7 @@ static const struct { const char *name; void *ptr; } name_to_funcptr_map[] = { + { "vkGetInstanceProcAddr", (void *) vkGetInstanceProcAddr }, { "vkGetDeviceProcAddr", (void *) vkGetDeviceProcAddr }, #define ADD_HOOK(fn) { "vk" # fn, (void *) overlay_ ## fn } #define ADD_ALIAS_HOOK(alias, fn) { "vk" # alias, (void *) overlay_ ## fn } diff --git a/lib/mesa/src/vulkan/overlay-layer/overlay_params.c b/lib/mesa/src/vulkan/overlay-layer/overlay_params.c index afc17ec07..48a9f7e3b 100644 --- a/lib/mesa/src/vulkan/overlay-layer/overlay_params.c +++ b/lib/mesa/src/vulkan/overlay-layer/overlay_params.c @@ -165,6 +165,8 @@ parse_overlay_env(struct overlay_params *params, /* Visible by default */ params->enabled[OVERLAY_PARAM_ENABLED_fps] = true; params->enabled[OVERLAY_PARAM_ENABLED_frame_timing] = true; + params->enabled[OVERLAY_PARAM_ENABLED_device] = true; + params->enabled[OVERLAY_PARAM_ENABLED_format] = true; params->fps_sampling_period = 500000; /* 500ms */ params->width = params->height = 300; params->control = -1; diff --git a/lib/mesa/src/vulkan/overlay-layer/overlay_params.h b/lib/mesa/src/vulkan/overlay-layer/overlay_params.h index 7ff092dae..e919f74ff 100644 --- a/lib/mesa/src/vulkan/overlay-layer/overlay_params.h +++ b/lib/mesa/src/vulkan/overlay-layer/overlay_params.h @@ -33,6 +33,8 @@ extern "C" { #include <stdbool.h> #define OVERLAY_PARAMS \ + OVERLAY_PARAM_BOOL(device) \ + OVERLAY_PARAM_BOOL(format) \ OVERLAY_PARAM_BOOL(fps) \ OVERLAY_PARAM_BOOL(frame) \ OVERLAY_PARAM_BOOL(frame_timing) \ 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 */ diff --git a/lib/mesa/src/vulkan/vulkan-icd-symbols.txt b/lib/mesa/src/vulkan/vulkan-icd-symbols.txt index feca419c0..b463ca83a 100644 --- a/lib/mesa/src/vulkan/vulkan-icd-symbols.txt +++ b/lib/mesa/src/vulkan/vulkan-icd-symbols.txt @@ -12,3 +12,8 @@ vk_icdNegotiateLoaderICDInterfaceVersion # Version 4 - Add unknown physical device extension querying via # vk_icdGetPhysicalDeviceProcAddr. (optional) vk_icdGetPhysicalDeviceProcAddr + +# Andoid looks for this global in HAL modules. In the source it occurs +# as HAL_MODULE_INFO_SYM (which is just a #define for HMI) and it's an +# instance of struct hwvulkan_module_t. +(optional) HMI diff --git a/lib/mesa/src/vulkan/wsi/meson.build b/lib/mesa/src/vulkan/wsi/meson.build index 6cf9a04f3..1deafa0c5 100644 --- a/lib/mesa/src/vulkan/wsi/meson.build +++ b/lib/mesa/src/vulkan/wsi/meson.build @@ -20,6 +20,10 @@ files_vulkan_wsi = files('wsi_common.c') +if dep_libdrm.found() + files_vulkan_wsi += files('wsi_common_drm.c') +endif + if with_platform_x11 files_vulkan_wsi += files('wsi_common_x11.c') endif @@ -34,15 +38,20 @@ if with_platform_wayland ] endif -if with_platform_drm +if with_platform_windows + files_vulkan_wsi += files('wsi_common_win32.c') +endif + +if system_has_kms_drm and not with_platform_android files_vulkan_wsi += files('wsi_common_display.c') endif libvulkan_wsi = static_library( 'vulkan_wsi', files_vulkan_wsi, - include_directories : [inc_common, inc_include], + include_directories : [inc_include, inc_src], dependencies : [vulkan_wsi_deps, dep_libdrm, idep_vulkan_util, idep_xmlconfig], - c_args : [c_vis_args, vulkan_wsi_args], + c_args : [vulkan_wsi_args], + gnu_symbol_visibility : 'hidden', build_by_default : false, ) diff --git a/lib/mesa/src/vulkan/wsi/wsi_common.c b/lib/mesa/src/vulkan/wsi/wsi_common.c index d629ea339..b1360edb9 100644 --- a/lib/mesa/src/vulkan/wsi/wsi_common.c +++ b/lib/mesa/src/vulkan/wsi/wsi_common.c @@ -22,14 +22,13 @@ */ #include "wsi_common_private.h" -#include "drm-uapi/drm_fourcc.h" #include "util/macros.h" +#include "util/os_file.h" +#include "util/os_time.h" #include "util/xmlconfig.h" #include "vk_util.h" #include <time.h> -#include <unistd.h> -#include <xf86drm.h> #include <stdlib.h> #include <stdio.h> @@ -39,7 +38,8 @@ wsi_device_init(struct wsi_device *wsi, WSI_FN_GetPhysicalDeviceProcAddr proc_addr, const VkAllocationCallbacks *alloc, int display_fd, - const struct driOptionCache *dri_options) + const struct driOptionCache *dri_options, + bool sw_device) { const char *present_mode; UNUSED VkResult result; @@ -48,7 +48,7 @@ wsi_device_init(struct wsi_device *wsi, wsi->instance_alloc = *alloc; wsi->pdevice = pdevice; - + wsi->sw = sw_device; #define WSI_GET_CB(func) \ PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func) WSI_GET_CB(GetPhysicalDeviceProperties2); @@ -93,13 +93,16 @@ wsi_device_init(struct wsi_device *wsi, WSI_GET_CB(GetImageDrmFormatModifierPropertiesEXT); WSI_GET_CB(GetImageMemoryRequirements); WSI_GET_CB(GetImageSubresourceLayout); - WSI_GET_CB(GetMemoryFdKHR); + if (!wsi->sw) + WSI_GET_CB(GetMemoryFdKHR); WSI_GET_CB(GetPhysicalDeviceFormatProperties); WSI_GET_CB(GetPhysicalDeviceFormatProperties2KHR); WSI_GET_CB(GetPhysicalDeviceImageFormatProperties2); WSI_GET_CB(ResetFences); WSI_GET_CB(QueueSubmit); WSI_GET_CB(WaitForFences); + WSI_GET_CB(MapMemory); + WSI_GET_CB(UnmapMemory); #undef WSI_GET_CB #ifdef VK_USE_PLATFORM_XCB_KHR @@ -114,6 +117,12 @@ wsi_device_init(struct wsi_device *wsi, goto fail; #endif +#ifdef VK_USE_PLATFORM_WIN32_KHR + result = wsi_win32_init_wsi(wsi, alloc, pdevice); + if (result != VK_SUCCESS) + goto fail; +#endif + #ifdef VK_USE_PLATFORM_DISPLAY_KHR result = wsi_display_init_wsi(wsi, alloc, display_fd); if (result != VK_SUCCESS) @@ -124,6 +133,8 @@ wsi_device_init(struct wsi_device *wsi, if (present_mode) { if (!strcmp(present_mode, "fifo")) { wsi->override_present_mode = VK_PRESENT_MODE_FIFO_KHR; + } else if (!strcmp(present_mode, "relaxed")) { + wsi->override_present_mode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; } else if (!strcmp(present_mode, "mailbox")) { wsi->override_present_mode = VK_PRESENT_MODE_MAILBOX_KHR; } else if (!strcmp(present_mode, "immediate")) { @@ -147,6 +158,7 @@ wsi_device_init(struct wsi_device *wsi, return VK_SUCCESS; #if defined(VK_USE_PLATFORM_XCB_KHR) || \ defined(VK_USE_PLATFORM_WAYLAND_KHR) || \ + defined(VK_USE_PLATFORM_WIN32_KHR) || \ defined(VK_USE_PLATFORM_DISPLAY_KHR) fail: wsi_device_finish(wsi, alloc); @@ -164,37 +176,14 @@ wsi_device_finish(struct wsi_device *wsi, #ifdef VK_USE_PLATFORM_WAYLAND_KHR wsi_wl_finish_wsi(wsi, alloc); #endif +#ifdef VK_USE_PLATFORM_WIN32_KHR + wsi_win32_finish_wsi(wsi, alloc); +#endif #ifdef VK_USE_PLATFORM_XCB_KHR wsi_x11_finish_wsi(wsi, alloc); #endif } -bool -wsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd) -{ - drmDevicePtr fd_device; - int ret = drmGetDevice2(drm_fd, 0, &fd_device); - if (ret) - return false; - - bool match = false; - switch (fd_device->bustype) { - case DRM_BUS_PCI: - match = wsi->pci_bus_info.pciDomain == fd_device->businfo.pci->domain && - wsi->pci_bus_info.pciBus == fd_device->businfo.pci->bus && - wsi->pci_bus_info.pciDevice == fd_device->businfo.pci->dev && - wsi->pci_bus_info.pciFunction == fd_device->businfo.pci->func; - break; - - default: - break; - } - - drmFreeDevice(&fd_device); - - return match; -} - VkResult wsi_swapchain_init(const struct wsi_device *wsi, struct wsi_swapchain *chain, @@ -206,6 +195,8 @@ wsi_swapchain_init(const struct wsi_device *wsi, memset(chain, 0, sizeof(*chain)); + vk_object_base_init(NULL, &chain->base, VK_OBJECT_TYPE_SWAPCHAIN_KHR); + chain->wsi = wsi; chain->device = device; chain->alloc = *pAllocator; @@ -305,562 +296,8 @@ wsi_swapchain_finish(struct wsi_swapchain *chain) &chain->alloc); } vk_free(&chain->alloc, chain->cmd_pools); -} - -static uint32_t -select_memory_type(const struct wsi_device *wsi, - VkMemoryPropertyFlags props, - uint32_t type_bits) -{ - for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) { - const VkMemoryType type = wsi->memory_props.memoryTypes[i]; - if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props) - return i; - } - - unreachable("No memory type found"); -} - -static uint32_t -vk_format_size(VkFormat format) -{ - switch (format) { - case VK_FORMAT_B8G8R8A8_UNORM: - case VK_FORMAT_B8G8R8A8_SRGB: - return 4; - default: - unreachable("Unknown WSI Format"); - } -} - -static inline uint32_t -align_u32(uint32_t v, uint32_t a) -{ - assert(a != 0 && a == (a & -a)); - return (v + a - 1) & ~(a - 1); -} - -VkResult -wsi_create_native_image(const struct wsi_swapchain *chain, - const VkSwapchainCreateInfoKHR *pCreateInfo, - uint32_t num_modifier_lists, - const uint32_t *num_modifiers, - const uint64_t *const *modifiers, - struct wsi_image *image) -{ - const struct wsi_device *wsi = chain->wsi; - VkResult result; - - memset(image, 0, sizeof(*image)); - for (int i = 0; i < ARRAY_SIZE(image->fds); i++) - image->fds[i] = -1; - - VkImageCreateInfo image_info = { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .flags = 0, - .imageType = VK_IMAGE_TYPE_2D, - .format = pCreateInfo->imageFormat, - .extent = { - .width = pCreateInfo->imageExtent.width, - .height = pCreateInfo->imageExtent.height, - .depth = 1, - }, - .mipLevels = 1, - .arrayLayers = 1, - .samples = VK_SAMPLE_COUNT_1_BIT, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = pCreateInfo->imageUsage, - .sharingMode = pCreateInfo->imageSharingMode, - .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, - .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - }; - - VkImageFormatListCreateInfoKHR image_format_list; - if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) { - image_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | - VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR; - - const VkImageFormatListCreateInfoKHR *format_list = - vk_find_struct_const(pCreateInfo->pNext, - IMAGE_FORMAT_LIST_CREATE_INFO_KHR); - -#ifndef NDEBUG - assume(format_list && format_list->viewFormatCount > 0); - bool format_found = false; - for (int i = 0; i < format_list->viewFormatCount; i++) - if (pCreateInfo->imageFormat == format_list->pViewFormats[i]) - format_found = true; - assert(format_found); -#endif - - image_format_list = *format_list; - image_format_list.pNext = NULL; - __vk_append_struct(&image_info, &image_format_list); - } - - struct wsi_image_create_info image_wsi_info; - VkImageDrmFormatModifierListCreateInfoEXT image_modifier_list; - - uint32_t image_modifier_count = 0, modifier_prop_count = 0; - struct VkDrmFormatModifierPropertiesEXT *modifier_props = NULL; - uint64_t *image_modifiers = NULL; - if (num_modifier_lists == 0) { - /* If we don't have modifiers, fall back to the legacy "scanout" flag */ - image_wsi_info = (struct wsi_image_create_info) { - .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA, - .scanout = true, - }; - __vk_append_struct(&image_info, &image_wsi_info); - } else { - /* The winsys can't request modifiers if we don't support them. */ - assert(wsi->supports_modifiers); - struct VkDrmFormatModifierPropertiesListEXT modifier_props_list = { - .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT, - }; - VkFormatProperties2 format_props = { - .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, - .pNext = &modifier_props_list, - }; - wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice, - pCreateInfo->imageFormat, - &format_props); - assert(modifier_props_list.drmFormatModifierCount > 0); - modifier_props = vk_alloc(&chain->alloc, - sizeof(*modifier_props) * - modifier_props_list.drmFormatModifierCount, - 8, - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); - if (!modifier_props) { - result = VK_ERROR_OUT_OF_HOST_MEMORY; - goto fail; - } - - modifier_props_list.pDrmFormatModifierProperties = modifier_props; - wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice, - pCreateInfo->imageFormat, - &format_props); - - /* Call GetImageFormatProperties with every modifier and filter the list - * down to those that we know work. - */ - modifier_prop_count = 0; - for (uint32_t i = 0; i < modifier_props_list.drmFormatModifierCount; i++) { - VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT, - .drmFormatModifier = modifier_props[i].drmFormatModifier, - .sharingMode = pCreateInfo->imageSharingMode, - .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, - .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, - }; - VkPhysicalDeviceImageFormatInfo2 format_info = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, - .format = pCreateInfo->imageFormat, - .type = VK_IMAGE_TYPE_2D, - .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, - .usage = pCreateInfo->imageUsage, - .flags = image_info.flags, - }; - - VkImageFormatListCreateInfoKHR format_list; - if (image_info.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) { - format_list = image_format_list; - format_list.pNext = NULL; - __vk_append_struct(&format_info, &format_list); - } - - VkImageFormatProperties2 format_props = { - .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, - .pNext = NULL, - }; - __vk_append_struct(&format_info, &mod_info); - result = wsi->GetPhysicalDeviceImageFormatProperties2(wsi->pdevice, - &format_info, - &format_props); - if (result == VK_SUCCESS) - modifier_props[modifier_prop_count++] = modifier_props[i]; - } - - uint32_t max_modifier_count = 0; - for (uint32_t l = 0; l < num_modifier_lists; l++) - max_modifier_count = MAX2(max_modifier_count, num_modifiers[l]); - - image_modifiers = vk_alloc(&chain->alloc, - sizeof(*image_modifiers) * - max_modifier_count, - 8, - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); - if (!image_modifiers) { - result = VK_ERROR_OUT_OF_HOST_MEMORY; - goto fail; - } - - image_modifier_count = 0; - for (uint32_t l = 0; l < num_modifier_lists; l++) { - /* Walk the modifier lists and construct a list of supported - * modifiers. - */ - for (uint32_t i = 0; i < num_modifiers[l]; i++) { - for (uint32_t j = 0; j < modifier_prop_count; j++) { - if (modifier_props[j].drmFormatModifier == modifiers[l][i]) - image_modifiers[image_modifier_count++] = modifiers[l][i]; - } - } - - /* We only want to take the modifiers from the first list */ - if (image_modifier_count > 0) - break; - } - - if (image_modifier_count > 0) { - image_modifier_list = (VkImageDrmFormatModifierListCreateInfoEXT) { - .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT, - .drmFormatModifierCount = image_modifier_count, - .pDrmFormatModifiers = image_modifiers, - }; - image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; - __vk_append_struct(&image_info, &image_modifier_list); - } else { - /* TODO: Add a proper error here */ - assert(!"Failed to find a supported modifier! This should never " - "happen because LINEAR should always be available"); - result = VK_ERROR_OUT_OF_HOST_MEMORY; - goto fail; - } - } - - result = wsi->CreateImage(chain->device, &image_info, - &chain->alloc, &image->image); - if (result != VK_SUCCESS) - goto fail; - - VkMemoryRequirements reqs; - wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); - - const struct wsi_memory_allocate_info memory_wsi_info = { - .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, - .pNext = NULL, - .implicit_sync = true, - }; - const VkExportMemoryAllocateInfo memory_export_info = { - .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, - .pNext = &memory_wsi_info, - .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, - }; - const VkMemoryDedicatedAllocateInfo memory_dedicated_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, - .pNext = &memory_export_info, - .image = image->image, - .buffer = VK_NULL_HANDLE, - }; - const VkMemoryAllocateInfo memory_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = &memory_dedicated_info, - .allocationSize = reqs.size, - .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - reqs.memoryTypeBits), - }; - result = wsi->AllocateMemory(chain->device, &memory_info, - &chain->alloc, &image->memory); - if (result != VK_SUCCESS) - goto fail; - - result = wsi->BindImageMemory(chain->device, image->image, - image->memory, 0); - if (result != VK_SUCCESS) - goto fail; - - const VkMemoryGetFdInfoKHR memory_get_fd_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, - .pNext = NULL, - .memory = image->memory, - .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, - }; - int fd; - result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd); - if (result != VK_SUCCESS) - goto fail; - - if (num_modifier_lists > 0) { - VkImageDrmFormatModifierPropertiesEXT image_mod_props = { - .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT, - }; - result = wsi->GetImageDrmFormatModifierPropertiesEXT(chain->device, - image->image, - &image_mod_props); - if (result != VK_SUCCESS) { - close(fd); - goto fail; - } - image->drm_modifier = image_mod_props.drmFormatModifier; - assert(image->drm_modifier != DRM_FORMAT_MOD_INVALID); - for (uint32_t j = 0; j < modifier_prop_count; j++) { - if (modifier_props[j].drmFormatModifier == image->drm_modifier) { - image->num_planes = modifier_props[j].drmFormatModifierPlaneCount; - break; - } - } - - for (uint32_t p = 0; p < image->num_planes; p++) { - const VkImageSubresource image_subresource = { - .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << p, - .mipLevel = 0, - .arrayLayer = 0, - }; - VkSubresourceLayout image_layout; - wsi->GetImageSubresourceLayout(chain->device, image->image, - &image_subresource, &image_layout); - image->sizes[p] = image_layout.size; - image->row_pitches[p] = image_layout.rowPitch; - image->offsets[p] = image_layout.offset; - if (p == 0) { - image->fds[p] = fd; - } else { - image->fds[p] = dup(fd); - if (image->fds[p] == -1) { - for (uint32_t i = 0; i < p; i++) - close(image->fds[i]); - - result = VK_ERROR_OUT_OF_HOST_MEMORY; - goto fail; - } - } - } - } else { - const VkImageSubresource image_subresource = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .arrayLayer = 0, - }; - VkSubresourceLayout image_layout; - wsi->GetImageSubresourceLayout(chain->device, image->image, - &image_subresource, &image_layout); - - image->drm_modifier = DRM_FORMAT_MOD_INVALID; - image->num_planes = 1; - image->sizes[0] = reqs.size; - image->row_pitches[0] = image_layout.rowPitch; - image->offsets[0] = 0; - image->fds[0] = fd; - } - - vk_free(&chain->alloc, modifier_props); - vk_free(&chain->alloc, image_modifiers); - - return VK_SUCCESS; - -fail: - vk_free(&chain->alloc, modifier_props); - vk_free(&chain->alloc, image_modifiers); - wsi_destroy_image(chain, image); - - return result; -} - -#define WSI_PRIME_LINEAR_STRIDE_ALIGN 256 - -VkResult -wsi_create_prime_image(const struct wsi_swapchain *chain, - const VkSwapchainCreateInfoKHR *pCreateInfo, - bool use_modifier, - struct wsi_image *image) -{ - const struct wsi_device *wsi = chain->wsi; - VkResult result; - - memset(image, 0, sizeof(*image)); - - const uint32_t cpp = vk_format_size(pCreateInfo->imageFormat); - const uint32_t linear_stride = align_u32(pCreateInfo->imageExtent.width * cpp, - WSI_PRIME_LINEAR_STRIDE_ALIGN); - - uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height; - linear_size = align_u32(linear_size, 4096); - - const VkExternalMemoryBufferCreateInfo prime_buffer_external_info = { - .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, - .pNext = NULL, - .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, - }; - const VkBufferCreateInfo prime_buffer_info = { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = &prime_buffer_external_info, - .size = linear_size, - .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - }; - result = wsi->CreateBuffer(chain->device, &prime_buffer_info, - &chain->alloc, &image->prime.buffer); - if (result != VK_SUCCESS) - goto fail; - - VkMemoryRequirements reqs; - wsi->GetBufferMemoryRequirements(chain->device, image->prime.buffer, &reqs); - assert(reqs.size <= linear_size); - - const struct wsi_memory_allocate_info memory_wsi_info = { - .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, - .pNext = NULL, - .implicit_sync = true, - }; - const VkExportMemoryAllocateInfo prime_memory_export_info = { - .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, - .pNext = &memory_wsi_info, - .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, - }; - const VkMemoryDedicatedAllocateInfo prime_memory_dedicated_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, - .pNext = &prime_memory_export_info, - .image = VK_NULL_HANDLE, - .buffer = image->prime.buffer, - }; - const VkMemoryAllocateInfo prime_memory_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = &prime_memory_dedicated_info, - .allocationSize = linear_size, - .memoryTypeIndex = select_memory_type(wsi, 0, reqs.memoryTypeBits), - }; - result = wsi->AllocateMemory(chain->device, &prime_memory_info, - &chain->alloc, &image->prime.memory); - if (result != VK_SUCCESS) - goto fail; - - result = wsi->BindBufferMemory(chain->device, image->prime.buffer, - image->prime.memory, 0); - if (result != VK_SUCCESS) - goto fail; - - const VkImageCreateInfo image_info = { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = NULL, - .flags = 0, - .imageType = VK_IMAGE_TYPE_2D, - .format = pCreateInfo->imageFormat, - .extent = { - .width = pCreateInfo->imageExtent.width, - .height = pCreateInfo->imageExtent.height, - .depth = 1, - }, - .mipLevels = 1, - .arrayLayers = 1, - .samples = VK_SAMPLE_COUNT_1_BIT, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = pCreateInfo->imageUsage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, - .sharingMode = pCreateInfo->imageSharingMode, - .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, - .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - }; - result = wsi->CreateImage(chain->device, &image_info, - &chain->alloc, &image->image); - if (result != VK_SUCCESS) - goto fail; - - wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); - - const VkMemoryDedicatedAllocateInfo memory_dedicated_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, - .pNext = NULL, - .image = image->image, - .buffer = VK_NULL_HANDLE, - }; - const VkMemoryAllocateInfo memory_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = &memory_dedicated_info, - .allocationSize = reqs.size, - .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - reqs.memoryTypeBits), - }; - result = wsi->AllocateMemory(chain->device, &memory_info, - &chain->alloc, &image->memory); - if (result != VK_SUCCESS) - goto fail; - - result = wsi->BindImageMemory(chain->device, image->image, - image->memory, 0); - if (result != VK_SUCCESS) - goto fail; - - image->prime.blit_cmd_buffers = - vk_zalloc(&chain->alloc, - sizeof(VkCommandBuffer) * wsi->queue_family_count, 8, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - if (!image->prime.blit_cmd_buffers) { - result = VK_ERROR_OUT_OF_HOST_MEMORY; - goto fail; - } - - for (uint32_t i = 0; i < wsi->queue_family_count; i++) { - const VkCommandBufferAllocateInfo cmd_buffer_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .pNext = NULL, - .commandPool = chain->cmd_pools[i], - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1, - }; - result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info, - &image->prime.blit_cmd_buffers[i]); - if (result != VK_SUCCESS) - goto fail; - - const VkCommandBufferBeginInfo begin_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - }; - wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info); - - struct VkBufferImageCopy buffer_image_copy = { - .bufferOffset = 0, - .bufferRowLength = linear_stride / cpp, - .bufferImageHeight = 0, - .imageSubresource = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }, - .imageOffset = { .x = 0, .y = 0, .z = 0 }, - .imageExtent = { - .width = pCreateInfo->imageExtent.width, - .height = pCreateInfo->imageExtent.height, - .depth = 1, - }, - }; - wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i], - image->image, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - image->prime.buffer, - 1, &buffer_image_copy); - - result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]); - if (result != VK_SUCCESS) - goto fail; - } - - const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, - .pNext = NULL, - .memory = image->prime.memory, - .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, - }; - int fd; - result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd); - if (result != VK_SUCCESS) - goto fail; - - image->drm_modifier = use_modifier ? DRM_FORMAT_MOD_LINEAR : DRM_FORMAT_MOD_INVALID; - image->num_planes = 1; - image->sizes[0] = linear_size; - image->row_pitches[0] = linear_stride; - image->offsets[0] = 0; - image->fds[0] = fd; - - return VK_SUCCESS; - -fail: - wsi_destroy_image(chain, image); - - return result; + vk_object_base_finish(&chain->base); } void @@ -1061,7 +498,7 @@ wsi_common_destroy_swapchain(VkDevice device, VkSwapchainKHR _swapchain, const VkAllocationCallbacks *pAllocator) { - WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); + VK_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); if (!swapchain) return; @@ -1073,11 +510,11 @@ wsi_common_get_images(VkSwapchainKHR _swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) { - WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); - VK_OUTARRAY_MAKE(images, pSwapchainImages, pSwapchainImageCount); + VK_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); + VK_OUTARRAY_MAKE_TYPED(VkImage, images, pSwapchainImages, pSwapchainImageCount); for (uint32_t i = 0; i < swapchain->image_count; i++) { - vk_outarray_append(&images, image) { + vk_outarray_append_typed(VkImage, &images, image) { *image = swapchain->get_wsi_image(swapchain, i)->image; } } @@ -1091,13 +528,18 @@ wsi_common_acquire_next_image2(const struct wsi_device *wsi, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex) { - WSI_FROM_HANDLE(wsi_swapchain, swapchain, pAcquireInfo->swapchain); + VK_FROM_HANDLE(wsi_swapchain, swapchain, pAcquireInfo->swapchain); VkResult result = swapchain->acquire_next_image(swapchain, pAcquireInfo, pImageIndex); - if (result != VK_SUCCESS) + if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) return result; + if (wsi->set_memory_ownership) { + VkDeviceMemory mem = swapchain->get_wsi_image(swapchain, *pImageIndex)->memory; + wsi->set_memory_ownership(swapchain->device, mem, true); + } + if (pAcquireInfo->semaphore != VK_NULL_HANDLE && wsi->signal_semaphore_for_memory != NULL) { struct wsi_image *image = @@ -1114,7 +556,7 @@ wsi_common_acquire_next_image2(const struct wsi_device *wsi, image->memory); } - return VK_SUCCESS; + return result; } VkResult @@ -1130,7 +572,7 @@ wsi_common_queue_present(const struct wsi_device *wsi, vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR); for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) { - WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]); + VK_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]); uint32_t image_index = pPresentInfo->pImageIndices[i]; VkResult result; @@ -1216,9 +658,14 @@ wsi_common_queue_present(const struct wsi_device *wsi, region = ®ions->pRegions[i]; result = swapchain->queue_present(swapchain, image_index, region); - if (result != VK_SUCCESS) + if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) goto fail_present; + if (wsi->set_memory_ownership) { + VkDeviceMemory mem = swapchain->get_wsi_image(swapchain, image_index)->memory; + wsi->set_memory_ownership(swapchain->device, mem, false); + } + fail_present: if (pPresentInfo->pResults != NULL) pPresentInfo->pResults[i] = result; @@ -1234,7 +681,5 @@ wsi_common_queue_present(const struct wsi_device *wsi, uint64_t wsi_common_get_current_time(void) { - struct timespec current; - clock_gettime(CLOCK_MONOTONIC, ¤t); - return current.tv_nsec + current.tv_sec * 1000000000ull; + return os_time_get_nano(); } diff --git a/lib/mesa/src/vulkan/wsi/wsi_common_display.c b/lib/mesa/src/vulkan/wsi/wsi_common_display.c index 0f9a1ffe8..e25dc1a3f 100644 --- a/lib/mesa/src/vulkan/wsi/wsi_common_display.c +++ b/lib/mesa/src/vulkan/wsi/wsi_common_display.c @@ -137,6 +137,7 @@ struct wsi_display_fence { struct wsi_fence base; bool event_received; bool destroyed; + uint32_t syncobj; /* syncobj to signal on event */ uint64_t sequence; }; @@ -814,7 +815,10 @@ wsi_display_surface_get_support(VkIcdSurfaceBase *surface, uint32_t queueFamilyIndex, VkBool32* pSupported) { - *pSupported = VK_TRUE; + struct wsi_display *wsi = + (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + + *pSupported = wsi->fd != -1; return VK_SUCCESS; } @@ -1209,8 +1213,8 @@ wsi_display_wait_thread(void *data) if (ret > 0) { pthread_mutex_lock(&wsi->wait_mutex); (void) drmHandleEvent(wsi->fd, &event_context); - pthread_mutex_unlock(&wsi->wait_mutex); pthread_cond_broadcast(&wsi->wait_cond); + pthread_mutex_unlock(&wsi->wait_mutex); } } return NULL; @@ -1228,6 +1232,18 @@ wsi_display_start_wait_thread(struct wsi_display *wsi) return 0; } +static void +wsi_display_stop_wait_thread(struct wsi_display *wsi) +{ + pthread_mutex_lock(&wsi->wait_mutex); + if (wsi->wait_thread) { + pthread_cancel(wsi->wait_thread); + pthread_join(wsi->wait_thread, NULL); + wsi->wait_thread = 0; + } + pthread_mutex_unlock(&wsi->wait_mutex); +} + /* * Wait for at least one event from the kernel to be processed. * Call with wait_mutex held @@ -1515,6 +1531,14 @@ wsi_display_fence_check_free(struct wsi_display_fence *fence) static void wsi_display_fence_event_handler(struct wsi_display_fence *fence) { + struct wsi_display *wsi = + (struct wsi_display *) fence->base.wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + + if (fence->syncobj) { + (void) drmSyncobjSignal(wsi->fd, &fence->syncobj, 1); + (void) drmSyncobjDestroy(wsi->fd, fence->syncobj); + } + fence->event_received = true; wsi_display_fence_check_free(fence); } @@ -1533,7 +1557,8 @@ static struct wsi_display_fence * wsi_display_fence_alloc(VkDevice device, const struct wsi_device *wsi_device, VkDisplayKHR display, - const VkAllocationCallbacks *allocator) + const VkAllocationCallbacks *allocator, + int sync_fd) { struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; @@ -1544,6 +1569,14 @@ wsi_display_fence_alloc(VkDevice device, if (!fence) return NULL; + if (sync_fd >= 0) { + int ret = drmSyncobjFDToHandle(wsi->fd, sync_fd, &fence->syncobj); + if (ret) { + vk_free2(wsi->alloc, allocator, fence); + return NULL; + } + } + fence->base.device = device; fence->base.display = display; fence->base.wsi_device = wsi_device; @@ -1936,12 +1969,7 @@ wsi_display_finish_wsi(struct wsi_device *wsi_device, vk_free(wsi->alloc, connector); } - pthread_mutex_lock(&wsi->wait_mutex); - if (wsi->wait_thread) { - pthread_cancel(wsi->wait_thread); - pthread_join(wsi->wait_thread, NULL); - } - pthread_mutex_unlock(&wsi->wait_mutex); + wsi_display_stop_wait_thread(wsi); pthread_mutex_destroy(&wsi->wait_mutex); pthread_cond_destroy(&wsi->wait_cond); @@ -1961,9 +1989,12 @@ wsi_release_display(VkPhysicalDevice physical_device, (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; if (wsi->fd >= 0) { + wsi_display_stop_wait_thread(wsi); + close(wsi->fd); wsi->fd = -1; } + #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT wsi_display_connector_from_handle(display)->output = None; #endif @@ -2489,7 +2520,8 @@ wsi_register_device_event(VkDevice device, struct wsi_device *wsi_device, const VkDeviceEventInfoEXT *device_event_info, const VkAllocationCallbacks *allocator, - struct wsi_fence **fence_p) + struct wsi_fence **fence_p, + int sync_fd) { return VK_ERROR_FEATURE_NOT_PRESENT; } @@ -2500,7 +2532,8 @@ wsi_register_display_event(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT *display_event_info, const VkAllocationCallbacks *allocator, - struct wsi_fence **fence_p) + struct wsi_fence **fence_p, + int sync_fd) { struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; @@ -2510,7 +2543,7 @@ wsi_register_display_event(VkDevice device, switch (display_event_info->displayEvent) { case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT: - fence = wsi_display_fence_alloc(device, wsi_device, display, allocator); + fence = wsi_display_fence_alloc(device, wsi_device, display, allocator, sync_fd); if (!fence) return VK_ERROR_OUT_OF_HOST_MEMORY; @@ -2518,10 +2551,16 @@ wsi_register_display_event(VkDevice device, ret = wsi_register_vblank_event(fence, wsi_device, display, DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL); - if (ret == VK_SUCCESS) - *fence_p = &fence->base; - else if (fence != NULL) + if (ret == VK_SUCCESS) { + if (fence_p) + *fence_p = &fence->base; + else + fence->base.destroy(&fence->base); + } else if (fence != NULL) { + if (fence->syncobj) + drmSyncobjDestroy(wsi->fd, fence->syncobj); vk_free2(wsi->alloc, allocator, fence); + } break; default: diff --git a/lib/mesa/src/vulkan/wsi/wsi_common_display.h b/lib/mesa/src/vulkan/wsi/wsi_common_display.h index be0bd4e06..d65517ab9 100644 --- a/lib/mesa/src/vulkan/wsi/wsi_common_display.h +++ b/lib/mesa/src/vulkan/wsi/wsi_common_display.h @@ -27,11 +27,6 @@ #include <xf86drm.h> #include <xf86drmMode.h> -#define typed_memcpy(dest, src, count) ({ \ - STATIC_ASSERT(sizeof(*src) == sizeof(*dest)); \ - memcpy((dest), (src), (count) * sizeof(*(src))); \ -}) - VkResult wsi_display_get_physical_device_display_properties( VkPhysicalDevice physical_device, @@ -143,7 +138,8 @@ wsi_register_device_event(VkDevice device, struct wsi_device *wsi_device, const VkDeviceEventInfoEXT *device_event_info, const VkAllocationCallbacks *allocator, - struct wsi_fence **fence); + struct wsi_fence **fence, + int sync_fd); VkResult wsi_register_display_event(VkDevice device, @@ -151,7 +147,8 @@ wsi_register_display_event(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT *display_event_info, const VkAllocationCallbacks *allocator, - struct wsi_fence **fence); + struct wsi_fence **fence, + int sync_fd); VkResult wsi_get_swapchain_counter(VkDevice device, diff --git a/lib/mesa/src/vulkan/wsi/wsi_common_drm.c b/lib/mesa/src/vulkan/wsi/wsi_common_drm.c new file mode 100644 index 000000000..1f81a92ff --- /dev/null +++ b/lib/mesa/src/vulkan/wsi/wsi_common_drm.c @@ -0,0 +1,621 @@ +/* + * 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 "wsi_common_private.h" +#include "util/macros.h" +#include "util/os_file.h" +#include "util/xmlconfig.h" +#include "vk_util.h" +#include "drm-uapi/drm_fourcc.h" + +#include <time.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <xf86drm.h> + +bool +wsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd) +{ + drmDevicePtr fd_device; + int ret = drmGetDevice2(drm_fd, 0, &fd_device); + if (ret) + return false; + + bool match = false; + switch (fd_device->bustype) { + case DRM_BUS_PCI: + match = wsi->pci_bus_info.pciDomain == fd_device->businfo.pci->domain && + wsi->pci_bus_info.pciBus == fd_device->businfo.pci->bus && + wsi->pci_bus_info.pciDevice == fd_device->businfo.pci->dev && + wsi->pci_bus_info.pciFunction == fd_device->businfo.pci->func; + break; + + default: + break; + } + + drmFreeDevice(&fd_device); + + return match; +} + +static uint32_t +select_memory_type(const struct wsi_device *wsi, + VkMemoryPropertyFlags props, + uint32_t type_bits) +{ + for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) { + const VkMemoryType type = wsi->memory_props.memoryTypes[i]; + if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props) + return i; + } + + unreachable("No memory type found"); +} + +static uint32_t +vk_format_size(VkFormat format) +{ + switch (format) { + case VK_FORMAT_B8G8R8A8_UNORM: + case VK_FORMAT_B8G8R8A8_SRGB: + return 4; + default: + unreachable("Unknown WSI Format"); + } +} + +VkResult +wsi_create_native_image(const struct wsi_swapchain *chain, + const VkSwapchainCreateInfoKHR *pCreateInfo, + uint32_t num_modifier_lists, + const uint32_t *num_modifiers, + const uint64_t *const *modifiers, + struct wsi_image *image) +{ + const struct wsi_device *wsi = chain->wsi; + VkResult result; + + memset(image, 0, sizeof(*image)); + for (int i = 0; i < ARRAY_SIZE(image->fds); i++) + image->fds[i] = -1; + + VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = pCreateInfo->imageFormat, + .extent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = pCreateInfo->imageUsage, + .sharingMode = pCreateInfo->imageSharingMode, + .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, + .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + + VkImageFormatListCreateInfoKHR image_format_list; + if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) { + image_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR; + + const VkImageFormatListCreateInfoKHR *format_list = + vk_find_struct_const(pCreateInfo->pNext, + IMAGE_FORMAT_LIST_CREATE_INFO_KHR); + +#ifndef NDEBUG + assume(format_list && format_list->viewFormatCount > 0); + bool format_found = false; + for (int i = 0; i < format_list->viewFormatCount; i++) + if (pCreateInfo->imageFormat == format_list->pViewFormats[i]) + format_found = true; + assert(format_found); +#endif + + image_format_list = *format_list; + image_format_list.pNext = NULL; + __vk_append_struct(&image_info, &image_format_list); + } + + struct wsi_image_create_info image_wsi_info; + VkImageDrmFormatModifierListCreateInfoEXT image_modifier_list; + + uint32_t image_modifier_count = 0, modifier_prop_count = 0; + struct VkDrmFormatModifierPropertiesEXT *modifier_props = NULL; + uint64_t *image_modifiers = NULL; + if (num_modifier_lists == 0) { + /* If we don't have modifiers, fall back to the legacy "scanout" flag */ + image_wsi_info = (struct wsi_image_create_info) { + .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA, + .scanout = true, + }; + __vk_append_struct(&image_info, &image_wsi_info); + } else { + /* The winsys can't request modifiers if we don't support them. */ + assert(wsi->supports_modifiers); + struct VkDrmFormatModifierPropertiesListEXT modifier_props_list = { + .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT, + }; + VkFormatProperties2 format_props = { + .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, + .pNext = &modifier_props_list, + }; + wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice, + pCreateInfo->imageFormat, + &format_props); + assert(modifier_props_list.drmFormatModifierCount > 0); + modifier_props = vk_alloc(&chain->alloc, + sizeof(*modifier_props) * + modifier_props_list.drmFormatModifierCount, + 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!modifier_props) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + modifier_props_list.pDrmFormatModifierProperties = modifier_props; + wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice, + pCreateInfo->imageFormat, + &format_props); + + /* Call GetImageFormatProperties with every modifier and filter the list + * down to those that we know work. + */ + modifier_prop_count = 0; + for (uint32_t i = 0; i < modifier_props_list.drmFormatModifierCount; i++) { + VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT, + .drmFormatModifier = modifier_props[i].drmFormatModifier, + .sharingMode = pCreateInfo->imageSharingMode, + .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, + .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, + }; + VkPhysicalDeviceImageFormatInfo2 format_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .format = pCreateInfo->imageFormat, + .type = VK_IMAGE_TYPE_2D, + .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, + .usage = pCreateInfo->imageUsage, + .flags = image_info.flags, + }; + + VkImageFormatListCreateInfoKHR format_list; + if (image_info.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) { + format_list = image_format_list; + format_list.pNext = NULL; + __vk_append_struct(&format_info, &format_list); + } + + VkImageFormatProperties2 format_props = { + .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, + .pNext = NULL, + }; + __vk_append_struct(&format_info, &mod_info); + result = wsi->GetPhysicalDeviceImageFormatProperties2(wsi->pdevice, + &format_info, + &format_props); + if (result == VK_SUCCESS) + modifier_props[modifier_prop_count++] = modifier_props[i]; + } + + uint32_t max_modifier_count = 0; + for (uint32_t l = 0; l < num_modifier_lists; l++) + max_modifier_count = MAX2(max_modifier_count, num_modifiers[l]); + + image_modifiers = vk_alloc(&chain->alloc, + sizeof(*image_modifiers) * + max_modifier_count, + 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!image_modifiers) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + image_modifier_count = 0; + for (uint32_t l = 0; l < num_modifier_lists; l++) { + /* Walk the modifier lists and construct a list of supported + * modifiers. + */ + for (uint32_t i = 0; i < num_modifiers[l]; i++) { + for (uint32_t j = 0; j < modifier_prop_count; j++) { + if (modifier_props[j].drmFormatModifier == modifiers[l][i]) + image_modifiers[image_modifier_count++] = modifiers[l][i]; + } + } + + /* We only want to take the modifiers from the first list */ + if (image_modifier_count > 0) + break; + } + + if (image_modifier_count > 0) { + image_modifier_list = (VkImageDrmFormatModifierListCreateInfoEXT) { + .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT, + .drmFormatModifierCount = image_modifier_count, + .pDrmFormatModifiers = image_modifiers, + }; + image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; + __vk_append_struct(&image_info, &image_modifier_list); + } else { + /* TODO: Add a proper error here */ + assert(!"Failed to find a supported modifier! This should never " + "happen because LINEAR should always be available"); + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + } + + result = wsi->CreateImage(chain->device, &image_info, + &chain->alloc, &image->image); + if (result != VK_SUCCESS) + goto fail; + + VkMemoryRequirements reqs; + wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); + + const struct wsi_memory_allocate_info memory_wsi_info = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, + .pNext = NULL, + .implicit_sync = true, + }; + const VkExportMemoryAllocateInfo memory_export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, + .pNext = &memory_wsi_info, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + const VkMemoryDedicatedAllocateInfo memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + .pNext = &memory_export_info, + .image = image->image, + .buffer = VK_NULL_HANDLE, + }; + const VkMemoryAllocateInfo memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &memory_dedicated_info, + .allocationSize = reqs.size, + .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &memory_info, + &chain->alloc, &image->memory); + if (result != VK_SUCCESS) + goto fail; + + result = wsi->BindImageMemory(chain->device, image->image, + image->memory, 0); + if (result != VK_SUCCESS) + goto fail; + + int fd = -1; + if (!wsi->sw) { + const VkMemoryGetFdInfoKHR memory_get_fd_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, + .pNext = NULL, + .memory = image->memory, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + + result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd); + if (result != VK_SUCCESS) + goto fail; + } + + if (!wsi->sw && num_modifier_lists > 0) { + VkImageDrmFormatModifierPropertiesEXT image_mod_props = { + .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT, + }; + result = wsi->GetImageDrmFormatModifierPropertiesEXT(chain->device, + image->image, + &image_mod_props); + if (result != VK_SUCCESS) { + close(fd); + goto fail; + } + image->drm_modifier = image_mod_props.drmFormatModifier; + assert(image->drm_modifier != DRM_FORMAT_MOD_INVALID); + + for (uint32_t j = 0; j < modifier_prop_count; j++) { + if (modifier_props[j].drmFormatModifier == image->drm_modifier) { + image->num_planes = modifier_props[j].drmFormatModifierPlaneCount; + break; + } + } + + for (uint32_t p = 0; p < image->num_planes; p++) { + const VkImageSubresource image_subresource = { + .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << p, + .mipLevel = 0, + .arrayLayer = 0, + }; + VkSubresourceLayout image_layout; + wsi->GetImageSubresourceLayout(chain->device, image->image, + &image_subresource, &image_layout); + image->sizes[p] = image_layout.size; + image->row_pitches[p] = image_layout.rowPitch; + image->offsets[p] = image_layout.offset; + if (p == 0) { + image->fds[p] = fd; + } else { + image->fds[p] = os_dupfd_cloexec(fd); + if (image->fds[p] == -1) { + for (uint32_t i = 0; i < p; i++) + close(image->fds[i]); + + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + } + } + } else { + const VkImageSubresource image_subresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .arrayLayer = 0, + }; + VkSubresourceLayout image_layout; + wsi->GetImageSubresourceLayout(chain->device, image->image, + &image_subresource, &image_layout); + + image->drm_modifier = DRM_FORMAT_MOD_INVALID; + image->num_planes = 1; + image->sizes[0] = reqs.size; + image->row_pitches[0] = image_layout.rowPitch; + image->offsets[0] = 0; + image->fds[0] = fd; + } + + vk_free(&chain->alloc, modifier_props); + vk_free(&chain->alloc, image_modifiers); + + return VK_SUCCESS; + +fail: + vk_free(&chain->alloc, modifier_props); + vk_free(&chain->alloc, image_modifiers); + wsi_destroy_image(chain, image); + + return result; +} + +static inline uint32_t +align_u32(uint32_t v, uint32_t a) +{ + assert(a != 0 && a == (a & -a)); + return (v + a - 1) & ~(a - 1); +} + +#define WSI_PRIME_LINEAR_STRIDE_ALIGN 256 + +VkResult +wsi_create_prime_image(const struct wsi_swapchain *chain, + const VkSwapchainCreateInfoKHR *pCreateInfo, + bool use_modifier, + struct wsi_image *image) +{ + const struct wsi_device *wsi = chain->wsi; + VkResult result; + + memset(image, 0, sizeof(*image)); + + const uint32_t cpp = vk_format_size(pCreateInfo->imageFormat); + const uint32_t linear_stride = align_u32(pCreateInfo->imageExtent.width * cpp, + WSI_PRIME_LINEAR_STRIDE_ALIGN); + + uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height; + linear_size = align_u32(linear_size, 4096); + + const VkExternalMemoryBufferCreateInfo prime_buffer_external_info = { + .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, + .pNext = NULL, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + const VkBufferCreateInfo prime_buffer_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = &prime_buffer_external_info, + .size = linear_size, + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + result = wsi->CreateBuffer(chain->device, &prime_buffer_info, + &chain->alloc, &image->prime.buffer); + if (result != VK_SUCCESS) + goto fail; + + VkMemoryRequirements reqs; + wsi->GetBufferMemoryRequirements(chain->device, image->prime.buffer, &reqs); + assert(reqs.size <= linear_size); + + const struct wsi_memory_allocate_info memory_wsi_info = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, + .pNext = NULL, + .implicit_sync = true, + }; + const VkExportMemoryAllocateInfo prime_memory_export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, + .pNext = &memory_wsi_info, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + const VkMemoryDedicatedAllocateInfo prime_memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + .pNext = &prime_memory_export_info, + .image = VK_NULL_HANDLE, + .buffer = image->prime.buffer, + }; + const VkMemoryAllocateInfo prime_memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &prime_memory_dedicated_info, + .allocationSize = linear_size, + .memoryTypeIndex = select_memory_type(wsi, 0, reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &prime_memory_info, + &chain->alloc, &image->prime.memory); + if (result != VK_SUCCESS) + goto fail; + + result = wsi->BindBufferMemory(chain->device, image->prime.buffer, + image->prime.memory, 0); + if (result != VK_SUCCESS) + goto fail; + + const VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = pCreateInfo->imageFormat, + .extent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = pCreateInfo->imageUsage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + .sharingMode = pCreateInfo->imageSharingMode, + .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, + .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + result = wsi->CreateImage(chain->device, &image_info, + &chain->alloc, &image->image); + if (result != VK_SUCCESS) + goto fail; + + wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); + + const VkMemoryDedicatedAllocateInfo memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + .pNext = NULL, + .image = image->image, + .buffer = VK_NULL_HANDLE, + }; + const VkMemoryAllocateInfo memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &memory_dedicated_info, + .allocationSize = reqs.size, + .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &memory_info, + &chain->alloc, &image->memory); + if (result != VK_SUCCESS) + goto fail; + + result = wsi->BindImageMemory(chain->device, image->image, + image->memory, 0); + if (result != VK_SUCCESS) + goto fail; + + image->prime.blit_cmd_buffers = + vk_zalloc(&chain->alloc, + sizeof(VkCommandBuffer) * wsi->queue_family_count, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!image->prime.blit_cmd_buffers) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + for (uint32_t i = 0; i < wsi->queue_family_count; i++) { + const VkCommandBufferAllocateInfo cmd_buffer_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = NULL, + .commandPool = chain->cmd_pools[i], + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info, + &image->prime.blit_cmd_buffers[i]); + if (result != VK_SUCCESS) + goto fail; + + const VkCommandBufferBeginInfo begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + }; + wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info); + + struct VkBufferImageCopy buffer_image_copy = { + .bufferOffset = 0, + .bufferRowLength = linear_stride / cpp, + .bufferImageHeight = 0, + .imageSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = { .x = 0, .y = 0, .z = 0 }, + .imageExtent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1, + }, + }; + wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i], + image->image, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + image->prime.buffer, + 1, &buffer_image_copy); + + result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]); + if (result != VK_SUCCESS) + goto fail; + } + + const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, + .pNext = NULL, + .memory = image->prime.memory, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + int fd; + result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd); + if (result != VK_SUCCESS) + goto fail; + + image->drm_modifier = use_modifier ? DRM_FORMAT_MOD_LINEAR : DRM_FORMAT_MOD_INVALID; + image->num_planes = 1; + image->sizes[0] = linear_size; + image->row_pitches[0] = linear_stride; + image->offsets[0] = 0; + image->fds[0] = fd; + + return VK_SUCCESS; + +fail: + wsi_destroy_image(chain, image); + + return result; +} + diff --git a/lib/mesa/src/vulkan/wsi/wsi_common_private.h b/lib/mesa/src/vulkan/wsi/wsi_common_private.h index 88c360a24..1fe8211f9 100644 --- a/lib/mesa/src/vulkan/wsi/wsi_common_private.h +++ b/lib/mesa/src/vulkan/wsi/wsi_common_private.h @@ -24,6 +24,7 @@ #define WSI_COMMON_PRIVATE_H #include "wsi_common.h" +#include "vulkan/util/vk_object.h" struct wsi_image { VkImage image; @@ -44,6 +45,8 @@ struct wsi_image { }; struct wsi_swapchain { + struct vk_object_base base; + const struct wsi_device *wsi; VkDevice device; @@ -147,6 +150,11 @@ VkResult wsi_wl_init_wsi(struct wsi_device *wsi_device, VkPhysicalDevice physical_device); void wsi_wl_finish_wsi(struct wsi_device *wsi_device, const VkAllocationCallbacks *alloc); +VkResult wsi_win32_init_wsi(struct wsi_device *wsi_device, + const VkAllocationCallbacks *alloc, + VkPhysicalDevice physical_device); +void wsi_win32_finish_wsi(struct wsi_device *wsi_device, + const VkAllocationCallbacks *alloc); VkResult @@ -158,23 +166,7 @@ void wsi_display_finish_wsi(struct wsi_device *wsi_device, const VkAllocationCallbacks *alloc); -#define WSI_DEFINE_NONDISP_HANDLE_CASTS(__wsi_type, __VkType) \ - \ - static inline struct __wsi_type * \ - __wsi_type ## _from_handle(__VkType _handle) \ - { \ - return (struct __wsi_type *)(uintptr_t) _handle; \ - } \ - \ - static inline __VkType \ - __wsi_type ## _to_handle(struct __wsi_type *_obj) \ - { \ - return (__VkType)(uintptr_t) _obj; \ - } - -#define WSI_FROM_HANDLE(__wsi_type, __name, __handle) \ - struct __wsi_type *__name = __wsi_type ## _from_handle(__handle) - -WSI_DEFINE_NONDISP_HANDLE_CASTS(wsi_swapchain, VkSwapchainKHR) +VK_DEFINE_NONDISP_HANDLE_CASTS(wsi_swapchain, base, VkSwapchainKHR, + VK_OBJECT_TYPE_SWAPCHAIN_KHR) #endif /* WSI_COMMON_PRIVATE_H */ diff --git a/lib/mesa/src/vulkan/wsi/wsi_common_win32.c b/lib/mesa/src/vulkan/wsi/wsi_common_win32.c new file mode 100644 index 000000000..fa6f898e5 --- /dev/null +++ b/lib/mesa/src/vulkan/wsi/wsi_common_win32.c @@ -0,0 +1,675 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "vk_util.h" +#include "wsi_common_private.h" +#include "wsi_common_win32.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#endif + +struct wsi_win32; + +struct wsi_win32 { + struct wsi_interface base; + + struct wsi_device *wsi; + + const VkAllocationCallbacks *alloc; + VkPhysicalDevice physical_device; +}; + +struct wsi_win32_image { + struct wsi_image base; + struct wsi_win32_swapchain *chain; + HDC dc; + HBITMAP bmp; + int bmp_row_pitch; + void *ppvBits; +}; + + +struct wsi_win32_swapchain { + struct wsi_swapchain base; + struct wsi_win32 *wsi; + VkIcdSurfaceWin32 *surface; + uint64_t flip_sequence; + VkResult status; + VkExtent2D extent; + HWND wnd; + HDC chain_dc; + struct wsi_win32_image images[0]; +}; + +VkBool32 +wsi_win32_get_presentation_support(struct wsi_device *wsi_device) +{ + return TRUE; +} + +VkResult +wsi_create_win32_surface(VkInstance instance, + const VkAllocationCallbacks *allocator, + const VkWin32SurfaceCreateInfoKHR *create_info, + VkSurfaceKHR *surface_khr) +{ + VkIcdSurfaceWin32 *surface = vk_zalloc(allocator, sizeof *surface, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (surface == NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + surface->base.platform = VK_ICD_WSI_PLATFORM_WIN32; + + surface->hinstance = create_info->hinstance; + surface->hwnd = create_info->hwnd; + + *surface_khr = VkIcdSurfaceBase_to_handle(&surface->base); + return VK_SUCCESS; +} + +static VkResult +wsi_win32_surface_get_support(VkIcdSurfaceBase *surface, + struct wsi_device *wsi_device, + uint32_t queueFamilyIndex, + VkBool32* pSupported) +{ + *pSupported = true; + + return VK_SUCCESS; +} + +static VkResult +wsi_win32_surface_get_capabilities(VkIcdSurfaceBase *surface, + struct wsi_device *wsi_device, + VkSurfaceCapabilitiesKHR* caps) +{ + caps->minImageCount = 1; + /* There is no real maximum */ + caps->maxImageCount = 0; + + caps->currentExtent = (VkExtent2D) { UINT32_MAX, UINT32_MAX }; + caps->minImageExtent = (VkExtent2D) { 1, 1 }; + caps->maxImageExtent = (VkExtent2D) { + wsi_device->maxImageDimension2D, + wsi_device->maxImageDimension2D, + }; + + caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + caps->maxImageArrayLayers = 1; + + caps->supportedCompositeAlpha = + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; + + caps->supportedUsageFlags = + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + return VK_SUCCESS; +} + +static VkResult +wsi_win32_surface_get_capabilities2(VkIcdSurfaceBase *surface, + struct wsi_device *wsi_device, + const void *info_next, + VkSurfaceCapabilities2KHR* caps) +{ + assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); + + VkResult result = + wsi_win32_surface_get_capabilities(surface, wsi_device, + &caps->surfaceCapabilities); + + vk_foreach_struct(ext, caps->pNext) { + switch (ext->sType) { + case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { + VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext; + protected->supportsProtected = VK_FALSE; + break; + } + + default: + /* Ignored */ + break; + } + } + + return result; +} + + +static const struct { + VkFormat format; +} available_surface_formats[] = { + { .format = VK_FORMAT_B8G8R8A8_SRGB }, + { .format = VK_FORMAT_B8G8R8A8_UNORM }, +}; + + +static void +get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats) +{ + for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) + sorted_formats[i] = available_surface_formats[i].format; + + if (wsi_device->force_bgra8_unorm_first) { + for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { + if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) { + sorted_formats[i] = sorted_formats[0]; + sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM; + break; + } + } + } +} + +static VkResult +wsi_win32_surface_get_formats(VkIcdSurfaceBase *icd_surface, + struct wsi_device *wsi_device, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormatKHR* pSurfaceFormats) +{ + VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out, pSurfaceFormats, pSurfaceFormatCount); + + VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)]; + get_sorted_vk_formats(wsi_device, sorted_formats); + + for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) { + vk_outarray_append_typed(VkSurfaceFormatKHR, &out, f) { + f->format = sorted_formats[i]; + f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + } + } + + return vk_outarray_status(&out); +} + +static VkResult +wsi_win32_surface_get_formats2(VkIcdSurfaceBase *icd_surface, + struct wsi_device *wsi_device, + const void *info_next, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormat2KHR* pSurfaceFormats) +{ + VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out, pSurfaceFormats, pSurfaceFormatCount); + + VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)]; + get_sorted_vk_formats(wsi_device, sorted_formats); + + for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) { + vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, f) { + assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR); + f->surfaceFormat.format = sorted_formats[i]; + f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + } + } + + return vk_outarray_status(&out); +} + +static const VkPresentModeKHR present_modes[] = { + //VK_PRESENT_MODE_MAILBOX_KHR, + VK_PRESENT_MODE_FIFO_KHR, +}; + +static VkResult +wsi_win32_surface_get_present_modes(VkIcdSurfaceBase *surface, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes) +{ + if (pPresentModes == NULL) { + *pPresentModeCount = ARRAY_SIZE(present_modes); + return VK_SUCCESS; + } + + *pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes)); + typed_memcpy(pPresentModes, present_modes, *pPresentModeCount); + + if (*pPresentModeCount < ARRAY_SIZE(present_modes)) + return VK_INCOMPLETE; + else + return VK_SUCCESS; +} + +static VkResult +wsi_win32_surface_get_present_rectangles(VkIcdSurfaceBase *surface, + struct wsi_device *wsi_device, + uint32_t* pRectCount, + VkRect2D* pRects) +{ + VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount); + + vk_outarray_append_typed(VkRect2D, &out, rect) { + /* We don't know a size so just return the usual "I don't know." */ + *rect = (VkRect2D) { + .offset = { 0, 0 }, + .extent = { UINT32_MAX, UINT32_MAX }, + }; + } + + return vk_outarray_status(&out); +} + +static uint32_t +select_memory_type(const struct wsi_device *wsi, + VkMemoryPropertyFlags props, + uint32_t type_bits) +{ + for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) { + const VkMemoryType type = wsi->memory_props.memoryTypes[i]; + if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props) + return i; + } + + unreachable("No memory type found"); +} + +VkResult +wsi_create_native_image(const struct wsi_swapchain *chain, + const VkSwapchainCreateInfoKHR *pCreateInfo, + uint32_t num_modifier_lists, + const uint32_t *num_modifiers, + const uint64_t *const *modifiers, + struct wsi_image *image) +{ + const struct wsi_device *wsi = chain->wsi; + VkResult result; + + memset(image, 0, sizeof(*image)); + for (int i = 0; i < ARRAY_SIZE(image->fds); i++) + image->fds[i] = -1; + + VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = pCreateInfo->imageFormat, + .extent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = pCreateInfo->imageUsage, + .sharingMode = pCreateInfo->imageSharingMode, + .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, + .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + + VkImageFormatListCreateInfoKHR image_format_list; + if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) { + image_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR; + + const VkImageFormatListCreateInfoKHR *format_list = + vk_find_struct_const(pCreateInfo->pNext, + IMAGE_FORMAT_LIST_CREATE_INFO_KHR); + +#ifndef NDEBUG + assume(format_list && format_list->viewFormatCount > 0); + bool format_found = false; + for (int i = 0; i < format_list->viewFormatCount; i++) + if (pCreateInfo->imageFormat == format_list->pViewFormats[i]) + format_found = true; + assert(format_found); +#endif + + image_format_list = *format_list; + image_format_list.pNext = NULL; + __vk_append_struct(&image_info, &image_format_list); + } + + + result = wsi->CreateImage(chain->device, &image_info, + &chain->alloc, &image->image); + if (result != VK_SUCCESS) + goto fail; + + VkMemoryRequirements reqs; + wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); + + const struct wsi_memory_allocate_info memory_wsi_info = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, + .pNext = NULL, + .implicit_sync = true, + }; + const VkExportMemoryAllocateInfo memory_export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, + .pNext = &memory_wsi_info, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + const VkMemoryDedicatedAllocateInfo memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + .pNext = &memory_export_info, + .image = image->image, + .buffer = VK_NULL_HANDLE, + }; + const VkMemoryAllocateInfo memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &memory_dedicated_info, + .allocationSize = reqs.size, + .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &memory_info, + &chain->alloc, &image->memory); + if (result != VK_SUCCESS) + goto fail; + + result = wsi->BindImageMemory(chain->device, image->image, + image->memory, 0); + if (result != VK_SUCCESS) + goto fail; + + const VkImageSubresource image_subresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .arrayLayer = 0, + }; + VkSubresourceLayout image_layout; + wsi->GetImageSubresourceLayout(chain->device, image->image, + &image_subresource, &image_layout); + + image->num_planes = 1; + image->sizes[0] = reqs.size; + image->row_pitches[0] = image_layout.rowPitch; + image->offsets[0] = 0; + + return VK_SUCCESS; + +fail: + wsi_destroy_image(chain, image); + + return result; +} + +static VkResult +wsi_win32_image_init(VkDevice device_h, + struct wsi_swapchain *drv_chain, + const VkSwapchainCreateInfoKHR *create_info, + const VkAllocationCallbacks *allocator, + struct wsi_win32_image *image) +{ + struct wsi_win32_swapchain *chain = (struct wsi_win32_swapchain *) drv_chain; + + VkResult result = wsi_create_native_image(&chain->base, create_info, + 0, NULL, NULL, + &image->base); + if (result != VK_SUCCESS) + return result; + + VkIcdSurfaceWin32 *win32_surface = (VkIcdSurfaceWin32 *)create_info->surface; + chain->wnd = win32_surface->hwnd; + chain->chain_dc = GetDC(chain->wnd); + + image->dc = CreateCompatibleDC(chain->chain_dc); + HBITMAP bmp = NULL; + + BITMAPINFO info = { 0 }; + info.bmiHeader.biSize = sizeof(BITMAPINFO); + info.bmiHeader.biWidth = create_info->imageExtent.width; + info.bmiHeader.biHeight = -create_info->imageExtent.height; + info.bmiHeader.biPlanes = 1; + info.bmiHeader.biBitCount = 32; + info.bmiHeader.biCompression = BI_RGB; + + bmp = CreateDIBSection(image->dc, &info, DIB_RGB_COLORS, &image->ppvBits, NULL, 0); + assert(bmp && image->ppvBits); + + SelectObject(image->dc, bmp); + + BITMAP header; + int status = GetObject(bmp, sizeof(BITMAP), &header); + (void)status; + image->bmp_row_pitch = header.bmWidthBytes; + image->bmp = bmp; + image->chain = chain; + + return VK_SUCCESS; +} + +static void +wsi_win32_image_finish(struct wsi_swapchain *drv_chain, + const VkAllocationCallbacks *allocator, + struct wsi_win32_image *image) +{ + struct wsi_win32_swapchain *chain = + (struct wsi_win32_swapchain *) drv_chain; + + DeleteDC(image->dc); + if(image->bmp) + DeleteObject(image->bmp); + wsi_destroy_image(&chain->base, &image->base); +} + +static VkResult +wsi_win32_swapchain_destroy(struct wsi_swapchain *drv_chain, + const VkAllocationCallbacks *allocator) +{ + struct wsi_win32_swapchain *chain = + (struct wsi_win32_swapchain *) drv_chain; + + for (uint32_t i = 0; i < chain->base.image_count; i++) + wsi_win32_image_finish(drv_chain, allocator, &chain->images[i]); + + DeleteDC(chain->chain_dc); + + wsi_swapchain_finish(&chain->base); + vk_free(allocator, chain); + return VK_SUCCESS; +} + +static struct wsi_image * +wsi_win32_get_wsi_image(struct wsi_swapchain *drv_chain, + uint32_t image_index) +{ + struct wsi_win32_swapchain *chain = + (struct wsi_win32_swapchain *) drv_chain; + + return &chain->images[image_index].base; +} + +static VkResult +wsi_win32_acquire_next_image(struct wsi_swapchain *drv_chain, + const VkAcquireNextImageInfoKHR *info, + uint32_t *image_index) +{ + struct wsi_win32_swapchain *chain = + (struct wsi_win32_swapchain *)drv_chain; + + /* Bail early if the swapchain is broken */ + if (chain->status != VK_SUCCESS) + return chain->status; + + *image_index = 0; + return VK_SUCCESS; +} + +static VkResult +wsi_win32_queue_present(struct wsi_swapchain *drv_chain, + uint32_t image_index, + const VkPresentRegionKHR *damage) +{ + struct wsi_win32_swapchain *chain = (struct wsi_win32_swapchain *) drv_chain; + assert(image_index < chain->base.image_count); + struct wsi_win32_image *image = &chain->images[image_index]; + VkResult result; + + char *ptr; + char *dptr = image->ppvBits; + result = chain->base.wsi->MapMemory(chain->base.device, + image->base.memory, + 0, 0, 0, (void**)&ptr); + + for (unsigned h = 0; h < chain->extent.height; h++) { + memcpy(dptr, ptr, chain->extent.width * 4); + dptr += image->bmp_row_pitch; + ptr += image->base.row_pitches[0]; + } + if(StretchBlt(chain->chain_dc, 0, 0, chain->extent.width, chain->extent.height, image->dc, 0, 0, chain->extent.width, chain->extent.height, SRCCOPY)) + result = VK_SUCCESS; + else + result = VK_ERROR_MEMORY_MAP_FAILED; + + chain->base.wsi->UnmapMemory(chain->base.device, image->base.memory); + if (result != VK_SUCCESS) + chain->status = result; + + if (result != VK_SUCCESS) + return result; + + return chain->status; +} + +static VkResult +wsi_win32_surface_create_swapchain( + VkIcdSurfaceBase *icd_surface, + VkDevice device, + struct wsi_device *wsi_device, + const VkSwapchainCreateInfoKHR *create_info, + const VkAllocationCallbacks *allocator, + struct wsi_swapchain **swapchain_out) +{ + VkIcdSurfaceWin32 *surface = (VkIcdSurfaceWin32 *)icd_surface; + struct wsi_win32 *wsi = + (struct wsi_win32 *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32]; + + assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); + + const unsigned num_images = create_info->minImageCount; + struct wsi_win32_swapchain *chain; + size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]); + + chain = vk_zalloc(allocator, size, + 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (chain == NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device, + create_info, allocator); + if (result != VK_SUCCESS) { + vk_free(allocator, chain); + return result; + } + + chain->base.destroy = wsi_win32_swapchain_destroy; + chain->base.get_wsi_image = wsi_win32_get_wsi_image; + chain->base.acquire_next_image = wsi_win32_acquire_next_image; + chain->base.queue_present = wsi_win32_queue_present; + chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info); + chain->base.image_count = num_images; + chain->extent = create_info->imageExtent; + + chain->wsi = wsi; + chain->status = VK_SUCCESS; + + chain->surface = surface; + + for (uint32_t image = 0; image < chain->base.image_count; image++) { + result = wsi_win32_image_init(device, &chain->base, + create_info, allocator, + &chain->images[image]); + if (result != VK_SUCCESS) { + while (image > 0) { + --image; + wsi_win32_image_finish(&chain->base, allocator, + &chain->images[image]); + } + vk_free(allocator, chain); + goto fail_init_images; + } + } + + *swapchain_out = &chain->base; + + return VK_SUCCESS; + +fail_init_images: + return result; +} + + +VkResult +wsi_win32_init_wsi(struct wsi_device *wsi_device, + const VkAllocationCallbacks *alloc, + VkPhysicalDevice physical_device) +{ + struct wsi_win32 *wsi; + VkResult result; + + wsi = vk_alloc(alloc, sizeof(*wsi), 8, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); + if (!wsi) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + wsi->physical_device = physical_device; + wsi->alloc = alloc; + wsi->wsi = wsi_device; + + wsi->base.get_support = wsi_win32_surface_get_support; + wsi->base.get_capabilities2 = wsi_win32_surface_get_capabilities2; + wsi->base.get_formats = wsi_win32_surface_get_formats; + wsi->base.get_formats2 = wsi_win32_surface_get_formats2; + wsi->base.get_present_modes = wsi_win32_surface_get_present_modes; + wsi->base.get_present_rectangles = wsi_win32_surface_get_present_rectangles; + wsi->base.create_swapchain = wsi_win32_surface_create_swapchain; + + wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = &wsi->base; + + return VK_SUCCESS; + +fail: + wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = NULL; + + return result; +} + +void +wsi_win32_finish_wsi(struct wsi_device *wsi_device, + const VkAllocationCallbacks *alloc) +{ + struct wsi_win32 *wsi = + (struct wsi_win32 *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32]; + if (!wsi) + return; + + vk_free(alloc, wsi); +} diff --git a/lib/mesa/src/vulkan/wsi/wsi_common_win32.h b/lib/mesa/src/vulkan/wsi/wsi_common_win32.h new file mode 100644 index 000000000..661ba9dea --- /dev/null +++ b/lib/mesa/src/vulkan/wsi/wsi_common_win32.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef WSI_COMMON_WIN32_H +#define WSI_COMMON_WIN32_H + +#include "wsi_common.h" +#include <vulkan/vulkan_win32.h> + +VkBool32 +wsi_win32_get_presentation_support(struct wsi_device *wsi_device); + +VkResult +wsi_create_win32_surface(VkInstance instance, + const VkAllocationCallbacks *pAllocator, + const VkWin32SurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface); +#endif |