X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=liberebus%2Fsrc%2Ferebus.c;h=de8598fb845cd2c053595cdc05587d35238127ba;hb=7572b3ea92bec83c2a256eb1d6c1b0b77233c6b9;hp=da0763520ed8de6017418bdf3c66531562354ef3;hpb=c8b13dff969d8104c178d9362aa21cefb9d61fe8;p=erebus2020 diff --git a/liberebus/src/erebus.c b/liberebus/src/erebus.c index da07635..de8598f 100644 --- a/liberebus/src/erebus.c +++ b/liberebus/src/erebus.c @@ -1,10 +1,238 @@ +#include +#include #include "erebus.h" +#include "tpool.h" -int erb_init(void) +struct render_job { + struct erb_rend *erb; + unsigned int id; + struct erb_rect rect; + struct render_job *next; +}; + +struct erb_rend { + int fb_width, fb_height, fb_size; + float *fb_pixels; + + erb_done_func donecb; + void *donecls; + + float vfov; +}; + +static void proc_render_job(void *cls); +static void done_render_job(void *cls); +static struct render_job *alloc_job(void); +static void free_job(struct render_job *job); + +static struct thread_pool *tpool; + + +struct erb_rend *erb_create(void) { + struct erb_rend *erb; + + if(!tpool) { + if(!(tpool = tpool_create(0))) { + fprintf(stderr, "erb_create: fatal error, failed to create thread pool!\n"); + return 0; + } + } + + if(!(erb = calloc(1, sizeof *erb))) { + return 0; + } + + erb->vfov = cgm_deg_to_rad(50.0f); + + return erb; +} + +void erb_destroy(struct erb_rend *erb) +{ + if(!erb) return; + free(erb->fb_pixels); + free(erb); +} + +int erb_allocframe(struct erb_rend *erb, int width, int height) +{ + float *newfb; + int sz; + + if(width == erb->fb_width && height == erb->fb_height) { + return 0; + } + + sz = width * height * 4 * sizeof *erb->fb_pixels; + if(!(newfb = malloc(sz))) { + fprintf(stderr, "erb_allocframe: failed to allocate %dx%d framebuffer\n", width, height); + return -1; + } + + free(erb->fb_pixels); + + erb->fb_pixels = newfb; + erb->fb_width = width; + erb->fb_height = height; + erb->fb_size = sz; return 0; } -void erb_cleanup(void) +float *erb_getframe(struct erb_rend *erb) +{ + return erb->fb_pixels; +} + +void erb_setfov(struct erb_rend *erb, float vfov_deg) +{ + erb->vfov = cgm_deg_to_rad(vfov_deg); +} + +void erb_begin(struct erb_rend *erb) +{ + memset(erb->fb_pixels, 0, erb->fb_size); +} + +float *erb_end(struct erb_rend *erb) +{ + int i, npix = erb->fb_width * erb->fb_height; + float s; + float *pptr = erb->fb_pixels; + + for(i=0; i 1) { + s = 1.0f / pptr[3]; + *pptr++ *= s; + *pptr++ *= s; + *pptr++ *= s; + *pptr++ = 1.0f; + } else { + pptr += 4; + } + } + + return erb->fb_pixels; +} + +void erb_set_done_callback(struct erb_rend *erb, erb_done_func donecb, void *cls) +{ + erb->donecb = donecb; + erb->donecls = cls; +} + +void erb_queue_frame(struct erb_rend *erb, unsigned int job_id) +{ + erb_queue_block(erb, job_id, 0, 0, erb->fb_width, erb->fb_height); +} + +void erb_queue_block(struct erb_rend *erb, unsigned int job_id, int x, int y, + int width, int height) +{ + struct render_job *job; + + if(!(job = alloc_job())) { + fprintf(stderr, "erb_queue_block: failed to allocate rendering job\n"); + return; + } + + job->erb = erb; + job->id = job_id; + job->rect.x = x; + job->rect.y = y; + job->rect.w = width; + job->rect.h = height; + + tpool_enqueue(tpool, job, proc_render_job, done_render_job); +} + +void erb_wait(struct erb_rend *erb) +{ + /* XXX should we have a per-renderer instance thread pool, to wait only for our own jobs? */ + tpool_wait(tpool); +} + +void erb_primary_ray(struct erb_rend *erb, struct erb_ray *ray, int sample) +{ + /* TODO */ +} + +void erb_sample_ray(struct erb_rend *erb, struct erb_ray *ray, float *col) +{ + /* TODO */ + col[0] = fmod(col[0] + 1.0f, 1.0f); + col[1] = col[2] = fmod(col[1] + 0.33f, 1.0f); +} + +static void proc_render_job(void *cls) { + int i, j, fboffs; + struct erb_rend *erb; + struct render_job *job = cls; + float *fbptr; + struct erb_ray ray; + + erb = job->erb; + fboffs = job->rect.y * erb->fb_width + job->rect.x; + fbptr = erb->fb_pixels + fboffs * 4; + + for(i=0; irect.h; i++) { + for(j=0; jrect.w; j++) { + erb_primary_ray(erb, &ray, (int)fbptr[3]); + erb_sample_ray(erb, &ray, fbptr); + fbptr += 4; + } + fbptr += (erb->fb_width - job->rect.w) * 4; + } +} + +static void done_render_job(void *cls) +{ + struct erb_rend *erb; + struct render_job *job = cls; + + erb = job->erb; + if(erb->donecb) { + erb->donecb(job->id, &job->rect, erb->donecls); + } + + free_job(job); +} + + +#define MAX_JOB_POOL 128 +static struct render_job *job_pool; +static int num_free_jobs; +static pthread_mutex_t job_pool_lock = PTHREAD_MUTEX_INITIALIZER; + +static struct render_job *alloc_job(void) +{ + struct render_job *job; + + pthread_mutex_lock(&job_pool_lock); + if(!job_pool) { + pthread_mutex_unlock(&job_pool_lock); + return malloc(sizeof *job); + } + + job = job_pool; + job_pool = job->next; + num_free_jobs--; + pthread_mutex_unlock(&job_pool_lock); + return job; +} + +static void free_job(struct render_job *job) +{ + pthread_mutex_lock(&job_pool_lock); + if(num_free_jobs >= MAX_JOB_POOL) { + pthread_mutex_unlock(&job_pool_lock); + free(job); + return; + } + + job->next = job_pool; + job_pool = job; + num_free_jobs++; + pthread_mutex_unlock(&job_pool_lock); }