2019-09-30 22:41:29 +02:00

384 lines
10 KiB
C

#include <stdio.h>
#include <gtk/gtk.h>
#include <math.h>
#include <errno.h>
#include <stdlib.h>
#include <CL/cl.h>
#include <epoxy/gl.h>
#include <epoxy/glx.h>
#include <time.h>
static const char * const vertex_shader = "#version 330 core\n \
layout (location = 0) in vec3 aPos;\n \
layout (location = 1) in vec2 aTexCoord;\n\
out vec2 texCoord;\n\
out vec3 vertPos;\n \
void main()\n \
{\n \
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n \
texCoord = aTexCoord;\n\
vertPos = aPos;\n\
}\n";
static const char * const orange_framgment_shader = " \
#version 330 core\n \
out vec4 FragColor;\n \
in vec3 vertPos;\n \
in vec2 texCoord;\n \
uniform sampler2D ourTexture;\n \
\n \
void main()\n \
{\n \
FragColor = texture(ourTexture, texCoord); //+ vec4(vertPos.x, -vertPos.x, vertPos.y, 0.0);\n \
}";
struct canvas_buffer {
unsigned char *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)
{
gtk_main_quit();
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;
}
static int calculate_mandelbrot(struct canvas_buffer *buff)
{
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;
data_size = buff->width*buff->height;
if (!buff->mandelbrot_buffer)
buff->mandelbrot_buffer = (unsigned char *)malloc(data_size*3);
if (!buff->mandelbrot_buffer)
return -ENOMEM;
clGetPlatformIDs(0, NULL, &platform_id_count);
if (platform_id_count == 0)
return -ENOMEM;
platform_ids = (cl_platform_id *)malloc(platform_id_count *
sizeof(cl_platform_id));
if (platform_ids == NULL)
return -ENOMEM;
clGetPlatformIDs(platform_id_count, platform_ids, NULL);
printf("Platforms available: %u\n", (unsigned int)platform_id_count);
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);
}
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);
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,
3*data_size, buff->mandelbrot_buffer, &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*3, buff->mandelbrot_buffer, 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;
}
float vertices[] = {
// Vertex Texture
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom left
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top left
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom right
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top right
};
unsigned int indices[] = {
0, 1, 2,
2, 1, 3
};
static unsigned int vertex_buffer_object;
static unsigned int element_buffer_object;
static unsigned int vertex_array_object;
static unsigned int shader_program_id;
static unsigned int texture_id;
gboolean render(GtkGLArea *gl_area, GdkGLContext *context, gpointer user_data)
{
gtk_gl_area_make_current(gl_area);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader_program_id);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBindTexture(GL_TEXTURE_2D, texture_id);
glBindVertexArray(vertex_array_object);
//glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glFlush();
return TRUE;
}
void realize(GtkGLArea *gl_area, gpointer user_data)
{
unsigned int vertex_shader_id;
unsigned int fragment_shader_id;
struct canvas_buffer *mandelbrot_buff = (struct canvas_buffer *)user_data;
int success;
char info_log[512];
gtk_gl_area_make_current(gl_area);
glClearColor(0, 0, 0, 1);
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
glGenBuffers(1, &vertex_buffer_object);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &element_buffer_object);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer_object);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
vertex_shader_id = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader_id, 1, &vertex_shader, NULL);
glCompileShader(vertex_shader_id);
glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex_shader_id, 512, NULL, info_log);
printf("%s\n", info_log);
} else {
printf("Vertex shader compilation successful\n");
}
fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader_id, 1, &orange_framgment_shader, NULL);
glCompileShader(fragment_shader_id);
glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment_shader_id, 512, NULL, info_log);
printf("%s\n", info_log);
} else {
printf("Fragment shader compilation successful\n");
}
shader_program_id = glCreateProgram();
glAttachShader(shader_program_id, vertex_shader_id);
glAttachShader(shader_program_id, fragment_shader_id);
glLinkProgram(shader_program_id);
glGetShaderiv(shader_program_id, GL_LINK_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader_program_id, 512, NULL, info_log);
printf("%s\n", info_log);
} else {
printf("Shader Core linked successfully\n");
}
glUseProgram(shader_program_id);
glDeleteShader(vertex_shader_id);
glDeleteShader(fragment_shader_id);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, mandelbrot_buff->width, mandelbrot_buff->height,
0, GL_RGB, GL_UNSIGNED_BYTE, mandelbrot_buff->mandelbrot_buffer);
glGenerateMipmap(GL_TEXTURE_2D);
//glClear(GL_COLOR_BUFFER_BIT);
}
int main(int argc, char **argv)
{
GtkGLArea *gl_area;
GtkWindow *window;
GtkBuilder *builder;
static struct canvas_buffer mandelbrot_buff;
clock_t start, end;
gtk_init(&argc, &argv);
builder = gtk_builder_new_from_resource("/main.glade");
window = GTK_WINDOW(gtk_builder_get_object(builder, "main-window"));
g_signal_connect(window, "delete-event", G_CALLBACK(on_main_window_close), NULL);
mandelbrot_buff.x_span = 0.075;//2.8;
mandelbrot_buff.y_span = 0.075;//2.25;
mandelbrot_buff.center_x = -0.6;
mandelbrot_buff.center_y = 0.45;
mandelbrot_buff.width = 2000;
mandelbrot_buff.height = 2000;
mandelbrot_buff.iterations = 400;
mandelbrot_buff.mandelbrot_buffer = NULL;
printf("Compile and run Mandelbrot on OpenCL HW\n");
start = clock();
calculate_mandelbrot(&mandelbrot_buff);
end = clock();
printf("Calculation finished. Time needed: %lf ms\n", ((double) (end - start)) / CLOCKS_PER_SEC * 1000.0);
gl_area = GTK_GL_AREA(gtk_gl_area_new());
gtk_gl_area_set_auto_render(gl_area, TRUE);
gtk_widget_set_vexpand(GTK_WIDGET(gl_area), TRUE);
gtk_widget_set_hexpand(GTK_WIDGET(gl_area), TRUE);
g_signal_connect(gl_area, "realize", G_CALLBACK(realize), &mandelbrot_buff);
g_signal_connect(gl_area, "render", G_CALLBACK(render), NULL);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(gl_area));
gtk_widget_show(GTK_WIDGET(gl_area));
g_object_unref(builder);
gtk_gl_area_make_current(gl_area);
printf("Gui will be displayed\n");
gtk_main();
return 0;
}