Skip to content

Commit

Permalink
Enumerate additional PCI classes in the graphics adapter probe
Browse files Browse the repository at this point in the history
Some integrated GPUs, such as RDNA3.5, appear to use
the PCI_CLASS_DISPLAY_OTHER class.
  • Loading branch information
jellysquid3 committed Oct 26, 2024
1 parent b206496 commit fcfc28c
Showing 1 changed file with 31 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@

import net.caffeinemc.mods.sodium.client.compatibility.environment.OsUtils;
import net.caffeinemc.mods.sodium.client.platform.windows.api.d3dkmt.D3DKMT;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import oshi.util.ExecutingCommand;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.*;

public class GraphicsAdapterProbe {
private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-GraphicsAdapterProbe");

private static final Set<String> LINUX_PCI_CLASSES = Set.of(
"0x030000", // PCI_CLASS_DISPLAY_VGA
"0x030001", // PCI_CLASS_DISPLAY_XGA
"0x030200", // PCI_CLASS_DISPLAY_3D
"0x038000" // PCI_CLASS_DISPLAY_OTHER
);

private static List<? extends GraphicsAdapterInfo> ADAPTERS = List.of();

public static void findAdapters() {
Expand Down Expand Up @@ -65,37 +70,43 @@ public static void findAdapters() {
Iterable<Path> devicesIter = devices::iterator;

for (var devicePath : devicesIter) {
// 0x030000 = VGA compatible controller
// 0x030200 = 3D controller (GPUs with no inputs attached, e.g. hybrid graphics laptops)
var deviceClass = Files.readString(devicePath.resolve("class")).trim();
if (!deviceClass.equals("0x030000") && !deviceClass.equals("0x030200")) {

if (!LINUX_PCI_CLASSES.contains(deviceClass)) {
continue;
}

var pciVendorId = Files.readString(devicePath.resolve("vendor")).trim();
var pciDeviceId = Files.readString(devicePath.resolve("device")).trim();

var adapterVendor = GraphicsAdapterVendor.fromPciVendorId(pciVendorId);
var adapterName = getPciDeviceName$Linux(pciVendorId, pciDeviceId);

// The Linux kernel doesn't provide a way to get the device name, so we need to use lspci,
// since it comes with a list of known device names mapped to device IDs.
var name = ExecutingCommand // See `man lspci` for more information
.runNative("lspci -vmm -d " + pciVendorId.substring(2) + ":" + pciDeviceId.substring(2))
.stream()
.filter(line -> line.startsWith("Device:"))
.map(line -> line.substring("Device:".length()).trim())
.findFirst()
.orElse("unknown");

var vendor = GraphicsAdapterVendor.fromPciVendorId(pciVendorId);

var info = new GraphicsAdapterInfo.LinuxPciAdapterInfo(vendor, name, pciVendorId, pciDeviceId);
var info = new GraphicsAdapterInfo.LinuxPciAdapterInfo(adapterVendor, adapterName, pciVendorId, pciDeviceId);
results.add(info);
}
} catch (IOException ignored) {}

return results;
}

private static @NotNull String getPciDeviceName$Linux(String vendorId, String deviceId) {
// The Linux kernel doesn't provide a way to get the device name, so we need to use lspci,
// since it comes with a list of known device names mapped to device IDs.
// See `man lspci` for more information

// [<vendor>]:[<device>][:<class>[:<prog-if>]]
var deviceFilter = vendorId.substring(2) + ":" + deviceId.substring(2);

return ExecutingCommand
.runNative("lspci -vmm -d " + deviceFilter)
.stream()
.filter(line -> line.startsWith("Device:"))
.map(line -> line.substring("Device:".length()).trim())
.findFirst()
.orElse("unknown");
}

public static Collection<? extends GraphicsAdapterInfo> getAdapters() {
if (ADAPTERS == null) {
LOGGER.error("Graphics adapters not probed yet; returning an empty list.");
Expand Down

0 comments on commit fcfc28c

Please sign in to comment.