對於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 –