sarasvati sarasvati - 4 months ago 23
iOS Question

iOS Metal – reading old values while writing into texture

I have a kernel function (compute shader) that reads nearby pixels of a pixel from a texture and based on the old nearby-pixel values updates the value of the current pixel (it's not a simple convolution).

I've tried creating a copy of the texture using

BlitCommandEncoder
and feeding the kernel function with 2 textures - one read-only and another write-only. Unfortunately, this approach is GPU-wise time consuming.

What is the most efficient (GPU- and memory-wise) way of reading old values from a texture while updating its content?

Answer

(Bit late but oh well)

There is no way you could make it work with only one texture, because the GPU is a highly parallel processor: Your kernel that you wrote for a single pixel gets called in parallel on all pixels, you can't tell which one goes first.

So you definitely need 2 textures. The way you probably should do it is by using 2 textures where one is the "old" one and the other the "new" one. Between passes, you switch the role of the textures, now old is new and new is old. Here is some 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()
}
Comments