对于C++ AMP,您希望在开始卷积计算之前将瓦片中每个线程使用的数据加载到tile_static
内存中。由于每个线程都访问其他线程也读取的像素,因此您可以对来自(慢速)全局内存的每个像素执行一次读取,并将其缓存到(快速)tile静态内存中,以便后续读取速度更快。你可以看到一个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上还有一个例子。
但是,当使用OpenCL纹理<>'我将如何分割瓷砖/块,以便它们也可以缓存部分图像?至于你的例子,它并没有完全清楚我的变化和偏移量是如何工作的。 –
还有另一个例子,如果这有助于http://blogs.msdn.com/b/nativeconcurrency/archive/2011/11/01/convolution-sample.aspx –