clray

view src/rt.cc @ 54:6a30f27fa1e6

separated the OpenGL visualization and added a CPU raytracing mode
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 10 Sep 2010 16:47:00 +0100
parents 54a96b738afe
children df239a52a091
line source
1 #include <stdio.h>
2 #include <string.h>
3 #include <math.h>
4 #include <assert.h>
5 #include "rt.h"
6 #include "ogl.h"
7 #include "ocl.h"
8 #include "scene.h"
9 #include "timer.h"
10 #include "common.h"
12 // kernel arguments
13 enum {
14 KARG_FRAMEBUFFER,
15 KARG_RENDER_INFO,
16 KARG_FACES,
17 KARG_MATLIB,
18 KARG_LIGHTS,
19 KARG_PRIM_RAYS,
20 KARG_XFORM,
21 KARG_INVTRANS_XFORM,
22 KARG_KDTREE,
24 NUM_KERNEL_ARGS
25 };
27 static void update_render_info();
28 static Ray get_primary_ray(int x, int y, int w, int h, float vfov_deg);
29 static float *create_kdimage(const KDNodeGPU *kdtree, int num_nodes, int *xsz_ret, int *ysz_ret);
31 static Face *faces;
32 static Ray *prim_rays;
33 static CLProgram *prog;
34 static int global_size;
37 static RendInfo rinf;
38 static int saved_iter_val;
40 static long timing_sample_sum;
41 static long num_timing_samples;
43 extern bool dbg_frame_time;
46 bool init_renderer(int xsz, int ysz, Scene *scn, unsigned int tex)
47 {
48 // render info
49 rinf.ambient[0] = rinf.ambient[1] = rinf.ambient[2] = 0.0;
50 rinf.ambient[3] = 0.0;
52 rinf.xsz = xsz;
53 rinf.ysz = ysz;
54 rinf.num_faces = scn->get_num_faces();
55 rinf.num_lights = scn->get_num_lights();
56 rinf.max_iter = saved_iter_val = 6;
57 rinf.cast_shadows = true;
59 /* calculate primary rays */
60 prim_rays = new Ray[xsz * ysz];
62 for(int i=0; i<ysz; i++) {
63 for(int j=0; j<xsz; j++) {
64 prim_rays[i * xsz + j] = get_primary_ray(j, i, xsz, ysz, 45.0);
65 }
66 }
67 dbg_set_primary_rays(prim_rays); // give them to the debug renderer
69 /* setup opencl */
70 prog = new CLProgram("render");
71 if(!prog->load("src/rt.cl")) {
72 return false;
73 }
75 if(!(faces = (Face*)scn->get_face_buffer())) {
76 fprintf(stderr, "failed to create face buffer\n");
77 return false;
78 }
80 const KDNodeGPU *kdbuf = scn->get_kdtree_buffer();
81 if(!kdbuf) {
82 fprintf(stderr, "failed to create kdtree buffer\n");
83 return false;
84 }
86 int kdimg_xsz, kdimg_ysz;
87 float *kdimg_pixels = create_kdimage(kdbuf, scn->get_num_kdnodes(), &kdimg_xsz, &kdimg_ysz);
89 /* setup argument buffers */
90 #ifdef CLGL_INTEROP
91 prog->set_arg_texture(KARG_FRAMEBUFFER, ARG_WR, tex);
92 #else
93 prog->set_arg_image(KARG_FRAMEBUFFER, ARG_WR, xsz, ysz);
94 #endif
95 prog->set_arg_buffer(KARG_RENDER_INFO, ARG_RD, sizeof rinf, &rinf);
96 prog->set_arg_buffer(KARG_FACES, ARG_RD, rinf.num_faces * sizeof(Face), faces);
97 prog->set_arg_buffer(KARG_MATLIB, ARG_RD, scn->get_num_materials() * sizeof(Material), scn->get_materials());
98 prog->set_arg_buffer(KARG_LIGHTS, ARG_RD, scn->get_num_lights() * sizeof(Light), scn->get_lights());
99 prog->set_arg_buffer(KARG_PRIM_RAYS, ARG_RD, xsz * ysz * sizeof *prim_rays, prim_rays);
100 prog->set_arg_buffer(KARG_XFORM, ARG_RD, 16 * sizeof(float));
101 prog->set_arg_buffer(KARG_INVTRANS_XFORM, ARG_RD, 16 * sizeof(float));
102 //prog->set_arg_buffer(KARG_KDTREE, ARG_RD, scn->get_num_kdnodes() * sizeof *kdbuf, kdbuf);
103 prog->set_arg_image(KARG_KDTREE, ARG_RD, kdimg_xsz, kdimg_ysz, kdimg_pixels);
105 delete [] kdimg_pixels;
108 if(prog->get_num_args() < NUM_KERNEL_ARGS) {
109 return false;
110 }
112 const char *opt = "-Isrc -cl-mad-enable -cl-single-precision-constant -cl-fast-relaxed-math";
113 if(!prog->build(opt)) {
114 return false;
115 }
117 //delete [] prim_rays; now dbg_renderer handles them
119 global_size = xsz * ysz;
122 init_dbg_renderer(xsz, ysz, scn, tex);
123 return true;
124 }
126 void destroy_renderer()
127 {
128 delete prog;
130 destroy_dbg_renderer();
132 if(num_timing_samples) {
133 printf("rendertime mean: %ld msec\n", timing_sample_sum / num_timing_samples);
134 }
135 }
137 bool render()
138 {
139 // XXX do we need to call glFinish ?
141 long tm0 = get_msec();
143 #ifdef CLGL_INTEROP
144 cl_event ev;
145 CLMemBuffer *texbuf = prog->get_arg_buffer(KARG_FRAMEBUFFER);
147 if(!acquire_gl_object(texbuf, &ev)) {
148 return false;
149 }
151 // make sure that we will wait for the acquire to finish before running
152 prog->set_wait_event(ev);
153 #endif
155 if(!prog->run(1, global_size)) {
156 return false;
157 }
159 #ifdef CLGL_INTEROP
160 if(!release_gl_object(texbuf, &ev)) {
161 return false;
162 }
163 clWaitForEvents(1, &ev);
164 #endif
166 #ifndef CLGL_INTEROP
167 /* if we don't compile in CL/GL interoperability support, we need
168 * to copy the output buffer to the OpenGL texture used to displaying
169 * the image.
170 */
171 CLMemBuffer *mbuf = prog->get_arg_buffer(KARG_FRAMEBUFFER);
172 void *fb = map_mem_buffer(mbuf, MAP_RD);
173 if(!fb) {
174 fprintf(stderr, "FAILED\n");
175 return false;
176 }
178 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rinf.xsz, rinf.ysz, GL_RGBA, GL_FLOAT, fb);
179 unmap_mem_buffer(mbuf);
180 #endif
182 long msec = get_msec() - tm0;
183 timing_sample_sum += msec;
184 num_timing_samples++;
186 if(dbg_frame_time) {
187 printf("rendered in %ld msec\n", msec);
188 }
189 return true;
190 }
193 void set_xform(float *matrix, float *invtrans)
194 {
195 CLMemBuffer *mbuf_xform = prog->get_arg_buffer(KARG_XFORM);
196 CLMemBuffer *mbuf_invtrans = prog->get_arg_buffer(KARG_INVTRANS_XFORM);
197 assert(mbuf_xform && mbuf_invtrans);
199 float *mem = (float*)map_mem_buffer(mbuf_xform, MAP_WR);
200 memcpy(mem, matrix, 16 * sizeof *mem);
201 unmap_mem_buffer(mbuf_xform);
203 mem = (float*)map_mem_buffer(mbuf_invtrans, MAP_WR);
204 memcpy(mem, invtrans, 16 * sizeof *mem);
205 unmap_mem_buffer(mbuf_invtrans);
206 }
209 const RendInfo *get_render_info()
210 {
211 return &rinf;
212 }
214 void set_render_option(int opt, bool val)
215 {
216 switch(opt) {
217 case ROPT_ITER:
218 case ROPT_REFL:
219 rinf.max_iter = val ? saved_iter_val : 0;
220 break;
222 case ROPT_SHAD:
223 rinf.cast_shadows = val;
224 break;
226 default:
227 return;
228 }
230 update_render_info();
231 }
233 void set_render_option(int opt, int val)
234 {
235 switch(opt) {
236 case ROPT_ITER:
237 rinf.max_iter = saved_iter_val = val;
238 break;
240 case ROPT_SHAD:
241 rinf.cast_shadows = val;
242 break;
244 case ROPT_REFL:
245 rinf.max_iter = val ? saved_iter_val : 0;
246 break;
248 default:
249 return;
250 }
252 update_render_info();
253 }
255 void set_render_option(int opt, float val)
256 {
257 set_render_option(opt, (int)val);
258 }
260 bool get_render_option_bool(int opt)
261 {
262 switch(opt) {
263 case ROPT_ITER:
264 return rinf.max_iter;
265 case ROPT_SHAD:
266 return rinf.cast_shadows;
267 case ROPT_REFL:
268 return rinf.max_iter == saved_iter_val;
269 default:
270 break;
271 }
272 return false;
273 }
275 int get_render_option_int(int opt)
276 {
277 switch(opt) {
278 case ROPT_ITER:
279 return rinf.max_iter;
280 case ROPT_SHAD:
281 return rinf.cast_shadows ? 1 : 0;
282 case ROPT_REFL:
283 return rinf.max_iter == saved_iter_val ? 1 : 0;
284 default:
285 break;
286 }
287 return -1;
288 }
290 float get_render_option_float(int opt)
291 {
292 return (float)get_render_option_int(opt);
293 }
295 static void update_render_info()
296 {
297 if(!prog) {
298 return;
299 }
301 CLMemBuffer *mbuf = prog->get_arg_buffer(KARG_RENDER_INFO);
302 assert(mbuf);
304 RendInfo *rinf_ptr = (RendInfo*)map_mem_buffer(mbuf, MAP_WR);
305 *rinf_ptr = rinf;
306 unmap_mem_buffer(mbuf);
307 }
309 static Ray get_primary_ray(int x, int y, int w, int h, float vfov_deg)
310 {
311 float vfov = M_PI * vfov_deg / 180.0;
312 float aspect = (float)w / (float)h;
314 float ysz = 2.0;
315 float xsz = aspect * ysz;
317 float px = ((float)x / (float)w) * xsz - xsz / 2.0;
318 float py = 1.0 - ((float)y / (float)h) * ysz;
319 float pz = 1.0 / tan(0.5 * vfov);
321 float mag = sqrt(px * px + py * py + pz * pz);
323 px = px * RAY_MAG / mag;
324 py = py * RAY_MAG / mag;
325 pz = pz * RAY_MAG / mag;
327 Ray ray = {{0, 0, 0, 1}, {px, py, -pz, 1}};
328 return ray;
329 }
331 #define MIN(a, b) ((a) < (b) ? (a) : (b))
333 static float *create_kdimage(const KDNodeGPU *kdtree, int num_nodes, int *xsz_ret, int *ysz_ret)
334 {
335 int ysz = MIN(num_nodes, KDIMG_MAX_HEIGHT);
336 int columns = (num_nodes - 1) / KDIMG_MAX_HEIGHT + 1;
337 int xsz = KDIMG_NODE_WIDTH * columns;
339 printf("creating kdtree image %dx%d (%d nodes)\n", xsz, ysz, num_nodes);
341 float *img = new float[4 * xsz * ysz];
342 memset(img, 0, 4 * xsz * ysz * sizeof *img);
344 for(int i=0; i<num_nodes; i++) {
345 int x = KDIMG_NODE_WIDTH * (i / KDIMG_MAX_HEIGHT);
346 int y = i % KDIMG_MAX_HEIGHT;
348 float *ptr = img + (y * xsz + x) * 4;
350 *ptr++ = kdtree[i].aabb.min[0];
351 *ptr++ = kdtree[i].aabb.min[1];
352 *ptr++ = kdtree[i].aabb.min[2];
353 *ptr++ = 0.0;
355 *ptr++ = kdtree[i].aabb.max[0];
356 *ptr++ = kdtree[i].aabb.max[1];
357 *ptr++ = kdtree[i].aabb.max[2];
358 *ptr++ = 0.0;
360 for(int j=0; j<MAX_NODE_FACES; j++) {
361 *ptr++ = j < kdtree[i].num_faces ? (float)kdtree[i].face_idx[j] : 0.0f;
362 }
364 *ptr++ = (float)kdtree[i].num_faces;
365 *ptr++ = (float)kdtree[i].left;
366 *ptr++ = (float)kdtree[i].right;
367 *ptr++ = 0.0;
368 }
370 if(xsz_ret) *xsz_ret = xsz;
371 if(ysz_ret) *ysz_ret = ysz;
372 return img;
373 }