From b1149cf1d7080141410b9cad6b2fa6ed0283411a Mon Sep 17 00:00:00 2001 From: mcrcortex <{ID}+{username}@users.noreply.github.com> Date: Mon, 20 May 2024 09:52:34 +1000 Subject: [PATCH] Relocate the check and applicator, checks to see if the user has a preference first, if not, take over --- .../mods/sodium/client/SodiumPreLaunch.java | 5 + .../compatibility/checks/BugChecks.java | 1 - .../compatibility/checks/PreLaunchChecks.java | 43 -------- .../workarounds/Workarounds.java | 10 ++ .../windows/ForceDedicatedGPU.java | 99 +++++++++++++++++++ 5 files changed, 114 insertions(+), 44 deletions(-) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/windows/ForceDedicatedGPU.java diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/SodiumPreLaunch.java b/src/main/java/net/caffeinemc/mods/sodium/client/SodiumPreLaunch.java index 227b90759d..8745691e30 100644 --- a/src/main/java/net/caffeinemc/mods/sodium/client/SodiumPreLaunch.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/SodiumPreLaunch.java @@ -3,6 +3,7 @@ import net.caffeinemc.mods.sodium.client.compatibility.checks.PreLaunchChecks; import net.caffeinemc.mods.sodium.client.compatibility.workarounds.Workarounds; import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.windows.ForceDedicatedGPU; import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; public class SodiumPreLaunch implements PreLaunchEntrypoint { @@ -11,5 +12,9 @@ public void onPreLaunch() { GraphicsAdapterProbe.findAdapters(); PreLaunchChecks.onGameInit(); Workarounds.init(); + + if (Workarounds.isWorkaroundEnabled(Workarounds.Reference.FORCE_DEDICATED_GPU)) { + ForceDedicatedGPU.forceDedicatedGpu(); + } } } diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/BugChecks.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/BugChecks.java index 71a57732e0..ba9e49f288 100644 --- a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/BugChecks.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/BugChecks.java @@ -5,7 +5,6 @@ * failing checks will crash the game and prompt the user for intervention. */ class BugChecks { - public static final boolean FORCE_DGPU = configureCheck("forgeDGPU", true); public static final boolean ISSUE_899 = configureCheck("issue899", true); public static final boolean ISSUE_1486 = configureCheck("issue1486", true); public static final boolean ISSUE_2048 = configureCheck("issue2048", true); diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PreLaunchChecks.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PreLaunchChecks.java index 3003dcd349..381578fc86 100644 --- a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PreLaunchChecks.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PreLaunchChecks.java @@ -1,6 +1,5 @@ package net.caffeinemc.mods.sodium.client.compatibility.checks; -import com.sun.jna.platform.win32.VersionHelpers; import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion; @@ -10,8 +9,6 @@ import net.caffeinemc.mods.sodium.client.util.OsUtils; import net.caffeinemc.mods.sodium.client.util.OsUtils.OperatingSystem; import org.jetbrains.annotations.Nullable; -import org.lwjgl.system.MemoryStack; -import org.lwjgl.system.MemoryUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,11 +20,6 @@ public class PreLaunchChecks { private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-EarlyDriverScanner"); public static void onGameInit() { - if (BugChecks.FORCE_DGPU) { - forceDGPU(); - } - - if (BugChecks.ISSUE_899) { var installedVersion = findIntelDriverMatchingBug899(); @@ -138,39 +130,4 @@ private static void showUnsupportedDriverMessageBox(String message, String url) return null; } - - private static void forceDGPU() { - if (OsUtils.getOs() != OperatingSystem.WIN) { - return; - } - if (!VersionHelpers.IsWindows10OrGreater()) { - //Only works on windows 10 and up for the time being - return; - } - D3DKMT.WDDMAdapterInfo selected = null; - for (var adapter : GraphicsAdapterProbe.getAdapters()) { - if (adapter instanceof D3DKMT.WDDMAdapterInfo wddmAdapterInfo) { - //Find target gpu, for the time being select the first dgpu - if ((wddmAdapterInfo.adapterType()&0x10)!=0) { - selected = wddmAdapterInfo; - break; - } - } - } - if (selected == null) { - return; - } - LOGGER.info("Attempting to forcefully set the gpu used to " + selected); - - //Need to force the preference type to be user selection - for (var adapter : GraphicsAdapterProbe.getAdapters()) { - if (adapter instanceof D3DKMT.WDDMAdapterInfo wddmAdapterInfo) { - D3DKMT.d3dkmtCacheHybridQueryValue(wddmAdapterInfo.luid(), 5 /*D3DKMT_GPU_PREFERENCE_STATE_USER_SPECIFIED_GPU*/, false, 2/*D3DKMT_GPU_PREFERENCE_TYPE_USER_PREFERENCE*/); - } - } - - //Prime the kernel adapter cache with the selected adapter - D3DKMT.setPciProperties(1 /*USER_SETTINGS*/, selected.pciInfo()); - D3DKMT.setPciProperties(2 /*GLOBAL_SETTINGS*/, selected.pciInfo()); - } } diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java index a1185ea5f5..dd35f8c3aa 100644 --- a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java @@ -3,6 +3,7 @@ import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterInfo; import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.windows.ForceDedicatedGPU; import net.caffeinemc.mods.sodium.client.util.OsUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,6 +38,10 @@ private static Set findNecessaryWorkarounds() { var graphicsAdapters = GraphicsAdapterProbe.getAdapters(); + if (ForceDedicatedGPU.shouldForceDedicatedGPU(operatingSystem, graphicsAdapters.size())) { + workarounds.add(Reference.FORCE_DEDICATED_GPU); + } + if (isUsingNvidiaGraphicsCard(operatingSystem, graphicsAdapters)) { workarounds.add(Reference.NVIDIA_THREADED_OPTIMIZATIONS); } @@ -82,5 +87,10 @@ public enum Reference { * GitHub Issue */ NO_ERROR_CONTEXT_UNSUPPORTED, + + /** + * Attempt to force opengl to launch on dedicated gpu when user hasn't specified a preference. + */ + FORCE_DEDICATED_GPU } } diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/windows/ForceDedicatedGPU.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/windows/ForceDedicatedGPU.java new file mode 100644 index 0000000000..b0ef92b983 --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/windows/ForceDedicatedGPU.java @@ -0,0 +1,99 @@ +package net.caffeinemc.mods.sodium.client.compatibility.workarounds.windows; + +import com.sun.jna.platform.win32.Advapi32; +import com.sun.jna.platform.win32.Advapi32Util; +import com.sun.jna.platform.win32.VersionHelpers; +import com.sun.jna.platform.win32.WinReg; +import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; +import net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32; +import net.caffeinemc.mods.sodium.client.platform.windows.api.d3dkmt.D3DKMT; +import net.caffeinemc.mods.sodium.client.util.OsUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashSet; +import java.util.Set; + +public class ForceDedicatedGPU { + private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-ForceDedicatedGPU"); + public static final String USER_GPU_PREFERENCE_REGISTRY = "Software\\Microsoft\\DirectX\\UserGpuPreferences"; + private static final int PREFERENCE_WINDOWS_DECIDE = 0; + private static final int PREFERENCE_POWER_SAVING = 1; + private static final int PREFERENCE_HIGH_PERFORMANCE = 2; + private static final int PREFERENCE_USER_SPECIFIC = 0x40000000; + public static boolean shouldForceDedicatedGPU(OsUtils.OperatingSystem operatingSystem, int adapterCount) { + if (adapterCount <= 1) {//Dont do it if there is only 1 (or none) adapters + return false; + } + if (operatingSystem != OsUtils.OperatingSystem.WIN) { + return false; + } + if (!VersionHelpers.IsWindows10OrGreater()) { + //Only works on windows 10 and up for the time being + return false; + } + var file = Kernel32.getModuleFileName(0); + try { + //Check if the registry contains a preference, if so, fetch and check preference + if (Advapi32Util.registryValueExists(WinReg.HKEY_CURRENT_USER, USER_GPU_PREFERENCE_REGISTRY, file, 0x20019)) { + var userPreference = Advapi32Util.registryGetStringValue(WinReg.HKEY_CURRENT_USER, USER_GPU_PREFERENCE_REGISTRY, file, 0x20019); + if (userPreference != null && !userPreference.isEmpty()) { + int preference = -1; + + //Need to check what the user preference is if possible + for (var part : userPreference.split(";")) { + var pieces = part.split("="); + if (pieces[0].equals("GpuPreference") && pieces.length == 2) { + try { + preference = Integer.parseUnsignedInt(pieces[1]); + } catch (NumberFormatException e) { + LOGGER.warn("GpuPreference had an unparsable number: " + pieces[1]); + } + break; + } + } + + if (preference == PREFERENCE_POWER_SAVING || preference == PREFERENCE_HIGH_PERFORMANCE || preference == PREFERENCE_USER_SPECIFIC) { + LOGGER.info(String.format("User has specified a graphics preference, not forcing gpu: %X", preference)); + return false; + } + } + } + //We have free rein as user has not specified a preference, or the registry is corrupted + return true; + } catch (Exception e) { + LOGGER.error("Failed to fetch the user preference from the registry.", e); + return false; + } + } + + + public static void forceDedicatedGpu() { + D3DKMT.WDDMAdapterInfo selected = null; + for (var adapter : GraphicsAdapterProbe.getAdapters()) { + if (adapter instanceof D3DKMT.WDDMAdapterInfo wddmAdapterInfo) { + //Find target gpu, for the time being select the first dgpu + if ((wddmAdapterInfo.adapterType()&0x10)!=0) { + selected = wddmAdapterInfo; + break; + } + } + } + if (selected == null) { + LOGGER.info("Unable to find a dedicated gpu to launch the game on."); + return; + } + LOGGER.info("Attempting to forcefully set the gpu used to " + selected); + + //Need to force the preference type to be user selection + for (var adapter : GraphicsAdapterProbe.getAdapters()) { + if (adapter instanceof D3DKMT.WDDMAdapterInfo wddmAdapterInfo) { + D3DKMT.d3dkmtCacheHybridQueryValue(wddmAdapterInfo.luid(), 5 /*D3DKMT_GPU_PREFERENCE_STATE_USER_SPECIFIED_GPU*/, false, 2/*D3DKMT_GPU_PREFERENCE_TYPE_USER_PREFERENCE*/); + } + } + + //Prime the kernel adapter cache with the selected adapter + D3DKMT.setPciProperties(1 /*USER_SETTINGS*/, selected.pciInfo()); + D3DKMT.setPciProperties(2 /*GLOBAL_SETTINGS*/, selected.pciInfo()); + } +}