ios - 将未对齐的缓冲区提供给 MTLBuffer 是否安全?

标签 ios memory-management shared-memory metal

当尝试使用 Metal 从内存中快速将像素缓冲区绘制到屏幕时,我们使用 MTLDevice.makeBuffer(bytesNoCopy:..) 创建 MTLBuffer 对象以允许GPU 直接从内存中读取像素而无需复制它。共享内存确实是实现良好像素传输性能的必备条件。

要注意的是,makeBuffer 需要页面对齐的内存地址和页面对齐的长度。这些要求不仅在文档中——它们还使用运行时断言强制执行。

我正在编写的代码必须处理各种传入的分辨率和像素格式,有时我会遇到未对齐的缓冲区或未对齐的长度。对此进行研究后,我发现了一个可以让我为这些实例使用共享内存的 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 不直接为我们做这件事?

最佳答案

我已经针对这个问题提交了Apple TSI(技术支持事件),答案基本上是是的,它是安全的。如果有人感兴趣,这里是确切的回复:

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.”

关于ios - 将未对齐的缓冲区提供给 MTLBuffer 是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39951878/

相关文章:

javascript - 如何在 javascript 中共享来自主线程和网络 worker 的变量?

c++ - 平台无关的内存映射 [文件] IO

iphone - Facebook iOS 似乎在单击“确定”后返回应用程序时丢失了 session 您已经授权了应用程序

ios - NSAssert 的处理方式是否应该作为错误提出

android - 如何将文本放入带有 flutter 的滑动器中?

Python Multiprocessing 共享全局值

ios - 如何安全地解包我的核心数据对象

c - 通过 strdup() 和 malloc() 构造字符串之间有什么实际区别吗?

vector - Rust如何为向量分配更多空间?

c++ - 重新分配结构体的 std::vector