2015-10-18 4 views
0

Я делаю моделирование твердого тела для iPhone/iPad с использованием Apple Metal. Для этого мне нужно сделать много вызовов функций ядра, и я вижу, что это занимает много времени, например, против CUDA. Я осуществил вызов функции ядра металла, как это описано в руководстве компании AppleВыполнение функции множественного вызова функции металла

let commandQueue = device.newCommandQueue() 

var commandBuffers:[MTLCommandBuffer]=[] 
var gpuPrograms:[MTLFunction]=[] 
var computePipelineFilters:[MTLComputePipelineState]=[] 
var computeCommandEncoders:[MTLComputeCommandEncoder]=[] 

//here i fill all arrays for my command queue 
//and next i execute it 

let threadsPerGroup = MTLSize(width:1,height:1,depth:1) 
let numThreadgroups = MTLSize(width:threadsAmount, height:1, depth:1) 

for computeCommandEncoder in computeCommandEncoders 
{ 
    computeCommandEncoder.dispatchThreadgroups(numThreadgroups, threadsPerThreadgroup: threadsPerGroup) 
} 

for computeCommandEncoder in computeCommandEncoders 
{ 
    computeCommandEncoder.endEncoding() 
} 

for commandBuffer in commandBuffers 
{ 
    commandBuffer.enqueue() 
} 

for commandBuffer in commandBuffers 
{ 
    commandBuffer.commit() 
} 

for commandBuffer in commandBuffers 
{ 
    commandBuffer.waitUntilCompleted() 
} 

Я сделать до нескольких функций ядра десятки металлических каждый кадр, и он работает слишком медленно. Я тестировал его с пустыми функциями ядра, и это показывает мне, что проблема в части выполнения Swift. Я имею в виду, когда я хочу выполнить функцию ядра в CUDA, я просто называю ее обычной функцией, и она работает очень быстро. Но здесь я должен сделать много действий для каждого выполнения каждой функции в каждом кадре. Может быть, я не знаю, что-то, но я хочу создать все дополнительные объекты один раз, а потом просто сделать что-то вроде

commandQueue.execute() 

выполнять все функции ядра.

Am i права в моих действиях для выполнения многих функций ядра, или есть какой-то другой способ сделать это быстрее?

ответ

5

У меня есть несколько проектов, которые используют несколько шейдеров за один шаг. Я создаю только один буфер и кодировщик, но несколько состояний конвейера; один для каждой вычислительной функции.

Помните, что MTLCommandQueue является постоянным, поэтому нужно только создать один раз, так что мой MetalKit View в drawRect() функция примерно так (там больше шейдеров и текстур, передаваемых между ними, но вы получите представление о структуре):

let commandBuffer = commandQueue.commandBuffer() 
let commandEncoder = commandBuffer.computeCommandEncoder() 

commandEncoder.setComputePipelineState(advect_pipelineState) 
commandEncoder.dispatchThreadgroups(threadgroupsPerGrid, 
    threadsPerThreadgroup: threadsPerThreadgroup) 

commandEncoder.setComputePipelineState(divergence_pipelineState) 
commandEncoder.dispatchThreadgroups(threadgroupsPerGrid, 
    threadsPerThreadgroup: threadsPerThreadgroup) 

[...] 

commandEncoder.endEncoding() 
commandBuffer.commit() 

Мой код фактически перебирает один из шейдеров в двадцать раз и все еще работает довольно nippily, так что если вы реорганизовать и следовать этой структуры с одним буфером и один кодер и вызывать только endEncoding() и commit() один раз за один проход, вы может увидеть улучшение производительности.

май являющийся оперативным словом:

Смежные вопросы