问题是makeBuffer需要页面对齐的内存地址和页面对齐的长度.这些要求不仅在文档中 – 它们也是使用运行时断言强制执行的.
我写的代码必须处理各种传入的分辨率和像素格式,偶尔我会得到未对齐的缓冲区或未对齐的长度.在研究了这个之后,我发现了一个允许我为这些实例使用共享内存的hack.
基本上我所做的是将未对齐的缓冲区地址向下舍入到最近的页面边界,并使用makeTexture中的offset参数来确保GPU从正确的位置开始读取.然后我将长度向上舍入到最接近的页面大小.显然内存将是有效的(因为分配只能在页面边界上发生),我认为可以安全地假设GPU没有写入或破坏该内存.
这是我用来从未对齐的缓冲区分配共享缓冲区的代码:
extension MTLDevice { func makeTextureFromUnalignedBuffer(textureDescriptor : MTLTextureDescriptor,bufferPtr : UnsafeMutableRawPointer,bufferLength : UInt,bytesPerRow : Int) -> MTLTexture? { var calculatedBufferLength = bufferLength let pageSize = UInt(getpagesize()) let pageSizeBitmask = UInt(getpagesize()) - 1 let alignedBufferAddr = UnsafeMutableRawPointer(bitPattern: UInt(bitPattern: bufferPtr) & ~pageSizeBitmask) let offset = UInt(bitPattern: bufferPtr) & pageSizeBitmask assert(bytesPerRow % 64 == 0 && offset % 64 == 0,"Supplied bufferPtr and bytesPerRow must be aligned on a 64-byte boundary!") calculatedBufferLength += offset if (calculatedBufferLength & pageSizeBitmask) != 0 { calculatedBufferLength &= ~(pageSize - 1) calculatedBufferLength += pageSize } let buffer = self.makeBuffer(bytesNoCopy: alignedBufferAddr!,length: Int(calculatedBufferLength),options: .storageModeShared,deallocator: nil) return buffer.makeTexture(descriptor: textureDescriptor,offset: Int(offset),bytesPerRow: bytesPerRow) } }
我已经在许多不同的缓冲区上测试了它,它似乎工作得很好(仅在iOS上测试,而不是在macOS上测试).我的问题是:这种方法安全吗?任何明显的原因,为什么这不起作用?
再说一次,如果它是安全的,为什么首先强加要求?为什么API不是这样做的呢?
解决方法
After discussing your approach with engineering we concluded that it
was valid and safe. Some noteworthy quotes:“The framework shouldn’t care about the fact that the user doesn’t own
the entire page,because it shouldn’t ever read before the offset
where the valid data begins.”“It really shouldn’t [care],but in general if the developer can use
page-allocators rather than malloc for their incoming images,that
would be nice.”As to why the alignment constraints/assertions are in place:
“Typically mapping memory you don’t own into another address space is a bit icky,even if it works in practice. This is one reason why we required mapping to be page aligned,because the hardware really is mapping (and gaining write access) to the entire page.”