Skip to content

Instantly share code, notes, and snippets.

@davidfoster
Last active May 22, 2020 05:14
Show Gist options
  • Save davidfoster/0ad08b490676e548c593dfdade3b725f to your computer and use it in GitHub Desktop.
Save davidfoster/0ad08b490676e548c593dfdade3b725f to your computer and use it in GitHub Desktop.
GPU Detection and Auto Quality Designation in Unity
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
[InitializeOnLoad]
#endif
public static class GpuDetection {
// N.B. type definitions are ordered above constants in this class because it makes more sense that way in this case.
//-----------------------------------------------------------------------------------------
// Type Definitions:
//-----------------------------------------------------------------------------------------
public enum Vendors {
Unknown,
Nvidia,
Amd
}
public enum Gpus {
Unknown,
NvidiaUnknown,
// Maxwell.
NvidiaGtx780, // #42, http://gpu.userbenchmark.com/Nvidia-GTX-780/Rating/2164
NvidiaGtx780M, // #83, http://gpu.userbenchmark.com/SpeedTest/7760/NVIDIA-GeForce-GTX-780M
NvidiaGtx780Ti, // #28, http://gpu.userbenchmark.com/Nvidia-GTX-780-Ti/Rating/2165
NvidiaGtx960, // #63, http://gpu.userbenchmark.com/Nvidia-GTX-960/Rating/3165
NvidiaGtx960M, // #128, http://gpu.userbenchmark.com/SpeedTest/27242/NVIDIA-GeForce-GTX-960M
NvidiaGtx965M, // #93, http://gpu.userbenchmark.com/SpeedTest/24481/NVIDIA-GeForce-GTX-965M
NvidiaGtx970, // #38, http://gpu.userbenchmark.com/Nvidia-GTX-970/Rating/2577
NvidiaGtx970M, // #67, http://gpu.userbenchmark.com/SpeedTest/17319/NVIDIA-GeForce-GTX-970M
NvidiaGtx980, // #26, http://gpu.userbenchmark.com/Nvidia-GTX-980/Rating/2576
NvidiaGtx980M, // #50, http://gpu.userbenchmark.com/SpeedTest/15596/NVIDIA-GeForce-GTX-980M
NvidiaGtx980Ti, // #16, http://gpu.userbenchmark.com/Nvidia-GTX-980-Ti/Rating/3439
NvidiaGtxTitan, // #41, http://gpu.userbenchmark.com/Nvidia-GTX-Titan/Rating/2191
NvidiaGtxTitanLe, // ?, https://pci-ids.ucw.cz/read/PC/10de
NvidiaGtxTitanBlack, // #31, http://gpu.userbenchmark.com/Nvidia-GTX-Titan-Black/Rating/3158
NvidiaGtxTitanX, // #17, http://gpu.userbenchmark.com/Nvidia-GTX-Titan-X/Rating/3282
NvidiaGtxTitanZ, // #33, http://gpu.userbenchmark.com/SpeedTest/17751/NVIDIA-GeForce-GTX-TITAN-Z
// Pascal.
NvidiaGtx1030, // #136, http://gpu.userbenchmark.com/SpeedTest/283726/NVIDIA-GeForce-GT-1030
NvidiaGtx1050, // #78, http://gpu.userbenchmark.com/Nvidia-GTX-1050/Rating/3650
NvidiaGtx10503Gb, // ?, https://pci-ids.ucw.cz/read/PC/10de
NvidiaGtx1050M, // #86, http://gpu.userbenchmark.com/SpeedTest/211022/NVIDIA-GeForce-GTX-1050
NvidiaGtx1050Ti, // #66, http://gpu.userbenchmark.com/Nvidia-GTX-1050-Ti/Rating/3649
NvidiaGtx1050TiM, // #72, http://gpu.userbenchmark.com/SpeedTest/223242/NVIDIA-GeForce-GTX-1050-Ti
NvidiaGtx1060, // #27, http://gpu.userbenchmark.com/Nvidia-GTX-1060-6GB/Rating/3639
NvidiaGtx10603Gb, // #35, http://gpu.userbenchmark.com/Nvidia-GTX-1060-3GB/Rating/3646
NvidiaGtx10605Gb, // ?, https://pci-ids.ucw.cz/read/PC/10de
NvidiaGtx1060M, // #45, http://gpu.userbenchmark.com/SpeedTest/164336/NVIDIA-GeForce-GTX-1060
NvidiaGtx1070, // #15, http://gpu.userbenchmark.com/Nvidia-GTX-1070/Rating/3609
NvidiaGtx1070M, // #21, http://gpu.userbenchmark.com/SpeedTest/164129/NVIDIA-GeForce-GTX-1070
NvidiaGtx1070Ti, // #11, http://gpu.userbenchmark.com/Nvidia-GTX-1070-Ti/Rating/3943
NvidiaGtx1080, // #8, http://gpu.userbenchmark.com/Nvidia-GTX-1080/Rating/3603
NvidiaGtx1080M, // #14, http://gpu.userbenchmark.com/SpeedTest/165564/NVIDIA-GeForce-GTX-1080
NvidiaGtx1080Ti, // #3, http://gpu.userbenchmark.com/Nvidia-GTX-1080-Ti/Rating/3918
NvidiaTitanX, // #5, http://gpu.userbenchmark.com/SpeedTest/158352/NVIDIA-TITAN-X-Pascal
NvidiaTitanXp, // #2, http://gpu.userbenchmark.com/SpeedTest/265423/NVIDIA-TITAN-Xp
NvidiaTitanV, // #1, http://gpu.userbenchmark.com/SpeedTest/395529/NVIDIA-TITAN-V
// Turing.
NvidiaGtx1180, // ?, https://pci-ids.ucw.cz/read/PC/10de
AmdUnknown,
// N.B. frustratingly AMD GPUs share PCI IDs, so we need to group them before teasing them apart.
AmdUnknownR9290Or390, // 0x67b1, https://pci-ids.ucw.cz/read/PC/1002
AmdUnknownR9290XOr390X, // 0x67b0, https://pci-ids.ucw.cz/read/PC/1002
AmdUnknownRx470Or480Or570Or580, // 0x67df, https://pci-ids.ucw.cz/read/PC/1002
AmdUnknownRx550Or560, // 0x67ff, https://pci-ids.ucw.cz/read/PC/1002
AmdUnknownR9FuryOrFuryXOrNano, // 0x7300, https://pci-ids.ucw.cz/read/PC/1002
AmdUnknownRxVega56Or64Or64Lc, // 0x687f, https://pci-ids.ucw.cz/read/PC/1002
AmdR9290, // #40, http://gpu.userbenchmark.com/AMD-R9-290/Rating/2171
AmdR9290X, // #32, http://gpu.userbenchmark.com/AMD-R9-290X/Rating/2166
AmdR9390, // #37, http://gpu.userbenchmark.com/AMD-R9-390/Rating/3481
AmdR9390X, // #29, http://gpu.userbenchmark.com/AMD-R9-390X/Rating/3497
AmdRx460, // #95, http://gpu.userbenchmark.com/AMD-RX-460/Rating/3641
AmdRx470, // #47, http://gpu.userbenchmark.com/AMD-RX-470/Rating/3640
AmdRx480, // #39, http://gpu.userbenchmark.com/AMD-RX-480/Rating/3634
AmdRx550, // #121, http://gpu.userbenchmark.com/AMD-RX-550/Rating/3925
AmdRx560, // #82, http://gpu.userbenchmark.com/AMD-RX-560/Rating/3926
AmdRx570, // #44, http://gpu.userbenchmark.com/AMD-RX-570/Rating/3924
AmdRx580, // #30, http://gpu.userbenchmark.com/AMD-RX-580/Rating/3923
AmdR9Nano, // #28, http://gpu.userbenchmark.com/SpeedTest/58413/AMD-Radeon-TM-R9-Fury
AmdR9Fury, // #24, http://gpu.userbenchmark.com/AMD-R9-Fury/Rating/3509
AmdR9FuryX, // #23, http://gpu.userbenchmark.com/AMD-R9-Fury-X/Rating/3498
AmdRxVegaMGl, // #73, http://gpu.userbenchmark.com/SpeedTest/453719/Radeon-RX-Vega-M-GL-Graphics
AmdRxVegaMGh, // #49, http://gpu.userbenchmark.com/SpeedTest/422266/Radeon-RX-Vega-M-GH-Graphics
AmdRxVega56, // #13, http://gpu.userbenchmark.com/AMD-RX-Vega-56/Rating/3938
AmdRxVegaFe, // #12, http://gpu.userbenchmark.com/AMD-Vega-Frontier-Edition/Rating/3929
AmdRxVega64, // #10, http://gpu.userbenchmark.com/AMD-RX-Vega-64/Rating/3933
AmdRxVega64Lc // #7, http://gpu.userbenchmark.com/SpeedTest/353890/Radeon-RX-Vega
}
//-----------------------------------------------------------------------------------------
// Constants:
//-----------------------------------------------------------------------------------------
private static readonly Dictionary<int, Vendors> VENDOR_IDS = new Dictionary<int, Vendors> {
{ 0x10de, Vendors.Nvidia },
{ 0x1002, Vendors.Amd },
};
// N.B. it is possible for the same device ID to be used by multiple vendors for different devices, so we must maintain each vendor's device IDs separately.
/// <remarks>List of NVIDIA PCI IDs: https://pci-ids.ucw.cz/read/PC/10de </remarks>
private static readonly Dictionary<int, Gpus> NVIDIA_GPU_IDS = new Dictionary<int, Gpus> {
{ 0xffff, Gpus.NvidiaUnknown },
// Maxwell.
{ 0x1004, Gpus.NvidiaGtx780 }, // #42, http://gpu.userbenchmark.com/Nvidia-GTX-780/Rating/2164
{ 0x1007, Gpus.NvidiaGtx780 }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x119e, Gpus.NvidiaGtx780M }, // #83, http://gpu.userbenchmark.com/SpeedTest/7760/NVIDIA-GeForce-GTX-780M
{ 0x119f, Gpus.NvidiaGtx780M }, // ^^
{ 0x100a, Gpus.NvidiaGtx780Ti }, // #28, http://gpu.userbenchmark.com/Nvidia-GTX-780-Ti/Rating/2165
{ 0x1008, Gpus.NvidiaGtx780Ti }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1401, Gpus.NvidiaGtx960 }, // #63, http://gpu.userbenchmark.com/Nvidia-GTX-960/Rating/3165
{ 0x1406, Gpus.NvidiaGtx960 }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x139b, Gpus.NvidiaGtx960M }, // #128, http://gpu.userbenchmark.com/SpeedTest/27242/NVIDIA-GeForce-GTX-960M
{ 0x13d9, Gpus.NvidiaGtx965M }, // #93, http://gpu.userbenchmark.com/SpeedTest/24481/NVIDIA-GeForce-GTX-965M
{ 0x1427, Gpus.NvidiaGtx965M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1619, Gpus.NvidiaGtx965M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1667, Gpus.NvidiaGtx965M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x13c2, Gpus.NvidiaGtx970 }, // #38, http://gpu.userbenchmark.com/Nvidia-GTX-970/Rating/2577
{ 0x13d8, Gpus.NvidiaGtx970M }, // #67, http://gpu.userbenchmark.com/SpeedTest/17319/NVIDIA-GeForce-GTX-970M
{ 0x1618, Gpus.NvidiaGtx970M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x13c0, Gpus.NvidiaGtx980 }, // #26, http://gpu.userbenchmark.com/Nvidia-GTX-980/Rating/2576
{ 0x13e7, Gpus.NvidiaGtx980 }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x13d7, Gpus.NvidiaGtx980M }, // #50, http://gpu.userbenchmark.com/SpeedTest/15596/NVIDIA-GeForce-GTX-980M
{ 0x13da, Gpus.NvidiaGtx980M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1617, Gpus.NvidiaGtx980M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x161a, Gpus.NvidiaGtx980M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x17c8, Gpus.NvidiaGtx980Ti }, // #16, http://gpu.userbenchmark.com/Nvidia-GTX-980-Ti/Rating/3439
{ 0x1005, Gpus.NvidiaGtxTitan }, // #41, http://gpu.userbenchmark.com/Nvidia-GTX-Titan/Rating/2191
{ 0x1003, Gpus.NvidiaGtxTitanLe }, // ? https://pci-ids.ucw.cz/read/PC/10de
{ 0x100c, Gpus.NvidiaGtxTitanBlack }, // #31, http://gpu.userbenchmark.com/Nvidia-GTX-Titan-Black/Rating/3158
{ 0x17c2, Gpus.NvidiaGtxTitanX }, // #17, http://gpu.userbenchmark.com/Nvidia-GTX-Titan-X/Rating/3282
{ 0x1001, Gpus.NvidiaGtxTitanZ }, // #33, http://gpu.userbenchmark.com/SpeedTest/17751/NVIDIA-GeForce-GTX-TITAN-Z
// Pascal.
{ 0x1d01, Gpus.NvidiaGtx1030 }, // #136, http://gpu.userbenchmark.com/SpeedTest/283726/NVIDIA-GeForce-GT-1030
{ 0x1c81, Gpus.NvidiaGtx1050 }, // #78, http://gpu.userbenchmark.com/Nvidia-GTX-1050/Rating/3650
{ 0x1c83, Gpus.NvidiaGtx10503Gb }, // ?, https://pci-ids.ucw.cz/read/PC/10de
{ 0x1c8d, Gpus.NvidiaGtx1050M }, // #86, http://gpu.userbenchmark.com/SpeedTest/211022/NVIDIA-GeForce-GTX-1050
{ 0x1c22, Gpus.NvidiaGtx1050M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1c62, Gpus.NvidiaGtx1050M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1c82, Gpus.NvidiaGtx1050Ti }, // #66, http://gpu.userbenchmark.com/Nvidia-GTX-1050-Ti/Rating/3649
{ 0x1c8f, Gpus.NvidiaGtx1050Ti }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1c8c, Gpus.NvidiaGtx1050TiM }, // #72, http://gpu.userbenchmark.com/SpeedTest/223242/NVIDIA-GeForce-GTX-1050-Ti
{ 0x1c21, Gpus.NvidiaGtx1050TiM }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1c61, Gpus.NvidiaGtx1050TiM }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1c03, Gpus.NvidiaGtx1060 }, // #27, http://gpu.userbenchmark.com/Nvidia-GTX-1060-6GB/Rating/3639
{ 0x1c06, Gpus.NvidiaGtx1060 }, // ^^
{ 0x1b83, Gpus.NvidiaGtx1060 }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1c02, Gpus.NvidiaGtx10603Gb }, // #35, http://gpu.userbenchmark.com/Nvidia-GTX-1060-3GB/Rating/3646
{ 0x1b84, Gpus.NvidiaGtx10603Gb }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1c04, Gpus.NvidiaGtx10605Gb }, // ?, https://pci-ids.ucw.cz/read/PC/10de
{ 0x1c20, Gpus.NvidiaGtx1060M }, // #45, http://gpu.userbenchmark.com/SpeedTest/164336/NVIDIA-GeForce-GTX-1060
{ 0x1c60, Gpus.NvidiaGtx1060M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1b81, Gpus.NvidiaGtx1070 }, // #15, http://gpu.userbenchmark.com/Nvidia-GTX-1070/Rating/3609
{ 0x1bad, Gpus.NvidiaGtx1070 }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1ba1, Gpus.NvidiaGtx1070M }, // #21, http://gpu.userbenchmark.com/SpeedTest/164129/NVIDIA-GeForce-GTX-1070
{ 0x1be1, Gpus.NvidiaGtx1070M }, // ^^
{ 0x1b82, Gpus.NvidiaGtx1070Ti }, // #11, http://gpu.userbenchmark.com/Nvidia-GTX-1070-Ti/Rating/3943
{ 0x1b80, Gpus.NvidiaGtx1080 }, // #8, http://gpu.userbenchmark.com/Nvidia-GTX-1080/Rating/3603
{ 0x1be0, Gpus.NvidiaGtx1080M }, // #14, http://gpu.userbenchmark.com/SpeedTest/165564/NVIDIA-GeForce-GTX-1080
{ 0x1ba0, Gpus.NvidiaGtx1080M }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1b06, Gpus.NvidiaGtx1080Ti }, // #3, http://gpu.userbenchmark.com/Nvidia-GTX-1080-Ti/Rating/3918
{ 0x1b01, Gpus.NvidiaGtx1080Ti }, // https://pci-ids.ucw.cz/read/PC/10de
{ 0x1b00, Gpus.NvidiaTitanX }, // #5, http://gpu.userbenchmark.com/SpeedTest/158352/NVIDIA-TITAN-X-Pascal
{ 0x1b02, Gpus.NvidiaTitanXp }, // #2, http://gpu.userbenchmark.com/SpeedTest/265423/NVIDIA-TITAN-Xp
{ 0x1d81, Gpus.NvidiaTitanV }, // #1, http://gpu.userbenchmark.com/SpeedTest/395529/NVIDIA-TITAN-V
// Turing.
{ 0x1e87, Gpus.NvidiaGtx1180 } // ?, https://pci-ids.ucw.cz/read/PC/10de
};
/// <remarks>List of AMD PCI IDs: https://pci-ids.ucw.cz/read/PC/1002 </remarks>
private static readonly Dictionary<int, Gpus> AMD_GPU_IDS = new Dictionary<int, Gpus> {
{ 0xffff, Gpus.AmdUnknown },
// N.B. frustratingly AMD GPUs share PCI IDs, so we need to group them before teasing them apart.
{ 0x67b1, Gpus.AmdUnknownR9290Or390 }, // https://pci-ids.ucw.cz/read/PC/1002
{ 0x67b0, Gpus.AmdUnknownR9290XOr390X }, // https://pci-ids.ucw.cz/read/PC/1002
{ 0x67df, Gpus.AmdUnknownRx470Or480Or570Or580 }, // https://pci-ids.ucw.cz/read/PC/1002
{ 0x67ff, Gpus.AmdUnknownRx550Or560 }, // https://pci-ids.ucw.cz/read/PC/1002
{ 0x7300, Gpus.AmdUnknownR9FuryOrFuryXOrNano }, // https://pci-ids.ucw.cz/read/PC/1002
{ 0x687f, Gpus.AmdUnknownRxVega56Or64Or64Lc }, // https://pci-ids.ucw.cz/read/PC/1002
{ 0x67ef, Gpus.AmdRx460 }, // #95, http://gpu.userbenchmark.com/AMD-RX-460/Rating/3641
{ 0x699f, Gpus.AmdRx550 }, // #121, https://pci-ids.ucw.cz/read/PC/1002
{ 0x694e, Gpus.AmdRxVegaMGl }, // #73, http://gpu.userbenchmark.com/SpeedTest/453719/Radeon-RX-Vega-M-GL-Graphics
{ 0x694c, Gpus.AmdRxVegaMGh }, // #49, http://gpu.userbenchmark.com/SpeedTest/422266/Radeon-RX-Vega-M-GH-Graphics
{ 0x6867, Gpus.AmdRxVega56 }, // #13, https://pci-ids.ucw.cz/read/PC/1002
{ 0x6863, Gpus.AmdRxVegaFe }, // #12, http://gpu.userbenchmark.com/AMD-Vega-Frontier-Edition/Rating/3929
};
private const string LOG_DETECTED_GPU_FORMAT = "GPU: {0}\nGPU Name: {1}\nVendor: {2}\nVendor Name: {3}";
private const string GPU_NAME_ID_REGEX_STRING = "[^a-z0-9]+";
//-----------------------------------------------------------------------------------------
// Public Properties:
//-----------------------------------------------------------------------------------------
public static Vendors Vendor { get; private set; }
public static int VendorId { get; private set; }
public static string VendorName { get; private set; }
public static Gpus Gpu { get; private set; }
public static int GpuId { get; private set; }
public static string GpuName { get; private set; }
public static bool IsNvidia { get { return (Vendor == Vendors.Nvidia); } }
public static bool IsAmd { get { return (Vendor == Vendors.Amd ); } }
public static bool IsMaxwell { get { return (Gpu > Gpus.NvidiaUnknown && Gpu <= Gpus.NvidiaGtxTitanZ); } }
public static bool IsPascal { get { return (Gpu >= Gpus.NvidiaGtx1030 && Gpu <= Gpus.NvidiaTitanV ); } }
public static bool IsTuring { get { return (Gpu >= Gpus.NvidiaGtx1180 && Gpu < Gpus.AmdUnknown ); } }
//-----------------------------------------------------------------------------------------
// Constructors:
//-----------------------------------------------------------------------------------------
static GpuDetection() {
// get the vendor from vendor ID.
VendorId = SystemInfo.graphicsDeviceVendorID;
VendorName = SystemInfo.graphicsDeviceVendor;
Vendors vendor;
if (!VENDOR_IDS.TryGetValue(VendorId, out vendor)) {
vendor = Vendors.Unknown;
}
Vendor = vendor;
// grab GPU device ID.
GpuId = SystemInfo.graphicsDeviceID;
GpuName = SystemInfo.graphicsDeviceName;
Gpus gpu = Gpus.Unknown;
// from the vendor, attempt to find the GPU from the associated device IDs, assigning unknown if we don't find it.
switch (Vendor) {
case Vendors.Nvidia:
// if we can't find a value for the NVIDIA GPU, use NvidiaUnknown.
if (!NVIDIA_GPU_IDS.TryGetValue(GpuId, out gpu)) {
gpu = Gpus.NvidiaUnknown;
}
break;
case Vendors.Amd:
// if we can't find a value for the AMD GPU, use AmdUnknown.
if (!AMD_GPU_IDS.TryGetValue(GpuId, out gpu)) {
gpu = Gpus.AmdUnknown;
}
// if we end up with an unknown AMD group, determine actual GPU.
if (gpu >= Gpus.AmdUnknownR9290Or390 && gpu <= Gpus.AmdUnknownRxVega56Or64Or64Lc) {
gpu = GetGpuByAmdUnknownGroup(gpu, GpuName);
}
break;
}
Gpu = gpu;
LogDetectedGpu();
}
public static void LogDetectedGpu() {
Debug.Log(string.Format(LOG_DETECTED_GPU_FORMAT, Gpu, GpuName, Vendor, VendorName));
}
public static Gpus GetGpuByAmdUnknownGroup(Gpus amdGpuGroup, string name) {
// throw invalid op if the given Gpus value is not an unknown AMD group or we don't have a name to deal with.
// N.B. we're fine dealing with empty strings for names, which is a conceivable situation.
if (amdGpuGroup < Gpus.AmdUnknownR9290Or390 || amdGpuGroup > Gpus.AmdUnknownRxVega56Or64Or64Lc || name == null)
throw new InvalidOperationException();
// to tease apart AMD GPUs which share PCI IDs, we have to query the name, so convert it into the most easily workable form, which
// is lower case with all whitespace and punctuation stripped out.
Regex replaceRegex = new Regex(GPU_NAME_ID_REGEX_STRING);
string gpuNameId = replaceRegex.Replace(name.ToLower(), string.Empty);
// switch over the group.
switch (amdGpuGroup) {
// N.B. there is a lot of string manipulation to detect AMD GPUs, so I will inline them all here because separating all of these
// out into constants would quickly become unwieldly.
// N.B. it is possible that GPU names contain every GPU in the group, for example, "Radeon RX 470/480/570/570X/580/580X", so, to
// deal with this, we make sure that each name contains only the specific ID we care about and no others, and if it does contain
// others, we default to the less performant one so that we're overly aggressive with our optimisations, resulting in better perf.
case Gpus.AmdUnknownR9290Or390: {
// if the name contains 390 and not 290, go with the 390, otherwise the 290.
return (gpuNameId.Contains("390") && !gpuNameId.Contains("290")) ? Gpus.AmdR9390 : Gpus.AmdR9290;
}
case Gpus.AmdUnknownR9290XOr390X: {
// if the name contains 390, go with the 390X, otherwise the 290X.
return (gpuNameId.Contains("390") && !gpuNameId.Contains("290")) ? Gpus.AmdR9390X : Gpus.AmdR9290X;
}
case Gpus.AmdUnknownRx470Or480Or570Or580: {
bool doesContain580 = gpuNameId.Contains("580");
bool doesContain570 = gpuNameId.Contains("570");
bool doesContain480 = gpuNameId.Contains("480");
bool doesContain470 = gpuNameId.Contains("470");
// handling the present of groups of three, go from 470 to 480 to 570 to 580.
if ( doesContain470 && doesContain480 && doesContain570 && !doesContain580) return Gpus.AmdRx470;
if ( doesContain470 && doesContain480 && !doesContain570 && doesContain580) return Gpus.AmdRx470;
if ( doesContain470 && !doesContain480 && doesContain570 && doesContain580) return Gpus.AmdRx470;
if (!doesContain470 && doesContain480 && doesContain570 && doesContain580) return Gpus.AmdRx480;
// N.B. the fact we're checking for groups of three, then two, then one, means there are many opportunities to optimise below
// conditions and remove redundant checks. However, it is very much unclear to the human brain how the preceding statements
// logically preclude others, so I'll leave them in, in full, to make it clearer that all conditions are handled.
// ReSharper disable ConditionIsAlwaysTrueOrFalse
// handling the presence of groups of two, go from 470 to 480 to 570 to 580.
if ( doesContain470 && doesContain480 && !doesContain570 && !doesContain580) return Gpus.AmdRx470;
if ( doesContain470 && !doesContain480 && doesContain570 && !doesContain580) return Gpus.AmdRx470;
if ( doesContain470 && !doesContain480 && !doesContain570 && doesContain580) return Gpus.AmdRx470;
if (!doesContain470 && doesContain480 && doesContain570 && !doesContain580) return Gpus.AmdRx480;
if (!doesContain470 && doesContain480 && !doesContain570 && doesContain580) return Gpus.AmdRx480;
if (!doesContain470 && !doesContain480 && doesContain570 && doesContain580) return Gpus.AmdRx570;
// handling exclusive presence of one, go in order from 580 to 570 to 480 to, otherwise, 470.
if (doesContain580 && !doesContain570 && !doesContain480 && !doesContain470) return Gpus.AmdRx580;
if (doesContain570 && !doesContain580 && !doesContain480 && !doesContain470) return Gpus.AmdRx570;
if (doesContain480 && !doesContain580 && !doesContain570 && !doesContain470) return Gpus.AmdRx480;
// ReSharper restore ConditionIsAlwaysTrueOrFalse
return Gpus.AmdRx470;
}
case Gpus.AmdUnknownRx550Or560: {
// if the name contains 560, go with the RX 560, otherwise the RX 550.
return (gpuNameId.Contains("560") && !gpuNameId.Contains("550")) ? Gpus.AmdRx560 : Gpus.AmdRx550;
}
case Gpus.AmdUnknownR9FuryOrFuryXOrNano: {
// N.B. in this example, Fury X already contains the word "Fury", so we have to get a bit creative.
const string furyId = "fury";
const string furyXId = furyId + "x";
const string nanoId = "nano";
bool doesContainFury = gpuNameId.Contains(furyId);
bool doesContainFuryX = gpuNameId.Contains(furyXId);
bool doesContainNano = gpuNameId.Contains(nanoId);
bool doesContainFuryAndFuryX = (doesContainFuryX && gpuNameId.Replace(furyXId, string.Empty).Contains(furyId));
bool doesContainAll = (doesContainFuryAndFuryX && doesContainNano);
// if it contains all, go with the worst, which is Nano.
if (doesContainAll) return Gpus.AmdR9Nano;
// if it contains Fury X but not also (a separate) Fury and Nano, it's Fury X.
if ( doesContainFuryX && !doesContainFuryAndFuryX && !doesContainNano) return Gpus.AmdR9FuryX;
// if it contains Fury but not Fury X, or both, but not Nano, it's Fury.
if (((doesContainFury && !doesContainFuryX) || doesContainFuryAndFuryX) && !doesContainNano) return Gpus.AmdR9Fury;
// and if all else fails, default to Nano, which is the least powerful.
return Gpus.AmdR9Nano;
}
case Gpus.AmdUnknownRxVega56Or64Or64Lc: {
// N.B. in this example, "64 LC" already contains "64", so we have to get a bit creative.
const string rxVega64Id = "64";
const string rxVega56Id = "56";
bool doesContainLc = gpuNameId.Contains("lc") || gpuNameId.Contains("liquid");
bool doesContain64 = gpuNameId.Contains(rxVega64Id);
bool doesContain56 = gpuNameId.Contains(rxVega56Id);
// N.B. because string.Replace replaces all instances, we need to use a custom ReplaceAll to delete only one of the "64" instances
// (the one used for 64 LC).
bool doesContain64LcAnd64 = (doesContainLc && ReplaceFirst(gpuNameId, rxVega64Id, string.Empty).Contains(rxVega64Id));
bool doesContainAll = (doesContain64LcAnd64 && doesContain56);
// if it contains all, go with the worst, which is 56.
if (doesContainAll) return Gpus.AmdRxVega56;
// if it contains LC but not also (a separate) 64 and 56, it's 64 LC.
if (doesContainLc && !doesContain64LcAnd64 && !doesContain56) return Gpus.AmdRxVega64Lc;
// if it contains 64 but not 64 LC, or both, but not 56, it's 64.
if (((doesContain64 && !doesContainLc) || doesContain64LcAnd64) && !doesContain56) return Gpus.AmdRxVega64;
// and if all else fails, default to 56, which is the least powerful.
return Gpus.AmdRxVega56;
}
}
// no dice, so just return unknown.
return Gpus.AmdUnknown;
}
//-----------------------------------------------------------------------------------------
// Private Methods:
//-----------------------------------------------------------------------------------------
/// <summary>
/// Replaces the first instance of <c>oldValue</c> with <c>newValue</c>.
/// </summary>
public static string ReplaceFirst(string @string, string oldValue, string newValue) {
int position = @string.IndexOf(oldValue, StringComparison.Ordinal);
if (position < 0) {
return @string;
}
return @string.Substring(0, position) + newValue + @string.Substring(position + oldValue.Length);
}
}
using System;
using NUnit.Framework;
public static class GpuDetectionTests {
//-----------------------------------------------------------------------------------------
// Tests:
//-----------------------------------------------------------------------------------------
[Test]
public static void GetGpuByAmdUnknownGroup_WithTooLowGpusValue_InvalidOps() {
Assert.Throws<InvalidOperationException>(() => GpuDetection.GetGpuByAmdUnknownGroup(EnumPrevOrLast(GpuDetection.Gpus.AmdUnknownR9290Or390), string.Empty));
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithFirstGpusValue_DoesNotInvalidOp() {
Assert.DoesNotThrow(() => GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, "AmdUnknownR9290Or390"));
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithTooHighGpusValue_InvalidOps() {
Assert.Throws<InvalidOperationException>(() => GpuDetection.GetGpuByAmdUnknownGroup(EnumNextOrFirst(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc), string.Empty));
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithLastGpusValue_DoesNotInvalidOp() {
Assert.DoesNotThrow(() => GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, "AmdUnknownR9290Or390"));
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithNullName_InvalidOps() {
Assert.Throws<InvalidOperationException>(() => GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, null));
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithEmptyName_DoesNotInvalidOp() {
Assert.DoesNotThrow(() => GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, string.Empty));
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290Or390GroupAnd290String_Returns290() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, "290") == GpuDetection.Gpus.AmdR9290);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290Or390GroupAnd390String_Returns390() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, "390") == GpuDetection.Gpus.AmdR9390);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290Or390GroupAnd290And390String_Returns290() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, "290 and 390") == GpuDetection.Gpus.AmdR9290);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290Or390GroupAndEmptyString_Returns290() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, string.Empty) == GpuDetection.Gpus.AmdR9290);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290Or390GroupAndPciIdName_Returns290() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, "Hawaii PRO [Radeon R9 290/390]") == GpuDetection.Gpus.AmdR9290);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290Or390GroupAndWhitespaceAndPunctuationString_Returns290() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, " $:@> >) $^% !_-=+") == GpuDetection.Gpus.AmdR9290);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290Or390GroupAndWhitespacePunctuationAnd390String_Returns390() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, "<:! %£( ) 390 @>(_+") == GpuDetection.Gpus.AmdR9390);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290Or390GroupAndWhitespaceBetweenAnd390String_Returns390() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290Or390, " 3 9 0 ") == GpuDetection.Gpus.AmdR9390);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290XOr390XGroupAnd290XString_Returns290X() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290XOr390X, "290 X") == GpuDetection.Gpus.AmdR9290X);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290XOr390XGroupAnd390XString_Returns390X() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290XOr390X, "390 X") == GpuDetection.Gpus.AmdR9390X);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290XOr390XGroupAnd290XAnd390XString_Returns290X() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290XOr390X, "290X/390X") == GpuDetection.Gpus.AmdR9290X);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290XOr390XGroupAndEmptyString_Returns290X() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290XOr390X, string.Empty) == GpuDetection.Gpus.AmdR9290X);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9290XOr390XGroupAndPciIdName_Returns290X() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9290XOr390X, "Hawaii XT / Grenada XT [Radeon R9 290X/390X]") == GpuDetection.Gpus.AmdR9290X);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd470String_Returns470() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "470") == GpuDetection.Gpus.AmdRx470);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd480String_Returns480() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "480") == GpuDetection.Gpus.AmdRx480);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd570String_Returns570() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "570") == GpuDetection.Gpus.AmdRx570);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd580String_Returns580() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "580") == GpuDetection.Gpus.AmdRx580);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd470And480String_Returns470() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "470/480") == GpuDetection.Gpus.AmdRx470);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd570And580String_Returns570() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "570 / 580") == GpuDetection.Gpus.AmdRx570);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd470And570String_Returns470() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "470 & 570") == GpuDetection.Gpus.AmdRx470);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd480And580String_Returns480() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "480 + 580") == GpuDetection.Gpus.AmdRx480);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd470480And570String_Returns470() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "470, 480, 570") == GpuDetection.Gpus.AmdRx470);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd470480And580String_Returns470() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "470 + 480 + 580") == GpuDetection.Gpus.AmdRx470);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd470570And580String_Returns470() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "470/570/580") == GpuDetection.Gpus.AmdRx470);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd480570And580String_Returns480() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "480 570 580") == GpuDetection.Gpus.AmdRx480);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAnd470480570And580String_Returns470() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "470/480 and 570/580") == GpuDetection.Gpus.AmdRx470);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAndEmptyString_Returns470() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, string.Empty) == GpuDetection.Gpus.AmdRx470);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx470Or480Or570Or580GroupAndPciIdName_Returns470() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx470Or480Or570Or580, "Ellesmere [Radeon RX 470/480/570/570X/580/580X]") == GpuDetection.Gpus.AmdRx470);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx550Or560GroupAnd550String_Returns550() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx550Or560, " 550 ") == GpuDetection.Gpus.AmdRx550);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx550Or560GroupAnd560String_Returns560() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx550Or560, "560") == GpuDetection.Gpus.AmdRx560);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx550Or560GroupAnd550And560String_Returns550() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx550Or560, "550 AND 560") == GpuDetection.Gpus.AmdRx550);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx550Or560GroupAndEmptyString_Returns550() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx550Or560, string.Empty) == GpuDetection.Gpus.AmdRx550);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithRx550Or560GroupAndPciIdName_Returns550() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRx550Or560, "Baffin [Radeon RX 550 640SP / RX 560/560X]") == GpuDetection.Gpus.AmdRx550);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9FuryOrFuryXOrNanoGroupAndNanoString_ReturnsNano() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9FuryOrFuryXOrNano, "Nano") == GpuDetection.Gpus.AmdR9Nano);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9FuryOrFuryXOrNanoGroupAndFuryString_ReturnsFury() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9FuryOrFuryXOrNano, "Fury") == GpuDetection.Gpus.AmdR9Fury);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9FuryOrFuryXOrNanoGroupAndFuryXString_ReturnsFuryX() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9FuryOrFuryXOrNano, "Fury (X)") == GpuDetection.Gpus.AmdR9FuryX);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9FuryOrFuryXOrNanoGroupAndNanoAndFuryString_ReturnsNano() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9FuryOrFuryXOrNano, "Nano / Fury") == GpuDetection.Gpus.AmdR9Nano);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9FuryOrFuryXOrNanoGroupAndFuryXAndNanoString_ReturnsNano() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9FuryOrFuryXOrNano, "FURY X & Nano") == GpuDetection.Gpus.AmdR9Nano);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9FuryOrFuryXOrNanoGroupAndFuryAndFuryXString_ReturnsFury() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9FuryOrFuryXOrNano, "Fury + Fury (X)!") == GpuDetection.Gpus.AmdR9Fury);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9FuryOrFuryXOrNanoGroupAndNanoAndFuryAndFuryXString_ReturnsNano() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9FuryOrFuryXOrNano, "Nano || FURY || FURY X") == GpuDetection.Gpus.AmdR9Nano);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9FuryOrFuryXOrNanoGroupAndEmptyString_ReturnsNano() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9FuryOrFuryXOrNano, string.Empty) == GpuDetection.Gpus.AmdR9Nano);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithR9FuryOrFuryXOrNanoGroupAndPciIdName_ReturnsNano() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownR9FuryOrFuryXOrNano, "Fiji [Radeon R9 FURY / NANO Series]") == GpuDetection.Gpus.AmdR9Nano);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithVega56Or64Or64LcGroupAnd56String_Returns56() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, "56") == GpuDetection.Gpus.AmdRxVega56);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithVega56Or64Or64LcGroupAnd64String_Returns64() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, "64") == GpuDetection.Gpus.AmdRxVega64);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithVega56Or64Or64LcGroupAnd64LcString_Returns64Lc() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, "64 LC") == GpuDetection.Gpus.AmdRxVega64Lc);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithVega56Or64Or64LcGroupAnd64LiquidCooledString_Returns64Lc() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, "64 (Liquid Cooled)") == GpuDetection.Gpus.AmdRxVega64Lc);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithVega56Or64Or64LcGroupAnd56And64String_Returns56() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, "56 / 64") == GpuDetection.Gpus.AmdRxVega56);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithVega56Or64Or64LcGroupAnd64LcAnd56String_Returns56() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, "56 & 64 (liquid-cooled)") == GpuDetection.Gpus.AmdRxVega56);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithVega56Or64Or64LcGroupAnd64And64LcString_Returns64() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, "64 + 64 (LC)!") == GpuDetection.Gpus.AmdRxVega64);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithVega56Or64Or64LcGroupAnd56And64And64LcString_Returns56() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, "56 \\ 64 \\ 64/lc") == GpuDetection.Gpus.AmdRxVega56);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithVega56Or64Or64LcGroupAndEmptyString_Returns56() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, string.Empty) == GpuDetection.Gpus.AmdRxVega56);
}
[Test]
public static void GetGpuByAmdUnknownGroup_WithVega56Or64Or64LcGroupAndPciIdName_Returns64() {
Assert.IsTrue(GpuDetection.GetGpuByAmdUnknownGroup(GpuDetection.Gpus.AmdUnknownRxVega56Or64Or64Lc, "Vega 10 XT [Radeon RX Vega 64]") == GpuDetection.Gpus.AmdRxVega64);
}
//-----------------------------------------------------------------------------------------
// Private Methods:
//-----------------------------------------------------------------------------------------
/// <summary>
/// Returns the next or first (if the current is the last) enumeration value.
/// </summary>
/// <typeparam name="TEnum">The generic enumeration type.</typeparam>
/// <remarks>The generic type name is <c>TEnum</c> to emphasise that it should be (but could conceivably not be) an enum.</remarks>
/// <remarks>The generic type constaints <c>IConvertible</c>, <c>IComparable</c>, <c>IFormattable</c> are all the interfaces which Enum implements, making it
/// less likely that this method is available to extend other types.</remarks>
private static TEnum EnumNextOrFirst<TEnum>(TEnum @enum) where TEnum : struct, IConvertible, IComparable, IFormattable {
CheckIsEnum<TEnum>();
// convert the possible enum values into an array of values and chose the next or first.
TEnum[] array = (TEnum[])Enum.GetValues(@enum.GetType());
int i = Array.IndexOf(array, @enum) + 1;
return (i == array.Length) ? array[0] : array[i];
}
/// <summary>
/// Returns the previous or last (if the current is the first) enumeration value.
/// </summary>
/// <typeparam name="TEnum">The generic enumeration type.</typeparam>
/// <remarks>The generic type name is <c>TEnum</c> to emphasise that it should be (but could conceivably not be) an enum.</remarks>
/// <remarks>The generic type constaints <c>IConvertible</c>, <c>IComparable</c>, <c>IFormattable</c> are all the interfaces which Enum implements, making it
/// less likely that this method is available to extend other types.</remarks>
private static TEnum EnumPrevOrLast<TEnum>(TEnum @enum) where TEnum : struct, IConvertible, IComparable, IFormattable {
CheckIsEnum<TEnum>();
// convert the possible enum values into an array of values and chose the previous or last.
TEnum[] array = (TEnum[])Enum.GetValues(@enum.GetType());
int i = Array.IndexOf(array, @enum) - 1;
return (i == -1) ? array[array.Length - 1] : array[i];
}
/// <summary>
/// Because we can't constrain on where TEnum : Enum, we have to check for accidental misuse.
/// </summary>
/// <typeparam name="TEnum">The type to check whether it is an enum.</typeparam>
private static void CheckIsEnum<TEnum>() {
if (!typeof(TEnum).IsEnum) {
throw new NotSupportedException(string.Format("Argument {0} is not an Enum.", typeof(TEnum).FullName));
}
}
}
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
[InitializeOnLoad]
#endif
public static class QualityDesignation {
//-----------------------------------------------------------------------------------------
// Constants:
//-----------------------------------------------------------------------------------------
private static readonly Dictionary<GpuDetection.Gpus, Designations> DESIGNATIONS = new Dictionary<GpuDetection.Gpus, Designations> {
{ GpuDetection.Gpus.Unknown, Designations.Default },
{ GpuDetection.Gpus.NvidiaUnknown, Designations.Default },
// Maxwell.
{ GpuDetection.Gpus.NvidiaGtx780, Designations.VeryLow }, // #42, http://gpu.userbenchmark.com/Nvidia-GTX-780/Rating/2164
{ GpuDetection.Gpus.NvidiaGtx780M, Designations.VeryLow }, // #83, http://gpu.userbenchmark.com/SpeedTest/7760/NVIDIA-GeForce-GTX-780M
{ GpuDetection.Gpus.NvidiaGtx780Ti, Designations.VeryLow }, // #28, http://gpu.userbenchmark.com/Nvidia-GTX-780-Ti/Rating/2165
{ GpuDetection.Gpus.NvidiaGtx960, Designations.VeryLow }, // #63, http://gpu.userbenchmark.com/Nvidia-GTX-960/Rating/3165
{ GpuDetection.Gpus.NvidiaGtx960M, Designations.VeryLow }, // #128, http://gpu.userbenchmark.com/SpeedTest/27242/NVIDIA-GeForce-GTX-960M
{ GpuDetection.Gpus.NvidiaGtx965M, Designations.VeryLow }, // #93, http://gpu.userbenchmark.com/SpeedTest/24481/NVIDIA-GeForce-GTX-965M
{ GpuDetection.Gpus.NvidiaGtx970, Designations.VeryLow }, // #38, http://gpu.userbenchmark.com/Nvidia-GTX-970/Rating/2577
{ GpuDetection.Gpus.NvidiaGtx970M, Designations.VeryLow }, // #67, http://gpu.userbenchmark.com/SpeedTest/17319/NVIDIA-GeForce-GTX-970M
{ GpuDetection.Gpus.NvidiaGtx980, Designations.Low }, // #26, http://gpu.userbenchmark.com/Nvidia-GTX-980/Rating/2576
{ GpuDetection.Gpus.NvidiaGtx980M, Designations.VeryLow }, // #50, http://gpu.userbenchmark.com/SpeedTest/15596/NVIDIA-GeForce-GTX-980M
{ GpuDetection.Gpus.NvidiaGtx980Ti, Designations.Default }, // #16, http://gpu.userbenchmark.com/Nvidia-GTX-980-Ti/Rating/3439
{ GpuDetection.Gpus.NvidiaGtxTitan, Designations.VeryLow }, // #41, http://gpu.userbenchmark.com/Nvidia-GTX-Titan/Rating/2191
{ GpuDetection.Gpus.NvidiaGtxTitanLe, Designations.VeryLow }, // ?, https://pci-ids.ucw.cz/read/PC/10de
{ GpuDetection.Gpus.NvidiaGtxTitanBlack, Designations.Low }, // #31, http://gpu.userbenchmark.com/Nvidia-GTX-Titan-Black/Rating/3158
{ GpuDetection.Gpus.NvidiaGtxTitanX, Designations.Default }, // #17, http://gpu.userbenchmark.com/Nvidia-GTX-Titan-X/Rating/3282
{ GpuDetection.Gpus.NvidiaGtxTitanZ, Designations.Low }, // #33, http://gpu.userbenchmark.com/SpeedTest/17751/NVIDIA-GeForce-GTX-TITAN-Z
// Pascal.
{ GpuDetection.Gpus.NvidiaGtx1030, Designations.VeryLow }, // #136, http://gpu.userbenchmark.com/SpeedTest/283726/NVIDIA-GeForce-GT-1030
{ GpuDetection.Gpus.NvidiaGtx1050, Designations.VeryLow }, // #78, http://gpu.userbenchmark.com/Nvidia-GTX-1050/Rating/3650
{ GpuDetection.Gpus.NvidiaGtx10503Gb, Designations.VeryLow }, // ?, https://pci-ids.ucw.cz/read/PC/10de
{ GpuDetection.Gpus.NvidiaGtx1050M, Designations.VeryLow }, // #86, http://gpu.userbenchmark.com/SpeedTest/211022/NVIDIA-GeForce-GTX-1050
{ GpuDetection.Gpus.NvidiaGtx1050Ti, Designations.VeryLow }, // #66, http://gpu.userbenchmark.com/Nvidia-GTX-1050-Ti/Rating/3649
{ GpuDetection.Gpus.NvidiaGtx1050TiM, Designations.VeryLow }, // #72, http://gpu.userbenchmark.com/SpeedTest/223242/NVIDIA-GeForce-GTX-1050-Ti
{ GpuDetection.Gpus.NvidiaGtx1060, Designations.Low }, // #27, http://gpu.userbenchmark.com/Nvidia-GTX-1060-6GB/Rating/3639
{ GpuDetection.Gpus.NvidiaGtx10603Gb, Designations.Low }, // #35, http://gpu.userbenchmark.com/Nvidia-GTX-1060-3GB/Rating/3646
{ GpuDetection.Gpus.NvidiaGtx10605Gb, Designations.Low }, // ?, https://pci-ids.ucw.cz/read/PC/10de
{ GpuDetection.Gpus.NvidiaGtx1060M, Designations.VeryLow }, // #45, http://gpu.userbenchmark.com/SpeedTest/164336/NVIDIA-GeForce-GTX-1060
{ GpuDetection.Gpus.NvidiaGtx1070, Designations.Default }, // #15, http://gpu.userbenchmark.com/Nvidia-GTX-1070/Rating/3609
{ GpuDetection.Gpus.NvidiaGtx1070M, Designations.Default }, // #21, http://gpu.userbenchmark.com/SpeedTest/164129/NVIDIA-GeForce-GTX-1070
{ GpuDetection.Gpus.NvidiaGtx1070Ti, Designations.High }, // #11, http://gpu.userbenchmark.com/Nvidia-GTX-1070-Ti/Rating/3943
{ GpuDetection.Gpus.NvidiaGtx1080, Designations.High }, // #8, http://gpu.userbenchmark.com/Nvidia-GTX-1080/Rating/3603
{ GpuDetection.Gpus.NvidiaGtx1080M, Designations.Default }, // #14, http://gpu.userbenchmark.com/SpeedTest/165564/NVIDIA-GeForce-GTX-1080
{ GpuDetection.Gpus.NvidiaGtx1080Ti, Designations.High }, // #3, http://gpu.userbenchmark.com/Nvidia-GTX-1080-Ti/Rating/3918
{ GpuDetection.Gpus.NvidiaTitanX, Designations.High }, // #5, http://gpu.userbenchmark.com/SpeedTest/158352/NVIDIA-TITAN-X-Pascal
{ GpuDetection.Gpus.NvidiaTitanXp, Designations.High }, // #2, http://gpu.userbenchmark.com/SpeedTest/265423/NVIDIA-TITAN-Xp
{ GpuDetection.Gpus.NvidiaTitanV, Designations.High }, // #1, http://gpu.userbenchmark.com/SpeedTest/395529/NVIDIA-TITAN-V
// Turing.
{ GpuDetection.Gpus.NvidiaGtx1180, Designations.High }, // ?, https://pci-ids.ucw.cz/read/PC/10de
{ GpuDetection.Gpus.AmdUnknown, Designations.Default },
{ GpuDetection.Gpus.AmdR9290, Designations.VeryLow }, // #40, http://gpu.userbenchmark.com/AMD-R9-290/Rating/2171
{ GpuDetection.Gpus.AmdR9290X, Designations.VeryLow }, // #32, http://gpu.userbenchmark.com/AMD-R9-290X/Rating/2166
{ GpuDetection.Gpus.AmdR9390, Designations.VeryLow }, // #37, http://gpu.userbenchmark.com/AMD-R9-390/Rating/3481
{ GpuDetection.Gpus.AmdR9390X, Designations.Low }, // #29, http://gpu.userbenchmark.com/AMD-R9-390X/Rating/3497
{ GpuDetection.Gpus.AmdRx460, Designations.VeryLow }, // #95, http://gpu.userbenchmark.com/AMD-RX-460/Rating/3641
{ GpuDetection.Gpus.AmdRx470, Designations.VeryLow }, // #47, http://gpu.userbenchmark.com/AMD-RX-470/Rating/3640
{ GpuDetection.Gpus.AmdRx480, Designations.VeryLow }, // #39, http://gpu.userbenchmark.com/AMD-RX-480/Rating/3634
{ GpuDetection.Gpus.AmdRx550, Designations.VeryLow }, // #121, http://gpu.userbenchmark.com/AMD-RX-550/Rating/3925
{ GpuDetection.Gpus.AmdRx560, Designations.VeryLow }, // #82, http://gpu.userbenchmark.com/AMD-RX-560/Rating/
{ GpuDetection.Gpus.AmdRx570, Designations.VeryLow }, // #44, http://gpu.userbenchmark.com/AMD-RX-570/Rating/3924
{ GpuDetection.Gpus.AmdRx580, Designations.Low }, // #30, http://gpu.userbenchmark.com/AMD-RX-580/Rating/3923
{ GpuDetection.Gpus.AmdR9Nano, Designations.Low }, // #28, http://gpu.userbenchmark.com/SpeedTest/58413/AMD-Radeon-TM-R9-Fury
{ GpuDetection.Gpus.AmdR9Fury, Designations.Low }, // #24, http://gpu.userbenchmark.com/AMD-R9-Fury/Rating/3509
{ GpuDetection.Gpus.AmdR9FuryX, Designations.Default }, // #23, http://gpu.userbenchmark.com/AMD-R9-Fury-X/Rating/3498
{ GpuDetection.Gpus.AmdRxVegaMGl, Designations.VeryLow }, // #73, http://gpu.userbenchmark.com/SpeedTest/453719/Radeon-RX-Vega-M-GL-Graphics
{ GpuDetection.Gpus.AmdRxVegaMGh, Designations.VeryLow }, // #49, http://gpu.userbenchmark.com/SpeedTest/422266/Radeon-RX-Vega-M-GH-Graphics
{ GpuDetection.Gpus.AmdRxVega56, Designations.High }, // #13, http://gpu.userbenchmark.com/AMD-RX-Vega-56/Rating/3938
{ GpuDetection.Gpus.AmdRxVegaFe, Designations.High }, // #12, http://gpu.userbenchmark.com/AMD-Vega-Frontier-Edition/Rating/3929
{ GpuDetection.Gpus.AmdRxVega64, Designations.High }, // #10, http://gpu.userbenchmark.com/AMD-RX-Vega-64/Rating/3933
{ GpuDetection.Gpus.AmdRxVega64Lc, Designations.High }, // #7, http://gpu.userbenchmark.com/SpeedTest/353890/Radeon-RX-Vega
};
private const string LOG_DESIGNATION_FORMAT = "Quality Designation: {0}";
//-----------------------------------------------------------------------------------------
// Type Definitions:
//-----------------------------------------------------------------------------------------
public enum Designations {
Undetermined = -1,
Default,
VeryLow,
Low,
High
}
//-----------------------------------------------------------------------------------------
// Private Fields:
//-----------------------------------------------------------------------------------------
private static Designations _designation = Designations.Undetermined;
//-----------------------------------------------------------------------------------------
// Public Properties:
//-----------------------------------------------------------------------------------------
public static Designations Designation {
get {
// return the designation if it has already been determined.
if (_designation != Designations.Undetermined) return _designation;
// try to determine quality from detected GPU, ensuring we set to Default if we don't find a designation.
if (!DESIGNATIONS.TryGetValue(GpuDetection.Gpu, out _designation)) {
_designation = Designations.Default;
}
return _designation;
}
}
//-----------------------------------------------------------------------------------------
// Constructors:
//-----------------------------------------------------------------------------------------
static QualityDesignation() {
LogDesignation();
}
//-----------------------------------------------------------------------------------------
// Public Methods:
//-----------------------------------------------------------------------------------------
public static void LogDesignation() {
Debug.Log(string.Format(LOG_DESIGNATION_FORMAT, Designation));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment