Как правильно использовать результаты одного вычислительного шейдера в следующем вычислительном шейдере?
Предположим, я отправляю два вычислительных шейдера 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