From ad60008b6a8b07cc6777624855d1ddeb8917ec7b Mon Sep 17 00:00:00 2001 From: Ryan Date: Thu, 9 May 2024 10:49:41 -0700 Subject: [PATCH] ryanmyers: Improve logging for Metallib function lookup failures (#7836) If a .metallib was compiled with a target iOS version that's newer than the current device, loading the .metallib may succeed, but finding main0 (or any other function in it) will fail. Currently, this causes a crash due to an assert. Logging the error and returning MetalFunctionBundle::error() makes the crash slightly easier to diagnose. (Note that in practice, this will probably be a useless "Compiler encountered an internal error" message -- the GPU backend is crashing, and the Metal stub library sees XPC_ERROR_CONNECTION_INTERRUPTED. It retries up to 3 times (crashing each time) and then gives up.) --- .../backend/src/metal/MetalShaderCompiler.mm | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/filament/backend/src/metal/MetalShaderCompiler.mm b/filament/backend/src/metal/MetalShaderCompiler.mm index 1aa02f9c87..90d6a47721 100644 --- a/filament/backend/src/metal/MetalShaderCompiler.mm +++ b/filament/backend/src/metal/MetalShaderCompiler.mm @@ -169,6 +169,23 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept { id function = [library newFunctionWithName:@"main0" constantValues:constants error:&error]; + if (function == nil) { + // If the library loads but functions within it fail to load, it usually means the + // GPU backend crashed. (This can happen if it's a Metallib shader that was compiled + // with a minimum iOS version that's newer than this device.) + NSString* errorMessage = @"unknown error"; + if (error) { + auto description = + [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding]; + utils::slog.w << description << utils::io::endl; + errorMessage = error.localizedDescription; + } + PANIC_LOG("Failed to load main0 in Metal program."); + NSString* programName = + [NSString stringWithFormat:@"%s::main0", program.getName().c_str_safe()]; + return MetalFunctionBundle::error(errorMessage, programName); + } + if (!program.getName().empty()) { function.label = @(program.getName().c_str()); }