using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; using ADOFAIRenderer.Util.FFmpeg; using MelonLoader; namespace ADOFAIRenderer.Util { [SuppressMessage("ReSharper", "InconsistentNaming")] public enum GPUVendor { Unknown, NVIDIA, AMD, Intel } public static class GPUUtil { private const string NvidiaPattern = @"^NVIDIA GeForce [RG]TX [0-9]+(?> SUPER| Ti(?> SUPER)?)?(?> [0-9]+GB)?(?> Laptop GPU)?/PCIe/SSE2$"; private const string IntelPattern = @"^Intel(?>\(R\))? (?>U?HD Graphics [0-9]+$|Arc\(TM\) [A-C][0-9]+ Graphics)$"; // ReSharper disable once InconsistentNaming private const string AMDPattern = @"^AMD Radeon RX [0-9]+(?> XT)?$"; private static readonly Dictionary> CodecMap = new() { [Codec.H264] = new List<(GPUVendor, string)> { (GPUVendor.NVIDIA, "h264_nvenc"), (GPUVendor.Intel, "h264_qsv"), (GPUVendor.AMD, "h264_amf"), (GPUVendor.Unknown, "libx264") }, [Codec.H265] = new List<(GPUVendor, string)> { (GPUVendor.NVIDIA, "hevc_nvenc"), (GPUVendor.Intel, "hevc_qsv"), (GPUVendor.AMD, "hevc_amf"), (GPUVendor.Unknown, "libx265") }, [Codec.VP9] = new List<(GPUVendor, string)> { (GPUVendor.NVIDIA, "vp9_nvenc"), (GPUVendor.Intel, "vp9_qsv"), (GPUVendor.Unknown, "libvpx-vp9") }, [Codec.AV1] = new List<(GPUVendor, string)> { (GPUVendor.NVIDIA, "av1_nvenc"), (GPUVendor.Intel, "av1_qsv"), (GPUVendor.AMD, "av1_amf"), (GPUVendor.Unknown, "libsvtav1"), (GPUVendor.Unknown, "libaom-av1") }, [Codec.VVC] = new List<(GPUVendor, string)> { (GPUVendor.Unknown, "libvvenc") } }; private static GPUVendor _cachedVendor = GPUVendor.Unknown; private static bool _hasCachedVendor = false; private static GPUVendor GetActiveGPUVendor() { if (_hasCachedVendor) return _cachedVendor; var gpuName = UnityEngine.SystemInfo.graphicsDeviceName; Melon.Logger.Msg($"Active GPU: {gpuName}"); _cachedVendor = GPUVendor.Unknown; foreach (Match unused in Regex.Matches(gpuName, NvidiaPattern)) { _cachedVendor = GPUVendor.NVIDIA; break; } if (_cachedVendor == GPUVendor.Unknown) { foreach (Match unused in Regex.Matches(gpuName, IntelPattern)) { _cachedVendor = GPUVendor.Intel; break; } } if (_cachedVendor == GPUVendor.Unknown) { foreach (Match unused in Regex.Matches(gpuName, AMDPattern)) { _cachedVendor = GPUVendor.AMD; break; } } _hasCachedVendor = true; return _cachedVendor; } public static List GetPrioritizedEncoderCandidates(Codec codec) { if (!CodecMap.TryGetValue(codec, out var list)) return new List(); var vendor = GetActiveGPUVendor(); var prioritized = new List(); var others = new List(); foreach (var item in list) { if (item.Item1 == vendor) prioritized.Add(item.Item2); else others.Add(item.Item2); } prioritized.AddRange(others); return prioritized; } } }