对于 C++ AMP,您希望在开始卷积计算之前将磁贴中的每个线程使用的数据加载到 tile_static 内存中。因为每个线程访问的像素也被其他线程读取,这允许您从(慢)全局内存中对每个像素进行一次读取,并将其缓存在(快速)平铺静态内存中,以便所有后续读取更快。
您可以看到example of tiling for convolution here。 DetectEdgeTiled 方法加载它需要的所有数据并调用idx.barrier.wait() 以确保所有线程已完成将数据写入平铺静态内存。然后它利用tile_static 内存执行边缘检测代码。示例中还有许多其他这种模式的示例。请注意,DetectEdgeTiled 中的加载代码之所以复杂,只是因为它必须考虑正在写入当前图块的像素边缘周围的额外像素,并且本质上是一个展开的循环,因此它是长度。
我不确定您是否以正确的方式思考问题。这里有两个级别的分区。为了计算每个像素的新值,执行此工作的线程读取周围像素块。此外,线程块(瓦片)将较大的像素数据块加载到tile_static 内存中。然后,图块上的每个线程计算块内一个像素的结果。
void ApplyEdgeDetectionTiledHelper(const array<ArgbPackedPixel, 2>& srcFrame,
array<ArgbPackedPixel, 2>& destFrame)
{
tiled_extent<tileSize, tileSize> computeDomain = GetTiledExtent(srcFrame.extent);
parallel_for_each(computeDomain.tile<tileSize, tileSize>(), [=, &srcFrame, &destFrame, &orgFrame](tiled_index<tileSize, tileSize> idx) restrict(amp)
{
DetectEdgeTiled(idx, srcFrame, destFrame, orgFrame);
});
}
void DetectEdgeTiled(
tiled_index<tileSize, tileSize> idx,
const array<ArgbPackedPixel, 2>& srcFrame,
array<ArgbPackedPixel, 2>& destFrame) restrict(amp)
{
const UINT shift = imageBorderWidth / 2;
const UINT startHeight = 0;
const UINT startWidth = 0;
const UINT endHeight = srcFrame.extent[0];
const UINT endWidth = srcFrame.extent[1];
tile_static RgbPixel localSrc[tileSize + imageBorderWidth ]
[tileSize + imageBorderWidth];
const UINT global_idxY = idx.global[0];
const UINT global_idxX = idx.global[1];
const UINT local_idxY = idx.local[0];
const UINT local_idxX = idx.local[1];
const UINT local_idx_tsY = local_idxY + shift;
const UINT local_idx_tsX = local_idxX + shift;
// Copy image data to tile_static memory. The if clauses are required to deal with threads that own a
// pixel close to the edge of the tile and need to copy additional halo data.
// This pixel
index<2> gNew = index<2>(global_idxY, global_idxX);
localSrc[local_idx_tsY][local_idx_tsX] = UnpackPixel(srcFrame[gNew]);
// Left edge
if (local_idxX < shift)
{
index<2> gNew = index<2>(global_idxY, global_idxX - shift);
localSrc[local_idx_tsY][local_idx_tsX-shift] = UnpackPixel(srcFrame[gNew]);
}
// Right edge
// Top edge
// Bottom edge
// Top Left corner
// Bottom Left corner
// Bottom Right corner
// Top Right corner
// Synchronize all threads so that none of them start calculation before
// all data is copied onto the current tile.
idx.barrier.wait();
// Make sure that the thread is not referring to a border pixel
// for which the filter cannot be applied.
if ((global_idxY >= startHeight + 1 && global_idxY <= endHeight - 1) &&
(global_idxX >= startWidth + 1 && global_idxX <= endWidth - 1))
{
RgbPixel result = Convolution(localSrc, index<2>(local_idx_tsY, local_idx_tsX));
destFrame[index<2>(global_idxY, global_idxX)] = result;
}
}
这段代码取自 CodePlex,我去掉了很多真实的实现以使其更清晰。
WRT @sharpneli 的回答,您可以在 C++ AMP 中使用 texture<> 来实现与 OpenCL 图像相同的结果。 CodePlex 上也有一个例子。