2 * Copyright © 2017 Google
3 * Copyright © 2019 Red Hat
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 /* Rules for device selection.
26 * Is there an X or wayland connection open (or DISPLAY set).
27 * If no - try and find which device was the boot_vga device.
28 * If yes - try and work out which device is the connection primary,
29 * DRI_PRIME tagged overrides only work if bus info, =1 will just pick an alternate.
32 #include <vulkan/vk_layer.h>
40 #include "device_select.h"
41 #include "c99_compat.h"
42 #include "hash_table.h"
44 #include "c11/threads.h"
46 struct instance_info
{
47 PFN_vkDestroyInstance DestroyInstance
;
48 PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices
;
49 PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups
;
50 PFN_vkGetInstanceProcAddr GetInstanceProcAddr
;
51 PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr
;
52 PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties
;
53 PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties
;
54 PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR
;
55 bool has_props2
, has_pci_bus
;
56 bool has_wayland
, has_xcb
;
59 static struct hash_table
*device_select_instance_ht
= NULL
;
60 static mtx_t device_select_mutex
;
62 static once_flag device_select_is_init
= ONCE_FLAG_INIT
;
64 static void device_select_once_init(void) {
65 mtx_init(&device_select_mutex
, mtx_plain
);
69 device_select_init_instances(void)
71 call_once(&device_select_is_init
, device_select_once_init
);
73 mtx_lock(&device_select_mutex
);
74 if (!device_select_instance_ht
)
75 device_select_instance_ht
= _mesa_hash_table_create(NULL
, _mesa_hash_pointer
,
76 _mesa_key_pointer_equal
);
77 mtx_unlock(&device_select_mutex
);
81 device_select_try_free_ht(void)
83 mtx_lock(&device_select_mutex
);
84 if (device_select_instance_ht
) {
85 if (_mesa_hash_table_num_entries(device_select_instance_ht
) == 0) {
86 _mesa_hash_table_destroy(device_select_instance_ht
, NULL
);
87 device_select_instance_ht
= NULL
;
90 mtx_unlock(&device_select_mutex
);
94 device_select_layer_add_instance(VkInstance instance
, struct instance_info
*info
)
96 device_select_init_instances();
97 mtx_lock(&device_select_mutex
);
98 _mesa_hash_table_insert(device_select_instance_ht
, instance
, info
);
99 mtx_unlock(&device_select_mutex
);
102 static struct instance_info
*
103 device_select_layer_get_instance(VkInstance instance
)
105 struct hash_entry
*entry
;
106 struct instance_info
*info
= NULL
;
107 mtx_lock(&device_select_mutex
);
108 entry
= _mesa_hash_table_search(device_select_instance_ht
, (void *)instance
);
110 info
= (struct instance_info
*)entry
->data
;
111 mtx_unlock(&device_select_mutex
);
116 device_select_layer_remove_instance(VkInstance instance
)
118 mtx_lock(&device_select_mutex
);
119 _mesa_hash_table_remove_key(device_select_instance_ht
, instance
);
120 mtx_unlock(&device_select_mutex
);
121 device_select_try_free_ht();
124 static VkResult
device_select_CreateInstance(const VkInstanceCreateInfo
*pCreateInfo
,
125 const VkAllocationCallbacks
*pAllocator
,
126 VkInstance
*pInstance
)
128 VkLayerInstanceCreateInfo
*chain_info
;
129 for(chain_info
= (VkLayerInstanceCreateInfo
*)pCreateInfo
->pNext
; chain_info
; chain_info
= (VkLayerInstanceCreateInfo
*)chain_info
->pNext
)
130 if(chain_info
->sType
== VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
&& chain_info
->function
== VK_LAYER_LINK_INFO
)
133 assert(chain_info
->u
.pLayerInfo
);
134 struct instance_info
*info
= (struct instance_info
*)calloc(1, sizeof(struct instance_info
));
136 info
->GetInstanceProcAddr
= chain_info
->u
.pLayerInfo
->pfnNextGetInstanceProcAddr
;
137 PFN_vkCreateInstance fpCreateInstance
=
138 (PFN_vkCreateInstance
)info
->GetInstanceProcAddr(NULL
, "vkCreateInstance");
139 if (fpCreateInstance
== NULL
) {
140 return VK_ERROR_INITIALIZATION_FAILED
;
143 chain_info
->u
.pLayerInfo
= chain_info
->u
.pLayerInfo
->pNext
;
145 VkResult result
= fpCreateInstance(pCreateInfo
, pAllocator
, pInstance
);
146 if (result
!= VK_SUCCESS
)
149 for (unsigned i
= 0; i
< pCreateInfo
->enabledExtensionCount
; i
++) {
150 if (!strcmp(pCreateInfo
->ppEnabledExtensionNames
[i
], VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
))
151 info
->has_props2
= true;
152 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
153 if (!strcmp(pCreateInfo
->ppEnabledExtensionNames
[i
], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
))
154 info
->has_wayland
= true;
156 #ifdef VK_USE_PLATFORM_XCB_KHR
157 if (!strcmp(pCreateInfo
->ppEnabledExtensionNames
[i
], VK_KHR_XCB_SURFACE_EXTENSION_NAME
))
158 info
->has_xcb
= true;
162 info
->GetPhysicalDeviceProcAddr
= (PFN_GetPhysicalDeviceProcAddr
)info
->GetInstanceProcAddr(*pInstance
, "vk_layerGetPhysicalDeviceProcAddr");
163 #define DEVSEL_GET_CB(func) info->func = (PFN_vk##func)info->GetInstanceProcAddr(*pInstance, "vk" #func)
164 DEVSEL_GET_CB(DestroyInstance
);
165 DEVSEL_GET_CB(EnumeratePhysicalDevices
);
166 DEVSEL_GET_CB(EnumeratePhysicalDeviceGroups
);
167 DEVSEL_GET_CB(GetPhysicalDeviceProperties
);
168 DEVSEL_GET_CB(EnumerateDeviceExtensionProperties
);
169 if (info
->has_props2
)
170 DEVSEL_GET_CB(GetPhysicalDeviceProperties2KHR
);
173 device_select_layer_add_instance(*pInstance
, info
);
178 static void device_select_DestroyInstance(VkInstance instance
, const VkAllocationCallbacks
* pAllocator
)
180 struct instance_info
*info
= device_select_layer_get_instance(instance
);
182 device_select_layer_remove_instance(instance
);
183 info
->DestroyInstance(instance
, pAllocator
);
188 static void print_gpu(const struct instance_info
*info
, unsigned index
, VkPhysicalDevice device
)
190 const char *type
= "";
191 VkPhysicalDevicePCIBusInfoPropertiesEXT ext_pci_properties
= (VkPhysicalDevicePCIBusInfoPropertiesEXT
) {
192 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT
194 VkPhysicalDeviceProperties2KHR properties
= (VkPhysicalDeviceProperties2KHR
){
195 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR
197 if (info
->has_props2
&& info
->has_pci_bus
)
198 properties
.pNext
= &ext_pci_properties
;
199 if (info
->GetPhysicalDeviceProperties2KHR
)
200 info
->GetPhysicalDeviceProperties2KHR(device
, &properties
);
202 info
->GetPhysicalDeviceProperties(device
, &properties
.properties
);
204 switch(properties
.properties
.deviceType
) {
205 case VK_PHYSICAL_DEVICE_TYPE_OTHER
:
209 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
:
210 type
= "integrated GPU";
212 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
:
213 type
= "discrete GPU";
215 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU
:
216 type
= "virtual GPU";
218 case VK_PHYSICAL_DEVICE_TYPE_CPU
:
222 fprintf(stderr
, " GPU %d: %x:%x \"%s\" %s", index
, properties
.properties
.vendorID
,
223 properties
.properties
.deviceID
, properties
.properties
.deviceName
, type
);
224 if (info
->has_pci_bus
)
225 fprintf(stderr
, " %04x:%02x:%02x.%x", ext_pci_properties
.pciDomain
,
226 ext_pci_properties
.pciBus
, ext_pci_properties
.pciDevice
,
227 ext_pci_properties
.pciFunction
);
228 fprintf(stderr
, "\n");
231 static void fill_drm_device_info(const struct instance_info
*info
,
232 struct device_pci_info
*drm_device
,
233 VkPhysicalDevice device
)
235 VkPhysicalDevicePCIBusInfoPropertiesEXT ext_pci_properties
= (VkPhysicalDevicePCIBusInfoPropertiesEXT
) {
236 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT
239 VkPhysicalDeviceProperties2KHR properties
= (VkPhysicalDeviceProperties2KHR
){
240 .sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR
243 if (info
->has_props2
&& info
->has_pci_bus
)
244 properties
.pNext
= &ext_pci_properties
;
245 if (info
->GetPhysicalDeviceProperties2KHR
)
246 info
->GetPhysicalDeviceProperties2KHR(device
, &properties
);
248 info
->GetPhysicalDeviceProperties(device
, &properties
.properties
);
250 drm_device
->dev_info
.vendor_id
= properties
.properties
.vendorID
;
251 drm_device
->dev_info
.device_id
= properties
.properties
.deviceID
;
252 if (info
->has_pci_bus
) {
253 drm_device
->has_bus_info
= true;
254 drm_device
->bus_info
.domain
= ext_pci_properties
.pciDomain
;
255 drm_device
->bus_info
.bus
= ext_pci_properties
.pciBus
;
256 drm_device
->bus_info
.dev
= ext_pci_properties
.pciDevice
;
257 drm_device
->bus_info
.func
= ext_pci_properties
.pciFunction
;
261 static int device_select_find_explicit_default(struct device_pci_info
*pci_infos
,
262 uint32_t device_count
,
263 const char *selection
)
265 int default_idx
= -1;
266 unsigned vendor_id
, device_id
;
267 int matched
= sscanf(selection
, "%x:%x", &vendor_id
, &device_id
);
271 for (unsigned i
= 0; i
< device_count
; ++i
) {
272 if (pci_infos
[i
].dev_info
.vendor_id
== vendor_id
&&
273 pci_infos
[i
].dev_info
.device_id
== device_id
)
279 static int device_select_find_dri_prime_tag_default(struct device_pci_info
*pci_infos
,
280 uint32_t device_count
,
281 const char *dri_prime
)
283 int default_idx
= -1;
284 for (unsigned i
= 0; i
< device_count
; ++i
) {
286 if (asprintf(&tag
, "pci-%04x_%02x_%02x_%1u",
287 pci_infos
[i
].bus_info
.domain
,
288 pci_infos
[i
].bus_info
.bus
,
289 pci_infos
[i
].bus_info
.dev
,
290 pci_infos
[i
].bus_info
.func
) >= 0) {
291 if (strcmp(dri_prime
, tag
))
299 static int device_select_find_boot_vga_default(struct device_pci_info
*pci_infos
,
300 uint32_t device_count
)
302 char boot_vga_path
[1024];
303 int default_idx
= -1;
304 for (unsigned i
= 0; i
< device_count
; ++i
) {
305 /* fallback to probing the pci bus boot_vga device. */
306 snprintf(boot_vga_path
, 1023, "/sys/bus/pci/devices/%04x:%02x:%02x.%x/boot_vga", pci_infos
[i
].bus_info
.domain
,
307 pci_infos
[i
].bus_info
.bus
, pci_infos
[i
].bus_info
.dev
, pci_infos
[i
].bus_info
.func
);
308 int fd
= open(boot_vga_path
, O_RDONLY
);
311 if (read(fd
, &val
, 1) == 1) {
317 if (default_idx
!= -1)
323 static uint32_t get_default_device(const struct instance_info
*info
,
324 const char *selection
,
325 uint32_t physical_device_count
,
326 VkPhysicalDevice
*pPhysicalDevices
)
328 int default_idx
= -1;
329 const char *dri_prime
= getenv("DRI_PRIME");
330 bool dri_prime_is_one
= false;
332 if (dri_prime
&& !strcmp(dri_prime
, "1"))
333 dri_prime_is_one
= true;
335 if (dri_prime
&& !dri_prime_is_one
&& !info
->has_pci_bus
) {
336 fprintf(stderr
, "device-select: cannot correctly use DRI_PRIME tag\n");
339 struct device_pci_info
*pci_infos
= (struct device_pci_info
*)calloc(physical_device_count
, sizeof(struct device_pci_info
));
343 for (unsigned i
= 0; i
< physical_device_count
; ++i
) {
344 fill_drm_device_info(info
, &pci_infos
[i
], pPhysicalDevices
[i
]);
348 default_idx
= device_select_find_explicit_default(pci_infos
, physical_device_count
, selection
);
349 if (default_idx
== -1 && info
->has_pci_bus
&& dri_prime
&& !dri_prime_is_one
)
350 default_idx
= device_select_find_dri_prime_tag_default(pci_infos
, physical_device_count
, dri_prime
);
351 if (default_idx
== -1 && info
->has_wayland
)
352 default_idx
= device_select_find_wayland_pci_default(pci_infos
, physical_device_count
);
353 if (default_idx
== -1 && info
->has_xcb
)
354 default_idx
= device_select_find_xcb_pci_default(pci_infos
, physical_device_count
);
355 if (info
->has_pci_bus
&& default_idx
== -1) {
356 default_idx
= device_select_find_boot_vga_default(pci_infos
, physical_device_count
);
359 /* DRI_PRIME=1 handling - pick any other device than default. */
360 if (default_idx
!= -1 && dri_prime_is_one
&& physical_device_count
> 1) {
361 if (default_idx
== 0)
363 else if (default_idx
== 1)
367 return default_idx
== -1 ? 0 : default_idx
;
370 static VkResult
device_select_EnumeratePhysicalDevices(VkInstance instance
,
371 uint32_t* pPhysicalDeviceCount
,
372 VkPhysicalDevice
*pPhysicalDevices
)
374 struct instance_info
*info
= device_select_layer_get_instance(instance
);
375 uint32_t physical_device_count
= 0;
376 uint32_t selected_physical_device_count
= 0;
377 const char* selection
= getenv("MESA_VK_DEVICE_SELECT");
378 VkResult result
= info
->EnumeratePhysicalDevices(instance
, &physical_device_count
, NULL
);
379 VK_OUTARRAY_MAKE(out
, pPhysicalDevices
, pPhysicalDeviceCount
);
380 if (result
!= VK_SUCCESS
)
383 VkPhysicalDevice
*physical_devices
= (VkPhysicalDevice
*)calloc(sizeof(VkPhysicalDevice
), physical_device_count
);
384 VkPhysicalDevice
*selected_physical_devices
= (VkPhysicalDevice
*)calloc(sizeof(VkPhysicalDevice
),
385 physical_device_count
);
387 if (!physical_devices
|| !selected_physical_devices
) {
388 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
392 result
= info
->EnumeratePhysicalDevices(instance
, &physical_device_count
, physical_devices
);
393 if (result
!= VK_SUCCESS
)
396 for (unsigned i
= 0; i
< physical_device_count
; i
++) {
398 info
->EnumerateDeviceExtensionProperties(physical_devices
[i
], NULL
, &count
, NULL
);
400 VkExtensionProperties
*extensions
= calloc(count
, sizeof(VkExtensionProperties
));
401 if (info
->EnumerateDeviceExtensionProperties(physical_devices
[i
], NULL
, &count
, extensions
) == VK_SUCCESS
) {
402 for (unsigned j
= 0; j
< count
; j
++) {
403 if (!strcmp(extensions
[j
].extensionName
, VK_EXT_PCI_BUS_INFO_EXTENSION_NAME
))
404 info
->has_pci_bus
= true;
410 if (selection
&& strcmp(selection
, "list") == 0) {
411 fprintf(stderr
, "selectable devices:\n");
412 for (unsigned i
= 0; i
< physical_device_count
; ++i
)
413 print_gpu(info
, i
, physical_devices
[i
]);
416 unsigned selected_index
= get_default_device(info
, selection
, physical_device_count
, physical_devices
);
417 selected_physical_device_count
= physical_device_count
;
418 selected_physical_devices
[0] = physical_devices
[selected_index
];
419 for (unsigned i
= 0; i
< physical_device_count
- 1; ++i
) {
420 unsigned this_idx
= i
< selected_index
? i
: i
+ 1;
421 selected_physical_devices
[i
+ 1] = physical_devices
[this_idx
];
425 if (selected_physical_device_count
== 0) {
426 fprintf(stderr
, "WARNING: selected no devices with MESA_VK_DEVICE_SELECT\n");
429 assert(result
== VK_SUCCESS
);
431 for (unsigned i
= 0; i
< selected_physical_device_count
; i
++) {
432 vk_outarray_append(&out
, ent
) {
433 *ent
= selected_physical_devices
[i
];
436 result
= vk_outarray_status(&out
);
438 free(physical_devices
);
439 free(selected_physical_devices
);
443 static VkResult
device_select_EnumeratePhysicalDeviceGroups(VkInstance instance
,
444 uint32_t* pPhysicalDeviceGroupCount
,
445 VkPhysicalDeviceGroupProperties
*pPhysicalDeviceGroups
)
447 struct instance_info
*info
= device_select_layer_get_instance(instance
);
448 VkResult result
= info
->EnumeratePhysicalDeviceGroups(instance
, pPhysicalDeviceGroupCount
, pPhysicalDeviceGroups
);
452 static void (*get_pdevice_proc_addr(VkInstance instance
, const char* name
))()
454 struct instance_info
*info
= device_select_layer_get_instance(instance
);
455 return info
->GetPhysicalDeviceProcAddr(instance
, name
);
458 static void (*get_instance_proc_addr(VkInstance instance
, const char* name
))()
460 if (strcmp(name
, "vkCreateInstance") == 0)
461 return (void(*)())device_select_CreateInstance
;
462 if (strcmp(name
, "vkDestroyInstance") == 0)
463 return (void(*)())device_select_DestroyInstance
;
464 if (strcmp(name
, "vkEnumeratePhysicalDevices") == 0)
465 return (void(*)())device_select_EnumeratePhysicalDevices
;
466 if (strcmp(name
, "vkEnumeratePhysicalDeviceGroups") == 0)
467 return (void(*)())device_select_EnumeratePhysicalDeviceGroups
;
469 struct instance_info
*info
= device_select_layer_get_instance(instance
);
470 return info
->GetInstanceProcAddr(instance
, name
);
473 VK_LAYER_EXPORT VkResult
vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface
*pVersionStruct
)
475 if (pVersionStruct
->loaderLayerInterfaceVersion
< 2)
476 return VK_ERROR_INITIALIZATION_FAILED
;
477 pVersionStruct
->loaderLayerInterfaceVersion
= 2;
479 pVersionStruct
->pfnGetInstanceProcAddr
= get_instance_proc_addr
;
480 pVersionStruct
->pfnGetPhysicalDeviceProcAddr
= get_pdevice_proc_addr
;