2020-03-30 09:38:38 +10:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2017 Google
|
|
|
|
|
* Copyright © 2019 Red Hat
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Rules for device selection.
|
|
|
|
|
* Is there an X or wayland connection open (or DISPLAY set).
|
|
|
|
|
* If no - try and find which device was the boot_vga device.
|
|
|
|
|
* If yes - try and work out which device is the connection primary,
|
|
|
|
|
* DRI_PRIME tagged overrides only work if bus info, =1 will just pick an alternate.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <vulkan/vk_layer.h>
|
2023-02-16 16:40:23 -06:00
|
|
|
#include <vulkan/vulkan.h>
|
2020-03-30 09:38:38 +10:00
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2022-11-05 19:55:32 +08:00
|
|
|
#include "util/hash_table.h"
|
2022-08-24 03:25:46 +08:00
|
|
|
#include "util/simple_mtx.h"
|
2023-01-15 16:23:32 -08:00
|
|
|
#include "util/u_debug.h"
|
2025-08-08 15:52:36 +01:00
|
|
|
#include "device_select.h"
|
|
|
|
|
#include "vk_util.h"
|
2020-03-30 09:38:38 +10:00
|
|
|
|
|
|
|
|
static struct hash_table *device_select_instance_ht = NULL;
|
2022-08-24 03:25:46 +08:00
|
|
|
static simple_mtx_t device_select_mutex = SIMPLE_MTX_INITIALIZER;
|
2020-03-30 09:38:38 +10:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
device_select_layer_add_instance(VkInstance instance, struct instance_info *info)
|
|
|
|
|
{
|
2022-08-24 03:25:46 +08:00
|
|
|
simple_mtx_lock(&device_select_mutex);
|
2025-08-08 16:27:04 +01:00
|
|
|
|
|
|
|
|
if (!device_select_instance_ht)
|
|
|
|
|
device_select_instance_ht = _mesa_pointer_hash_table_create(NULL);
|
2020-03-30 09:38:38 +10:00
|
|
|
_mesa_hash_table_insert(device_select_instance_ht, instance, info);
|
2025-08-08 16:27:04 +01:00
|
|
|
|
2022-08-24 03:25:46 +08:00
|
|
|
simple_mtx_unlock(&device_select_mutex);
|
2020-03-30 09:38:38 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct instance_info *
|
2025-12-15 16:46:13 +00:00
|
|
|
device_select_layer_get_instance(VkInstance instance)
|
2020-03-30 09:38:38 +10:00
|
|
|
{
|
|
|
|
|
struct hash_entry *entry;
|
|
|
|
|
struct instance_info *info = NULL;
|
2022-08-24 03:25:46 +08:00
|
|
|
simple_mtx_lock(&device_select_mutex);
|
2020-03-30 09:38:38 +10:00
|
|
|
entry = _mesa_hash_table_search(device_select_instance_ht, (void *)instance);
|
|
|
|
|
if (entry)
|
|
|
|
|
info = (struct instance_info *)entry->data;
|
2022-08-24 03:25:46 +08:00
|
|
|
simple_mtx_unlock(&device_select_mutex);
|
2020-03-30 09:38:38 +10:00
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
device_select_layer_remove_instance(VkInstance instance)
|
|
|
|
|
{
|
2022-08-24 03:25:46 +08:00
|
|
|
simple_mtx_lock(&device_select_mutex);
|
2025-08-08 16:27:04 +01:00
|
|
|
|
2020-03-30 09:38:38 +10:00
|
|
|
_mesa_hash_table_remove_key(device_select_instance_ht, instance);
|
2025-08-08 16:27:04 +01:00
|
|
|
|
|
|
|
|
if (_mesa_hash_table_num_entries(device_select_instance_ht) == 0) {
|
|
|
|
|
_mesa_hash_table_destroy(device_select_instance_ht, NULL);
|
|
|
|
|
device_select_instance_ht = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-24 03:25:46 +08:00
|
|
|
simple_mtx_unlock(&device_select_mutex);
|
2020-03-30 09:38:38 +10:00
|
|
|
}
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
static VkResult
|
|
|
|
|
device_select_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
|
|
|
|
|
const VkAllocationCallbacks *pAllocator, VkInstance *pInstance)
|
2020-03-30 09:38:38 +10:00
|
|
|
{
|
|
|
|
|
VkLayerInstanceCreateInfo *chain_info;
|
2025-08-08 15:52:36 +01:00
|
|
|
for (chain_info = (VkLayerInstanceCreateInfo *)pCreateInfo->pNext; chain_info;
|
|
|
|
|
chain_info = (VkLayerInstanceCreateInfo *)chain_info->pNext)
|
|
|
|
|
if (chain_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&
|
|
|
|
|
chain_info->function == VK_LAYER_LINK_INFO)
|
2020-03-30 09:38:38 +10:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
assert(chain_info->u.pLayerInfo);
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
PFN_vkGetInstanceProcAddr GetInstanceProcAddr =
|
|
|
|
|
chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
|
|
|
|
|
PFN_vkCreateInstance fpCreateInstance =
|
|
|
|
|
(PFN_vkCreateInstance)GetInstanceProcAddr(NULL, "vkCreateInstance");
|
2020-03-30 09:38:38 +10:00
|
|
|
if (fpCreateInstance == NULL) {
|
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
const char *engineName =
|
|
|
|
|
pCreateInfo->pApplicationInfo && pCreateInfo->pApplicationInfo->pEngineName
|
|
|
|
|
? pCreateInfo->pApplicationInfo->pEngineName
|
|
|
|
|
: "";
|
|
|
|
|
const char *applicationName =
|
|
|
|
|
pCreateInfo->pApplicationInfo && pCreateInfo->pApplicationInfo->pApplicationName
|
|
|
|
|
? pCreateInfo->pApplicationInfo->pApplicationName
|
|
|
|
|
: "";
|
2020-03-30 09:38:38 +10:00
|
|
|
VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
|
2020-08-30 17:39:43 -07:00
|
|
|
if (result != VK_SUCCESS) {
|
2020-03-30 09:38:38 +10:00
|
|
|
return result;
|
2020-08-30 17:39:43 -07:00
|
|
|
}
|
2020-03-30 09:38:38 +10:00
|
|
|
|
2024-08-13 11:49:50 -04:00
|
|
|
struct instance_info *info = (struct instance_info *)calloc(1, sizeof(struct instance_info));
|
|
|
|
|
info->GetInstanceProcAddr = GetInstanceProcAddr;
|
2024-08-13 12:06:34 -04:00
|
|
|
info->zink = !strcmp(engineName, "mesa zink");
|
|
|
|
|
info->xwayland = !strcmp(applicationName, "Xwayland");
|
2024-08-23 09:08:26 -04:00
|
|
|
info->xserver = !strcmp(applicationName, "Xorg") || !strcmp(applicationName, "Xephyr");
|
2024-08-13 11:49:50 -04:00
|
|
|
|
2025-05-27 18:51:12 +02:00
|
|
|
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
mesa: replace most occurrences of getenv() with os_get_option()
The standard way to query options in mesa is `os_get_option()` which
abstracts platform-specific mechanisms to get config variables.
However in quite a few places `getenv()` is still used and this may
preclude controlling some options on some systems.
For instance it is not generally possible to use `MESA_DEBUG` on
Android.
So replace most `getenv()` occurrences with `os_get_option()` to
support configuration options more consistently across different
platforms.
Do the same with `secure_getenv()` replacing it with
`os_get_option_secure()`.
The bulk of the proposed changes are mechanically performed by the
following script:
-----------------------------------------------------------------------
#!/bin/sh
set -e
replace() {
# Don't replace in some files, for example where `os_get_option` is defined,
# or in external files
EXCLUDE_FILES_PATTERN='(src/util/os_misc.c|src/util/u_debug.h|src/gtest/include/gtest/internal/gtest-port.h)'
# Don't replace some "system" variables
EXCLUDE_VARS_PATTERN='("XDG|"DISPLAY|"HOME|"TMPDIR|"POSIXLY_CORRECT)'
git grep "[=!( ]$1(" -- src/ | cut -d ':' -f 1 | sort | uniq | \
grep -v -E "$EXCLUDE_FILES_PATTERN" | \
while read -r file;
do
# Don't replace usages of XDG_* variables or HOME
sed -E -e "/$EXCLUDE_VARS_PATTERN/!s/([=!\( ])$1\(/\1$2\(/g" -i "$file";
done
}
# Add const to os_get_option results, to avoid warning about discarded qualifier:
# warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
# but also errors in some cases:
# error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
add_const_results() {
git grep -l -P '(?<!const )char.*os_get_option' | \
while read -r file;
do
sed -e '/^\s*const/! s/\(char.*os_get_option\)/const \1/g' -i "$file"
done
}
replace 'secure_getenv' 'os_get_option_secure'
replace 'getenv' 'os_get_option'
add_const_results
-----------------------------------------------------------------------
After this, the `#include "util/os_misc.h"` is also added in files where
`os_get_option()` was not used before.
And since the replacements from the script above generated some new
`-Wdiscarded-qualifiers` warnings, those have been addressed as well,
generally by declaring `os_get_option()` results as `const char *` and
adjusting some function declarations.
Finally some replacements caused new errors like:
-----------------------------------------------------------------------
../src/gallium/auxiliary/gallivm/lp_bld_misc.cpp:127:31: error: no matching function for call to 'strtok'
127 | for (n = 0, option = strtok(env_llc_options, " "); option; n++, option = strtok(NULL, " ")) {
| ^~~~~~
/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin/../sysroot/usr/include/string.h:124:17: note: candidate function not viable: 1st argument ('const char *') would lose const qualifier
124 | char* _Nullable strtok(char* _Nullable __s, const char* _Nonnull __delimiter);
| ^ ~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------------------
Those have been addressed too, copying the const string returned by
`os_get_option()` so that it could be modified.
In particular, the error above has been fixed by copying the `const
char *env_llc_options` variable in
`src/gallium/auxiliary/gallivm/lp_bld_misc.cpp` to a `char *` which can
be tokenized using `strtok()`.
Reviewed-by: Eric Engestrom <eric@igalia.com>
Reviewed-by: Yonggang Luo <luoyonggang@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38128>
2025-10-20 20:02:49 +08:00
|
|
|
bool has_wayland = os_get_option("WAYLAND_DISPLAY") || os_get_option("WAYLAND_SOCKET");
|
2025-05-27 18:51:12 +02:00
|
|
|
#endif
|
|
|
|
|
#ifdef VK_USE_PLATFORM_XCB_KHR
|
2025-11-06 14:18:15 +08:00
|
|
|
bool has_xcb = !!os_get_option("DISPLAY");
|
2025-05-27 18:51:12 +02:00
|
|
|
#endif
|
2024-10-18 09:42:04 -04:00
|
|
|
|
2020-03-30 09:38:38 +10:00
|
|
|
for (unsigned i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
|
|
|
|
|
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
2025-08-08 15:52:36 +01:00
|
|
|
if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) &&
|
|
|
|
|
has_wayland)
|
2020-03-30 09:38:38 +10:00
|
|
|
info->has_wayland = true;
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef VK_USE_PLATFORM_XCB_KHR
|
2025-08-08 15:52:36 +01:00
|
|
|
if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME) &&
|
|
|
|
|
has_xcb)
|
2024-08-23 09:08:26 -04:00
|
|
|
info->has_xcb = !info->xserver || !info->zink;
|
2020-03-30 09:38:38 +10:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-11 15:20:40 +01:00
|
|
|
/*
|
|
|
|
|
* The loader is currently not able to handle GetPhysicalDeviceProperties2KHR calls in
|
|
|
|
|
* EnumeratePhysicalDevices when there are other layers present. To avoid mysterious crashes
|
|
|
|
|
* for users just use only the vulkan version for now.
|
|
|
|
|
*/
|
|
|
|
|
info->has_vulkan11 = pCreateInfo->pApplicationInfo &&
|
|
|
|
|
pCreateInfo->pApplicationInfo->apiVersion >= VK_MAKE_VERSION(1, 1, 0);
|
|
|
|
|
|
2025-08-08 16:38:02 +01:00
|
|
|
info->debug = debug_get_bool_option("MESA_VK_DEVICE_SELECT_DEBUG", false) ||
|
|
|
|
|
debug_get_bool_option("DRI_PRIME_DEBUG", false);
|
2025-10-29 16:04:47 +08:00
|
|
|
info->selection = os_get_option_dup("MESA_VK_DEVICE_SELECT");
|
|
|
|
|
info->dri_prime = os_get_option_dup("DRI_PRIME");
|
2025-08-08 16:39:37 +01:00
|
|
|
info->force_default_device =
|
|
|
|
|
debug_get_bool_option("MESA_VK_DEVICE_SELECT_FORCE_DEFAULT_DEVICE", false);
|
2025-08-08 16:38:02 +01:00
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
#define DEVSEL_GET_CB(func) \
|
|
|
|
|
info->func = (PFN_vk##func)info->GetInstanceProcAddr(*pInstance, "vk" #func)
|
2020-03-30 09:38:38 +10:00
|
|
|
DEVSEL_GET_CB(DestroyInstance);
|
|
|
|
|
DEVSEL_GET_CB(EnumeratePhysicalDevices);
|
|
|
|
|
DEVSEL_GET_CB(EnumeratePhysicalDeviceGroups);
|
|
|
|
|
DEVSEL_GET_CB(GetPhysicalDeviceProperties);
|
|
|
|
|
DEVSEL_GET_CB(EnumerateDeviceExtensionProperties);
|
2021-01-11 15:20:40 +01:00
|
|
|
if (info->has_vulkan11)
|
|
|
|
|
DEVSEL_GET_CB(GetPhysicalDeviceProperties2);
|
2020-03-30 09:38:38 +10:00
|
|
|
#undef DEVSEL_GET_CB
|
|
|
|
|
|
|
|
|
|
device_select_layer_add_instance(*pInstance, info);
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
static void
|
|
|
|
|
device_select_DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator)
|
2020-03-30 09:38:38 +10:00
|
|
|
{
|
2025-12-15 16:46:13 +00:00
|
|
|
struct instance_info *info = device_select_layer_get_instance(instance);
|
2020-03-30 09:38:38 +10:00
|
|
|
|
|
|
|
|
device_select_layer_remove_instance(instance);
|
|
|
|
|
info->DestroyInstance(instance, pAllocator);
|
2025-08-08 16:38:02 +01:00
|
|
|
free(info->dri_prime);
|
|
|
|
|
free(info->selection);
|
2020-03-30 09:38:38 +10:00
|
|
|
free(info);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-08 16:06:48 +01:00
|
|
|
void
|
|
|
|
|
device_select_get_properties(const struct instance_info *info, VkPhysicalDevice device,
|
|
|
|
|
VkPhysicalDeviceProperties2 *properties)
|
2021-03-08 17:39:09 +01:00
|
|
|
{
|
2025-12-21 19:11:45 +01:00
|
|
|
if (info->GetPhysicalDeviceProperties2 && info->has_vulkan11)
|
2025-08-08 15:52:36 +01:00
|
|
|
info->GetPhysicalDeviceProperties2(device, properties);
|
2025-12-21 19:11:45 +01:00
|
|
|
else
|
|
|
|
|
info->GetPhysicalDeviceProperties(device, &properties->properties);
|
2021-03-08 17:39:09 +01:00
|
|
|
}
|
2020-03-30 09:38:38 +10:00
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
static void
|
|
|
|
|
print_gpu(const struct instance_info *info, unsigned index, VkPhysicalDevice device)
|
2020-03-30 09:38:38 +10:00
|
|
|
{
|
|
|
|
|
const char *type = "";
|
2025-08-08 15:52:36 +01:00
|
|
|
VkPhysicalDevicePCIBusInfoPropertiesEXT ext_pci_properties =
|
|
|
|
|
(VkPhysicalDevicePCIBusInfoPropertiesEXT){
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT,
|
|
|
|
|
};
|
2022-07-01 13:02:59 +01:00
|
|
|
VkPhysicalDeviceProperties2 properties = (VkPhysicalDeviceProperties2){
|
2025-08-08 15:52:36 +01:00
|
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
2020-03-30 09:38:38 +10:00
|
|
|
};
|
2021-01-11 15:20:40 +01:00
|
|
|
if (info->has_vulkan11 && info->has_pci_bus)
|
2020-03-30 09:38:38 +10:00
|
|
|
properties.pNext = &ext_pci_properties;
|
2025-08-08 16:06:48 +01:00
|
|
|
device_select_get_properties(info, device, &properties);
|
2020-03-30 09:38:38 +10:00
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
switch (properties.properties.deviceType) {
|
2020-03-30 09:38:38 +10:00
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
|
|
|
|
|
default:
|
|
|
|
|
type = "other";
|
|
|
|
|
break;
|
|
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
|
|
|
|
type = "integrated GPU";
|
|
|
|
|
break;
|
|
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
|
|
|
|
|
type = "discrete GPU";
|
|
|
|
|
break;
|
|
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
|
|
|
|
|
type = "virtual GPU";
|
|
|
|
|
break;
|
|
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_CPU:
|
|
|
|
|
type = "CPU";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
fprintf(stderr, " GPU %d: %x:%x \"%s\" %s", index, properties.properties.vendorID,
|
|
|
|
|
properties.properties.deviceID, properties.properties.deviceName, type);
|
2022-01-13 16:06:48 +05:30
|
|
|
if (info->has_vulkan11 && info->has_pci_bus)
|
2025-08-08 15:52:36 +01:00
|
|
|
fprintf(stderr, " %04x:%02x:%02x.%x", ext_pci_properties.pciDomain, ext_pci_properties.pciBus,
|
|
|
|
|
ext_pci_properties.pciDevice, ext_pci_properties.pciFunction);
|
2020-03-30 09:38:38 +10:00
|
|
|
fprintf(stderr, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
static VkResult
|
|
|
|
|
device_select_EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
|
|
|
|
|
VkPhysicalDevice *pPhysicalDevices)
|
2020-03-30 09:38:38 +10:00
|
|
|
{
|
2025-12-15 16:46:13 +00:00
|
|
|
struct instance_info *info = device_select_layer_get_instance(instance);
|
2020-03-30 09:38:38 +10:00
|
|
|
uint32_t physical_device_count = 0;
|
|
|
|
|
uint32_t selected_physical_device_count = 0;
|
2023-08-17 12:41:42 +02:00
|
|
|
bool expose_only_one_dev = false;
|
2024-08-13 12:06:34 -04:00
|
|
|
if (info->zink && info->xwayland)
|
|
|
|
|
return info->EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
|
2020-03-30 09:38:38 +10:00
|
|
|
VkResult result = info->EnumeratePhysicalDevices(instance, &physical_device_count, NULL);
|
2022-03-23 13:59:40 +01:00
|
|
|
VK_OUTARRAY_MAKE_TYPED(VkPhysicalDevice, out, pPhysicalDevices, pPhysicalDeviceCount);
|
2020-03-30 09:38:38 +10:00
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
return result;
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
VkPhysicalDevice *physical_devices =
|
|
|
|
|
(VkPhysicalDevice *)calloc(sizeof(VkPhysicalDevice), physical_device_count);
|
|
|
|
|
VkPhysicalDevice *selected_physical_devices =
|
|
|
|
|
(VkPhysicalDevice *)calloc(sizeof(VkPhysicalDevice), physical_device_count);
|
2020-03-30 09:38:38 +10:00
|
|
|
|
|
|
|
|
if (!physical_devices || !selected_physical_devices) {
|
|
|
|
|
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = info->EnumeratePhysicalDevices(instance, &physical_device_count, physical_devices);
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < physical_device_count; i++) {
|
|
|
|
|
uint32_t count;
|
|
|
|
|
info->EnumerateDeviceExtensionProperties(physical_devices[i], NULL, &count, NULL);
|
|
|
|
|
if (count > 0) {
|
2025-05-15 17:17:08 -07:00
|
|
|
VkExtensionProperties *extensions = calloc(count, sizeof(VkExtensionProperties));
|
2025-08-08 15:52:36 +01:00
|
|
|
if (info->EnumerateDeviceExtensionProperties(physical_devices[i], NULL, &count,
|
|
|
|
|
extensions) == VK_SUCCESS) {
|
2025-05-15 17:17:08 -07:00
|
|
|
for (unsigned j = 0; j < count; j++) {
|
2020-03-30 09:38:38 +10:00
|
|
|
if (!strcmp(extensions[j].extensionName, VK_EXT_PCI_BUS_INFO_EXTENSION_NAME))
|
|
|
|
|
info->has_pci_bus = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-15 17:17:08 -07:00
|
|
|
free(extensions);
|
2020-03-30 09:38:38 +10:00
|
|
|
}
|
|
|
|
|
}
|
2025-08-08 16:38:02 +01:00
|
|
|
if (info->debug || (info->selection && strcmp(info->selection, "list") == 0)) {
|
2020-03-30 09:38:38 +10:00
|
|
|
fprintf(stderr, "selectable devices:\n");
|
|
|
|
|
for (unsigned i = 0; i < physical_device_count; ++i)
|
|
|
|
|
print_gpu(info, i, physical_devices[i]);
|
2023-01-12 13:58:16 +01:00
|
|
|
|
2025-08-08 16:38:02 +01:00
|
|
|
if (info->selection && strcmp(info->selection, "list") == 0)
|
2023-01-16 17:05:39 -08:00
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-08 16:56:52 +01:00
|
|
|
unsigned selected_index =
|
|
|
|
|
device_select_get_first(info, physical_device_count, physical_devices, &expose_only_one_dev);
|
2023-01-16 17:05:39 -08:00
|
|
|
selected_physical_device_count = physical_device_count;
|
|
|
|
|
selected_physical_devices[0] = physical_devices[selected_index];
|
|
|
|
|
for (unsigned i = 0; i < physical_device_count - 1; ++i) {
|
2025-08-08 15:52:36 +01:00
|
|
|
unsigned this_idx = i < selected_index ? i : i + 1;
|
2023-01-16 17:05:39 -08:00
|
|
|
selected_physical_devices[i + 1] = physical_devices[this_idx];
|
2020-03-30 09:38:38 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (selected_physical_device_count == 0) {
|
|
|
|
|
fprintf(stderr, "WARNING: selected no devices with MESA_VK_DEVICE_SELECT\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(result == VK_SUCCESS);
|
|
|
|
|
|
2022-03-26 00:01:44 +05:30
|
|
|
/* do not give multiple device option to app if force default device */
|
2025-08-08 16:38:02 +01:00
|
|
|
if (info->force_default_device && selected_physical_device_count != 0)
|
2023-08-17 12:41:42 +02:00
|
|
|
expose_only_one_dev = true;
|
|
|
|
|
|
|
|
|
|
if (expose_only_one_dev)
|
2022-03-26 00:01:44 +05:30
|
|
|
selected_physical_device_count = 1;
|
|
|
|
|
|
2020-03-30 09:38:38 +10:00
|
|
|
for (unsigned i = 0; i < selected_physical_device_count; i++) {
|
2025-08-08 15:52:36 +01:00
|
|
|
vk_outarray_append_typed(VkPhysicalDevice, &out, ent)
|
|
|
|
|
{
|
2020-03-30 09:38:38 +10:00
|
|
|
*ent = selected_physical_devices[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
result = vk_outarray_status(&out);
|
2025-08-08 15:52:36 +01:00
|
|
|
out:
|
2020-03-30 09:38:38 +10:00
|
|
|
free(physical_devices);
|
|
|
|
|
free(selected_physical_devices);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
static VkResult
|
|
|
|
|
device_select_EnumeratePhysicalDeviceGroups(VkInstance instance,
|
|
|
|
|
uint32_t *pPhysicalDeviceGroupCount,
|
|
|
|
|
VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroups)
|
2020-03-30 09:38:38 +10:00
|
|
|
{
|
2025-12-15 16:46:13 +00:00
|
|
|
struct instance_info *info = device_select_layer_get_instance(instance);
|
2021-01-18 15:12:49 +10:00
|
|
|
uint32_t physical_device_group_count = 0;
|
|
|
|
|
uint32_t selected_physical_device_group_count = 0;
|
2024-08-13 12:06:34 -04:00
|
|
|
if (info->zink && info->xwayland)
|
2025-08-08 15:52:36 +01:00
|
|
|
return info->EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount,
|
|
|
|
|
pPhysicalDeviceGroups);
|
|
|
|
|
VkResult result =
|
|
|
|
|
info->EnumeratePhysicalDeviceGroups(instance, &physical_device_group_count, NULL);
|
|
|
|
|
VK_OUTARRAY_MAKE_TYPED(VkPhysicalDeviceGroupProperties, out, pPhysicalDeviceGroups,
|
|
|
|
|
pPhysicalDeviceGroupCount);
|
2021-01-18 15:12:49 +10:00
|
|
|
|
|
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
return result;
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
VkPhysicalDeviceGroupProperties *physical_device_groups =
|
|
|
|
|
(VkPhysicalDeviceGroupProperties *)calloc(sizeof(VkPhysicalDeviceGroupProperties),
|
|
|
|
|
physical_device_group_count);
|
|
|
|
|
VkPhysicalDeviceGroupProperties *selected_physical_device_groups =
|
|
|
|
|
(VkPhysicalDeviceGroupProperties *)calloc(sizeof(VkPhysicalDeviceGroupProperties),
|
|
|
|
|
physical_device_group_count);
|
2021-01-18 15:12:49 +10:00
|
|
|
|
|
|
|
|
if (!physical_device_groups || !selected_physical_device_groups) {
|
|
|
|
|
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-12 17:51:51 +01:00
|
|
|
for (unsigned i = 0; i < physical_device_group_count; i++)
|
|
|
|
|
physical_device_groups[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
result = info->EnumeratePhysicalDeviceGroups(instance, &physical_device_group_count,
|
|
|
|
|
physical_device_groups);
|
2021-01-18 15:12:49 +10:00
|
|
|
if (result != VK_SUCCESS)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
/* just sort groups with CPU devices to the end? - assume nobody will mix these */
|
|
|
|
|
int num_gpu_groups = 0;
|
|
|
|
|
int num_cpu_groups = 0;
|
|
|
|
|
selected_physical_device_group_count = physical_device_group_count;
|
|
|
|
|
for (unsigned i = 0; i < physical_device_group_count; i++) {
|
|
|
|
|
bool group_has_cpu_device = false;
|
|
|
|
|
for (unsigned j = 0; j < physical_device_groups[i].physicalDeviceCount; j++) {
|
|
|
|
|
VkPhysicalDevice physical_device = physical_device_groups[i].physicalDevices[j];
|
2022-07-01 13:02:59 +01:00
|
|
|
VkPhysicalDeviceProperties2 properties = (VkPhysicalDeviceProperties2){
|
2025-08-08 15:52:36 +01:00
|
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
2021-01-18 15:12:49 +10:00
|
|
|
};
|
|
|
|
|
info->GetPhysicalDeviceProperties(physical_device, &properties.properties);
|
|
|
|
|
group_has_cpu_device = properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (group_has_cpu_device) {
|
2025-08-08 15:52:36 +01:00
|
|
|
selected_physical_device_groups[physical_device_group_count - num_cpu_groups - 1] =
|
|
|
|
|
physical_device_groups[i];
|
2021-01-18 15:12:49 +10:00
|
|
|
num_cpu_groups++;
|
|
|
|
|
} else {
|
|
|
|
|
selected_physical_device_groups[num_gpu_groups] = physical_device_groups[i];
|
|
|
|
|
num_gpu_groups++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(result == VK_SUCCESS);
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < selected_physical_device_group_count; i++) {
|
2025-08-08 15:52:36 +01:00
|
|
|
vk_outarray_append_typed(VkPhysicalDeviceGroupProperties, &out, ent)
|
|
|
|
|
{
|
2021-01-18 15:12:49 +10:00
|
|
|
*ent = selected_physical_device_groups[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
result = vk_outarray_status(&out);
|
|
|
|
|
out:
|
|
|
|
|
free(physical_device_groups);
|
|
|
|
|
free(selected_physical_device_groups);
|
2020-03-30 09:38:38 +10:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
static void (*get_instance_proc_addr(VkInstance instance, const char *name))()
|
2020-03-30 09:38:38 +10:00
|
|
|
{
|
2020-12-31 17:17:34 +01:00
|
|
|
if (strcmp(name, "vkGetInstanceProcAddr") == 0)
|
2025-08-08 15:52:36 +01:00
|
|
|
return (void (*)())get_instance_proc_addr;
|
2020-03-30 09:38:38 +10:00
|
|
|
if (strcmp(name, "vkCreateInstance") == 0)
|
2025-08-08 15:52:36 +01:00
|
|
|
return (void (*)())device_select_CreateInstance;
|
2020-03-30 09:38:38 +10:00
|
|
|
if (strcmp(name, "vkDestroyInstance") == 0)
|
2025-08-08 15:52:36 +01:00
|
|
|
return (void (*)())device_select_DestroyInstance;
|
2020-03-30 09:38:38 +10:00
|
|
|
if (strcmp(name, "vkEnumeratePhysicalDevices") == 0)
|
2025-08-08 15:52:36 +01:00
|
|
|
return (void (*)())device_select_EnumeratePhysicalDevices;
|
2020-03-30 09:38:38 +10:00
|
|
|
if (strcmp(name, "vkEnumeratePhysicalDeviceGroups") == 0)
|
2025-08-08 15:52:36 +01:00
|
|
|
return (void (*)())device_select_EnumeratePhysicalDeviceGroups;
|
2020-03-30 09:38:38 +10:00
|
|
|
|
2025-12-15 16:46:13 +00:00
|
|
|
struct instance_info *info = device_select_layer_get_instance(instance);
|
2020-03-30 09:38:38 +10:00
|
|
|
return info->GetInstanceProcAddr(instance, name);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-08 15:52:36 +01:00
|
|
|
PUBLIC VkResult
|
|
|
|
|
vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct)
|
2020-03-30 09:38:38 +10:00
|
|
|
{
|
|
|
|
|
if (pVersionStruct->loaderLayerInterfaceVersion < 2)
|
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
|
pVersionStruct->loaderLayerInterfaceVersion = 2;
|
|
|
|
|
|
|
|
|
|
pVersionStruct->pfnGetInstanceProcAddr = get_instance_proc_addr;
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|