clray

annotate src/rt.cc @ 50:d3c46803242e

- added button to stop the timing messages
author John Tsiombikas
date Tue, 31 Aug 2010 02:54:37 +0100
parents 30bf84881553
children 55b30d8b6805
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@8 2 #include <string.h>
nuclear@2 3 #include <math.h>
nuclear@0 4 #include <assert.h>
nuclear@47 5 #include "rt.h"
John@14 6 #include "ogl.h"
nuclear@0 7 #include "ocl.h"
nuclear@22 8 #include "scene.h"
nuclear@32 9 #include "timer.h"
nuclear@45 10 #include "common.h"
nuclear@0 11
nuclear@12 12 // kernel arguments
nuclear@12 13 enum {
nuclear@12 14 KARG_FRAMEBUFFER,
nuclear@12 15 KARG_RENDER_INFO,
nuclear@12 16 KARG_FACES,
nuclear@12 17 KARG_MATLIB,
nuclear@12 18 KARG_LIGHTS,
nuclear@12 19 KARG_PRIM_RAYS,
nuclear@12 20 KARG_XFORM,
John@14 21 KARG_INVTRANS_XFORM,
nuclear@28 22 KARG_KDTREE,
John@14 23
John@14 24 NUM_KERNEL_ARGS
nuclear@12 25 };
John@11 26
nuclear@2 27 struct RendInfo {
nuclear@22 28 float ambient[4];
nuclear@2 29 int xsz, ysz;
nuclear@9 30 int num_faces, num_lights;
nuclear@2 31 int max_iter;
nuclear@47 32 int cast_shadows;
nuclear@12 33 };
nuclear@2 34
nuclear@1 35 struct Ray {
nuclear@8 36 float origin[4], dir[4];
nuclear@12 37 };
nuclear@1 38
nuclear@3 39 struct Light {
nuclear@8 40 float pos[4], color[4];
nuclear@12 41 };
nuclear@1 42
nuclear@47 43 static void update_render_info();
nuclear@3 44 static Ray get_primary_ray(int x, int y, int w, int h, float vfov_deg);
nuclear@43 45 static float *create_kdimage(const KDNodeGPU *kdtree, int num_nodes, int *xsz_ret, int *ysz_ret);
nuclear@3 46
nuclear@13 47 static Face *faces;
nuclear@3 48 static Ray *prim_rays;
nuclear@3 49 static CLProgram *prog;
nuclear@3 50 static int global_size;
nuclear@3 51
nuclear@4 52 static Light lightlist[] = {
nuclear@22 53 {{-8, 15, 18, 0}, {1, 1, 1, 1}}
nuclear@4 54 };
nuclear@4 55
nuclear@7 56
nuclear@4 57 static RendInfo rinf;
nuclear@47 58 static int saved_iter_val;
nuclear@4 59
nuclear@43 60 static long timing_sample_sum;
nuclear@43 61 static long num_timing_samples;
nuclear@43 62
John@50 63 extern bool dbg_frame_time;
John@50 64
nuclear@4 65
nuclear@39 66 bool init_renderer(int xsz, int ysz, Scene *scn, unsigned int tex)
nuclear@0 67 {
nuclear@4 68 // render info
nuclear@22 69 rinf.ambient[0] = rinf.ambient[1] = rinf.ambient[2] = 0.0;
nuclear@16 70 rinf.ambient[3] = 0.0;
nuclear@16 71
nuclear@4 72 rinf.xsz = xsz;
nuclear@4 73 rinf.ysz = ysz;
nuclear@13 74 rinf.num_faces = scn->get_num_faces();
nuclear@4 75 rinf.num_lights = sizeof lightlist / sizeof *lightlist;
nuclear@47 76 rinf.max_iter = saved_iter_val = 6;
nuclear@47 77 rinf.cast_shadows = true;
nuclear@4 78
nuclear@3 79 /* calculate primary rays */
nuclear@3 80 prim_rays = new Ray[xsz * ysz];
nuclear@2 81
nuclear@2 82 for(int i=0; i<ysz; i++) {
nuclear@2 83 for(int j=0; j<xsz; j++) {
nuclear@2 84 prim_rays[i * xsz + j] = get_primary_ray(j, i, xsz, ysz, 45.0);
nuclear@2 85 }
nuclear@0 86 }
nuclear@0 87
nuclear@2 88 /* setup opencl */
nuclear@3 89 prog = new CLProgram("render");
nuclear@3 90 if(!prog->load("rt.cl")) {
nuclear@8 91 return false;
nuclear@0 92 }
nuclear@0 93
nuclear@24 94 if(!(faces = (Face*)scn->get_face_buffer())) {
nuclear@13 95 fprintf(stderr, "failed to create face buffer\n");
nuclear@13 96 return false;
nuclear@13 97 }
nuclear@13 98
nuclear@28 99 const KDNodeGPU *kdbuf = scn->get_kdtree_buffer();
nuclear@28 100 if(!kdbuf) {
nuclear@28 101 fprintf(stderr, "failed to create kdtree buffer\n");
nuclear@28 102 return false;
nuclear@28 103 }
nuclear@43 104
nuclear@43 105 int kdimg_xsz, kdimg_ysz;
nuclear@43 106 float *kdimg_pixels = create_kdimage(kdbuf, scn->get_num_kdnodes(), &kdimg_xsz, &kdimg_ysz);
nuclear@28 107
nuclear@3 108 /* setup argument buffers */
nuclear@41 109 #ifdef CLGL_INTEROP
nuclear@39 110 prog->set_arg_texture(KARG_FRAMEBUFFER, ARG_WR, tex);
nuclear@41 111 #else
nuclear@41 112 prog->set_arg_image(KARG_FRAMEBUFFER, ARG_WR, xsz, ysz);
nuclear@41 113 #endif
nuclear@12 114 prog->set_arg_buffer(KARG_RENDER_INFO, ARG_RD, sizeof rinf, &rinf);
John@14 115 prog->set_arg_buffer(KARG_FACES, ARG_RD, rinf.num_faces * sizeof(Face), faces);
John@14 116 prog->set_arg_buffer(KARG_MATLIB, ARG_RD, scn->get_num_materials() * sizeof(Material), scn->get_materials());
nuclear@12 117 prog->set_arg_buffer(KARG_LIGHTS, ARG_RD, sizeof lightlist, lightlist);
nuclear@12 118 prog->set_arg_buffer(KARG_PRIM_RAYS, ARG_RD, xsz * ysz * sizeof *prim_rays, prim_rays);
nuclear@12 119 prog->set_arg_buffer(KARG_XFORM, ARG_RD, 16 * sizeof(float));
nuclear@12 120 prog->set_arg_buffer(KARG_INVTRANS_XFORM, ARG_RD, 16 * sizeof(float));
nuclear@43 121 //prog->set_arg_buffer(KARG_KDTREE, ARG_RD, scn->get_num_kdnodes() * sizeof *kdbuf, kdbuf);
nuclear@43 122 prog->set_arg_image(KARG_KDTREE, ARG_RD, kdimg_xsz, kdimg_ysz, kdimg_pixels);
nuclear@43 123
nuclear@43 124 delete [] kdimg_pixels;
nuclear@43 125
nuclear@12 126
John@14 127 if(prog->get_num_args() < NUM_KERNEL_ARGS) {
John@14 128 return false;
John@14 129 }
John@14 130
nuclear@45 131 const char *opt = "-Isrc -cl-mad-enable -cl-single-precision-constant -cl-fast-relaxed-math";
nuclear@45 132 if(!prog->build(opt)) {
nuclear@16 133 return false;
nuclear@16 134 }
nuclear@16 135
nuclear@12 136 delete [] prim_rays;
nuclear@2 137
nuclear@3 138 global_size = xsz * ysz;
nuclear@3 139 return true;
nuclear@3 140 }
nuclear@3 141
nuclear@3 142 void destroy_renderer()
nuclear@3 143 {
nuclear@3 144 delete prog;
nuclear@43 145
nuclear@43 146 printf("rendertime mean: %ld msec\n", timing_sample_sum / num_timing_samples);
nuclear@3 147 }
nuclear@3 148
nuclear@3 149 bool render()
nuclear@3 150 {
nuclear@39 151 // XXX do we need to call glFinish ?
nuclear@39 152
nuclear@32 153 long tm0 = get_msec();
nuclear@32 154
nuclear@40 155 #ifdef CLGL_INTEROP
nuclear@39 156 cl_event ev;
nuclear@39 157 CLMemBuffer *texbuf = prog->get_arg_buffer(KARG_FRAMEBUFFER);
nuclear@39 158
nuclear@39 159 if(!acquire_gl_object(texbuf, &ev)) {
nuclear@39 160 return false;
nuclear@39 161 }
nuclear@39 162
nuclear@39 163 // make sure that we will wait for the acquire to finish before running
nuclear@39 164 prog->set_wait_event(ev);
nuclear@40 165 #endif
nuclear@39 166
nuclear@3 167 if(!prog->run(1, global_size)) {
nuclear@3 168 return false;
nuclear@0 169 }
John@15 170
nuclear@40 171 #ifdef CLGL_INTEROP
nuclear@39 172 if(!release_gl_object(texbuf, &ev)) {
nuclear@39 173 return false;
nuclear@39 174 }
nuclear@39 175 clWaitForEvents(1, &ev);
nuclear@40 176 #endif
nuclear@39 177
nuclear@40 178 #ifndef CLGL_INTEROP
nuclear@40 179 /* if we don't compile in CL/GL interoperability support, we need
nuclear@40 180 * to copy the output buffer to the OpenGL texture used to displaying
nuclear@40 181 * the image.
nuclear@40 182 */
nuclear@13 183 CLMemBuffer *mbuf = prog->get_arg_buffer(KARG_FRAMEBUFFER);
nuclear@12 184 void *fb = map_mem_buffer(mbuf, MAP_RD);
nuclear@13 185 if(!fb) {
nuclear@13 186 fprintf(stderr, "FAILED\n");
nuclear@13 187 return false;
nuclear@13 188 }
nuclear@13 189
nuclear@12 190 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rinf.xsz, rinf.ysz, GL_RGBA, GL_FLOAT, fb);
nuclear@2 191 unmap_mem_buffer(mbuf);
nuclear@40 192 #endif
nuclear@32 193
nuclear@43 194 long msec = get_msec() - tm0;
nuclear@43 195 timing_sample_sum += msec;
nuclear@43 196 num_timing_samples++;
nuclear@43 197
John@50 198 if(dbg_frame_time) {
John@50 199 printf("rendered in %ld msec\n", msec);
John@50 200 }
nuclear@3 201 return true;
nuclear@0 202 }
nuclear@2 203
nuclear@27 204 #define MIN(a, b) ((a) < (b) ? (a) : (b))
nuclear@21 205 static void dbg_set_gl_material(Material *mat)
nuclear@21 206 {
nuclear@21 207 static Material def_mat = {{0.7, 0.7, 0.7, 1}, {0, 0, 0, 0}, 0, 0, 0};
nuclear@21 208
nuclear@21 209 if(!mat) mat = &def_mat;
nuclear@21 210
nuclear@21 211 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat->kd);
nuclear@21 212 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat->ks);
nuclear@27 213 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, MIN(mat->spow, 128.0f));
nuclear@21 214 }
nuclear@21 215
nuclear@27 216 void dbg_render_gl(Scene *scn, bool show_tree, bool show_obj)
nuclear@8 217 {
nuclear@22 218 glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_LIGHTING_BIT);
nuclear@8 219
nuclear@21 220 for(int i=0; i<rinf.num_lights; i++) {
nuclear@21 221 float lpos[4];
nuclear@21 222
nuclear@21 223 memcpy(lpos, lightlist[i].pos, sizeof lpos);
nuclear@21 224 lpos[3] = 1.0;
nuclear@21 225
nuclear@21 226 glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos);
nuclear@21 227 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lightlist[i].color);
nuclear@22 228 glEnable(GL_LIGHT0 + i);
nuclear@21 229 }
nuclear@21 230
nuclear@12 231 glDisable(GL_TEXTURE_2D);
nuclear@12 232 glEnable(GL_DEPTH_TEST);
John@15 233 glEnable(GL_LIGHTING);
nuclear@12 234
nuclear@12 235 glMatrixMode(GL_PROJECTION);
nuclear@12 236 glPushMatrix();
nuclear@12 237 glLoadIdentity();
nuclear@12 238 gluPerspective(45.0, (float)rinf.xsz / (float)rinf.ysz, 0.5, 1000.0);
nuclear@12 239
nuclear@27 240 if(show_obj) {
nuclear@27 241 Material *materials = scn->get_materials();
John@14 242
nuclear@27 243 int num_faces = scn->get_num_faces();
nuclear@27 244 int cur_mat = -1;
nuclear@21 245
nuclear@27 246 for(int i=0; i<num_faces; i++) {
nuclear@27 247 if(faces[i].matid != cur_mat) {
nuclear@27 248 if(cur_mat != -1) {
nuclear@27 249 glEnd();
nuclear@27 250 }
nuclear@27 251 dbg_set_gl_material(materials ? materials + faces[i].matid : 0);
nuclear@27 252 cur_mat = faces[i].matid;
nuclear@27 253 glBegin(GL_TRIANGLES);
nuclear@21 254 }
nuclear@27 255
nuclear@27 256 for(int j=0; j<3; j++) {
nuclear@27 257 glNormal3fv(faces[i].v[j].normal);
nuclear@27 258 glVertex3fv(faces[i].v[j].pos);
nuclear@27 259 }
John@14 260 }
nuclear@27 261 glEnd();
nuclear@27 262 }
nuclear@12 263
nuclear@27 264 if(show_tree) {
nuclear@27 265 scn->draw_kdtree();
nuclear@12 266 }
nuclear@12 267
nuclear@12 268 glPopMatrix();
nuclear@12 269 glPopAttrib();
nuclear@22 270
nuclear@22 271 assert(glGetError() == GL_NO_ERROR);
nuclear@12 272 }
nuclear@12 273
nuclear@12 274 void set_xform(float *matrix, float *invtrans)
nuclear@12 275 {
nuclear@12 276 CLMemBuffer *mbuf_xform = prog->get_arg_buffer(KARG_XFORM);
nuclear@12 277 CLMemBuffer *mbuf_invtrans = prog->get_arg_buffer(KARG_INVTRANS_XFORM);
nuclear@12 278 assert(mbuf_xform && mbuf_invtrans);
nuclear@12 279
nuclear@12 280 float *mem = (float*)map_mem_buffer(mbuf_xform, MAP_WR);
nuclear@12 281 memcpy(mem, matrix, 16 * sizeof *mem);
nuclear@12 282 unmap_mem_buffer(mbuf_xform);
nuclear@12 283
nuclear@12 284 mem = (float*)map_mem_buffer(mbuf_invtrans, MAP_WR);
nuclear@12 285 memcpy(mem, invtrans, 16 * sizeof *mem);
nuclear@12 286 unmap_mem_buffer(mbuf_invtrans);
nuclear@8 287 }
nuclear@8 288
nuclear@47 289 void set_render_option(int opt, bool val)
nuclear@47 290 {
nuclear@47 291 switch(opt) {
nuclear@47 292 case ROPT_ITER:
nuclear@47 293 case ROPT_REFL:
nuclear@47 294 rinf.max_iter = val ? saved_iter_val : 0;
nuclear@47 295 break;
nuclear@47 296
nuclear@47 297 case ROPT_SHAD:
nuclear@47 298 rinf.cast_shadows = val;
nuclear@47 299 break;
nuclear@47 300
nuclear@47 301 default:
nuclear@47 302 return;
nuclear@47 303 }
nuclear@47 304
nuclear@47 305 update_render_info();
nuclear@47 306 }
nuclear@47 307
nuclear@47 308 void set_render_option(int opt, int val)
nuclear@47 309 {
nuclear@47 310 switch(opt) {
nuclear@47 311 case ROPT_ITER:
nuclear@47 312 rinf.max_iter = saved_iter_val = val;
nuclear@47 313 break;
nuclear@47 314
nuclear@47 315 case ROPT_SHAD:
nuclear@47 316 rinf.cast_shadows = val;
nuclear@47 317 break;
nuclear@47 318
nuclear@47 319 case ROPT_REFL:
nuclear@47 320 rinf.max_iter = val ? saved_iter_val : 0;
nuclear@47 321 break;
nuclear@47 322
nuclear@47 323 default:
nuclear@47 324 return;
nuclear@47 325 }
nuclear@47 326
nuclear@47 327 update_render_info();
nuclear@47 328 }
nuclear@47 329
nuclear@47 330 void set_render_option(int opt, float val)
nuclear@47 331 {
nuclear@47 332 set_render_option(opt, (int)val);
nuclear@47 333 }
nuclear@47 334
nuclear@47 335 bool get_render_option_bool(int opt)
nuclear@47 336 {
nuclear@47 337 switch(opt) {
nuclear@47 338 case ROPT_ITER:
nuclear@47 339 return rinf.max_iter;
nuclear@47 340 case ROPT_SHAD:
nuclear@47 341 return rinf.cast_shadows;
nuclear@47 342 case ROPT_REFL:
nuclear@47 343 return rinf.max_iter == saved_iter_val;
nuclear@47 344 default:
nuclear@47 345 break;
nuclear@47 346 }
nuclear@47 347 return false;
nuclear@47 348 }
nuclear@47 349
nuclear@47 350 int get_render_option_int(int opt)
nuclear@47 351 {
nuclear@47 352 switch(opt) {
nuclear@47 353 case ROPT_ITER:
nuclear@47 354 return rinf.max_iter;
nuclear@47 355 case ROPT_SHAD:
nuclear@47 356 return rinf.cast_shadows ? 1 : 0;
nuclear@47 357 case ROPT_REFL:
nuclear@47 358 return rinf.max_iter == saved_iter_val ? 1 : 0;
nuclear@47 359 default:
nuclear@47 360 break;
nuclear@47 361 }
nuclear@47 362 return -1;
nuclear@47 363 }
nuclear@47 364
nuclear@47 365 float get_render_option_float(int opt)
nuclear@47 366 {
nuclear@47 367 return (float)get_render_option_int(opt);
nuclear@47 368 }
nuclear@47 369
nuclear@47 370 static void update_render_info()
nuclear@47 371 {
nuclear@47 372 if(!prog) {
nuclear@47 373 return;
nuclear@47 374 }
nuclear@47 375
nuclear@47 376 CLMemBuffer *mbuf = prog->get_arg_buffer(KARG_RENDER_INFO);
nuclear@47 377 assert(mbuf);
nuclear@47 378
nuclear@47 379 RendInfo *rinf_ptr = (RendInfo*)map_mem_buffer(mbuf, MAP_WR);
nuclear@47 380 *rinf_ptr = rinf;
nuclear@47 381 unmap_mem_buffer(mbuf);
nuclear@47 382 }
nuclear@47 383
nuclear@3 384 static Ray get_primary_ray(int x, int y, int w, int h, float vfov_deg)
nuclear@2 385 {
nuclear@2 386 float vfov = M_PI * vfov_deg / 180.0;
nuclear@2 387 float aspect = (float)w / (float)h;
nuclear@2 388
nuclear@2 389 float ysz = 2.0;
nuclear@2 390 float xsz = aspect * ysz;
nuclear@2 391
nuclear@2 392 float px = ((float)x / (float)w) * xsz - xsz / 2.0;
nuclear@2 393 float py = 1.0 - ((float)y / (float)h) * ysz;
nuclear@2 394 float pz = 1.0 / tan(0.5 * vfov);
nuclear@2 395
nuclear@43 396 float mag = sqrt(px * px + py * py + pz * pz);
nuclear@43 397
nuclear@45 398 px = px * RAY_MAG / mag;
nuclear@45 399 py = py * RAY_MAG / mag;
nuclear@45 400 pz = pz * RAY_MAG / mag;
nuclear@2 401
nuclear@18 402 Ray ray = {{0, 0, 0, 1}, {px, py, -pz, 1}};
nuclear@2 403 return ray;
nuclear@2 404 }
nuclear@43 405
nuclear@43 406 static float *create_kdimage(const KDNodeGPU *kdtree, int num_nodes, int *xsz_ret, int *ysz_ret)
nuclear@43 407 {
nuclear@45 408 int ysz = MIN(num_nodes, KDIMG_MAX_HEIGHT);
nuclear@45 409 int columns = (num_nodes - 1) / KDIMG_MAX_HEIGHT + 1;
nuclear@45 410 int xsz = KDIMG_NODE_WIDTH * columns;
nuclear@43 411
nuclear@43 412 printf("creating kdtree image %dx%d (%d nodes)\n", xsz, ysz, num_nodes);
nuclear@43 413
nuclear@43 414 float *img = new float[4 * xsz * ysz];
nuclear@43 415 memset(img, 0, 4 * xsz * ysz * sizeof *img);
nuclear@43 416
nuclear@43 417 for(int i=0; i<num_nodes; i++) {
nuclear@45 418 int x = KDIMG_NODE_WIDTH * (i / KDIMG_MAX_HEIGHT);
nuclear@45 419 int y = i % KDIMG_MAX_HEIGHT;
nuclear@45 420
nuclear@45 421 float *ptr = img + (y * xsz + x) * 4;
nuclear@43 422
nuclear@43 423 *ptr++ = kdtree[i].aabb.min[0];
nuclear@43 424 *ptr++ = kdtree[i].aabb.min[1];
nuclear@43 425 *ptr++ = kdtree[i].aabb.min[2];
nuclear@43 426 *ptr++ = 0.0;
nuclear@43 427
nuclear@43 428 *ptr++ = kdtree[i].aabb.max[0];
nuclear@43 429 *ptr++ = kdtree[i].aabb.max[1];
nuclear@43 430 *ptr++ = kdtree[i].aabb.max[2];
nuclear@43 431 *ptr++ = 0.0;
nuclear@43 432
nuclear@43 433 for(int j=0; j<MAX_NODE_FACES; j++) {
nuclear@43 434 *ptr++ = j < kdtree[i].num_faces ? (float)kdtree[i].face_idx[j] : 0.0f;
nuclear@43 435 }
nuclear@43 436
nuclear@43 437 *ptr++ = (float)kdtree[i].num_faces;
nuclear@43 438 *ptr++ = (float)kdtree[i].left;
nuclear@43 439 *ptr++ = (float)kdtree[i].right;
nuclear@43 440 *ptr++ = 0.0;
nuclear@43 441 }
nuclear@43 442
nuclear@43 443 if(xsz_ret) *xsz_ret = xsz;
nuclear@43 444 if(ysz_ret) *ysz_ret = ysz;
nuclear@43 445 return img;
nuclear@43 446 }