opencl example
This commit is contained in:
246
src/main.c
246
src/main.c
@@ -1,17 +1,19 @@
|
||||
#include <stdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <math.h>
|
||||
#include <threads.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <CL/cl.h>
|
||||
|
||||
struct canvas_buffer {
|
||||
unsigned int *mandelbrot_buffer;
|
||||
unsigned int iterations;
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
double center_x;
|
||||
double center_y;
|
||||
double x_span;
|
||||
double y_span;
|
||||
unsigned int *mandelbrot_buffer;
|
||||
unsigned int iterations;
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
double center_x;
|
||||
double center_y;
|
||||
double x_span;
|
||||
double y_span;
|
||||
};
|
||||
|
||||
static gboolean on_main_window_close(GtkWidget *window, gpointer data)
|
||||
@@ -20,6 +22,43 @@ static gboolean on_main_window_close(GtkWidget *window, gpointer data)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void check_error(cl_int error)
|
||||
{
|
||||
if (error != CL_SUCCESS) {
|
||||
printf("OpenCL call failed with error %d\n", (int)error);
|
||||
exit(error);
|
||||
}
|
||||
}
|
||||
|
||||
void load_kernel_from_file(char *file, char **src)
|
||||
{
|
||||
long fsize;
|
||||
FILE *f = fopen(file, "rb");
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET); //same as rewind(f);
|
||||
*src = (char *)malloc(fsize + 1);
|
||||
fread(*src, fsize, 1, f);
|
||||
fclose(f);
|
||||
(*src)[fsize] = 0;
|
||||
}
|
||||
|
||||
cl_program create_program(char *src, cl_context context)
|
||||
{
|
||||
cl_program program;
|
||||
size_t lengths[1];
|
||||
cl_int error = 0;
|
||||
|
||||
lengths[0] = strlen(src);
|
||||
printf("strlen: %u\n", (unsigned int)lengths[0]);
|
||||
program = clCreateProgramWithSource(context, 1, (const char **)&src,
|
||||
lengths, &error);
|
||||
check_error(error);
|
||||
|
||||
return program;
|
||||
}
|
||||
unsigned int *data_array = NULL;
|
||||
static gboolean drawing_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
|
||||
{
|
||||
struct canvas_buffer *buff = (struct canvas_buffer *)data;
|
||||
@@ -38,24 +77,24 @@ static gboolean drawing_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
|
||||
cairo_scale(cr, 1, -1);
|
||||
cairo_translate(cr, (double)width/2.0, -(double)height/2.0);
|
||||
|
||||
for (x = 0; x < buff->width; x++) {
|
||||
for (y = 0; y < buff->height; y++) {
|
||||
cairo_rectangle(cr,
|
||||
((double)x - (double)(buff->width - 1) / 2),
|
||||
((double)y - (double)(buff->height - 1) / 2),
|
||||
1,
|
||||
1);
|
||||
if (buff->mandelbrot_buffer[y * buff->width + x] == buff->iterations) {
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
} else {
|
||||
color_scale = (double)buff->mandelbrot_buffer[y * buff->width + x] / buff->iterations;
|
||||
cairo_set_source_rgb (cr, (sqrt(1-color_scale)), (color_scale*color_scale), color_scale);
|
||||
}
|
||||
cairo_fill(cr);
|
||||
|
||||
}
|
||||
}
|
||||
for (x = 0; x < buff->width; x++) {
|
||||
for (y = 0; y < buff->height; y++) {
|
||||
cairo_rectangle(cr,
|
||||
((double)x - (double)(buff->width - 1) / 2),
|
||||
((double)y - (double)(buff->height - 1) / 2),
|
||||
1,
|
||||
1);
|
||||
if (data_array[y * buff->width + x] == buff->iterations) {
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
} else {
|
||||
color_scale = (double)data_array[y * buff->width + x] / buff->iterations;
|
||||
cairo_set_source_rgb (cr, (sqrt(1-color_scale)), (color_scale*color_scale), color_scale);
|
||||
}
|
||||
cairo_fill(cr);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Drawing code end */
|
||||
@@ -64,58 +103,124 @@ static gboolean drawing_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void calculate_mandelbrot(struct canvas_buffer *buff)
|
||||
|
||||
static int calculate_mandelbrot(struct canvas_buffer *buff)
|
||||
{
|
||||
double val_per_x_pixel;
|
||||
double val_per_y_pixel;
|
||||
unsigned int i;
|
||||
unsigned int pixel_x;
|
||||
unsigned int pixel_y;
|
||||
double point_real, point_imag;
|
||||
double z_real, z_imag;
|
||||
double z2_real, z2_imag;
|
||||
|
||||
int i;
|
||||
cl_int error;
|
||||
cl_int ret;
|
||||
cl_platform_id *platform_ids = NULL;
|
||||
cl_device_id *device_ids = NULL;
|
||||
cl_uint platform_id_count = 0;
|
||||
cl_uint device_id_count = 0;
|
||||
cl_context context;
|
||||
cl_program program;
|
||||
cl_kernel kernel;
|
||||
cl_command_queue queue;
|
||||
cl_mem dat_buff;
|
||||
char *source_code = NULL;
|
||||
char temp_buff[100];
|
||||
size_t data_size;
|
||||
size_t work_size = 64;
|
||||
|
||||
|
||||
if (!buff)
|
||||
return;
|
||||
data_size = buff->width*buff->height;
|
||||
data_array = (unsigned int *)malloc(sizeof(data_array[0])*data_size);
|
||||
if (!data_array)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Setup the calculation data */
|
||||
val_per_x_pixel = (buff->x_span) / (buff->width - 1);
|
||||
val_per_y_pixel = (buff->y_span) / (buff->height - 1);
|
||||
|
||||
for (pixel_y = 0; pixel_y < buff->height; pixel_y++) {
|
||||
for (pixel_x = 0; pixel_x < buff->width; pixel_x++) {
|
||||
point_real = (((double)pixel_x - (double)(buff->width - 1) / 2)) * val_per_x_pixel + buff->center_x;
|
||||
point_imag = (((double)pixel_y - (double)(buff->height - 1) / 2)) * val_per_y_pixel + buff->center_y;
|
||||
clGetPlatformIDs(0, NULL, &platform_id_count);
|
||||
if (platform_id_count == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
z_real = 0.0;
|
||||
z_imag = 0.0;
|
||||
platform_ids = (cl_platform_id *)malloc(platform_id_count *
|
||||
sizeof(cl_platform_id));
|
||||
if (platform_ids == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Check for convergence */
|
||||
for (i = 0; i < buff->iterations; i++) {
|
||||
clGetPlatformIDs(platform_id_count, platform_ids, NULL);
|
||||
|
||||
z2_real = z_real * z_real - z_imag * z_imag;
|
||||
z2_imag = 2.0 * z_real * z_imag;
|
||||
printf("Platforms available: %u\n", (unsigned int)platform_id_count);
|
||||
|
||||
z_real = z2_real + point_real;
|
||||
z_imag = z2_imag + point_imag;
|
||||
for (i = 0; i < platform_id_count; i++) {
|
||||
temp_buff[0] = '\0';
|
||||
clGetPlatformInfo(platform_ids[i], CL_PLATFORM_NAME, sizeof(temp_buff), temp_buff, NULL);
|
||||
printf("Platform ID %d: %s\n", i, temp_buff);
|
||||
}
|
||||
|
||||
if ((z_real * z_real + z_imag * z_imag) >= 4.0)
|
||||
break;
|
||||
}
|
||||
clGetDeviceIDs(platform_ids[0], CL_DEVICE_TYPE_ALL, 0, NULL,
|
||||
&device_id_count);
|
||||
printf("Device in Platform 0 count: %u\n",
|
||||
(unsigned int)device_id_count);
|
||||
|
||||
buff->mandelbrot_buffer[pixel_y * buff->width + pixel_x] = i;
|
||||
}
|
||||
if (device_id_count == 0)
|
||||
return -1;
|
||||
|
||||
device_ids = (cl_device_id *) malloc(sizeof(cl_device_id)
|
||||
*device_id_count);
|
||||
|
||||
clGetDeviceIDs(platform_ids[0], CL_DEVICE_TYPE_ALL, device_id_count,
|
||||
device_ids, NULL);
|
||||
|
||||
for (i = 0; i < device_id_count; i++) {
|
||||
temp_buff[0] = '\0';
|
||||
clGetDeviceInfo(device_ids[i], CL_DEVICE_NAME, sizeof(temp_buff), temp_buff, NULL);
|
||||
printf("Device ID %d: %s\n", i, temp_buff);
|
||||
}
|
||||
|
||||
|
||||
context = clCreateContext(NULL, 1, &device_ids[0], NULL, NULL, &error);
|
||||
check_error(error);
|
||||
|
||||
queue = clCreateCommandQueue(context, device_ids[0], 0, &error);
|
||||
|
||||
dat_buff = clCreateBuffer(context, CL_MEM_WRITE_ONLY |
|
||||
CL_MEM_COPY_HOST_PTR,
|
||||
sizeof(data_array[0])*data_size, data_array, &error);
|
||||
check_error(error);
|
||||
|
||||
load_kernel_from_file("cl_kernels/mandelbrot.cl", &source_code);
|
||||
program = create_program(source_code, context);
|
||||
|
||||
/* Compile the source code */
|
||||
check_error(clBuildProgram(program, device_id_count,
|
||||
device_ids, NULL, NULL, NULL));
|
||||
kernel = clCreateKernel(program, "mandelbrot", &error);
|
||||
|
||||
|
||||
/* Setting the arguments */
|
||||
clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&dat_buff);
|
||||
clSetKernelArg(kernel, 1, sizeof(unsigned int), (void *)&buff->iterations);
|
||||
clSetKernelArg(kernel, 2, sizeof(double), (void *)&buff->center_x);
|
||||
clSetKernelArg(kernel, 3, sizeof(double), (void *)&buff->center_y);
|
||||
clSetKernelArg(kernel, 4, sizeof(double), (void *)&buff->x_span);
|
||||
clSetKernelArg(kernel, 5, sizeof(double), (void *)&buff->y_span);
|
||||
clSetKernelArg(kernel, 6, sizeof(unsigned int), (void *)&buff->width);
|
||||
clSetKernelArg(kernel, 7, sizeof(unsigned int), (void *)&buff->height);
|
||||
|
||||
ret = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &data_size, &work_size, 0, NULL, NULL);
|
||||
check_error(ret);
|
||||
|
||||
clEnqueueReadBuffer(queue, dat_buff, CL_TRUE, 0, data_size*sizeof(data_array[0]), data_array, 0, NULL, NULL);
|
||||
|
||||
ret = clFlush(queue);
|
||||
ret = clFinish(queue);
|
||||
ret = clReleaseKernel(kernel);
|
||||
ret = clReleaseProgram(program);
|
||||
ret = clReleaseMemObject(dat_buff);
|
||||
ret = clReleaseCommandQueue(queue);
|
||||
ret = clReleaseContext(context);
|
||||
free(platform_ids);
|
||||
free(device_ids);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int f(void * a)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@@ -133,22 +238,19 @@ int main(int argc, char **argv)
|
||||
|
||||
g_signal_connect(window, "delete-event", G_CALLBACK(on_main_window_close), NULL);
|
||||
g_signal_connect(G_OBJECT(drawing_area),
|
||||
"draw", G_CALLBACK(drawing_callback), (gpointer)&mandelbrot_buff);
|
||||
"draw", G_CALLBACK(drawing_callback), (gpointer)&mandelbrot_buff);
|
||||
|
||||
g_object_unref(builder);
|
||||
|
||||
thrd_t t;
|
||||
thrd_create(&t, f, NULL);
|
||||
|
||||
|
||||
mandelbrot_buff.x_span = 2.8;
|
||||
mandelbrot_buff.y_span = 2.25;
|
||||
mandelbrot_buff.center_x = -0.5;
|
||||
mandelbrot_buff.center_y = 0.0;
|
||||
mandelbrot_buff.width = 1900;
|
||||
mandelbrot_buff.height = 1000;
|
||||
mandelbrot_buff.iterations = 300;
|
||||
mandelbrot_buff.mandelbrot_buffer = (unsigned int *)malloc(sizeof(unsigned int) * mandelbrot_buff.height * mandelbrot_buff.width);
|
||||
mandelbrot_buff.x_span = 1;//2.8;
|
||||
mandelbrot_buff.y_span = 0.5;//2.25;
|
||||
mandelbrot_buff.center_x = -0.6;
|
||||
mandelbrot_buff.center_y = 0.6;
|
||||
mandelbrot_buff.width = 4000;
|
||||
mandelbrot_buff.height = 2000;
|
||||
mandelbrot_buff.iterations = 70;
|
||||
mandelbrot_buff.mandelbrot_buffer = NULL;
|
||||
calculate_mandelbrot(&mandelbrot_buff);
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user