newComputePipelineStateWithFunction не удалось

Я пытаюсь позволить нейронной сети работать на металле.
Основная идея заключается в дублировании данных. Каждый поток GPU запускает одну версию сети для случайных точек данных.

Я написал другие шейдеры, которые отлично работают.

Я также попробовал свой код в приложении командной строки c ++. Там нет ошибок.
Также нет ошибки компиляции.

Я использовал документацию apple, чтобы конвертировать в металл с ++, так как не все из с ++ 11 поддерживается.

Вылетает после загрузки функции ядра и при попытке назначить newComputePipelineStateWithFunction к металлическому устройству. Это означает, что есть проблема с кодом, который не перехватывается во время компиляции.

MCVE:

kernel void net(const device float *inputsVector [[ buffer(0) ]], // layout of net *
uint id [[ thread_position_in_grid ]]) {

uint floatSize = sizeof(tempFloat);
uint inputsVectorSize = sizeof(inputsVector) / floatSize;

float newArray[inputsVectorSize];float test = inputsVector[id];

newArray[id] = test;

}

Обновить

Это связано с динамическими массивами.

Поскольку он не может создать состояние конвейера и не приводит к сбою при запуске реального шейдера, это должно быть проблемой кодирования. Не проблема ввода.

Назначение значений из динамического массива в буфер приводит к сбою.

11

Решение

Настоящая проблема:
Это проблема памяти!

Чтобы все люди говорили, что это проблема памяти, вы были правы!
Вот некоторый псевдокод, чтобы проиллюстрировать это. Извините, что это в «Свифте», но легче читать. Металлические шейдеры имеют причудливый способ ожить. Сначала они инициализируются без значений, чтобы получить память. Этот шаг не удался, потому что он опирался на более поздний шаг: настройку буфера.

Все сводится к тому, какие значения доступны, когда. Мое понимание newComputePipelineStateWithFunction был неправ. Это не просто получение функции шейдера. Это также маленький шаг в процессе инициализации.

class MetalShader {

// buffers
var aBuffer : [Float]
var aBufferCount : Int

// step One : newComputePipelineStateWithFunction
memory init() {
// assign shader memory

// create memory for one int
let aStaticValue : Int
// create memory for one int
var aNotSoStaticValue : Int // this wil succeed, assigns memory for one int

// create memory for 10 floats
var aStaticArray : [Float] = [Float](count: aStaticValue, repeatedValue: y) // this will succeed

// create memory for x floats
var aDynamicArray : [Float] = [Float](count: aBuffer.count, repeatedValue: y) // this will fail
var aDynamicArray : [Float] = [Float](count: aBufferCount, repeatedValue: y) // this will fail

let tempValue : Float // one float from a loop

}

// step Two : commandEncoder.setBuffer()
assign buffers (buffers) {

aBuffer = cpuMemoryBuffer

}

// step Three : commandEncoder.endEncoding()
actual init() {
// set shader values

let aStaticValue : Int = 0

var aNotSoStaticValue : Int = aBuffer.count

var aDynamicArray : [Float] = [Float](count: aBuffer.count, repeatedValue: 1) // this could work, but the app already crashed before getting to this point.

}

// step Four : commandBuffer.commit()
func shaderFunction() {
// do stuff
for i in 0..<aBuffer.count {

let tempValue = aBuffer[i]

}
}
}

Fix:

Я наконец понял, что буферы — это технически динамические массивы, и вместо создания массивов внутри шейдера я мог бы просто добавить больше буферов. Это очевидно работает.

4

Другие решения

Я думаю, что ваша проблема с этой строкой:

uint schemeVectorSize = sizeof(schemeVector) / uintSize;

Вот schemeVector является динамический так как в классическом C ++ вы не можете использовать sizeof на динамическом массиве, чтобы получить количество элементов. sizeof будет работать только с массивами, которые вы определили бы локально / статически в коде шейдера металла.

Только представьте, как это работает внутри: во время компиляции компилятор Metal должен преобразовывать sizeof позвонить в константу … но он не может, так как schemeVector является параметром вашего шейдера и поэтому может иметь любой размер …

Так что для меня решение было бы вычислить schemeVectorSize в части кода C ++ / ObjectiveC / Swift и передайте ее в качестве параметра шейдеру (как униформу в терминологии OpenGLES …).

-1

По вопросам рекламы [email protected]