Skip to content

Commit

Permalink
feat!: dxvk support
Browse files Browse the repository at this point in the history
  • Loading branch information
vapidinfinity committed Jan 14, 2025
1 parent 56206b4 commit 4115d2a
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 18 deletions.
8 changes: 6 additions & 2 deletions Mythic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
5A62AE982C27DB1200BA31D2 /* GameListEvoVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A62AE972C27DB1200BA31D2 /* GameListEvoVM.swift */; };
5A9573AA2C29BBEC009C8F85 /* SparkleController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A9573A92C29BBEC009C8F85 /* SparkleController.swift */; };
6A0688442C2BCE8B004DF10F /* DownloadCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0688432C2BCE87004DF10F /* DownloadCard.swift */; };
6A08A29B2D36E0B800E6AEFB /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A08A29A2D36E0B500E6AEFB /* FileManager.swift */; };
6A12FF8E2B73AC4E00AA948C /* Glur in Frameworks */ = {isa = PBXBuildFile; productRef = 6A12FF8D2B73AC4E00AA948C /* Glur */; };
6A1357B32CE4B0CD00B19213 /* SemanticVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A1357B22CE4B0C900B19213 /* SemanticVersion.swift */; };
6A2935322BFCFAFD0035CE4B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A2934AE2BFCFAFD0035CE4B /* Preview Assets.xcassets */; };
Expand Down Expand Up @@ -113,6 +114,7 @@
5A62AE972C27DB1200BA31D2 /* GameListEvoVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameListEvoVM.swift; sourceTree = "<group>"; };
5A9573A92C29BBEC009C8F85 /* SparkleController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SparkleController.swift; sourceTree = "<group>"; };
6A0688432C2BCE87004DF10F /* DownloadCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadCard.swift; sourceTree = "<group>"; };
6A08A29A2D36E0B500E6AEFB /* FileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = "<group>"; };
6A1357B22CE4B0C900B19213 /* SemanticVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SemanticVersion.swift; sourceTree = "<group>"; };
6A2934AE2BFCFAFD0035CE4B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
6A2934B02BFCFAFD0035CE4B /* Engine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Engine.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -424,6 +426,7 @@
6AD44DE52C0A29BF00824C06 /* Built-in */ = {
isa = PBXGroup;
children = (
6A08A29A2D36E0B500E6AEFB /* FileManager.swift */,
6ACFAD8A2D356910009B1554 /* Bool.swift */,
6A1357B22CE4B0C900B19213 /* SemanticVersion.swift */,
6A2960FF2CE1033000917E90 /* NSWindow.swift */,
Expand Down Expand Up @@ -600,6 +603,7 @@
6A2935612BFCFAFD0035CE4B /* GameListViewEvo.swift in Sources */,
6A29354F2BFCFAFD0035CE4B /* DownloadsViewEvo.swift in Sources */,
6A496A732C1AF75B00FD637B /* Game.swift in Sources */,
6A08A29B2D36E0B800E6AEFB /* FileManager.swift in Sources */,
6A2935602BFCFAFD0035CE4B /* ContainerListView.swift in Sources */,
6A29355E2BFCFAFD0035CE4B /* StopDownloadAlert.swift in Sources */,
6A2935662BFCFAFD0035CE4B /* AppDelegate.swift in Sources */,
Expand Down Expand Up @@ -801,7 +805,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 3276;
CURRENT_PROJECT_VERSION = 3278;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "\"Mythic/Preview Content\"";
Expand Down Expand Up @@ -848,7 +852,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 3276;
CURRENT_PROJECT_VERSION = 3278;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "\"Mythic/Preview Content\"";
Expand Down
15 changes: 15 additions & 0 deletions Mythic/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -6126,6 +6126,9 @@
}
}
}
},
"Asynchronous DXVK" : {

},
"Automatically check for Mythic Engine updates" : {
"localizations" : {
Expand Down Expand Up @@ -11268,6 +11271,12 @@
}
}
}
},
"DXVK" : {

},
"DXVK cannot be modified: %@" : {

},
"Engine" : {

Expand Down Expand Up @@ -26707,6 +26716,9 @@
}
}
}
},
"Quit games running in this container?" : {

},
"Remove" : {
"localizations" : {
Expand Down Expand Up @@ -35080,6 +35092,9 @@
}
}
}
},
"To toggle DXVK, Mythic must quit all games currently running in this container.\nAdditionally, D3DMetal will be disabled.\n\nToggling DXVK may impact compatibility positively or negatively." : {

},
"Unable to locate %@ at its specified path (%@)" : {
"localizations" : {
Expand Down
16 changes: 16 additions & 0 deletions Mythic/Utilities/Extensions/Built-in/FileManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// FileManager.swift
// Mythic
//
// Created by vapidinfinity (esi) on 15/1/2025.
//

import Foundation

extension FileManager {
func removeItemIfExists(at url: URL) throws {
if files.fileExists(atPath: url.path) {
try files.removeItem(at: url)
}
}
}
12 changes: 10 additions & 2 deletions Mythic/Utilities/Legendary/LegendaryInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,16 @@ final class Legendary {
if case .windows = game.platform {
arguments += ["--wine", Engine.directory.appending(path: "wine/bin/wine64").path]
environmentVariables["WINEPREFIX"] = container.url.path(percentEncoded: false)
environmentVariables["WINEMSYNC"] = container.settings.msync ? "1" : "0"
environmentVariables["ROSETTA_ADVERTISE_AVX"] = container.settings.avx2 ? "1" : "0"
environmentVariables["WINEMSYNC"] = "\(container.settings.msync.numericalValue)"
environmentVariables["ROSETTA_ADVERTISE_AVX"] = "\(container.settings.avx2.numericalValue)"

if container.settings.dxvk {
environmentVariables["WINEDLLOVERRIDES"] = "d3d10core,d3d11=n,b"

if container.settings.dxvkAsync {
environmentVariables["DXVK_ASYNC"] = "1"
}
}
}

arguments.append(contentsOf: ["--"] + game.launchArguments)
Expand Down
25 changes: 18 additions & 7 deletions Mythic/Utilities/Local/LocalGames.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,28 @@ final class LocalGames {
guard Engine.exists else { throw Engine.NotInstalledError() }
guard let containerURL = game.containerURL else { throw Wine.ContainerDoesNotExistError() } // FIXME: Container Revamp
let container = try Wine.getContainerObject(url: containerURL)


var environmentVariables = [
"MTL_HUD_ENABLED": "\(container.settings.metalHUD.numericalValue)",
"WINEMSYNC": "\(container.settings.msync.numericalValue)",
"ROSETTA_ADVERTISE_AVX": "\(container.settings.avx2.numericalValue)"
]

if container.settings.dxvk {
environmentVariables["WINEDLLOVERRIDES"] = "d3d10core,d3d11=n,b"

if container.settings.dxvkAsync {
environmentVariables["DXVK_ASYNC"] = "1"
}
}

try await Wine.command(
arguments: [game.path!] + game.launchArguments,
identifier: "launch_\(game.title)",
containerURL: container.url,
environment: [
"MTL_HUD_ENABLED": container.settings.metalHUD ? "1" : "0",
"WINEMSYNC": container.settings.msync ? "1" : "0",
"ROSETTA_ADVERTISE_AVX": container.settings.avx2 ? "1" : "0",
]
) { _ in }
environment: environmentVariables,
completion: { _ in }
)

case .none:
do { } // this should never happen
Expand Down
6 changes: 3 additions & 3 deletions Mythic/Utilities/Wine/WineInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ final class Wine { // TODO: https://forum.winehq.org/viewtopic.php?t=15416
}

/// The directory where all wine prefixes/containers related to Mythic are stored.
static let containersDirectory: URL? = {
static var containersDirectory: URL? {
let directory = Bundle.appContainer!.appending(path: "Containers")
if files.fileExists(atPath: directory.path) {
return directory
Expand All @@ -58,8 +58,8 @@ final class Wine { // TODO: https://forum.winehq.org/viewtopic.php?t=15416
return nil
}
}
}()
}

static var containerURLs: Set<URL> {
get {
return .init((try? defaults.decodeAndGet([URL].self, forKey: "containerURLs")) ?? [])
Expand Down
104 changes: 100 additions & 4 deletions Mythic/Views/Unified/Sheets/ContainerSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@

import SwiftUI

// TODO: refactor
struct ContainerSettingsView: View {
// TODO: Add DXVK
// TODO: FSR 3?

@Binding var selectedContainerURL: URL?
var withPicker: Bool

Expand All @@ -30,7 +28,11 @@ struct ContainerSettingsView: View {
@State private var retinaMode: Bool = Wine.ContainerSettings().retinaMode
@State private var modifyingRetinaMode: Bool = true
@State private var retinaModeError: Error?


@State private var isDXVKDisclaimerPresented: Bool = false
@State private var modifyingDXVK: Bool = false
@State private var dxvkError: Error?

@State private var windowsVersion: Wine.WindowsVersion = Wine.ContainerSettings().windowsVersion
@State private var modifyingWindowsVersion: Bool = true
@State private var windowsVersionError: Error?
Expand Down Expand Up @@ -142,6 +144,100 @@ struct ContainerSettingsView: View {
return "AVX2 is only supported on macOS Sequoia (15) or later."
}())

if !modifyingDXVK, dxvkError == nil {
Toggle("DXVK", isOn: Binding(
get: { container.settings.dxvk },
set: { newValue in
isDXVKDisclaimerPresented = true
}
))
.alert(isPresented: $isDXVKDisclaimerPresented) {
.init(
title: .init("Quit games running in this container?"),
message: .init("""
To toggle DXVK, Mythic must quit all games currently running in this container.
Additionally, D3DMetal will be disabled.
Toggling DXVK may impact compatibility positively or negatively.
"""),
primaryButton: .default(.init("OK")) {
Task(priority: .userInitiated) {
do {
print("begin mod")
withAnimation { modifyingDXVK = true }

print(container.url.appending(path: "drive_c/windows/system32/d3d10core.dll").path)
// x64
try files.removeItemIfExists(at: container.url.appending(path: "drive_c/windows/system32/d3d10core.dll"))
try files.removeItemIfExists(at: container.url.appending(path: "drive_c/windows/system32/d3d11.dll"))
print("cleared x64")

// x32
try files.removeItemIfExists(at: container.url.appending(path: "drive_c/windows/syswow64/d3d10core.dll"))
try files.removeItemIfExists(at: container.url.appending(path: "drive_c/windows/syswow64/d3d11.dll"))
print("sayonara❤️")

if container.settings.dxvk {
try await Wine.command(
arguments: ["wineboot", "-u"],
identifier: "dxvkRestore",
containerURL: container.url,
completion: { _ in }
)
} else {
// x64
try files.copyItem(
at: Engine.directory.appending(path: "DXVK/x64/d3d10core.dll"),
to: container.url.appending(path: "drive_c/windows/system32")
)
try files.copyItem(
at: Engine.directory.appending(path: "DXVK/x64/d3d11.dll"),
to: container.url.appending(path: "drive_c/windows/system32")
)

// x32
try files.copyItem(
at: Engine.directory.appending(path: "DXVK/x32/d3d10core.dll"),
to: container.url.appending(path: "drive_c/windows/syswow64")
)
try files.copyItem(
at: Engine.directory.appending(path: "DXVK/x32/d3d11.dll"),
to: container.url.appending(path: "drive_c/windows/syswow64")
)
}

container.settings.dxvk.toggle()
withAnimation { modifyingDXVK = false }
} catch {
dxvkError = error
}
}
},
secondaryButton: .cancel()
)
}
} else {
HStack {
Text("DXVK")
Spacer()
if dxvkError == nil {
ProgressView()
.controlSize(.small)
} else {
Image(systemName: "exclamationmark.triangle")
.symbolVariant(.fill)
.controlSize(.small)
.help("DXVK cannot be modified: \(dxvkError?.localizedDescription ?? "Unknown Error.")")
}
}
}

Toggle("Asynchronous DXVK", isOn: Binding(
get: { container.settings.dxvkAsync },
set: { container.settings.dxvkAsync = $0 }
))
.disabled(!container.settings.dxvk)

if !modifyingWindowsVersion, windowsVersionError == nil {
Picker("Windows Version", selection: Binding(
get: { windowsVersion },
Expand Down

0 comments on commit 4115d2a

Please sign in to comment.