diff --git a/README.md b/README.md index 717ed15..3f4922b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,11 @@ you find out that virtual GPU is now the primary display adapter, GPU acceleration is unavailable, and the screen connected to Radeon GPU is treated as the secondary screen. +This service intends to solve all the above problems. +With it, you will be able to use Radeon GPU as your only GPU, +with your actual display connected to Radeon as a primary display, +and reboot your VM without triggering AMD reset bug - even installing Windows updates! + ## Limitations Currently this project is only tested with Hyper-V VMs, @@ -23,17 +28,40 @@ and probably also supports KVM and QEMU, but it should be trivial to add other hypervisors support (the relevant files are `Tasks\DisableVirtualVideoTask.cs` and `EnableVirtualVideoTask.cs`). +**Note that you will still have to add a virtual GPU to your VM, +otherwise Windows won't boot.** + +Note that it will add 1-5 minutes both to startup and to shutdown time. +So don't panic if your screen is black immediately after VM startup, +it is expected. + ## Install instructions +Put `RadeonResetBugFixService.exe` in a permanent location. + In elevated command prompt in Guest VM, run ``` RadeonResetBugFixService.exe install ``` -Then check that everything works correctly by opening Services (`services.msc`), -locating Radeon Reset Bug Fix Service there and starting or restarting it. -The display connected to Radeon GPU should go dark and then work again. +The screen may go blank several times during the process. +It may take up to 15 minutes total (but should take less than 5). + +Do not remove the file after that, or the service won't be able to start or stop. +The `install` command does not create any copies, does not create a folder in `Program Files`, +it simply adds a service to Windows, but the service refers to the `exe` file you invoked. + +## Upgrade instructions + +In elevated command prompt in Guest VM, run + +``` +RadeonResetBugFixService.exe reinstall +``` + +The screen may go blank several times during the process. +It may take up to 20 minutes total (but should take less than 5). ## Uninstall instructions @@ -43,6 +71,9 @@ In elevated command prompt in Guest VM, run RadeonResetBugFixService.exe uninstall ``` +The screen may go blank several times during the process. +It may take up to 5 minutes total (but should take less than 2). + ## Debugging The service stores its verbose log files in `logs` directory located next to the executable. diff --git a/RadeonResetBugFixService/Constants.cs b/RadeonResetBugFixService/Constants.cs index 6a7d25b..58ce150 100644 --- a/RadeonResetBugFixService/Constants.cs +++ b/RadeonResetBugFixService/Constants.cs @@ -1,9 +1,17 @@ namespace RadeonResetBugFixService { using System; + using System.IO; + using System.Reflection; static class Constants { public static TimeSpan ServiceTimeout { get; } = TimeSpan.FromMinutes(5); + + public static string ServiceName { get; } = "RadeonResetBugFixService"; + + public static string LogDirectory { get; } = Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "logs"); } } diff --git a/RadeonResetBugFixService/MainHandler.cs b/RadeonResetBugFixService/MainHandler.cs index d74ea7c..0b3b474 100644 --- a/RadeonResetBugFixService/MainHandler.cs +++ b/RadeonResetBugFixService/MainHandler.cs @@ -2,7 +2,6 @@ { using System; using System.IO; - using System.Reflection; using Contracts; using Logging; using Tasks; @@ -21,8 +20,7 @@ { var date = DateTime.Now; this.LogFilename = Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), - "logs", + Constants.LogDirectory, $"radeonfix_{date:yyyyMMdd}_{date:HHmmss}.log"); } diff --git a/RadeonResetBugFixService/Program.cs b/RadeonResetBugFixService/Program.cs index 8d5b63d..b36300c 100644 --- a/RadeonResetBugFixService/Program.cs +++ b/RadeonResetBugFixService/Program.cs @@ -22,8 +22,8 @@ if (!HasAdministratorPrivileges()) { Console.Error.WriteLine("Access Denied."); - Console.Error.WriteLine("Administrator permissions are needed to use the selected options."); - Console.Error.WriteLine("Use an administrator command prompt to complete these tasks."); + Console.Error.WriteLine("Administrator permissions are needed to use this tool."); + Console.Error.WriteLine("Run the command again from an administrator command prompt."); return 740; // ERROR_ELEVATION_REQUIRED } @@ -50,13 +50,8 @@ private static void MainConsole(string[] args) { - if (args.Length != 1) - { - ShowHelp(); - return; - } + var command = args.Length == 1 ? args[0] : string.Empty; - var command = args[0]; if (command.Equals("install", StringComparison.OrdinalIgnoreCase)) { DoInstall(); } @@ -64,6 +59,10 @@ { DoUninstall(); } + else if (command.Equals("reinstall", StringComparison.OrdinalIgnoreCase)) + { + DoReinstall(); + } else if (command.Equals("startup", StringComparison.OrdinalIgnoreCase)) { DoStartup(); @@ -72,6 +71,10 @@ { DoShutdown(); } + else + { + ShowHelp(); + } } private static void ShowHelp() @@ -82,10 +85,12 @@ Console.WriteLine("\t\tInstalls service"); Console.WriteLine($"\t{exeName} uninstall"); Console.WriteLine("\t\tUninstalls service"); + Console.WriteLine($"\t{exeName} reinstall"); + Console.WriteLine("\t\tReinstalls service (might be useful for some upgrades)"); Console.WriteLine($"\t{exeName} startup"); - Console.WriteLine("\t\tPerforms startup sequence"); + Console.WriteLine("\t\tPerforms startup sequence (development command, does not affect services)"); Console.WriteLine($"\t{exeName} shutdown"); - Console.WriteLine("\t\tPerforms shutdown sequence"); + Console.WriteLine("\t\tPerforms shutdown sequence (development command, does not affect services)"); } private static void DoInstall() @@ -93,21 +98,33 @@ Console.WriteLine("Setting registry values..."); Console.WriteLine("Installing service..."); - ServiceHelpers.InstallService(nameof(RadeonResetBugFixService), typeof(RadeonResetBugFixService)); + ServiceHelpers.InstallService(Constants.ServiceName, typeof(RadeonResetBugFixService)); Console.WriteLine("Starting service..."); - ServiceHelpers.StartService(nameof(RadeonResetBugFixService)); - Console.WriteLine("Started service"); + ServiceHelpers.StartService(Constants.ServiceName); + Console.WriteLine("Should restart service now; stopping service..."); + ServiceHelpers.StopService(Constants.ServiceName); + Console.WriteLine("Starting service..."); + ServiceHelpers.StartService(Constants.ServiceName); } private static void DoUninstall() { Console.WriteLine("Stopping service..."); - ServiceHelpers.StopService(nameof(RadeonResetBugFixService)); + ServiceHelpers.StopService(Constants.ServiceName); Console.WriteLine("Uninstalling service..."); - ServiceHelpers.UninstallService(nameof(RadeonResetBugFixService), typeof(RadeonResetBugFixService)); + ServiceHelpers.UninstallService(Constants.ServiceName, typeof(RadeonResetBugFixService)); Console.WriteLine("Uninstalled"); } + private static void DoReinstall() + { + Console.WriteLine("Attempting to uninstall..."); + DoUninstall(); + + Console.WriteLine("Attempting to install..."); + DoInstall(); + } + private static void DoStartup() { new MainHandler().HandleStartup("Program.DoStartup"); diff --git a/RadeonResetBugFixService/ProjectInstaller.cs b/RadeonResetBugFixService/ProjectInstaller.cs index 82f7bd2..161a715 100644 --- a/RadeonResetBugFixService/ProjectInstaller.cs +++ b/RadeonResetBugFixService/ProjectInstaller.cs @@ -3,6 +3,7 @@ using System; using System.ComponentModel; using System.Configuration.Install; + using System.IO; using System.Linq; using System.Management; @@ -16,6 +17,9 @@ private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e) { + Console.WriteLine($"Creating log directory ({Constants.LogDirectory})"); + Directory.CreateDirectory(Constants.LogDirectory); + Console.WriteLine("Preventing Windows from killing services that take up to 300 seconds to shutdown"); RegistryHelper.SetWaitToKillServiceTimeout((int)Constants.ServiceTimeout.TotalMilliseconds); diff --git a/RadeonResetBugFixService/ThirdParty/ServiceHelpers.cs b/RadeonResetBugFixService/ThirdParty/ServiceHelpers.cs index eea396b..70642cb 100644 --- a/RadeonResetBugFixService/ThirdParty/ServiceHelpers.cs +++ b/RadeonResetBugFixService/ThirdParty/ServiceHelpers.cs @@ -36,8 +36,10 @@ public static AssemblyInstaller GetInstaller(Type serviceType) { - AssemblyInstaller installer = new AssemblyInstaller(serviceType.Assembly, null); - installer.UseNewContext = true; + AssemblyInstaller installer = new AssemblyInstaller(serviceType.Assembly, null) + { + UseNewContext = true + }; return installer; } @@ -74,7 +76,7 @@ { if (!IsInstalled(serviceName)) { - Console.WriteLine("Service not installed"); + Console.WriteLine("Service not installed; nothing to uninstall"); return; } @@ -94,7 +96,11 @@ public static void StartService(string serviceName) { - if (!IsInstalled(serviceName)) return; + if (!IsInstalled(serviceName)) + { + Console.WriteLine("Service not installed; nothing to start"); + return; + } using (ServiceController controller = new ServiceController(serviceName)) { @@ -108,7 +114,11 @@ public static void StopService(string serviceName) { - if (!IsInstalled(serviceName)) return; + if (!IsInstalled(serviceName)) + { + Console.WriteLine("Service not installed; nothing to stop"); + return; + } using (ServiceController controller = new ServiceController(serviceName)) {