iOS Metal – 在写入纹理时读取旧值

iOS Metal – reading old values while writing into texture

我有一个内核函数(计算着色器),它从纹理中读取像素的附近像素,并根据旧的附近像素值更新当前像素的值(这不是一个简单的卷积).

我已经尝试使用 BlitCommandEncoder 创建纹理的副本并为内核函数提供 2 个纹理 - 一个只读和另一个只写。不幸的是,这种方法在 GPU 方面非常耗时。

在更新纹理内容的同时从纹理读取旧值的最有效(GPU 和内存)方式是什么?

(有点晚但是哦好吧)

你不可能让它只使用一个纹理,因为 GPU 是一个高度并行的处理器:你为单个像素编写的内核会在所有像素上并行调用,你无法分辨哪个先走

所以你肯定需要2个纹理。您可能应该这样做的方法是使用 2 个纹理,其中一个是 "old" 一个,另一个是 "new" 一个。在通道之间,您可以切换纹理的角色,现在旧的是新的,新的是旧的。这是一些 pseudoswift:

var currentText = MTLTexture()
var nextText = MTLTexture()

let semaphore = dispatch_semaphore_create(1)

func update() {
    dispatch_semaphore_wait(semaphore) // Wait for updating done signal

    let commands = commandQueue.commandBuffer()
    let encoder = commands.computeCommandEncoder()

    encoder.setTexture(currentText, atIndex: 0)
    encoder.setTexture(nextText, atIndex: 1)

    encoder.dispatchThreadgroups(...)
    encoder.endEncoding()

    // When updating done, swap the textures and signal that it's done updating
    commands.addCompletionHandler { 
        swap(&currentText, &nextText)
        dispatch_semaphore_signal(semaphore)
    }
    commands.commit()
}

我写了很多 iOS 金属代码,这些代码从渲染到的相同纹理中采样(或读取)。我正在使用渲染管道,将我的纹理设置为渲染目标附件,并将其加载为源纹理。它工作得很好。

需要说明的是,更有效的方法是在片段着色器中使用 color() 属性,但这仅适用于您只需要 current 片段,而不是附近的任何其他位置。如果您需要从渲染目标中的其他位置读取,我只会将渲染目标作为源纹理加载到片段着色器中。