render/vulkan: negotiate instance API version

Use vkEnumerateInstanceVersion to pick the instance API version and load
vkGetPhysicalDevice*2 entrypoints via core or KHR depending on that.
This avoids API version validation errors when running with Vulkan 1.0.
This commit is contained in:
Furkan Sahin 2026-06-02 17:57:55 -04:00
parent 280cc0742a
commit c26c8ba315
2 changed files with 70 additions and 18 deletions

View file

@ -19,14 +19,15 @@ struct wlr_vk_texture;
struct wlr_vk_instance { struct wlr_vk_instance {
VkInstance instance; VkInstance instance;
VkDebugUtilsMessengerEXT messenger; VkDebugUtilsMessengerEXT messenger;
uint32_t api_version;
struct { struct {
PFN_vkCreateDebugUtilsMessengerEXT createDebugUtilsMessengerEXT; PFN_vkCreateDebugUtilsMessengerEXT createDebugUtilsMessengerEXT;
PFN_vkDestroyDebugUtilsMessengerEXT destroyDebugUtilsMessengerEXT; PFN_vkDestroyDebugUtilsMessengerEXT destroyDebugUtilsMessengerEXT;
} api; } api;
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2;
PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2;
}; };
// Creates and initializes a vulkan instance. // Creates and initializes a vulkan instance.

View file

