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); 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 const char *get_nv_attr(const char *attr)
{ {
static char out[EXTERNAL_BUFFER_MAX]; static char out[EXTERNAL_BUFFER_MAX];
@@ -91,37 +99,41 @@ static int set_nv_attr(const char *attr)
return 0; 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) static long get_gpu_index_id_nv(struct GameModeGPUInfo *info)
{ {
if (info->vendor != Vendor_NVIDIA) if (info->vendor != Vendor_NVIDIA)
return -1; 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; 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) { /* Iterate over DRM card numbers up to the requested one,
case Vendor_NVIDIA: * but skip holes like a missing card0.
/* If we've found an nvidia device, increment our counter */ */
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++; nv_device++;
break; } else {
case Vendor_Invalid: /* Non-NVIDIA or unreadable -> just ignore */
/* Bail out, we've gone too far */ continue;
LOG_ERROR("Failed to find Nvidia GPU with expected index!\n"); }
break; }
default:
/* Non-NV gpu, continue */ if (nv_device < 0) {
break; 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; return nv_device;
} }