mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-06-10 18:21:11 +00:00
Fix iOS Metal startup crash
This commit is contained in:
parent
42ed8f1580
commit
f532a8e73b
3 changed files with 211 additions and 14 deletions
|
|
@ -176,6 +176,7 @@
|
|||
"CMAKE_SYSTEM_NAME": "iOS",
|
||||
"CMAKE_OSX_SYSROOT": "iphonesimulator",
|
||||
"CMAKE_OSX_ARCHITECTURES": "arm64",
|
||||
"CMAKE_OSX_DEPLOYMENT_TARGET": "16.0",
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"UNLEASHED_RECOMP_SKIP_TARGET_TOOL_EXECUTABLES": true,
|
||||
"UNLEASHED_RECOMP_HOST_TOOLS_DIR": "${sourceDir}/out/build/macos-release",
|
||||
|
|
@ -207,6 +208,7 @@
|
|||
"CMAKE_SYSTEM_NAME": "iOS",
|
||||
"CMAKE_OSX_SYSROOT": "iphoneos",
|
||||
"CMAKE_OSX_ARCHITECTURES": "arm64",
|
||||
"CMAKE_OSX_DEPLOYMENT_TARGET": "16.0",
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_INTERPROCEDURAL_OPTIMIZATION": true,
|
||||
"UNLEASHED_RECOMP_SKIP_TARGET_TOOL_EXECUTABLES": true,
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@
|
|||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<true/>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>13.0</string>
|
||||
<string>16.0</string>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ index 64e4dc9..1d14600 100644
|
|||
}
|
||||
}
|
||||
diff --git a/plume_metal.cpp b/plume_metal.cpp
|
||||
index ebbbaa3..6f5a82c 100644
|
||||
index ebbbaa3..854107a 100644
|
||||
--- a/plume_metal.cpp
|
||||
+++ b/plume_metal.cpp
|
||||
@@ -14,8 +14,12 @@
|
||||
|
|
@ -258,10 +258,58 @@ index ebbbaa3..6f5a82c 100644
|
|||
|
||||
#include "plume_metal.h"
|
||||
|
||||
@@ -38,6 +42,141 @@ namespace plume {
|
||||
@@ -38,6 +42,186 @@ namespace plume {
|
||||
return (n + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
+ bool supportsMetalFamily(MTL::Device* device, MTL::GPUFamily family) {
|
||||
+ return device != nullptr && device->supportsFamily(family);
|
||||
+ }
|
||||
+
|
||||
+ bool supportsBufferDeviceAddress(MTL::Device* device) {
|
||||
+ return supportsMetalFamily(device, MTL::GPUFamilyMetal3);
|
||||
+ }
|
||||
+
|
||||
+ uint64_t getRecommendedWorkingSetSize(MTL::Device* device) {
|
||||
+#if PLUME_IOS
|
||||
+ // recommendedMaxWorkingSetSize is iOS 16+. The app requires Metal 3 for
|
||||
+ // gpuAddress, but keep startup safe on older runtimes and SDK shims.
|
||||
+ (void)device;
|
||||
+ return 2ULL * 1024ULL * 1024ULL * 1024ULL;
|
||||
+#else
|
||||
+ return device->recommendedMaxWorkingSetSize();
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+ bool hasUnifiedMemory(MTL::Device* device) {
|
||||
+#if PLUME_IOS
|
||||
+ (void)device;
|
||||
+ return true;
|
||||
+#else
|
||||
+ return device->hasUnifiedMemory();
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+ bool supportsProgrammableSamplePositions(MTL::Device* device) {
|
||||
+#if PLUME_IOS
|
||||
+ return supportsMetalFamily(device, MTL::GPUFamilyApple3);
|
||||
+#else
|
||||
+ return device->programmableSamplePositionsSupported();
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+ spirv_cross::CompilerMSL::Options::ArgumentBuffersTier getArgumentBuffersTier(MTL::Device* device) {
|
||||
+#if PLUME_IOS
|
||||
+ return supportsMetalFamily(device, MTL::GPUFamilyApple3)
|
||||
+ ? spirv_cross::CompilerMSL::Options::ArgumentBuffersTier::Tier2
|
||||
+ : spirv_cross::CompilerMSL::Options::ArgumentBuffersTier::Tier1;
|
||||
+#else
|
||||
+ return device->argumentBuffersSupport() == MTL::ArgumentBuffersTier2
|
||||
+ ? spirv_cross::CompilerMSL::Options::ArgumentBuffersTier::Tier2
|
||||
+ : spirv_cross::CompilerMSL::Options::ArgumentBuffersTier::Tier1;
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+ uint32_t getSpirvResourceArrayCount(const spirv_cross::SPIRType& type) {
|
||||
+ uint32_t count = 1;
|
||||
+ for (const uint32_t dimension : type.array) {
|
||||
|
|
@ -339,10 +387,7 @@ index ebbbaa3..6f5a82c 100644
|
|||
+#endif
|
||||
+ options.set_msl_version(3, 0);
|
||||
+ options.argument_buffers = true;
|
||||
+ options.argument_buffers_tier =
|
||||
+ device->mtl->argumentBuffersSupport() == MTL::ArgumentBuffersTier2
|
||||
+ ? spirv_cross::CompilerMSL::Options::ArgumentBuffersTier::Tier2
|
||||
+ : spirv_cross::CompilerMSL::Options::ArgumentBuffersTier::Tier1;
|
||||
+ options.argument_buffers_tier = getArgumentBuffersTier(device->mtl);
|
||||
+ options.enable_base_index_zero = true;
|
||||
+ options.enable_decoration_binding = true;
|
||||
+ options.force_active_argument_buffer_resources = true;
|
||||
|
|
@ -400,7 +445,16 @@ index ebbbaa3..6f5a82c 100644
|
|||
uint64_t createClearPipelineKey(MTL::RenderPipelineDescriptor *pipelineDesc, bool depthWriteEnabled, bool stencilWriteEnabled) {
|
||||
auto colorFormat = [&](uint32_t index) {
|
||||
if (auto colorAttachment = pipelineDesc->colorAttachments()->object(index)) {
|
||||
@@ -1278,24 +1417,46 @@ namespace plume {
|
||||
@@ -1133,7 +1317,7 @@ namespace plume {
|
||||
}
|
||||
|
||||
uint64_t MetalBuffer::getDeviceAddress() const {
|
||||
- assert(device->mtl->supportsFamily(MTL::GPUFamilyMetal3) && "Device address is only supported on Metal3 devices.");
|
||||
+ assert(supportsBufferDeviceAddress(device->mtl) && "Device address is only supported on Metal3 devices.");
|
||||
return mtl->gpuAddress();
|
||||
}
|
||||
|
||||
@@ -1278,24 +1462,46 @@ namespace plume {
|
||||
assert(device != nullptr);
|
||||
assert(data != nullptr);
|
||||
assert(size > 0);
|
||||
|
|
@ -453,7 +507,7 @@ index ebbbaa3..6f5a82c 100644
|
|||
if (debugName) {
|
||||
debugName->release();
|
||||
}
|
||||
@@ -1306,10 +1467,16 @@ namespace plume {
|
||||
@@ -1306,10 +1512,16 @@ namespace plume {
|
||||
debugName->release();
|
||||
}
|
||||
debugName = NS::String::string(name.c_str(), NS::UTF8StringEncoding);
|
||||
|
|
@ -471,7 +525,110 @@ index ebbbaa3..6f5a82c 100644
|
|||
MTL::FunctionConstantValues *values = MTL::FunctionConstantValues::alloc()->init();
|
||||
if (specConstants != nullptr) {
|
||||
for (uint32_t i = 0; i < specConstantsCount; i++) {
|
||||
@@ -3308,6 +3475,9 @@ namespace plume {
|
||||
@@ -1793,6 +2005,11 @@ namespace plume {
|
||||
|
||||
MetalSwapChain::MetalSwapChain(MetalCommandQueue *commandQueue, const RenderWindow renderWindow, uint32_t textureCount, const RenderFormat format) {
|
||||
this->layer = static_cast<CA::MetalLayer*>(renderWindow.view);
|
||||
+ if (layer == nullptr) {
|
||||
+ fprintf(stderr, "Metal swapchain creation failed: SDL did not provide a CAMetalLayer.\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
layer->setDevice(commandQueue->device->mtl);
|
||||
layer->setPixelFormat(mapPixelFormat(format));
|
||||
|
||||
@@ -1819,7 +2036,10 @@ namespace plume {
|
||||
}
|
||||
|
||||
bool MetalSwapChain::present(const uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, const uint32_t waitSemaphoreCount) {
|
||||
- assert(layer != nullptr && "Cannot present without a valid layer.");
|
||||
+ if (layer == nullptr) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
NS::AutoreleasePool *releasePool = NS::AutoreleasePool::alloc()->init();
|
||||
|
||||
const MetalDrawable &drawable = drawables[textureIndex];
|
||||
@@ -1861,7 +2081,7 @@ namespace plume {
|
||||
bool MetalSwapChain::resize() {
|
||||
getWindowSize(width, height);
|
||||
|
||||
- if (width == 0 || height == 0) {
|
||||
+ if (layer == nullptr || width == 0 || height == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1886,11 +2106,29 @@ namespace plume {
|
||||
}
|
||||
|
||||
void MetalSwapChain::setVsyncEnabled(const bool vsyncEnabled) {
|
||||
+ if (layer == nullptr) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+#if PLUME_IOS
|
||||
+ // CAMetalLayer.displaySyncEnabled is unavailable on iOS. iOS drawables
|
||||
+ // are display-synchronized by default, so keep this as a no-op.
|
||||
+ (void)vsyncEnabled;
|
||||
+#else
|
||||
layer->setDisplaySyncEnabled(vsyncEnabled);
|
||||
+#endif
|
||||
}
|
||||
|
||||
bool MetalSwapChain::isVsyncEnabled() const {
|
||||
+ if (layer == nullptr) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+#if PLUME_IOS
|
||||
+ return true;
|
||||
+#else
|
||||
return layer->displaySyncEnabled();
|
||||
+#endif
|
||||
}
|
||||
|
||||
uint32_t MetalSwapChain::getWidth() const {
|
||||
@@ -1910,6 +2148,10 @@ namespace plume {
|
||||
assert(textureIndex != nullptr);
|
||||
assert(*textureIndex < MAX_DRAWABLES);
|
||||
|
||||
+ if (layer == nullptr) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
NS::AutoreleasePool *releasePool = NS::AutoreleasePool::alloc()->init();
|
||||
|
||||
// Create a command buffer just to encode the signal
|
||||
@@ -1923,6 +2165,7 @@ namespace plume {
|
||||
CA::MetalDrawable *nextDrawable = layer->nextDrawable();
|
||||
if (nextDrawable == nullptr) {
|
||||
fprintf(stderr, "No more drawables available for rendering.\n");
|
||||
+ releasePool->release();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1954,10 +2197,20 @@ namespace plume {
|
||||
}
|
||||
|
||||
uint32_t MetalSwapChain::getRefreshRate() const {
|
||||
+ if (windowWrapper == nullptr) {
|
||||
+ return 60;
|
||||
+ }
|
||||
+
|
||||
return windowWrapper->getRefreshRate();
|
||||
}
|
||||
|
||||
void MetalSwapChain::getWindowSize(uint32_t &dstWidth, uint32_t &dstHeight) const {
|
||||
+ if (windowWrapper == nullptr) {
|
||||
+ dstWidth = 0;
|
||||
+ dstHeight = 0;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
CocoaWindowAttributes attributes;
|
||||
windowWrapper->getWindowAttributes(&attributes);
|
||||
dstWidth = attributes.width;
|
||||
@@ -3308,6 +3561,9 @@ namespace plume {
|
||||
this->renderInterface = renderInterface;
|
||||
|
||||
// Device Selection
|
||||
|
|
@ -481,7 +638,7 @@ index ebbbaa3..6f5a82c 100644
|
|||
const NS::Array* devices = MTL::CopyAllDevices();
|
||||
MTL::Device *preferredDevice = nullptr;
|
||||
for (NS::UInteger i = 0; i < devices->count(); i++) {
|
||||
@@ -3320,9 +3490,18 @@ namespace plume {
|
||||
@@ -3320,12 +3576,31 @@ namespace plume {
|
||||
}
|
||||
|
||||
mtl = preferredDevice ? preferredDevice : MTL::CreateSystemDefaultDevice();;
|
||||
|
|
@ -490,6 +647,16 @@ index ebbbaa3..6f5a82c 100644
|
|||
+ return;
|
||||
+ }
|
||||
+
|
||||
+#if PLUME_IOS
|
||||
+ if (!supportsBufferDeviceAddress(mtl)) {
|
||||
+ fprintf(stderr, "Metal device '%s' does not support Metal 3 buffer GPU addresses required by Unleashed Recompiled.\n", mtl->name()->utf8String());
|
||||
+ mtl->release();
|
||||
+ mtl = nullptr;
|
||||
+ return;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ const uint64_t workingSetSize = getRecommendedWorkingSetSize(mtl);
|
||||
const std::string deviceName(mtl->name()->utf8String());
|
||||
description.name = deviceName;
|
||||
+#if PLUME_IOS
|
||||
|
|
@ -499,8 +666,36 @@ index ebbbaa3..6f5a82c 100644
|
|||
+#endif
|
||||
description.driverVersion = 1; // Unavailable
|
||||
description.vendor = mtl->supportsFamily(MTL::GPUFamilyApple1) ? RenderDeviceVendor::APPLE : getRenderDeviceVendor(mtl->registryID());
|
||||
description.dedicatedVideoMemory = mtl->recommendedMaxWorkingSetSize();
|
||||
@@ -3357,17 +3536,19 @@ namespace plume {
|
||||
- description.dedicatedVideoMemory = mtl->recommendedMaxWorkingSetSize();
|
||||
+ description.dedicatedVideoMemory = workingSetSize;
|
||||
|
||||
// Setup blit, clear and resolve shaders / pipelines
|
||||
createClearShaderLibrary();
|
||||
@@ -3337,7 +3612,7 @@ namespace plume {
|
||||
// TODO: Support Raytracing.
|
||||
// capabilities.raytracing = mtl->supportsRaytracing();
|
||||
capabilities.maxTextureSize = mtl->supportsFamily(MTL::GPUFamilyApple3) ? 16384 : 8192;
|
||||
- capabilities.sampleLocations = mtl->programmableSamplePositionsSupported();
|
||||
+ capabilities.sampleLocations = supportsProgrammableSamplePositions(mtl);
|
||||
capabilities.resolveModes = false;
|
||||
#if PLUME_IOS
|
||||
capabilities.descriptorIndexing = mtl->supportsFamily(MTL::GPUFamilyApple3);
|
||||
@@ -3345,11 +3620,11 @@ namespace plume {
|
||||
capabilities.descriptorIndexing = true;
|
||||
#endif
|
||||
capabilities.scalarBlockLayout = true;
|
||||
- capabilities.bufferDeviceAddress = mtl->supportsFamily(MTL::GPUFamilyApple3);
|
||||
+ capabilities.bufferDeviceAddress = supportsBufferDeviceAddress(mtl);
|
||||
capabilities.presentWait = false;
|
||||
- capabilities.preferHDR = mtl->recommendedMaxWorkingSetSize() > (512 * 1024 * 1024);
|
||||
+ capabilities.preferHDR = workingSetSize > (512 * 1024 * 1024);
|
||||
capabilities.dynamicDepthBias = true;
|
||||
- capabilities.uma = mtl->hasUnifiedMemory();
|
||||
+ capabilities.uma = hasUnifiedMemory(mtl);
|
||||
capabilities.gpuUploadHeap = capabilities.uma;
|
||||
capabilities.queryPools = false;
|
||||
|
||||
@@ -3357,17 +3632,19 @@ namespace plume {
|
||||
}
|
||||
|
||||
MetalDevice::~MetalDevice() {
|
||||
|
|
@ -526,7 +721,7 @@ index ebbbaa3..6f5a82c 100644
|
|||
}
|
||||
|
||||
std::unique_ptr<RenderDescriptorSet> MetalDevice::createDescriptorSet(const RenderDescriptorSetDesc &desc) {
|
||||
@@ -3635,16 +3816,24 @@ namespace plume {
|
||||
@@ -3635,16 +3912,24 @@ namespace plume {
|
||||
|
||||
MetalInterface::MetalInterface() {
|
||||
NS::AutoreleasePool *releasePool = NS::AutoreleasePool::alloc()->init();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue