#include #include #include #include #include #include #include #include #include #include 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 \ uniform float zoom;\n\ void main()\n \ {\n \ gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n \ texCoord = aTexCoord / zoom;\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);\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 -0.95f, -0.95f, 0.0f, 0.0f, 0.0f, // bottom left -0.95f, 0.95f, 0.0f, 0.0f, 1.0f, // top left 0.95f, -0.95f, 0.0f, 1.0f, 0.0f, // bottom right 0.95f, 0.95f, 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) { int zoom_loc; static float zoom = 1.0f; gtk_gl_area_make_current(gl_area); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(shader_program_id); zoom_loc = glGetUniformLocation(shader_program_id, "zoom"); glUniform1f(zoom_loc, zoom); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 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.2, 0.2, 0.2, 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.1;//2.8; mandelbrot_buff.y_span = 0.1;//2.25; mandelbrot_buff.center_x = -0.6; mandelbrot_buff.center_y = 0.44; mandelbrot_buff.width = 4000; mandelbrot_buff.height = 4000; mandelbrot_buff.iterations = 1000; 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; }