Files
mesa/src/virtio/vulkan/vn_instance.c
T
Dave Airlie 25b8f4f714 venus: handle device probing properly.
Currently if you try to probe the virtio ICD on a non-virtio system
it will fail in CreateInstance which causes the loader to spit on the
screen.

However instance creation shouldn't fail, the driver should just
not enumerate any devices in this case. It's a bit tricky to ensure
this, but return instance and then handle instance destruction
and fail device enumeration.

Cc: mesa-stable
Reviewed-by: Ryan Neph
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32266>
2024-11-22 13:06:11 +10:00

441 lines
14 KiB
C

/*
* Copyright 2019 Google LLC
* SPDX-License-Identifier: MIT
*
* based in part on anv and radv which are:
* Copyright © 2015 Intel Corporation
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*/
#include "vn_instance.h"
#include "util/driconf.h"
#include "venus-protocol/vn_protocol_driver_info.h"
#include "venus-protocol/vn_protocol_driver_instance.h"
#include "venus-protocol/vn_protocol_driver_transport.h"
#include "vn_icd.h"
#include "vn_physical_device.h"
#include "vn_renderer.h"
#include "vn_ring.h"
/*
* Instance extensions add instance-level or physical-device-level
* functionalities. It seems renderer support is either unnecessary or
* optional. We should be able to advertise them or lie about them locally.
*/
static const struct vk_instance_extension_table
vn_instance_supported_extensions = {
/* promoted to VK_VERSION_1_1 */
.KHR_device_group_creation = true,
.KHR_external_fence_capabilities = true,
.KHR_external_memory_capabilities = true,
.KHR_external_semaphore_capabilities = true,
.KHR_get_physical_device_properties2 = true,
#ifdef VN_USE_WSI_PLATFORM
.KHR_get_surface_capabilities2 = true,
.KHR_surface = true,
.KHR_surface_protected_capabilities = true,
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
.KHR_wayland_surface = true,
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
.KHR_xcb_surface = true,
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
.KHR_xlib_surface = true,
#endif
#ifndef VK_USE_PLATFORM_WIN32_KHR
.EXT_headless_surface = true,
#endif
};
static const driOptionDescription vn_dri_options[] = {
/* clang-format off */
DRI_CONF_SECTION_PERFORMANCE
DRI_CONF_VK_X11_ENSURE_MIN_IMAGE_COUNT(false)
DRI_CONF_VK_X11_OVERRIDE_MIN_IMAGE_COUNT(0)
DRI_CONF_VK_X11_STRICT_IMAGE_COUNT(false)
DRI_CONF_VK_XWAYLAND_WAIT_READY(true)
DRI_CONF_VENUS_IMPLICIT_FENCING(false)
DRI_CONF_VENUS_WSI_MULTI_PLANE_MODIFIERS(false)
DRI_CONF_SECTION_END
DRI_CONF_SECTION_DEBUG
DRI_CONF_VK_WSI_FORCE_BGRA8_UNORM_FIRST(false)
DRI_CONF_VK_WSI_FORCE_SWAPCHAIN_TO_CURRENT_EXTENT(false)
DRI_CONF_SECTION_END
/* clang-format on */
};
static VkResult
vn_instance_init_renderer_versions(struct vn_instance *instance)
{
uint32_t instance_version = 0;
VkResult result = vn_call_vkEnumerateInstanceVersion(instance->ring.ring,
&instance_version);
if (result != VK_SUCCESS) {
if (VN_DEBUG(INIT))
vn_log(instance, "failed to enumerate renderer instance version");
return result;
}
if (instance_version < VN_MIN_RENDERER_VERSION) {
if (VN_DEBUG(INIT)) {
vn_log(instance, "unsupported renderer instance version %d.%d",
VK_VERSION_MAJOR(instance_version),
VK_VERSION_MINOR(instance_version));
}
return VK_ERROR_INITIALIZATION_FAILED;
}
if (VN_DEBUG(INIT)) {
vn_log(instance, "renderer instance version %d.%d.%d",
VK_VERSION_MAJOR(instance_version),
VK_VERSION_MINOR(instance_version),
VK_VERSION_PATCH(instance_version));
}
/* request at least VN_MIN_RENDERER_VERSION internally */
instance->renderer_api_version =
MAX2(instance->base.base.app_info.api_version, VN_MIN_RENDERER_VERSION);
/* instance version for internal use is capped */
instance_version = MIN3(instance_version, instance->renderer_api_version,
instance->renderer->info.vk_xml_version);
assert(instance_version >= VN_MIN_RENDERER_VERSION);
instance->renderer_version = instance_version;
return VK_SUCCESS;
}
static inline void
vn_instance_fini_ring(struct vn_instance *instance)
{
vn_watchdog_fini(&instance->ring.watchdog);
list_for_each_entry_safe(struct vn_tls_ring, tls_ring,
&instance->ring.tls_rings, vk_head)
vn_tls_destroy_ring(tls_ring);
vn_ring_destroy(instance->ring.ring);
}
static VkResult
vn_instance_init_ring(struct vn_instance *instance)
{
/* 32-bit seqno for renderer roundtrips */
static const size_t extra_size = sizeof(uint32_t);
/* default instance ring size */
static const size_t buf_size = 128 * 1024;
/* order of 4 for performant async cmd enqueue */
static const uint8_t direct_order = 4;
struct vn_ring_layout layout;
vn_ring_get_layout(buf_size, extra_size, &layout);
instance->ring.ring = vn_ring_create(instance, &layout, direct_order,
false /* is_tls_ring */);
if (!instance->ring.ring)
return VK_ERROR_OUT_OF_HOST_MEMORY;
list_inithead(&instance->ring.tls_rings);
vn_watchdog_init(&instance->ring.watchdog);
return VK_SUCCESS;
}
static VkResult
vn_instance_init_renderer(struct vn_instance *instance)
{
const VkAllocationCallbacks *alloc = &instance->base.base.alloc;
VkResult result = vn_renderer_create(instance, alloc, &instance->renderer);
if (result != VK_SUCCESS)
return result;
struct vn_renderer_info *renderer_info = &instance->renderer->info;
uint32_t version = vn_info_wire_format_version();
if (renderer_info->wire_format_version != version) {
if (VN_DEBUG(INIT)) {
vn_log(instance, "wire format version %d != %d",
renderer_info->wire_format_version, version);
}
return VK_ERROR_INITIALIZATION_FAILED;
}
version = vn_info_vk_xml_version();
if (renderer_info->vk_xml_version > version)
renderer_info->vk_xml_version = version;
if (renderer_info->vk_xml_version < VN_MIN_RENDERER_VERSION) {
if (VN_DEBUG(INIT)) {
vn_log(instance, "vk xml version %d.%d.%d < %d.%d.%d",
VK_VERSION_MAJOR(renderer_info->vk_xml_version),
VK_VERSION_MINOR(renderer_info->vk_xml_version),
VK_VERSION_PATCH(renderer_info->vk_xml_version),
VK_VERSION_MAJOR(VN_MIN_RENDERER_VERSION),
VK_VERSION_MINOR(VN_MIN_RENDERER_VERSION),
VK_VERSION_PATCH(VN_MIN_RENDERER_VERSION));
}
return VK_ERROR_INITIALIZATION_FAILED;
}
uint32_t spec_version =
vn_extension_get_spec_version("VK_EXT_command_serialization");
if (renderer_info->vk_ext_command_serialization_spec_version >
spec_version) {
renderer_info->vk_ext_command_serialization_spec_version = spec_version;
}
spec_version = vn_extension_get_spec_version("VK_MESA_venus_protocol");
if (renderer_info->vk_mesa_venus_protocol_spec_version > spec_version)
renderer_info->vk_mesa_venus_protocol_spec_version = spec_version;
if (VN_DEBUG(INIT)) {
vn_log(instance, "connected to renderer");
vn_log(instance, "wire format version %d",
renderer_info->wire_format_version);
vn_log(instance, "vk xml version %d.%d.%d",
VK_VERSION_MAJOR(renderer_info->vk_xml_version),
VK_VERSION_MINOR(renderer_info->vk_xml_version),
VK_VERSION_PATCH(renderer_info->vk_xml_version));
vn_log(instance, "VK_EXT_command_serialization spec version %d",
renderer_info->vk_ext_command_serialization_spec_version);
vn_log(instance, "VK_MESA_venus_protocol spec version %d",
renderer_info->vk_mesa_venus_protocol_spec_version);
}
return VK_SUCCESS;
}
/* instance commands */
VkResult
vn_EnumerateInstanceVersion(uint32_t *pApiVersion)
{
*pApiVersion = VN_MAX_API_VERSION;
return VK_SUCCESS;
}
VkResult
vn_EnumerateInstanceExtensionProperties(const char *pLayerName,
uint32_t *pPropertyCount,
VkExtensionProperties *pProperties)
{
if (pLayerName)
return vn_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
return vk_enumerate_instance_extension_properties(
&vn_instance_supported_extensions, pPropertyCount, pProperties);
}
VkResult
vn_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
VkLayerProperties *pProperties)
{
*pPropertyCount = 0;
return VK_SUCCESS;
}
VkResult
vn_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkInstance *pInstance)
{
vn_trace_init();
VN_TRACE_FUNC();
const VkAllocationCallbacks *alloc =
pAllocator ? pAllocator : vk_default_allocator();
struct vn_instance *instance;
VkResult result;
vn_env_init();
instance = vk_zalloc(alloc, sizeof(*instance), VN_DEFAULT_ALIGN,
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (!instance)
return vn_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
struct vk_instance_dispatch_table dispatch_table;
vk_instance_dispatch_table_from_entrypoints(
&dispatch_table, &vn_instance_entrypoints, true);
vk_instance_dispatch_table_from_entrypoints(
&dispatch_table, &wsi_instance_entrypoints, false);
result = vn_instance_base_init(&instance->base,
&vn_instance_supported_extensions,
&dispatch_table, pCreateInfo, alloc);
if (result != VK_SUCCESS) {
vk_free(alloc, instance);
return vn_error(NULL, result);
}
VkInstance instance_handle = vn_instance_to_handle(instance);
/* ring_idx = 0 reserved for CPU timeline */
instance->ring_idx_used_mask = 0x1;
mtx_init(&instance->physical_device.mutex, mtx_plain);
mtx_init(&instance->ring_idx_mutex, mtx_plain);
if (!vn_icd_supports_api_version(
instance->base.base.app_info.api_version)) {
result = VK_ERROR_INCOMPATIBLE_DRIVER;
goto out_mtx_destroy;
}
if (pCreateInfo->enabledLayerCount) {
result = VK_ERROR_LAYER_NOT_PRESENT;
goto out_mtx_destroy;
}
result = vn_instance_init_renderer(instance);
if (result == VK_ERROR_INITIALIZATION_FAILED) {
*pInstance = instance_handle;
return VK_SUCCESS;
}
if (result != VK_SUCCESS)
goto out_mtx_destroy;
vn_cs_renderer_protocol_info_init(instance);
vn_renderer_shmem_pool_init(instance->renderer, &instance->cs_shmem_pool,
8u << 20);
vn_renderer_shmem_pool_init(instance->renderer,
&instance->reply_shmem_pool, 1u << 20);
result = vn_instance_init_ring(instance);
if (result != VK_SUCCESS)
goto out_shmem_pool_fini;
result = vn_instance_init_renderer_versions(instance);
if (result != VK_SUCCESS)
goto out_ring_fini;
VkInstanceCreateInfo local_create_info = *pCreateInfo;
local_create_info.ppEnabledExtensionNames = NULL;
local_create_info.enabledExtensionCount = 0;
pCreateInfo = &local_create_info;
VkApplicationInfo local_app_info;
if (instance->base.base.app_info.api_version <
instance->renderer_api_version) {
if (pCreateInfo->pApplicationInfo) {
local_app_info = *pCreateInfo->pApplicationInfo;
local_app_info.apiVersion = instance->renderer_api_version;
} else {
local_app_info = (const VkApplicationInfo){
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.apiVersion = instance->renderer_api_version,
};
}
local_create_info.pApplicationInfo = &local_app_info;
}
result = vn_call_vkCreateInstance(instance->ring.ring, pCreateInfo, NULL,
&instance_handle);
if (result != VK_SUCCESS)
goto out_ring_fini;
driParseOptionInfo(&instance->available_dri_options, vn_dri_options,
ARRAY_SIZE(vn_dri_options));
driParseConfigFiles(&instance->dri_options,
&instance->available_dri_options, 0, "venus", NULL,
NULL, instance->base.base.app_info.app_name,
instance->base.base.app_info.app_version,
instance->base.base.app_info.engine_name,
instance->base.base.app_info.engine_version);
instance->renderer->info.has_implicit_fencing =
driQueryOptionb(&instance->dri_options, "venus_implicit_fencing");
instance->enable_wsi_multi_plane_modifiers = driQueryOptionb(
&instance->dri_options, "venus_wsi_multi_plane_modifiers");
if (VN_DEBUG(INIT)) {
vn_log(instance, "supports multi-plane wsi format modifiers: %s",
instance->enable_wsi_multi_plane_modifiers ? "yes" : "no");
}
const char *engine_name = instance->base.base.app_info.engine_name;
if (engine_name) {
instance->engine_is_zink = strcmp(engine_name, "mesa zink") == 0;
}
*pInstance = instance_handle;
return VK_SUCCESS;
out_ring_fini:
vn_instance_fini_ring(instance);
out_shmem_pool_fini:
vn_renderer_shmem_pool_fini(instance->renderer,
&instance->reply_shmem_pool);
vn_renderer_shmem_pool_fini(instance->renderer, &instance->cs_shmem_pool);
vn_renderer_destroy(instance->renderer, alloc);
out_mtx_destroy:
mtx_destroy(&instance->physical_device.mutex);
mtx_destroy(&instance->ring_idx_mutex);
vn_instance_base_fini(&instance->base);
vk_free(alloc, instance);
return vn_error(NULL, result);
}
void
vn_DestroyInstance(VkInstance _instance,
const VkAllocationCallbacks *pAllocator)
{
VN_TRACE_FUNC();
struct vn_instance *instance = vn_instance_from_handle(_instance);
const VkAllocationCallbacks *alloc =
pAllocator ? pAllocator : &instance->base.base.alloc;
if (!instance)
return;
if (instance->physical_device.initialized) {
for (uint32_t i = 0; i < instance->physical_device.device_count; i++)
vn_physical_device_fini(&instance->physical_device.devices[i]);
vk_free(alloc, instance->physical_device.devices);
vk_free(alloc, instance->physical_device.groups);
}
mtx_destroy(&instance->physical_device.mutex);
mtx_destroy(&instance->ring_idx_mutex);
if (instance->renderer) {
vn_call_vkDestroyInstance(instance->ring.ring, _instance, NULL);
vn_instance_fini_ring(instance);
vn_renderer_shmem_pool_fini(instance->renderer,
&instance->reply_shmem_pool);
vn_renderer_shmem_pool_fini(instance->renderer, &instance->cs_shmem_pool);
vn_renderer_destroy(instance->renderer, alloc);
}
driDestroyOptionCache(&instance->dri_options);
driDestroyOptionInfo(&instance->available_dri_options);
vn_instance_base_fini(&instance->base);
vk_free(alloc, instance);
}
PFN_vkVoidFunction
vn_GetInstanceProcAddr(VkInstance _instance, const char *pName)
{
struct vn_instance *instance = vn_instance_from_handle(_instance);
return vk_instance_get_proc_addr(&instance->base.base,
&vn_instance_entrypoints, pName);
}