mirror of
https://github.com/utmapp/UTM.git
synced 2026-10-12 02:24:01 +00:00
Merge pull request #7800 from utmapp/dev/neptune
project: add DirectX support for Windows guests
This commit is contained in:
@@ -147,6 +147,9 @@ jobs:
|
||||
if: steps.cache-sysroot-universal.outputs.cache-matched-key == ''
|
||||
run: |
|
||||
./scripts/pack_dependencies.sh . macos arm64 x86_64
|
||||
- name: Install D3DMetal
|
||||
if: steps.cache-sysroot-universal.outputs.cache-matched-key == '' || github.event_name == 'release' || github.event.inputs.test_release == 'true' || github.event.inputs.rebuild_sysroot == 'true'
|
||||
run: ./scripts/install_d3dmetal.sh sysroot-macOS-arm64_x86_64 "${{ secrets.D3DM_DIST_DMG_URL || vars.D3DM_DIST_DMG_URL }}"
|
||||
- name: Compress Sysroot
|
||||
if: steps.cache-sysroot-universal.outputs.cache-matched-key == '' || github.event_name == 'release' || github.event.inputs.test_release == 'true' || github.event.inputs.rebuild_sysroot == 'true'
|
||||
run: tar -acf sysroot.tgz sysroot-macOS-arm64_x86_64
|
||||
|
||||
@@ -43,7 +43,7 @@ must apply unprompted — they override default behavior and are easy to violate
|
||||
`Assisted-by: AGENT:MODEL` trailer (e.g. `Assisted-by: Claude:claude-opus-4-8`) —
|
||||
add it explicitly **even if your agent doesn't normally inject attribution
|
||||
trailers**; the absence of a default trailer is not an excuse to omit it. Never
|
||||
add `Co-authored-by` (strip any a tool adds). Commit titles are
|
||||
add `Co-authored-by` or session links (strip any a tool adds). Commit titles are
|
||||
`component: short description` explaining *why*.
|
||||
- **Scope:** one feature/fix per PR; don't touch, refactor, or reformat unrelated
|
||||
files; route new logging through `UTMLogging`/`logging` at `debug` level.
|
||||
|
||||
@@ -39,3 +39,6 @@ LAUNCHER_CODE_SIGN_ENTITLEMENTS = $(LAUNCHER_CODE_SIGN_ENTITLEMENTS_$(DEVELOPER_
|
||||
CLI_CODE_SIGN_ENTITLEMENTS_YES = utmctl/utmctl.entitlements
|
||||
CLI_CODE_SIGN_ENTITLEMENTS_NO = utmctl/utmctl-unsigned.entitlements
|
||||
CLI_CODE_SIGN_ENTITLEMENTS = $(CLI_CODE_SIGN_ENTITLEMENTS_$(DEVELOPER_ACCOUNT_VM_ACCESS:default=NO))
|
||||
RENDERER_CODE_SIGN_ENTITLEMENTS_YES = QEMURenderServer/QEMURenderServer.entitlements
|
||||
RENDERER_CODE_SIGN_ENTITLEMENTS_NO = QEMURenderServer/QEMURenderServer-unsigned.entitlements
|
||||
RENDERER_CODE_SIGN_ENTITLEMENTS = $(RENDERER_CODE_SIGN_ENTITLEMENTS_$(DEVELOPER_ACCOUNT_VM_ACCESS:default=NO))
|
||||
|
||||
@@ -27,13 +27,21 @@ import Virtualization // for getting network interfaces
|
||||
private func f(_ string: String = "") -> QEMUArgumentFragment {
|
||||
QEMUArgumentFragment(final: string)
|
||||
}
|
||||
|
||||
|
||||
/// Shared group ID for main process and helper
|
||||
var appGroupIdentifier: String? {
|
||||
let appGroup = Bundle.main.infoDictionary?["AppGroupIdentifier"] as? String
|
||||
if let appGroup, !appGroup.hasPrefix("invalid.") {
|
||||
return appGroup
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Shared between helper and main process to store Unix sockets
|
||||
var socketURL: URL {
|
||||
#if os(iOS) || os(visionOS)
|
||||
return FileManager.default.temporaryDirectory
|
||||
#else
|
||||
let appGroup = Bundle.main.infoDictionary?["AppGroupIdentifier"] as? String
|
||||
let helper = Bundle.main.infoDictionary?["HelperIdentifier"] as? String
|
||||
// default to unsigned sandbox path
|
||||
var parentURL: URL = FileManager.default.homeDirectoryForCurrentUser
|
||||
@@ -42,7 +50,7 @@ import Virtualization // for getting network interfaces
|
||||
parentURL.appendPathComponent(helper ?? "com.utmapp.QEMUHelper")
|
||||
parentURL.appendPathComponent("Data")
|
||||
parentURL.appendPathComponent("tmp")
|
||||
if let appGroup = appGroup, !appGroup.hasPrefix("invalid.") {
|
||||
if let appGroup = appGroupIdentifier {
|
||||
if let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) {
|
||||
return containerURL
|
||||
}
|
||||
@@ -276,10 +284,25 @@ import Virtualization // for getting network interfaces
|
||||
"edid=on"
|
||||
}
|
||||
if isDisplayGLSupported(display) && isVulkanSupported {
|
||||
#if os(macOS)
|
||||
"hostmem=8G"
|
||||
#else
|
||||
"hostmem=256M"
|
||||
#endif
|
||||
"blob=true"
|
||||
"venus=true"
|
||||
}
|
||||
if isDisplayGLSupported(display) && isNeptuneSupported {
|
||||
if !isVulkanSupported {
|
||||
#if os(macOS)
|
||||
"hostmem=8G"
|
||||
#else
|
||||
"hostmem=256M"
|
||||
#endif
|
||||
"blob=true"
|
||||
}
|
||||
"neptune=true"
|
||||
}
|
||||
f()
|
||||
}
|
||||
}
|
||||
@@ -322,12 +345,27 @@ import Virtualization // for getting network interfaces
|
||||
return UTMQEMUVulkanDriver(rawValue: rawValue) ?? .qemuVulkanDriverDefault
|
||||
}
|
||||
|
||||
private var directXDriver: UTMQEMUDirectXDriver {
|
||||
let rawValue = UserDefaults.standard.integer(forKey: "QEMUDirectXDriver")
|
||||
return UTMQEMUDirectXDriver(rawValue: rawValue) ?? .qemuDirectXDriverDefault
|
||||
}
|
||||
|
||||
private var isVulkanSupported: Bool {
|
||||
isGLSupported &&
|
||||
(rendererBackend == .qemuRendererBackendAngleMetal || rendererBackend == .qemuRendererBackendDefault) &&
|
||||
vulkanDriver != .qemuVulkanDriverDisabled
|
||||
}
|
||||
|
||||
private var isNeptuneSupported: Bool {
|
||||
#if os(macOS)
|
||||
isGLSupported &&
|
||||
(rendererBackend == .qemuRendererBackendAngleMetal || rendererBackend == .qemuRendererBackendDefault) &&
|
||||
directXDriver != .qemuDirectXDriverDisabled
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
}
|
||||
|
||||
private var isSparc: Bool {
|
||||
system.architecture == .sparc || system.architecture == .sparc64
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ import Foundation
|
||||
class UTMDownloadSupportToolsTask: UTMDownloadTask {
|
||||
private let vm: any UTMSpiceVirtualMachine
|
||||
|
||||
private static let supportToolsDownloadUrl = URL(string: "https://getutm.app/downloads/utm-guest-tools-latest.iso")!
|
||||
|
||||
private static let supportToolsDownloadUrl = URL(string: "https://getutm.app/downloads/utm-guest-tools-3d-latest.iso")!
|
||||
|
||||
private var toolsUrl: URL {
|
||||
fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!.appendingPathComponent("GuestSupportTools")
|
||||
}
|
||||
|
||||
@@ -144,5 +144,7 @@
|
||||
</dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>AppGroupIdentifier</key>
|
||||
<string>group.$(PRODUCT_BUNDLE_PREFIX:default=com.utmapp).UTM</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.kernel.increased-memory-limit</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.kernel.increased-memory-limit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.$(PRODUCT_BUNDLE_PREFIX:default=com.utmapp).UTM</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -211,12 +211,26 @@ struct DisplaySettingsView: View {
|
||||
@AppStorage("NoSaveScreenshot") var isNoSaveScreenshot = false
|
||||
@AppStorage("QEMURendererBackend") var qemuRendererBackend: UTMQEMURendererBackend = .qemuRendererBackendDefault
|
||||
@AppStorage("QEMUVulkanDriver") var qemuVulkanDriver: UTMQEMUVulkanDriver = .qemuVulkanDriverDefault
|
||||
@AppStorage("QEMUDirectXDriver") var qemuDirectXDriver: UTMQEMUDirectXDriver = .qemuDirectXDriverDefault
|
||||
@AppStorage("QEMURendererFPSLimit") var qemuRendererFpsLimit: Int = 0
|
||||
|
||||
private var isVulkanSupported: Bool {
|
||||
qemuRendererBackend == .qemuRendererBackendDefault || qemuRendererBackend == .qemuRendererBackendAngleMetal
|
||||
}
|
||||
|
||||
private static var hasD3DMetal: Bool = {
|
||||
let d3dMetalFramework = Bundle.main.bundleURL.appendingPathComponent("Contents/Frameworks/D3DMetal.framework")
|
||||
return FileManager.default.fileExists(atPath: d3dMetalFramework.path)
|
||||
}()
|
||||
|
||||
private var isD3DMetalAvailable: Bool {
|
||||
if qemuDirectXDriver == .qemuDirectXDriverD3DMetal {
|
||||
return true // always show option if already selected
|
||||
} else {
|
||||
return Self.hasD3DMetal
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Display")) {
|
||||
@@ -253,6 +267,20 @@ struct DisplaySettingsView: View {
|
||||
qemuVulkanDriver = .qemuVulkanDriverDefault
|
||||
}
|
||||
}
|
||||
Picker("DirectX Driver", selection: $qemuDirectXDriver) {
|
||||
Text("Default").tag(UTMQEMUDirectXDriver.qemuDirectXDriverDefault)
|
||||
Text("Disabled").tag(UTMQEMUDirectXDriver.qemuDirectXDriverDisabled)
|
||||
Text("DXMT").tag(UTMQEMUDirectXDriver.qemuDirectXDriverDXMT)
|
||||
if isD3DMetalAvailable {
|
||||
Text("D3DMetal").tag(UTMQEMUDirectXDriver.qemuDirectXDriverD3DMetal)
|
||||
}
|
||||
}.help("Select the DirectX driver to use for host passthrough rendering. DirectX requires guest drivers to be installed.")
|
||||
.disabled(!isVulkanSupported)
|
||||
.onChange(of: qemuRendererBackend) { _ in
|
||||
if !isVulkanSupported {
|
||||
qemuDirectXDriver = .qemuDirectXDriverDefault
|
||||
}
|
||||
}
|
||||
if !isVulkanSupported {
|
||||
Text("The selected renderer backend does not support Vulkan.")
|
||||
}
|
||||
|
||||
@@ -128,7 +128,9 @@ static const int64_t kProcessTerminateTimeoutSeconds = 1;
|
||||
task.standardOutput = standardOutput;
|
||||
task.standardError = standardError;
|
||||
NSMutableDictionary<NSString *, NSString *> *environment = [NSMutableDictionary dictionary];
|
||||
NSURL *renderServerURL = [[[NSBundle mainBundle] URLForAuxiliaryExecutable:@"QEMURenderServer.app"] URLByAppendingPathComponent:@"Contents/MacOS/QEMURenderServer"];
|
||||
environment[@"TMPDIR"] = NSFileManager.defaultManager.temporaryDirectory.path;
|
||||
environment[@"RENDER_SERVER_EXEC_PATH"] = renderServerURL.path;
|
||||
if (self.environment) {
|
||||
[environment addEntriesFromDictionary:self.environment];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<key>com.apple.security.inherit</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.inherit</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -26,7 +26,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, nullable) NSDictionary<NSURL *, NSData *> *remoteBookmarks;
|
||||
@property (nonatomic) UTMQEMURendererBackend rendererBackend;
|
||||
@property (nonatomic) UTMQEMUVulkanDriver vulkanDriver;
|
||||
@property (nonatomic) UTMQEMUDirectXDriver directXDriver;
|
||||
@property (nonatomic) NSURL *shmemDirectoryURL;
|
||||
@property (nonatomic, nullable) NSString *appSandboxGroupId;
|
||||
@property (nonatomic, weak) id<QEMULauncherDelegate> launcherDelegate;
|
||||
@property (nonatomic, nullable) QEMULogging *logging;
|
||||
@property (nonatomic) BOOL hasDebugLog;
|
||||
|
||||
@@ -58,7 +58,6 @@ static int startQemu(UTMProcess *process, int argc, const char *argv[], const ch
|
||||
}
|
||||
|
||||
- (void)setVulkanDriver:(UTMQEMUVulkanDriver)vulkanDriver {
|
||||
_vulkanDriver = vulkanDriver;
|
||||
NSURL *vulkanIcds = [[NSBundle.mainBundle URLForResource:@"vulkan" withExtension:nil] URLByAppendingPathComponent:@"icd.d" isDirectory:YES];
|
||||
NSURL *driver;
|
||||
switch (vulkanDriver) {
|
||||
@@ -77,12 +76,86 @@ static int startQemu(UTMProcess *process, int argc, const char *argv[], const ch
|
||||
if (driver) {
|
||||
self.mutableEnvironment[@"VK_DRIVER_FILES"] = driver.path;
|
||||
self.resources = [self.resources arrayByAddingObject:driver];
|
||||
_vulkanDriver = vulkanDriver;
|
||||
} else {
|
||||
[self.mutableEnvironment removeObjectForKey:@"VK_DRIVER_FILES"];
|
||||
_vulkanDriver = kQEMUVulkanDriverDisabled;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDirectXDriver:(UTMQEMUDirectXDriver)directXDriver {
|
||||
NSString *backend;
|
||||
NSString *frameworkName;
|
||||
NSURL *library;
|
||||
switch (directXDriver) {
|
||||
case kQEMUDirectXDriverDefault:
|
||||
case kQEMUDirectXDriverDXMT:
|
||||
backend = @"dxmt";
|
||||
frameworkName = @"dxmt-native";
|
||||
break;
|
||||
case kQEMUDirectXDriverD3DMetal:
|
||||
backend = @"d3dmetal";
|
||||
frameworkName = @"d3dmetal-native";
|
||||
break;
|
||||
case kQEMUDirectXDriverDisabled:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (frameworkName) {
|
||||
NSURL *bundleURL = NSBundle.mainBundle.bundleURL;
|
||||
#if TARGET_OS_OSX
|
||||
NSURL *contentsURL = [bundleURL URLByAppendingPathComponent:@"Contents" isDirectory:YES];
|
||||
NSString *versionPath = @"Versions/A/";
|
||||
#else
|
||||
NSURL *contentsURL = bundleURL;
|
||||
NSString *versionPath = @"";
|
||||
#endif
|
||||
NSURL *frameworksURL = [contentsURL URLByAppendingPathComponent:@"Frameworks" isDirectory:YES];
|
||||
library = [frameworksURL URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.framework/%@%@", frameworkName, versionPath, frameworkName] isDirectory:NO];
|
||||
if (![NSFileManager.defaultManager fileExistsAtPath:library.path]) {
|
||||
UTMLog(@"DirectX driver '%@' is not available in this build", backend);
|
||||
backend = nil;
|
||||
library = nil;
|
||||
} else if (directXDriver == kQEMUDirectXDriverD3DMetal) {
|
||||
NSString *d3dMetal = @"D3DMetal";
|
||||
NSURL *d3dMetalURL = [frameworksURL URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.framework/%@%@", d3dMetal, versionPath, d3dMetal] isDirectory:NO];
|
||||
self.mutableEnvironment[@"D3DMETAL_FRAMEWORK_PATH"] = d3dMetalURL.path;
|
||||
self.resources = [self.resources arrayByAddingObject:d3dMetalURL];
|
||||
}
|
||||
}
|
||||
if (backend && library) {
|
||||
self.mutableEnvironment[@"NPT_D3D11_LIBRARY_PATH"] = library.path;
|
||||
self.mutableEnvironment[@"NPT_D3D12_LIBRARY_PATH"] = library.path;
|
||||
self.mutableEnvironment[@"NPT_DXGI_LIBRARY_PATH"] = library.path;
|
||||
self.mutableEnvironment[@"NPT_BACKEND"] = backend;
|
||||
self.resources = [self.resources arrayByAddingObject:library];
|
||||
_directXDriver = directXDriver;
|
||||
} else {
|
||||
[self.mutableEnvironment removeObjectForKey:@"NPT_D3D11_LIBRARY_PATH"];
|
||||
[self.mutableEnvironment removeObjectForKey:@"NPT_D3D12_LIBRARY_PATH"];
|
||||
[self.mutableEnvironment removeObjectForKey:@"NPT_DXGI_LIBRARY_PATH"];
|
||||
[self.mutableEnvironment removeObjectForKey:@"NPT_BACKEND"];
|
||||
[self.mutableEnvironment removeObjectForKey:@"D3DMETAL_FRAMEWORK_PATH"];
|
||||
_directXDriver = kQEMUDirectXDriverDisabled;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setShmemDirectoryURL:(NSURL *)shmemDirectoryURL {
|
||||
_shmemDirectoryURL = shmemDirectoryURL;
|
||||
self.mutableEnvironment[@"XDG_RUNTIME_DIR"] = shmemDirectoryURL.path;
|
||||
if (shmemDirectoryURL) {
|
||||
self.mutableEnvironment[@"XDG_RUNTIME_DIR"] = shmemDirectoryURL.path;
|
||||
} else {
|
||||
[self.mutableEnvironment removeObjectForKey:@"XDG_RUNTIME_DIR"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setAppSandboxGroupId:(NSString *)appSandboxGroupId {
|
||||
_appSandboxGroupId = appSandboxGroupId;
|
||||
if (appSandboxGroupId) {
|
||||
self.mutableEnvironment[@"APP_SANDBOX_GROUP_ID"] = appSandboxGroupId;
|
||||
} else {
|
||||
[self.mutableEnvironment removeObjectForKey:@"APP_SANDBOX_GROUP_ID"];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSPipe *)standardOutput {
|
||||
@@ -122,6 +195,9 @@ static int startQemu(UTMProcess *process, int argc, const char *argv[], const ch
|
||||
self.mutableEnvironment[@"MVK_CONFIG_LOG_LEVEL"] = @"4";
|
||||
self.mutableEnvironment[@"MVK_DEBUG"] = @"1";
|
||||
self.mutableEnvironment[@"MTL_DEBUG_LAYER"] = @"1";
|
||||
self.mutableEnvironment[@"MTL_DEBUG_LAYER_ERROR_MODE"] = @"nslog";
|
||||
self.mutableEnvironment[@"ANGLE_ENABLE_DEBUG_TRACE"] = @"1";
|
||||
self.mutableEnvironment[@"ANGLE_METAL_DEBUG_BINDINGS"] = @"1";
|
||||
} else {
|
||||
[self.mutableEnvironment removeObjectForKey:@"G_MESSAGES_DEBUG"];
|
||||
[self.mutableEnvironment removeObjectForKey:@"VK_LOADER_DEBUG"];
|
||||
@@ -130,6 +206,9 @@ static int startQemu(UTMProcess *process, int argc, const char *argv[], const ch
|
||||
[self.mutableEnvironment removeObjectForKey:@"MVK_CONFIG_LOG_LEVEL"];
|
||||
[self.mutableEnvironment removeObjectForKey:@"MVK_DEBUG"];
|
||||
[self.mutableEnvironment removeObjectForKey:@"MTL_DEBUG_LAYER"];
|
||||
[self.mutableEnvironment removeObjectForKey:@"MTL_DEBUG_LAYER_ERROR_MODE"];
|
||||
[self.mutableEnvironment removeObjectForKey:@"ANGLE_ENABLE_DEBUG_TRACE"];
|
||||
[self.mutableEnvironment removeObjectForKey:@"ANGLE_METAL_DEBUG_BINDINGS"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,4 +42,12 @@ typedef NS_ENUM(NSInteger, UTMQEMUVulkanDriver) {
|
||||
kQEMUVulkanDriverKosmicKrisp = 3,
|
||||
};
|
||||
|
||||
/// Specify the DirectX driver for this VM
|
||||
typedef NS_ENUM(NSInteger, UTMQEMUDirectXDriver) {
|
||||
kQEMUDirectXDriverDefault = 0,
|
||||
kQEMUDirectXDriverDisabled = 1,
|
||||
kQEMUDirectXDriverDXMT = 2,
|
||||
kQEMUDirectXDriverD3DMetal = 3,
|
||||
};
|
||||
|
||||
#endif /* UTMQemuSystemBackends_h */
|
||||
|
||||
@@ -254,6 +254,13 @@ extension UTMQemuVirtualMachine {
|
||||
}
|
||||
}
|
||||
|
||||
private var directXDriver: UTMQEMUDirectXDriver {
|
||||
get {
|
||||
let rawValue = UserDefaults.standard.integer(forKey: "QEMUDirectXDriver")
|
||||
return UTMQEMUDirectXDriver(rawValue: rawValue) ?? .qemuDirectXDriverDefault
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor private func qemuEnsureEfiVarsAvailable() async throws {
|
||||
guard let efiVarsURL = config.qemu.efiVarsURL else {
|
||||
return
|
||||
@@ -346,7 +353,9 @@ extension UTMQemuVirtualMachine {
|
||||
system.remoteBookmarks = remoteBookmarks
|
||||
system.rendererBackend = rendererBackend
|
||||
system.vulkanDriver = try vulkanDriver
|
||||
system.directXDriver = directXDriver
|
||||
system.shmemDirectoryURL = await config.shmemDirectoryURL
|
||||
system.appSandboxGroupId = await config.appGroupIdentifier
|
||||
system.hasDebugLog = hasDebugLog
|
||||
try Task.checkCancellation()
|
||||
|
||||
|
||||
+158
-11
@@ -52,7 +52,7 @@
|
||||
84018699288B71BF0050AC51 /* BusyIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84018696288B71BF0050AC51 /* BusyIndicator.swift */; };
|
||||
8401FD71269BEB2B00265F0D /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = CE6B240A25F1F3CE0020D43E /* main.c */; };
|
||||
8401FD72269BEB3000265F0D /* Bootstrap.c in Sources */ = {isa = PBXBuildFile; fileRef = CE0DF17125A80B6300A51894 /* Bootstrap.c */; };
|
||||
8401FD7A269BECE200265F0D /* QEMULauncher.app in Embed Launcher */ = {isa = PBXBuildFile; fileRef = 8401FD62269BE9C500265F0D /* QEMULauncher.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
8401FD7A269BECE200265F0D /* QEMULauncher.app in Embed Executables */ = {isa = PBXBuildFile; fileRef = 8401FD62269BE9C500265F0D /* QEMULauncher.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
8401FDA0269D266E00265F0D /* VMConfigAppleBootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8401FD9F269D266E00265F0D /* VMConfigAppleBootView.swift */; };
|
||||
8401FDA2269D3E2500265F0D /* VMConfigAppleNetworkingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8401FDA1269D3E2500265F0D /* VMConfigAppleNetworkingView.swift */; };
|
||||
8401FDA4269D43CF00265F0D /* VMConfigAppleDisplayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8401FDA3269D43CF00265F0D /* VMConfigAppleDisplayView.swift */; };
|
||||
@@ -735,6 +735,11 @@
|
||||
CE9B15482B12A87E003A32DD /* GenerateKey.c in Sources */ = {isa = PBXBuildFile; fileRef = CE9B15462B12A87E003A32DD /* GenerateKey.c */; };
|
||||
CE9B15492B12A87E003A32DD /* GenerateKey.c in Sources */ = {isa = PBXBuildFile; fileRef = CE9B15462B12A87E003A32DD /* GenerateKey.c */; };
|
||||
CE9B154A2B12A87E003A32DD /* GenerateKey.c in Sources */ = {isa = PBXBuildFile; fileRef = CE9B15462B12A87E003A32DD /* GenerateKey.c */; };
|
||||
CEA3EDEB3016810500AAA8E4 /* dxmt-native.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEA3EDE93016810500AAA8E4 /* dxmt-native.framework */; };
|
||||
CEA3EDEC3016810500AAA8E4 /* dxmt-native.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CEA3EDE93016810500AAA8E4 /* dxmt-native.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
CEA3EDED3016810500AAA8E4 /* d3dmetal-native.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEA3EDEA3016810500AAA8E4 /* d3dmetal-native.framework */; };
|
||||
CEA3EDEE3016810500AAA8E4 /* d3dmetal-native.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CEA3EDEA3016810500AAA8E4 /* d3dmetal-native.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
CEA3EE05301691C500AAA8E4 /* QEMURenderServer.app in Embed Executables */ = {isa = PBXBuildFile; fileRef = CEA3EDFA30168B9000AAA8E4 /* QEMURenderServer.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
CEA45E25263519B5002FA97D /* VMDisplayMetalViewController+Pointer.h in Sources */ = {isa = PBXBuildFile; fileRef = 83FBDD53242FA71900D2C5D7 /* VMDisplayMetalViewController+Pointer.h */; };
|
||||
CEA45E27263519B5002FA97D /* VMRemovableDrivesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2D954524AD4F980059923A /* VMRemovableDrivesView.swift */; };
|
||||
CEA45E37263519B5002FA97D /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE772AAB25C8B0F600E4E379 /* ContentView.swift */; };
|
||||
@@ -1313,6 +1318,13 @@
|
||||
remoteGlobalIDString = CE9A352C26533A51005077CF;
|
||||
remoteInfo = JailbreakInterposer;
|
||||
};
|
||||
CEA3EE03301691C500AAA8E4 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = CE550BC1225947990063E575 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = CEA3EDEF30168B9000AAA8E4;
|
||||
remoteInfo = QEMURenderServer;
|
||||
};
|
||||
CEBDA1E324D8BDDB0010B5EC /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = CE550BC1225947990063E575 /* Project object */;
|
||||
@@ -1364,6 +1376,7 @@
|
||||
CEF83F8F250094EE00557D15 /* gcrypt.20.framework in Embed Libraries */,
|
||||
CE0B6F5424AD67FA00FE012D /* spice-client-glib-2.0.8.framework in Embed Libraries */,
|
||||
CEF83F8B250094D700557D15 /* spice-server.1.framework in Embed Libraries */,
|
||||
CEA3EDEC3016810500AAA8E4 /* dxmt-native.framework in Embed Libraries */,
|
||||
CE0B6F1B24AD679700FE012D /* gstapp-1.0.0.framework in Embed Libraries */,
|
||||
CE0B6F2924AD67AD00FE012D /* gsttag-1.0.0.framework in Embed Libraries */,
|
||||
CE0B6F3124AD67C100FE012D /* phodav-3.0.0.framework in Embed Libraries */,
|
||||
@@ -1388,6 +1401,7 @@
|
||||
CE03D0C524D913AF00F76B84 /* ffi.8.framework in Embed Libraries */,
|
||||
CEF83F8D250094E700557D15 /* gthread-2.0.0.framework in Embed Libraries */,
|
||||
CE63B0DB2F0ED4FF00C59D13 /* vulkan_kosmickrisp.framework in Embed Libraries */,
|
||||
CEA3EDEE3016810500AAA8E4 /* d3dmetal-native.framework in Embed Libraries */,
|
||||
CE064C662A563F4B003C833D /* swtpm.0.framework in Embed Libraries */,
|
||||
CE03D09024D9124800F76B84 /* intl.8.framework in Embed Libraries */,
|
||||
CE03D0C924D9140A00F76B84 /* pixman-1.0.framework in Embed Libraries */,
|
||||
@@ -1521,15 +1535,16 @@
|
||||
name = "Embed Libraries";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
CE6B241425F1F5630020D43E /* Embed Launcher */ = {
|
||||
CE6B241425F1F5630020D43E /* Embed Executables */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 6;
|
||||
files = (
|
||||
8401FD7A269BECE200265F0D /* QEMULauncher.app in Embed Launcher */,
|
||||
8401FD7A269BECE200265F0D /* QEMULauncher.app in Embed Executables */,
|
||||
CEA3EE05301691C500AAA8E4 /* QEMURenderServer.app in Embed Executables */,
|
||||
);
|
||||
name = "Embed Launcher";
|
||||
name = "Embed Executables";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
CEA45F71263519B5002FA97D /* Embed Libraries */ = {
|
||||
@@ -2075,6 +2090,11 @@
|
||||
CE9D197B226542FE00355E14 /* UTMProcess.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UTMProcess.m; sourceTree = "<group>"; };
|
||||
CEA02A972436C7A30087E45F /* UTMLegacyQemuConfiguration+Networking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UTMLegacyQemuConfiguration+Networking.h"; sourceTree = "<group>"; };
|
||||
CEA02A982436C7A30087E45F /* UTMLegacyQemuConfiguration+Networking.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UTMLegacyQemuConfiguration+Networking.m"; sourceTree = "<group>"; };
|
||||
CEA3EDE93016810500AAA8E4 /* dxmt-native.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "dxmt-native.framework"; path = "$(SYSROOT_DIR)/Frameworks/dxmt-native.framework"; sourceTree = "<group>"; };
|
||||
CEA3EDEA3016810500AAA8E4 /* d3dmetal-native.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "d3dmetal-native.framework"; path = "$(SYSROOT_DIR)/Frameworks/d3dmetal-native.framework"; sourceTree = "<group>"; };
|
||||
CEA3EDFA30168B9000AAA8E4 /* QEMURenderServer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QEMURenderServer.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
CEA3EDFD30168C9900AAA8E4 /* QEMURenderServer.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QEMURenderServer.entitlements; sourceTree = "<group>"; };
|
||||
CEA3EE13301C15DD00AAA8E4 /* QEMURenderServer-unsigned.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "QEMURenderServer-unsigned.entitlements"; sourceTree = "<group>"; };
|
||||
CEA45FB9263519B5002FA97D /* UTM SE.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "UTM SE.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
CEA51F862A81EAB700DDD7FA /* VMToolbarOrnamentModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMToolbarOrnamentModifier.swift; sourceTree = "<group>"; };
|
||||
CEA9053725F981E900801E7C /* usb-1.0.0.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "usb-1.0.0.framework"; path = "$(SYSROOT_DIR)/Frameworks/usb-1.0.0.framework"; sourceTree = "<group>"; };
|
||||
@@ -2349,6 +2369,7 @@
|
||||
CEF83F882500949D00557D15 /* gthread-2.0.0.framework in Frameworks */,
|
||||
CE03D08724D90F0700F76B84 /* gobject-2.0.0.framework in Frameworks */,
|
||||
CE9B15362B11A491003A32DD /* SwiftConnect in Frameworks */,
|
||||
CEA3EDED3016810500AAA8E4 /* d3dmetal-native.framework in Frameworks */,
|
||||
CE0B6F0A24AD677200FE012D /* spice-client-glib-2.0.8.framework in Frameworks */,
|
||||
CE0B6ECF24AD677200FE012D /* gstrtp-1.0.0.framework in Frameworks */,
|
||||
CE0B6ECC24AD677200FE012D /* gstriff-1.0.0.framework in Frameworks */,
|
||||
@@ -2364,6 +2385,7 @@
|
||||
CE0B6EBB24AD677200FE012D /* libgstgio.a in Frameworks */,
|
||||
84937EFF28960789003148F4 /* zstd.1.framework in Frameworks */,
|
||||
CE0B6EE224AD677200FE012D /* gstnet-1.0.0.framework in Frameworks */,
|
||||
CEA3EDEB3016810500AAA8E4 /* dxmt-native.framework in Frameworks */,
|
||||
CE03D08624D90F0700F76B84 /* gmodule-2.0.0.framework in Frameworks */,
|
||||
CED297142CE425CB00F1E3EB /* soup-3.0.0.framework in Frameworks */,
|
||||
CE03D0CA24D9142000F76B84 /* ssl.1.1.framework in Frameworks */,
|
||||
@@ -2624,6 +2646,8 @@
|
||||
CE2D63D622653C7300FC7E63 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CEA3EDEA3016810500AAA8E4 /* d3dmetal-native.framework */,
|
||||
CEA3EDE93016810500AAA8E4 /* dxmt-native.framework */,
|
||||
CE63B0D92F0ED4FF00C59D13 /* MoltenVK.framework */,
|
||||
CE63B0D72F0ED4FE00C59D13 /* vulkan_kosmickrisp.framework */,
|
||||
CE63B0D82F0ED4FE00C59D13 /* vulkan.1.framework */,
|
||||
@@ -2894,6 +2918,7 @@
|
||||
CE9D18F72265410E00355E14 /* qemu */,
|
||||
CE63B0F02F0ED67700C59D13 /* vulkan */,
|
||||
CE6B240925F1F3CE0020D43E /* QEMULauncher */,
|
||||
CEA3EDFB30168C6300AAA8E4 /* QEMURenderServer */,
|
||||
CE9A352E26533A51005077CF /* JailbreakInterposer */,
|
||||
CE9B153D2B11A4ED003A32DD /* Remote */,
|
||||
CE4698F824C8FBD9008C1BD6 /* Icons */,
|
||||
@@ -2917,6 +2942,7 @@
|
||||
8401FD62269BE9C500265F0D /* QEMULauncher.app */,
|
||||
84E3A8F0293DB37E0024A740 /* utmctl */,
|
||||
CEF7F6D32AEEDCC400E34952 /* UTM Remote.app */,
|
||||
CEA3EDFA30168B9000AAA8E4 /* QEMURenderServer.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -3047,6 +3073,15 @@
|
||||
path = Remote;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CEA3EDFB30168C6300AAA8E4 /* QEMURenderServer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CEA3EDFD30168C9900AAA8E4 /* QEMURenderServer.entitlements */,
|
||||
CEA3EE13301C15DD00AAA8E4 /* QEMURenderServer-unsigned.entitlements */,
|
||||
);
|
||||
path = QEMURenderServer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CEB63A9624F47C1200CAF323 /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -3249,6 +3284,7 @@
|
||||
CE2D951924AD48BE0059923A /* Frameworks */,
|
||||
CE2D951A24AD48BE0059923A /* Resources */,
|
||||
CE0B6E6D24AD66CE00FE012D /* Embed Libraries */,
|
||||
CEA3EE0F301A5A4900AAA8E4 /* Embed D3DMetal */,
|
||||
CEBDA1E924D8BDDB0010B5EC /* Embed XPC Services */,
|
||||
84E3A8FA293DB70A0024A740 /* Embed CLI Tool */,
|
||||
);
|
||||
@@ -3293,6 +3329,21 @@
|
||||
productReference = CE9A352D26533A51005077CF /* JailbreakInterposer.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
CEA3EDEF30168B9000AAA8E4 /* QEMURenderServer */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = CEA3EDF730168B9000AAA8E4 /* Build configuration list for PBXNativeTarget "QEMURenderServer" */;
|
||||
buildPhases = (
|
||||
CEA3EE0130168DF000AAA8E4 /* Copy prebuilt binary */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = QEMURenderServer;
|
||||
productName = QEMULauncher;
|
||||
productReference = CEA3EDFA30168B9000AAA8E4 /* QEMURenderServer.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
CEA45E1F263519B5002FA97D /* iOS-SE */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = CEA45FB6263519B5002FA97D /* Build configuration list for PBXNativeTarget "iOS-SE" */;
|
||||
@@ -3333,12 +3384,13 @@
|
||||
CEBDA1D624D8BDDA0010B5EC /* Sources */,
|
||||
CEBDA1D724D8BDDA0010B5EC /* Frameworks */,
|
||||
CEBDA1D824D8BDDA0010B5EC /* Resources */,
|
||||
CE6B241425F1F5630020D43E /* Embed Launcher */,
|
||||
CE6B241425F1F5630020D43E /* Embed Executables */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
8401FD7C269BECF200265F0D /* PBXTargetDependency */,
|
||||
CEA3EE04301691C500AAA8E4 /* PBXTargetDependency */,
|
||||
);
|
||||
name = QEMUHelper;
|
||||
productName = QEMUHelper;
|
||||
@@ -3457,6 +3509,7 @@
|
||||
CE2D951B24AD48BE0059923A /* macOS */,
|
||||
CEBDA1D924D8BDDA0010B5EC /* QEMUHelper */,
|
||||
8401FD61269BE9C500265F0D /* QEMULauncher */,
|
||||
CEA3EDEF30168B9000AAA8E4 /* QEMURenderServer */,
|
||||
CE9A352C26533A51005077CF /* JailbreakInterposer */,
|
||||
84E3A8EF293DB37E0024A740 /* utmctl */,
|
||||
);
|
||||
@@ -3625,6 +3678,46 @@
|
||||
shellScript = "#!/bin/sh\n\nPLISTBUDDY=/usr/libexec/PlistBuddy\nROOT_PLIST=\"$SCRIPT_OUTPUT_FILE_0\"\n\nCOUNT=$($PLISTBUDDY -c \"Print :PreferenceSpecifiers\" \"$ROOT_PLIST\" | grep -c '^ }$')\n\nfor ((i = 0; i < COUNT; i++)); do\n remove=0\n platform=$($PLISTBUDDY -c \"Print :PreferenceSpecifiers:$i:Platform\" \"$ROOT_PLIST\" 2> /dev/null)\n if [ ! -z \"$platform\" ]; then\n if [ \"$platform\" == \"$PLATFORM_FAMILY_NAME\" ]; then\n echo \"Found entry $i for $platform\"\n $PLISTBUDDY -c \"Delete :PreferenceSpecifiers:$i:Platform\" \"$ROOT_PLIST\"\n else\n echo \"Exclude $i due to Platform\"\n remove=1\n fi\n fi\n excludetargets=$($PLISTBUDDY -c \"Print :PreferenceSpecifiers:$i:ExcludeTargets\" \"$ROOT_PLIST\" 2> /dev/null | sed '1d;$d' | xargs)\n if [ ! -z \"$excludetargets\" ]; then\n found=0\n for target in $excludetargets; do\n if [ \"$target\" == \"$TARGET_NAME\" ]; then\n found=1\n fi\n done\n if [ $found -eq 1 ]; then\n echo \"Exclude $i due to ExcludeTargets\"\n remove=1\n else\n echo \"Found entry $i for ExcludeTargets\"\n $PLISTBUDDY -c \"Delete :PreferenceSpecifiers:$i:ExcludeTargets\" \"$ROOT_PLIST\"\n fi\n fi\n if [ $remove -eq 1 ]; then\n echo \"Removing entry $i\"\n $PLISTBUDDY -c \"Delete :PreferenceSpecifiers:$i\" \"$ROOT_PLIST\"\n ((COUNT--))\n ((i--))\n fi\ndone\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
CEA3EE0130168DF000AAA8E4 /* Copy prebuilt binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(PROJECT_DIR)/$(SYSROOT_DIR)/libexec/virgl_render_server",
|
||||
);
|
||||
name = "Copy prebuilt binary";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "set -e\n\nSRC=\"${PROJECT_DIR}/${SYSROOT_DIR}/libexec/virgl_render_server\"\nDST=\"${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}\"\nTMP=\"${TARGET_TEMP_DIR}/${EXECUTABLE_NAME}\"\n\nif [ ! -f \"${SRC}\" ]; then\n echo \"error: prebuilt binary not found at ${SRC}\" >&2\n exit 1\nfi\n\n# install_name_tool writes a temporary file next to the binary it patches,\n# which the script sandbox disallows inside the product, so patch it here.\nrm -f \"${TMP}\"\ncp -X \"${SRC}\" \"${TMP}\"\nxattr -c \"${TMP}\"\nchmod +x \"${TMP}\"\n\n# The prebuilt binary has no LC_RPATH but links against\n# @rpath/vulkan.1.framework, so add the load paths this target declares.\nfor RPATH in ${LD_RUNPATH_SEARCH_PATHS}; do\n install_name_tool -add_rpath \"${RPATH}\" \"${TMP}\"\ndone\n\nmkdir -p \"$(dirname \"${DST}\")\"\nrm -f \"${DST}\"\ncp -X \"${TMP}\" \"${DST}\"\n";
|
||||
};
|
||||
CEA3EE0F301A5A4900AAA8E4 /* Embed D3DMetal */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(PROJECT_DIR)/$(SYSROOT_DIR)/Frameworks/D3DMetal.framework",
|
||||
);
|
||||
name = "Embed D3DMetal";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(TARGET_BUILD_DIR)/$(FRAMEWORKS_FOLDER_PATH)/D3DMetal.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "set -e\n\nSRC=\"${PROJECT_DIR}/${SYSROOT_DIR}/Frameworks/D3DMetal.framework\"\nDST=\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/D3DMetal.framework\"\n\nif [ ! -d \"${SRC}\" ]; then\n echo \"note: D3DMetal.framework not found in ${SYSROOT_DIR}, skipping\"\n rm -rf \"${DST}\"\n exit 0\nfi\n\n# Extended attributes on the input would make codesign refuse the bundle.\nmkdir -p \"$(dirname \"${DST}\")\"\nrm -rf \"${DST}\"\nditto --norsrc --noextattr --noqtn \"${SRC}\" \"${DST}\"\n\nif [ \"${CODE_SIGNING_ALLOWED}\" != \"NO\" ] && [ -n \"${EXPANDED_CODE_SIGN_IDENTITY}\" ]; then\n if [ \"${ENABLE_HARDENED_RUNTIME}\" = \"YES\" ]; then\n RUNTIME_FLAGS=\"--options runtime\"\n fi\n codesign --force --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" ${RUNTIME_FLAGS} ${OTHER_CODE_SIGN_FLAGS} \"${DST}\"\nfi\n";
|
||||
};
|
||||
CEF7F6812AEEDCC400E34952 /* Patch Settings bundle */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -4426,6 +4519,11 @@
|
||||
target = CE9A352C26533A51005077CF /* JailbreakInterposer */;
|
||||
targetProxy = CE9A353226533A52005077CF /* PBXContainerItemProxy */;
|
||||
};
|
||||
CEA3EE04301691C500AAA8E4 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = CEA3EDEF30168B9000AAA8E4 /* QEMURenderServer */;
|
||||
targetProxy = CEA3EE03301691C500AAA8E4 /* PBXContainerItemProxy */;
|
||||
};
|
||||
CEBDA1E424D8BDDB0010B5EC /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = CEBDA1D924D8BDDA0010B5EC /* QEMUHelper */;
|
||||
@@ -4633,7 +4731,6 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "$(LAUNCHER_CODE_SIGN_ENTITLEMENTS)";
|
||||
CODE_SIGN_IDENTITY = "$(CODE_SIGN_IDENTITY_MAC:default=-)";
|
||||
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -4655,7 +4752,6 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "$(LAUNCHER_CODE_SIGN_ENTITLEMENTS)";
|
||||
CODE_SIGN_IDENTITY = "$(CODE_SIGN_IDENTITY_MAC:default=-)";
|
||||
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -4798,6 +4894,7 @@
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"WITH_JIT=1",
|
||||
"WITH_SERVER=1",
|
||||
@@ -4832,6 +4929,7 @@
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"WITH_JIT=1",
|
||||
"WITH_SERVER=1",
|
||||
@@ -4925,13 +5023,13 @@
|
||||
"$(PROJECT_DIR)/$(QUOTED_SYSROOT_DIR)/include/spice-1",
|
||||
"$(PROJECT_DIR)/$(QUOTED_SYSROOT_DIR)/include/libusb-1.0",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(PROJECT_DIR)/$(QUOTED_SYSROOT_DIR)/lib",
|
||||
"$(PROJECT_DIR)/$(QUOTED_SYSROOT_DIR)/lib/gstreamer-1.0",
|
||||
"$(PROJECT_DIR)/$(QUOTED_SYSROOT_DIR)/lib",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.3;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
@@ -5008,13 +5106,13 @@
|
||||
"$(PROJECT_DIR)/$(QUOTED_SYSROOT_DIR)/include/spice-1",
|
||||
"$(PROJECT_DIR)/$(QUOTED_SYSROOT_DIR)/include/libusb-1.0",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(PROJECT_DIR)/$(QUOTED_SYSROOT_DIR)/lib",
|
||||
"$(PROJECT_DIR)/$(QUOTED_SYSROOT_DIR)/lib/gstreamer-1.0",
|
||||
"$(PROJECT_DIR)/$(QUOTED_SYSROOT_DIR)/lib",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.3;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
QUOTED_SYSROOT_DIR = "\"$(SYSROOT_DIR)\"";
|
||||
@@ -5080,6 +5178,46 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
CEA3EDF830168B9000AAA8E4 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "$(RENDERER_CODE_SIGN_ENTITLEMENTS)";
|
||||
CODE_SIGN_IDENTITY = "$(CODE_SIGN_IDENTITY_MAC:default=-)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../../../../../../../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_PREFIX:default=com.utmapp).QEMURenderServer";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = macosx;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
CEA3EDF930168B9000AAA8E4 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "$(RENDERER_CODE_SIGN_ENTITLEMENTS)";
|
||||
CODE_SIGN_IDENTITY = "$(CODE_SIGN_IDENTITY_MAC:default=-)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../../../../../../../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_PREFIX:default=com.utmapp).QEMURenderServer";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = macosx;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
CEA45FB7263519B5002FA97D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -5327,6 +5465,15 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
CEA3EDF730168B9000AAA8E4 /* Build configuration list for PBXNativeTarget "QEMURenderServer" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
CEA3EDF830168B9000AAA8E4 /* Debug */,
|
||||
CEA3EDF930168B9000AAA8E4 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
CEA45FB6263519B5002FA97D /* Build configuration list for PBXNativeTarget "iOS-SE" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"location" : "https://github.com/utmapp/CocoaSpice.git",
|
||||
"state" : {
|
||||
"branch" : "main",
|
||||
"revision" : "52b1535824657354fc3089eab24f1827280f9143"
|
||||
"revision" : "9873c6cacf866c8f47964e777b53f5c8f47364d7"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,548 @@
|
||||
From 263d9536fa0f652024b90103b1c9fffd57cc2542 Mon Sep 17 00:00:00 2001
|
||||
From: osy <[email protected]>
|
||||
Date: Tue, 28 Jul 2026 10:04:14 -0700
|
||||
Subject: [PATCH 1/4] spice-display: avoid sending duplicate scanout
|
||||
|
||||
If the same surface + size is sent, ignore sending scanout to the client.
|
||||
|
||||
Guests using flip-model presentation issue a set_scanout for every frame
|
||||
with a different backing buffer of the same dimensions. The IOSurface and
|
||||
its ID are unchanged in that case, so re-announcing it also closes the
|
||||
previous pipe and trips the client's stale-POLLHUP protection. Frame
|
||||
content is delivered by gl_draw regardless.
|
||||
|
||||
Assisted-by: Claude:claude-fable-5
|
||||
---
|
||||
include/ui/spice-display.h | 4 ++++
|
||||
ui/spice-display.c | 42 ++++++++++++++++++++++++++++----------
|
||||
2 files changed, 35 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h
|
||||
index 8e752f67da..cc052f0a08 100644
|
||||
--- a/include/ui/spice-display.h
|
||||
+++ b/include/ui/spice-display.h
|
||||
@@ -145,6 +145,10 @@ struct SimpleSpiceDisplay {
|
||||
#if defined(CONFIG_IOSURFACE)
|
||||
IOSurfaceRef iosurface;
|
||||
int surface_send_fd;
|
||||
+ /* last geometry sent via spice_qxl_gl_scanout/monitor_config so we can
|
||||
+ * skip re-sending the scanout for pure back-buffer flips */
|
||||
+ uint32_t scanout_last_x, scanout_last_y, scanout_last_w, scanout_last_h;
|
||||
+ bool scanout_last_y0top;
|
||||
#if defined(CONFIG_METAL)
|
||||
SpiceDisplayMetalContext metal_context;
|
||||
#endif
|
||||
diff --git a/ui/spice-display.c b/ui/spice-display.c
|
||||
index 976f68710a..82d758ae08 100644
|
||||
--- a/ui/spice-display.c
|
||||
+++ b/ui/spice-display.c
|
||||
@@ -995,18 +995,19 @@ static void spice_iosurface_destroy(SimpleSpiceDisplay *ssd)
|
||||
ssd->iosurface = NULL;
|
||||
}
|
||||
|
||||
-static bool spice_iosurface_resize(SimpleSpiceDisplay *ssd, int width, int height)
|
||||
+/* returns -1 on error, 0 if the surface is unchanged, 1 if (re)created */
|
||||
+static int spice_iosurface_resize(SimpleSpiceDisplay *ssd, int width, int height)
|
||||
{
|
||||
if (ssd->iosurface) {
|
||||
if (IOSurfaceGetHeight(ssd->iosurface) != height ||
|
||||
IOSurfaceGetWidth(ssd->iosurface) != width) {
|
||||
spice_iosurface_destroy(ssd);
|
||||
- return spice_iosurface_create(ssd, width, height);
|
||||
+ return spice_iosurface_create(ssd, width, height) ? 1 : -1;
|
||||
} else {
|
||||
- return true;
|
||||
+ return 0;
|
||||
}
|
||||
} else {
|
||||
- return spice_iosurface_create(ssd, width, height);
|
||||
+ return spice_iosurface_create(ssd, width, height) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1277,7 +1278,7 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
|
||||
qemu_spice_display_metal_scanout_disable(ssd->metal_context);
|
||||
}
|
||||
#endif
|
||||
- if (spice_iosurface_resize(ssd, width, height)) {
|
||||
+ if (spice_iosurface_resize(ssd, width, height) >= 0) {
|
||||
fd = spice_iosurface_create_fd(ssd, &fourcc);
|
||||
if (fd < 0) {
|
||||
error_report("spice_gl_switch: failed to create fd");
|
||||
@@ -1390,13 +1391,12 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
|
||||
#if defined(CONFIG_GBM)
|
||||
fd = egl_get_fd_for_texture(tex_id, &stride, &fourcc, NULL);
|
||||
#elif defined(CONFIG_IOSURFACE)
|
||||
- if (spice_iosurface_resize(ssd, backing_width, backing_height)) {
|
||||
- ssd->tex_id = tex_id;
|
||||
- ssd->y_0_top = y_0_top;
|
||||
- fd = spice_iosurface_create_fd(ssd, &fourcc);
|
||||
- } else {
|
||||
- fd = -1;
|
||||
+ int res = spice_iosurface_resize(ssd, backing_width, backing_height);
|
||||
+ if (res < 0) {
|
||||
+ fprintf(stderr, "%s: failed to create IOSurface\n", __func__);
|
||||
+ return;
|
||||
}
|
||||
+ ssd->tex_id = tex_id;
|
||||
#if defined(CONFIG_METAL)
|
||||
if (ssd->metal_context && native.type == SCANOUT_TEXTURE_NATIVE_TYPE_METAL) {
|
||||
qemu_spice_display_metal_scanout_texture(ssd->metal_context,
|
||||
@@ -1406,6 +1406,26 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
|
||||
qemu_spice_display_metal_scanout_disable(ssd->metal_context);
|
||||
}
|
||||
#endif
|
||||
+ /*
|
||||
+ * Guests using flip-model presentation issue a set_scanout for every
|
||||
+ * frame with a different backing buffer of the same dimensions. The
|
||||
+ * IOSurface (and its ID) is unchanged in that case, so avoid spamming
|
||||
+ * the SPICE client with gl_scanout/monitors_config messages (which
|
||||
+ * would also close the previous pipe and trigger the client's
|
||||
+ * stale-POLLHUP protection). Frame content is delivered by gl_draw.
|
||||
+ */
|
||||
+ if (res == 0 && ssd->have_scanout &&
|
||||
+ ssd->y_0_top == y_0_top &&
|
||||
+ ssd->scanout_last_x == x && ssd->scanout_last_y == y &&
|
||||
+ ssd->scanout_last_w == w && ssd->scanout_last_h == h) {
|
||||
+ return;
|
||||
+ }
|
||||
+ ssd->y_0_top = y_0_top;
|
||||
+ ssd->scanout_last_x = x;
|
||||
+ ssd->scanout_last_y = y;
|
||||
+ ssd->scanout_last_w = w;
|
||||
+ ssd->scanout_last_h = h;
|
||||
+ fd = spice_iosurface_create_fd(ssd, &fourcc);
|
||||
#endif
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "%s: failed to get fd for texture\n", __func__);
|
||||
--
|
||||
2.41.0
|
||||
|
||||
From 7e67e276de77359eeccd7eeacdc644e735919280 Mon Sep 17 00:00:00 2001
|
||||
From: osy <[email protected]>
|
||||
Date: Tue, 28 Jul 2026 10:04:32 -0700
|
||||
Subject: [PATCH 2/4] hvf: fix lost interrupt delivery during WFI
|
||||
|
||||
cpus_kick_thread() can race hvf_wait_for_ipi() and deadlock the VM: its
|
||||
thread_kicked dedup can swallow a kick that was issued right after
|
||||
hvf_wait_for_ipi() cleared the flag but before it entered pselect(). The
|
||||
vCPU then sleeps in WFI with the interrupt or stop request still pending,
|
||||
which stalls guest interrupts indefinitely and hangs pause_all_vcpus() on
|
||||
guest reset.
|
||||
|
||||
Always send the signal instead of relying on the dedup, and bound the
|
||||
otherwise open-ended pselect() so that a kick lost for any other reason
|
||||
degrades to a short delay rather than an unbounded sleep.
|
||||
|
||||
Assisted-by: Claude:claude-fable-5
|
||||
---
|
||||
target/arm/hvf/hvf.c | 33 +++++++++++++++++++++++++++++++--
|
||||
1 file changed, 31 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
|
||||
index 1f35d9f4d4..b20d70458f 100644
|
||||
--- a/target/arm/hvf/hvf.c
|
||||
+++ b/target/arm/hvf/hvf.c
|
||||
@@ -1242,7 +1242,21 @@ int hvf_arch_init_vcpu(CPUState *cpu)
|
||||
|
||||
void hvf_kick_vcpu_thread(CPUState *cpu)
|
||||
{
|
||||
- cpus_kick_thread(cpu);
|
||||
+ /*
|
||||
+ * Do not use cpus_kick_thread(): its thread_kicked dedup races with
|
||||
+ * hvf_wait_for_ipi() clearing thread_kicked right before an unbounded
|
||||
+ * pselect(). A kick that is skipped because thread_kicked was still set
|
||||
+ * from an already-consumed kick is lost forever: the vCPU sleeps in WFI
|
||||
+ * with the interrupt (or stop request) pending, which delays guest
|
||||
+ * interrupts indefinitely and deadlocks pause_all_vcpus() on guest
|
||||
+ * reset (zombie VM). Always send the signal.
|
||||
+ */
|
||||
+ qatomic_set(&cpu->thread_kicked, true);
|
||||
+ int err = pthread_kill(cpu->thread->thread, SIG_IPI);
|
||||
+ if (err && err != ESRCH) {
|
||||
+ fprintf(stderr, "qemu:%s: %s", __func__, strerror(err));
|
||||
+ exit(1);
|
||||
+ }
|
||||
hv_vcpus_exit(&cpu->accel->fd, 1);
|
||||
}
|
||||
|
||||
@@ -1967,13 +1981,28 @@ static uint64_t hvf_vtimer_val(void)
|
||||
|
||||
static void hvf_wait_for_ipi(CPUState *cpu, struct timespec *ts)
|
||||
{
|
||||
+ /*
|
||||
+ * Cap open-ended waits so that a lost kick degrades to a short delay
|
||||
+ * instead of an unbounded sleep (defense in depth on top of the
|
||||
+ * unconditional signal in hvf_kick_vcpu_thread()).
|
||||
+ */
|
||||
+ struct timespec bounded = { .tv_sec = 0, .tv_nsec = 10 * SCALE_MS };
|
||||
+
|
||||
/*
|
||||
* Use pselect to sleep so that other threads can IPI us while we're
|
||||
* sleeping.
|
||||
*/
|
||||
qatomic_set_mb(&cpu->thread_kicked, false);
|
||||
+ /*
|
||||
+ * A kick sent before thread_kicked was cleared may have been deduped;
|
||||
+ * re-check the conditions it would have signalled before sleeping.
|
||||
+ */
|
||||
+ if (qatomic_read(&cpu->stop) ||
|
||||
+ (cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIQ))) {
|
||||
+ return;
|
||||
+ }
|
||||
bql_unlock();
|
||||
- pselect(0, 0, 0, 0, ts, &cpu->accel->unblock_ipi_mask);
|
||||
+ pselect(0, 0, 0, 0, ts ? ts : &bounded, &cpu->accel->unblock_ipi_mask);
|
||||
bql_lock();
|
||||
}
|
||||
|
||||
--
|
||||
2.41.0
|
||||
|
||||
From 6c0ee265362b5cd22786f38f21806465c064b502 Mon Sep 17 00:00:00 2001
|
||||
From: osy <[email protected]>
|
||||
Date: Wed, 29 Jul 2026 01:02:20 -0700
|
||||
Subject: [PATCH 3/4] ui/spice: carry the guest scanout's pixel format to the
|
||||
IOSurface
|
||||
|
||||
The shared IOSurface was created with a hardcoded 'BGRA' pixel format,
|
||||
and that format was hardcoded again at every consumer, including the
|
||||
fourcc reported to the client through spice_qxl_gl_scanout().
|
||||
|
||||
A scanout is in whatever format the guest allocated. That is normally
|
||||
BGRA, but a fullscreen D3D swapchain becomes the scanout directly and may
|
||||
be R8G8B8A8, so its bytes ended up in a surface every consumer read as
|
||||
BGRA and red and blue came out transposed. Windowed output was unaffected
|
||||
because the scanout is then the desktop primary, which is BGRA.
|
||||
|
||||
Take the format from the scanout MTLTexture, recreate the surface when it
|
||||
changes just as for a size change, and report the real fourcc.
|
||||
SpiceGlScanout.format is documented as the drm fourcc format; it was
|
||||
being filled with a constant.
|
||||
|
||||
The EGL path takes the format too. The CGL path cannot: for 8-bit colour
|
||||
CGLTexImageIOSurface2D only accepts GL_BGRA with
|
||||
GL_UNSIGNED_INT_8_8_8_8_REV, and that combination reads the surface as
|
||||
BGRA no matter what its fourcc says, so a non-BGRA surface there is
|
||||
refused rather than silently transposed. Only the Metal path is ever
|
||||
asked for a different order.
|
||||
|
||||
Assisted-by: Claude:claude-opus-5
|
||||
---
|
||||
include/ui/spice-display.h | 5 +++
|
||||
ui/spice-display-metal.m | 23 +++++++++++++-
|
||||
ui/spice-display.c | 65 +++++++++++++++++++++++++++++---------
|
||||
3 files changed, 77 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h
|
||||
index cc052f0a08..965e248511 100644
|
||||
--- a/include/ui/spice-display.h
|
||||
+++ b/include/ui/spice-display.h
|
||||
@@ -144,6 +144,9 @@ struct SimpleSpiceDisplay {
|
||||
#endif
|
||||
#if defined(CONFIG_IOSURFACE)
|
||||
IOSurfaceRef iosurface;
|
||||
+ /* IOSurface pixel format ('BGRA'/'RGBA') the surface was created with;
|
||||
+ * a guest scanout in a different channel order forces a recreate. */
|
||||
+ uint32_t iosurface_fourcc;
|
||||
int surface_send_fd;
|
||||
/* last geometry sent via spice_qxl_gl_scanout/monitor_config so we can
|
||||
* skip re-sending the scanout for pure back-buffer flips */
|
||||
@@ -220,6 +223,8 @@ SpiceDisplayMetalContext qemu_spice_display_metal_create_context(IOSurfaceRef su
|
||||
uint32_t width,
|
||||
uint32_t height);
|
||||
void qemu_spice_display_metal_destroy_context(SpiceDisplayMetalContext ctx);
|
||||
+/* IOSurface pixel format matching a scanout MTLTexture, 0 if unsupported. */
|
||||
+uint32_t qemu_spice_display_metal_texture_fourcc(void *texture);
|
||||
void qemu_spice_display_metal_scanout_texture(SpiceDisplayMetalContext ctx,
|
||||
MTLTexture_id tex, uint32_t x, uint32_t y,
|
||||
uint32_t w, uint32_t h);
|
||||
diff --git a/ui/spice-display-metal.m b/ui/spice-display-metal.m
|
||||
index 29e58d9461..23d8408068 100644
|
||||
--- a/ui/spice-display-metal.m
|
||||
+++ b/ui/spice-display-metal.m
|
||||
@@ -38,7 +38,10 @@ - (instancetype)initWithDevice:(id<MTLDevice>)device
|
||||
{
|
||||
if (self = [super init]) {
|
||||
MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init];
|
||||
- textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
+ /* must match the surface, which follows the guest scanout's order */
|
||||
+ textureDescriptor.pixelFormat =
|
||||
+ IOSurfaceGetPixelFormat(surface) == 'RGBA' ? MTLPixelFormatRGBA8Unorm
|
||||
+ : MTLPixelFormatBGRA8Unorm;
|
||||
textureDescriptor.width = width;
|
||||
textureDescriptor.height = height;
|
||||
textureDescriptor.usage = MTLTextureUsageRenderTarget;
|
||||
@@ -112,6 +115,24 @@ - (void)drawFrameAtRect:(CGRect)rect completion:(void (^)(void))completion
|
||||
|
||||
@end
|
||||
|
||||
+uint32_t qemu_spice_display_metal_texture_fourcc(void *texture)
|
||||
+{
|
||||
+ id<MTLTexture> tex = (id<MTLTexture>)texture;
|
||||
+
|
||||
+ if (!tex) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ switch (tex.pixelFormat) {
|
||||
+ case MTLPixelFormatBGRA8Unorm:
|
||||
+ return 'BGRA';
|
||||
+ case MTLPixelFormatRGBA8Unorm:
|
||||
+ return 'RGBA';
|
||||
+ default:
|
||||
+ /* no IOSurface equivalent wired up; caller keeps its default */
|
||||
+ return 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
SpiceDisplayMetalContext qemu_spice_display_metal_create_context(IOSurfaceRef surface,
|
||||
uint32_t width,
|
||||
uint32_t height)
|
||||
diff --git a/ui/spice-display.c b/ui/spice-display.c
|
||||
index 82d758ae08..d73fbf5271 100644
|
||||
--- a/ui/spice-display.c
|
||||
+++ b/ui/spice-display.c
|
||||
@@ -818,9 +818,10 @@ static void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef
|
||||
CFRelease(number);
|
||||
}
|
||||
|
||||
-static bool spice_iosurface_create_egl(SimpleSpiceDisplay *ssd, int width, int height,
|
||||
- IOSurfaceRef surface)
|
||||
+static bool spice_iosurface_create_egl_fmt(SimpleSpiceDisplay *ssd, int width, int height,
|
||||
+ IOSurfaceRef surface, uint32_t fourcc)
|
||||
{
|
||||
+ const GLenum egl_internal_format = (fourcc == 'RGBA') ? GL_RGBA : GL_BGRA_EXT;
|
||||
#if defined(CONFIG_EGL)
|
||||
EGLint target = 0;
|
||||
GLenum tex_target = 0;
|
||||
@@ -845,7 +846,7 @@ static bool spice_iosurface_create_egl(SimpleSpiceDisplay *ssd, int width, int h
|
||||
EGL_HEIGHT, height,
|
||||
EGL_IOSURFACE_PLANE_ANGLE, 0,
|
||||
EGL_TEXTURE_TARGET, target,
|
||||
- EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
|
||||
+ EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, egl_internal_format,
|
||||
EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
|
||||
EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE,
|
||||
EGL_IOSURFACE_USAGE_HINT_ANGLE, EGL_IOSURFACE_WRITE_HINT_ANGLE,
|
||||
@@ -872,11 +873,23 @@ static bool spice_iosurface_create_egl(SimpleSpiceDisplay *ssd, int width, int h
|
||||
}
|
||||
|
||||
static bool spice_iosurface_create_cgl(SimpleSpiceDisplay *ssd, int width, int height,
|
||||
- IOSurfaceRef surface)
|
||||
+ IOSurfaceRef surface, uint32_t fourcc)
|
||||
{
|
||||
#if defined(HAVE_SPICE_MAC_CGL)
|
||||
GLuint tex;
|
||||
|
||||
+ /*
|
||||
+ * CGLTexImageIOSurface2D accepts only GL_BGRA/GL_UNSIGNED_INT_8_8_8_8_REV
|
||||
+ * for 8-bit colour (see the table in <OpenGL/CGLIOSurface.h>; anything else
|
||||
+ * returns kCGLBadValue), and that combination reads the surface as BGRA
|
||||
+ * whatever its fourcc says. So this path cannot carry a differently-ordered
|
||||
+ * scanout at all, and must refuse rather than silently transpose.
|
||||
+ */
|
||||
+ if (fourcc != 'BGRA') {
|
||||
+ error_report("spice_iosurface_create: CGL supports BGRA surfaces only");
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
CGLSetCurrentContext(spice_gl_ctx);
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, tex);
|
||||
@@ -904,14 +917,15 @@ static bool spice_iosurface_create_cgl(SimpleSpiceDisplay *ssd, int width, int h
|
||||
#endif
|
||||
}
|
||||
|
||||
-static bool spice_iosurface_create(SimpleSpiceDisplay *ssd, int width, int height)
|
||||
+static bool spice_iosurface_create(SimpleSpiceDisplay *ssd, int width, int height,
|
||||
+ uint32_t fourcc)
|
||||
{
|
||||
IOSurfaceRef surface;
|
||||
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
|
||||
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
AddIntegerValue(dict, kIOSurfaceWidth, width);
|
||||
AddIntegerValue(dict, kIOSurfaceHeight, height);
|
||||
- AddIntegerValue(dict, kIOSurfacePixelFormat, 'BGRA');
|
||||
+ AddIntegerValue(dict, kIOSurfacePixelFormat, (int)fourcc);
|
||||
AddIntegerValue(dict, kIOSurfaceBytesPerElement, 4);
|
||||
#if TARGET_OS_OSX
|
||||
CFDictionaryAddValue(dict, kIOSurfaceIsGlobal, kCFBooleanTrue);
|
||||
@@ -926,18 +940,19 @@ static bool spice_iosurface_create(SimpleSpiceDisplay *ssd, int width, int heigh
|
||||
}
|
||||
|
||||
if (spice_opengl == DISPLAY_GL_MODE_CORE) {
|
||||
- if (!spice_iosurface_create_cgl(ssd, width, height, surface)) {
|
||||
+ if (!spice_iosurface_create_cgl(ssd, width, height, surface, fourcc)) {
|
||||
CFRelease(surface);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
- if (!spice_iosurface_create_egl(ssd, width, height, surface)) {
|
||||
+ if (!spice_iosurface_create_egl_fmt(ssd, width, height, surface, fourcc)) {
|
||||
CFRelease(surface);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ssd->iosurface = surface;
|
||||
+ ssd->iosurface_fourcc = fourcc;
|
||||
|
||||
#if defined(CONFIG_METAL)
|
||||
ssd->metal_context = qemu_spice_display_metal_create_context(surface, width, height);
|
||||
@@ -996,18 +1011,20 @@ static void spice_iosurface_destroy(SimpleSpiceDisplay *ssd)
|
||||
}
|
||||
|
||||
/* returns -1 on error, 0 if the surface is unchanged, 1 if (re)created */
|
||||
-static int spice_iosurface_resize(SimpleSpiceDisplay *ssd, int width, int height)
|
||||
+static int spice_iosurface_resize(SimpleSpiceDisplay *ssd, int width, int height,
|
||||
+ uint32_t fourcc)
|
||||
{
|
||||
if (ssd->iosurface) {
|
||||
if (IOSurfaceGetHeight(ssd->iosurface) != height ||
|
||||
- IOSurfaceGetWidth(ssd->iosurface) != width) {
|
||||
+ IOSurfaceGetWidth(ssd->iosurface) != width ||
|
||||
+ ssd->iosurface_fourcc != fourcc) {
|
||||
spice_iosurface_destroy(ssd);
|
||||
- return spice_iosurface_create(ssd, width, height) ? 1 : -1;
|
||||
+ return spice_iosurface_create(ssd, width, height, fourcc) ? 1 : -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
- return spice_iosurface_create(ssd, width, height) ? 1 : -1;
|
||||
+ return spice_iosurface_create(ssd, width, height, fourcc) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,7 +1048,7 @@ static int spice_iosurface_create_fd(SimpleSpiceDisplay *ssd, int *fourcc)
|
||||
// when we close it, POLLHUP will be seen by the other side and know that
|
||||
// the surface ID is stale and should not be used
|
||||
ssd->surface_send_fd = fds[1];
|
||||
- *fourcc = 'BGRA';
|
||||
+ *fourcc = (int)ssd->iosurface_fourcc;
|
||||
surfaceid = IOSurfaceGetID(ssd->iosurface);
|
||||
write(ssd->surface_send_fd, &surfaceid, sizeof(surfaceid));
|
||||
return fds[0];
|
||||
@@ -1278,7 +1295,7 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
|
||||
qemu_spice_display_metal_scanout_disable(ssd->metal_context);
|
||||
}
|
||||
#endif
|
||||
- if (spice_iosurface_resize(ssd, width, height) >= 0) {
|
||||
+ if (spice_iosurface_resize(ssd, width, height, 'BGRA') >= 0) {
|
||||
fd = spice_iosurface_create_fd(ssd, &fourcc);
|
||||
if (fd < 0) {
|
||||
error_report("spice_gl_switch: failed to create fd");
|
||||
@@ -1391,7 +1408,25 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
|
||||
#if defined(CONFIG_GBM)
|
||||
fd = egl_get_fd_for_texture(tex_id, &stride, &fourcc, NULL);
|
||||
#elif defined(CONFIG_IOSURFACE)
|
||||
- int res = spice_iosurface_resize(ssd, backing_width, backing_height);
|
||||
+ /*
|
||||
+ * The surface is shared with the client verbatim, so it has to be in the
|
||||
+ * guest scanout's channel order: a fullscreen D3D swapchain can be
|
||||
+ * R8G8B8A8 while the desktop is B8G8R8A8. Only the Metal path can honour
|
||||
+ * a non-BGRA order end to end, so everything else stays BGRA.
|
||||
+ */
|
||||
+ uint32_t want_fourcc = 'BGRA';
|
||||
+#if defined(CONFIG_METAL)
|
||||
+ if (native.type == SCANOUT_TEXTURE_NATIVE_TYPE_METAL &&
|
||||
+ spice_opengl != DISPLAY_GL_MODE_CORE) {
|
||||
+ uint32_t native_fourcc =
|
||||
+ qemu_spice_display_metal_texture_fourcc(native.handle);
|
||||
+ if (native_fourcc) {
|
||||
+ want_fourcc = native_fourcc;
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+ int res = spice_iosurface_resize(ssd, backing_width, backing_height,
|
||||
+ want_fourcc);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "%s: failed to create IOSurface\n", __func__);
|
||||
return;
|
||||
--
|
||||
2.41.0
|
||||
|
||||
From 27d8515de35937969dec6144dc6a0b63362d5ecc Mon Sep 17 00:00:00 2001
|
||||
From: osy <[email protected]>
|
||||
Date: Wed, 29 Jul 2026 16:20:12 -0700
|
||||
Subject: [PATCH 4/4] Revert "ui/console: force gl-unblock from the watchdog
|
||||
timer"
|
||||
|
||||
This reverts commit 5cb1434ba33797b08f94c0f2168cd5ee7f70d8e6.
|
||||
---
|
||||
ui/console.c | 45 ++-------------------------------------------
|
||||
1 file changed, 2 insertions(+), 43 deletions(-)
|
||||
|
||||
diff --git a/ui/console.c b/ui/console.c
|
||||
index a2dddbd37a..f6d7879eff 100644
|
||||
--- a/ui/console.c
|
||||
+++ b/ui/console.c
|
||||
@@ -166,32 +166,7 @@ void qemu_console_co_wait_update(QemuConsole *con)
|
||||
|
||||
static void graphic_hw_gl_unblock_timer(void *opaque)
|
||||
{
|
||||
- QemuConsole *con = opaque;
|
||||
-
|
||||
- /*
|
||||
- * The display's GL render did not release the block within the timeout
|
||||
- * (e.g. the gtk window is occluded, the host compositor throttled the
|
||||
- * frame callback, or the host GPU stalled). The device's command queue is
|
||||
- * gated on this block (virtio-gpu: renderer_blocked), so a stuck display
|
||||
- * stalls the guest GPU scheduler into a TDR (dxgmms1 0x7E) ~2 s later.
|
||||
- * Force the unblock so guest command/fence processing resumes well before
|
||||
- * the guest's TdrDelay; the worst case is one stale/torn displayed frame,
|
||||
- * never a guest crash. A late real release is absorbed in
|
||||
- * graphic_hw_gl_block() (con->gl_block already 0 -> no-op).
|
||||
- */
|
||||
- /* Rate-limited: this can fire repeatedly when the display fence is
|
||||
- * persistently slow; an occasional line is enough to know it's active. */
|
||||
- static unsigned _ub;
|
||||
- if ((_ub++ % 60u) == 0u) {
|
||||
- warn_report("console: gl-unblock fallback firing (display GL fence slow); "
|
||||
- "forcing unblock to keep the guest cmdq moving");
|
||||
- }
|
||||
- if (con->gl_block > 0) {
|
||||
- con->gl_block = 0;
|
||||
- if (con->hw_ops->gl_block) {
|
||||
- con->hw_ops->gl_block(con->hw, false);
|
||||
- }
|
||||
- }
|
||||
+ warn_report("console: no gl-unblock within one second");
|
||||
}
|
||||
|
||||
void graphic_hw_gl_block(QemuConsole *con, bool block)
|
||||
@@ -202,13 +177,6 @@ void graphic_hw_gl_block(QemuConsole *con, bool block)
|
||||
if (block) {
|
||||
con->gl_block++;
|
||||
} else {
|
||||
- /*
|
||||
- * A late release after graphic_hw_gl_unblock_timer() force-cleared the
|
||||
- * block (con->gl_block already 0) must be a safe no-op, not underflow.
|
||||
- */
|
||||
- if (con->gl_block == 0) {
|
||||
- return;
|
||||
- }
|
||||
con->gl_block--;
|
||||
}
|
||||
assert(con->gl_block >= 0);
|
||||
@@ -222,16 +190,7 @@ void graphic_hw_gl_block(QemuConsole *con, bool block)
|
||||
|
||||
if (block) {
|
||||
timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
|
||||
- /* Safety net only. The display samples (blits + fences) the guest
|
||||
- * buffer directly at flush time, so the block lifetime is the GPU
|
||||
- * fence latency -- not the host compositor's frame clock -- and
|
||||
- * releasing the guest early TEARS: it re-renders into the buffer
|
||||
- * while the queued blit still reads it (scaled/shifted frame
|
||||
- * artifacts under present storms). 500ms is correct backpressure
|
||||
- * for a slow (shared, possibly saturated) GPU while still
|
||||
- * recovering a genuinely stuck fence well inside the guest's ~2s
|
||||
- * TDR budget. */
|
||||
- timeout += 500;
|
||||
+ timeout += 1000; /* one sec */
|
||||
timer_mod(con->gl_unblock_timer, timeout);
|
||||
} else {
|
||||
timer_del(con->gl_unblock_timer);
|
||||
--
|
||||
2.41.0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+9
-4
@@ -23,7 +23,7 @@ SPICE_SERVER_SRC="https://www.spice-space.org/download/releases/spice-server/spi
|
||||
USB_SRC="https://github.com/libusb/libusb/releases/download/v1.0.25/libusb-1.0.25.tar.bz2"
|
||||
USBREDIR_SRC="https://www.spice-space.org/download/usbredir/usbredir-0.14.0.tar.xz"
|
||||
SLIRP_SRC="https://github.com/utmapp/libslirp/releases/download/v4.9.1-release-mirror/libslirp-v4.9.1.tar.gz"
|
||||
QEMU_SRC="https://github.com/utmapp/qemu/releases/download/v10.0.2-utm/qemu-10.0.2-utm.tar.xz"
|
||||
QEMU_SRC="https://github.com/utmapp/qemu/releases/download/v10.0.12-utm/qemu-10.0.12-utm.tar.xz"
|
||||
|
||||
# Source files for spice-client
|
||||
JSON_GLIB_SRC="https://download.gnome.org/sources/json-glib/1.10/json-glib-1.10.0.tar.xz"
|
||||
@@ -42,15 +42,20 @@ WEBKIT_REPO="https://github.com/utmapp/WebKit.git"
|
||||
WEBKIT_COMMIT="ed78ab6e1a37f4f11583a0bd038f22ec91f3ff10"
|
||||
WEBKIT_SUBDIRS="Source/ThirdParty/ANGLE Configurations Tools/ccache"
|
||||
EPOXY_REPO="https://github.com/utmapp/libepoxy.git"
|
||||
EPOXY_COMMIT="5014658f79e4d6872a1ad6754da9098ccd9d4fc5"
|
||||
EPOXY_COMMIT="bf98587477fe68d07b93319ece7b40a7d0e2eabe"
|
||||
VULKAN_LOADER_REPO="https://github.com/osy/Vulkan-Loader.git"
|
||||
VULKAN_LOADER_COMMIT="6df86907be582927507637f3f6003ea58bc34517"
|
||||
VIRGLRENDERER_REPO="https://github.com/utmapp/virglrenderer.git"
|
||||
VIRGLRENDERER_COMMIT="d48a2d0d9a722fffd3f92c83e71d9426a4892a66"
|
||||
VIRGLRENDERER_COMMIT="9499d3e53edbf356fb3e8f5ab68b27e208003022"
|
||||
MESA_REPO="https://gitlab.freedesktop.org/osy/mesa.git"
|
||||
MESA_COMMIT="79bc850d884a1307356ff61c017e58901b90c7e2"
|
||||
MOLTENVK_REPO="https://github.com/utmapp/MoltenVK.git"
|
||||
MOLTENVK_COMMIT="111c14f3abf5c00118fc7a5b00c92d7abbf40f62"
|
||||
MOLTENVK_COMMIT="ef1c5461774f5fbd224ddcfd91fd2c0ea23f0384"
|
||||
LLVM15_SRC="https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.7/llvm-project-15.0.7.src.tar.xz"
|
||||
DXMT_REPO="https://github.com/utmapp/dxmt.git"
|
||||
DXMT_COMMIT="be80e14c07613cd558036a576b82dc6d78acdfce"
|
||||
D3DMETAL_REPO="https://github.com/utmapp/d3dmetal-native.git"
|
||||
D3DMETAL_COMMIT="edd2e386c25a2039eca0f6ce8f794b3b165841eb"
|
||||
|
||||
# Decompiled Hypervisor for iOS
|
||||
HYPERVISOR_REPO="https://github.com/utmapp/Hypervisor.git"
|
||||
|
||||
+118
-37
@@ -21,9 +21,13 @@ RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Knobs
|
||||
IOS_SDKMINVER="14.0"
|
||||
MAC_SDKMINVER="11.0"
|
||||
IOS_SDKMINVER="16.0"
|
||||
MAC_SDKMINVER="13.0"
|
||||
VISIONOS_SDKMINVER="1.0"
|
||||
# Network operations are retried because concurrent builds on the same CI runner
|
||||
# get rate limited by GitHub and fail to clone/fetch.
|
||||
RETRY_ATTEMPTS="${RETRY_ATTEMPTS:-5}"
|
||||
RETRY_DELAY="${RETRY_DELAY:-15}"
|
||||
|
||||
# Build environment
|
||||
PLATFORM=
|
||||
@@ -90,6 +94,26 @@ check_env () {
|
||||
version_check "2.4" "$(bison -V | head -1 | awk '{ print $NF }')" || { echo >&2 "${RED}'bison' >= 2.4 is required. Did you install from Homebrew and updated your \$PATH variable?"; exit 1; }
|
||||
}
|
||||
|
||||
# Run a command, retrying with exponential backoff if it fails. Jitter is derived
|
||||
# from the PID so that concurrent builds do not retry in lockstep.
|
||||
retry () {
|
||||
ATTEMPT=1
|
||||
DELAY="$RETRY_DELAY"
|
||||
while true; do
|
||||
"$@" && return 0
|
||||
STATUS=$?
|
||||
if [ $ATTEMPT -ge $RETRY_ATTEMPTS ]; then
|
||||
echo >&2 "${RED}'$*' failed after $ATTEMPT attempts.${NC}"
|
||||
return $STATUS
|
||||
fi
|
||||
SLEEP=$(( DELAY + ($$ + ATTEMPT) % 10 ))
|
||||
echo >&2 "${RED}'$*' failed (attempt $ATTEMPT of $RETRY_ATTEMPTS), retrying in ${SLEEP}s...${NC}"
|
||||
sleep $SLEEP
|
||||
ATTEMPT=$(( ATTEMPT + 1 ))
|
||||
DELAY=$(( DELAY * 2 ))
|
||||
done
|
||||
}
|
||||
|
||||
download () {
|
||||
URL=$1
|
||||
FILE="$(basename $URL)"
|
||||
@@ -102,7 +126,7 @@ download () {
|
||||
echo "${GREEN}$TARGET already downloaded! Run with -d to force re-download.${NC}"
|
||||
else
|
||||
echo "${GREEN}Downloading ${URL}${NC}"
|
||||
curl -L -O "$URL"
|
||||
retry curl -f -L -O "$URL"
|
||||
mv "$FILE" "$TARGET"
|
||||
fi
|
||||
if [ -d "$DIR" ]; then
|
||||
@@ -121,6 +145,12 @@ download () {
|
||||
fi
|
||||
}
|
||||
|
||||
# Discard any partial clone from a previous attempt so that a retry starts clean.
|
||||
clone_fresh () {
|
||||
rm -rf "$2"
|
||||
git clone --filter=tree:0 --no-checkout "$1" "$2"
|
||||
}
|
||||
|
||||
clone () {
|
||||
REPO="$1"
|
||||
COMMIT="$2"
|
||||
@@ -130,15 +160,26 @@ clone () {
|
||||
if [ -d "$DIR" -a -z "$REDOWNLOAD" ]; then
|
||||
echo "${GREEN}$DIR already downloaded! Run with -d to force re-download.${NC}"
|
||||
else
|
||||
rm -rf "$DIR"
|
||||
echo "${GREEN}Cloning ${REPO}...${NC}"
|
||||
git clone --filter=tree:0 --no-checkout "$REPO" "$DIR"
|
||||
retry clone_fresh "$REPO" "$DIR"
|
||||
if [ ! -z "$SUBDIRS" ]; then
|
||||
git -C "$DIR" sparse-checkout init
|
||||
git -C "$DIR" sparse-checkout set $SUBDIRS
|
||||
fi
|
||||
fi
|
||||
git -C "$DIR" checkout "$COMMIT"
|
||||
# tree:0 filtered clones fetch missing objects here, so these hit the network too
|
||||
retry git -C "$DIR" checkout "$COMMIT"
|
||||
retry git -C "$DIR" submodule update --init --recursive --filter=tree:0
|
||||
}
|
||||
|
||||
clone_moltenvk_dependences () {
|
||||
REPO="$1"
|
||||
NAME="$(basename $REPO)"
|
||||
DIR="$BUILD_DIR/$NAME"
|
||||
pwd="$(pwd)"
|
||||
cd "$DIR"
|
||||
retry "./fetchDependencies" --none -v
|
||||
cd "$pwd"
|
||||
}
|
||||
|
||||
download_all () {
|
||||
@@ -182,6 +223,10 @@ download_all () {
|
||||
clone $LIBUCONTEXT_REPO $LIBUCONTEXT_COMMIT
|
||||
clone $MESA_REPO $MESA_COMMIT
|
||||
clone $MOLTENVK_REPO $MOLTENVK_COMMIT
|
||||
clone_moltenvk_dependences $MOLTENVK_REPO
|
||||
download $LLVM15_SRC
|
||||
clone $DXMT_REPO $DXMT_COMMIT
|
||||
clone $D3DMETAL_REPO $D3DMETAL_COMMIT
|
||||
}
|
||||
|
||||
copy_private_headers() {
|
||||
@@ -225,13 +270,16 @@ generate_meson_cross() {
|
||||
echo "c_args = [${CFLAGS:+$(meson_quote $CFLAGS)}]" >> $cross
|
||||
echo "cpp_args = [${CXXFLAGS:+$(meson_quote $CXXFLAGS)}]" >> $cross
|
||||
echo "objc_args = [${OBJCFLAGS:+$(meson_quote $OBJCFLAGS)}]" >> $cross
|
||||
echo "objcpp_args = [${OBJCFLAGS:+$(meson_quote $OBJCFLAGS)}]" >> $cross
|
||||
echo "c_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
|
||||
echo "cpp_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
|
||||
echo "objc_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
|
||||
echo "objcpp_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
|
||||
echo "[binaries]" >> $cross
|
||||
echo "c = [$(meson_quote $CC)]" >> $cross
|
||||
echo "cpp = [$(meson_quote $CXX)]" >> $cross
|
||||
echo "objc = [$(meson_quote $OBJCC)]" >> $cross
|
||||
echo "objcpp = [$(meson_quote $OBJCC)]" >> $cross
|
||||
echo "ar = [$(meson_quote $AR)]" >> $cross
|
||||
echo "nm = [$(meson_quote $NM)]" >> $cross
|
||||
echo "pkgconfig = ['$PREFIX/host/bin/pkg-config']" >> $cross
|
||||
@@ -293,19 +341,19 @@ generate_cmake_toolchain() {
|
||||
case $PLATFORM in
|
||||
ios_simulator* )
|
||||
echo "set(CMAKE_SYSTEM_NAME iOS)" >> "$toolchain"
|
||||
echo "set(CMAKE_OSX_SYSROOT iphonesimulator)" >> "$toolchain"
|
||||
echo "set(CMAKE_OSX_SYSROOT iphonesimulator CACHE STRING \"\" FORCE)" >> "$toolchain"
|
||||
;;
|
||||
ios* )
|
||||
echo "set(CMAKE_SYSTEM_NAME iOS)" >> "$toolchain"
|
||||
echo "set(CMAKE_OSX_SYSROOT iphoneos)" >> "$toolchain"
|
||||
echo "set(CMAKE_OSX_SYSROOT iphoneos CACHE STRING \"\" FORCE)" >> "$toolchain"
|
||||
;;
|
||||
visionos_simulator* )
|
||||
echo "set(CMAKE_SYSTEM_NAME visionOS)" >> "$toolchain"
|
||||
echo "set(CMAKE_OSX_SYSROOT xrsimulator)" >> "$toolchain"
|
||||
echo "set(CMAKE_OSX_SYSROOT xrsimulator CACHE STRING \"\" FORCE)" >> "$toolchain"
|
||||
;;
|
||||
visionos* )
|
||||
echo "set(CMAKE_SYSTEM_NAME visionOS)" >> "$toolchain"
|
||||
echo "set(CMAKE_OSX_SYSROOT xros)" >> "$toolchain"
|
||||
echo "set(CMAKE_OSX_SYSROOT xros CACHE STRING \"\" FORCE)" >> "$toolchain"
|
||||
;;
|
||||
macos )
|
||||
echo "set(CMAKE_SYSTEM_NAME Darwin)" >> "$toolchain"
|
||||
@@ -317,7 +365,7 @@ generate_cmake_toolchain() {
|
||||
# Architecture
|
||||
#
|
||||
echo "set(CMAKE_SYSTEM_PROCESSOR \"$ARCH\")" >> "$toolchain"
|
||||
echo "set(CMAKE_OSX_ARCHITECTURES \"$ARCH\")" >> "$toolchain"
|
||||
echo "set(CMAKE_OSX_ARCHITECTURES \"$ARCH\" CACHE STRING \"\" FORCE)" >> "$toolchain"
|
||||
echo "set(CMAKE_MACOSX_BUNDLE OFF CACHE BOOL \"\")" >> "$toolchain"
|
||||
echo "" >> "$toolchain"
|
||||
|
||||
@@ -343,6 +391,7 @@ generate_cmake_toolchain() {
|
||||
echo "set(CMAKE_C_COMPILER \"$CC_BIN\")" >> "$toolchain"
|
||||
echo "set(CMAKE_CXX_COMPILER \"$CXX_BIN\")" >> "$toolchain"
|
||||
echo "set(CMAKE_OBJC_COMPILER \"$OBJC_BIN\")" >> "$toolchain"
|
||||
echo "set(CMAKE_ASM_COMPILER \"$CC_BIN\")" >> "$toolchain"
|
||||
echo "" >> "$toolchain"
|
||||
|
||||
#
|
||||
@@ -359,6 +408,7 @@ generate_cmake_toolchain() {
|
||||
#
|
||||
if [ -n "$CFLAGS" ]; then
|
||||
echo "set(CMAKE_C_FLAGS \"$CFLAGS\" CACHE STRING \"\" FORCE)" >> "$toolchain"
|
||||
echo "set(CMAKE_ASM_FLAGS \"$CFLAGS\" CACHE STRING \"\" FORCE)" >> "$toolchain"
|
||||
fi
|
||||
|
||||
if [ -n "$OBJCFLAGS" ]; then
|
||||
@@ -695,7 +745,12 @@ build_qemu_dependencies () {
|
||||
# strip the minor versions
|
||||
VULKAN_DYLIB="$PREFIX/lib/libvulkan.1.dylib"
|
||||
mv "$(dirname $VULKAN_DYLIB)/$(readlink $VULKAN_DYLIB)" "$VULKAN_DYLIB"
|
||||
meson_darwin_build $VIRGLRENDERER_REPO -Dtests=false -Dcheck-gl-errors=false -Dvenus=true -Dvulkan-dload=false -Drender-server-worker=thread
|
||||
if [ "$PLATFORM" == "macos" ]; then
|
||||
VIRGL_RENDER_SERVER_MODE="process"
|
||||
else
|
||||
VIRGL_RENDER_SERVER_MODE="thread"
|
||||
fi
|
||||
meson_darwin_build $VIRGLRENDERER_REPO -Dtests=false -Dcheck-gl-errors=false -Dvenus=true -Dneptune=true -Dvulkan-dload=false -Drender-server-mode="$VIRGL_RENDER_SERVER_MODE"
|
||||
# Hypervisor for iOS
|
||||
if [ "$PLATFORM" == "ios" ] || [ "$PLATFORM" == "ios_simulator" ]; then
|
||||
build_hypervisor
|
||||
@@ -785,7 +840,39 @@ build_vulkan_drivers () {
|
||||
patch_vulkan_icd "$PREFIX/share/vulkan/icd.d/MoltenVK_icd.json"
|
||||
}
|
||||
|
||||
fixup () {
|
||||
build_d3d_drivers () {
|
||||
LLVM15_NAME=$(basename "${LLVM15_SRC%.tar.*}")
|
||||
cmake_build "$BUILD_DIR/$LLVM15_NAME/llvm" -DLLVM_ENABLE_ZSTD=Off -DLLVM_TARGETS_TO_BUILD="" -DLLVM_BUILD_TOOLS=Off -DLLVM_VERSION_PRINTER_SHOW_HOST_TARGET_INFO=Off
|
||||
meson_build $DXMT_REPO -Dnative_llvm_path="$PREFIX"
|
||||
if [ "$ARCH" == "x86_64" ]; then
|
||||
meson_build $D3DMETAL_REPO -Dtests=disabled
|
||||
else
|
||||
# empty placeholder file
|
||||
$CC -dynamiclib -x c /dev/null -o "$PREFIX/lib/libd3dmetal-native.dylib"
|
||||
fi
|
||||
}
|
||||
|
||||
fixup_imports() {
|
||||
_file=$1
|
||||
_list=$(otool -L "$_file" | tail -n +2 | cut -d ' ' -f 1 | awk '{$1=$1};1')
|
||||
for g in $_list
|
||||
do
|
||||
base=$(basename "$g")
|
||||
basefilename=${base%.*}
|
||||
libname=${basefilename#lib*}
|
||||
dir=$(dirname "$g")
|
||||
if [ "$dir" == "$PREFIX/lib" ] || [ "$dir" == "@rpath" ]; then
|
||||
if [ "$PLATFORM" == "macos" ]; then
|
||||
newname="@rpath/$libname.framework/Versions/A/$libname"
|
||||
else
|
||||
newname="@rpath/$libname.framework/$libname"
|
||||
fi
|
||||
install_name_tool -change "$g" "$newname" "$_file"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
fixup_dylib () {
|
||||
FILE=$1
|
||||
BASE=$(basename "$FILE")
|
||||
BASEFILENAME=${BASE%.*}
|
||||
@@ -801,18 +888,16 @@ fixup () {
|
||||
INFOPATH="$FRAMEWORKPATH"
|
||||
fi
|
||||
NEWFILE="$FRAMEWORKPATH/$LIBNAME"
|
||||
LIST=$(otool -L "$FILE" | tail -n +2 | cut -d ' ' -f 1 | awk '{$1=$1};1')
|
||||
OLDIFS=$IFS
|
||||
IFS=$'\n'
|
||||
echo "${GREEN}Fixing up $FILE...${NC}"
|
||||
mkdir -p "$FRAMEWORKPATH"
|
||||
mkdir -p "$INFOPATH"
|
||||
cp -a "$FILE" "$NEWFILE"
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleExecutable string $LIBNAME" "$INFOPATH/Info.plist"
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleIdentifier string $BUNDLE_ID" "$INFOPATH/Info.plist"
|
||||
/usr/libexec/PlistBuddy -c "Add :MinimumOSVersion string $SDKMINVER" "$INFOPATH/Info.plist"
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleVersion string 1" "$INFOPATH/Info.plist"
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string 1.0" "$INFOPATH/Info.plist"
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleExecutable string $LIBNAME" "$INFOPATH/Info.plist" || true
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleIdentifier string $BUNDLE_ID" "$INFOPATH/Info.plist" || true
|
||||
/usr/libexec/PlistBuddy -c "Add :MinimumOSVersion string $SDKMINVER" "$INFOPATH/Info.plist" || true
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleVersion string 1" "$INFOPATH/Info.plist" || true
|
||||
/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string 1.0" "$INFOPATH/Info.plist" || true
|
||||
if [ "$PLATFORM" == "macos" ]; then
|
||||
ln -sf "A" "$BASEFRAMEWORKPATH/Versions/Current"
|
||||
ln -sf "Versions/Current/Resources" "$BASEFRAMEWORKPATH/Resources"
|
||||
@@ -820,21 +905,7 @@ fixup () {
|
||||
fi
|
||||
newname="@rpath/$FRAMEWORKNAME/$LIBNAME"
|
||||
install_name_tool -id "$newname" "$NEWFILE"
|
||||
for g in $LIST
|
||||
do
|
||||
base=$(basename "$g")
|
||||
basefilename=${base%.*}
|
||||
libname=${basefilename#lib*}
|
||||
dir=$(dirname "$g")
|
||||
if [ "$dir" == "$PREFIX/lib" ] || [ "$dir" == "@rpath" ]; then
|
||||
if [ "$PLATFORM" == "macos" ]; then
|
||||
newname="@rpath/$libname.framework/Versions/A/$libname"
|
||||
else
|
||||
newname="@rpath/$libname.framework/$libname"
|
||||
fi
|
||||
install_name_tool -change "$g" "$newname" "$NEWFILE"
|
||||
fi
|
||||
done
|
||||
fixup_imports "$NEWFILE"
|
||||
IFS=$OLDIFS
|
||||
}
|
||||
|
||||
@@ -844,7 +915,14 @@ fixup_all () {
|
||||
FILES=$(find "$SYSROOT_DIR/lib" -type f -maxdepth 1 -name "*.dylib")
|
||||
for f in $FILES
|
||||
do
|
||||
fixup $f
|
||||
echo "${GREEN}Fixing up $f...${NC}"
|
||||
fixup_dylib $f
|
||||
done
|
||||
FILES=$(find "$SYSROOT_DIR/libexec" -type f -maxdepth 1 -perm +111)
|
||||
for f in $FILES
|
||||
do
|
||||
echo "${GREEN}Fixing up $f...${NC}"
|
||||
fixup_imports $f
|
||||
done
|
||||
IFS=$OLDIFS
|
||||
}
|
||||
@@ -1089,7 +1167,7 @@ fi
|
||||
echo "${GREEN}Deleting old sysroot!${NC}"
|
||||
rm -rf "$PREFIX/"*
|
||||
rm -f "$BUILD_DIR/BUILD_SUCCESS"
|
||||
rm -f "$BUILD_DIR/meson*.cross"
|
||||
rm -f "$BUILD_DIR"/meson*.cross
|
||||
rm -f "$BUILD_DIR/cross.cmake"
|
||||
mkdir -p "$PREFIX/Frameworks"
|
||||
copy_private_headers
|
||||
@@ -1098,6 +1176,9 @@ build_qemu_dependencies
|
||||
build $QEMU_DIR --cross-prefix="" $QEMU_PLATFORM_BUILD_FLAGS $QEMU_DEBUG_FLAGS
|
||||
build_spice_client
|
||||
build_vulkan_drivers
|
||||
if [ "$PLATFORM" == "macos" ]; then
|
||||
build_d3d_drivers
|
||||
fi
|
||||
fixup_all
|
||||
remove_shared_gst_plugins # another hack...
|
||||
echo "${GREEN}All done!${NC}"
|
||||
|
||||
@@ -92,10 +92,12 @@ if [ "$SDK" == "macosx" ]; then
|
||||
# this way we can import into Xcode and re-sign from there
|
||||
UTM_ENTITLEMENTS="/tmp/utm.$$.entitlements"
|
||||
LAUNCHER_ENTITLEMENTS="/tmp/launcher.$$.entitlements"
|
||||
RENDERER_ENTITLEMENTS="/tmp/renderer.$$.entitlements"
|
||||
HELPER_ENTITLEMENTS="/tmp/helper.$$.entitlements"
|
||||
CLI_ENTITLEMENTS="/tmp/cli.$$.entitlements"
|
||||
cp "$BASEDIR/../Platform/macOS/macOS.entitlements" "$UTM_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../QEMULauncher/QEMULauncher.entitlements" "$LAUNCHER_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../QEMURenderServer/QEMURenderServer.entitlements" "$RENDERER_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../QEMUHelper/QEMUHelper.entitlements" "$HELPER_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../utmctl/utmctl.entitlements" "$CLI_ENTITLEMENTS"
|
||||
if [ ! -z "$TEAM_IDENTIFIER" ]; then
|
||||
@@ -105,12 +107,15 @@ if [ "$SDK" == "macosx" ]; then
|
||||
/usr/libexec/PlistBuddy -c "Set :com.apple.security.application-groups:0 ${TEAM_ID_PREFIX}${PRODUCT_BUNDLE_PREFIX}.UTM" "$UTM_ENTITLEMENTS"
|
||||
/usr/libexec/PlistBuddy -c "Set :com.apple.security.application-groups:0 ${TEAM_ID_PREFIX}${PRODUCT_BUNDLE_PREFIX}.UTM" "$HELPER_ENTITLEMENTS"
|
||||
/usr/libexec/PlistBuddy -c "Set :com.apple.security.application-groups:0 ${TEAM_ID_PREFIX}${PRODUCT_BUNDLE_PREFIX}.UTM" "$CLI_ENTITLEMENTS"
|
||||
# nested bundles must be signed before the XPC service that contains them
|
||||
codesign --force --sign - --entitlements "$LAUNCHER_ENTITLEMENTS" --timestamp=none --options runtime "$BUILT_PATH/Contents/XPCServices/QEMUHelper.xpc/Contents/MacOS/QEMULauncher.app/Contents/MacOS/QEMULauncher"
|
||||
codesign --force --sign - --entitlements "$RENDERER_ENTITLEMENTS" --timestamp=none --options runtime "$BUILT_PATH/Contents/XPCServices/QEMUHelper.xpc/Contents/MacOS/QEMURenderServer.app/Contents/MacOS/QEMURenderServer"
|
||||
codesign --force --sign - --entitlements "$HELPER_ENTITLEMENTS" --timestamp=none --options runtime "$BUILT_PATH/Contents/XPCServices/QEMUHelper.xpc/Contents/MacOS/QEMUHelper"
|
||||
codesign --force --sign - --entitlements "$CLI_ENTITLEMENTS" --timestamp=none --options runtime "$BUILT_PATH/Contents/MacOS/utmctl"
|
||||
codesign --force --sign - --entitlements "$UTM_ENTITLEMENTS" --timestamp=none --options runtime "$BUILT_PATH/Contents/MacOS/UTM"
|
||||
rm "$UTM_ENTITLEMENTS"
|
||||
rm "$LAUNCHER_ENTITLEMENTS"
|
||||
rm "$RENDERER_ENTITLEMENTS"
|
||||
rm "$HELPER_ENTITLEMENTS"
|
||||
rm "$CLI_ENTITLEMENTS"
|
||||
fi
|
||||
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
usage () {
|
||||
echo "Usage: $(basename $0) sysroot-dir [dmg-url]"
|
||||
echo ""
|
||||
echo " sysroot-dir Sysroot to install into, e.g. sysroot-macOS-arm64_x86_64."
|
||||
echo " dmg-url D3DMetal distribution DMG, either a URL or a local path."
|
||||
echo ""
|
||||
echo "Installs D3DMetal.framework into <sysroot-dir>/Frameworks, rebranded to"
|
||||
echo "BUNDLE_ID below and ad-hoc signed. Does nothing if no URL is given."
|
||||
echo ""
|
||||
exit 1
|
||||
}
|
||||
|
||||
# D3DMetal loads its own default.metallib through
|
||||
# [NSBundle bundleWithIdentifier:@"com.apple.D3DMetal"]
|
||||
# using that identifier as a literal compiled into the framework binary. We must
|
||||
# not ship a com.apple.* bundle, so the identifier is rewritten in BOTH the
|
||||
# Info.plist and the binary -- rewriting only one makes the lookup return nil and
|
||||
# every D3DMetal process aborts in -[MTLDevice newLibraryWithFile:nil error:].
|
||||
APPLE_BUNDLE_ID=com.apple.D3DMetal
|
||||
BUNDLE_ID=com.elppa.D3DMetal
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
SYSROOT_DIR="$1"
|
||||
DMG_URL="$2"
|
||||
|
||||
if [ -z "$DMG_URL" ]; then
|
||||
echo "note: no D3DMetal DMG URL given, skipping"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ${#APPLE_BUNDLE_ID} -ne ${#BUNDLE_ID} ]; then
|
||||
echo "error: $BUNDLE_ID must be ${#APPLE_BUNDLE_ID} bytes to patch in place" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FRAMEWORK="$SYSROOT_DIR/Frameworks/D3DMetal.framework"
|
||||
MOUNT="$PWD/d3dmetal-mount"
|
||||
DMG="$PWD/d3dmetal.dmg"
|
||||
|
||||
# Rewrite every occurrence of $1 with $2 in the binary $3, in place. Fails if the
|
||||
# identifier is absent, so a future D3DMetal that drops it cannot ship silently.
|
||||
patch_binary_identifier () {
|
||||
LC_ALL=C perl -0777 -i -pe '
|
||||
BEGIN { $old = shift @ARGV; $new = shift @ARGV }
|
||||
$found += s/\Q$old\E/$new/g;
|
||||
END { die "error: $old not found in $ARGV\n" unless $found }
|
||||
' "$1" "$2" "$3"
|
||||
}
|
||||
|
||||
if [ -f "$DMG_URL" ]; then
|
||||
DMG="$DMG_URL"
|
||||
else
|
||||
curl -f -L -o "$DMG" "$DMG_URL"
|
||||
fi
|
||||
|
||||
# The distribution DMG carries a license agreement, which hdiutil prompts for on
|
||||
# stdin unless we answer it.
|
||||
mkdir -p "$MOUNT"
|
||||
yes | PAGER=cat hdiutil attach -nobrowse -readonly -noautoopen -mountpoint "$MOUNT" "$DMG"
|
||||
trap 'hdiutil detach "$MOUNT" -quiet || true' EXIT
|
||||
|
||||
mkdir -p "$SYSROOT_DIR/Frameworks"
|
||||
rm -rf "$FRAMEWORK"
|
||||
ditto "$MOUNT/redist/lib/external/D3DMetal.framework" "$FRAMEWORK"
|
||||
xattr -drs com.apple.quarantine "$FRAMEWORK"
|
||||
|
||||
patch_binary_identifier "$APPLE_BUNDLE_ID" "$BUNDLE_ID" "$FRAMEWORK/Versions/A/D3DMetal"
|
||||
plutil -replace CFBundleIdentifier -string "$BUNDLE_ID" "$FRAMEWORK/Resources/Info.plist"
|
||||
|
||||
# Signs after the rewrite so the signing identifier is derived from the new
|
||||
# Info.plist and the two agree.
|
||||
codesign --force --sign - "$FRAMEWORK"
|
||||
|
||||
echo "installed D3DMetal $(plutil -extract CFBundleShortVersionString raw "$FRAMEWORK/Resources/version.plist") as $BUNDLE_ID into $FRAMEWORK"
|
||||
@@ -72,6 +72,7 @@ pack_dir() {
|
||||
cp -a "$SRC/$DIR" "$TGT/$DIR"
|
||||
}
|
||||
|
||||
pack_all_objs "$BASEDIR" "*/libexec/virgl_render_server"
|
||||
pack_all_objs "$BASEDIR" "*/bin/qemu-*"
|
||||
pack_all_objs "$BASEDIR" "*/lib/*.dylib"
|
||||
pack_all_objs "$BASEDIR" "*/lib/*.a"
|
||||
|
||||
@@ -31,6 +31,7 @@ OPTIONS="/tmp/options.$$.plist"
|
||||
SIGNED="/tmp/signed.$$"
|
||||
UTM_ENTITLEMENTS="/tmp/utm.$$.entitlements"
|
||||
LAUNCHER_ENTITLEMENTS="/tmp/launcher.$$.entitlements"
|
||||
RENDERER_ENTITLEMENTS="/tmp/renderer.$$.entitlements"
|
||||
HELPER_ENTITLEMENTS="/tmp/helper.$$.entitlements"
|
||||
CLI_ENTITLEMENTS="/tmp/cli.$$.entitlements"
|
||||
INPUT_COPY="/tmp/UTM.$$.xcarchive"
|
||||
@@ -71,11 +72,13 @@ EOL
|
||||
if [ "$MODE" == "unsigned" ]; then
|
||||
cp "$BASEDIR/../Platform/macOS/macOS-unsigned.entitlements" "$UTM_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../QEMULauncher/QEMULauncher-unsigned.entitlements" "$LAUNCHER_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../QEMURenderServer/QEMURenderServer-unsigned.entitlements" "$RENDERER_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../QEMUHelper/QEMUHelper-unsigned.entitlements" "$HELPER_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../utmctl/utmctl-unsigned.entitlements" "$CLI_ENTITLEMENTS"
|
||||
else
|
||||
cp "$BASEDIR/../Platform/macOS/macOS.entitlements" "$UTM_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../QEMULauncher/QEMULauncher.entitlements" "$LAUNCHER_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../QEMURenderServer/QEMURenderServer.entitlements" "$RENDERER_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../QEMUHelper/QEMUHelper.entitlements" "$HELPER_ENTITLEMENTS"
|
||||
cp "$BASEDIR/../utmctl/utmctl.entitlements" "$CLI_ENTITLEMENTS"
|
||||
|
||||
@@ -92,7 +95,9 @@ fi
|
||||
rm -rf "$INPUT_COPY"
|
||||
cp -a "$INPUT" "$INPUT_COPY"
|
||||
find "$INPUT_COPY/Products/Applications/UTM.app" -type d -path '*/Frameworks/*.framework' -exec codesign --force --sign - --timestamp=none \{\} \;
|
||||
# nested bundles must be signed before the XPC service that contains them
|
||||
codesign --force --sign - --entitlements "$LAUNCHER_ENTITLEMENTS" --timestamp=none --options runtime "$INPUT_COPY/Products/Applications/UTM.app/Contents/XPCServices/QEMUHelper.xpc/Contents/MacOS/QEMULauncher.app/Contents/MacOS/QEMULauncher"
|
||||
codesign --force --sign - --entitlements "$RENDERER_ENTITLEMENTS" --timestamp=none --options runtime "$INPUT_COPY/Products/Applications/UTM.app/Contents/XPCServices/QEMUHelper.xpc/Contents/MacOS/QEMURenderServer.app/Contents/MacOS/QEMURenderServer"
|
||||
codesign --force --sign - --entitlements "$HELPER_ENTITLEMENTS" --timestamp=none --options runtime "$INPUT_COPY/Products/Applications/UTM.app/Contents/XPCServices/QEMUHelper.xpc/Contents/MacOS/QEMUHelper"
|
||||
codesign --force --sign - --entitlements "$CLI_ENTITLEMENTS" --timestamp=none --options runtime "$INPUT_COPY/Products/Applications/UTM.app/Contents/MacOS/utmctl"
|
||||
codesign --force --sign - --entitlements "$UTM_ENTITLEMENTS" --timestamp=none --options runtime "$INPUT_COPY/Products/Applications/UTM.app/Contents/MacOS/UTM"
|
||||
@@ -107,6 +112,7 @@ fi
|
||||
rm "$OPTIONS"
|
||||
rm "$UTM_ENTITLEMENTS"
|
||||
rm "$LAUNCHER_ENTITLEMENTS"
|
||||
rm "$RENDERER_ENTITLEMENTS"
|
||||
rm "$HELPER_ENTITLEMENTS"
|
||||
rm "$CLI_ENTITLEMENTS"
|
||||
rm -rf "$INPUT_COPY"
|
||||
|
||||
Reference in New Issue
Block a user