Я работаю над реализацией игры с кудой. Я хочу найти индекс массива для каждого элемента, чтобы я мог рассчитать соседей для этого элемента и чтобы я мог написать новое значение этому массиву. Все, что я нашел об этом, работает с указателями на строки, и я просто не могу понять, как это точно переводится в индексы. Чтобы лучше понять, что я имею в виду, я должен следовать коду (некоторые фрагменты):
#define THREADSPERBLOCK 1024
lifeState *d_gameStateInitial;
size_t d_gameStateInitial_pitch;
int sizeX = 100;
int sizeY = 100;
int numBlocks = ((sizeX * sizeY) % THREADSPERBLOCK) + 1;
int numThreadsPerBlock;
if(numBlocks == 1)
{
numThreadsPerBlock = sizeX * sizeY;
}
else
{
numThreadsPerBlock = THREADSPERBLOCK;
}
cudaMallocPitch((void **)&d_gameStateInitial, &d_gameStateInitial_pitch, sizeX * sizeof(lifeState), sizeY);
doTheGame<<<numBlocks, numThreadsPerBlock>>>(d_gameStateInitial, d_gameStateInitial_pitch, d_gameStateNew, d_gameStateNew_pitch, sizeX, sizeY);
"Lifestate *" - это просто структура, содержащая переиздание "мертвое/живое". Оба массива, исходные и новые, являются malloc'd точно так же. В ядре doTheGame я теперь хочу знать, как вычислить индекс, я думал о чем-то подобном, но я думаю, что это неправильно:
__global__ void doTheGame(lifeState *initialArray, size_t initialArrayPitch,
lifeState *newArray, size_t newArrayPitch,
int sizeX, int sizeY)
{
int initialArrayThreadIndex = (blockIdx.x * initialArrayPitch) + threadIdx.x;
int newArrayThreadIndex = (blockIdx.x * initialArrayPitch) + threadIdx.x;
}
Все, что я нашел до сих пор, в основном все равно, как пример cudaMallocPitch:
T* pElement = (T*)((char*)BaseAddress + Row * pitch) + Column;
Но я просто не могу понять, как это точно переводится в блоки, потоки и х и у.
Заранее спасибо.
Предположим, у меня есть массив double data[]
:
A B C D x x x x
E F G H x x x x
Тогда data[0] = A
, data[1] = B
и т.д.
Это может быть результатом выделения массива 2x4 с распределением основного тона в 64 байта (таким образом, 4 дополнительных x
элемента в каждой строке). Пусть предположим, что каждый элемент в указанном массиве является double
величиной.
Теперь предположим, что у меня есть ядро, и я запускаю массив из 2x4 потоков, по одному на допустимый элемент (элементы x
недействительны - они являются дополнительными выделениями для удовлетворения требования шага, которое произвольно выбирается для этого примера как 64 байт).
В этом ядре я мог бы создать индекс x и y следующим образом:
int idx = threadIdx.x +blockDim.x * blockIdx.x;
int idy = threadIdx.y +blockDim.y * blockIdx.y;
Каждый поток может затем получить доступ к соответствующему элементу следующим образом.
Так как pitch
количество, возвращаемое cudaMallocPitch
в байтах, нам необходимо вычислить ряд смещения во- первых, с помощью char
арифметики указателей:
double *rowptr = (double *)((char *)data + idy*pitch);
Затем мы можем получить доступ к элементу в этой строке следующим образом:
rowptr[idx] = 0.0;
Если я хочу, чтобы поток обращался к элементу, отличному от того, который соответствует его индексам потока, вычисления аналогичны.
Например, чтобы установить элемент G
(т.е. элемент (1,2)) в нуль в указанном массиве data
, я мог бы сделать:
double *rowptr = (double *)((char *)data + 1*pitch);
rowptr[2] = 0.0;
rowptr
в массиве, что сработало бы, только если вы тщательно манипулировали количеством потоков и блоков. Кроме того, может показаться, что вы проходите сквозь слепые элементы. Можете ли вы опубликовать более полный пример?