using System; using System.Collections.Generic; using Microsoft.Win32; namespace ParsecDisplay.Vdd { internal static class Utils { /// /// Get list of custom display modes. /// public static IList GetCustomDisplayModes() { var list = new List(); using (var vdd = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Parsec\\vdd", RegistryKeyPermissionCheck.ReadSubTree)) { if (vdd != null) { for (int i = 0; i < 5; i++) { using (var index = vdd.OpenSubKey($"{i}", RegistryKeyPermissionCheck.ReadSubTree)) { if (index != null) { var width = index.GetValue("width"); var height = index.GetValue("height"); var hz = index.GetValue("hz"); if (width != null && height != null && hz != null) { list.Add(new Display.Mode { Width = Convert.ToUInt16(width), Height = Convert.ToUInt16(height), Hz = Convert.ToUInt16(hz), }); } } } } } } return list; } /// /// Set list of custom display modes. /// This function requires admin rights. /// public static void SetCustomDisplayModes(List modes) { using (var vdd = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Parsec\\vdd", RegistryKeyPermissionCheck.ReadWriteSubTree)) { if (vdd != null) { for (int i = 0; i < 5; i++) { using (var index = vdd.CreateSubKey($"{i}", RegistryKeyPermissionCheck.ReadWriteSubTree)) { if (i >= modes.Count && index != null) { index.Dispose(); vdd.DeleteSubKey($"{i}"); } else if (index != null) { index.SetValue("width", modes[i].Width, RegistryValueKind.DWord); index.SetValue("height", modes[i].Height, RegistryValueKind.DWord); index.SetValue("hz", modes[i].Hz, RegistryValueKind.DWord); } } } } } } /// /// DXGI adapter vendor ids for VDD parent GPU selection. /// Ref: https://support.parsec.app/hc/en-us/articles/4423615425293-VDD-Advanced-Configuration#parent_gpu /// public enum ParentGPU { Auto = 0, NVIDIA = 0x10DE, AMD = 0x1002, Intel = 0x8086, } const string PARAMETERS_KEY = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WUDF\\Services\\ParsecVDA\\Parameters"; const string VALUE_VENDOR_ID = "PreferredRenderAdapterVendorId"; const string VALUE_DISABLE_CHANGE = "DisablePreferredRenderAdapterChange"; /// /// Get parent GPU of VDD. /// public static ParentGPU GetParentGPU() { using (var parameters = Registry.LocalMachine.OpenSubKey( PARAMETERS_KEY, RegistryKeyPermissionCheck.ReadSubTree)) { if (parameters != null) { object value = parameters.GetValue(VALUE_VENDOR_ID); if (value != null) { return (ParentGPU)Convert.ToInt32(value); } } } return ParentGPU.Auto; } /// /// Set parent GPU for VDD. Requires admin rights. /// The driver ships with DisablePreferredRenderAdapterChange = 1 which /// blocks any vendor preference, so we toggle that to 0 before writing the /// vendor id, and restore it to 1 when switching back to Auto. /// public static void SetParentGPU(ParentGPU kind) { using (var parameters = Registry.LocalMachine.OpenSubKey( PARAMETERS_KEY, RegistryKeyPermissionCheck.ReadWriteSubTree)) { if (parameters == null) return; if (kind == ParentGPU.Auto) { parameters.DeleteValue(VALUE_VENDOR_ID, false); parameters.SetValue(VALUE_DISABLE_CHANGE, 1, RegistryValueKind.DWord); } else { parameters.SetValue(VALUE_DISABLE_CHANGE, 0, RegistryValueKind.DWord); parameters.SetValue(VALUE_VENDOR_ID, (uint)kind, RegistryValueKind.DWord); } } } } }