Я работал над реализацией игры с использованием cuda. Я хочу найти индекс массива каждого элемента, чтобы я мог вычислить соседей для этого элемента и чтобы я мог записать новое значение в этот массив. Все, что я нашел по этому поводу, работает с указателями на строки, и я просто не могу понять, как это в точности соответствует индексам. Чтобы дать лучшее представление о том, что я имею в виду, я должен следующий код (некоторые фрагменты):
#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 *» — это просто структура, содержащая перечисление dead / alive. Оба массива, начальный и новый, имеют одинаковый malloc. В ядре 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;
Но я просто не могу понять, как это преобразуется в блоки, потоки и x и y точно.
Заранее спасибо.
Предположим, у меня есть double data[]
массив, как это:
A B C D x x x x
E F G H x x x x
затем data[0] = A
, data[1] = B
и т.п.
Это может быть результатом выделения массива 2×4 с шагом в 64 байта (таким образом, 4 дополнительных x
записи в каждом ряду). Давайте предположим, что каждый элемент в массиве выше double
количество.
Теперь предположим, что у меня есть ядро, и я запускаю массив потоков 2х4, по одному на каждый допустимый элемент ( 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;
Других решений пока нет …