【问题标题】:iOS Metal – reading old values while writing into textureiOS Metal – 在写入纹理时读取旧值
【发布时间】:2016-10-30 22:58:53
【问题描述】:

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

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

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

【问题讨论】:

  • 您是否使用 Time Profiler(在仪器中)和 GPU 帧捕获(在 Xcode 中)分析了您的应用程序?确定您在分配资源、复制和运行内核上花费了多少时间将帮助您确定首先要优化什么。
  • @warrenm 感谢您的回复。事实证明,使用BlitCommandEncoder 的例程正在调用另一个耗时的函数,这导致了延迟,Blit 操作不是延迟的主要来源——这是我的错。但是,在查看 GPU 帧捕获时,我发现没有提到 Blit 操作的持续时间(与 Compute 操作相反)——有没有办法测量这些(或者我错过了什么)?
  • 我不认为目前有一种方法可以在 GPU 帧捕获中捕获计算编码器持续时间,抱歉。

标签: ios shader texture2d metal


【解决方案1】:

(有点晚了,但还好)

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

所以你肯定需要 2 个纹理。您可能应该这样做的方式是使用 2 个纹理,其中一个是“旧”纹理,另一个是“新”纹理。在传递之间,您切换纹理的角色,现在旧的是新的,新的是旧的。这是一些伪swift:

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()
}

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 这可能有点太晚了,但我正在努力做到这一点。你介意分享代码吗? :)
    猜你喜欢
    • 2016-07-08
    • 2018-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多