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