Compute Kernel Metal - Как получить результаты и отладить? - PullRequest
1 голос
/ 04 октября 2019

Я скачал пример truedepth streamer от Apple и пытаюсь добавить конвейер вычислений. Я думаю, что я получаю результаты вычислений, но я не уверен, так как все они кажутся равными нулю.

Я новичок в разработке iOS, поэтому, возможно, довольно много ошибок, так что, пожалуйста, потерпите меня!

Конвейер настроен: (я не совсем уверен, как создать буфер результатов, так как ядро ​​выдает float3)

int resultsCount = CVPixelBufferGetWidth(depthFrame) * CVPixelBufferGetHeight(depthFrame);

//because I will be output 3 floats for each value in depthframe
id<MTLBuffer> resultsBuffer = [self.device newBufferWithLength:(sizeof(float) * 3 * resultsCount) options:MTLResourceOptionCPUCacheModeDefault];


_threadgroupSize = MTLSizeMake(16, 16, 1);

// Calculate the number of rows and columns of threadgroups given the width of the input image
// Ensure that you cover the entire image (or more) so you process every pixel
_threadgroupCount.width  = (inTexture.width  + _threadgroupSize.width -  1) / _threadgroupSize.width;
_threadgroupCount.height = (inTexture.height + _threadgroupSize.height - 1) / _threadgroupSize.height;

// Since we're only dealing with a 2D data set, set depth to 1
_threadgroupCount.depth = 1;

id<MTLComputeCommandEncoder> computeEncoder = [commandBuffer computeCommandEncoder];

[computeEncoder setComputePipelineState:_computePipelineState];

[computeEncoder setTexture: inTexture atIndex:0];

[computeEncoder setBuffer:resultsBuffer offset:0 atIndex:1];

[computeEncoder setBytes:&intrinsics length:sizeof(intrinsics) atIndex:0];

[computeEncoder dispatchThreadgroups:_threadgroupCount
                       threadsPerThreadgroup:_threadgroupSize];

[computeEncoder endEncoding];


// Finalize rendering here & push the command buffer to the GPU
[commandBuffer commit];

//for testing
[commandBuffer waitUntilCompleted];

Я добавил следующее вычислительное ядро:

kernel void
calc(texture2d<float, access::read>  inTexture  [[texture(0)]],
                device float3 *resultsBuffer [[buffer(1)]],
                constant float3x3& cameraIntrinsics [[ buffer(0) ]],
                uint2 gid [[thread_position_in_grid]])
{

    float val = inTexture.read(gid).x * 1000.0f;

    float xrw = (gid.x - cameraIntrinsics[2][0]) * val / cameraIntrinsics[0][0];
    float yrw = (gid.y - cameraIntrinsics[2][1]) * val / cameraIntrinsics[1][1];

    int vertex_id = ((gid.y * inTexture.get_width()) + gid.x);

    resultsBuffer[vertex_id] = float3(xrw, yrw, val);

}

Код для просмотра результата буфера: (Я пробовал два разных способа, и оба выводят все нули в данный момент)

    void *output = [resultsBuffer contents];
    for (int i = 0; i < 10; ++i) {
        NSLog(@"value is %f", *(float *)(output) ); //= *(float *)(output + 4 * i);
    }

    NSData *data = [NSData dataWithBytesNoCopy:resultsBuffer.contents length:(sizeof(float) * 3 * resultsCount)freeWhenDone:NO];
    float *finalArray = new float [resultsCount * 3];
    [data getBytes:&finalArray[0] length:sizeof(finalArray)];
    for (int i = 0; i < 10; ++i) {
        NSLog(@"here is output %f", finalArray[i]);
    }

1 Ответ

2 голосов
/ 05 октября 2019

Я вижу здесь пару проблем, но ни одна из них не связана с вашим кодом Metal как таковым.

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

NSLog(@"value is %f", ((float *)output)[i]);

, я увидел разные значения, напечатанные при запуске вашего ядра на тестовом образе.

Другая проблема связана с вашим вызовом getBytes:length:. Вы хотите передать количество байтов для копирования, но sizeof(finalArray) на самом деле размер указателя finalArray , то есть 4 байта, а не общий размер буфераэто указывает на. Это чрезвычайно распространенная ошибка в коде C и C ++.

Вместо этого вы можете использовать тот же счетчик байтов, что и тот, который вы использовали при распределении пространства:

[data getBytes:&finalArray[0] length:(sizeof(float) * 3 * resultsCount)];

Затем вы должны найти этовы получите те же (ненулевые) значения, что и на предыдущем шаге.

...