启动时在日志中记录当前平台的所有 GPU (#3893)
This commit is contained in:
@@ -16,6 +16,7 @@ dependencies {
|
||||
api(libs.jsoup)
|
||||
api(libs.chardet)
|
||||
api(libs.jna)
|
||||
api(libs.pci.ids)
|
||||
|
||||
compileOnlyApi(libs.jetbrains.annotations)
|
||||
}
|
||||
|
||||
@@ -19,66 +19,113 @@
|
||||
package org.jackhuang.hmcl.util.io;
|
||||
|
||||
import org.jackhuang.hmcl.util.InfiniteSizeList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
public final class CSVTable {
|
||||
private final List<List<String>> table = new InfiniteSizeList<>();
|
||||
private int columnCount = 0;
|
||||
private int rowCount = 0;
|
||||
private final InfiniteSizeList<InfiniteSizeList<String>> table = new InfiniteSizeList<>();
|
||||
|
||||
private CSVTable() {
|
||||
public CSVTable() {
|
||||
}
|
||||
|
||||
public static CSVTable createEmpty() {
|
||||
return new CSVTable();
|
||||
public int getColumnCount() {
|
||||
return columnCount;
|
||||
}
|
||||
|
||||
public String get(int x, int y) {
|
||||
public int getRowCount() {
|
||||
return rowCount;
|
||||
}
|
||||
|
||||
public @NotNull String get(int x, int y) {
|
||||
List<String> row = table.get(y);
|
||||
if (row == null) {
|
||||
return null;
|
||||
return "";
|
||||
}
|
||||
return row.get(x);
|
||||
String value = row.get(x);
|
||||
return value != null ? value : "";
|
||||
}
|
||||
|
||||
public void set(int x, int y, String txt) {
|
||||
List<String> row = table.get(y);
|
||||
if (x < 0 || y < 0)
|
||||
throw new IllegalArgumentException("x or y must be greater than or equal to 0");
|
||||
|
||||
InfiniteSizeList<String> row = table.get(y);
|
||||
if (row == null) {
|
||||
row = new InfiniteSizeList<>(x);
|
||||
table.set(y, row);
|
||||
}
|
||||
row.set(x, txt);
|
||||
|
||||
columnCount = Integer.max(columnCount, x + 1);
|
||||
rowCount = Integer.max(rowCount, y + 1);
|
||||
}
|
||||
|
||||
public void write(OutputStream outputStream) throws IOException {
|
||||
try (PrintWriter printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
|
||||
outputStream, StandardCharsets.UTF_8)), false
|
||||
)) {
|
||||
for (List<String> row : this.table) {
|
||||
if (row != null) {
|
||||
for (int j = 0; j < row.size(); j++) {
|
||||
String txt = row.get(j);
|
||||
if (txt != null) {
|
||||
printWriter.write(this.escape(txt));
|
||||
}
|
||||
public void write(Path file) throws IOException {
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
|
||||
write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
if (j != row.size() - 1) {
|
||||
printWriter.write(',');
|
||||
public void write(Appendable out) throws IOException {
|
||||
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
||||
List<String> row = this.table.get(rowIndex);
|
||||
if (row != null) {
|
||||
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) {
|
||||
String txt = row.get(columnIndex);
|
||||
if (txt != null) {
|
||||
if (txt.indexOf('"') < 0 && txt.indexOf(',') < 0 && txt.indexOf('\n') < 0 && txt.indexOf('\r') < 0)
|
||||
out.append(txt);
|
||||
else {
|
||||
out.append('"');
|
||||
for (int i = 0; i < txt.length(); i++) {
|
||||
char c = txt.charAt(i);
|
||||
switch (c) {
|
||||
case '"':
|
||||
out.append("\\\"");
|
||||
break;
|
||||
case '\r':
|
||||
out.append("\\r");
|
||||
break;
|
||||
case '\n':
|
||||
out.append("\\n");
|
||||
break;
|
||||
default:
|
||||
out.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
out.append('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printWriter.write('\n');
|
||||
if (columnIndex < columnCount - 1)
|
||||
out.append(',');
|
||||
}
|
||||
} else {
|
||||
for (int columnIndex = 0; columnIndex < columnCount - 1; columnIndex++) {
|
||||
out.append(',');
|
||||
}
|
||||
}
|
||||
|
||||
out.append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
private String escape(String txt) {
|
||||
if (!txt.contains("\"") && !txt.contains(",")) {
|
||||
return txt;
|
||||
} else {
|
||||
return "\"" + txt.replace("\"", "\"\"") + "\"";
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try {
|
||||
write(builder);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.platform;
|
||||
|
||||
import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector;
|
||||
import org.jackhuang.hmcl.util.platform.linux.LinuxHardwareDetector;
|
||||
import org.jackhuang.hmcl.util.platform.macos.MacOSHardwareDetector;
|
||||
import org.jackhuang.hmcl.util.platform.windows.WindowsHardwareDetector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
public final class SystemInfo {
|
||||
|
||||
private static final class Holder {
|
||||
public static final HardwareDetector DETECTOR;
|
||||
|
||||
static {
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS)
|
||||
DETECTOR = new WindowsHardwareDetector();
|
||||
else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX)
|
||||
DETECTOR = new LinuxHardwareDetector();
|
||||
else if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX)
|
||||
DETECTOR = new MacOSHardwareDetector();
|
||||
else
|
||||
DETECTOR = new HardwareDetector();
|
||||
}
|
||||
|
||||
public static final @Nullable List<GraphicsCard> GRAPHICS_CARDS = DETECTOR.detectGraphicsCards();
|
||||
}
|
||||
|
||||
public static void initialize() {
|
||||
StringBuilder builder = new StringBuilder("System Info:");
|
||||
List<GraphicsCard> graphicsCards = getGraphicsCards();
|
||||
|
||||
if (graphicsCards != null) {
|
||||
if (graphicsCards.isEmpty())
|
||||
builder.append("\n - GPU: Not Found");
|
||||
else if (graphicsCards.size() == 1)
|
||||
builder.append("\n - GPU: ").append(graphicsCards.get(0));
|
||||
else {
|
||||
int index = 1;
|
||||
for (GraphicsCard graphicsCard : graphicsCards) {
|
||||
builder.append("\n - GPU ").append(index++).append(": ").append(graphicsCard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OperatingSystem.PhysicalMemoryStatus memoryStatus = OperatingSystem.getPhysicalMemoryStatus();
|
||||
if (memoryStatus.getTotal() > 0 && memoryStatus.getAvailable() > 0) {
|
||||
builder.append("\n - Memory: ")
|
||||
.append(String.format("%.2f GiB / %.2f GiB (%d%%)",
|
||||
memoryStatus.getUsedGB(), memoryStatus.getTotalGB(),
|
||||
(int) (((double) memoryStatus.getUsed() / memoryStatus.getTotal()) * 100)
|
||||
));
|
||||
}
|
||||
|
||||
LOG.info(builder.toString());
|
||||
}
|
||||
|
||||
public static @Nullable List<GraphicsCard> getGraphicsCards() {
|
||||
return Holder.GRAPHICS_CARDS;
|
||||
}
|
||||
|
||||
private SystemInfo() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.platform.hardware;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
public final class GraphicsCard {
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final @Nullable Vendor vendor;
|
||||
private final @Nullable Type type;
|
||||
private final @Nullable String driver;
|
||||
private final @Nullable String driverVersion;
|
||||
|
||||
private GraphicsCard(String name, @Nullable Vendor vendor, @Nullable Type type, @Nullable String driver, @Nullable String driverVersion) {
|
||||
this.name = Objects.requireNonNull(name);
|
||||
this.vendor = vendor;
|
||||
this.type = type;
|
||||
this.driver = driver;
|
||||
this.driverVersion = driverVersion;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public @Nullable Vendor getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
public @Nullable String getDriverVersion() {
|
||||
return driverVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(name);
|
||||
|
||||
if (type != null) {
|
||||
builder.append(" [").append(type).append(']');
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static final class Vendor {
|
||||
public static final Vendor INTEL = new Vendor("Intel");
|
||||
public static final Vendor NVIDIA = new Vendor("NVIDIA");
|
||||
public static final Vendor AMD = new Vendor("AMD");
|
||||
public static final Vendor APPLE = new Vendor("Apple");
|
||||
public static final Vendor QUALCOMM = new Vendor("Qualcomm");
|
||||
public static final Vendor MTK = new Vendor("MTK");
|
||||
public static final Vendor VMWARE = new Vendor("VMware");
|
||||
public static final Vendor PARALLEL = new Vendor("Parallel");
|
||||
public static final Vendor MICROSOFT = new Vendor("Microsoft");
|
||||
public static final Vendor MOORE_THREADS = new Vendor("Moore Threads");
|
||||
public static final Vendor BROADCOM = new Vendor("Broadcom");
|
||||
public static final Vendor IMG = new Vendor("Imagination");
|
||||
public static final Vendor LOONGSON = new Vendor("Loongson");
|
||||
public static final Vendor JINGJIA_MICRO = new Vendor("Jingjia Micro");
|
||||
public static final Vendor HUAWEI = new Vendor("Huawei");
|
||||
public static final Vendor ZHAOXIN = new Vendor("Zhaoxin");
|
||||
|
||||
public static @Nullable Vendor getKnown(String name) {
|
||||
if (name == null)
|
||||
return null;
|
||||
|
||||
String lower = name.toLowerCase(Locale.ROOT);
|
||||
if (lower.startsWith("intel")) return INTEL;
|
||||
if (lower.startsWith("nvidia")) return NVIDIA;
|
||||
if (lower.startsWith("advanced micro devices")
|
||||
|| (lower.startsWith("amd") && !(lower.length() > 3 && Character.isAlphabetic(lower.charAt(3)))))
|
||||
return AMD;
|
||||
if (lower.equals("brcm") || lower.startsWith("broadcom")) return BROADCOM;
|
||||
if (lower.startsWith("mediatek")) return MTK;
|
||||
if (lower.startsWith("qualcomm")) return QUALCOMM;
|
||||
if (lower.startsWith("apple")) return APPLE;
|
||||
if (lower.startsWith("microsoft")) return MICROSOFT;
|
||||
if (lower.startsWith("imagination") || lower.equals("img")) return IMG;
|
||||
|
||||
if (lower.startsWith("loongson")) return LOONGSON;
|
||||
if (lower.startsWith("moore threads")) return MOORE_THREADS;
|
||||
if (lower.startsWith("jingjia")) return JINGJIA_MICRO;
|
||||
if (lower.startsWith("huawei")) return HUAWEI;
|
||||
if (lower.startsWith("zhaoxin")) return ZHAOXIN;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Contract("null -> null; !null -> !null")
|
||||
public static Vendor of(String name) {
|
||||
if (name == null)
|
||||
return null;
|
||||
|
||||
Vendor known = getKnown(name);
|
||||
return known != null ? known : new Vendor(name);
|
||||
}
|
||||
|
||||
public static @Nullable Vendor ofId(int vendorId) {
|
||||
// https://devicehunt.com/all-pci-vendors
|
||||
switch (vendorId) {
|
||||
case 0x106b:
|
||||
return APPLE;
|
||||
case 0x1002:
|
||||
case 0x1022:
|
||||
case 0x1dd8: // AMD Pensando Systems
|
||||
case 0x1924: // AMD Solarflare
|
||||
return AMD;
|
||||
case 0x8086:
|
||||
case 0x8087:
|
||||
case 0x03e7:
|
||||
return INTEL;
|
||||
case 0x0955:
|
||||
case 0x10de:
|
||||
case 0x12d2:
|
||||
return NVIDIA;
|
||||
case 0x1ed5:
|
||||
return MOORE_THREADS;
|
||||
case 0x168c:
|
||||
case 0x5143:
|
||||
return QUALCOMM;
|
||||
case 0x14c3:
|
||||
return MTK;
|
||||
case 0x15ad:
|
||||
return VMWARE;
|
||||
case 0x1ab8:
|
||||
return PARALLEL;
|
||||
case 0x1414:
|
||||
return MICROSOFT;
|
||||
case 0x182f:
|
||||
case 0x14e4:
|
||||
return BROADCOM;
|
||||
case 0x0014:
|
||||
return LOONGSON;
|
||||
case 0x0731:
|
||||
return JINGJIA_MICRO;
|
||||
case 0x19e5:
|
||||
return HUAWEI;
|
||||
case 0x1d17:
|
||||
return ZHAOXIN;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private final String name;
|
||||
|
||||
public Vendor(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof Vendor && name.equals(((Vendor) o).name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
Integrated,
|
||||
Discrete
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private String name;
|
||||
private Vendor vendor;
|
||||
private Type type;
|
||||
private String driver;
|
||||
private String driverVersion;
|
||||
|
||||
public GraphicsCard build() {
|
||||
if (name == null)
|
||||
throw new IllegalStateException("Name not set");
|
||||
|
||||
return new GraphicsCard(name, vendor, type, driver, driverVersion);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Builder setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vendor getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
public Builder setVendor(Vendor vendor) {
|
||||
this.vendor = vendor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Builder setType(Type type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
||||
public Builder setDriver(String driver) {
|
||||
this.driver = driver;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDriverVersion() {
|
||||
return driverVersion;
|
||||
}
|
||||
|
||||
public Builder setDriverVersion(String driverVersion) {
|
||||
this.driverVersion = driverVersion;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.platform.hardware;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
public class HardwareDetector {
|
||||
public @Nullable List<GraphicsCard> detectGraphicsCards() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.platform.linux;
|
||||
|
||||
import org.glavo.pci.ids.PCIIDsDatabase;
|
||||
import org.glavo.pci.ids.model.Device;
|
||||
import org.glavo.pci.ids.model.Vendor;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
* @see <a href="https://github.com/fastfetch-cli/fastfetch/blob/33205326683fd89ec63204f83549839e2374c286/src/detection/gpu/gpu_linux.c">gpu_linux.c</a>
|
||||
*/
|
||||
final class LinuxGPUDetector {
|
||||
private static volatile SoftReference<PCIIDsDatabase> databaseCache;
|
||||
|
||||
private static final Pattern PCI_MODALIAS_PATTERN =
|
||||
Pattern.compile("pci:v(?<vendorId>\\p{XDigit}{8})d(?<deviceId>\\p{XDigit}{8})sv(?<subVendorId>\\p{XDigit}{8})sd(?<subDeviceId>\\p{XDigit}{8})bc(?<classId>\\p{XDigit}{2})sc(?<subclassId>\\p{XDigit}{2})i\\p{XDigit}{2}");
|
||||
private static final Pattern PCI_DEVICE_PATTERN =
|
||||
Pattern.compile("(?<pciDomain>\\p{XDigit}+):(?<pciBus>\\p{XDigit}+):(?<pciDevice>\\p{XDigit}+)\\.(?<pciFunc>\\p{XDigit}+)");
|
||||
private static final Pattern OF_DEVICE_PATTERN =
|
||||
Pattern.compile("of:NgpuT[^C]*C(?<compatible>.*)");
|
||||
|
||||
private static PCIIDsDatabase getPCIIDsDatabase() {
|
||||
SoftReference<PCIIDsDatabase> databaseWeakReference = LinuxGPUDetector.databaseCache;
|
||||
PCIIDsDatabase pciIDsDatabase;
|
||||
|
||||
if (databaseCache != null) {
|
||||
pciIDsDatabase = databaseWeakReference.get();
|
||||
if (pciIDsDatabase != null) {
|
||||
return pciIDsDatabase;
|
||||
}
|
||||
}
|
||||
|
||||
for (String path : new String[]{
|
||||
"/usr/share/misc/pci.ids",
|
||||
"/usr/share/hwdata/pci.ids",
|
||||
"/usr/local/share/hwdata/pci.ids"
|
||||
}) {
|
||||
Path p = Paths.get(path);
|
||||
if (Files.isRegularFile(p)) {
|
||||
try {
|
||||
pciIDsDatabase = PCIIDsDatabase.load(p);
|
||||
databaseCache = new SoftReference<>(pciIDsDatabase);
|
||||
return pciIDsDatabase;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void detectDriver(GraphicsCard.Builder builder, Path deviceDir) {
|
||||
try {
|
||||
Path driverDir = Files.readSymbolicLink(deviceDir.resolve("driver"));
|
||||
if (driverDir.getNameCount() > 0) {
|
||||
|
||||
String name = driverDir.getName(driverDir.getNameCount() - 1).toString();
|
||||
builder.setDriver(name);
|
||||
|
||||
Path versionFile = deviceDir.resolve("driver/module/version");
|
||||
if (Files.isRegularFile(versionFile)) {
|
||||
builder.setDriverVersion(FileUtils.readText(versionFile).trim());
|
||||
} else if ("zx".equals(name)) {
|
||||
versionFile = deviceDir.resolve("zx_info/driver_version");
|
||||
if (Files.isRegularFile(versionFile)) {
|
||||
builder.setDriverVersion(FileUtils.readText(versionFile).trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private static GraphicsCard detectPCI(Path deviceDir, String modalias) throws IOException {
|
||||
Matcher matcher = PCI_MODALIAS_PATTERN.matcher(modalias);
|
||||
if (!matcher.matches())
|
||||
return null;
|
||||
|
||||
GraphicsCard.Builder builder = GraphicsCard.builder();
|
||||
|
||||
int vendorId = Integer.parseInt(matcher.group("vendorId"), 16);
|
||||
int deviceId = Integer.parseInt(matcher.group("deviceId"), 16);
|
||||
int classId = Integer.parseInt(matcher.group("classId"), 16);
|
||||
int subclassId = Integer.parseInt(matcher.group("subclassId"), 16);
|
||||
|
||||
if (classId != 0x03) // PCI_BASE_CLASS_DISPLAY
|
||||
return null; // Not a GPU device
|
||||
|
||||
Path pciPath = Files.readSymbolicLink(deviceDir);
|
||||
int nameCount = pciPath.getNameCount();
|
||||
if (nameCount == 0)
|
||||
return null;
|
||||
|
||||
matcher = PCI_DEVICE_PATTERN.matcher(pciPath.getName(nameCount - 1).toString());
|
||||
if (!matcher.matches())
|
||||
return null;
|
||||
|
||||
int pciDomain = Integer.parseInt(matcher.group("pciDomain"), 16);
|
||||
int pciBus = Integer.parseInt(matcher.group("pciBus"), 16);
|
||||
int pciDevice = Integer.parseInt(matcher.group("pciDevice"), 16);
|
||||
int pciFunc = Integer.parseInt(matcher.group("pciFunc"), 16);
|
||||
|
||||
builder.setVendor(GraphicsCard.Vendor.ofId(vendorId));
|
||||
|
||||
detectDriver(builder, deviceDir);
|
||||
|
||||
try {
|
||||
if (builder.getVendor() == GraphicsCard.Vendor.AMD) {
|
||||
Path hwmon = deviceDir.resolve("hwmon");
|
||||
try (Stream<Path> subDirs = Files.list(hwmon)) {
|
||||
for (Path subDir : Lang.toIterable(subDirs)) {
|
||||
if (Files.isDirectory(subDir) && !subDir.getFileName().toString().startsWith(".")) {
|
||||
builder.setType(Files.exists(subDir.resolve("in1_input"))
|
||||
? GraphicsCard.Type.Integrated
|
||||
: GraphicsCard.Type.Discrete);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
Path revisionFile = deviceDir.resolve("revision");
|
||||
if (Files.isRegularFile(revisionFile)) {
|
||||
String revisionString = FileUtils.readText(revisionFile).trim();
|
||||
int revision = Integer.decode(revisionString);
|
||||
String prefix = String.format("%X,\t%X,\t", deviceId, revision);
|
||||
//noinspection DataFlowIssue
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
LinuxHardwareDetector.class.getResourceAsStream("/assets/platform/amdgpu.ids"), StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith(prefix)) {
|
||||
builder.setName(line.substring(prefix.length()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (builder.getVendor() == GraphicsCard.Vendor.INTEL) {
|
||||
builder.setType(pciDevice == 20 ? GraphicsCard.Type.Integrated : GraphicsCard.Type.Discrete);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
if (builder.getName() == null || builder.getVendor() == null) {
|
||||
PCIIDsDatabase database = getPCIIDsDatabase();
|
||||
if (database != null) {
|
||||
Vendor vendor = database.findVendor(vendorId);
|
||||
if (vendor != null) {
|
||||
if (builder.getVendor() == null)
|
||||
builder.setVendor(GraphicsCard.Vendor.of(vendor.getName()));
|
||||
|
||||
if (builder.getName() == null) {
|
||||
Device device = vendor.getDevices().get(deviceId);
|
||||
if (device != null) {
|
||||
matcher = Pattern.compile(".*\\[(?<name>.*)]").matcher(device.getName());
|
||||
if (matcher.matches())
|
||||
builder.setName(builder.getVendor() + " " + matcher.group("name"));
|
||||
else
|
||||
builder.setName(builder.getVendor() + " " + device.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (builder.getName() == null) {
|
||||
String subclassStr;
|
||||
switch (subclassId) {
|
||||
case 0: // PCI_CLASS_DISPLAY_VGA
|
||||
subclassStr = " (VGA compatible)";
|
||||
break;
|
||||
case 1: // PCI_CLASS_DISPLAY_XGA
|
||||
subclassStr = " (XGA compatible)";
|
||||
break;
|
||||
case 2: // PCI_CLASS_DISPLAY_3D
|
||||
subclassStr = " (3D)";
|
||||
break;
|
||||
default:
|
||||
subclassStr = "";
|
||||
}
|
||||
|
||||
builder.setName(String.format("%s Device %04X%s",
|
||||
builder.getVendor() != null ? builder.getVendor().toString() : "Unknown",
|
||||
deviceId, subclassStr));
|
||||
}
|
||||
|
||||
if (builder.getType() == null) {
|
||||
if (builder.getVendor() == GraphicsCard.Vendor.NVIDIA) {
|
||||
if (builder.getName().startsWith("GeForce")
|
||||
|| builder.getName().startsWith("Quadro")
|
||||
|| builder.getName().startsWith("Tesla"))
|
||||
builder.setType(GraphicsCard.Type.Discrete);
|
||||
|
||||
} else if (builder.getVendor() == GraphicsCard.Vendor.MOORE_THREADS) {
|
||||
if (builder.getName().startsWith("MTT "))
|
||||
builder.setType(GraphicsCard.Type.Discrete);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static GraphicsCard detectOF(Path deviceDir, String modalias) throws IOException {
|
||||
Matcher matcher = OF_DEVICE_PATTERN.matcher(modalias);
|
||||
if (!matcher.matches())
|
||||
return null;
|
||||
|
||||
GraphicsCard.Builder builder = new GraphicsCard.Builder();
|
||||
|
||||
String compatible = matcher.group("compatible");
|
||||
int idx = compatible.indexOf(',');
|
||||
if (idx < 0) {
|
||||
builder.setName(compatible.trim());
|
||||
} else {
|
||||
String vendorName = compatible.substring(0, idx).trim();
|
||||
GraphicsCard.Vendor vendor = GraphicsCard.Vendor.getKnown(vendorName);
|
||||
if (vendor == null)
|
||||
vendor = new GraphicsCard.Vendor(vendorName.toUpperCase(Locale.ROOT));
|
||||
|
||||
builder.setName(vendor + " " + compatible.substring(idx + 1).trim());
|
||||
builder.setVendor(vendor);
|
||||
}
|
||||
|
||||
builder.setType(GraphicsCard.Type.Integrated);
|
||||
|
||||
detectDriver(builder, deviceDir);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static List<GraphicsCard> detectAll() {
|
||||
Path drm = Paths.get("/sys/class/drm");
|
||||
if (!Files.isDirectory(drm))
|
||||
return Collections.emptyList();
|
||||
|
||||
ArrayList<GraphicsCard> cards = new ArrayList<>();
|
||||
|
||||
try (Stream<Path> stream = Files.list(drm)) {
|
||||
for (Path deviceRoot : Lang.toIterable(stream)) {
|
||||
Path dirName = deviceRoot.getFileName();
|
||||
if (dirName == null)
|
||||
continue;
|
||||
|
||||
String name = dirName.toString();
|
||||
if (!name.startsWith("card") || name.indexOf('-') >= 0)
|
||||
continue;
|
||||
|
||||
Path deviceDir = deviceRoot.resolve("device");
|
||||
Path modaliasFile = deviceDir.resolve("modalias");
|
||||
if (!Files.isRegularFile(modaliasFile))
|
||||
continue;
|
||||
|
||||
try {
|
||||
String modalias = FileUtils.readText(modaliasFile).trim();
|
||||
GraphicsCard graphicsCard = null;
|
||||
if (modalias.startsWith("pci:"))
|
||||
graphicsCard = detectPCI(deviceDir, modalias);
|
||||
else if (modalias.startsWith("of:"))
|
||||
graphicsCard = detectOF(deviceDir, modalias);
|
||||
|
||||
if (graphicsCard != null)
|
||||
cards.add(graphicsCard);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOG.warning("Failed to get graphics card info", e);
|
||||
} finally {
|
||||
databaseCache = null;
|
||||
System.gc();
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(cards);
|
||||
}
|
||||
|
||||
private LinuxGPUDetector() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.platform.linux;
|
||||
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
public final class LinuxHardwareDetector extends HardwareDetector {
|
||||
|
||||
@Override
|
||||
public List<GraphicsCard> detectGraphicsCards() {
|
||||
if (OperatingSystem.CURRENT_OS != OperatingSystem.LINUX)
|
||||
return null;
|
||||
return LinuxGPUDetector.detectAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.platform.macos;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
public final class MacOSHardwareDetector extends HardwareDetector {
|
||||
|
||||
@Override
|
||||
public List<GraphicsCard> detectGraphicsCards() {
|
||||
if (OperatingSystem.CURRENT_OS != OperatingSystem.OSX)
|
||||
return null;
|
||||
|
||||
Process process = null;
|
||||
String json = null;
|
||||
try {
|
||||
File devNull = new File("/dev/null");
|
||||
|
||||
Process finalProcess = process = new ProcessBuilder("/usr/sbin/system_profiler",
|
||||
"SPDisplaysDataType",
|
||||
"-json")
|
||||
.redirectInput(devNull)
|
||||
.redirectError(devNull)
|
||||
.start();
|
||||
|
||||
CompletableFuture<String> future = CompletableFuture.supplyAsync(Lang.wrap(() ->
|
||||
IOUtils.readFullyAsString(finalProcess.getInputStream(), OperatingSystem.NATIVE_CHARSET)),
|
||||
Schedulers.io());
|
||||
|
||||
if (!process.waitFor(15, TimeUnit.SECONDS))
|
||||
throw new TimeoutException();
|
||||
|
||||
if (process.exitValue() != 0)
|
||||
throw new IOException("Bad exit code: " + process.exitValue());
|
||||
|
||||
json = future.get();
|
||||
|
||||
JsonObject object = JsonUtils.GSON.fromJson(json, JsonObject.class);
|
||||
JsonArray spDisplaysDataType = object.getAsJsonArray("SPDisplaysDataType");
|
||||
if (spDisplaysDataType != null) {
|
||||
ArrayList<GraphicsCard> cards = new ArrayList<>();
|
||||
|
||||
for (JsonElement element : spDisplaysDataType) {
|
||||
JsonObject item = element.getAsJsonObject();
|
||||
|
||||
JsonElement deviceType = item.get("sppci_device_type");
|
||||
if (deviceType == null || !"spdisplays_gpu".equals(deviceType.getAsString()))
|
||||
continue;
|
||||
|
||||
JsonElement model = item.getAsJsonPrimitive("sppci_model");
|
||||
JsonElement vendor = item.getAsJsonPrimitive("spdisplays_vendor");
|
||||
JsonElement bus = item.getAsJsonPrimitive("sppci_bus");
|
||||
|
||||
if (model == null)
|
||||
continue;
|
||||
|
||||
GraphicsCard.Builder builder = GraphicsCard.builder()
|
||||
.setName(model.getAsString());
|
||||
|
||||
if (vendor != null)
|
||||
builder.setVendor(GraphicsCard.Vendor.of(StringUtils.removePrefix(vendor.getAsString(), "sppci_vendor_")));
|
||||
|
||||
GraphicsCard.Type type = GraphicsCard.Type.Integrated;
|
||||
if (bus != null) {
|
||||
String lower = bus.getAsString().toLowerCase(Locale.ROOT);
|
||||
if (!lower.contains("builtin") && !lower.contains("built_in") & !lower.contains("built-in"))
|
||||
type = GraphicsCard.Type.Discrete;
|
||||
}
|
||||
builder.setType(type);
|
||||
|
||||
cards.add(builder.build());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(cards);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
if (process != null && process.isAlive())
|
||||
process.destroy();
|
||||
|
||||
LOG.warning("Failed to get graphics card info" + (json != null ? ": " + json : ""), e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.platform.windows;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
public abstract class WinReg {
|
||||
|
||||
/**
|
||||
* @see <a href="https://learn.microsoft.com/windows/win32/sysinfo/predefined-keys">Predefined Keys</a>
|
||||
*/
|
||||
public enum HKEY {
|
||||
HKEY_CLASSES_ROOT(0x80000000),
|
||||
HKEY_CURRENT_USER(0x80000001),
|
||||
HKEY_LOCAL_MACHINE(0x80000002),
|
||||
HKEY_USERS(0x80000003),
|
||||
HKEY_PERFORMANCE_DATA(0x80000004),
|
||||
HKEY_PERFORMANCE_TEXT(0x80000050),
|
||||
HKEY_PERFORMANCE_NLSTEXT(0x80000060),
|
||||
HKEY_CURRENT_CONFIG(0x80000005),
|
||||
HKEY_DYN_DATA(0x80000006),
|
||||
HKEY_CURRENT_USER_LOCAL_SETTINGS(0x80000007);
|
||||
|
||||
private final int value;
|
||||
|
||||
HKEY(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.platform.windows;
|
||||
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
public final class WindowsHardwareDetector extends HardwareDetector {
|
||||
|
||||
private static List<Map<String, String>> parsePowerShellFormatList(Iterable<String> lines) {
|
||||
ArrayList<Map<String, String>> result = new ArrayList<>();
|
||||
Map<String, String> current = new LinkedHashMap<>();
|
||||
|
||||
for (String line : lines) {
|
||||
int idx = line.indexOf(':');
|
||||
|
||||
if (idx < 0) {
|
||||
if (!current.isEmpty()) {
|
||||
result.add(current);
|
||||
current = new LinkedHashMap<>();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
String key = line.substring(0, idx).trim();
|
||||
String value = line.substring(idx + 1).trim();
|
||||
|
||||
current.put(key, value);
|
||||
}
|
||||
|
||||
if (!current.isEmpty())
|
||||
result.add(current);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GraphicsCard> detectGraphicsCards() {
|
||||
if (!OperatingSystem.isWindows7OrLater())
|
||||
return null;
|
||||
|
||||
Process process = null;
|
||||
String list = null;
|
||||
try {
|
||||
File nul = new File("NUL");
|
||||
|
||||
String getCimInstance = OperatingSystem.SYSTEM_VERSION.startsWith("6.1")
|
||||
? "Get-WmiObject"
|
||||
: "Get-CimInstance";
|
||||
|
||||
Process finalProcess = process = new ProcessBuilder("powershell.exe",
|
||||
"-Command",
|
||||
String.join(" | ",
|
||||
getCimInstance + " -Class Win32_VideoController",
|
||||
"Select-Object Name,AdapterCompatibility,DriverVersion,AdapterDACType",
|
||||
"Format-List"
|
||||
))
|
||||
.redirectInput(nul)
|
||||
.redirectError(nul)
|
||||
.start();
|
||||
|
||||
CompletableFuture<String> future = CompletableFuture.supplyAsync(Lang.wrap(() ->
|
||||
IOUtils.readFullyAsString(finalProcess.getInputStream(), OperatingSystem.NATIVE_CHARSET)),
|
||||
Schedulers.io());
|
||||
|
||||
if (!process.waitFor(15, TimeUnit.SECONDS))
|
||||
throw new TimeoutException();
|
||||
|
||||
if (process.exitValue() != 0)
|
||||
throw new IOException("Bad exit code: " + process.exitValue());
|
||||
|
||||
list = future.get();
|
||||
|
||||
List<Map<String, String>> videoControllers = parsePowerShellFormatList(Arrays.asList(list.split("\\R")));
|
||||
ArrayList<GraphicsCard> cards = new ArrayList<>(videoControllers.size());
|
||||
for (Map<String, String> videoController : videoControllers) {
|
||||
String name = videoController.get("Name");
|
||||
String adapterCompatibility = videoController.get("AdapterCompatibility");
|
||||
String driverVersion = videoController.get("DriverVersion");
|
||||
String adapterDACType = videoController.get("AdapterDACType");
|
||||
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
cards.add(GraphicsCard.builder().setName(name)
|
||||
.setVendor(GraphicsCard.Vendor.of(adapterCompatibility))
|
||||
.setDriverVersion(driverVersion)
|
||||
.setType(StringUtils.isBlank(adapterDACType)
|
||||
|| "Internal".equalsIgnoreCase(adapterDACType)
|
||||
|| "InternalDAC".equalsIgnoreCase(adapterDACType)
|
||||
? GraphicsCard.Type.Integrated
|
||||
: GraphicsCard.Type.Discrete)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return cards;
|
||||
} catch (Throwable e) {
|
||||
if (process != null && process.isAlive())
|
||||
process.destroy();
|
||||
LOG.warning("Failed to get graphics card info" + (list != null ? ": " + list : ""), e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
690
HMCLCore/src/main/resources/assets/platform/amdgpu.ids
Normal file
690
HMCLCore/src/main/resources/assets/platform/amdgpu.ids
Normal file
@@ -0,0 +1,690 @@
|
||||
# https://gitlab.freedesktop.org/mesa/drm/-/blob/b65d6ede3ebe64dbde5805007ddef22f390f8050/data/amdgpu.ids
|
||||
#
|
||||
# List of AMDGPU IDs
|
||||
#
|
||||
# Syntax:
|
||||
# device_id, revision_id, product_name <-- single tab after comma
|
||||
|
||||
1.0.0
|
||||
1114, C2, AMD Radeon 860M Graphics
|
||||
1114, C3, AMD Radeon 840M Graphics
|
||||
1114, D2, AMD Radeon 860M Graphics
|
||||
1114, D3, AMD Radeon 840M Graphics
|
||||
1309, 00, AMD Radeon R7 Graphics
|
||||
130A, 00, AMD Radeon R6 Graphics
|
||||
130B, 00, AMD Radeon R4 Graphics
|
||||
130C, 00, AMD Radeon R7 Graphics
|
||||
130D, 00, AMD Radeon R6 Graphics
|
||||
130E, 00, AMD Radeon R5 Graphics
|
||||
130F, 00, AMD Radeon R7 Graphics
|
||||
130F, D4, AMD Radeon R7 Graphics
|
||||
130F, D5, AMD Radeon R7 Graphics
|
||||
130F, D6, AMD Radeon R7 Graphics
|
||||
130F, D7, AMD Radeon R7 Graphics
|
||||
1313, 00, AMD Radeon R7 Graphics
|
||||
1313, D4, AMD Radeon R7 Graphics
|
||||
1313, D5, AMD Radeon R7 Graphics
|
||||
1313, D6, AMD Radeon R7 Graphics
|
||||
1315, 00, AMD Radeon R5 Graphics
|
||||
1315, D4, AMD Radeon R5 Graphics
|
||||
1315, D5, AMD Radeon R5 Graphics
|
||||
1315, D6, AMD Radeon R5 Graphics
|
||||
1315, D7, AMD Radeon R5 Graphics
|
||||
1316, 00, AMD Radeon R5 Graphics
|
||||
1318, 00, AMD Radeon R5 Graphics
|
||||
131B, 00, AMD Radeon R4 Graphics
|
||||
131C, 00, AMD Radeon R7 Graphics
|
||||
131D, 00, AMD Radeon R6 Graphics
|
||||
1435, AE, AMD Custom GPU 0932
|
||||
1506, C1, AMD Radeon 610M
|
||||
1506, C2, AMD Radeon 610M
|
||||
1506, C3, AMD Radeon 610M
|
||||
1506, C4, AMD Radeon 610M
|
||||
150E, C1, AMD Radeon 890M Graphics
|
||||
150E, C4, AMD Radeon 890M Graphics
|
||||
150E, C5, AMD Radeon 890M Graphics
|
||||
150E, C6, AMD Radeon 890M Graphics
|
||||
150E, D1, AMD Radeon 890M Graphics
|
||||
150E, D2, AMD Radeon 890M Graphics
|
||||
150E, D3, AMD Radeon 890M Graphics
|
||||
1586, C1, Radeon 8060S Graphics
|
||||
1586, C2, Radeon 8050S Graphics
|
||||
1586, C4, Radeon 8050S Graphics
|
||||
1586, D1, Radeon 8060S Graphics
|
||||
1586, D2, Radeon 8050S Graphics
|
||||
1586, D4, Radeon 8050S Graphics
|
||||
1586, D5, Radeon 8040S Graphics
|
||||
15BF, 00, AMD Radeon 780M Graphics
|
||||
15BF, 01, AMD Radeon 760M Graphics
|
||||
15BF, 02, AMD Radeon 780M Graphics
|
||||
15BF, 03, AMD Radeon 760M Graphics
|
||||
15BF, C1, AMD Radeon 780M Graphics
|
||||
15BF, C2, AMD Radeon 780M Graphics
|
||||
15BF, C3, AMD Radeon 760M Graphics
|
||||
15BF, C4, AMD Radeon 780M Graphics
|
||||
15BF, C5, AMD Radeon 740M Graphics
|
||||
15BF, C6, AMD Radeon 780M Graphics
|
||||
15BF, C7, AMD Radeon 780M Graphics
|
||||
15BF, C8, AMD Radeon 760M Graphics
|
||||
15BF, C9, AMD Radeon 780M Graphics
|
||||
15BF, CA, AMD Radeon 740M Graphics
|
||||
15BF, CB, AMD Radeon 760M Graphics
|
||||
15BF, CC, AMD Radeon 740M Graphics
|
||||
15BF, CD, AMD Radeon 760M Graphics
|
||||
15BF, CF, AMD Radeon 780M Graphics
|
||||
15BF, D0, AMD Radeon 780M Graphics
|
||||
15BF, D1, AMD Radeon 780M Graphics
|
||||
15BF, D2, AMD Radeon 780M Graphics
|
||||
15BF, D3, AMD Radeon 780M Graphics
|
||||
15BF, D4, AMD Radeon 780M Graphics
|
||||
15BF, D5, AMD Radeon 760M Graphics
|
||||
15BF, D6, AMD Radeon 760M Graphics
|
||||
15BF, D7, AMD Radeon 780M Graphics
|
||||
15BF, D8, AMD Radeon 740M Graphics
|
||||
15BF, D9, AMD Radeon 780M Graphics
|
||||
15BF, DA, AMD Radeon 780M Graphics
|
||||
15BF, DB, AMD Radeon 760M Graphics
|
||||
15BF, DC, AMD Radeon 760M Graphics
|
||||
15BF, DD, AMD Radeon 780M Graphics
|
||||
15BF, DE, AMD Radeon 740M Graphics
|
||||
15BF, DF, AMD Radeon 760M Graphics
|
||||
15BF, F0, AMD Radeon 760M Graphics
|
||||
15C8, C1, AMD Radeon 740M Graphics
|
||||
15C8, C2, AMD Radeon 740M Graphics
|
||||
15C8, C3, AMD Radeon 740M Graphics
|
||||
15C8, C4, AMD Radeon 740M Graphics
|
||||
15C8, D1, AMD Radeon 740M Graphics
|
||||
15C8, D2, AMD Radeon 740M Graphics
|
||||
15C8, D3, AMD Radeon 740M Graphics
|
||||
15C8, D4, AMD Radeon 740M Graphics
|
||||
15D8, 00, AMD Radeon RX Vega 8 Graphics WS
|
||||
15D8, 91, AMD Radeon Vega 3 Graphics
|
||||
15D8, 91, AMD Ryzen Embedded R1606G with Radeon Vega Gfx
|
||||
15D8, 92, AMD Radeon Vega 3 Graphics
|
||||
15D8, 92, AMD Ryzen Embedded R1505G with Radeon Vega Gfx
|
||||
15D8, 93, AMD Radeon Vega 1 Graphics
|
||||
15D8, A1, AMD Radeon Vega 10 Graphics
|
||||
15D8, A2, AMD Radeon Vega 8 Graphics
|
||||
15D8, A3, AMD Radeon Vega 6 Graphics
|
||||
15D8, A4, AMD Radeon Vega 3 Graphics
|
||||
15D8, B1, AMD Radeon Vega 10 Graphics
|
||||
15D8, B2, AMD Radeon Vega 8 Graphics
|
||||
15D8, B3, AMD Radeon Vega 6 Graphics
|
||||
15D8, B4, AMD Radeon Vega 3 Graphics
|
||||
15D8, C1, AMD Radeon Vega 10 Graphics
|
||||
15D8, C2, AMD Radeon Vega 8 Graphics
|
||||
15D8, C3, AMD Radeon Vega 6 Graphics
|
||||
15D8, C4, AMD Radeon Vega 3 Graphics
|
||||
15D8, C5, AMD Radeon Vega 3 Graphics
|
||||
15D8, C8, AMD Radeon Vega 11 Graphics
|
||||
15D8, C9, AMD Radeon Vega 8 Graphics
|
||||
15D8, CA, AMD Radeon Vega 11 Graphics
|
||||
15D8, CB, AMD Radeon Vega 8 Graphics
|
||||
15D8, CC, AMD Radeon Vega 3 Graphics
|
||||
15D8, CE, AMD Radeon Vega 3 Graphics
|
||||
15D8, CF, AMD Ryzen Embedded R1305G with Radeon Vega Gfx
|
||||
15D8, D1, AMD Radeon Vega 10 Graphics
|
||||
15D8, D2, AMD Radeon Vega 8 Graphics
|
||||
15D8, D3, AMD Radeon Vega 6 Graphics
|
||||
15D8, D4, AMD Radeon Vega 3 Graphics
|
||||
15D8, D8, AMD Radeon Vega 11 Graphics
|
||||
15D8, D9, AMD Radeon Vega 8 Graphics
|
||||
15D8, DA, AMD Radeon Vega 11 Graphics
|
||||
15D8, DB, AMD Radeon Vega 3 Graphics
|
||||
15D8, DB, AMD Radeon Vega 8 Graphics
|
||||
15D8, DC, AMD Radeon Vega 3 Graphics
|
||||
15D8, DD, AMD Radeon Vega 3 Graphics
|
||||
15D8, DE, AMD Radeon Vega 3 Graphics
|
||||
15D8, DF, AMD Radeon Vega 3 Graphics
|
||||
15D8, E3, AMD Radeon Vega 3 Graphics
|
||||
15D8, E4, AMD Ryzen Embedded R1102G with Radeon Vega Gfx
|
||||
15DD, 81, AMD Ryzen Embedded V1807B with Radeon Vega Gfx
|
||||
15DD, 82, AMD Ryzen Embedded V1756B with Radeon Vega Gfx
|
||||
15DD, 83, AMD Ryzen Embedded V1605B with Radeon Vega Gfx
|
||||
15DD, 84, AMD Radeon Vega 6 Graphics
|
||||
15DD, 85, AMD Ryzen Embedded V1202B with Radeon Vega Gfx
|
||||
15DD, 86, AMD Radeon Vega 11 Graphics
|
||||
15DD, 88, AMD Radeon Vega 8 Graphics
|
||||
15DD, C1, AMD Radeon Vega 11 Graphics
|
||||
15DD, C2, AMD Radeon Vega 8 Graphics
|
||||
15DD, C3, AMD Radeon Vega 3 / 10 Graphics
|
||||
15DD, C4, AMD Radeon Vega 8 Graphics
|
||||
15DD, C5, AMD Radeon Vega 3 Graphics
|
||||
15DD, C6, AMD Radeon Vega 11 Graphics
|
||||
15DD, C8, AMD Radeon Vega 8 Graphics
|
||||
15DD, C9, AMD Radeon Vega 11 Graphics
|
||||
15DD, CA, AMD Radeon Vega 8 Graphics
|
||||
15DD, CB, AMD Radeon Vega 3 Graphics
|
||||
15DD, CC, AMD Radeon Vega 6 Graphics
|
||||
15DD, CE, AMD Radeon Vega 3 Graphics
|
||||
15DD, CF, AMD Radeon Vega 3 Graphics
|
||||
15DD, D0, AMD Radeon Vega 10 Graphics
|
||||
15DD, D1, AMD Radeon Vega 8 Graphics
|
||||
15DD, D3, AMD Radeon Vega 11 Graphics
|
||||
15DD, D5, AMD Radeon Vega 8 Graphics
|
||||
15DD, D6, AMD Radeon Vega 11 Graphics
|
||||
15DD, D7, AMD Radeon Vega 8 Graphics
|
||||
15DD, D8, AMD Radeon Vega 3 Graphics
|
||||
15DD, D9, AMD Radeon Vega 6 Graphics
|
||||
15DD, E1, AMD Radeon Vega 3 Graphics
|
||||
15DD, E2, AMD Radeon Vega 3 Graphics
|
||||
163F, AE, AMD Custom GPU 0405
|
||||
163F, E1, AMD Custom GPU 0405
|
||||
164E, D8, AMD Radeon 610M
|
||||
164E, D9, AMD Radeon 610M
|
||||
164E, DA, AMD Radeon 610M
|
||||
164E, DB, AMD Radeon 610M
|
||||
164E, DC, AMD Radeon 610M
|
||||
1681, 06, AMD Radeon 680M
|
||||
1681, 07, AMD Radeon 660M
|
||||
1681, 0A, AMD Radeon 680M
|
||||
1681, 0B, AMD Radeon 660M
|
||||
1681, C7, AMD Radeon 680M
|
||||
1681, C8, AMD Radeon 680M
|
||||
1681, C9, AMD Radeon 660M
|
||||
1900, 01, AMD Radeon 780M Graphics
|
||||
1900, 02, AMD Radeon 760M Graphics
|
||||
1900, 03, AMD Radeon 780M Graphics
|
||||
1900, 04, AMD Radeon 760M Graphics
|
||||
1900, 05, AMD Radeon 780M Graphics
|
||||
1900, 06, AMD Radeon 780M Graphics
|
||||
1900, 07, AMD Radeon 760M Graphics
|
||||
1900, B0, AMD Radeon 780M Graphics
|
||||
1900, B1, AMD Radeon 780M Graphics
|
||||
1900, B2, AMD Radeon 780M Graphics
|
||||
1900, B3, AMD Radeon 780M Graphics
|
||||
1900, B4, AMD Radeon 780M Graphics
|
||||
1900, B5, AMD Radeon 780M Graphics
|
||||
1900, B6, AMD Radeon 780M Graphics
|
||||
1900, B7, AMD Radeon 760M Graphics
|
||||
1900, B8, AMD Radeon 760M Graphics
|
||||
1900, B9, AMD Radeon 780M Graphics
|
||||
1900, BA, AMD Radeon 780M Graphics
|
||||
1900, BB, AMD Radeon 780M Graphics
|
||||
1900, C0, AMD Radeon 780M Graphics
|
||||
1900, C1, AMD Radeon 760M Graphics
|
||||
1900, C2, AMD Radeon 780M Graphics
|
||||
1900, C3, AMD Radeon 760M Graphics
|
||||
1900, C4, AMD Radeon 780M Graphics
|
||||
1900, C5, AMD Radeon 780M Graphics
|
||||
1900, C6, AMD Radeon 760M Graphics
|
||||
1900, C7, AMD Radeon 780M Graphics
|
||||
1900, C8, AMD Radeon 760M Graphics
|
||||
1900, C9, AMD Radeon 780M Graphics
|
||||
1900, CA, AMD Radeon 760M Graphics
|
||||
1900, CB, AMD Radeon 780M Graphics
|
||||
1900, CC, AMD Radeon 780M Graphics
|
||||
1900, CD, AMD Radeon 760M Graphics
|
||||
1900, CE, AMD Radeon 780M Graphics
|
||||
1900, CF, AMD Radeon 760M Graphics
|
||||
1900, D0, AMD Radeon 780M Graphics
|
||||
1900, D1, AMD Radeon 760M Graphics
|
||||
1900, D2, AMD Radeon 780M Graphics
|
||||
1900, D3, AMD Radeon 760M Graphics
|
||||
1900, D4, AMD Radeon 780M Graphics
|
||||
1900, D5, AMD Radeon 780M Graphics
|
||||
1900, D6, AMD Radeon 760M Graphics
|
||||
1900, D7, AMD Radeon 780M Graphics
|
||||
1900, D8, AMD Radeon 760M Graphics
|
||||
1900, D9, AMD Radeon 780M Graphics
|
||||
1900, DA, AMD Radeon 760M Graphics
|
||||
1900, DB, AMD Radeon 780M Graphics
|
||||
1900, DC, AMD Radeon 780M Graphics
|
||||
1900, DD, AMD Radeon 760M Graphics
|
||||
1900, DE, AMD Radeon 780M Graphics
|
||||
1900, DF, AMD Radeon 760M Graphics
|
||||
1900, F0, AMD Radeon 780M Graphics
|
||||
1900, F1, AMD Radeon 780M Graphics
|
||||
1900, F2, AMD Radeon 780M Graphics
|
||||
1901, C1, AMD Radeon 740M Graphics
|
||||
1901, C2, AMD Radeon 740M Graphics
|
||||
1901, C3, AMD Radeon 740M Graphics
|
||||
1901, C6, AMD Radeon 740M Graphics
|
||||
1901, C7, AMD Radeon 740M Graphics
|
||||
1901, C8, AMD Radeon 740M Graphics
|
||||
1901, C9, AMD Radeon 740M Graphics
|
||||
1901, CA, AMD Radeon 740M Graphics
|
||||
1901, D1, AMD Radeon 740M Graphics
|
||||
1901, D2, AMD Radeon 740M Graphics
|
||||
1901, D3, AMD Radeon 740M Graphics
|
||||
1901, D4, AMD Radeon 740M Graphics
|
||||
1901, D5, AMD Radeon 740M Graphics
|
||||
1901, D6, AMD Radeon 740M Graphics
|
||||
1901, D7, AMD Radeon 740M Graphics
|
||||
1901, D8, AMD Radeon 740M Graphics
|
||||
6600, 00, AMD Radeon HD 8600 / 8700M
|
||||
6600, 81, AMD Radeon R7 M370
|
||||
6601, 00, AMD Radeon HD 8500M / 8700M
|
||||
6604, 00, AMD Radeon R7 M265 Series
|
||||
6604, 81, AMD Radeon R7 M350
|
||||
6605, 00, AMD Radeon R7 M260 Series
|
||||
6605, 81, AMD Radeon R7 M340
|
||||
6606, 00, AMD Radeon HD 8790M
|
||||
6607, 00, AMD Radeon R5 M240
|
||||
6608, 00, AMD FirePro W2100
|
||||
6610, 00, AMD Radeon R7 200 Series
|
||||
6610, 81, AMD Radeon R7 350
|
||||
6610, 83, AMD Radeon R5 340
|
||||
6610, 87, AMD Radeon R7 200 Series
|
||||
6611, 00, AMD Radeon R7 200 Series
|
||||
6611, 87, AMD Radeon R7 200 Series
|
||||
6613, 00, AMD Radeon R7 200 Series
|
||||
6617, 00, AMD Radeon R7 240 Series
|
||||
6617, 87, AMD Radeon R7 200 Series
|
||||
6617, C7, AMD Radeon R7 240 Series
|
||||
6640, 00, AMD Radeon HD 8950
|
||||
6640, 80, AMD Radeon R9 M380
|
||||
6646, 00, AMD Radeon R9 M280X
|
||||
6646, 80, AMD Radeon R9 M385
|
||||
6646, 80, AMD Radeon R9 M470X
|
||||
6647, 00, AMD Radeon R9 M200X Series
|
||||
6647, 80, AMD Radeon R9 M380
|
||||
6649, 00, AMD FirePro W5100
|
||||
6658, 00, AMD Radeon R7 200 Series
|
||||
665C, 00, AMD Radeon HD 7700 Series
|
||||
665D, 00, AMD Radeon R7 200 Series
|
||||
665F, 81, AMD Radeon R7 360 Series
|
||||
6660, 00, AMD Radeon HD 8600M Series
|
||||
6660, 81, AMD Radeon R5 M335
|
||||
6660, 83, AMD Radeon R5 M330
|
||||
6663, 00, AMD Radeon HD 8500M Series
|
||||
6663, 83, AMD Radeon R5 M320
|
||||
6664, 00, AMD Radeon R5 M200 Series
|
||||
6665, 00, AMD Radeon R5 M230 Series
|
||||
6665, 83, AMD Radeon R5 M320
|
||||
6665, C3, AMD Radeon R5 M435
|
||||
6666, 00, AMD Radeon R5 M200 Series
|
||||
6667, 00, AMD Radeon R5 M200 Series
|
||||
666F, 00, AMD Radeon HD 8500M
|
||||
66A1, 02, AMD Instinct MI60 / MI50
|
||||
66A1, 06, AMD Radeon Pro VII
|
||||
66AF, C1, AMD Radeon VII
|
||||
6780, 00, AMD FirePro W9000
|
||||
6784, 00, ATI FirePro V (FireGL V) Graphics Adapter
|
||||
6788, 00, ATI FirePro V (FireGL V) Graphics Adapter
|
||||
678A, 00, AMD FirePro W8000
|
||||
6798, 00, AMD Radeon R9 200 / HD 7900 Series
|
||||
6799, 00, AMD Radeon HD 7900 Series
|
||||
679A, 00, AMD Radeon HD 7900 Series
|
||||
679B, 00, AMD Radeon HD 7900 Series
|
||||
679E, 00, AMD Radeon HD 7800 Series
|
||||
67A0, 00, AMD Radeon FirePro W9100
|
||||
67A1, 00, AMD Radeon FirePro W8100
|
||||
67B0, 00, AMD Radeon R9 200 Series
|
||||
67B0, 80, AMD Radeon R9 390 Series
|
||||
67B1, 00, AMD Radeon R9 200 Series
|
||||
67B1, 80, AMD Radeon R9 390 Series
|
||||
67B9, 00, AMD Radeon R9 200 Series
|
||||
67C0, 00, AMD Radeon Pro WX 7100 Graphics
|
||||
67C0, 80, AMD Radeon E9550
|
||||
67C2, 01, AMD Radeon Pro V7350x2
|
||||
67C2, 02, AMD Radeon Pro V7300X
|
||||
67C4, 00, AMD Radeon Pro WX 7100 Graphics
|
||||
67C4, 80, AMD Radeon E9560 / E9565 Graphics
|
||||
67C7, 00, AMD Radeon Pro WX 5100 Graphics
|
||||
67C7, 80, AMD Radeon E9390 Graphics
|
||||
67D0, 01, AMD Radeon Pro V7350x2
|
||||
67D0, 02, AMD Radeon Pro V7300X
|
||||
67DF, C0, AMD Radeon Pro 580X
|
||||
67DF, C1, AMD Radeon RX 580 Series
|
||||
67DF, C2, AMD Radeon RX 570 Series
|
||||
67DF, C3, AMD Radeon RX 580 Series
|
||||
67DF, C4, AMD Radeon RX 480 Graphics
|
||||
67DF, C5, AMD Radeon RX 470 Graphics
|
||||
67DF, C6, AMD Radeon RX 570 Series
|
||||
67DF, C7, AMD Radeon RX 480 Graphics
|
||||
67DF, CF, AMD Radeon RX 470 Graphics
|
||||
67DF, D7, AMD Radeon RX 470 Graphics
|
||||
67DF, E0, AMD Radeon RX 470 Series
|
||||
67DF, E1, AMD Radeon RX 590 Series
|
||||
67DF, E3, AMD Radeon RX Series
|
||||
67DF, E7, AMD Radeon RX 580 Series
|
||||
67DF, EB, AMD Radeon Pro 580X
|
||||
67DF, EF, AMD Radeon RX 570 Series
|
||||
67DF, F7, AMD Radeon RX P30PH
|
||||
67DF, FF, AMD Radeon RX 470 Series
|
||||
67E0, 00, AMD Radeon Pro WX Series
|
||||
67E3, 00, AMD Radeon Pro WX 4100
|
||||
67E8, 00, AMD Radeon Pro WX Series
|
||||
67E8, 01, AMD Radeon Pro WX Series
|
||||
67E8, 80, AMD Radeon E9260 Graphics
|
||||
67EB, 00, AMD Radeon Pro V5300X
|
||||
67EF, C0, AMD Radeon RX Graphics
|
||||
67EF, C1, AMD Radeon RX 460 Graphics
|
||||
67EF, C2, AMD Radeon Pro Series
|
||||
67EF, C3, AMD Radeon RX Series
|
||||
67EF, C5, AMD Radeon RX 460 Graphics
|
||||
67EF, C7, AMD Radeon RX Graphics
|
||||
67EF, CF, AMD Radeon RX 460 Graphics
|
||||
67EF, E0, AMD Radeon RX 560 Series
|
||||
67EF, E1, AMD Radeon RX Series
|
||||
67EF, E2, AMD Radeon RX 560X
|
||||
67EF, E3, AMD Radeon RX Series
|
||||
67EF, E5, AMD Radeon RX 560 Series
|
||||
67EF, E7, AMD Radeon RX 560 Series
|
||||
67EF, EF, AMD Radeon 550 Series
|
||||
67EF, FF, AMD Radeon RX 460 Graphics
|
||||
67FF, C0, AMD Radeon Pro 465
|
||||
67FF, C1, AMD Radeon RX 560 Series
|
||||
67FF, CF, AMD Radeon RX 560 Series
|
||||
67FF, EF, AMD Radeon RX 560 Series
|
||||
67FF, FF, AMD Radeon RX 550 Series
|
||||
6800, 00, AMD Radeon HD 7970M
|
||||
6801, 00, AMD Radeon HD 8970M
|
||||
6806, 00, AMD Radeon R9 M290X
|
||||
6808, 00, AMD FirePro W7000
|
||||
6808, 00, ATI FirePro V (FireGL V) Graphics Adapter
|
||||
6809, 00, ATI FirePro W5000
|
||||
6810, 00, AMD Radeon R9 200 Series
|
||||
6810, 81, AMD Radeon R9 370 Series
|
||||
6811, 00, AMD Radeon R9 200 Series
|
||||
6811, 81, AMD Radeon R7 370 Series
|
||||
6818, 00, AMD Radeon HD 7800 Series
|
||||
6819, 00, AMD Radeon HD 7800 Series
|
||||
6820, 00, AMD Radeon R9 M275X
|
||||
6820, 81, AMD Radeon R9 M375
|
||||
6820, 83, AMD Radeon R9 M375X
|
||||
6821, 00, AMD Radeon R9 M200X Series
|
||||
6821, 83, AMD Radeon R9 M370X
|
||||
6821, 87, AMD Radeon R7 M380
|
||||
6822, 00, AMD Radeon E8860
|
||||
6823, 00, AMD Radeon R9 M200X Series
|
||||
6825, 00, AMD Radeon HD 7800M Series
|
||||
6826, 00, AMD Radeon HD 7700M Series
|
||||
6827, 00, AMD Radeon HD 7800M Series
|
||||
6828, 00, AMD FirePro W600
|
||||
682B, 00, AMD Radeon HD 8800M Series
|
||||
682B, 87, AMD Radeon R9 M360
|
||||
682C, 00, AMD FirePro W4100
|
||||
682D, 00, AMD Radeon HD 7700M Series
|
||||
682F, 00, AMD Radeon HD 7700M Series
|
||||
6830, 00, AMD Radeon 7800M Series
|
||||
6831, 00, AMD Radeon 7700M Series
|
||||
6835, 00, AMD Radeon R7 Series / HD 9000 Series
|
||||
6837, 00, AMD Radeon HD 7700 Series
|
||||
683D, 00, AMD Radeon HD 7700 Series
|
||||
683F, 00, AMD Radeon HD 7700 Series
|
||||
684C, 00, ATI FirePro V (FireGL V) Graphics Adapter
|
||||
6860, 00, AMD Radeon Instinct MI25
|
||||
6860, 01, AMD Radeon Instinct MI25
|
||||
6860, 02, AMD Radeon Instinct MI25
|
||||
6860, 03, AMD Radeon Pro V340
|
||||
6860, 04, AMD Radeon Instinct MI25x2
|
||||
6860, 07, AMD Radeon Pro V320
|
||||
6861, 00, AMD Radeon Pro WX 9100
|
||||
6862, 00, AMD Radeon Pro SSG
|
||||
6863, 00, AMD Radeon Vega Frontier Edition
|
||||
6864, 03, AMD Radeon Pro V340
|
||||
6864, 04, AMD Radeon Instinct MI25x2
|
||||
6864, 05, AMD Radeon Pro V340
|
||||
6868, 00, AMD Radeon Pro WX 8200
|
||||
686C, 00, AMD Radeon Instinct MI25 MxGPU
|
||||
686C, 01, AMD Radeon Instinct MI25 MxGPU
|
||||
686C, 02, AMD Radeon Instinct MI25 MxGPU
|
||||
686C, 03, AMD Radeon Pro V340 MxGPU
|
||||
686C, 04, AMD Radeon Instinct MI25x2 MxGPU
|
||||
686C, 05, AMD Radeon Pro V340L MxGPU
|
||||
686C, 06, AMD Radeon Instinct MI25 MxGPU
|
||||
687F, 01, AMD Radeon RX Vega
|
||||
687F, C0, AMD Radeon RX Vega
|
||||
687F, C1, AMD Radeon RX Vega
|
||||
687F, C3, AMD Radeon RX Vega
|
||||
687F, C7, AMD Radeon RX Vega
|
||||
6900, 00, AMD Radeon R7 M260
|
||||
6900, 81, AMD Radeon R7 M360
|
||||
6900, 83, AMD Radeon R7 M340
|
||||
6900, C1, AMD Radeon R5 M465 Series
|
||||
6900, C3, AMD Radeon R5 M445 Series
|
||||
6900, D1, AMD Radeon 530 Series
|
||||
6900, D3, AMD Radeon 530 Series
|
||||
6901, 00, AMD Radeon R5 M255
|
||||
6902, 00, AMD Radeon Series
|
||||
6907, 00, AMD Radeon R5 M255
|
||||
6907, 87, AMD Radeon R5 M315
|
||||
6920, 00, AMD Radeon R9 M395X
|
||||
6920, 01, AMD Radeon R9 M390X
|
||||
6921, 00, AMD Radeon R9 M390X
|
||||
6929, 00, AMD FirePro S7150
|
||||
6929, 01, AMD FirePro S7100X
|
||||
692B, 00, AMD FirePro W7100
|
||||
6938, 00, AMD Radeon R9 200 Series
|
||||
6938, F0, AMD Radeon R9 200 Series
|
||||
6938, F1, AMD Radeon R9 380 Series
|
||||
6939, 00, AMD Radeon R9 200 Series
|
||||
6939, F0, AMD Radeon R9 200 Series
|
||||
6939, F1, AMD Radeon R9 380 Series
|
||||
694C, C0, AMD Radeon RX Vega M GH Graphics
|
||||
694E, C0, AMD Radeon RX Vega M GL Graphics
|
||||
6980, 00, AMD Radeon Pro WX 3100
|
||||
6981, 00, AMD Radeon Pro WX 3200 Series
|
||||
6981, 01, AMD Radeon Pro WX 3200 Series
|
||||
6981, 10, AMD Radeon Pro WX 3200 Series
|
||||
6985, 00, AMD Radeon Pro WX 3100
|
||||
6986, 00, AMD Radeon Pro WX 2100
|
||||
6987, 80, AMD Embedded Radeon E9171
|
||||
6987, C0, AMD Radeon 550X Series
|
||||
6987, C1, AMD Radeon RX 640
|
||||
6987, C3, AMD Radeon 540X Series
|
||||
6987, C7, AMD Radeon 540
|
||||
6995, 00, AMD Radeon Pro WX 2100
|
||||
6997, 00, AMD Radeon Pro WX 2100
|
||||
699F, 81, AMD Embedded Radeon E9170 Series
|
||||
699F, C0, AMD Radeon 500 Series
|
||||
699F, C1, AMD Radeon 540 Series
|
||||
699F, C3, AMD Radeon 500 Series
|
||||
699F, C7, AMD Radeon RX 550 / 550 Series
|
||||
699F, C9, AMD Radeon 540
|
||||
6FDF, E7, AMD Radeon RX 590 GME
|
||||
6FDF, EF, AMD Radeon RX 580 2048SP
|
||||
7300, C1, AMD FirePro S9300 x2
|
||||
7300, C8, AMD Radeon R9 Fury Series
|
||||
7300, C9, AMD Radeon Pro Duo
|
||||
7300, CA, AMD Radeon R9 Fury Series
|
||||
7300, CB, AMD Radeon R9 Fury Series
|
||||
7312, 00, AMD Radeon Pro W5700
|
||||
731E, C6, AMD Radeon RX 5700XTB
|
||||
731E, C7, AMD Radeon RX 5700B
|
||||
731F, C0, AMD Radeon RX 5700 XT 50th Anniversary
|
||||
731F, C1, AMD Radeon RX 5700 XT
|
||||
731F, C2, AMD Radeon RX 5600M
|
||||
731F, C3, AMD Radeon RX 5700M
|
||||
731F, C4, AMD Radeon RX 5700
|
||||
731F, C5, AMD Radeon RX 5700 XT
|
||||
731F, CA, AMD Radeon RX 5600 XT
|
||||
731F, CB, AMD Radeon RX 5600 OEM
|
||||
7340, C1, AMD Radeon RX 5500M
|
||||
7340, C3, AMD Radeon RX 5300M
|
||||
7340, C5, AMD Radeon RX 5500 XT
|
||||
7340, C7, AMD Radeon RX 5500
|
||||
7340, C9, AMD Radeon RX 5500XTB
|
||||
7340, CF, AMD Radeon RX 5300
|
||||
7341, 00, AMD Radeon Pro W5500
|
||||
7347, 00, AMD Radeon Pro W5500M
|
||||
7360, 41, AMD Radeon Pro 5600M
|
||||
7360, C3, AMD Radeon Pro V520
|
||||
7362, C1, AMD Radeon Pro V540
|
||||
7362, C3, AMD Radeon Pro V520
|
||||
738C, 01, AMD Instinct MI100
|
||||
73A1, 00, AMD Radeon Pro V620
|
||||
73A3, 00, AMD Radeon Pro W6800
|
||||
73A5, C0, AMD Radeon RX 6950 XT
|
||||
73AE, 00, AMD Radeon Pro V620 MxGPU
|
||||
73AF, C0, AMD Radeon RX 6900 XT
|
||||
73BF, C0, AMD Radeon RX 6900 XT
|
||||
73BF, C1, AMD Radeon RX 6800 XT
|
||||
73BF, C3, AMD Radeon RX 6800
|
||||
73DF, C0, AMD Radeon RX 6750 XT
|
||||
73DF, C1, AMD Radeon RX 6700 XT
|
||||
73DF, C2, AMD Radeon RX 6800M
|
||||
73DF, C3, AMD Radeon RX 6800M
|
||||
73DF, C5, AMD Radeon RX 6700 XT
|
||||
73DF, CF, AMD Radeon RX 6700M
|
||||
73DF, D5, AMD Radeon RX 6750 GRE 12GB
|
||||
73DF, D7, AMD TDC-235
|
||||
73DF, DF, AMD Radeon RX 6700
|
||||
73DF, E5, AMD Radeon RX 6750 GRE 12GB
|
||||
73DF, FF, AMD Radeon RX 6700
|
||||
73E0, 00, AMD Radeon RX 6600M
|
||||
73E1, 00, AMD Radeon Pro W6600M
|
||||
73E3, 00, AMD Radeon Pro W6600
|
||||
73EF, C0, AMD Radeon RX 6800S
|
||||
73EF, C1, AMD Radeon RX 6650 XT
|
||||
73EF, C2, AMD Radeon RX 6700S
|
||||
73EF, C3, AMD Radeon RX 6650M
|
||||
73EF, C4, AMD Radeon RX 6650M XT
|
||||
73FF, C1, AMD Radeon RX 6600 XT
|
||||
73FF, C3, AMD Radeon RX 6600M
|
||||
73FF, C7, AMD Radeon RX 6600
|
||||
73FF, CB, AMD Radeon RX 6600S
|
||||
73FF, CF, AMD Radeon RX 6600 LE
|
||||
73FF, DF, AMD Radeon RX 6750 GRE 10GB
|
||||
7408, 00, AMD Instinct MI250X
|
||||
740C, 01, AMD Instinct MI250X / MI250
|
||||
740F, 02, AMD Instinct MI210
|
||||
7421, 00, AMD Radeon Pro W6500M
|
||||
7422, 00, AMD Radeon Pro W6400
|
||||
7423, 00, AMD Radeon Pro W6300M
|
||||
7423, 01, AMD Radeon Pro W6300
|
||||
7424, 00, AMD Radeon RX 6300
|
||||
743F, C1, AMD Radeon RX 6500 XT
|
||||
743F, C3, AMD Radeon RX 6500
|
||||
743F, C3, AMD Radeon RX 6500M
|
||||
743F, C7, AMD Radeon RX 6400
|
||||
743F, C8, AMD Radeon RX 6500M
|
||||
743F, CC, AMD Radeon 6550S
|
||||
743F, CE, AMD Radeon RX 6450M
|
||||
743F, CF, AMD Radeon RX 6300M
|
||||
743F, D3, AMD Radeon RX 6550M
|
||||
743F, D7, AMD Radeon RX 6400
|
||||
7448, 00, AMD Radeon Pro W7900
|
||||
7449, 00, AMD Radeon Pro W7800 48GB
|
||||
744A, 00, AMD Radeon Pro W7900 Dual Slot
|
||||
744C, C8, AMD Radeon RX 7900 XTX
|
||||
744C, CC, AMD Radeon RX 7900 XT
|
||||
744C, CE, AMD Radeon RX 7900 GRE
|
||||
744C, CF, AMD Radeon RX 7900M
|
||||
745E, CC, AMD Radeon Pro W7800
|
||||
7460, 00, AMD Radeon Pro V710
|
||||
7461, 00, AMD Radeon Pro V710 MxGPU
|
||||
7470, 00, AMD Radeon Pro W7700
|
||||
747E, C8, AMD Radeon RX 7800 XT
|
||||
747E, D8, AMD Radeon RX 7800M
|
||||
747E, FF, AMD Radeon RX 7700 XT
|
||||
7480, 00, AMD Radeon Pro W7600
|
||||
7480, C0, AMD Radeon RX 7600 XT
|
||||
7480, C1, AMD Radeon RX 7700S
|
||||
7480, C2, AMD Radeon RX 7650 GRE
|
||||
7480, C3, AMD Radeon RX 7600S
|
||||
7480, C7, AMD Radeon RX 7600M XT
|
||||
7480, CF, AMD Radeon RX 7600
|
||||
7483, CF, AMD Radeon RX 7600M
|
||||
7489, 00, AMD Radeon Pro W7500
|
||||
7499, 00, AMD Radeon Pro W7400
|
||||
7499, C0, AMD Radeon RX 7400
|
||||
7499, C1, AMD Radeon RX 7300
|
||||
74A0, 00, AMD Instinct MI300A
|
||||
74A1, 00, AMD Instinct MI300X
|
||||
74A2, 00, AMD Instinct MI308X
|
||||
74A5, 00, AMD Instinct MI325X
|
||||
74A9, 00, AMD Instinct MI300X HF
|
||||
74B5, 00, AMD Instinct MI300X VF
|
||||
74B6, 00, AMD Instinct MI308X
|
||||
74BD, 00, AMD Instinct MI300X HF
|
||||
7550, C0, AMD Radeon RX 9070 XT
|
||||
7550, C3, AMD Radeon RX 9070
|
||||
9830, 00, AMD Radeon HD 8400 / R3 Series
|
||||
9831, 00, AMD Radeon HD 8400E
|
||||
9832, 00, AMD Radeon HD 8330
|
||||
9833, 00, AMD Radeon HD 8330E
|
||||
9834, 00, AMD Radeon HD 8210
|
||||
9835, 00, AMD Radeon HD 8210E
|
||||
9836, 00, AMD Radeon HD 8200 / R3 Series
|
||||
9837, 00, AMD Radeon HD 8280E
|
||||
9838, 00, AMD Radeon HD 8200 / R3 series
|
||||
9839, 00, AMD Radeon HD 8180
|
||||
983D, 00, AMD Radeon HD 8250
|
||||
9850, 00, AMD Radeon R3 Graphics
|
||||
9850, 03, AMD Radeon R3 Graphics
|
||||
9850, 40, AMD Radeon R2 Graphics
|
||||
9850, 45, AMD Radeon R3 Graphics
|
||||
9851, 00, AMD Radeon R4 Graphics
|
||||
9851, 01, AMD Radeon R5E Graphics
|
||||
9851, 05, AMD Radeon R5 Graphics
|
||||
9851, 06, AMD Radeon R5E Graphics
|
||||
9851, 40, AMD Radeon R4 Graphics
|
||||
9851, 45, AMD Radeon R5 Graphics
|
||||
9852, 00, AMD Radeon R2 Graphics
|
||||
9852, 40, AMD Radeon E1 Graphics
|
||||
9853, 00, AMD Radeon R2 Graphics
|
||||
9853, 01, AMD Radeon R4E Graphics
|
||||
9853, 03, AMD Radeon R2 Graphics
|
||||
9853, 05, AMD Radeon R1E Graphics
|
||||
9853, 06, AMD Radeon R1E Graphics
|
||||
9853, 07, AMD Radeon R1E Graphics
|
||||
9853, 08, AMD Radeon R1E Graphics
|
||||
9853, 40, AMD Radeon R2 Graphics
|
||||
9854, 00, AMD Radeon R3 Graphics
|
||||
9854, 01, AMD Radeon R3E Graphics
|
||||
9854, 02, AMD Radeon R3 Graphics
|
||||
9854, 05, AMD Radeon R2 Graphics
|
||||
9854, 06, AMD Radeon R4 Graphics
|
||||
9854, 07, AMD Radeon R3 Graphics
|
||||
9855, 02, AMD Radeon R6 Graphics
|
||||
9855, 05, AMD Radeon R4 Graphics
|
||||
9856, 00, AMD Radeon R2 Graphics
|
||||
9856, 01, AMD Radeon R2E Graphics
|
||||
9856, 02, AMD Radeon R2 Graphics
|
||||
9856, 05, AMD Radeon R1E Graphics
|
||||
9856, 06, AMD Radeon R2 Graphics
|
||||
9856, 07, AMD Radeon R1E Graphics
|
||||
9856, 08, AMD Radeon R1E Graphics
|
||||
9856, 13, AMD Radeon R1E Graphics
|
||||
9874, 81, AMD Radeon R6 Graphics
|
||||
9874, 84, AMD Radeon R7 Graphics
|
||||
9874, 85, AMD Radeon R6 Graphics
|
||||
9874, 87, AMD Radeon R5 Graphics
|
||||
9874, 88, AMD Radeon R7E Graphics
|
||||
9874, 89, AMD Radeon R6E Graphics
|
||||
9874, C4, AMD Radeon R7 Graphics
|
||||
9874, C5, AMD Radeon R6 Graphics
|
||||
9874, C6, AMD Radeon R6 Graphics
|
||||
9874, C7, AMD Radeon R5 Graphics
|
||||
9874, C8, AMD Radeon R7 Graphics
|
||||
9874, C9, AMD Radeon R7 Graphics
|
||||
9874, CA, AMD Radeon R5 Graphics
|
||||
9874, CB, AMD Radeon R5 Graphics
|
||||
9874, CC, AMD Radeon R7 Graphics
|
||||
9874, CD, AMD Radeon R7 Graphics
|
||||
9874, CE, AMD Radeon R5 Graphics
|
||||
9874, E1, AMD Radeon R7 Graphics
|
||||
9874, E2, AMD Radeon R7 Graphics
|
||||
9874, E3, AMD Radeon R7 Graphics
|
||||
9874, E4, AMD Radeon R7 Graphics
|
||||
9874, E5, AMD Radeon R5 Graphics
|
||||
9874, E6, AMD Radeon R5 Graphics
|
||||
98E4, 80, AMD Radeon R5E Graphics
|
||||
98E4, 81, AMD Radeon R4E Graphics
|
||||
98E4, 83, AMD Radeon R2E Graphics
|
||||
98E4, 84, AMD Radeon R2E Graphics
|
||||
98E4, 86, AMD Radeon R1E Graphics
|
||||
98E4, C0, AMD Radeon R4 Graphics
|
||||
98E4, C1, AMD Radeon R5 Graphics
|
||||
98E4, C2, AMD Radeon R4 Graphics
|
||||
98E4, C4, AMD Radeon R5 Graphics
|
||||
98E4, C6, AMD Radeon R5 Graphics
|
||||
98E4, C8, AMD Radeon R4 Graphics
|
||||
98E4, C9, AMD Radeon R4 Graphics
|
||||
98E4, CA, AMD Radeon R5 Graphics
|
||||
98E4, D0, AMD Radeon R2 Graphics
|
||||
98E4, D1, AMD Radeon R2 Graphics
|
||||
98E4, D2, AMD Radeon R2 Graphics
|
||||
98E4, D4, AMD Radeon R2 Graphics
|
||||
98E4, D9, AMD Radeon R5 Graphics
|
||||
98E4, DA, AMD Radeon R5 Graphics
|
||||
98E4, DB, AMD Radeon R3 Graphics
|
||||
98E4, E1, AMD Radeon R3 Graphics
|
||||
98E4, E2, AMD Radeon R3 Graphics
|
||||
98E4, E9, AMD Radeon R4 Graphics
|
||||
98E4, EA, AMD Radeon R4 Graphics
|
||||
98E4, EB, AMD Radeon R3 Graphics
|
||||
98E4, EB, AMD Radeon R4 Graphics
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.io;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
public final class CSVTableTest {
|
||||
|
||||
@Test
|
||||
public void testCreate() {
|
||||
CSVTable table = new CSVTable();
|
||||
|
||||
assertEquals(0, table.getColumnCount());
|
||||
assertEquals(0, table.getRowCount());
|
||||
|
||||
table.set(0, 0, "test1");
|
||||
assertEquals(1, table.getColumnCount());
|
||||
assertEquals(1, table.getRowCount());
|
||||
|
||||
table.set(4, 0, "test2");
|
||||
assertEquals(5, table.getColumnCount());
|
||||
assertEquals(1, table.getRowCount());
|
||||
|
||||
table.set(2, 1, "test3");
|
||||
assertEquals(5, table.getColumnCount());
|
||||
assertEquals(2, table.getRowCount());
|
||||
|
||||
assertEquals("test1", table.get(0, 0));
|
||||
assertEquals("", table.get(1, 0));
|
||||
assertEquals("", table.get(0, 1));
|
||||
assertEquals("test2", table.get(4, 0));
|
||||
assertEquals("test3", table.get(2, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() {
|
||||
CSVTable table = new CSVTable();
|
||||
table.set(0, 0, "a");
|
||||
table.set(1, 0, "b");
|
||||
table.set(3, 0, "c");
|
||||
table.set(0, 2, "a,b");
|
||||
table.set(1, 2, "c");
|
||||
table.set(3, 2, "d\"e\n");
|
||||
|
||||
assertEquals("a,b,,c\n,,,\n\"a,b\",c,,\"d\\\"e\\n\"\n", table.toString());
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user