Open chyyran opened 1 month ago
error parameter should be set if the method returns NO
Huh, that's very odd, and contrary to the documented behaviour of the function - the header says:
@method
serializeToURL:error:@abstract
Write the contents of a MTLBinaryArchive to a file.@discussion
Persisting the archive to a file allows opening the archive on a subsequent instance of the app, making available the contents without recompiling.@param
url The file URL to which to write the file@param
error If the function fails, this will be set to describe the failure. This can be (but is not required to be) an error from the MTLBinaryArchiveDomain domain. Other possible errors can be file access or I/O related.@return
Whether or not the writing the file succeeded.
Emphasis mine, I cannot read this in any other way than that the error is set if the method fails (and that's also the expected behaviour in general, see https://github.com/madsmtm/objc2/pull/276 for more details).
So I'd argue that this is an Apple bug, but I guess I'll have a look at what Swift does in this case.
This won't actually give you the full unwind message though due to C-unwind ABI changes
Yeah, see also https://github.com/madsmtm/objc2/issues/539, should hopefully be a bit better with the next version of objc2
.
Smaller reproducer:
use objc2::rc::Retained;
use objc2_foundation::{ns_string, NSURL};
use objc2_metal::{
MTLBinaryArchive, MTLBinaryArchiveDescriptor, MTLCreateSystemDefaultDevice, MTLDevice,
};
#[link(name = "CoreGraphics", kind = "framework")]
extern "C" {}
fn main() {
unsafe {
let device = Retained::from_raw(MTLCreateSystemDefaultDevice()).unwrap();
let binary_archive = device
.newBinaryArchiveWithDescriptor_error(&MTLBinaryArchiveDescriptor::new())
.unwrap();
let metal_lib = NSURL::URLWithString(ns_string!("file://test.metallib")).unwrap();
if let Err(e) = binary_archive.serializeToURL_error(&metal_lib) {
eprintln!("{:?}", e.localizedDescription());
}
}
}
Equivalent Swift:
import Foundation
import Metal
import CoreGraphics
let device = MTLCreateSystemDefaultDevice()!
let binary_archive = try! device.makeBinaryArchive(descriptor: MTLBinaryArchiveDescriptor())
let metal_lib = NSURL(string: "file://test.metallib")!
do {
try binary_archive.serialize(to: metal_lib as URL)
} catch {
print(error)
}
Seems like they return a Foundation._GenericObjCError.nilError
.
In newer versions Foundation.UnknownNSError.missingError
, see https://github.com/apple/swift-corelibs-foundation/blob/86a733f50607d3ffed67357d2a518f8010c208b3/Sources/Foundation/NSError.swift#L876-L885.
Hmm, wondering how we can do the same, without defining a whole new NSError
subclass? Maybe we use a custom "__objc2"
NSErrorDomain
, a custom status code, and a useful description/debug description? Might also be useful for objc2::exception::catch
which currently has to awkwardly handle nil
exceptions.
Although all of that's still fallible in OOM situations, so we'll still have to panic/abort somewhere.
And the error should of course be cached.
I'm trying to serialize a
MTLBinaryArchive
to a file inside the application bundle caches directory.This is panicking unexpectedly with objc2 generated code
How I'm debugging this is a little complex so it might just be easier to give repro instructions.
This won't actually give you the full unwind message though due to C-unwind ABI changes, but I wrapped it in
catch_unwind
in the repro branch (https://github.com/SnowflakePowered/librashader/tree/metal-shader-cache) to get more of that out. I got this backtrace via a very finicky debug setup with C ABI bindings and running within XCode so it's too complicated to set up compared to just thecargo test
.