Skip to content

Commit

Permalink
Attempt to force windows to use the dedicated gpu instead of igpu
Browse files Browse the repository at this point in the history
  • Loading branch information
mcrcortex authored and mcrcortex committed May 19, 2024
1 parent cb73ef7 commit 970b3b2
Show file tree
Hide file tree
Showing 10 changed files with 541 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 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);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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;
Expand All @@ -9,6 +10,8 @@
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;

Expand All @@ -20,6 +23,11 @@ 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();

Expand Down Expand Up @@ -131,4 +139,38 @@ 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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class Gdi32 {
public static final long PFN_D3DKMTQueryAdapterInfo = apiGetFunctionAddressOptional(LIBRARY, "D3DKMTQueryAdapterInfo");
public static final long PFN_D3DKMTCloseAdapter = apiGetFunctionAddressOptional(LIBRARY, "D3DKMTCloseAdapter");
public static final long PFN_D3DKMTEnumAdapters = apiGetFunctionAddressOptional(LIBRARY, "D3DKMTEnumAdapters");
public static final long PFN_D3DKMTCacheHybridQueryValue = apiGetFunctionAddressOptional(LIBRARY, "D3DKMTCacheHybridQueryValue");
public static final long PFN_D3DKMTSetProperties = apiGetFunctionAddressOptional(LIBRARY, "D3DKMTSetProperties");

public static boolean isD3DKMTSupported() {
return PFN_D3DKMTQueryAdapterInfo != NULL && PFN_D3DKMTCloseAdapter != NULL && PFN_D3DKMTEnumAdapters != NULL;
Expand All @@ -36,4 +38,16 @@ public static boolean isD3DKMTSupported() {
Validate.isTrue(PFN_D3DKMTCloseAdapter != NULL);
return JNI.callPI(ptr, PFN_D3DKMTCloseAdapter);
}

//Undocumented
public static int /* NTSTATUS */ nD3DKMTCacheHybridQueryValue(long ptr /* D3DKMT_HYBRID_LIST */) {
Validate.isTrue(PFN_D3DKMTCacheHybridQueryValue != NULL);
return JNI.callPI(ptr, PFN_D3DKMTCacheHybridQueryValue);
}

//Undocumented
public static int /* NTSTATUS */ nD3DKMTSetProperties(long ptr /* D3DKMT_PROPERTIES */) {
Validate.isTrue(PFN_D3DKMTSetProperties != NULL);
return JNI.callPI(ptr, PFN_D3DKMTSetProperties);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -19,6 +20,7 @@

import static net.caffeinemc.mods.sodium.client.platform.windows.api.Gdi32.*;
import static net.caffeinemc.mods.sodium.client.platform.windows.api.d3dkmt.D3DKMTQueryAdapterInfoType.WDDM12.*;
import static net.caffeinemc.mods.sodium.client.platform.windows.api.d3dkmt.D3DKMTQueryAdapterInfoType.WDDM20.KMTQAITYPE_PHYSICALADAPTERDEVICEIDS;
import static org.lwjgl.system.MemoryUtil.memAddress;
import static org.lwjgl.system.MemoryUtil.memByteBuffer;

Expand All @@ -27,6 +29,7 @@ public class D3DKMT {

private static final boolean SUPPORTS_D3DKMT = VersionHelpers.IsWindowsVistaOrGreater() && Gdi32.isD3DKMTSupported();
private static final boolean SUPPORTS_QUERYING_ADAPTER_TYPE = VersionHelpers.IsWindows8OrGreater();
private static final boolean SUPPORTS_QUERYING_PCI_INFO = VersionHelpers.IsWindows10OrGreater();

public static List<WDDMAdapterInfo> findGraphicsAdapters() {
if (!SUPPORTS_D3DKMT) {
Expand Down Expand Up @@ -55,7 +58,7 @@ public static List<WDDMAdapterInfo> findGraphicsAdapters() {
var pAdapterInfo = adapterInfoBuffer.get(adapterIndex);
int pAdapter = pAdapterInfo.getAdapterHandle();

var parsed = getAdapterInfo(pAdapter);
var parsed = getAdapterInfo(pAdapter, pAdapterInfo.getLuid());

if (parsed != null) {
results.add(parsed);
Expand All @@ -73,7 +76,7 @@ private static void freeAdapters(@NotNull D3DKMTAdapterInfoStruct.Buffer adapter
}
}

private static @Nullable D3DKMT.WDDMAdapterInfo getAdapterInfo(int adapter) {
private static @Nullable D3DKMT.WDDMAdapterInfo getAdapterInfo(int adapter, long luid) {
int adapterType = -1;

if (SUPPORTS_QUERYING_ADAPTER_TYPE) {
Expand All @@ -96,7 +99,12 @@ private static void freeAdapters(@NotNull D3DKMTAdapterInfoStruct.Buffer adapter
driverVendor = GraphicsAdapterVendor.fromIcdName(getOpenGlIcdName(driverFileName));
}

return new WDDMAdapterInfo(driverVendor, adapterName, adapterType, driverFileName, driverVersion);
PciInfo pciInfo = null;
if (SUPPORTS_QUERYING_PCI_INFO) {
pciInfo = queryPciInfo(adapter, 0);
}

return new WDDMAdapterInfo(driverVendor, adapterName, adapterType, luid, driverFileName, driverVersion, pciInfo);

}

Expand Down Expand Up @@ -163,6 +171,21 @@ private static int queryAdapterType(int adapter) {
}
}

private static PciInfo queryPciInfo(int adapter, int physicalAdapterIndex) {
try (MemoryStack stack = MemoryStack.stackPush()) {
var queryDeviceIds = D3DKMTQueryDeviceIdsStruct.calloc(stack);
queryDeviceIds.setPhysicalAdapterIndex(0);
d3dkmtQueryAdapterInfo(adapter, KMTQAITYPE_PHYSICALADAPTERDEVICEIDS, memByteBuffer(queryDeviceIds));

var deviceIds = queryDeviceIds.getDeviceIds();


return new PciInfo(deviceIds.getVendorId(),
deviceIds.getDeviceId(),
(deviceIds.getSubSystemId()<<16)|deviceIds.getSubVendorId());
}
}

private static void d3dkmtQueryAdapterInfo(int adapter, int type, ByteBuffer holder) {
try (MemoryStack stack = MemoryStack.stackPush()) {
var info = D3DKMTQueryAdapterInfoStruct.malloc(stack);
Expand All @@ -175,6 +198,39 @@ private static void d3dkmtQueryAdapterInfo(int adapter, int type, ByteBuffer hol
}
}

public static void d3dkmtCacheHybridQueryValue(long luid, int state, boolean userPreferenceQuery, int queryType) {
try (MemoryStack stack = MemoryStack.stackPush()) {
var info = D3DKMTHybridListStruct.malloc(stack);
info.setAdapterLuid(luid);
info.setState(state);
info.setbUserPreferenceQuery(userPreferenceQuery);
info.setQueryType(queryType);

apiCheckError("D3DKMTCacheHybridQueryValue", nD3DKMTCacheHybridQueryValue(info.address()));
}
}

private static void d3dkmtSetProperties(int type, ByteBuffer payload) {
try (MemoryStack stack = MemoryStack.stackPush()) {
var properties = D3DKMTProperties.calloc(stack);
properties.setType(type);
properties.setSize(payload.remaining());
properties.setPointer(memAddress(payload));

apiCheckError("D3DKMTSetProperties", nD3DKMTSetProperties(properties.address()));
}
}

public static void setPciProperties(int type, PciInfo info) {
try (MemoryStack stack = MemoryStack.stackPush()) {
var pci = D3DKMTPciStruct.calloc(stack);
pci.setDevice(info.device);
pci.setVendor(info.vendor);
pci.setSubSys(info.subsys);
d3dkmtSetProperties(type, MemoryUtil.memByteBuffer(pci.address(), pci.sizeof()));//Cannot figure out how to do this nicely
}
}

private static int d3dkmtCloseAdapter(int handle) {
try (var stack = MemoryStack.stackPush()) {
var info = stack.ints(handle);
Expand All @@ -188,21 +244,34 @@ private static void apiCheckError(String name, int error) {
}
}

public record PciInfo(
int vendor,
int device,
int subsys) {
@Override
public String toString() {
return String.format("PciInfo{%X&%X&%X}", this.vendor, this.device, this.subsys);
}
}


public record WDDMAdapterInfo(
@NotNull GraphicsAdapterVendor vendor,
@NotNull String name,
int adapterType,
long luid,
String openglIcdFilePath,
WindowsFileVersion openglIcdVersion
WindowsFileVersion openglIcdVersion,
PciInfo pciInfo
) implements GraphicsAdapterInfo {
public String getOpenGlIcdName() {
return D3DKMT.getOpenGlIcdName(this.name);
}

@Override
public String toString() {
return "AdapterInfo{vendor=%s, description='%s', adapterType=0x%08X, openglIcdFilePath='%s', openglIcdVersion=%s}"
.formatted(this.vendor, this.name, this.adapterType, this.openglIcdFilePath, this.openglIcdVersion);
return "AdapterInfo{vendor=%s, description='%s', adapterType=0x%08X, openglIcdFilePath='%s', openglIcdVersion=%s, pciInfo=%s}"
.formatted(this.vendor, this.name, this.adapterType, this.openglIcdFilePath, this.openglIcdVersion, this.pciInfo);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ public int getAdapterHandle() {
return memGetInt(this.address + OFFSET_HADAPTER);
}

public long getLuid() {
return memGetInt(this.address + OFFSET_ADAPTER_LUID);
}

@Override
public int sizeof() {
return SIZEOF;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package net.caffeinemc.mods.sodium.client.platform.windows.api.d3dkmt;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.system.Struct;

import java.nio.ByteBuffer;

import static org.lwjgl.system.MemoryUtil.*;

// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/d3dkmthk/ns-d3dkmthk-_d3dkmt_device_ids
//typedef struct _D3DKMT_DEVICE_IDS {
// UINT VendorID;
// UINT DeviceID;
// UINT SubVendorID;
// UINT SubSystemID;
// UINT RevisionID;
// UINT BusType;
//} D3DKMT_DEVICE_IDS;
public class D3DKMTDeviceIdsStruct extends Struct<D3DKMTDeviceIdsStruct> {
public static final int SIZEOF, ALIGNOF;

private static final int OFFSET_VENDORID;
private static final int OFFSET_DEVICEID;
private static final int OFFSET_SUBVENDORID;
private static final int OFFSET_SUBSYSTEMID;
private static final int OFFSET_REVISIONID;
private static final int OFFSET_BUSTYPE;

static {
var layout = __struct(
__member(Integer.BYTES),
__member(Integer.BYTES),
__member(Integer.BYTES),
__member(Integer.BYTES),
__member(Integer.BYTES),
__member(Integer.BYTES)
);

SIZEOF = layout.getSize();
ALIGNOF = layout.getAlignment();

OFFSET_VENDORID = layout.offsetof(0);
OFFSET_DEVICEID = layout.offsetof(1);
OFFSET_SUBVENDORID = layout.offsetof(2);
OFFSET_SUBSYSTEMID = layout.offsetof(3);
OFFSET_REVISIONID = layout.offsetof(4);
OFFSET_BUSTYPE = layout.offsetof(5);
}

public D3DKMTDeviceIdsStruct(long address, @Nullable ByteBuffer container) {
super(address, container);
}

@Override
protected @NotNull D3DKMTDeviceIdsStruct create(long address, ByteBuffer container) {
return new D3DKMTDeviceIdsStruct(address, container);
}

public static D3DKMTDeviceIdsStruct calloc() {
return new D3DKMTDeviceIdsStruct(MemoryUtil.nmemCalloc(1, SIZEOF), null);
}

public static D3DKMTDeviceIdsStruct calloc(MemoryStack stack) {
return new D3DKMTDeviceIdsStruct(stack.ncalloc(ALIGNOF, 1, SIZEOF), null);
}

@Override
public int sizeof() {
return SIZEOF;
}


public int getVendorId() {
return memGetInt(this.address + OFFSET_VENDORID);
}

public int getDeviceId() {
return memGetInt(this.address + OFFSET_DEVICEID);
}

public int getSubVendorId() {
return memGetInt(this.address + OFFSET_SUBVENDORID);
}

public int getSubSystemId() {
return memGetInt(this.address + OFFSET_SUBSYSTEMID);
}
}
Loading

0 comments on commit 970b3b2

Please sign in to comment.