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 {
VkInstance instance;
VkDebugUtilsMessengerEXT messenger;
uint32_t api_version;
struct {
PFN_vkCreateDebugUtilsMessengerEXT createDebugUtilsMessengerEXT;
PFN_vkDestroyDebugUtilsMessengerEXT destroyDebugUtilsMessengerEXT;
} api;
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2;
PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2;
};
// 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) {
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;
VkResult res;
@ -108,12 +129,15 @@ struct wlr_vk_instance *vulkan_instance_create(bool debug) {
wlr_log_errno(WLR_ERROR, "allocation failed");
return NULL;
}
ini->api_version = api_version;
size_t extensions_len = 0;
const char *extensions[8] = {0};
extensions[extensions_len++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
extensions[extensions_len++] = VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME;
extensions[extensions_len++] = VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME;
if (api_version < VK_API_VERSION_1_1) {
extensions[extensions_len++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_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++) {
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,
.pEngineName = "wlroots",
.engineVersion = WLR_VERSION_NUM,
.apiVersion = VK_API_VERSION_1_0,
.apiVersion = api_version,
};
VkInstanceCreateInfo instance_info = {
@ -195,18 +219,41 @@ struct wlr_vk_instance *vulkan_instance_create(bool debug) {
}
}
ini->vkGetPhysicalDeviceProperties2KHR = (PFN_vkGetPhysicalDeviceProperties2KHR)
vkGetInstanceProcAddr(ini->instance, "vkGetPhysicalDeviceProperties2KHR");
if (!ini->vkGetPhysicalDeviceProperties2KHR) {
wlr_log(WLR_ERROR, "vkGetPhysicalDeviceProperties2KHR not found");
if (ini->api_version < VK_API_VERSION_1_1) {
ini->vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)
vkGetInstanceProcAddr(ini->instance,
"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;
}
ini->vkGetPhysicalDeviceFeatures2KHR = (PFN_vkGetPhysicalDeviceFeatures2KHR)
vkGetInstanceProcAddr(ini->instance, "vkGetPhysicalDeviceFeatures2KHR");
if (!ini->vkGetPhysicalDeviceFeatures2KHR) {
wlr_log(WLR_ERROR, "vkGetPhysicalDeviceFeatures2KHR not found");
goto error;
if (ini->api_version < VK_API_VERSION_1_1) {
ini->vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)
vkGetInstanceProcAddr(ini->instance,
"vkGetPhysicalDeviceFeatures2KHR");
} 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;
}
ini->vkGetPhysicalDeviceProperties2KHR(phdev, &props);
ini->vkGetPhysicalDeviceProperties2(phdev, &props);
if (has_driver_props) {
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,
.pNext = &drm_props,
};
ini->vkGetPhysicalDeviceProperties2KHR(phdev, &props);
ini->vkGetPhysicalDeviceProperties2(phdev, &props);
dev_t devid;
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,
.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;
wlr_log(WLR_DEBUG, "Sampler YCbCr conversion %s",