7

我想用newBufferWithBytesNoCopy函数创建一个 Metal 缓冲区,让 CPU 和 GPU 共享内存并练习零拷贝数据传输。

newBufferWithBytesNoCopy 函数接受一个 UnsafeMutablePointer 类型的指针,该指针需要对齐到 16K(16384) 字节。

任何人都可以提供有关如何在 Swift 中创建特定大小的对齐内存的建议吗?

4

3 回答 3

6

我相信这应该对你有用:

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

于 2014-12-09T08:02:25.830 回答
2

Swift PageAligned Array(只是有效的解决方案)

PageAlignedArray是一个项目,当内存将与 Metal 一起使用时,它会为您处理内存分配问题。

更多详情

4096字节对齐

我没有看到您的 16k 字节要求。调试器说 4k。也许您可以提供参考?它应该基于系统的页面大小。

使用 posix_memalign

我相信最初的想法来自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 的情况下分配共享内存。

posix_memalign如今,您无需指定 .StorageModeShared即可分配内存。

let byteCount = 1000 * sizeof(Float)
let sharedMetalBuffer = self.metalDevice.newBufferWithLength(byteCount, options: .StorageModeShared)
于 2016-02-08T09:12:20.973 回答
1

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

于 2016-10-13T00:52:52.537 回答