Strange attractors with OpenCL
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 

259 lines
6.0 KiB

#include <cl2.hpp>
#include <NSWrapper.hpp>
#include <NSGLWrapper.hpp>
#include <png.hpp>
#include <moggle/core/gl.hpp>
#include <moggle/core/shader.hpp>
#include <moggle/core/vao.hpp>
#include <moggle/core/vbo.hpp>
#include <OpenGL/OpenGL.h>
#include <OpenGL/CGLDevice.h>
#include <OpenCL/opencl.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <cassert>
#include <memory>
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<char>(f), std::istreambuf_iterator<char>()};
}
struct Vertex{
moggle::vector3<GLfloat> position;
moggle::vector2<GLfloat> 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<Vertex> quad_vbo;
// ptrs to postpone construction, should clean this up
unique_ptr<cl::Context> cl_context;
unique_ptr<cl::ImageGL> cl_image;
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_texture(){
std::vector<GLubyte> data(4*W*H);
for(int i = 0; i < data.size(); i += 4){
data[i+0] = 255 * i / (W-1);
data[i+1] = 127;
data[i+2] = 0;
data[i+3] = 255;
}
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, data.data());
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;
}
void initialize(GLContext & gl_context){
// Fractal part
load_shader();
create_vao();
// create a texture for opencl
gl_texture = create_texture();
// share the bitch
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::Context>(CL_DEVICE_TYPE_CPU, properties, nullptr, nullptr, &err);
cl::checky(err);
auto cl_device = cl_context->getInfo<CL_CONTEXT_DEVICES>().front();
// obtain cl memory object
cl_image = make_unique<cl::ImageGL>(*cl_context, CL_MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, gl_texture, &err);
cl::checky(err);
std::cout << *cl_image << std::endl; // sanity check
// build the program
auto KernelSource = slurp("Kernel.cl");
cl::Program program(*cl_context, {KernelSource.c_str(), KernelSource.size()}, true, &err);
cout << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(cl_device) << std::endl;
cl::checky(err);
cout << program << endl;
// grab the kernel
KernelOp kernel(program, "initialize", &err);
cl::checky(err);
// create a queue (for the first device)
cl::CommandQueue queue(*cl_context, cl_device);
cl::checky(kernel(queue, W, H, W, H, *cl_image));
cl::checky(queue.flush());
}
void draw(){
time += 1/60.0f;
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<GLint>("tex").set(0);
v.bind();
moggle::gl::draw_arrays(GL_TRIANGLE_STRIP, 0, 4);
}
};
struct CLApp {
void initialize(){
auto context = cl::Context::getDefault();
cout << context << endl;
cl_int err = 0;
// build the program
auto KernelSource = slurp("Kernel.cl");
cl::Program program(context, {KernelSource.c_str(), KernelSource.size()}, true, &err);
check(err);
cout << program << endl;
// grab the kernel
KernelOp kernel(program, "square", &err);
check(err);
// create a queue
cl::CommandQueue queue(context, context.getInfo<CL_CONTEXT_DEVICES>().front());
// make a lot of data
constexpr size_t W = 512;
constexpr size_t H = 512;
std::vector<cl_float> input_vector(W*H);
for(int y = 0; y < H; ++y){
for(int x = 0; x < W; ++x){
input_vector[x + W*y] = 10 * ((x / double(W) - 0.5) + 1.3371337*(y / double(H) - 0.5));
}
}
// transfer data into buffers
cl::Buffer input(context, input_vector.begin(), input_vector.end(), false, true);
int r = 10, g = 10, b = 10;
// DO IT (in place)
for(int i = 0; i < r; ++i){
check(kernel(queue, W, H, input, W, input));
}
// read back
queue.finish();
auto red = input_vector;
// DO IT (in place)
for(int i = 0; i < g; ++i){
check(kernel(queue, W, H, input, W, input));
}
// read back
queue.finish();
auto green = input_vector;
// DO IT (in place)
for(int i = 0; i < b; ++i){
check(kernel(queue, W, H, input, W, input));
}
// read back
queue.finish();
auto& blue = input_vector;
// test
cout << "opencl is done" << endl;
png::ostream<> image(W, H, "test.png");
for(int i = 0; i < red.size(); ++i){
image << png::ostream<>::pixel(blue[i], red[i], green[i]);
}
cout << "png is saved" << endl;
}
};
int main() {
App a;
CLApp b;
NSAppWrapper app;
app.create_window({
[&](ContextParameters ctxp){
//b.initialize();
a.initialize(ctxp.context);
},
[&](ContextParameters){
a.draw();
},
nullptr
});
app.run();
}