Как правильно использовать результаты одного вычислительного шейдера в следующем вычислительном шейдере?

Предположим, я отправляю два вычислительных шейдера A и B в металле. Я не хочу, чтобы Б бежал до тех пор, пока А не закончил. На данный момент я кодирую каждый шейдер в свой собственный командный буфер и фиксирую так:

commandBufferA.commit()
commandBufferA.waitUntilCompleted()
commandBufferB.commit()

Это правильная техника?

1 ответ

Решение

Призвание waitUntilCompleted() Командный буфер полезен, если вам нужно использовать результаты ядра обратно на ЦП, но не нужен и неэффективен, если вы хотите просто использовать результат команды compute (dispatch) в последующей команде compute. Если между командами вычислений существует зависимость данных, результаты, записанные первой, гарантированно будут видны последним даже в пределах одного буфера команд. Итак, вы можете структурировать это примерно так:

let commandBuffer = commandQueue.makeCommandBuffer()
let commandEncoder = commandBuffer.makeComputeCommandEncoder()

commandEncoder.setComputePipelineState(pipelineStateA)
commandEncoder.setTexture(inputTexture, at: 0)
commandEncoder.setTexture(intermediateTexture, at: 1)
commandEncoder.dispatchThreadgroups(threadgroupCount, 
                                    threadsPerThreadgroup: threadgroupSize)

commandEncoder.setComputePipelineState(pipelineStateB)
commandEncoder.setTexture(intermediateTexture, at: 0)
commandEncoder.setTexture(outputTexture, at: 1)
commandEncoder.dispatchThreadgroups(threadgroupCount, 
                                    threadsPerThreadgroup: threadgroupSize)

commandEncoder.endEncoding()
commandBuffer.commit()

commandBuffer.waitUntilCompleted() // optional; only if you need to read the result on the CPU
Другие вопросы по тегам