#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; std::string slurp(std::string file_name){ std::ifstream f(file_name); if (!f) throw std::runtime_error(std::string("Unable to open file: ") + file_name); return {std::istreambuf_iterator(f), std::istreambuf_iterator()}; } struct Vertex{ moggle::vector3 position; moggle::vector2 tex_coord; }; const Vertex quad[] = { // x y z u v {{ 1, -1, 0}, {1, 0}}, {{-1, -1, 0}, {0, 0}}, {{ 1, 1, 0}, {1, 1}}, {{-1, 1, 0}, {0, 1}} }; struct App { moggle::shader_program program; moggle::vao v; moggle::vbo quad_vbo; // ptrs to postpone construction, should clean this up unique_ptr cl_context; unique_ptr cl_device; unique_ptr cl_queue; unique_ptr cl_image; unique_ptr cl_program; unique_ptr k_initialize; unique_ptr k_update; float time = 0; GLuint gl_texture = 0; size_t W = 128; size_t H = 128; enum { POS_ATTR, TEX_ATTR }; void load_shader(){ auto vs = moggle::shader::from_file(moggle::shader_type::vertex, "Fractal.vsh"); auto fs = moggle::shader::from_file(moggle::shader_type::fragment, "Fractal.fsh"); program.attach(vs); program.attach(fs); program.bind_attribute(POS_ATTR, "position"); program.bind_attribute(TEX_ATTR, "tex_coord"); program.link(); } void create_vao(){ v.bind(); quad_vbo.bind(GL_ARRAY_BUFFER); quad_vbo.data(quad); moggle::gl::enable_vertex_attribute_array(POS_ATTR); moggle::gl::enable_vertex_attribute_array(TEX_ATTR); v.attribute(POS_ATTR, quad_vbo, &Vertex::position); v.attribute(TEX_ATTR, quad_vbo, &Vertex::tex_coord); } GLuint create_gl_texture(){ GLuint tex = 0; moggle::gl::active_texture(GL_TEXTURE0); moggle::gl::generate_textures(1, &tex); moggle::gl::bind_texture(GL_TEXTURE_2D, tex); moggle::gl::texture_image_2d(GL_TEXTURE_2D, 0, GL_RGBA, W, H, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); moggle::gl::texture_parameter_i(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); moggle::gl::texture_parameter_i(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); return tex; } // shared with opengl void initialize_cl(GLContext & gl_context){ CGLShareGroupObj sharegroup = CGLGetShareGroup(gl_context.ctx); cl_int err = 0; cl_context_properties properties[] = { CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)sharegroup, 0 }; cl_context = make_unique(CL_DEVICE_TYPE_CPU, properties, nullptr, nullptr, &err); cl::checky(err); cl_device = make_unique(cl_context->getInfo().front()); cl_queue = make_unique(*cl_context, *cl_device, 0, &err); cl::checky(err); } void load_cl_kernels(){ cl_int err = 0; // build the program cl_program = make_unique(*cl_context, slurp("Kernel.cl"), true, &err); cout << cl_program->getBuildInfo(*cl_device) << std::endl; cl::checky(err); cout << *cl_program << endl; // grab the kernels k_initialize = make_unique(*cl_program, "initialize", &err); cl::checky(err); k_update = make_unique(*cl_program, "update", &err); cl::checky(err); } void initialize(GLContext & gl_context){ // gl part load_shader(); create_vao(); gl_texture = create_gl_texture(); // cl part initialize_cl(gl_context); load_cl_kernels(); cl_int err = 0; // obtain cl memory object cl_image = make_unique(*cl_context, CL_MEM_READ_WRITE, GL_TEXTURE_2D, 0, gl_texture, &err); cl::checky(err); std::cout << *cl_image << std::endl; cl::checky((*k_initialize)(*cl_queue, W, H, W, H, *cl_image)); // no need for finish here, as we will always do a finish in draw(), before gl calls } void draw(){ time += 1/60.0f; cl::checky((*k_update)(*cl_queue, W, H, W, H, *cl_image, *cl_image)); cl::checky(cl_queue->finish()); moggle::gl::clear_color(0.65f, 0.65f, 0.65f, 1.0f); moggle::gl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); program.use(); moggle::gl::bind_texture(GL_TEXTURE_2D, gl_texture); program.uniform("tex").set(0); v.bind(); moggle::gl::draw_arrays(GL_TRIANGLE_STRIP, 0, 4); } void resize(size_t w, size_t h){ W = w; H = h; gl_texture = create_gl_texture(); cl_int err = 0; cl_image = make_unique(*cl_context, CL_MEM_READ_WRITE, GL_TEXTURE_2D, 0, gl_texture, &err); cl::checky(err); std::cout << *cl_image << std::endl; cl::checky((*k_initialize)(*cl_queue, W, H, W, H, *cl_image)); } }; int main() { App a; NSAppWrapper app; app.create_window({ [&](ContextParameters ctxp){ a.initialize(ctxp.context); }, [&](ContextParameters){ a.draw(); }, [&](ContextParameters, CGFloat w, CGFloat h){ a.resize(size_t(floor(w)), size_t(floor(h))); } }); app.run(); }