OpenCL en C
L'API OpenCL pour le langage C est la couche la plus basse pour accéder à OpenCL. C'est certainement celle qui évoluera le plus vite et qui fait l'objet de spécification par le Kronos Group. Les autres API sont souvent basées sur cette API C. Voici une présentation rapide de l'api opencl pour le C. Le but est simplement d'illustrer l'utilisation de l'API, je ne vous conseille pas d'écrire vos applications directement avec cette API à moins de commencer par écrire une petite couche d'abstraction (simplification).
Voici les différentes étapes de création:
Récupérer le(s) device(s)
cl_uint nbDevice;
cl_device_id device;
err=clGetDeviceIDs(NULL,CL_DEVICE_TYPE_GPU,1,&device,&nbDevice);
Récupérer les infos sur chaque device
char deviceName[1024];
cl_uint maxComputeUnits;
cl_uint maxClockFrequency;
err=clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(deviceName), &deviceName, NULL);
cout << deviceName << endl;
err=clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(maxComputeUnits), &maxComputeUnits, NULL);
cout << "Max Compute Units : " << maxComputeUnits << endl;
err=clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(maxClockFrequency), &maxClockFrequency, NULL);
cout << "Max Clock Frequency : " << maxClockFrequency << " MHz" << endl;
Créer un context
cl_context context;
context=clCreateContext(0,1,&device,NULL,NULL,&err);
Créer une queue de commande sur chaqu'une des devices
cl_command_queue cQueue;
cQueue = clCreateCommandQueue(context, device, 0, &err);
Allouer les buffers dans le context
cl_mem ib_A,ib_B,ob_dest;
ib_A = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(cl_float) * szGlobalWorkSize, NULL, &err);
ib_B = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(cl_float) * szGlobalWorkSize, NULL, &err);
ob_dest = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(cl_float) * szGlobalWorkSize, NULL, &err);
err = clEnqueueWriteBuffer(cQueue, ib_A, CL_FALSE, 0, sizeof(cl_float) * szGlobalWorkSize, A, 0, NULL, NULL);
err = clEnqueueWriteBuffer(cQueue, ib_B, CL_FALSE, 0, sizeof(cl_float) * szGlobalWorkSize, B, 0, NULL, NULL);
Créer/compiler un Program depuis les sources en OpenCL
cl_program hProgram;
hProgram = clCreateProgramWithSource(context, 1, &sProgramSource, 0, &err);
err = clBuildProgram(hProgram, 0, 0, 0, 0, 0);
if(err) {
size_t len;
char buffer[2048];
clGetProgramBuildInfo(hProgram, device, CL_PROGRAM_BUILD_LOG, sizeof(buffer), buffer,&len);
cout << buffer << endl;
}
Créer un kernel a partir de ce Program
cl_kernel hKernel;
hKernel = clCreateKernel(hProgram, "myadd", &err);
Lancer le kernel
La fonction clEnqueueNDRangeKernel permet de lancer un kernel existant. Il faut au préalable avoir transmit les arguments clSetKernelArg.
err = clSetKernelArg(hKernel, 0, sizeof(cl_mem), (void*)&ib_A);
err = clSetKernelArg(hKernel, 1, sizeof(cl_mem), (void*)&ib_B);
err = clSetKernelArg(hKernel, 2, sizeof(cl_mem), (void*)&ob_dest);
err = clSetKernelArg(hKernel, 3, sizeof(cl_int), (void*)&iNumElements);
err = clEnqueueNDRangeKernel(cQueue, hKernel, 1, 0, &szGlobalWorkSize, &szLocalWorkSize, 0, 0, 0);
Récupérer le résultat
err = clEnqueueReadBuffer(cQueue, ob_dest, CL_TRUE, 0, sizeof(cl_float) * szGlobalWorkSize, dest, 0, NULL, NULL);
Posted Jeu 31 décembre 2009 by Stéphane Planquart in programmation graphique