Для 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 вы можете использовать texture<>
в C++ AMP для достижения того же результата, что и изображения OpenCL. Также есть пример этого на CodePlex.
Но при использовании OpenCL 'texture <>' как бы я разбил фрагменты/блоки так, чтобы они также кэшировали части изображения? Что касается вашего примера, я не совсем понимаю, как работают сдвиги и смещения. –
Здесь есть еще один пример, если это поможет http://blogs.msdn.com/b/nativeconcurrency/archive/2011/11/01/convolution-sample.aspx –