我正在制作一个OpenFX插件来处理分级/后期制作软件中的图像。
我所有的处理都是在一系列的Metal内核函数中完成的。图像作为缓冲区(浮点数组)发送到GPU,一个用于输入,一个用于输出。
输出然后由OpenFX框架用于在主机应用程序中显示,所以直到那时我还没有注意到它。
一旦GPU处理了命令,我现在需要能够读取输出值。我试过使用"内容"方法应用于缓冲区,但我的插件总是崩溃(在最坏的情况下),或者当它"工作"时给我非常奇怪的值。(我不应该有大于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();
}
如果命令缓冲区包含对给定MTLBuffer
的写或读操作,则必须确保这些操作在读取缓冲区内容之前完成。您可以使用addCompletedHandler:
方法,waitUntilCompleted
方法或自定义信号量来表示命令缓冲区已完成执行。
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
/* read or write buffer here */
}];
[commandBuffer commit];