diff --git a/docs/envvars.rst b/docs/envvars.rst index 27073747a95..935bc7d9414 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -395,7 +395,10 @@ Core Mesa environment variables - ``DRI_PRIME=N``: selects the Nth non-default GPU (N > 0). - ``DRI_PRIME=pci-0000_02_00_0``: selects the GPU connected to this PCIe bus - - ``DRI_PRIME=vendor_id:device_id``: selects the first GPU matching these ids + - ``DRI_PRIME=vendor_id:device_id``: selects the first GPU matching these ids. + + For Vulkan it's possible to append ``!``, in which case only the selected GPU + will be exposed to the application (eg: DRI_PRIME=1!). .. note:: @@ -801,6 +804,8 @@ Vulkan mesa device select layer environment variables when set to "vid:did" number from PCI device. That PCI device is selected as default. The default device is returned as the first device in vkEnumeratePhysicalDevices API. + Using "vid:did!" will have the same effect as using the + ``MESA_VK_DEVICE_SELECT_FORCE_DEFAULT_DEVICE`` variable. .. envvar:: MESA_VK_DEVICE_SELECT_FORCE_DEFAULT_DEVICE diff --git a/src/vulkan/device-select-layer/device_select_layer.c b/src/vulkan/device-select-layer/device_select_layer.c index 2c273c3de19..73bb4313437 100644 --- a/src/vulkan/device-select-layer/device_select_layer.c +++ b/src/vulkan/device-select-layer/device_select_layer.c @@ -284,6 +284,15 @@ static int device_select_find_dri_prime_tag_default(struct device_pci_info *pci_ const char *dri_prime) { int default_idx = -1; + + /* Drop the trailing '!' if present. */ + int ref = strlen("pci-xxxx_yy_zz_w"); + int n = strlen(dri_prime); + if (n < ref) + return default_idx; + if (n == ref + 1 && dri_prime[n - 1] == '!') + n--; + for (unsigned i = 0; i < device_count; ++i) { char *tag = NULL; if (asprintf(&tag, "pci-%04x_%02x_%02x_%1u", @@ -291,7 +300,7 @@ static int device_select_find_dri_prime_tag_default(struct device_pci_info *pci_ pci_infos[i].bus_info.bus, pci_infos[i].bus_info.dev, pci_infos[i].bus_info.func) >= 0) { - if (strcmp(dri_prime, tag) == 0) + if (strncmp(dri_prime, tag, n) == 0) default_idx = i; } free(tag); @@ -419,10 +428,16 @@ static bool should_debug_device_selection() { debug_get_bool_option("DRI_PRIME_DEBUG", false); } +static bool ends_with_exclamation_mark(const char *str) { + size_t n = strlen(str); + return n > 1 && str[n - 1] == '!'; +} + static uint32_t get_default_device(const struct instance_info *info, const char *selection, uint32_t physical_device_count, - VkPhysicalDevice *pPhysicalDevices) + VkPhysicalDevice *pPhysicalDevices, + bool *expose_only_one_dev) { int default_idx = -1; const char *dri_prime = getenv("DRI_PRIME"); @@ -447,12 +462,18 @@ static uint32_t get_default_device(const struct instance_info *info, if (selection) default_idx = device_select_find_explicit_default(pci_infos, physical_device_count, selection); + if (default_idx != -1) { + *expose_only_one_dev = ends_with_exclamation_mark(selection); + } if (default_idx == -1 && dri_prime && dri_prime_as_int == 0) { /* Try DRI_PRIME=vendor_id:device_id */ default_idx = device_select_find_explicit_default(pci_infos, physical_device_count, dri_prime); - if (debug && default_idx != -1) - fprintf(stderr, "device-select: device_select_find_explicit_default selected %i\n", default_idx); + if (default_idx != -1) { + if (debug) + fprintf(stderr, "device-select: device_select_find_explicit_default selected %i\n", default_idx); + *expose_only_one_dev = ends_with_exclamation_mark(dri_prime); + } if (default_idx == -1) { /* Try DRI_PRIME=pci-xxxx_yy_zz_w */ @@ -461,8 +482,11 @@ static uint32_t get_default_device(const struct instance_info *info, else default_idx = device_select_find_dri_prime_tag_default(pci_infos, physical_device_count, dri_prime); - if (debug && default_idx != -1) - fprintf(stderr, "device-select: device_select_find_dri_prime_tag_default selected %i\n", default_idx); + if (default_idx != -1) { + if (debug) + fprintf(stderr, "device-select: device_select_find_dri_prime_tag_default selected %i\n", default_idx); + *expose_only_one_dev = ends_with_exclamation_mark(dri_prime); + } } } if (default_idx == -1 && info->has_wayland) { @@ -506,8 +530,11 @@ static uint32_t get_default_device(const struct instance_info *info, if (dri_prime_as_int > 0 && physical_device_count > (cpu_count + 1)) { if (default_idx == 0 || default_idx == 1) { default_idx = find_non_cpu_skip(pci_infos, physical_device_count, default_idx, dri_prime_as_int); - if (debug && default_idx != -1) - fprintf(stderr, "device-select: find_non_cpu_skip selected %i\n", default_idx); + if (default_idx != -1) { + if (debug) + fprintf(stderr, "device-select: find_non_cpu_skip selected %i\n", default_idx); + *expose_only_one_dev = ends_with_exclamation_mark(dri_prime); + } } } free(pci_infos); @@ -522,6 +549,7 @@ static VkResult device_select_EnumeratePhysicalDevices(VkInstance instance, uint32_t physical_device_count = 0; uint32_t selected_physical_device_count = 0; const char* selection = getenv("MESA_VK_DEVICE_SELECT"); + bool expose_only_one_dev = false; VkResult result = info->EnumeratePhysicalDevices(instance, &physical_device_count, NULL); VK_OUTARRAY_MAKE_TYPED(VkPhysicalDevice, out, pPhysicalDevices, pPhysicalDeviceCount); if (result != VK_SUCCESS) @@ -563,7 +591,8 @@ static VkResult device_select_EnumeratePhysicalDevices(VkInstance instance, exit(0); } - unsigned selected_index = get_default_device(info, selection, physical_device_count, physical_devices); + unsigned selected_index = get_default_device(info, selection, physical_device_count, + physical_devices, &expose_only_one_dev); 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) { @@ -580,6 +609,9 @@ static VkResult device_select_EnumeratePhysicalDevices(VkInstance instance, /* do not give multiple device option to app if force default device */ const char *force_default_device = getenv("MESA_VK_DEVICE_SELECT_FORCE_DEFAULT_DEVICE"); if (force_default_device && !strcmp(force_default_device, "1") && selected_physical_device_count != 0) + expose_only_one_dev = true; + + if (expose_only_one_dev) selected_physical_device_count = 1; for (unsigned i = 0; i < selected_physical_device_count; i++) {