Looking to use Tier 2 AB in Swift. Since the struct can't be shared properly between header and Swift file like in Obj-C I have 2 structs:
In Swift:
struct VertexShaderArguments {
var uniforms: MTLBuffer
var materials: MTLBuffer
}
In Header:
struct VertexShaderArguments {
device Uniforms &uniforms;
device Material *materials;
};
And I construct and populate the argument buffer like so:
let vertexShaderArgumentBuffer = Renderer.device.makeBuffer(length: MemoryLayout<VertexShaderArguments>.stride)!
vertexShaderArgumentBuffer.label = "Vertex Shader Argument Buffer"
self.vertexShaderArgumentBuffer = vertexShaderArgumentBuffer
let vertexShaderArgumentBufferContents = vertexShaderArgumentBuffer.contents().assumingMemoryBound(to: VertexShaderArguments.self)
vertexShaderArgumentBufferContents.pointee.uniforms = uniformsBuffer
vertexShaderArgumentBufferContents.pointee.materials = scene.materialsBuffer
I've followed this example closely (https://developer.apple.com/documentation/metal/buffers/managing_groups_of_resources_with_argument_buffers) and consulted other resources.
Examining the VertexShaderArgumentBuffer in the Metal debugger reveals the error: "Not a valid buffer" for both members.
I would appreciate any assistance, and ask that Apple please try to provide more examples in Swift in the future. The fact that virtually all Metal examples are only Objective-C is baffling.
To populate an argument buffer, you need any device and constant pointers to be a valid GPU address. One way to get a valid GPU address is to take a gpuAddress property from an existing MTLBuffer and add an offset to it up to the buffer length. And gpuAddress is a uint64_t. The code you wrote tries to turn an id of an MTLBuffer into a GPU address, and the Metal debugger correctly indicates that it's not a valid buffer.
To fix your snippet,
struct VertexShaderArguments {
var uniforms: UInt64
var materials: UInt64
}
let vertexShaderArgumentBuffer = Renderer.device.makeBuffer(length: MemoryLayout<VertexShaderArguments>.stride)!
vertexShaderArgumentBuffer.label = "Vertex Shader Argument Buffer"
self.vertexShaderArgumentBuffer = vertexShaderArgumentBuffer
let vertexShaderArgumentBufferContents = vertexShaderArgumentBuffer.contents().assumingMemoryBound(to: VertexShaderArguments.self)
vertexShaderArgumentBufferContents.pointee.uniforms = uniformsBuffer.gpuAddress
vertexShaderArgumentBufferContents.pointee.materials = scene.materialsBuffer.gpuAddress
Also, I would advice declaring a struct common header, and then including that header in a bridging header and including it in the shaders. That way, you can be sure that they are layout compatible.
To do that, you can use some macros that are defined to different things depending on whether __METAL_VERSION_ is defined or not.
There's an example at around 6:53 in this talk from last years WWDC: https://developer.apple.com/videos/play/wwdc2022/10101/