我有一个内核函数(计算着色器),它从纹理中读取像素的附近像素,并根据旧的附近像素值更新当前像素的值(它不是简单的卷积)。
我尝试使用BlitCommandEncoder
创建纹理的副本,并为内核函数提供2个纹理 - 一个只读,另一个只写。不幸的是,这种方法耗费了GPU时间。
在更新内容时,从纹理中读取旧值的最有效(GPU和内存方式)是什么?
答案 0 :(得分:3)
(迟到但很好)
你无法让它只用一个纹理,因为GPU是一个高度并行的处理器:你为一个像素写的内核在所有像素上并行调用,你无法分辨出哪一个先走了。
所以你肯定需要2个纹理。您可能应该这样做的方法是使用2个纹理,其中一个是“旧”纹理,另一个是“新”纹理。在传递之间,你切换纹理的角色,现在旧的是新的,新的是旧的。这是一些伪转换:
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(¤tText, &nextText)
dispatch_semaphore_signal(semaphore)
}
commands.commit()
}
答案 1 :(得分:0)
我已经编写了大量的iOS Metal代码,可以从它渲染的相同纹理中采样(或读取)。我正在使用渲染管道,将我的纹理设置为渲染目标附件,并将其加载为源纹理。它运作得很好。
要明确一点,更有效的方法是在片段着色器中使用color()
属性,但这只适用于您需要的只是当前片段的值,没有任何其他附近的位置。如果你需要从渲染目标中的其他位置读取,我只需将渲染目标作为源纹理加载到片段着色器中。