A program megvalósításáhzo először a CPU oldalon elő kell készítenünk az adatokat. Ez gyakorlatilag a képtömb lefoglalását takarja.
unsigned char* result = new unsigned char[N*N*3];
unsigned char* dev_result;
cudaMalloc((void**)&dev_result, N*N*4 * sizeof(unsigned char));
Látható, hogy két tömböt foglalunk, az egyiket a központi, a másikat a grafikus memóriában.
Mindd a két képtömb N*N pixelt tartalmaz. Továbbá RGB képet fogunk tárolni pixelenként 4 színcsatornával, ezért összesen N*N*4 értéket kell lefoglalnunk
A következő efladat, el kell indítanunka programunkat. A korábbiaktól eltérüen most kihasználjuk, hogy a blokkok, és a rács mérete dim3 typusú, vagyis lehet akár 2-3.dimenziós is.
dim3 blockDim = dim3(BLOCKDIM, BLOCKDIM, 1);
dim3 gridDim = dim3((N + BLOCKDIM - 1) / BLOCKDIM, (N + BLOCKDIM - 1) / BLOCKDIM, 1);
rippleKernel <<<gridDim, blockDim >>> (dev_result, N, N, 50);
A függvény hívásakor át kell még adnunk a kép szélességét, és magassáhát. Illetve ebben a példában még meg van adva a hullámok hullámhossza (ami most 50 pixel), amivel be tudjuk állítanu, hogy milyen sűrűen legyenek a hullámok.
Végül pedig meg kell adnunk, magát a kernelt.
__global__ void rippleKernel(unsigned char* result, int w, int h, float waveLength)
{
// ...
return;
}
A kernelben az első feladatunk a feldolgozott pixel koordinátáinak kiszámítása. Mivel most 2D adatunk van, ezt két tendely mentén kell megtennünk.
A pixel koordináták mellet kiszámítjuk azt is, hogy a lineáris tömbünkben hanyadik helyen áll a feldolgozott pixel.
int x = blockDim.x *blockIdx.x + threadIdx.x;
int y = blockDim.y *blockIdx.y + threadIdx.y;
int tid = y*w + x;
Ezek után jöhet a geometriai számítás. Kiszámítjuk a pixel intenzitását.
Ehhez annyit kell tennünk, hogy kiszámítjuk a képpont távolságát a kép középpontjától, és a kapott a kapott értéket átskálázzuk, hogy 50 pixel jelentsen egy db 2*pi -s ciklust, és használjuk a koszinus függvényt a hullám generálására.
float dist = sqrtf((x - w / 2.0f)*(x - w / 2.0f) + (y-h/2.0f)*(y - h / 2.0f));
float value = (cosf(dist / waveLength * CUDART_PI_F * 2)+1)*127;
Végül pedig kiírjuk az erdményt a globális memóriába.
if (x < w && y < h)
{
result[tid * 4] = value;
result[tid * 4 + 1] = value;
result[tid * 4 + 2] = value;
result[tid * 4 + 3] = 255;
}
Itt két fontos dologra kell figyelnünk:
- Csak akkor próbáljunk kiírni egy képpontot, ha létezik is. Az indított blokkstruktúra ugyanis túllóghat a képen.
- Illetve, hogy a képeken 4 színcsatorna van. Ezért a piel koordinátáját is meg kell szorozni 4-el, és 4 csatornát kell kiirnunk.