clray

view src/rt.cc @ 62:d9520da6b801

minor readme fix
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 28 Dec 2015 10:31:58 +0200
parents 3d13924b22e6
children
line source
1 #include <stdio.h>
2 #include <string.h>
3 #include <math.h>
4 #include <limits.h>
5 #include <assert.h>
6 #include "rt.h"
7 #include "ogl.h"
8 #include "ocl.h"
9 #include "scene.h"
10 #include "timer.h"
11 #include "common.h"
13 // kernel arguments
14 enum {
15 KARG_FRAMEBUFFER,
16 KARG_RENDER_INFO,
17 KARG_FACES,
18 KARG_MATLIB,
19 KARG_LIGHTS,
20 KARG_PRIM_RAYS,
21 KARG_XFORM,
22 KARG_INVTRANS_XFORM,
23 KARG_KDTREE,
25 NUM_KERNEL_ARGS
26 };
28 static void update_render_info();
29 static Ray get_primary_ray(int x, int y, int w, int h, float vfov_deg);
30 static float *create_kdimage(const KDNodeGPU *kdtree, int num_nodes, int *xsz_ret, int *ysz_ret);
32 static Face *faces;
33 static Ray *prim_rays;
34 static CLProgram *prog;
35 static int global_size;
38 static RendInfo rinf;
39 static RenderStats rstat;
40 static int saved_iter_val;
42 static long timing_sample_sum;
43 static long num_timing_samples;
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 long tm0 = get_msec();
141 // initialize render-stats
142 memset(&rstat, 0, sizeof rstat);
143 rstat.min_aabb_tests = rstat.min_triangle_tests = INT_MAX;
144 rstat.max_aabb_tests = rstat.max_triangle_tests = 0;
146 #ifdef CLGL_INTEROP
147 cl_event ev;
148 CLMemBuffer *texbuf = prog->get_arg_buffer(KARG_FRAMEBUFFER);
150 if(!acquire_gl_object(texbuf, &ev)) {
151 return false;
152 }
154 // make sure that we will wait for the acquire to finish before running
155 prog->set_wait_event(ev);
156 #endif
158 if(!prog->run(1, global_size)) {
159 return false;
160 }
162 #ifdef CLGL_INTEROP
163 if(!release_gl_object(texbuf, &ev)) {
164 return false;
165 }
166 clWaitForEvents(1, &ev);
167 #endif
169 #ifndef CLGL_INTEROP
170 /* if we don't compile in CL/GL interoperability support, we need
171 * to copy the output buffer to the OpenGL texture used to displaying
172 * the image.
173 */
174 CLMemBuffer *mbuf = prog->get_arg_buffer(KARG_FRAMEBUFFER);
175 void *fb = map_mem_buffer(mbuf, MAP_RD);
176 if(!fb) {
177 fprintf(stderr, "FAILED\n");
178 return false;
179 }
181 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rinf.xsz, rinf.ysz, GL_RGBA, GL_FLOAT, fb);
182 unmap_mem_buffer(mbuf);
183 #endif
185 finish_opencl();
187 rstat.render_time = get_msec() - tm0;
188 printf("FOO: %ld msec\n", rstat.render_time);
190 timing_sample_sum += rstat.render_time;
191 num_timing_samples++;
193 return true;
194 }
197 void set_xform(float *matrix, float *invtrans)
198 {
199 CLMemBuffer *mbuf_xform = prog->get_arg_buffer(KARG_XFORM);
200 CLMemBuffer *mbuf_invtrans = prog->get_arg_buffer(KARG_INVTRANS_XFORM);
201 assert(mbuf_xform && mbuf_invtrans);
203 float *mem = (float*)map_mem_buffer(mbuf_xform, MAP_WR);
204 memcpy(mem, matrix, 16 * sizeof *mem);
205 unmap_mem_buffer(mbuf_xform);
207 mem = (float*)map_mem_buffer(mbuf_invtrans, MAP_WR);
208 memcpy(mem, invtrans, 16 * sizeof *mem);
209 unmap_mem_buffer(mbuf_invtrans);
210 }
213 const RendInfo *get_render_info()
214 {
215 return &rinf;
216 }
218 const RenderStats *get_render_stats()
219 {
220 return &rstat;
221 }
223 void print_render_stats(FILE *fp)
224 {
225 fprintf(fp, "-- render stats --\n");
226 fprintf(fp, "> timing\n");
227 fprintf(fp, " render time (msec): %lu\n", rstat.render_time);
228 fprintf(fp, " tex update time (msec): %lu\n", rstat.tex_update_time);
229 fprintf(fp, "> counters\n");
230 fprintf(fp, " AABB tests: %d\n", rstat.aabb_tests);
231 fprintf(fp, " AABB tests per ray (min/max/avg): %d/%d/%f\n",
232 rstat.min_aabb_tests, rstat.max_aabb_tests, rstat.avg_aabb_tests);
233 fprintf(fp, " triangle tests: %d\n", rstat.triangle_tests);
234 fprintf(fp, " triangle tests per ray (min/max/avg): %d/%d/%f\n",
235 rstat.min_triangle_tests, rstat.max_triangle_tests, rstat.avg_triangle_tests);
236 fprintf(fp, " rays cast: %dp %dr %ds (sum: %d)\n", rstat.prim_rays,
237 rstat.refl_rays, rstat.shadow_rays, rstat.rays_cast);
238 fprintf(fp, " rays per second: %d\n", rstat.rays_per_sec);
239 fprintf(fp, " BRDF evaluations: %d\n", rstat.brdf_evals);
240 fputc('\n', fp);
241 }
243 void set_render_option(int opt, bool val)
244 {
245 switch(opt) {
246 case ROPT_ITER:
247 case ROPT_REFL:
248 rinf.max_iter = val ? saved_iter_val : 0;
249 break;
251 case ROPT_SHAD:
252 rinf.cast_shadows = val;
253 break;
255 default:
256 return;
257 }
259 update_render_info();
260 }
262 void set_render_option(int opt, int val)
263 {
264 switch(opt) {
265 case ROPT_ITER:
266 rinf.max_iter = saved_iter_val = val;
267 break;
269 case ROPT_SHAD:
270 rinf.cast_shadows = val;
271 break;
273 case ROPT_REFL:
274 rinf.max_iter = val ? saved_iter_val : 0;
275 break;
277 default:
278 return;
279 }
281 update_render_info();
282 }
284 void set_render_option(int opt, float val)
285 {
286 set_render_option(opt, (int)val);
287 }
289 bool get_render_option_bool(int opt)
290 {
291 switch(opt) {
292 case ROPT_ITER:
293 return rinf.max_iter;
294 case ROPT_SHAD:
295 return rinf.cast_shadows;
296 case ROPT_REFL:
297 return rinf.max_iter == saved_iter_val;
298 default:
299 break;
300 }
301 return false;
302 }
304 int get_render_option_int(int opt)
305 {
306 switch(opt) {
307 case ROPT_ITER:
308 return rinf.max_iter;
309 case ROPT_SHAD:
310 return rinf.cast_shadows ? 1 : 0;
311 case ROPT_REFL:
312 return rinf.max_iter == saved_iter_val ? 1 : 0;
313 default:
314 break;
315 }
316 return -1;
317 }
319 float get_render_option_float(int opt)
320 {
321 return (float)get_render_option_int(opt);
322 }
324 static void update_render_info()
325 {
326 if(!prog) {
327 return;
328 }
330 CLMemBuffer *mbuf = prog->get_arg_buffer(KARG_RENDER_INFO);
331 assert(mbuf);
333 RendInfo *rinf_ptr = (RendInfo*)map_mem_buffer(mbuf, MAP_WR);
334 *rinf_ptr = rinf;
335 unmap_mem_buffer(mbuf);
336 }
338 static Ray get_primary_ray(int x, int y, int w, int h, float vfov_deg)
339 {
340 float vfov = M_PI * vfov_deg / 180.0;
341 float aspect = (float)w / (float)h;
343 float ysz = 2.0;
344 float xsz = aspect * ysz;
346 float px = ((float)x / (float)w) * xsz - xsz / 2.0;
347 float py = 1.0 - ((float)y / (float)h) * ysz;
348 float pz = 1.0 / tan(0.5 * vfov);
350 float mag = sqrt(px * px + py * py + pz * pz);
352 px = px * RAY_MAG / mag;
353 py = py * RAY_MAG / mag;
354 pz = pz * RAY_MAG / mag;
356 Ray ray = {{0, 0, 0, 1}, {px, py, -pz, 1}};
357 return ray;
358 }
360 #define MIN(a, b) ((a) < (b) ? (a) : (b))
362 static float *create_kdimage(const KDNodeGPU *kdtree, int num_nodes, int *xsz_ret, int *ysz_ret)
363 {
364 int ysz = MIN(num_nodes, KDIMG_MAX_HEIGHT);
365 int columns = (num_nodes - 1) / KDIMG_MAX_HEIGHT + 1;
366 int xsz = KDIMG_NODE_WIDTH * columns;
368 printf("creating kdtree image %dx%d (%d nodes)\n", xsz, ysz, num_nodes);
370 float *img = new float[4 * xsz * ysz];
371 memset(img, 0, 4 * xsz * ysz * sizeof *img);
373 for(int i=0; i<num_nodes; i++) {
374 int x = KDIMG_NODE_WIDTH * (i / KDIMG_MAX_HEIGHT);
375 int y = i % KDIMG_MAX_HEIGHT;
377 float *ptr = img + (y * xsz + x) * 4;
379 *ptr++ = kdtree[i].aabb.min[0];
380 *ptr++ = kdtree[i].aabb.min[1];
381 *ptr++ = kdtree[i].aabb.min[2];
382 *ptr++ = 0.0;
384 *ptr++ = kdtree[i].aabb.max[0];
385 *ptr++ = kdtree[i].aabb.max[1];
386 *ptr++ = kdtree[i].aabb.max[2];
387 *ptr++ = 0.0;
389 for(int j=0; j<MAX_NODE_FACES; j++) {
390 *ptr++ = j < kdtree[i].num_faces ? (float)kdtree[i].face_idx[j] : 0.0f;
391 }
393 *ptr++ = (float)kdtree[i].num_faces;
394 *ptr++ = (float)kdtree[i].left;
395 *ptr++ = (float)kdtree[i].right;
396 *ptr++ = 0.0;
397 }
399 if(xsz_ret) *xsz_ret = xsz;
400 if(ysz_ret) *ysz_ret = ysz;
401 return img;
402 }