Skip to content

Commit 3a0296d

Browse files
jellysquid3ThatMG393
authored andcommitted
Use alternative workaround for NVIDIA drivers
The NVIDIA driver enables a driver feature called "Threaded Optimizations" when it finds Minecraft, which causes severe performance issues and sometimes even crashes. Newer versions of the driver seem to use a slightly different heuristic which our workaround doesn't address. So, instead, use an alternative method that enables GL_DEBUG_OUTPUT_SYNCHRONOUS. This seems to reliably disable the functionality *even if* the user has configured it otherwise in their driver settings. Additionally, on Windows, we now always indicate to the driver that Minecraft is running, so that users with hybrid graphics don't see regressed performance.
1 parent d6c6526 commit 3a0296d

File tree

15 files changed

+326
-215
lines changed

15 files changed

+326
-215
lines changed

common/build.gradle.kts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,8 @@ dependencies {
6969

7070
// We need to be careful during pre-launch that we don't touch any Minecraft classes, since other mods
7171
// will not yet have an opportunity to apply transformations.
72-
configurationPreLaunch("org.apache.commons:commons-lang3:3.14.0")
73-
configurationPreLaunch("commons-io:commons-io:2.15.1")
7472
configurationPreLaunch("org.lwjgl:lwjgl:3.3.3")
73+
configurationPreLaunch("org.lwjgl:lwjgl-opengl:3.3.3")
7574
configurationPreLaunch("net.java.dev.jna:jna:5.14.0")
7675
configurationPreLaunch("net.java.dev.jna:jna-platform:5.14.0")
7776
configurationPreLaunch("org.slf4j:slf4j-api:2.0.9")

common/src/main/java/net/caffeinemc/mods/sodium/client/gl/GlContextInfo.java

Lines changed: 0 additions & 19 deletions
This file was deleted.

common/src/main/java/net/caffeinemc/mods/sodium/mixin/core/WindowMixin.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ public class WindowMixin implements NativeWindowHandle {
2222

2323
@WrapOperation(method = "<init>", at = @At(value = "INVOKE", target = "Lorg/lwjgl/glfw/GLFW;glfwCreateWindow(IILjava/lang/CharSequence;JJ)J"), require = 0)
2424
public long setAdditionalWindowHints(int titleEncoded, int width, CharSequence height, long title, long monitor, Operation<Long> original) {
25-
if (!PlatformRuntimeInformation.getInstance().platformHasEarlyLoadingScreen() && SodiumClientMod.options().performance.useNoErrorGLContext &&
26-
!Workarounds.isWorkaroundEnabled(Workarounds.Reference.NO_ERROR_CONTEXT_UNSUPPORTED)) {
27-
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_NO_ERROR, GLFW.GLFW_TRUE);
25+
if (!PlatformRuntimeInformation.getInstance().platformHasEarlyLoadingScreen()) {
26+
if (SodiumClientMod.options().performance.useNoErrorGLContext) {
27+
if (!Workarounds.isWorkaroundEnabled(Workarounds.Reference.NO_ERROR_CONTEXT_UNSUPPORTED)) {
28+
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_NO_ERROR, GLFW.GLFW_TRUE);
29+
}
30+
}
2831
}
2932

3033
return original.call(titleEncoded, width, height, title, monitor);

common/src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
import com.mojang.blaze3d.platform.ScreenManager;
77
import com.mojang.blaze3d.platform.Window;
88
import com.mojang.blaze3d.platform.WindowEventHandler;
9-
import net.caffeinemc.mods.sodium.client.compatibility.checks.PostLaunchChecks;
109
import net.caffeinemc.mods.sodium.client.compatibility.checks.ModuleScanner;
11-
import net.caffeinemc.mods.sodium.client.gl.GlContextInfo;
12-
import net.caffeinemc.mods.sodium.client.compatibility.workarounds.Workarounds;
10+
import net.caffeinemc.mods.sodium.client.compatibility.checks.PostLaunchChecks;
1311
import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds;
12+
import net.caffeinemc.mods.sodium.client.compatibility.environment.GlContextInfo;
1413
import net.caffeinemc.mods.sodium.client.platform.NativeWindowHandle;
1514
import net.caffeinemc.mods.sodium.client.services.PlatformRuntimeInformation;
1615
import net.minecraft.Util;
@@ -38,59 +37,46 @@ public class WindowMixin {
3837
@Final
3938
private static Logger LOGGER;
4039

41-
@Shadow
42-
@Final
43-
private long window;
44-
4540
@Unique
4641
private long wglPrevContext = MemoryUtil.NULL;
4742

4843
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lorg/lwjgl/glfw/GLFW;glfwCreateWindow(IILjava/lang/CharSequence;JJ)J"), expect = 0, require = 0)
4944
private long wrapGlfwCreateWindow(int width, int height, CharSequence title, long monitor, long share) {
50-
final boolean applyNvidiaWorkarounds = Workarounds.isWorkaroundEnabled(Workarounds.Reference.NVIDIA_THREADED_OPTIMIZATIONS);
51-
52-
if (applyNvidiaWorkarounds) {
53-
NvidiaWorkarounds.install();
54-
}
45+
NvidiaWorkarounds.applyEnvironmentChanges();
5546

5647
try {
5748
return GLFW.glfwCreateWindow(width, height, title, monitor, share);
5849
} finally {
59-
if (applyNvidiaWorkarounds) {
60-
NvidiaWorkarounds.uninstall();
61-
}
50+
NvidiaWorkarounds.undoEnvironmentChanges();
6251
}
6352
}
6453

6554
@SuppressWarnings("all")
6655
@WrapOperation(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/neoforged/fml/loading/ImmediateWindowHandler;setupMinecraftWindow(Ljava/util/function/IntSupplier;Ljava/util/function/IntSupplier;Ljava/util/function/Supplier;Ljava/util/function/LongSupplier;)J"), expect = 0, require = 0)
6756
private long wrapGlfwCreateWindowForge(final IntSupplier width, final IntSupplier height, final Supplier<String> title, final LongSupplier monitor, Operation<Long> op) {
68-
final boolean applyNvidiaWorkarounds = Workarounds.isWorkaroundEnabled(Workarounds.Reference.NVIDIA_THREADED_OPTIMIZATIONS);
57+
boolean applyWorkaroundsLate = !PlatformRuntimeInformation.getInstance()
58+
.platformHasEarlyLoadingScreen();
6959

70-
if (applyNvidiaWorkarounds && !PlatformRuntimeInformation.getInstance().platformHasEarlyLoadingScreen()) {
71-
NvidiaWorkarounds.install();
60+
if (applyWorkaroundsLate) {
61+
NvidiaWorkarounds.applyEnvironmentChanges();
7262
}
7363

7464
try {
7565
return op.call(width, height, title, monitor);
7666
} finally {
77-
if (applyNvidiaWorkarounds) {
78-
NvidiaWorkarounds.uninstall();
67+
if (applyWorkaroundsLate) {
68+
NvidiaWorkarounds.undoEnvironmentChanges();
7969
}
8070
}
8171
}
8272

73+
8374
@Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL;createCapabilities()Lorg/lwjgl/opengl/GLCapabilities;", shift = At.Shift.AFTER))
8475
private void postContextReady(WindowEventHandler eventHandler, ScreenManager monitorTracker, DisplayData settings, String videoMode, String title, CallbackInfo ci) {
8576
GlContextInfo driver = GlContextInfo.create();
86-
87-
if (driver == null) {
88-
LOGGER.warn("Could not retrieve identifying strings for OpenGL implementation");
89-
} else {
90-
LOGGER.info("OpenGL Vendor: {}", driver.vendor());
91-
LOGGER.info("OpenGL Renderer: {}", driver.renderer());
92-
LOGGER.info("OpenGL Version: {}", driver.version());
93-
}
77+
LOGGER.info("OpenGL Vendor: {}", driver.vendor());
78+
LOGGER.info("OpenGL Renderer: {}", driver.renderer());
79+
LOGGER.info("OpenGL Version: {}", driver.version());
9480

9581
// Capture the current WGL context so that we can detect it being replaced later.
9682
if (Util.getPlatform() == Util.OS.WINDOWS) {
@@ -99,6 +85,7 @@ private void postContextReady(WindowEventHandler eventHandler, ScreenManager mon
9985
this.wglPrevContext = MemoryUtil.NULL;
10086
}
10187

88+
NvidiaWorkarounds.applyContextChanges(driver);
10289
PostLaunchChecks.onContextInitialized();
10390
ModuleScanner.checkModules((NativeWindowHandle) this);
10491
}
Lines changed: 28 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,37 @@
11
package net.caffeinemc.mods.sodium.client.compatibility.checks;
22

3-
import net.caffeinemc.mods.sodium.client.compatibility.environment.OsUtils;
4-
import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe;
5-
import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor;
3+
import net.caffeinemc.mods.sodium.client.compatibility.workarounds.intel.IntelWorkarounds;
64
import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion;
5+
import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds;
76
import net.caffeinemc.mods.sodium.client.platform.MessageBox;
8-
import net.caffeinemc.mods.sodium.client.platform.windows.WindowsFileVersion;
9-
import net.caffeinemc.mods.sodium.client.platform.windows.api.d3dkmt.D3DKMT;
10-
import org.jetbrains.annotations.Nullable;
117
import org.lwjgl.Version;
128
import org.slf4j.Logger;
139
import org.slf4j.LoggerFactory;
1410

15-
import java.util.Arrays;
16-
1711
/**
1812
* Performs OpenGL driver validation before the game creates an OpenGL context. This runs during the earliest possible
1913
* opportunity at game startup, and uses a custom hardware prober to search for problematic drivers.
2014
*/
2115
public class PreLaunchChecks {
2216
private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-EarlyDriverScanner");
2317

24-
// This string should be determined at compile time, so it can be checked against the runtime version.
25-
private static final String REQUIRED_LWJGL_VERSION = Version.VERSION_MAJOR + "." + Version.VERSION_MINOR + "." + Version.VERSION_REVISION;
18+
// These version constants are inlined at compile time.
19+
private static final String REQUIRED_LWJGL_VERSION =
20+
Version.VERSION_MAJOR + "." + Version.VERSION_MINOR + "." + Version.VERSION_REVISION;
2621

27-
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.";
22+
private static final String normalMessage = "You must change the LWJGL version in your launcher to continue. " +
23+
"This is usually controlled by the settings for a profile or instance in your launcher.";
2824

29-
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.";
25+
private static final String prismMessage = "It appears you are using Prism Launcher to start the game. You can " +
26+
"likely fix this problem by opening your instance settings and navigating to the Version section in the " +
27+
"sidebar.";
3028

3129
public static void beforeLWJGLInit() {
3230
if (BugChecks.ISSUE_2561) {
33-
if (!Version.getVersion().startsWith(REQUIRED_LWJGL_VERSION)) {
31+
if (!isUsingKnownCompatibleLwjglVersion()) {
3432
String message = normalMessage;
3533

36-
if (System.getProperty("minecraft.launcher.brand", "unknown").equalsIgnoreCase("PrismLauncher")) {
34+
if (isUsingPrismLauncher()) {
3735
message = prismMessage;
3836
}
3937

@@ -46,19 +44,20 @@ public static void beforeLWJGLInit() {
4644
Required version: ###REQUIRED_VERSION###
4745
4846
""" + message)
49-
.replace("###CURRENT_VERSION###", org.lwjgl.Version.getVersion())
47+
.replace("###CURRENT_VERSION###", Version.getVersion())
5048
.replace("###REQUIRED_VERSION###", REQUIRED_LWJGL_VERSION),
5149
"https://github.com/CaffeineMC/sodium/wiki/LWJGL-Compatibility");
52-
5350
}
5451
}
5552
}
5653

5754
public static void onGameInit() {
5855
if (BugChecks.ISSUE_899) {
59-
var installedVersion = findIntelDriverMatchingBug899();
56+
var installedVersion = IntelWorkarounds.findIntelDriverMatchingBug899();
6057

6158
if (installedVersion != null) {
59+
var installedVersionString = installedVersion.toString();
60+
6261
showCriticalErrorAndClose("Sodium Renderer - Unsupported Driver",
6362
"""
6463
The game failed to start because the currently installed Intel Graphics Driver is not \
@@ -68,15 +67,18 @@ public static void onGameInit() {
6867
Required version: 10.18.10.5161 (or newer)
6968
7069
You must update your graphics card driver in order to continue."""
71-
.replace("###CURRENT_DRIVER###", installedVersion.toString()),
70+
.replace("###CURRENT_DRIVER###", installedVersionString),
7271
"https://github.com/CaffeineMC/sodium/wiki/Driver-Compatibility#windows-intel-gen7");
7372
}
7473
}
7574

7675
if (BugChecks.ISSUE_1486) {
77-
var installedVersion = findNvidiaDriverMatchingBug1486();
76+
var installedVersion = NvidiaWorkarounds.findNvidiaDriverMatchingBug1486();
7877

7978
if (installedVersion != null) {
79+
var installedVersionString = NvidiaDriverVersion.parse(installedVersion)
80+
.toString();
81+
8082
showCriticalErrorAndClose("Sodium Renderer - Unsupported Driver",
8183
"""
8284
The game failed to start because the currently installed NVIDIA Graphics Driver is not \
@@ -86,7 +88,7 @@ public static void onGameInit() {
8688
Required version: 536.23 (or newer)
8789
8890
You must update your graphics card driver in order to continue."""
89-
.replace("###CURRENT_DRIVER###", NvidiaDriverVersion.parse(installedVersion).toString()),
91+
.replace("###CURRENT_DRIVER###", installedVersionString),
9092
"https://github.com/CaffeineMC/sodium/wiki/Driver-Compatibility#nvidia-gpus");
9193

9294
}
@@ -107,67 +109,13 @@ private static void showCriticalErrorAndClose(String title, String message, Stri
107109
System.exit(1 /* failure code */);
108110
}
109111

110-
// https://github.com/CaffeineMC/sodium/issues/899
111-
private static @Nullable WindowsFileVersion findIntelDriverMatchingBug899() {
112-
if (OsUtils.getOs() != OsUtils.OperatingSystem.WIN) {
113-
return null;
114-
}
115-
116-
for (var adapter : GraphicsAdapterProbe.getAdapters()) {
117-
if (adapter instanceof D3DKMT.WDDMAdapterInfo wddmAdapterInfo) {
118-
@Nullable var driverName = wddmAdapterInfo.getOpenGlIcdName();
119-
120-
if (driverName == null) {
121-
continue;
122-
}
123-
124-
var driverVersion = wddmAdapterInfo.openglIcdVersion();
125-
126-
// Intel OpenGL ICD for Generation 7 GPUs
127-
if (driverName.matches("ig7icd(32|64)")) {
128-
// https://www.intel.com/content/www/us/en/support/articles/000005654/graphics.html
129-
// Anything which matches the 15.33 driver scheme (WDDM x.y.10.w) should be checked
130-
// Drivers before build 5161 are assumed to have bugs with synchronization primitives
131-
if (driverVersion.z() == 10 && driverVersion.w() < 5161) {
132-
return driverVersion;
133-
}
134-
}
135-
}
136-
}
137-
138-
return null;
112+
private static boolean isUsingKnownCompatibleLwjglVersion() {
113+
return Version.getVersion()
114+
.startsWith(REQUIRED_LWJGL_VERSION);
139115
}
140116

141-
142-
// https://github.com/CaffeineMC/sodium/issues/1486
143-
// The way which NVIDIA tries to detect the Minecraft process could not be circumvented until fairly recently
144-
// So we require that an up-to-date graphics driver is installed so that our workarounds can disable the Threaded
145-
// Optimizations driver hack.
146-
private static @Nullable WindowsFileVersion findNvidiaDriverMatchingBug1486() {
147-
// The Linux driver has two separate branches which have overlapping version numbers, despite also having
148-
// different feature sets. As a result, we can't reliably determine which Linux drivers are broken...
149-
if (OsUtils.getOs() != OsUtils.OperatingSystem.WIN) {
150-
return null;
151-
}
152-
153-
for (var adapter : GraphicsAdapterProbe.getAdapters()) {
154-
if (adapter.vendor() != GraphicsAdapterVendor.NVIDIA) {
155-
continue;
156-
}
157-
158-
if (adapter instanceof D3DKMT.WDDMAdapterInfo wddmAdapterInfo) {
159-
var driverVersion = wddmAdapterInfo.openglIcdVersion();
160-
161-
if (driverVersion.z() == 15) { // Only match 5XX.XX drivers
162-
// Broken in x.y.15.2647 (526.47)
163-
// Fixed in x.y.15.3623 (536.23)
164-
if (driverVersion.w() >= 2647 && driverVersion.w() < 3623) {
165-
return driverVersion;
166-
}
167-
}
168-
}
169-
}
170-
171-
return null;
117+
private static boolean isUsingPrismLauncher() {
118+
return System.getProperty("minecraft.launcher.brand", "unknown")
119+
.equalsIgnoreCase("PrismLauncher");
172120
}
173121
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package net.caffeinemc.mods.sodium.client.compatibility.environment;
2+
3+
import org.jetbrains.annotations.Nullable;
4+
import org.lwjgl.opengl.GL11C;
5+
6+
import java.util.Objects;
7+
8+
public record GlContextInfo(String vendor, String renderer, String version) {
9+
public static GlContextInfo create() {
10+
String vendor = Objects.requireNonNull(GL11C.glGetString(GL11C.GL_VENDOR),
11+
"GL_VENDOR is NULL");
12+
String renderer = Objects.requireNonNull(GL11C.glGetString(GL11C.GL_RENDERER),
13+
"GL_RENDERER is NULL");
14+
String version = Objects.requireNonNull(GL11C.glGetString(GL11C.GL_VERSION),
15+
"GL_VERSION is NULL");
16+
17+
return new GlContextInfo(vendor, renderer, version);
18+
}
19+
}

common/src/workarounds/java/net/caffeinemc/mods/sodium/client/compatibility/environment/OsUtils.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
package net.caffeinemc.mods.sodium.client.compatibility.environment;
22

3-
import org.apache.commons.lang3.SystemUtils;
3+
import java.util.Locale;
44

55
public class OsUtils {
6+
private static final OperatingSystem OS = determineOs();
67

7-
public static OperatingSystem getOs() {
8-
if (SystemUtils.IS_OS_WINDOWS) {
9-
return OperatingSystem.WIN;
10-
} else if (SystemUtils.IS_OS_MAC) {
11-
return OperatingSystem.MAC;
12-
} else if (SystemUtils.IS_OS_LINUX) {
13-
return OperatingSystem.LINUX;
8+
public static OperatingSystem determineOs() {
9+
var name = System.getProperty("os.name");
10+
11+
if (name != null) {
12+
var normalized = name.toLowerCase(Locale.ROOT);
13+
14+
if (normalized.startsWith("windows")) {
15+
return OperatingSystem.WIN;
16+
} else if (normalized.startsWith("mac")) {
17+
return OperatingSystem.MAC;
18+
} else if (normalized.startsWith("linux")) {
19+
return OperatingSystem.LINUX;
20+
}
1421
}
1522

1623
return OperatingSystem.UNKNOWN;
1724
}
1825

26+
public static OperatingSystem getOs() {
27+
return OS;
28+
}
29+
1930
public enum OperatingSystem {
2031
WIN,
2132
MAC,

0 commit comments

Comments
 (0)