For my project (being compiled as a framework) I have a file ops.metal:
kernel void add(device float *lhs [[buffer(0)]],
device float *rhs [[buffer(1)]],
device float *result [[buffer(2)]],
uint id [[ thread_position_in_grid ]])
{
result[id] = lhs[id] + rhs[id];
}
and the following Swift code:
@available(OSX 10.11, *)
public class MTLContext {
var device: MTLDevice!
var commandQueue:MTLCommandQueue!
var library:MTLLibrary!
var commandBuffer:MTLCommandBuffer
var commandEncoder:MTLComputeCommandEncoder
init() {
if let defaultDevice = MTLCreateSystemDefaultDevice() {
device = defaultDevice
print("device created")
} else {
print("Metal is not supported")
}
commandQueue = device.makeCommandQueue()
library = device.newDefaultLibrary()
if let defaultLibrary = device.newDefaultLibrary() {
library = defaultLibrary
} else {
print("could not load default library")
}
commandBuffer = commandQueue.makeCommandBuffer()
commandEncoder = commandBuffer.makeComputeCommandEncoder()
}
deinit {
commandEncoder.endEncoding()
}
}
When I try to create an instance of MTLContext in a unit test, the device is created, but the default library cannot be created ("could not load default library"). I've checked that the compiled framework has a default.metallib in Resources (which is the most common reason given for newDefaultLibrary).
Unfortunately I haven't been able to find any working examples that are creating compute kernels in a Metal shader file (there are a few examples using the performance shaders, but they don't need to make kernels in the shader file).
Any suggestions would be greatly appreciated!
newDefaultLibrary() loads from the main bundle of the currently running application. It doesn't search any embedded frameworks or other locations for libraries.
If you want to use a metallib that was compiled into an embedded framework, the easiest thing to do is to get a reference to its containing Bundle and ask for the default library of that bundle instead:
let frameworkBundle = Bundle(for: SomeClassFromMyShaderFramework.self)
guard let defaultLibrary = try? device.makeDefaultLibrary(bundle: frameworkBundle) else {
fatalError("Could not load default library from specified bundle")
}
This does require that you have at least one publicly-visible class in the framework containing your shaders, but that can be as simple as declaring an empty class strictly for the purpose of doing the bundle look-up:
public class SomeClassFromMyShaderFramework {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With