将未对齐的缓冲区提供给 MTLBuffer 是不是安全?
Posted
技术标签:
【中文标题】将未对齐的缓冲区提供给 MTLBuffer 是不是安全?【英文标题】:Is it safe to feed unaligned buffers to MTLBuffer?将未对齐的缓冲区提供给 MTLBuffer 是否安全? 【发布时间】:2017-02-18 11:56:26 【问题描述】:当尝试使用 Metal 从内存中快速将像素缓冲区绘制到屏幕时,我们使用 MTLDevice.makeBuffer(bytesNoCopy:..)
创建了 MTLBuffer
对象,以允许 GPU 直接从内存中读取像素而无需复制它。共享内存确实是实现良好像素传输性能的必备条件。
问题是makeBuffer
需要一个页面对齐的内存地址和一个页面对齐的length
。这些要求不仅在文档中——它们还使用运行时断言来强制执行。
我正在编写的代码必须处理各种传入的分辨率和像素格式,有时我会遇到未对齐的缓冲区或未对齐的长度。在对此进行研究后,我发现了一个允许我为这些实例使用共享内存的 hack。
基本上我所做的是将未对齐的缓冲区地址向下舍入到最近的页面边界,并使用来自makeTexture
的offset
参数来确保GPU 从正确的位置开始读取。然后我将length
舍入到最接近的页面大小。显然,内存将是有效的(因为分配只能发生在页面边界上),我认为可以安全地假设 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 不只是为我们做这件事?
【问题讨论】:
我也会在苹果开发者论坛上问这个问题。 【参考方案1】:我已经针对这个问题提交了 Apple TSI(技术支持事件),答案基本上是是的,它是安全的。如果有人感兴趣,这里是确切的回复:
在与工程部门讨论您的方法后,我们得出的结论是 是有效且安全的。一些值得注意的引语:
“框架不应该关心用户不拥有的事实 整个页面,因为它不应该在偏移之前读取 有效数据从哪里开始。”
“确实不应该 [关心],但总的来说,如果开发人员可以使用 页面分配器而不是 malloc 用于它们的传入图像,即 会很好。”
关于对齐约束/断言的原因:
“通常将不属于你的内存映射到另一个地址空间是 有点恶心,即使它在实践中有效。这也是我们为什么 要求映射是页面对齐的,因为硬件确实是 映射(并获得写入权限)到整个页面。”
【讨论】:
帮助很大。谢谢!以上是关于将未对齐的缓冲区提供给 MTLBuffer 是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章