clray

changeset 39:980bc07be868

Implemented OpenGL/OpenCL interop, and removed the texture copy
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 27 Aug 2010 18:30:09 +0100
parents 4bcf78e572d6
children 1bcbb53b3505
files rt.cl src/clray.cc src/ocl.cc src/ocl.h src/rt.cc src/rt.h
diffstat 6 files changed, 208 insertions(+), 50 deletions(-) [+]
line diff
     1.1 --- a/rt.cl	Fri Aug 27 02:22:08 2010 +0100
     1.2 +++ b/rt.cl	Fri Aug 27 18:30:09 2010 +0100
     1.3 @@ -80,7 +80,8 @@
     1.4  float4 calc_bary(float4 pt, global const struct Face *face, float4 norm);
     1.5  float mean(float4 v);
     1.6  
     1.7 -kernel void render(global float4 *fb,
     1.8 +
     1.9 +kernel void render(write_only image2d_t fb,
    1.10  		global const struct RendInfo *rinf,
    1.11  		global const struct Face *faces,
    1.12  		global const struct Material *matlib,
    1.13 @@ -124,7 +125,14 @@
    1.14  		}
    1.15  	}
    1.16  
    1.17 -	fb[idx] = pixel;
    1.18 +	int img_x = get_image_width(fb);
    1.19 +
    1.20 +	int2 coord;
    1.21 +	coord.x = idx % img_x;
    1.22 +	coord.y = idx / img_x;
    1.23 +
    1.24 +	write_imagef(fb, coord, pixel);
    1.25 +	//fb[idx] = pixel;
    1.26  }
    1.27  
    1.28  float4 shade(struct Ray ray, struct Scene *scn, const struct SurfPoint *sp)
     2.1 --- a/src/clray.cc	Fri Aug 27 02:22:08 2010 +0100
     2.2 +++ b/src/clray.cc	Fri Aug 27 18:30:09 2010 +0100
     2.3 @@ -11,6 +11,7 @@
     2.4  #include "rt.h"
     2.5  #include "matrix.h"
     2.6  #include "scene.h"
     2.7 +#include "ocl.h"
     2.8  
     2.9  void cleanup();
    2.10  void disp();
    2.11 @@ -31,6 +32,7 @@
    2.12  static bool dbg_show_obj = true;
    2.13  
    2.14  static Scene scn;
    2.15 +static unsigned int tex;
    2.16  
    2.17  int main(int argc, char **argv)
    2.18  {
    2.19 @@ -102,11 +104,6 @@
    2.20  	glutMouseFunc(mouse);
    2.21  	glutMotionFunc(motion);
    2.22  
    2.23 -	if(!init_renderer(xsz, ysz, &scn)) {
    2.24 -		return 1;
    2.25 -	}
    2.26 -	atexit(cleanup);
    2.27 -
    2.28  	unsigned int *test_pattern = new unsigned int[xsz * ysz];
    2.29  	for(int i=0; i<ysz; i++) {
    2.30  		for(int j=0; j<xsz; j++) {
    2.31 @@ -114,15 +111,24 @@
    2.32  		}
    2.33  	}
    2.34  
    2.35 -	/*glGenTextures(1, &tex);
    2.36 -	glBindTexture(GL_TEXTURE_2D, tex);*/
    2.37 +	glGenTextures(1, &tex);
    2.38 +	glBindTexture(GL_TEXTURE_2D, tex);
    2.39  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    2.40  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    2.41  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    2.42  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    2.43 -	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F_ARB, xsz, ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, test_pattern);
    2.44 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, xsz, ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, test_pattern);
    2.45  	delete [] test_pattern;
    2.46  
    2.47 +	if(!init_opencl()) {
    2.48 +		return 1;
    2.49 +	}
    2.50 +
    2.51 +	if(!init_renderer(xsz, ysz, &scn, tex)) {
    2.52 +		return 1;
    2.53 +	}
    2.54 +	atexit(cleanup);
    2.55 +
    2.56  	glutMainLoop();
    2.57  	return 0;
    2.58  }
     3.1 --- a/src/ocl.cc	Fri Aug 27 02:22:08 2010 +0100
     3.2 +++ b/src/ocl.cc	Fri Aug 27 18:30:09 2010 +0100
     3.3 @@ -5,6 +5,7 @@
     3.4  #include <string.h>
     3.5  #include <stdarg.h>
     3.6  #include <errno.h>
     3.7 +#include <assert.h>
     3.8  #ifndef _MSC_VER
     3.9  #include <alloca.h>
    3.10  #else
    3.11 @@ -12,13 +13,14 @@
    3.12  #endif
    3.13  #include <sys/stat.h>
    3.14  #include "ocl.h"
    3.15 +#include "ogl.h"
    3.16  #include "ocl_errstr.h"
    3.17  
    3.18 +#if defined(unix) || defined(__unix__)
    3.19 +#include <X11/Xlib.h>
    3.20 +#include <GL/glx.h>
    3.21 +#endif
    3.22  
    3.23 -class InitCL {
    3.24 -public:
    3.25 -	InitCL();
    3.26 -};
    3.27  
    3.28  struct device_info {
    3.29  	cl_device_id id;
    3.30 @@ -33,7 +35,6 @@
    3.31  	unsigned long mem_size;
    3.32  };
    3.33  
    3.34 -static bool init_opencl(void);
    3.35  static int select_device(struct device_info *di, int (*devcmp)(struct device_info*, struct device_info*));
    3.36  static int get_dev_info(cl_device_id dev, struct device_info *di);
    3.37  static int devcmp(struct device_info *a, struct device_info *b);
    3.38 @@ -42,26 +43,36 @@
    3.39  static const char *clstrerror(int err);
    3.40  
    3.41  
    3.42 -static InitCL initcl;
    3.43  static cl_context ctx;
    3.44  static cl_command_queue cmdq;
    3.45  static device_info devinf;
    3.46  
    3.47 -InitCL::InitCL()
    3.48 -{
    3.49 -	if(!init_opencl()) {
    3.50 -		exit(0);
    3.51 -	}
    3.52 -}
    3.53 -
    3.54 -static bool init_opencl(void)
    3.55 +bool init_opencl()
    3.56  {
    3.57  	if(select_device(&devinf, devcmp) == -1) {
    3.58  		return false;
    3.59  	}
    3.60  
    3.61 +#if defined(__APPLE__)
    3.62 +#error "CL/GL context sharing not implemented on MacOSX yet"
    3.63 +#elif defined(unix) || defined(__unix__)
    3.64 +	Display *dpy = glXGetCurrentDisplay();
    3.65 +	GLXContext glctx = glXGetCurrentContext();
    3.66  
    3.67 -	if(!(ctx = clCreateContext(0, 1, &devinf.id, 0, 0, 0))) {
    3.68 +	assert(dpy && glctx);
    3.69 +
    3.70 +	cl_context_properties prop[] = {
    3.71 +		CL_GLX_DISPLAY_KHR, (cl_context_properties)dpy,
    3.72 +		CL_GL_CONTEXT_KHR, (cl_context_properties)glctx,
    3.73 +		0
    3.74 +	};
    3.75 +#elif defined(WIN32) || defined(__WIN32__)
    3.76 +#error "CL/GL context sharing not implemented on windows yet"
    3.77 +#else
    3.78 +#error "unknown or unsupported platform"
    3.79 +#endif
    3.80 +
    3.81 +	if(!(ctx = clCreateContext(prop, 1, &devinf.id, 0, 0, 0))) {
    3.82  		fprintf(stderr, "failed to create opencl context\n");
    3.83  		return false;
    3.84  	}
    3.85 @@ -94,6 +105,25 @@
    3.86  	mbuf->mem = mem;
    3.87  	mbuf->size = sz;
    3.88  	mbuf->ptr = 0;
    3.89 +	mbuf->tex = 0;
    3.90 +	return mbuf;
    3.91 +}
    3.92 +
    3.93 +CLMemBuffer *create_mem_buffer(int rdwr, unsigned int tex)
    3.94 +{
    3.95 +	int err;
    3.96 +	cl_mem mem;
    3.97 +
    3.98 +	if(!(mem = clCreateFromGLTexture2D(ctx, rdwr, GL_TEXTURE_2D, 0, tex, &err))) {
    3.99 +		fprintf(stderr, "failed to create memory buffer from GL texture %u: %s\n", tex, clstrerror(err));
   3.100 +		return 0;
   3.101 +	}
   3.102 +
   3.103 +	CLMemBuffer *mbuf = new CLMemBuffer;
   3.104 +	mbuf->mem = mem;
   3.105 +	mbuf->size = 0;
   3.106 +	mbuf->ptr = 0;
   3.107 +	mbuf->tex = tex;
   3.108  	return mbuf;
   3.109  }
   3.110  
   3.111 @@ -105,7 +135,7 @@
   3.112  	}
   3.113  }
   3.114  
   3.115 -void *map_mem_buffer(CLMemBuffer *mbuf, int rdwr)
   3.116 +void *map_mem_buffer(CLMemBuffer *mbuf, int rdwr, cl_event *ev)
   3.117  {
   3.118  	if(!mbuf) return 0;
   3.119  
   3.120 @@ -116,7 +146,7 @@
   3.121  #endif
   3.122  
   3.123  	int err;
   3.124 -	mbuf->ptr = clEnqueueMapBuffer(cmdq, mbuf->mem, 1, rdwr, 0, mbuf->size, 0, 0, 0, &err);
   3.125 +	mbuf->ptr = clEnqueueMapBuffer(cmdq, mbuf->mem, 1, rdwr, 0, mbuf->size, 0, 0, ev, &err);
   3.126  	if(!mbuf->ptr) {
   3.127  		fprintf(stderr, "failed to map buffer: %s\n", clstrerror(err));
   3.128  		return 0;
   3.129 @@ -124,31 +154,31 @@
   3.130  	return mbuf->ptr;
   3.131  }
   3.132  
   3.133 -void unmap_mem_buffer(CLMemBuffer *mbuf)
   3.134 +void unmap_mem_buffer(CLMemBuffer *mbuf, cl_event *ev)
   3.135  {
   3.136  	if(!mbuf || !mbuf->ptr) return;
   3.137 -	clEnqueueUnmapMemObject(cmdq, mbuf->mem, mbuf->ptr, 0, 0, 0);
   3.138 +	clEnqueueUnmapMemObject(cmdq, mbuf->mem, mbuf->ptr, 0, 0, ev);
   3.139  	mbuf->ptr = 0;
   3.140  }
   3.141  
   3.142 -bool write_mem_buffer(CLMemBuffer *mbuf, size_t sz, const void *src)
   3.143 +bool write_mem_buffer(CLMemBuffer *mbuf, size_t sz, const void *src, cl_event *ev)
   3.144  {
   3.145  	if(!mbuf) return false;
   3.146  
   3.147  	int err;
   3.148 -	if((err = clEnqueueWriteBuffer(cmdq, mbuf->mem, 1, 0, sz, src, 0, 0, 0)) != 0) {
   3.149 +	if((err = clEnqueueWriteBuffer(cmdq, mbuf->mem, 1, 0, sz, src, 0, 0, ev)) != 0) {
   3.150  		fprintf(stderr, "failed to write buffer: %s\n", clstrerror(err));
   3.151  		return false;
   3.152  	}
   3.153  	return true;
   3.154  }
   3.155  
   3.156 -bool read_mem_buffer(CLMemBuffer *mbuf, size_t sz, void *dest)
   3.157 +bool read_mem_buffer(CLMemBuffer *mbuf, size_t sz, void *dest, cl_event *ev)
   3.158  {
   3.159  	if(!mbuf) return false;
   3.160  
   3.161  	int err;
   3.162 -	if((err = clEnqueueReadBuffer(cmdq, mbuf->mem, 1, 0, sz, dest, 0, 0, 0)) != 0) {
   3.163 +	if((err = clEnqueueReadBuffer(cmdq, mbuf->mem, 1, 0, sz, dest, 0, 0, ev)) != 0) {
   3.164  		fprintf(stderr, "failed to read buffer: %s\n", clstrerror(err));
   3.165  		return false;
   3.166  	}
   3.167 @@ -156,6 +186,35 @@
   3.168  }
   3.169  
   3.170  
   3.171 +bool acquire_gl_object(CLMemBuffer *mbuf, cl_event *ev)
   3.172 +{
   3.173 +	if(!mbuf || !mbuf->tex) {
   3.174 +		return false;
   3.175 +	}
   3.176 +
   3.177 +	int err;
   3.178 +	if((err = clEnqueueAcquireGLObjects(cmdq, 1, &mbuf->mem, 0, 0, ev)) != 0) {
   3.179 +		fprintf(stderr, "failed to acquire gl object: %s\n", clstrerror(err));
   3.180 +		return false;
   3.181 +	}
   3.182 +	return true;
   3.183 +}
   3.184 +
   3.185 +bool release_gl_object(CLMemBuffer *mbuf, cl_event *ev)
   3.186 +{
   3.187 +	if(!mbuf || !mbuf->tex) {
   3.188 +		return false;
   3.189 +	}
   3.190 +
   3.191 +	int err;
   3.192 +	if((err = clEnqueueReleaseGLObjects(cmdq, 1, &mbuf->mem, 0, 0, ev)) != 0) {
   3.193 +		fprintf(stderr, "failed to release gl object: %s\n", clstrerror(err));
   3.194 +		return false;
   3.195 +	}
   3.196 +	return true;
   3.197 +}
   3.198 +
   3.199 +
   3.200  CLArg::CLArg()
   3.201  {
   3.202  	memset(this, 0, sizeof *this);
   3.203 @@ -169,10 +228,19 @@
   3.204  	this->kname = kname;
   3.205  	args.resize(16);
   3.206  	built = false;
   3.207 +
   3.208 +	wait_event = last_event = 0;
   3.209  }
   3.210  
   3.211  CLProgram::~CLProgram()
   3.212  {
   3.213 +	if(wait_event) {
   3.214 +		clReleaseEvent(wait_event);
   3.215 +	}
   3.216 +	if(last_event) {
   3.217 +		clReleaseEvent(last_event);
   3.218 +	}
   3.219 +
   3.220  	if(prog) {
   3.221  
   3.222  		clReleaseProgram(prog);
   3.223 @@ -248,8 +316,28 @@
   3.224  	printf("create argument %d buffer: %d bytes\n", idx, (int)sz);
   3.225  	CLMemBuffer *buf;
   3.226  
   3.227 -	if(sz <= 0 || !(buf = create_mem_buffer(rdwr, sz, ptr))) {
   3.228 -		fprintf(stderr, "invalid size while creating argument buffer %d: %d\n", idx, (int)sz);
   3.229 +	if(sz <= 0) {
   3.230 +		fprintf(stderr, "invalid size while creating argument buffer %d: %d bytes\n", idx, (int)sz);
   3.231 +		return false;
   3.232 +	}
   3.233 +	if(!(buf = create_mem_buffer(rdwr, sz, ptr))) {
   3.234 +		return false;
   3.235 +	}
   3.236 +
   3.237 +	if((int)args.size() <= idx) {
   3.238 +		args.resize(idx + 1);
   3.239 +	}
   3.240 +	args[idx].type = ARGTYPE_MEM_BUF;
   3.241 +	args[idx].v.mbuf = buf;
   3.242 +	return true;
   3.243 +}
   3.244 +
   3.245 +bool CLProgram::set_arg_texture(int idx, int rdwr, unsigned int tex)
   3.246 +{
   3.247 +	printf("create argument %d from texture %u\n", idx, tex);
   3.248 +	CLMemBuffer *buf;
   3.249 +
   3.250 +	if(!(buf = create_mem_buffer(rdwr, tex))) {
   3.251  		return false;
   3.252  	}
   3.253  
   3.254 @@ -284,7 +372,7 @@
   3.255  {
   3.256  	int err;
   3.257  
   3.258 -	if((err = clBuildProgram(prog, 0, 0, 0, 0, 0)) != 0) {
   3.259 +	if((err = clBuildProgram(prog, 0, 0, "-cl-mad-enable", 0, 0)) != 0) {
   3.260  		size_t sz;
   3.261  		clGetProgramBuildInfo(prog, devinf.id, CL_PROGRAM_BUILD_LOG, 0, 0, &sz);
   3.262  
   3.263 @@ -376,19 +464,37 @@
   3.264  	}
   3.265  	va_end(ap);
   3.266  
   3.267 +	if(last_event) {
   3.268 +		clReleaseEvent(last_event);
   3.269 +	}
   3.270 +
   3.271  	int err;
   3.272 -	cl_event event;
   3.273 -
   3.274 -	if((err = clEnqueueNDRangeKernel(cmdq, kernel, dim, 0, global_size, 0, 0, 0, &event)) != 0) {
   3.275 +	if((err = clEnqueueNDRangeKernel(cmdq, kernel, dim, 0, global_size, 0,
   3.276 +					wait_event ? 1 : 0, wait_event ? &wait_event : 0, &last_event)) != 0) {
   3.277  		fprintf(stderr, "error executing kernel: %s\n", clstrerror(err));
   3.278  		return false;
   3.279  	}
   3.280  
   3.281 -	clWaitForEvents(1, &event);
   3.282 -	clReleaseEvent(event);
   3.283 +	if(wait_event) {
   3.284 +		clReleaseEvent(wait_event);
   3.285 +		wait_event = 0;
   3.286 +	}
   3.287  	return true;
   3.288  }
   3.289  
   3.290 +void CLProgram::set_wait_event(cl_event ev)
   3.291 +{
   3.292 +	if(wait_event) {
   3.293 +		clReleaseEvent(wait_event);
   3.294 +	}
   3.295 +	wait_event = ev;
   3.296 +}
   3.297 +
   3.298 +cl_event CLProgram::get_last_event() const
   3.299 +{
   3.300 +	return last_event;
   3.301 +}
   3.302 +
   3.303  static int select_device(struct device_info *dev_inf, int (*devcmp)(struct device_info*, struct device_info*))
   3.304  {
   3.305  	unsigned int i, j, num_dev, num_plat, sel, ret;
     4.1 --- a/src/ocl.h	Fri Aug 27 02:22:08 2010 +0100
     4.2 +++ b/src/ocl.h	Fri Aug 27 18:30:09 2010 +0100
     4.3 @@ -5,6 +5,7 @@
     4.4  #include <string>
     4.5  #ifndef __APPLE__
     4.6  #include <CL/cl.h>
     4.7 +#include <CL/cl_gl.h>
     4.8  #else
     4.9  #include <OpenCL/opencl.h>
    4.10  #endif
    4.11 @@ -25,16 +26,24 @@
    4.12  	cl_mem mem;
    4.13  	size_t size;
    4.14  	void *ptr;
    4.15 +	unsigned int tex;
    4.16  };
    4.17  
    4.18 -CLMemBuffer *create_mem_buffer(int rdwr, size_t sz, const void *buf = 0);
    4.19 +
    4.20 +bool init_opencl();
    4.21 +
    4.22 +CLMemBuffer *create_mem_buffer(int rdwr, size_t sz, const void *buf);
    4.23 +CLMemBuffer *create_mem_buffer(int rdwr, unsigned int tex);
    4.24  void destroy_mem_buffer(CLMemBuffer *mbuf);
    4.25  
    4.26 -void *map_mem_buffer(CLMemBuffer *mbuf, int rdwr);
    4.27 -void unmap_mem_buffer(CLMemBuffer *mbuf);
    4.28 +void *map_mem_buffer(CLMemBuffer *mbuf, int rdwr, cl_event *ev = 0);
    4.29 +void unmap_mem_buffer(CLMemBuffer *mbuf, cl_event *ev = 0);
    4.30  
    4.31 -bool write_mem_buffer(CLMemBuffer *mbuf, size_t sz, const void *src);
    4.32 -bool read_mem_buffer(CLMemBuffer *mbuf, size_t sz, void *dest);
    4.33 +bool write_mem_buffer(CLMemBuffer *mbuf, size_t sz, const void *src, cl_event *ev = 0);
    4.34 +bool read_mem_buffer(CLMemBuffer *mbuf, size_t sz, void *dest, cl_event *ev = 0);
    4.35 +
    4.36 +bool acquire_gl_object(CLMemBuffer *mbuf, cl_event *ev = 0);
    4.37 +bool release_gl_object(CLMemBuffer *mbuf, cl_event *ev = 0);
    4.38  
    4.39  enum {
    4.40  	ARGTYPE_NONE,
    4.41 @@ -65,6 +74,8 @@
    4.42  	cl_kernel kernel;
    4.43  	std::vector<CLArg> args;
    4.44  	bool built;
    4.45 +	mutable cl_event wait_event;
    4.46 +	mutable cl_event last_event;
    4.47  
    4.48  public:
    4.49  	CLProgram(const char *kname);
    4.50 @@ -75,6 +86,7 @@
    4.51  	bool set_argi(int arg, int val);
    4.52  	bool set_argf(int arg, float val);
    4.53  	bool set_arg_buffer(int arg, int rdwr, size_t sz, const void *buf = 0);
    4.54 +	bool set_arg_texture(int arg, int rdwr, unsigned int tex);
    4.55  	CLMemBuffer *get_arg_buffer(int arg);
    4.56  	int get_num_args() const;
    4.57  
    4.58 @@ -82,6 +94,12 @@
    4.59  
    4.60  	bool run() const;
    4.61  	bool run(int dim, ...) const;
    4.62 +
    4.63 +	// sets an event that has to be completed before running the kernel
    4.64 +	void set_wait_event(cl_event ev);
    4.65 +
    4.66 +	// gets the last event so that we can wait for it to finish
    4.67 +	cl_event get_last_event() const;
    4.68  };
    4.69  
    4.70  #endif	/* OCL_H_ */
     5.1 --- a/src/rt.cc	Fri Aug 27 02:22:08 2010 +0100
     5.2 +++ b/src/rt.cc	Fri Aug 27 18:30:09 2010 +0100
     5.3 @@ -53,7 +53,7 @@
     5.4  static RendInfo rinf;
     5.5  
     5.6  
     5.7 -bool init_renderer(int xsz, int ysz, Scene *scn)
     5.8 +bool init_renderer(int xsz, int ysz, Scene *scn, unsigned int tex)
     5.9  {
    5.10  	// render info
    5.11  	rinf.ambient[0] = rinf.ambient[1] = rinf.ambient[2] = 0.0;
    5.12 @@ -94,7 +94,7 @@
    5.13  	// XXX now we can actually destroy the original kdtree and keep only the GPU version
    5.14  
    5.15  	/* setup argument buffers */
    5.16 -	prog->set_arg_buffer(KARG_FRAMEBUFFER, ARG_WR, xsz * ysz * 4 * sizeof(float));
    5.17 +	prog->set_arg_texture(KARG_FRAMEBUFFER, ARG_WR, tex);
    5.18  	prog->set_arg_buffer(KARG_RENDER_INFO, ARG_RD, sizeof rinf, &rinf);
    5.19  	prog->set_arg_buffer(KARG_FACES, ARG_RD, rinf.num_faces * sizeof(Face), faces);
    5.20  	prog->set_arg_buffer(KARG_MATLIB, ARG_RD, scn->get_num_materials() * sizeof(Material), scn->get_materials());
    5.21 @@ -125,13 +125,32 @@
    5.22  
    5.23  bool render()
    5.24  {
    5.25 +	// XXX do we need to call glFinish ?
    5.26 +
    5.27  	long tm0 = get_msec();
    5.28  
    5.29 +	cl_event ev;
    5.30 +	CLMemBuffer *texbuf = prog->get_arg_buffer(KARG_FRAMEBUFFER);
    5.31 +
    5.32 +	if(!acquire_gl_object(texbuf, &ev)) {
    5.33 +		return false;
    5.34 +	}
    5.35 +
    5.36 +	// make sure that we will wait for the acquire to finish before running
    5.37 +	prog->set_wait_event(ev);
    5.38 +
    5.39  	if(!prog->run(1, global_size)) {
    5.40  		return false;
    5.41  	}
    5.42  
    5.43 -	long tm_run = get_msec() - tm0;
    5.44 +	if(!release_gl_object(texbuf, &ev)) {
    5.45 +		return false;
    5.46 +	}
    5.47 +	clWaitForEvents(1, &ev);
    5.48 +
    5.49 +	printf("rendered in %ld msec\n", get_msec() - tm0);
    5.50 +
    5.51 +	/*long tm_run = get_msec() - tm0;
    5.52  
    5.53  	CLMemBuffer *mbuf = prog->get_arg_buffer(KARG_FRAMEBUFFER);
    5.54  	void *fb = map_mem_buffer(mbuf, MAP_RD);
    5.55 @@ -146,6 +165,7 @@
    5.56  	long tm_upd = get_msec() - tm0 - tm_run;
    5.57  
    5.58  	printf("render %ld msec (%ld run, %ld upd)\n", tm_run + tm_upd, tm_run, tm_upd);
    5.59 +	*/
    5.60  	return true;
    5.61  }
    5.62  
     6.1 --- a/src/rt.h	Fri Aug 27 02:22:08 2010 +0100
     6.2 +++ b/src/rt.h	Fri Aug 27 18:30:09 2010 +0100
     6.3 @@ -3,7 +3,7 @@
     6.4  
     6.5  #include "scene.h"
     6.6  
     6.7 -bool init_renderer(int xsz, int ysz, Scene *scn);
     6.8 +bool init_renderer(int xsz, int ysz, Scene *scn, unsigned int tex);
     6.9  void destroy_renderer();
    6.10  bool render();
    6.11  void set_xform(float *matrix, float *invtrans);