Files
factorio-ios/platform/native/shim/metal_compat.m
T
SashaGoncharov19 51d085e865 Native iPhone port of Factorio 2.0.77
Run the original macOS ARM64 game code on iOS:
- tools/retarget.py: header-only Mach-O retargeting to an iOS dylib
- platform/native: UIKit host and macOS API shims (AppKit for SDL's
  Cocoa backend, CoreGraphics displays, CoreAudio device, Metal device
  properties, Wuffs PNG decoding, Steam and peripheral stubs)
- touch, overlay, iOS keyboard and hardware keyboard input
- tools/build_native.py: build, sign, install, data copy, launch
- docs: build guide, controls, architecture

Also includes the earlier static-translation research (ARM64 -> WASM ->
native) under docs/research, runtime/, tests/ and tools/.

No game files are included; the build reads them from a local install.
2026-10-23 15:27:58 +04:00

54 lines
2.8 KiB
Objective-C

// macOS-only MTLDevice properties, added to the device's concrete class before the game starts.
// Values describe a built-in Apple GPU. Other selectors iOS lacks are logged and answer zero.
#import <Metal/Metal.h>
#import <objc/runtime.h>
#import "fx.h"
static id fx_zero(id self, SEL _cmd, ...) { return nil; }
static BOOL fx_no(id self, SEL _cmd) { return NO; }
static BOOL fx_yes(id self, SEL _cmd) { return YES; }
static NSUInteger fx_uint_zero(id self, SEL _cmd) { return 0; }
static NSUInteger fx_uint_one(id self, SEL _cmd) { return 1; }
static void fx_add(Class cls, const char *name, IMP imp, const char *types) {
SEL sel = sel_registerName(name);
if (!class_getInstanceMethod(cls, sel)) {
class_addMethod(cls, sel, imp, types);
fx_log("[fx] Metal compat: -[%s %s]", class_getName(cls), name);
}
}
static BOOL (*fx_original_resolve)(id, SEL, SEL);
static BOOL fx_device_resolve(id cls, SEL _cmd, SEL sel) {
if (fx_original_resolve && fx_original_resolve(cls, _cmd, sel)) return YES;
const char *name = sel_getName(sel);
if (name[0] == '_' || name[0] == '.') return NO;
fx_log("[fx] Metal compat: unknown -[%s %s] -> 0", class_getName(cls), name);
class_addMethod(cls, sel, (IMP)fx_zero, "@@:");
return YES;
}
FX_EXPORT void fx_patch_metal(void) {
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
if (!device) { fx_log("[fx] no Metal device"); return; }
Class cls = object_getClass(device);
fx_log("[fx] Metal device %s (%s), unified memory %d", device.name.UTF8String, class_getName(cls), device.hasUnifiedMemory);
fx_add(cls, "isDepth24Stencil8PixelFormatSupported", (IMP)fx_no, "B@:");
fx_add(cls, "isLowPower", (IMP)fx_no, "B@:");
fx_add(cls, "isHeadless", (IMP)fx_no, "B@:");
fx_add(cls, "isRemovable", (IMP)fx_no, "B@:");
fx_add(cls, "location", (IMP)fx_uint_zero, "Q@:"); // MTLDeviceLocationBuiltIn
fx_add(cls, "locationNumber", (IMP)fx_uint_zero, "Q@:");
fx_add(cls, "maxTransferRate", (IMP)fx_uint_zero, "Q@:");
fx_add(cls, "peerGroupID", (IMP)fx_uint_zero, "Q@:");
fx_add(cls, "peerIndex", (IMP)fx_uint_zero, "I@:");
fx_add(cls, "peerCount", (IMP)fx_uint_one, "I@:");
fx_add(cls, "supportsBCTextureCompression", (IMP)fx_no, "B@:");
fx_add(cls, "areProgrammableSamplePositionsSupported", (IMP)fx_yes, "B@:");
Method resolve = class_getClassMethod(cls, @selector(resolveInstanceMethod:));
fx_original_resolve = (BOOL (*)(id, SEL, SEL))method_getImplementation(resolve);
// Overrides only this concrete class; inherited NSObject behavior is kept via fx_original_resolve.
if (!class_addMethod(object_getClass(cls), @selector(resolveInstanceMethod:), (IMP)fx_device_resolve, "B@::"))
method_setImplementation(resolve, (IMP)fx_device_resolve);
}