Skip to content

Commit b74c499

Browse files
committed
Re-organize infrastructure for startup checks
1 parent cc12279 commit b74c499

29 files changed

+562
-214
lines changed
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package me.jellysquid.mods.sodium.client;
22

3-
import me.jellysquid.mods.sodium.client.util.workarounds.PreLaunchChecks;
4-
import me.jellysquid.mods.sodium.client.util.workarounds.Workarounds;
5-
import me.jellysquid.mods.sodium.client.util.workarounds.probe.GraphicsAdapterProbe;
3+
import me.jellysquid.mods.sodium.client.compatibility.checks.EarlyDriverScanner;
4+
import me.jellysquid.mods.sodium.client.compatibility.workarounds.Workarounds;
5+
import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe;
66
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
77

88
public class SodiumPreLaunch implements PreLaunchEntrypoint {
99
@Override
1010
public void onPreLaunch() {
1111
GraphicsAdapterProbe.findAdapters();
12-
PreLaunchChecks.checkDrivers();
12+
EarlyDriverScanner.scanDrivers();
1313
Workarounds.init();
1414
}
1515
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package me.jellysquid.mods.sodium.client.compatibility.checks;
2+
3+
/**
4+
* "Checks" are used to determine whether the environment we are running within is actually reasonable. Most often,
5+
* failing checks will crash the game and prompt the user for intervention.
6+
*/
7+
class Configuration {
8+
public static final boolean WIN32_RTSS_HOOKS = configureCheck("win32.rtss", true);
9+
public static final boolean WIN32_DRIVER_INTEL_GEN7 = configureCheck("win32.intelGen7", true);
10+
11+
private static boolean configureCheck(String name, boolean defaultValue) {
12+
var propertyValue = System.getProperty(getPropertyKey(name), null);
13+
14+
if (propertyValue == null) {
15+
return defaultValue;
16+
}
17+
18+
return Boolean.parseBoolean(propertyValue);
19+
}
20+
21+
private static String getPropertyKey(String name) {
22+
return "sodium.checks." + name;
23+
}
24+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package me.jellysquid.mods.sodium.client.compatibility.checks;
2+
3+
import me.jellysquid.mods.sodium.client.platform.MessageBox;
4+
import me.jellysquid.mods.sodium.client.platform.windows.WindowsDriverStoreVersion;
5+
import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe;
6+
import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor;
7+
import net.minecraft.util.Util;
8+
import org.jetbrains.annotations.Nullable;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
12+
/**
13+
* Performs OpenGL driver validation before the game creates an OpenGL context. This runs during the earliest possible
14+
* opportunity at game startup, and uses a custom hardware prober to search for problematic drivers.
15+
*/
16+
public class EarlyDriverScanner {
17+
private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-EarlyDriverScanner");
18+
19+
private static final String CONSOLE_MESSAGE_TEMPLATE = """
20+
###ERROR_DESCRIPTION###
21+
22+
For more information, please see: ###HELP_URL###
23+
""";
24+
25+
private static final String INTEL_GEN7_DRIVER_MESSAGE = """
26+
The game failed to start because the currently installed Intel Graphics Driver is not compatible.
27+
28+
Installed version: ###CURRENT_DRIVER###
29+
Required version: 15.33.53.5161 (or newer)
30+
31+
You must update your graphics card driver in order to continue.""";
32+
33+
private static final String INTEL_GEN7_DRIVER_HELP_URL = "https://github.com/CaffeineMC/sodium-fabric/wiki/Driver-Compatibility#windows-intel-gen7";
34+
35+
public static void scanDrivers() {
36+
if (Configuration.WIN32_DRIVER_INTEL_GEN7) {
37+
var installedVersion = findBrokenIntelGen7GraphicsDriver();
38+
39+
if (installedVersion != null) {
40+
showUnsupportedDriverMessageBox(
41+
INTEL_GEN7_DRIVER_MESSAGE
42+
.replace("###CURRENT_DRIVER###", installedVersion.getFriendlyString()),
43+
INTEL_GEN7_DRIVER_HELP_URL);
44+
}
45+
}
46+
}
47+
48+
private static void showUnsupportedDriverMessageBox(String message, String url) {
49+
// Always print the information to the log file first, just in case we can't show the message box.
50+
LOGGER.error(CONSOLE_MESSAGE_TEMPLATE
51+
.replace("###ERROR_DESCRIPTION###", message)
52+
.replace("###HELP_URL###", url));
53+
54+
// Try to show a graphical message box (if the platform supports it) and shut down the game.
55+
MessageBox.showMessageBox(null, MessageBox.IconType.ERROR, "Sodium Renderer - Unsupported Driver", message, url);
56+
System.exit(1 /* failure code */);
57+
}
58+
59+
// https://github.com/CaffeineMC/sodium-fabric/issues/899
60+
private static @Nullable WindowsDriverStoreVersion findBrokenIntelGen7GraphicsDriver() {
61+
if (Util.getOperatingSystem() != Util.OperatingSystem.WINDOWS) {
62+
return null;
63+
}
64+
65+
for (var adapter : GraphicsAdapterProbe.getAdapters()) {
66+
if (adapter.vendor() != GraphicsAdapterVendor.INTEL) {
67+
continue;
68+
}
69+
70+
try {
71+
var version = WindowsDriverStoreVersion.parse(adapter.version());
72+
73+
if (version.driverModel() == 10 && version.featureLevel() == 18 && version.major() == 10) {
74+
return version;
75+
}
76+
} catch (WindowsDriverStoreVersion.ParseException ignored) { }
77+
}
78+
79+
return null;
80+
}
81+
}

src/main/java/me/jellysquid/mods/sodium/client/util/workarounds/PostLaunchChecks.java renamed to src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/LateDriverScanner.java

Lines changed: 25 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,34 @@
1-
package me.jellysquid.mods.sodium.client.util.workarounds;
1+
package me.jellysquid.mods.sodium.client.compatibility.checks;
22

3+
import me.jellysquid.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion;
34
import me.jellysquid.mods.sodium.client.gui.console.Console;
45
import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel;
5-
import me.jellysquid.mods.sodium.client.util.workarounds.driver.nvidia.NvidiaGLContextInfo;
6-
import me.jellysquid.mods.sodium.client.util.workarounds.platform.windows.WindowsModuleChecks;
7-
import net.minecraft.text.MutableText;
6+
import me.jellysquid.mods.sodium.client.compatibility.environment.GLContextInfo;
87
import net.minecraft.text.Text;
98
import net.minecraft.util.Util;
10-
import org.jetbrains.annotations.Nullable;
11-
import org.lwjgl.opengl.GL11C;
129
import org.slf4j.Logger;
1310
import org.slf4j.LoggerFactory;
1411

15-
public class PostLaunchChecks {
12+
/**
13+
* Performs OpenGL driver validation after the game creates an OpenGL context. This runs immediately after OpenGL
14+
* context creation, and uses the implementation details of the OpenGL context to perform validation.
15+
*/
16+
public class LateDriverScanner {
1617
private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-PostlaunchChecks");
1718

18-
public static void checkContext() {
19+
public static void onContextInitialized() {
1920
checkContextImplementation();
2021

2122
if (isUsingPojavLauncher()) {
22-
showConsoleMessage(Text.translatable("sodium.console.pojav_launcher"));
23-
logMessage("It appears that PojavLauncher is being used with an OpenGL compatibility layer. This will " +
23+
Console.instance().logMessage(MessageLevel.SEVERE, Text.translatable("sodium.console.pojav_launcher"), 30.0);
24+
LOGGER.error("It appears that PojavLauncher is being used with an OpenGL compatibility layer. This will " +
2425
"likely cause severe performance issues, graphical issues, and crashes when used with Sodium. This " +
2526
"configuration is not supported -- you are on your own!");
2627
}
27-
28-
// We should also check that nothing problematic has been injected into the process.
29-
WindowsModuleChecks.checkModules();
3028
}
3129

3230
private static void checkContextImplementation() {
33-
GLContextInfo driver = getGraphicsContextInfo();
31+
GLContextInfo driver = GLContextInfo.create();
3432

3533
if (driver == null) {
3634
LOGGER.warn("Could not retrieve identifying strings for OpenGL implementation");
@@ -41,56 +39,38 @@ private static void checkContextImplementation() {
4139
LOGGER.info("OpenGL Renderer: {}", driver.renderer());
4240
LOGGER.info("OpenGL Version: {}", driver.version());
4341

44-
if (isBrokenNvidiaDriverInstalled(driver)) {
45-
showConsoleMessage(Text.translatable("sodium.console.broken_nvidia_driver"));
46-
logMessage("The NVIDIA graphics driver appears to be out of date. This will likely cause severe " +
42+
if (!isSupportedNvidiaDriver(driver)) {
43+
Console.instance()
44+
.logMessage(MessageLevel.SEVERE, Text.translatable("sodium.console.broken_nvidia_driver"), 30.0);
45+
46+
LOGGER.error("The NVIDIA graphics driver appears to be out of date. This will likely cause severe " +
4747
"performance issues and crashes when used with Sodium. The graphics driver should be updated to " +
4848
"the latest version (version 536.23 or newer).");
4949
}
5050
}
5151

52-
@Nullable
53-
private static GLContextInfo getGraphicsContextInfo() {
54-
String vendor = GL11C.glGetString(GL11C.GL_VENDOR);
55-
String renderer = GL11C.glGetString(GL11C.GL_RENDERER);
56-
String version = GL11C.glGetString(GL11C.GL_VERSION);
57-
58-
if (vendor == null || renderer == null || version == null) {
59-
return null;
60-
}
61-
62-
return new GLContextInfo(vendor, renderer, version);
63-
}
64-
65-
private static void showConsoleMessage(MutableText message) {
66-
Console.instance().logMessage(MessageLevel.SEVERE, message, 30.0);
67-
}
68-
69-
private static void logMessage(String message, Object... args) {
70-
LOGGER.error(message, args);
71-
}
72-
7352
// https://github.com/CaffeineMC/sodium-fabric/issues/1486
7453
// The way which NVIDIA tries to detect the Minecraft process could not be circumvented until fairly recently
7554
// So we require that an up-to-date graphics driver is installed so that our workarounds can disable the Threaded
7655
// Optimizations driver hack.
77-
private static boolean isBrokenNvidiaDriverInstalled(GLContextInfo driver) {
56+
private static boolean isSupportedNvidiaDriver(GLContextInfo driver) {
7857
// The Linux driver has two separate branches which have overlapping version numbers, despite also having
7958
// different feature sets. As a result, we can't reliably determine which Linux drivers are broken...
8059
if (Util.getOperatingSystem() != Util.OperatingSystem.WINDOWS) {
81-
return false;
60+
return true;
8261
}
8362

84-
var version = NvidiaGLContextInfo.tryParse(driver);
63+
var version = NvidiaDriverVersion.tryParse(driver);
8564

8665
if (version != null) {
87-
return version.isWithinRange(
88-
new NvidiaGLContextInfo(526, 47), // Broken in 526.47
89-
new NvidiaGLContextInfo(536, 23) // Fixed in 536.23
66+
return !version.isWithinRange(
67+
new NvidiaDriverVersion(526, 47), // Broken in 526.47
68+
new NvidiaDriverVersion(536, 23) // Fixed in 536.23
9069
);
9170
}
9271

93-
return false;
72+
// If we couldn't determine the version, then it's supported either way.
73+
return true;
9474
}
9575

9676
// https://github.com/CaffeineMC/sodium-fabric/issues/1916
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package me.jellysquid.mods.sodium.client.compatibility.checks;
2+
3+
import net.minecraft.util.WinNativeModuleUtil;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
7+
import java.util.List;
8+
9+
/**
10+
* Utility class for determining whether the current process has been injected into or otherwise modified. This should
11+
* generally only be accessed after OpenGL context creation, as most third-party software waits until the OpenGL ICD
12+
* is initialized before injecting.
13+
*/
14+
public class ModuleScanner {
15+
private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-Win32ModuleChecks");
16+
17+
private static final String[] RTSS_HOOKS_MODULE_NAMES = { "RTSSHooks64.dll", "RTSSHooks.dll" };
18+
19+
public static void checkModules() {
20+
List<WinNativeModuleUtil.NativeModule> modules;
21+
22+
try {
23+
modules = WinNativeModuleUtil.collectNativeModules();
24+
} catch (Throwable t) {
25+
LOGGER.warn("Failed to scan the currently loaded modules", t);
26+
return;
27+
}
28+
29+
if (modules.isEmpty()) {
30+
// Platforms other than Windows will not return anything.
31+
return;
32+
}
33+
34+
// RivaTuner hooks the wglCreateContext function, and leaves itself behind as a loaded module
35+
if (Configuration.WIN32_RTSS_HOOKS && isModuleLoaded(modules, RTSS_HOOKS_MODULE_NAMES)) {
36+
throw new RuntimeException("RivaTuner Statistics Server (RTSS) is not compatible with Sodium, " +
37+
"see here for more details: https://github.com/CaffeineMC/sodium-fabric/wiki/Known-Issues#rtss-incompatible");
38+
}
39+
}
40+
41+
private static boolean isModuleLoaded(List<WinNativeModuleUtil.NativeModule> modules, String[] names) {
42+
for (var name : names) {
43+
for (var module : modules) {
44+
if (module.path.equalsIgnoreCase(name)) {
45+
return true;
46+
}
47+
}
48+
}
49+
50+
return false;
51+
}
52+
}

src/main/java/me/jellysquid/mods/sodium/client/util/workarounds/InGameChecks.java renamed to src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ResourcePackScanner.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package me.jellysquid.mods.sodium.client.util.workarounds;
1+
package me.jellysquid.mods.sodium.client.compatibility.checks;
22

33
import me.jellysquid.mods.sodium.client.gui.console.Console;
44
import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel;
@@ -14,7 +14,7 @@
1414
import java.util.List;
1515
import java.util.Map;
1616

17-
public class InGameChecks {
17+
public class ResourcePackScanner {
1818

1919
private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-InGameChecks");
2020
private static final List<String> VSH_FSH_BLACKLIST = Arrays.asList(
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package me.jellysquid.mods.sodium.client.compatibility.environment;
2+
3+
import org.jetbrains.annotations.Nullable;
4+
import org.lwjgl.opengl.GL11C;
5+
6+
public record GLContextInfo(String vendor, String renderer, String version) {
7+
@Nullable
8+
public static GLContextInfo create() {
9+
String vendor = GL11C.glGetString(GL11C.GL_VENDOR);
10+
String renderer = GL11C.glGetString(GL11C.GL_RENDERER);
11+
String version = GL11C.glGetString(GL11C.GL_VERSION);
12+
13+
if (vendor == null || renderer == null || version == null) {
14+
return null;
15+
}
16+
17+
return new GLContextInfo(vendor, renderer, version);
18+
}
19+
}

src/main/java/me/jellysquid/mods/sodium/client/util/workarounds/probe/GraphicsAdapterInfo.java renamed to src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterInfo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package me.jellysquid.mods.sodium.client.util.workarounds.probe;
1+
package me.jellysquid.mods.sodium.client.compatibility.environment.probe;
22

33
public record GraphicsAdapterInfo(GraphicsAdapterVendor vendor, String name, String version) {
44

src/main/java/me/jellysquid/mods/sodium/client/util/workarounds/probe/GraphicsAdapterProbe.java renamed to src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package me.jellysquid.mods.sodium.client.util.workarounds.probe;
1+
package me.jellysquid.mods.sodium.client.compatibility.environment.probe;
22

33
import net.minecraft.util.Util;
44
import org.slf4j.Logger;

src/main/java/me/jellysquid/mods/sodium/client/util/workarounds/probe/GraphicsAdapterVendor.java renamed to src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package me.jellysquid.mods.sodium.client.util.workarounds.probe;
1+
package me.jellysquid.mods.sodium.client.compatibility.environment.probe;
22

33
import org.jetbrains.annotations.NotNull;
44

0 commit comments

Comments
 (0)