I am writing an iOS application using Apple\'s new Metal framework. I have an array of Matrix4 objects (see Ray Wenderlich\'s tutorial) that I need to pass in to a shader via
Obviously the point of using shared memory and MTLDevice.makeBuffer(bytesNoCopy:...)
is to avoid redundant memory copies. Therefore, ideally we look for a design that allows us to easily manipulate the data after it's already been loaded into the MTLBuffer
object.
After researching this for a while, I've decided to try and create a semi-generic solution to allow for simplified allocation of page-aligned memory, loading your content into that memory, and subsequently manipulating your items in that shared memory block.
I've created a Swift array implementation called PageAlignedArray that matches the interface and functionality of the built-in Swift array, but always resides on page-aligned memory, and so can be very easily made into an MTLBuffer
. I've also added a convenience method to directly convert PageAlignedArray
into a Metal buffer.
Of course, you can continue to mutate your array afterwards and your updates will be automatically available to the GPU courtesy of the shared-memory architecture. However, keep in mind that you must regenerate your MTLBuffer
object whenever the array's length changes.
Here's a quick code sample:
var alignedArray : PageAlignedContiguousArray = [matrixTest, matrixTest]
alignedArray.append(item)
alignedArray.removeFirst() // Behaves just like a built-in array, with all convenience methods
// When it's time to generate a Metal buffer:
let testMetalBuffer = device?.makeBufferWithPageAlignedArray(alignedArray)
The sample uses matrix_double4x4
, but the array should work for any Swift value types. Please note that if you use a reference type (such as any kind of class
), the array will contain pointers to your elements and so won't be usable from your GPU code.