Хорошо, до сих пор, я могу создать массив на главном компьютере (плавания типа), и скопировать его в gpu, затем возвратить его хосту как другой массив (чтобы протестировать, если копия была успешна по сравнению с оригиналом).
Я затем создаю массив CUDA из массива на GPU. Затем я связываю тот массив со структурой CUDA.
Я теперь хочу считать ту структуру назад и соответствовать исходному массиву (снова для тестирования этого, это скопировало правильно). Я видел некоторый пример кода, который использует readTexel()
функция, показанная ниже. Это, кажется, не работает на меня... (в основном, все работает за исключением раздела в bindToTexture(float* deviceArray)
функция, запускающаяся в readTexels(SIZE, testArrayDevice)
строка).
Какие-либо предложения другого способа сделать это? Или есть ли некоторые очевидные проблемы, которые я пропустил в своем коде?
Спасибо за парней справки!
#include <stdio.h>
#include <assert.h>
#include <cuda.h>
#define SIZE 20;
//Create a channel description to use.
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
//Create a texture to use.
texture<float, 2, cudaReadModeElementType> cudaTexture;
//cudaTexture.filterMode = cudaFilterModeLinear;
//cudaTexture.normalized = false;
__global__ void readTexels(int amount, float *Array)
{
int index = blockIdx.x * blockDim.x + threadIdx.x;
if (index < amount)
{
float x = tex1D(cudaTexture, float(index));
Array[index] = x;
}
}
float* copyToGPU(float* hostArray, int size)
{
//Create pointers, one for the array to be on the device, and one for bringing it back to the host for testing.
float* deviceArray;
float* testArray;
//Allocate some memory for the two arrays so they don't get overwritten.
testArray = (float *)malloc(sizeof(float)*size);
//Allocate some memory for the array to be put onto the GPU device.
cudaMalloc((void **)&deviceArray, sizeof(float)*size);
//Actually copy the array from hostArray to deviceArray.
cudaMemcpy(deviceArray, hostArray, sizeof(float)*size, cudaMemcpyHostToDevice);
//Copy the deviceArray back to testArray in host memory for testing.
cudaMemcpy(testArray, deviceArray, sizeof(float)*size, cudaMemcpyDeviceToHost);
//Make sure contents of testArray match the original contents in hostArray.
for (int i = 0; i < size; i++)
{
if (hostArray[i] != testArray[i])
{
printf("Location [%d] does not match in hostArray and testArray.\n", i);
}
}
//Don't forget free these arrays after you're done!
free(testArray);
return deviceArray; //TODO: FREE THE DEVICE ARRAY VIA cudaFree(deviceArray);
}
cudaArray* bindToTexture(float* deviceArray)
{
//Create a CUDA array to translate deviceArray into.
cudaArray* cuArray;
//Allocate memory for the CUDA array.
cudaMallocArray(&cuArray, &cudaTexture.channelDesc, SIZE, 1);
//Copy the deviceArray into the CUDA array.
cudaMemcpyToArray(cuArray, 0, 0, deviceArray, sizeof(float)*SIZE, cudaMemcpyHostToDevice);
//Release the deviceArray
cudaFree(deviceArray);
//Bind the CUDA array to the texture.
cudaBindTextureToArray(cudaTexture, cuArray);
//Make a test array on the device and on the host to verify that the texture has been saved correctly.
float* testArrayDevice;
float* testArrayHost;
//Allocate memory for the two test arrays.
cudaMalloc((void **)&testArray, sizeof(float)*SIZE);
testArrayHost = (float *)malloc(sizeof(float)*SIZE);
//Read the texels of the texture to the test array in the device.
readTexels(SIZE, testArrayDevice);
//Copy the device test array to the host test array.
cudaMemcpy(testArrayHost, testArrayDevice, sizeof(float)*SIZE, cudaMemcpyDeviceToHost);
//Print contents of the array out.
for (int i = 0; i < SIZE; i++)
{
printf("%f\n", testArrayHost[i]);
}
//Free the memory for the test arrays.
free(testArrayHost);
cudaFree(testArrayDevice);
return cuArray; //TODO: UNBIND THE CUDA TEXTURE VIA cudaUnbindTexture(cudaTexture);
//TODO: FREE THE CUDA ARRAY VIA cudaFree(cuArray);
}
int main(void)
{
float* hostArray;
hostArray = (float *)malloc(sizeof(float)*SIZE);
for (int i = 0; i < SIZE; i++)
{
hostArray[i] = 10.f + i;
}
float* deviceAddy = copyToGPU(hostArray, SIZE);
free(hostArray);
return 0;
}
Кратко:
------------- в вашем main.cu --------- -------------------------------------------------- ----------------------------
-1. Определите текстуру как глобальную переменную
texture refTexture; // global variable !
// meaning: address the texture with (x,y) (2D) and get an unsinged int
В основной функции:
-2. Использовать массивы в сочетании с текстурой
cudaArray * myArray; // declar.
// запрашиваем память
cudaMallocArray (& myArray,
& refTex.channelDesc, / * этим вам не нужно заполнять дескриптор канала * /
ширина,
высота);
-3. копировать данные из CPU в GPU (в массив)
cudaMemcpyToArray (arrayCudaEntrada, // назначение: массив
0, 0, // смещения
sourceData , // указатель uint *
width height sizeof (uint), // общий объем копируемых байтов
cudaMemcpyHostToDevice);
- 4. связать текстуру и массив
cudaBindTextureToArray (refTex, arrayCudaEntrada)
-5. изменить некоторые параметры текстуры
refTextura_In.normalized = false; // не преобразовывать автоматически полученные данные в [0,1 [
refTextura_In.addressMode [0] = cudaAddressModeClamp; // если моя индексация выходит за рамки: автоматически использовать допустимую индексацию (0, если индекс отрицательный, последний, если индекс слишком большой)
refTextura_In.addressMode [1] = cudaAddressModeClamp;
------ ---- в ядре ------------------------------------------- -------------
// находим индексы (f, c) для обработки этим потоком
uint f = (blockIdx.x * blockDim.x) + threadIdx .x;
uint c = (blockIdx.y * blockDim.y) + threadIdx.y;
// this is curious and necessary: indexes for reading from a texture
// are floats !. Even if you are certain to access (4,5) you have
// match the "center" this is (4.5, 5.5)
uint read = tex2D( refTex, c+0.5f, f+0.5f); // texRef is a global variable
Теперь вы обрабатываете чтение и записываете результаты в другую зону глобальной памяти устройства, не к самой текстуре!
readTexels ()
- это функция ядра ( __ global __
), то есть она выполняется на графическом процессоре. Поэтому вам нужно использовать правильный синтаксис для запуска ядра.
Ознакомьтесь с Руководством по программированию CUDA и некоторыми примерами SDK, которые доступны на сайте NVIDIA CUDA , чтобы узнать, как запустить ядро.
Подсказка: в итоге получится что-то вроде readTexels <<< grid, block >>> (...)