@ -81,6 +81,27 @@ static VKAPI_ATTR VkBool32 debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT
} }
struct wlr_vk_instance *vulkan_instance_create(bool debug) { struct wlr_vk_instance *vulkan_instance_create(bool debug) {
uint32_t api_version = VK_API_VERSION_1_0;
PFN_vkEnumerateInstanceVersion enumerate_instance_version =
(PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(
VK_NULL_HANDLE, "vkEnumerateInstanceVersion");
if (enumerate_instance_version) {
uint32_t supported_api_version = VK_API_VERSION_1_0;
if (enumerate_instance_version(&supported_api_version) == VK_SUCCESS) {
api_version = supported_api_version;
} else {
wlr_log(WLR_INFO,
"vkEnumerateInstanceVersion failed, assuming Vulkan 1.0");
}
}
if (api_version >= VK_API_VERSION_1_1) {
api_version = VK_API_VERSION_1_1;
} else {
api_version = VK_API_VERSION_1_0;
}
wlr_log(WLR_DEBUG, "Using Vulkan instance API version %u.%u.%u",
VK_VERSION_MAJOR(api_version), VK_VERSION_MINOR(api_version),
VK_VERSION_PATCH(api_version));
uint32_t avail_extc = 0; uint32_t avail_extc = 0;
VkResult res; VkResult res;
@ -108,12 +129,15 @@ struct wlr_vk_instance *vulkan_instance_create(bool debug) {
wlr_log_errno(WLR_ERROR, "allocation failed"); wlr_log_errno(WLR_ERROR, "allocation failed");
return NULL; return NULL;
} }
ini->api_version = api_version;
size_t extensions_len = 0; size_t extensions_len = 0;
const char *extensions[8] = {0}; const char *extensions[8] = {0};
extensions[extensions_len++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; if (api_version < VK_API_VERSION_1_1) {
extensions[extensions_len++] = VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME; extensions[extensions_len++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
extensions[extensions_len++] = VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME; extensions[extensions_len++] = VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME;
extensions[extensions_len++] = VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME;
}
for (size_t i = 0; i < extensions_len; i++) { for (size_t i = 0; i < extensions_len; i++) {
if (!check_extension(avail_ext_props, avail_extc, extensions[i])) { if (!check_extension(avail_ext_props, avail_extc, extensions[i])) {
@ -136,7 +160,7 @@ struct wlr_vk_instance *vulkan_instance_create(bool debug) {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pEngineName = "wlroots", .pEngineName = "wlroots",
.engineVersion = WLR_VERSION_NUM, .engineVersion = WLR_VERSION_NUM,
.apiVersion = VK_API_VERSION_1_0, .apiVersion = api_version,
}; };
VkInstanceCreateInfo instance_info = { VkInstanceCreateInfo instance_info = {
@ -195,18 +219,41 @@ struct wlr_vk_instance *vulkan_instance_create(bool debug) {
} }
} }
ini->vkGetPhysicalDeviceProperties2KHR = (PFN_vkGetPhysicalDeviceProperties2KHR) if (ini->api_version < VK_API_VERSION_1_1) {
vkGetInstanceProcAddr(ini->instance, "vkGetPhysicalDeviceProperties2KHR"); ini->vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)
if (!ini->vkGetPhysicalDeviceProperties2KHR) { vkGetInstanceProcAddr(ini->instance,
wlr_log(WLR_ERROR, "vkGetPhysicalDeviceProperties2KHR not found"); "vkGetPhysicalDeviceProperties2KHR");
} else {
ini->vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)
vkGetInstanceProcAddr(ini->instance, "vkGetPhysicalDeviceProperties2");
if (!ini->vkGetPhysicalDeviceProperties2) {
ini->vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)
vkGetInstanceProcAddr(ini->instance,
"vkGetPhysicalDeviceProperties2KHR");
}
}
if (!ini->vkGetPhysicalDeviceProperties2) {
wlr_log(WLR_ERROR, "vkGetPhysicalDeviceProperties2 not found");
goto error; goto error;
} }
ini->vkGetPhysicalDeviceFeatures2KHR = (PFN_vkGetPhysicalDeviceFeatures2KHR) if (ini->api_version < VK_API_VERSION_1_1) {
vkGetInstanceProcAddr(ini->instance, "vkGetPhysicalDeviceFeatures2KHR"); ini->vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)
if (!ini->vkGetPhysicalDeviceFeatures2KHR) { vkGetInstanceProcAddr(ini->instance,
wlr_log(WLR_ERROR, "vkGetPhysicalDeviceFeatures2KHR not found"); "vkGetPhysicalDeviceFeatures2KHR");
goto error; } else {
ini->vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)
vkGetInstanceProcAddr(ini->instance, "vkGetPhysicalDeviceFeatures2");
if (!ini->vkGetPhysicalDeviceFeatures2) {
ini->vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)
vkGetInstanceProcAddr(ini->instance,
"vkGetPhysicalDeviceFeatures2KHR");
}
}
if (!ini->vkGetPhysicalDeviceFeatures2) {
wlr_log(WLR_INFO,
"vkGetPhysicalDeviceFeatures2 not available, assuming no sampler "
"YCbCr conversion support");
} }
@ -339,7 +386,7 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd)
props.pNext = &driver_props; props.pNext = &driver_props;
} }
ini->vkGetPhysicalDeviceProperties2KHR(phdev, &props); ini->vkGetPhysicalDeviceProperties2(phdev, &props);
if (has_driver_props) { if (has_driver_props) {
wlr_log(WLR_INFO, " Driver name: %s (%s)", driver_props.driverName, driver_props.driverInfo); wlr_log(WLR_INFO, " Driver name: %s (%s)", driver_props.driverName, driver_props.driverInfo);
@ -381,7 +428,7 @@ int vulkan_open_phdev_drm_fd(struct wlr_vk_instance *ini, VkPhysicalDevice phdev
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
.pNext = &drm_props, .pNext = &drm_props,
}; };
ini->vkGetPhysicalDeviceProperties2KHR(phdev, &props); ini->vkGetPhysicalDeviceProperties2(phdev, &props);
dev_t devid; dev_t devid;
if (drm_props.hasRender) { if (drm_props.hasRender) {
@ -562,7 +609,11 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
.pNext = &phdev_sampler_ycbcr_features, .pNext = &phdev_sampler_ycbcr_features,
}; };
ini->vkGetPhysicalDeviceFeatures2KHR(phdev, &phdev_features); if (ini->vkGetPhysicalDeviceFeatures2) {
ini->vkGetPhysicalDeviceFeatures2(phdev, &phdev_features);
} else {
phdev_sampler_ycbcr_features.samplerYcbcrConversion = VK_FALSE;
}
dev->sampler_ycbcr_conversion = phdev_sampler_ycbcr_features.samplerYcbcrConversion; dev->sampler_ycbcr_conversion = phdev_sampler_ycbcr_features.samplerYcbcrConversion;
wlr_log(WLR_DEBUG, "Sampler YCbCr conversion %s", wlr_log(WLR_DEBUG, "Sampler YCbCr conversion %s",