10 struct render_job *next;
14 int fb_width, fb_height, fb_size;
23 static void proc_render_job(void *cls);
24 static void done_render_job(void *cls);
25 static struct render_job *alloc_job(void);
26 static void free_job(struct render_job *job);
28 static struct thread_pool *tpool;
31 struct erb_rend *erb_create(void)
36 if(!(tpool = tpool_create(0))) {
37 fprintf(stderr, "erb_create: fatal error, failed to create thread pool!\n");
42 if(!(erb = calloc(1, sizeof *erb))) {
46 erb->vfov = cgm_deg_to_rad(50.0f);
51 void erb_destroy(struct erb_rend *erb)
58 int erb_allocframe(struct erb_rend *erb, int width, int height)
63 if(width == erb->fb_width && height == erb->fb_height) {
67 sz = width * height * 4 * sizeof *erb->fb_pixels;
68 if(!(newfb = malloc(sz))) {
69 fprintf(stderr, "erb_allocframe: failed to allocate %dx%d framebuffer\n", width, height);
75 erb->fb_pixels = newfb;
76 erb->fb_width = width;
77 erb->fb_height = height;
82 float *erb_getframe(struct erb_rend *erb)
84 return erb->fb_pixels;
87 void erb_setfov(struct erb_rend *erb, float vfov_deg)
89 erb->vfov = cgm_deg_to_rad(vfov_deg);
92 void erb_begin(struct erb_rend *erb)
94 memset(erb->fb_pixels, 0, erb->fb_size);
97 float *erb_end(struct erb_rend *erb)
99 int i, npix = erb->fb_width * erb->fb_height;
101 float *pptr = erb->fb_pixels;
103 for(i=0; i<npix; i++) {
115 return erb->fb_pixels;
118 void erb_set_done_callback(struct erb_rend *erb, erb_done_func donecb, void *cls)
120 erb->donecb = donecb;
124 void erb_queue_frame(struct erb_rend *erb, unsigned int job_id)
126 erb_queue_block(erb, job_id, 0, 0, erb->fb_width, erb->fb_height);
129 void erb_queue_block(struct erb_rend *erb, unsigned int job_id, int x, int y,
130 int width, int height)
132 struct render_job *job;
134 if(!(job = alloc_job())) {
135 fprintf(stderr, "erb_queue_block: failed to allocate rendering job\n");
144 job->rect.h = height;
146 tpool_enqueue(tpool, job, proc_render_job, done_render_job);
149 void erb_wait(struct erb_rend *erb)
151 /* XXX should we have a per-renderer instance thread pool, to wait only for our own jobs? */
155 void erb_primary_ray(struct erb_rend *erb, struct erb_ray *ray, int sample)
160 void erb_sample_ray(struct erb_rend *erb, struct erb_ray *ray, float *col)
163 col[0] = fmod(col[0] + 1.0f, 1.0f);
164 col[1] = col[2] = fmod(col[1] + 0.33f, 1.0f);
167 static void proc_render_job(void *cls)
170 struct erb_rend *erb;
171 struct render_job *job = cls;
176 fboffs = job->rect.y * erb->fb_width + job->rect.x;
177 fbptr = erb->fb_pixels + fboffs * 4;
179 for(i=0; i<job->rect.h; i++) {
180 for(j=0; j<job->rect.w; j++) {
181 erb_primary_ray(erb, &ray, (int)fbptr[3]);
182 erb_sample_ray(erb, &ray, fbptr);
185 fbptr += (erb->fb_width - job->rect.w) * 4;
189 static void done_render_job(void *cls)
191 struct erb_rend *erb;
192 struct render_job *job = cls;
196 erb->donecb(job->id, &job->rect, erb->donecls);
203 #define MAX_JOB_POOL 128
204 static struct render_job *job_pool;
205 static int num_free_jobs;
206 static pthread_mutex_t job_pool_lock = PTHREAD_MUTEX_INITIALIZER;
208 static struct render_job *alloc_job(void)
210 struct render_job *job;
212 pthread_mutex_lock(&job_pool_lock);
214 pthread_mutex_unlock(&job_pool_lock);
215 return malloc(sizeof *job);
219 job_pool = job->next;
221 pthread_mutex_unlock(&job_pool_lock);
225 static void free_job(struct render_job *job)
227 pthread_mutex_lock(&job_pool_lock);
228 if(num_free_jobs >= MAX_JOB_POOL) {
229 pthread_mutex_unlock(&job_pool_lock);
234 job->next = job_pool;
237 pthread_mutex_unlock(&job_pool_lock);