#include #define CL_HPP_TARGET_OPENCL_VERSION 200 #include #include #include #include #include #include #include #include #include struct Agent { float x,y,direction; }; bool get_source(std::string* source); unsigned long long sys_time_us(); int main(int argc, char* argv[]) { srand(time(0)); uint32_t u32_width, u32_height; uint32_t u32_dimensions[2]; if (argc == 1) { u32_width = u32_height = 300; } else { u32_width = atoi(argv[1]); u32_height = atoi(argv[2]); } int i_size = u32_width*u32_height; u32_dimensions[0] = u32_width; u32_dimensions[1] = u32_height; if (SDL_Init(SDL_INIT_VIDEO) < 0) { std::cout << "Video Init Error." << std::endl; } SDL_Window* window = SDL_CreateWindow("Slime Mold Simulator", SDL_WINDOWPOS_CENTERED-u32_width/2, SDL_WINDOWPOS_CENTERED-u32_height/2, u32_width, u32_height, SDL_WINDOW_SHOWN); SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); SDL_RenderClear(renderer); SDL_RenderPresent(renderer); SDL_Texture* field_texture = SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), SDL_TEXTUREACCESS_STREAMING, u32_width, u32_height); SDL_Texture* start_texture = SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), SDL_TEXTUREACCESS_STREAMING, u32_width, u32_height); float* ground = new float[i_size]; for(int i = 0; i < i_size; i++) { ground[i] = 0.0f; } int i_agent_count = (int)sqrt(u32_width*u32_height)*1000; Agent* agents = new Agent[i_agent_count]; { uint8_t* u8_pixels; int i_pitch; SDL_LockTexture(start_texture, NULL, (void**)&u8_pixels,&i_pitch); int i_created = 0; uint32_t u32_radius = 1*((u32_width all_platforms; cl::Platform::get(&all_platforms); cl::Platform default_platform=all_platforms[0]; std::cout << "Using platform :" << default_platform.getInfo() << std::endl; std::vector all_devices; default_platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices); if (all_devices.size() == 0) { std::cout << "Could not find OpenCL device." << std::endl; exit(1); } cl::Device default_device = all_devices[0]; std::cout << "Using device :" << default_device.getInfo() << std::endl; cl::Context context({default_device}); std::string kernel_code; if (!get_source(&kernel_code)) { std::cout << "Error reading kernel source." << std::endl; exit(1); } cl::Program::Sources sources; sources.push_back({kernel_code.c_str(), kernel_code.length()}); cl::Program program(context, sources); if (program.build({default_device}, "-cl-std=CL2.0") != CL_SUCCESS) { std::cout << "Error building: " << program.getBuildInfo(default_device) << std::endl; exit(1); } cl::Buffer buffer_agents(context, CL_MEM_READ_WRITE, sizeof(Agent)*i_agent_count); cl::Buffer buffer_ground(context, CL_MEM_READ_WRITE, sizeof(float)*i_size); cl::Buffer buffer_ground_swap(context, CL_MEM_READ_WRITE, sizeof(float)*i_size); cl::Buffer buffer_ground_dimensions(context, CL_MEM_READ_WRITE, sizeof(uint32_t)*2); cl::Buffer buffer_draw_data(context, CL_MEM_READ_WRITE, sizeof(uint8_t)*4*i_size); cl::CommandQueue queue(context,default_device); queue.enqueueWriteBuffer(buffer_agents, CL_TRUE, 0, sizeof(Agent)*i_agent_count, agents); queue.enqueueWriteBuffer(buffer_ground, CL_TRUE, 0, sizeof(float)*i_size, ground); queue.enqueueWriteBuffer(buffer_ground_swap, CL_TRUE, 0, sizeof(float)*i_size, ground); queue.enqueueWriteBuffer(buffer_ground_dimensions, CL_TRUE, 0, sizeof(uint32_t)*2, &u32_dimensions[0]); cl::Kernel kernel_initialize_globals(program, "initialize_globals"); kernel_initialize_globals.setArg(0, buffer_agents); kernel_initialize_globals.setArg(1, buffer_ground); kernel_initialize_globals.setArg(2, buffer_ground_swap); kernel_initialize_globals.setArg(3, buffer_ground_dimensions); queue.enqueueNDRangeKernel(kernel_initialize_globals, cl::NullRange, cl::NDRange(1), cl::NullRange); queue.finish(); cl::Kernel kernel_update_ground(program, "update_ground"); cl::Kernel kernel_iterate_ground(program, "iterate_ground"); cl::Kernel kernel_move_agents(program, "move_agents"); cl::Kernel kernel_emit_agent_pheromones(program, "emit_agent_pheromones"); cl::Kernel kernel_fill_draw_data(program, "fill_draw_data"); queue.enqueueNDRangeKernel(kernel_emit_agent_pheromones, cl::NullRange, cl::NDRange(i_agent_count), cl::NullRange); queue.enqueueReadBuffer(buffer_ground, CL_TRUE, 0, sizeof(float)*i_size, ground); queue.finish();//*/ SDL_Rect screen_rect = {0,0,(int)u32_width,(int)u32_height}; unsigned long long ull_time_old, ull_time_now; ull_time_now = ull_time_old = sys_time_us(); int iteration_duration = 16666/10; bool pause = true; while(true) { SDL_Event event; if (1 == SDL_PollEvent(&event)) { if (event.type == SDL_KEYDOWN) { if (event.key.keysym.scancode == SDL_SCANCODE_Q) { break; } else if (event.key.keysym.scancode == SDL_SCANCODE_P) { pause = !pause; } else if (event.key.keysym.scancode == SDL_SCANCODE_T) { SDL_SetRenderDrawColor(renderer, 0,0,0,0); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, start_texture, &screen_rect, &screen_rect); SDL_RenderPresent(renderer); } } } ull_time_now = sys_time_us(); if (ull_time_now >= ull_time_old + iteration_duration) { ull_time_old = ull_time_now; if (pause) { continue; } queue.enqueueNDRangeKernel(kernel_update_ground, cl::NullRange, cl::NDRange(i_size), cl::NullRange); queue.enqueueNDRangeKernel(kernel_iterate_ground, cl::NullRange, cl::NDRange(i_size), cl::NullRange); queue.enqueueNDRangeKernel(kernel_move_agents, cl::NullRange, cl::NDRange(i_agent_count), cl::NullRange); queue.enqueueNDRangeKernel(kernel_emit_agent_pheromones, cl::NullRange, cl::NDRange(i_agent_count), cl::NullRange); kernel_fill_draw_data.setArg(0, buffer_draw_data); queue.enqueueNDRangeKernel(kernel_fill_draw_data, cl::NullRange, cl::NDRange(i_size), cl::NullRange); uint8_t* u8_pixels; int i_pitch; SDL_LockTexture(field_texture, NULL, (void**)&u8_pixels, &i_pitch); queue.enqueueReadBuffer(buffer_draw_data, CL_TRUE, 0, sizeof(uint8_t)*4*i_size, u8_pixels); queue.finish(); SDL_UnlockTexture(field_texture); SDL_SetRenderDrawColor(renderer, 0,0,0,0); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, field_texture, &screen_rect, &screen_rect); SDL_RenderPresent(renderer); } } SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); delete[] agents; delete[] ground; return 0; } bool get_source(std::string* source) { if (source == nullptr) { return false; } std::ifstream in_file("gpu_kernel.clcpp", std::ios::in); std::stringstream buffer; buffer << in_file.rdbuf(); *source = buffer.str(); return true; } unsigned long long sys_time_us() { return (unsigned long long)(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); }