我想用newBufferWithBytesNoCopy函数创建一个 Metal 缓冲区,让 CPU 和 GPU 共享内存并练习零拷贝数据传输。
newBufferWithBytesNoCopy 函数接受一个 UnsafeMutablePointer 类型的指针,该指针需要对齐到 16K(16384) 字节。
任何人都可以提供有关如何在 Swift 中创建特定大小的对齐内存的建议吗?
我想用newBufferWithBytesNoCopy函数创建一个 Metal 缓冲区,让 CPU 和 GPU 共享内存并练习零拷贝数据传输。
newBufferWithBytesNoCopy 函数接受一个 UnsafeMutablePointer 类型的指针,该指针需要对齐到 16K(16384) 字节。
任何人都可以提供有关如何在 Swift 中创建特定大小的对齐内存的建议吗?
我相信这应该对你有用:
var memory:UnsafeMutablePointer<Void> = nil
var alignment:UInt = 0x4000 // 16K aligned
var size:UInt = bufferSize // bufferSize == your buffer size
posix_memalign(&memory, alignment, size)
以供参考:
http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_memalign.html
PageAlignedArray是一个项目,当内存将与 Metal 一起使用时,它会为您处理内存分配问题。
我没有看到您的 16k 字节要求。调试器说 4k。也许您可以提供参考?它应该基于系统的页面大小。
我相信最初的想法来自memkite ,如下所示:
private func setupSharedMemoryWithSize(byteCount: Int) ->
(pointer: UnsafeMutablePointer<Void>,
memoryWrapper: COpaquePointer)
{
let memoryAlignment = 0x1000 // 4096 bytes, 0x4000 would be 16k
var memory: UnsafeMutablePointer<Void> = nil
posix_memalign(&memory, memoryAlignment, byteSizeWithAlignment(memoryAlignment, size: byteCount))
let memoryWrapper = COpaquePointer(memory)
return (memory, memoryWrapper)
}
您需要计算要分配的正确内存量,以便它位于字节边界上。这意味着您可能需要分配比您想要的更多的钱。在这里,您传递您需要的大小和对齐方式,它将返回您应该分配的数量。
private func byteSizeWithAlignment(alignment: Int, size: Int) -> Int
{
return Int(ceil(Float(size) / Float(alignment))) * alignment
}
let (pointer, memoryWrapper) = setupSharedMemoryWithSize(byteCount)
var unsafeVoidPointer: UnsafeMutablePointer<Void> = pointer
// Assuming your underlying data is unsigned 8-bit integers.
let unsafeMutablePointer = UnsafeMutablePointer<UInt8>(memoryWrapper)
let unsafeMutableBufferPointer = UnsafeMutableBufferPointer(start: unsafeMutablePointer, count: byteCount)
不要忘记释放您分配的内存。
posix_memalign
如今,您无需指定 .StorageModeShared即可分配内存。
let byteCount = 1000 * sizeof(Float)
let sharedMetalBuffer = self.metalDevice.newBufferWithLength(byteCount, options: .StorageModeShared)
After experiencing some annoyance with this problem, I've decided to go ahead and create a simple solution that should make this a lot easier.
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<matrix_double4x4> = [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 device = MTLCreateSystemDefaultDevice()
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.
Please grab PageAlignedArray
here: https://github.com/eldoogy/PageAlignedArray