diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java b/common/src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java index 5b50b53a80..f15795c221 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java @@ -73,10 +73,10 @@ private long wrapGlfwCreateWindowForge(final IntSupplier width, final IntSupplie @Inject(method = "", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL;createCapabilities()Lorg/lwjgl/opengl/GLCapabilities;", shift = At.Shift.AFTER)) private void postContextReady(WindowEventHandler eventHandler, ScreenManager monitorTracker, DisplayData settings, String videoMode, String title, CallbackInfo ci) { - GlContextInfo driver = GlContextInfo.create(); - LOGGER.info("OpenGL Vendor: {}", driver.vendor()); - LOGGER.info("OpenGL Renderer: {}", driver.renderer()); - LOGGER.info("OpenGL Version: {}", driver.version()); + GlContextInfo context = GlContextInfo.create(); + LOGGER.info("OpenGL Vendor: {}", context.vendor()); + LOGGER.info("OpenGL Renderer: {}", context.renderer()); + LOGGER.info("OpenGL Version: {}", context.version()); // Capture the current WGL context so that we can detect it being replaced later. if (Util.getPlatform() == Util.OS.WINDOWS) { @@ -85,8 +85,7 @@ private void postContextReady(WindowEventHandler eventHandler, ScreenManager mon this.wglPrevContext = MemoryUtil.NULL; } - NvidiaWorkarounds.applyContextChanges(driver); - PostLaunchChecks.onContextInitialized(); + PostLaunchChecks.onContextInitialized((NativeWindowHandle) this, context); ModuleScanner.checkModules((NativeWindowHandle) this); } diff --git a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/GraphicsDriverChecks.java b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/GraphicsDriverChecks.java new file mode 100644 index 0000000000..5d410dadac --- /dev/null +++ b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/GraphicsDriverChecks.java @@ -0,0 +1,63 @@ +package net.caffeinemc.mods.sodium.client.compatibility.checks; + +import net.caffeinemc.mods.sodium.client.compatibility.environment.GlContextInfo; +import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.intel.IntelWorkarounds; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds; +import net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle; +import net.caffeinemc.mods.sodium.client.platform.PlatformHelper; + +class GraphicsDriverChecks { + static void postContextInit(NativeWindowHandle window, GlContextInfo context) { + var vendor = GraphicsAdapterVendor.fromContext(context); + + if (vendor == GraphicsAdapterVendor.UNKNOWN) { + return; + } + + if (vendor == GraphicsAdapterVendor.INTEL && BugChecks.ISSUE_899) { + var installedVersion = IntelWorkarounds.findIntelDriverMatchingBug899(); + + if (installedVersion != null) { + var installedVersionString = installedVersion.toString(); + + PlatformHelper.showCriticalErrorAndClose(window, + "Sodium Renderer - Unsupported Driver", + """ + The game failed to start because the currently installed Intel Graphics Driver is not \ + compatible. + + Installed version: ###CURRENT_DRIVER### + Required version: 10.18.10.5161 (or newer) + + You must update your graphics card driver in order to continue.""" + .replace("###CURRENT_DRIVER###", installedVersionString), + "https://github.com/CaffeineMC/sodium/wiki/Driver-Compatibility#windows-intel-gen7"); + } + } + + if (vendor == GraphicsAdapterVendor.NVIDIA && BugChecks.ISSUE_1486) { + var installedVersion = NvidiaWorkarounds.findNvidiaDriverMatchingBug1486(); + + if (installedVersion != null) { + var installedVersionString = NvidiaDriverVersion.parse(installedVersion) + .toString(); + + PlatformHelper.showCriticalErrorAndClose(window, + "Sodium Renderer - Unsupported Driver", + """ + The game failed to start because the currently installed NVIDIA Graphics Driver is not \ + compatible. + + Installed version: ###CURRENT_DRIVER### + Required version: 536.23 (or newer) + + You must update your graphics card driver in order to continue.""" + .replace("###CURRENT_DRIVER###", installedVersionString), + "https://github.com/CaffeineMC/sodium/wiki/Driver-Compatibility#nvidia-gpus"); + + } + } + } +} diff --git a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PostLaunchChecks.java b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PostLaunchChecks.java index 85f5d92488..907b877afe 100644 --- a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PostLaunchChecks.java +++ b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PostLaunchChecks.java @@ -1,7 +1,10 @@ package net.caffeinemc.mods.sodium.client.compatibility.checks; +import net.caffeinemc.mods.sodium.client.compatibility.environment.GlContextInfo; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds; import net.caffeinemc.mods.sodium.client.console.Console; import net.caffeinemc.mods.sodium.client.console.message.MessageLevel; +import net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,7 +15,10 @@ public class PostLaunchChecks { private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-PostlaunchChecks"); - public static void onContextInitialized() { + public static void onContextInitialized(NativeWindowHandle window, GlContextInfo context) { + GraphicsDriverChecks.postContextInit(window, context); + NvidiaWorkarounds.applyContextChanges(context); + // FIXME: This can be determined earlier, but we can't access the GUI classes in pre-launch if (isUsingPojavLauncher()) { Console.instance().logMessage(MessageLevel.SEVERE, "sodium.console.pojav_launcher", true, 30.0); diff --git a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PreLaunchChecks.java b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PreLaunchChecks.java index 170f329ff4..70cb73e27e 100644 --- a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PreLaunchChecks.java +++ b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/checks/PreLaunchChecks.java @@ -1,112 +1,55 @@ package net.caffeinemc.mods.sodium.client.compatibility.checks; -import net.caffeinemc.mods.sodium.client.compatibility.workarounds.intel.IntelWorkarounds; -import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion; -import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds; -import net.caffeinemc.mods.sodium.client.platform.MessageBox; +import net.caffeinemc.mods.sodium.client.platform.PlatformHelper; import org.lwjgl.Version; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Performs OpenGL driver validation before the game creates an OpenGL context. This runs during the earliest possible * opportunity at game startup, and uses a custom hardware prober to search for problematic drivers. */ public class PreLaunchChecks { - private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-EarlyDriverScanner"); - // These version constants are inlined at compile time. private static final String REQUIRED_LWJGL_VERSION = Version.VERSION_MAJOR + "." + Version.VERSION_MINOR + "." + Version.VERSION_REVISION; - private static final String normalMessage = "You must change the LWJGL version in your launcher to continue. " + - "This is usually controlled by the settings for a profile or instance in your launcher."; - - private static final String prismMessage = "It appears you are using Prism Launcher to start the game. You can " + - "likely fix this problem by opening your instance settings and navigating to the Version section in the " + - "sidebar."; - - public static void beforeLWJGLInit() { + public static void checkEnvironment() { if (BugChecks.ISSUE_2561) { - if (!isUsingKnownCompatibleLwjglVersion()) { - String message = normalMessage; - - if (isUsingPrismLauncher()) { - message = prismMessage; - } - - showCriticalErrorAndClose("Sodium Renderer - Unsupported LWJGL", - (""" - The game failed to start because the currently active LWJGL version is not \ - compatible. - - Installed version: ###CURRENT_VERSION### - Required version: ###REQUIRED_VERSION### - - """ + message) - .replace("###CURRENT_VERSION###", Version.getVersion()) - .replace("###REQUIRED_VERSION###", REQUIRED_LWJGL_VERSION), - "https://github.com/CaffeineMC/sodium/wiki/LWJGL-Compatibility"); - } + checkLwjglRuntimeVersion(); } } - public static void onGameInit() { - if (BugChecks.ISSUE_899) { - var installedVersion = IntelWorkarounds.findIntelDriverMatchingBug899(); - - if (installedVersion != null) { - var installedVersionString = installedVersion.toString(); - - showCriticalErrorAndClose("Sodium Renderer - Unsupported Driver", - """ - The game failed to start because the currently installed Intel Graphics Driver is not \ - compatible. - - Installed version: ###CURRENT_DRIVER### - Required version: 10.18.10.5161 (or newer) - - You must update your graphics card driver in order to continue.""" - .replace("###CURRENT_DRIVER###", installedVersionString), - "https://github.com/CaffeineMC/sodium/wiki/Driver-Compatibility#windows-intel-gen7"); - } + private static void checkLwjglRuntimeVersion() { + if (isUsingKnownCompatibleLwjglVersion()) { + return; } - if (BugChecks.ISSUE_1486) { - var installedVersion = NvidiaWorkarounds.findNvidiaDriverMatchingBug1486(); - - if (installedVersion != null) { - var installedVersionString = NvidiaDriverVersion.parse(installedVersion) - .toString(); - - showCriticalErrorAndClose("Sodium Renderer - Unsupported Driver", - """ - The game failed to start because the currently installed NVIDIA Graphics Driver is not \ - compatible. - - Installed version: ###CURRENT_DRIVER### - Required version: 536.23 (or newer) - - You must update your graphics card driver in order to continue.""" - .replace("###CURRENT_DRIVER###", installedVersionString), - "https://github.com/CaffeineMC/sodium/wiki/Driver-Compatibility#nvidia-gpus"); - - } + String advice; + + if (isUsingPrismLauncher()) { + advice = """ + It appears you are using Prism Launcher to start the game. You can \ + likely fix this problem by opening your instance settings and navigating to the Version\ + section in the sidebar."""; + } else { + advice = """ + You must change the LWJGL version in your launcher to continue. \ + This is usually controlled by the settings for a profile or instance in your launcher."""; } - } - private static void showCriticalErrorAndClose(String title, String message, String url) { - // Always print the information to the log file first, just in case we can't show the message box. - LOGGER.error(""" - ###ERROR_DESCRIPTION### - - For more information, please see: ###HELP_URL###""" - .replace("###ERROR_DESCRIPTION###", message) - .replace("###HELP_URL###", url == null ? "" : url)); - - // Try to show a graphical message box (if the platform supports it) and shut down the game. - MessageBox.showMessageBox(null, MessageBox.IconType.ERROR, title, message, url); - System.exit(1 /* failure code */); + String message = """ + The game failed to start because the currently active LWJGL version is not \ + compatible. + + Installed version: ###CURRENT_VERSION### + Required version: ###REQUIRED_VERSION### + + ###ADVICE_STRING###""" + .replace("###CURRENT_VERSION###", Version.getVersion()) + .replace("###REQUIRED_VERSION###", REQUIRED_LWJGL_VERSION) + .replace("###ADVICE_STRING###", advice); + + PlatformHelper.showCriticalErrorAndClose(null, "Sodium Renderer - Unsupported LWJGL", message, + "https://github.com/CaffeineMC/sodium/wiki/LWJGL-Compatibility"); } private static boolean isUsingKnownCompatibleLwjglVersion() { @@ -115,7 +58,11 @@ private static boolean isUsingKnownCompatibleLwjglVersion() { } private static boolean isUsingPrismLauncher() { - return System.getProperty("minecraft.launcher.brand", "unknown") + return getLauncherBrand() .equalsIgnoreCase("PrismLauncher"); } + + private static String getLauncherBrand() { + return System.getProperty("minecraft.launcher.brand", "unknown"); + } } diff --git a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java index 661f817ac9..57ddb79400 100644 --- a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java +++ b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java @@ -1,7 +1,9 @@ package net.caffeinemc.mods.sodium.client.compatibility.environment.probe; +import net.caffeinemc.mods.sodium.client.compatibility.environment.GlContextInfo; import org.jetbrains.annotations.NotNull; +import java.util.Locale; import java.util.regex.Pattern; public enum GraphicsAdapterVendor { @@ -41,6 +43,7 @@ static GraphicsAdapterVendor fromPciVendorId(String vendor) { return UNKNOWN; } + @NotNull public static GraphicsAdapterVendor fromIcdName(String name) { if (matchesPattern(INTEL_ICD_PATTERN, name)) { return INTEL; @@ -53,6 +56,19 @@ public static GraphicsAdapterVendor fromIcdName(String name) { } } + @NotNull + public static GraphicsAdapterVendor fromContext(GlContextInfo context) { + var vendor = context.vendor(); + + return switch (vendor) { + case "NVIDIA Corporation" -> NVIDIA; + case "Intel", "Intel Open Source Technology Center" -> INTEL; + case "AMD", "ATI Technologies Inc." -> AMD; + default -> UNKNOWN; + }; + + } + private static boolean matchesPattern(Pattern pattern, String name) { return pattern.matcher(name) .matches(); diff --git a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java index 9a07886829..659d98b6b3 100644 --- a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java +++ b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java @@ -37,7 +37,7 @@ private static Set findNecessaryWorkarounds() { var workarounds = EnumSet.noneOf(Reference.class); var operatingSystem = OsUtils.getOs(); - if (NvidiaWorkarounds.isUsingNvidiaGraphicsCard()) { + if (NvidiaWorkarounds.isNvidiaGraphicsCardPresent()) { workarounds.add(Reference.NVIDIA_THREADED_OPTIMIZATIONS_BROKEN); } diff --git a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java index 0caa32458f..d7c1be4da6 100644 --- a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java +++ b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java @@ -17,12 +17,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Locale; - public class NvidiaWorkarounds { private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-NvidiaWorkarounds"); - public static boolean isUsingNvidiaGraphicsCard() { + public static boolean isNvidiaGraphicsCardPresent() { return GraphicsAdapterProbe.getAdapters() .stream() .anyMatch(adapter -> adapter.vendor() == GraphicsAdapterVendor.NVIDIA); @@ -64,7 +62,7 @@ public static void applyEnvironmentChanges() { // We can't know if the OpenGL context will actually be initialized using the NVIDIA ICD, but we need to // modify the process environment *now* otherwise the driver will initialize with bad settings. For non-NVIDIA // drivers, these workarounds are not likely to cause issues. - if (!isUsingNvidiaGraphicsCard()) { + if (!isNvidiaGraphicsCardPresent()) { return; } @@ -106,14 +104,11 @@ public static void undoEnvironmentChanges() { WindowsCommandLine.resetCommandLine(); } - public static void applyContextChanges(GlContextInfo driver) { - var normalizedVendorName = driver.vendor() - .toLowerCase(Locale.ROOT); - + public static void applyContextChanges(GlContextInfo context) { // The context may not have been initialized with the NVIDIA ICD, even if we think there is an NVIDIA // graphics adapter in use. Because enabling these workarounds have the potential to severely hurt performance // on other drivers, make sure we exit now. - if (!normalizedVendorName.startsWith("nvidia")) { + if (GraphicsAdapterVendor.fromContext(context) != GraphicsAdapterVendor.NVIDIA) { return; } diff --git a/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/platform/PlatformHelper.java b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/platform/PlatformHelper.java new file mode 100644 index 0000000000..dfc1f2b77f --- /dev/null +++ b/common/src/workarounds/java/net/caffeinemc/mods/sodium/client/platform/PlatformHelper.java @@ -0,0 +1,29 @@ +package net.caffeinemc.mods.sodium.client.platform; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PlatformHelper { + private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-EarlyDriverScanner"); + + public static void showCriticalErrorAndClose( + @Nullable NativeWindowHandle window, + @NotNull String messageTitle, + @NotNull String messageBody, + @NotNull String helpUrl) + { + // Always print the information to the log file first, just in case we can't show the message box. + LOGGER.error(""" + ###ERROR_DESCRIPTION### + + For more information, please see: ###HELP_URL###""" + .replace("###ERROR_DESCRIPTION###", messageBody) + .replace("###HELP_URL###", helpUrl)); + + // Try to show a graphical message box (if the platform supports it) and shut down the game. + MessageBox.showMessageBox(window, MessageBox.IconType.ERROR, messageTitle, messageBody, helpUrl); + System.exit(1 /* failure code */); + } +} diff --git a/fabric/src/main/java/net/caffeinemc/mods/sodium/fabric/SodiumPreLaunch.java b/fabric/src/main/java/net/caffeinemc/mods/sodium/fabric/SodiumPreLaunch.java index 167edadf8b..473c5a6e8e 100644 --- a/fabric/src/main/java/net/caffeinemc/mods/sodium/fabric/SodiumPreLaunch.java +++ b/fabric/src/main/java/net/caffeinemc/mods/sodium/fabric/SodiumPreLaunch.java @@ -8,9 +8,8 @@ public class SodiumPreLaunch implements PreLaunchEntrypoint { @Override public void onPreLaunch() { - PreLaunchChecks.beforeLWJGLInit(); + PreLaunchChecks.checkEnvironment(); GraphicsAdapterProbe.findAdapters(); - PreLaunchChecks.onGameInit(); Workarounds.init(); } } diff --git a/neoforge/src/service/java/net/caffeinemc/mods/sodium/service/SodiumWorkarounds.java b/neoforge/src/service/java/net/caffeinemc/mods/sodium/service/SodiumWorkarounds.java index 8dab82a896..eb106c0ad0 100644 --- a/neoforge/src/service/java/net/caffeinemc/mods/sodium/service/SodiumWorkarounds.java +++ b/neoforge/src/service/java/net/caffeinemc/mods/sodium/service/SodiumWorkarounds.java @@ -14,9 +14,8 @@ public String name() { @Override public void bootstrap(String[] arguments) { - PreLaunchChecks.beforeLWJGLInit(); + PreLaunchChecks.checkEnvironment(); GraphicsAdapterProbe.findAdapters(); - PreLaunchChecks.onGameInit(); Workarounds.init(); // Context creation happens earlier on NeoForge, so we need to apply this now