gpu: Fix NVIDIA GPU index detection when card0 is missing

On systems without /sys/class/drm/card0, gamemode fails to detect the
correct NVIDIA GPU index when the GPU device is explicitly set in
gamemode.ini.

This patch adjusts get_gpu_index_id_nv() to skip over non-NVIDIA
devices without prematurely failing, correctly mapping the configured
DRM device index to the NVML index.

Fixes: #486
Tested on: RTX 3070 (driver 575.64.03) on Ubuntu 25.04, cards 0-2 and some other random numbers were tested
This commit is contained in:
mangobiche
2025-08-14 16:22:47 -05:00
committed by afayaz-feral
parent 4ce5f2193a
commit 4ae69409c1

View File

@@ -67,6 +67,14 @@ static void print_usage_and_exit(void)
exit(EXIT_FAILURE);
}
/* Return 1 if /sys/class/drm/card<idx>/device/vendor exists and is readable, else 0 */
static int drm_card_exists(int idx)
{
char path[PATH_MAX];
snprintf(path, PATH_MAX, "/sys/class/drm/card%d/device/vendor", idx);
return access(path, R_OK) == 0;
}
static const char *get_nv_attr(const char *attr)
{
static char out[EXTERNAL_BUFFER_MAX];
@@ -91,37 +99,41 @@ static int set_nv_attr(const char *attr)
return 0;
}
/* Get the nvidia driver index for the current GPU */
/* Get the nvidia driver index for the current GPU
* Map DRM card index (info->device) -> nvidia-settings GPU index.
* We only count *existing* DRM cards and only increment on NVIDIA vendors.
*/
static long get_gpu_index_id_nv(struct GameModeGPUInfo *info)
{
if (info->vendor != Vendor_NVIDIA)
return -1;
/* NOTE: This is currently based off of a best guess of how the NVidia gpu index works
* ie. that the index is simply the index into available NV gpus in the same order as drm
* If that is not the case then this may fail to discern the correct GPU
*/
int device = 0;
int nv_device = -1;
while (device <= info->device) {
/* Get the vendor for each gpu sequentially */
enum GPUVendor vendor = gamemode_get_gpu_vendor(device++);
switch (vendor) {
case Vendor_NVIDIA:
/* If we've found an nvidia device, increment our counter */
/* Iterate over DRM card numbers up to the requested one,
* but skip holes like a missing card0.
*/
for (int device = 0; device <= info->device; device++) {
/* Skip non-existent DRM indices to avoid noisy /sys errors */
if (!drm_card_exists(device))
continue;
/* Probe vendor only for existing cards */
enum GPUVendor vendor = gamemode_get_gpu_vendor(device);
if (vendor == Vendor_NVIDIA) {
/* Each NVIDIA DRM card before/at info->device bumps the NV index */
nv_device++;
break;
case Vendor_Invalid:
/* Bail out, we've gone too far */
LOG_ERROR("Failed to find Nvidia GPU with expected index!\n");
break;
default:
/* Non-NV gpu, continue */
break;
} else {
/* Non-NVIDIA or unreadable -> just ignore */
continue;
}
}
if (nv_device < 0) {
LOG_ERROR("Could not resolve NVIDIA index for DRM card%ld (no NVIDIA cards found up to that index)\n",
info->device);
}
};
return nv_device;
}