Как я могу получить доступ к содержимому MTLBuffer после рендеринга GPU?

Я работаю над плагином OpenFX для обработки изображений в программном обеспечении для оценки / постпроизводства.

Вся моя обработка выполняется в серии функций ядра Metal. Изображение отправляется в графический процессор в виде буферов (массив с плавающей запятой), один для ввода и один для вывода.

Затем результат используется платформой OpenFX для отображения внутри хост-приложения, поэтому до тех пор мне не приходилось об этом заботиться.

Теперь мне нужно иметь возможность читать выходные значения после того, как графический процессор обработал команды. Я попытался использовать метод «содержимого», примененный к буферу, но мой плагин продолжает давать сбой (в худшем случае) или дает мне очень странные значения, когда он «работает» (я не должен иметь ничего больше 1 и ниже 0, но я получаю очень большие числа, 0 или отрицательный 0, nan... Так что я предполагаю, что у меня есть своего рода проблема с доступом к памяти).

Сначала я подумал, что это проблема с частной / общей памятью, поэтому я попытался изменить буфер, который будет использоваться совместно. Но я все еще борюсь!

Полное раскрытие информации: у меня нет специального обучения MSL, я учусь в процессе работы над этим проектом, поэтому я могу делать и / или говорить очень глупые вещи. Я часами осматривался, прежде чем решил попросить о помощи. Спасибо всем, кто чем-нибудь поможет!

Ниже приведен код (без всего, что не касается моей текущей проблемы). Если в нем не хватает чего-либо интересного, пожалуйста, дайте мне знать.

      id < MTLBuffer > srcDeviceBuf = reinterpret_cast<id<MTLBuffer> >(const_cast<float*>(p_Input)) ;

//Below is the destination Image buffer creation the way it used to be done before my edits
//id < MTLBuffer > dstDeviceBuf = reinterpret_cast<id<MTLBuffer> >(p_Output);

//My attempt at creating a Shared memory buffer
MTLResourceOptions bufferOptions = MTLResourceStorageModeShared;
int bufferLength = sizeof(float)*1920*1080*4;
id <MTLBuffer> dstDeviceBuf = [device newBufferWithBytes:p_Output length:bufferLength options:bufferOptions];

id<MTLCommandBuffer> commandBuffer = [queue commandBuffer];
commandBuffer.label = [NSString stringWithFormat:@"RunMetalKernel"];

id<MTLComputeCommandEncoder> computeEncoder = [commandBuffer computeCommandEncoder];
//First method to be computed
[computeEncoder setComputePipelineState:_initModule];
int exeWidth = [_initModule threadExecutionWidth];

MTLSize threadGroupCount = MTLSizeMake(exeWidth, 1, 1);
MTLSize threadGroups = MTLSizeMake((p_Width + exeWidth - 1) / exeWidth,
        p_Height, 1);

[computeEncoder setBuffer:srcDeviceBuf offset: 0 atIndex: 0];
[computeEncoder setBuffer:dstDeviceBuf offset: 0 atIndex: 8];

//encodes first module to be executed
[computeEncoder dispatchThreadgroups:threadGroups threadsPerThreadgroup: threadGroupCount];

//Modules encoding
if (p_lutexport_on) {
    //Fills the image with patch values for the LUT computation
    [computeEncoder setComputePipelineState:_LUTExportModule];
    [computeEncoder dispatchThreadgroups:threadGroups threadsPerThreadgroup: threadGroupCount];
}

[computeEncoder endEncoding];
[commandBuffer commit];


if (p_lutexport_on) {
    
    //Here is where I try to read the buffer values (and inserts them into a custom object "p_lut_exp_lut"

    float* result = static_cast<float*>([dstDeviceBuf contents]);

    //Retrieve the output values and populate the LUT with them
    int lutLine = 0;
    float3 out;
    for (int index(0); index < 35937 * 4; index += 4) {
        out.x = result[index];
        out.y = result[index + 1];
        out.z = result[index + 2];

        p_lutexp_lut->setValuesAtLine(lutLine, out);
        lutLine++;
    }

    p_lutexp_lut->toFile();
}

1 ответ

Если буфер команд включает операции записи или чтения на заданном MTLBuffer, вы должны убедиться, что эти операции завершены, прежде чем читать содержимое буферов. Вы можете использовать addCompletedHandler: метод waitUntilCompleted метод или пользовательские семафоры, чтобы сигнализировать, что буфер команд завершил выполнение.

      [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
    /* read or write buffer here */
}];
[commandBuffer commit];
Другие вопросы по тегам