我尝试了不同的方法,最终得到了一个版本,它不那么“如果”,并且尽可能多地使用线程(在第二阶段,可能没有完全有效,因为很少有线程空闲,但这是我能得到的最好的版本)。
其原理是在左上角设置原点(起始位置),并使用循环索引从此位置创建读/写索引。循环从2D中的局部id位置开始。因此,所有256个工作项都写入其第一个元素,在第二阶段,256个工作项中只有68个工作项将完成底部的2行+右侧的2列。
我还不是OpenCL专业版,所以这可能还有更多改进(可能是循环展开,我不知道)。
__local float wrkSrc[324];
const int lpitch = 18;
// Add halfROI to handle the corner
const int lcol = get_local_id(0);
const int lrow = get_local_id(1);
const int2 gid = { col, row };
const int2 lid = { lcol, lrow };
// Always get the most Top-left corner of that ROI to extract.
const int2 startPos = gid - lid - halfROI;
// Loop on each thread to get their right ID.
// Thread with id < 2 * halfROI will process more then others, but not that much an issue.
for ( int x = lid.x; x < lpitch; x += 16 ) {
for ( int y = lid.y; y < lpitch; y += 16 ) {
// Get the position to write into the local array.
const int lidx = x + y * lpitch;
// Get the position to read into the global memory (src)
const int2 readPos = startPos + (int2)( x, y );
// Is inside ?
if ( readPos.x >= 0 && readPos.x < width && readPos.y >= 0 && readPos.y < height )
wrkSrc[lidx] = src[readPos.x + readPos.y * lab_new_pitch];
else
wrkSrc[lidx] = 0.0f;
}
}