2016-09-29 75 views
2

作为this answer的后续问题。我试图用Metal中的内核函数替换运行在CPU上的for-loop来并行化计算并提高性能。在iOS中为MTLBuffer使用的数据分配内存金属

我的功能基本上是一个卷积。由于我反复接收到我输入数组值的新数据(数据源自AVCaptureSession),因此似乎使用newBufferWithBytesNoCopy:length:options:deallocator:是创建MTLBuffer对象的明智选择。下面是相关代码:

id <MTLBuffer> dataBuffer = [device newBufferWithBytesNoCopy:dataVector length:sizeof(dataVector) options:MTLResourceStorageModeShared deallocator:nil]; 
id <MTLBuffer> filterBuffer = [device newBufferWithBytesNoCopy:filterVector length:sizeof(filterVector) options:MTLResourceStorageModeShared deallocator:nil]; 
id <MTLBuffer> outBuffer = [device newBufferWithBytesNoCopy:outVector length:sizeof(outVector) options:MTLResourceStorageModeShared deallocator:nil]; 

运行此我得到以下错误:

failed assertion `newBufferWithBytesNoCopy:pointer 0x16fd0bd48 is not 4096 byte aligned.'

现在,我没有分配任何内存,但(用于测试目的)只是创建一个空数组一个固定大小的浮游物并用随机数填充。所以我的主要问题是:

如何浮点数分配到这些阵列以下列要求得到满足

This value must result in a page-aligned region of memory.

此外,一些其他问题的正确方法是:

  • 不它甚至可以用newBufferWithBytesNoCopy方法创建MTLBuffer,或者在性能方面复制数据不是真正的问题? (我的实际数据将包括每个视频帧大约43'000浮点值。)
  • MTLResourceStorageModeSharedMTLResourceOptions
  • 正确的选择的API参考说

    The storage allocation of the returned new MTLBuffer object is the same as the pointer input value. The existing memory allocation must be covered by a single VM region, typically allocated with vm_allocate or mmap. Memory allocated by malloc is specifically disallowed.

    这是否仅适用于输出缓冲区,还是应该与MTLBuffer使用的所有对象的存储分配不应与malloc

回答

4

分配页对齐内存的最简单方法是使用posix_memalign。以下是创建页对齐的内存缓冲器的完整的例子:

void *data = NULL; 
NSUInteger pageSize = getpagesize(); 
NSUInteger allocationSize = /* required byte count, rounded up to next multiple of page size */ pageSize * 10; 
int result = posix_memalign(&data, pageSize, allocationSize); 

if (result == noErr && data) { 
    id<MTLBuffer> buffer = [device newBufferWithBytesNoCopy:data 
                length:allocationSize 
                options:MTLResourceStorageModeShared 
               deallocator:^(void *pointer, NSUInteger length) 
                  { 
                   free(pointer); 
                  }]; 
    NSLog(@"Created buffer of length %d", (int)buffer.length); 
} 

因为你不能保证你的数据将在页对齐指针到达时,你可能会更好只是分配一个MTLBuffer任何大小都可以容纳您的数据,而无需使用无拷贝变体。如果您需要对数据进行实时处理,则应该创建一个缓冲池并循环,而不是等待每个命令缓冲区完成。这些用例的Shared存储模式是正确的。与malloc相关的警告仅适用于非复制情况,因为在其他情况下,金属会为您分配内存。

+0

嗨@warrenm关于循环虽然缓冲区一个简单的问题。我希望实时处理数据,但是我在'AVCaptureVideoDataOutput'上设置了'setAlwaysDiscardsLateVideoFrames:YES',所以在我完成包括Metal部分在内的所有旧计算之前,永远不会处理新帧。在这种情况下,是否需要创建一个缓冲池,因为我总是可以使用相同的缓冲区? –

+0

您不希望在Metal处理中阻止捕获输出队列,因此您将工作交给Metal命令队列以异步执行。根据处理帧需要多长时间,您可能会同时有多个帧在飞行。如果是这样的话,你仍然应该使用缓冲池来避免读写冲突或不必要的阻塞。如果你发现你总是(或经常)在下一帧到来之前完成处理,你可以减少池的大小,甚至完全消除它。 – warrenm

+0

我不明白。我认为用上面提到的方法丢弃晚期视频帧确实是这样的,即强制处理总是必须在处理下一帧之前完成,并丢弃早到的东西。 –