Skip to content

Commit

Permalink
Use D3DKMT for probing graphics adapters at startup
Browse files Browse the repository at this point in the history
Co-authored-by: jellysquid3 <[email protected]>
  • Loading branch information
IMS212 and jellysquid3 committed Jun 7, 2024
1 parent 352972c commit 87f165a
Show file tree
Hide file tree
Showing 34 changed files with 1,195 additions and 330 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package me.jellysquid.mods.sodium.client;

import me.jellysquid.mods.sodium.client.compatibility.checks.EarlyDriverScanner;
import me.jellysquid.mods.sodium.client.compatibility.checks.PreLaunchChecks;
import me.jellysquid.mods.sodium.client.compatibility.workarounds.Workarounds;
import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
Expand All @@ -9,7 +9,7 @@ public class SodiumPreLaunch implements PreLaunchEntrypoint {
@Override
public void onPreLaunch() {
GraphicsAdapterProbe.findAdapters();
EarlyDriverScanner.scanDrivers();
PreLaunchChecks.onGameInit();
Workarounds.init();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
* "Checks" are used to determine whether the environment we are running within is actually reasonable. Most often,
* failing checks will crash the game and prompt the user for intervention.
*/
class Configuration {
public static final boolean WIN32_RTSS_HOOKS = configureCheck("win32.rtss", true);
public static final boolean WIN32_DRIVER_INTEL_GEN7 = configureCheck("win32.intelGen7", true);
class BugChecks {
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);

private static boolean configureCheck(String name, boolean defaultValue) {
var propertyValue = System.getProperty(getPropertyKey(name), null);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package me.jellysquid.mods.sodium.client.compatibility.checks;

import me.jellysquid.mods.sodium.client.platform.MessageBox;
import me.jellysquid.mods.sodium.client.platform.windows.WindowsFileVersion;
import me.jellysquid.mods.sodium.client.platform.windows.api.Kernel32;
import me.jellysquid.mods.sodium.client.platform.windows.api.version.Version;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.Window;
import net.minecraft.util.WinNativeModuleUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -40,15 +43,15 @@ public static void checkModules() {
}

// RivaTuner hooks the wglCreateContext function, and leaves itself behind as a loaded module
if (Configuration.WIN32_RTSS_HOOKS && isModuleLoaded(modules, RTSS_HOOKS_MODULE_NAMES)) {
if (BugChecks.ISSUE_2048 && isModuleLoaded(modules, RTSS_HOOKS_MODULE_NAMES)) {
checkRTSSModules();
}
}

private static void checkRTSSModules() {
LOGGER.warn("RivaTuner Statistics Server (RTSS) has injected into the process! Attempting to apply workarounds for compatibility...");

String version = null;
@Nullable WindowsFileVersion version = null;

try {
version = findRTSSModuleVersion();
Expand All @@ -65,43 +68,29 @@ private static void checkRTSSModules() {
if (version == null || !isRTSSCompatible(version)) {
Window window = MinecraftClient.getInstance().getWindow();
MessageBox.showMessageBox(window, MessageBox.IconType.ERROR, "Sodium Renderer",
"You appear to be using an older version of RivaTuner Statistics Server (RTSS) which is not compatible with Sodium. " +
"You must either update to a newer version (7.3.4 and later) or close the RivaTuner Statistics Server application.\n\n" +
"For more information on how to solve this problem, click the 'Help' button.",
"""
You appear to be using an older version of RivaTuner Statistics Server (RTSS) which is not compatible with Sodium.
You must either update to a newer version (7.3.4 and later) or close the RivaTuner Statistics Server application.
For more information on how to solve this problem, click the 'Help' button.""",
"https://github.com/CaffeineMC/sodium-fabric/wiki/Known-Issues#rtss-incompatible");

throw new RuntimeException("RivaTuner Statistics Server (RTSS) is not compatible with Sodium, " +
throw new RuntimeException("The installed version of RivaTuner Statistics Server (RTSS) is not compatible with Sodium, " +
"see here for more details: https://github.com/CaffeineMC/sodium-fabric/wiki/Known-Issues#rtss-incompatible");
}
}

// BUG: For some reason, the version string can either be in the format of "X.Y.Z.W" or "X, Y, Z, W"...
// This does not make sense, and probably points to our handling of code pages being wrong. But for the time being,
// the regex has been made to handle both formats, because looking at Win32 code any longer is going to break me.
private static final Pattern RTSS_VERSION_PATTERN = Pattern.compile("^(?<x>\\d*)(, |\\.)(?<y>\\d*)(, |\\.)(?<z>\\d*)(, |\\.)(?<w>\\d*)$");

private static boolean isRTSSCompatible(String version) {
var matcher = RTSS_VERSION_PATTERN.matcher(version);

if (!matcher.matches()) {
return false;
}

try {
int x = Integer.parseInt(matcher.group("x"));
int y = Integer.parseInt(matcher.group("y"));
int z = Integer.parseInt(matcher.group("z"));

// >=7.3.4
return x > 7 || (x == 7 && y > 3) || (x == 7 && y == 3 && z >= 4);
} catch (NumberFormatException e) {
LOGGER.warn("Invalid version string: {}", version);
}
private static boolean isRTSSCompatible(WindowsFileVersion version) {
int x = version.x();
int y = version.y();
int z = version.z();

return false;
// >=7.3.4
return x > 7 || (x == 7 && y > 3) || (x == 7 && y == 3 && z >= 4);
}

private static String findRTSSModuleVersion() {
private static @Nullable WindowsFileVersion findRTSSModuleVersion() {
long module;

try {
Expand Down Expand Up @@ -141,21 +130,14 @@ private static String findRTSSModuleVersion() {
return null;
}

var translation = version.queryEnglishTranslation();

if (translation == null) {
LOGGER.warn("Couldn't find suitable translation");
return null;
}

var fileVersion = version.queryValue("FileVersion", translation);
var fileVersion = version.queryFixedFileInfo();

if (fileVersion == null) {
LOGGER.warn("Couldn't query file version");
return null;
}

return fileVersion;
return WindowsFileVersion.fromFileVersion(fileVersion);
}

private static boolean isModuleLoaded(List<WinNativeModuleUtil.NativeModule> modules, String[] names) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
package me.jellysquid.mods.sodium.client.compatibility.checks;

import me.jellysquid.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion;
import me.jellysquid.mods.sodium.client.gui.console.Console;
import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel;
import me.jellysquid.mods.sodium.client.compatibility.environment.GLContextInfo;
import net.minecraft.text.Text;
import net.minecraft.util.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

public static void onContextInitialized() {
checkContextImplementation();

// FIXME: This can be determined earlier, but we can't access the GUI classes in pre-launch
if (isUsingPojavLauncher()) {
Console.instance().logMessage(MessageLevel.SEVERE, Text.translatable("sodium.console.pojav_launcher"), 30.0);
LOGGER.error("It appears that PojavLauncher is being used with an OpenGL compatibility layer. This will " +
Expand All @@ -27,52 +23,6 @@ public static void onContextInitialized() {
}
}

private static void checkContextImplementation() {
GLContextInfo driver = GLContextInfo.create();

if (driver == null) {
LOGGER.warn("Could not retrieve identifying strings for OpenGL implementation");
return;
}

LOGGER.info("OpenGL Vendor: {}", driver.vendor());
LOGGER.info("OpenGL Renderer: {}", driver.renderer());
LOGGER.info("OpenGL Version: {}", driver.version());

if (!isSupportedNvidiaDriver(driver)) {
Console.instance()
.logMessage(MessageLevel.SEVERE, Text.translatable("sodium.console.broken_nvidia_driver"), 30.0);

LOGGER.error("The NVIDIA graphics driver appears to be out of date. This will likely cause severe " +
"performance issues and crashes when used with Sodium. The graphics driver should be updated to " +
"the latest version (version 536.23 or newer).");
}
}

// https://github.com/CaffeineMC/sodium-fabric/issues/1486
// The way which NVIDIA tries to detect the Minecraft process could not be circumvented until fairly recently
// So we require that an up-to-date graphics driver is installed so that our workarounds can disable the Threaded
// Optimizations driver hack.
private static boolean isSupportedNvidiaDriver(GLContextInfo driver) {
// The Linux driver has two separate branches which have overlapping version numbers, despite also having
// different feature sets. As a result, we can't reliably determine which Linux drivers are broken...
if (Util.getOperatingSystem() != Util.OperatingSystem.WINDOWS) {
return true;
}

var version = NvidiaDriverVersion.tryParse(driver);

if (version != null) {
return !version.isWithinRange(
new NvidiaDriverVersion(526, 47), // Broken in 526.47
new NvidiaDriverVersion(536, 23) // Fixed in 536.23
);
}

// If we couldn't determine the version, then it's supported either way.
return true;
}

// https://github.com/CaffeineMC/sodium-fabric/issues/1916
private static boolean isUsingPojavLauncher() {
if (System.getenv("POJAV_RENDERER") != null) {
Expand Down
Loading

0 comments on commit 87f165a

Please sign in to comment.