# HG changeset patch # User Tero Marttila # Date 1212970534 -10800 # Node ID 8e8b56b0e0f5e7bace65d2be7387a67765bd0ff1 # Parent 50995bbe442a4add67ea36316af02c2cbbade4aa a half-working render_slices. Render_multi is currently semantically broken/buggy, but it's time to go to sleep committer: Tero Marttila diff -r 50995bbe442a -r 8e8b56b0e0f5 Makefile --- a/Makefile Sun Jun 08 23:10:36 2008 +0300 +++ b/Makefile Mon Jun 09 03:15:34 2008 +0300 @@ -16,6 +16,7 @@ render_local.o: render_local.c render_local.h render_multi.o: render_multi.c render_multi.h render_remote.h render_mandelbrot.o: render_mandelbrot.c render_mandelbrot.h +render_slices.o: render_slices.c render_slices.h file_main.o: file_main.c node_main.o: node_main.c @@ -23,7 +24,7 @@ file_main: file_main.o common.o render.o render_raw.o render_png.o render_local.o render_mandelbrot.o node_main: node_main.o common.o render.o render_raw.o render_png.o render_local.o render_mandelbrot.o -web_main: web_main.o common.o http.o render.o render_png.o remote_node.o remote_pool.o render_remote.o render_multi.o +web_main: web_main.o common.o http.o render.o render_png.o remote_node.o remote_pool.o render_remote.o render_multi.o render_slices.o clean : rm *.o ${EXECS} diff -r 50995bbe442a -r 8e8b56b0e0f5 render_internal.h --- a/render_internal.h Sun Jun 08 23:10:36 2008 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -#ifdef RENDER_H -#error render_internal.h must be included before render.h -#endif - -#ifndef RENDER_INTERNAL_H -#define RENDER_INTERNAL_H - -#include "render.h" - -struct render { -/* render mode */ - int mode; - -/* image size */ - u_int32_t img_w; - u_int32_t img_h; - -/* mandelbrot region */ - double x1; - double y1; - double x2; - double y2; - -/* local rendering */ - unsigned char **local_rowbuf_addr; - render_ctx_row_cb local_row_fn; - -/* local I/O parameters */ - // if this is non-NULL, the image data is simply fwrite():en to this stream - FILE *io_stream; - - // called to handle the output data - render_ctx_write_cb io_write_fn; - - // called when the output data should be flushed - can be safely ignored if not needed - render_ctx_flush_cb io_flush_fn; - - // the callback argument for all of the above *_fn - void *cb_arg; -}; - -#endif /* RENDER_INTERNAL_H */ - diff -r 50995bbe442a -r 8e8b56b0e0f5 render_local.c --- a/render_local.c Sun Jun 08 23:10:36 2008 +0300 +++ b/render_local.c Mon Jun 09 03:15:34 2008 +0300 @@ -3,21 +3,27 @@ #include #include "common.h" -#include "render_internal.h" +#include "render_struct.h" #include "render_local.h" +#include "render_png_struct.h" #include "render_png.h" +#include "render_raw_struct.h" #include "render_raw.h" #include "render_mandelbrot.h" int render_local (struct render *render, double *duration) { unsigned char *rowbuf = NULL; - struct render_png *png_ctx = NULL; - struct render_raw *raw_ctx = NULL; + struct render_png png_ctx; + struct render_raw raw_ctx; clock_t t1, t2; if (duration) *duration = -1; + // ugh + memset(&png_ctx, 0, sizeof(png_ctx)); + memset(&raw_ctx, 0, sizeof(raw_ctx)); + // alloc the memory buffer if (!(rowbuf = malloc(render->img_w))) ERROR("malloc"); @@ -26,22 +32,22 @@ switch (render->mode) { case RENDER_PNG : // the render_png stuff - if (!(png_ctx = render_png_init(render))) + if (render_png_init(&png_ctx, render)) ERROR("render_png_init"); // set render_* to use the render_png - if (render_local_mem(render, &rowbuf, (int(*)(void *arg, unsigned char *)) &render_png_row, png_ctx)) + if (render_local_mem(render, &rowbuf, (int(*)(void *arg, unsigned char *)) &render_png_row, &png_ctx)) ERROR("render_local_mem"); break; case RENDER_RAW : // the render_raw stuff - if (!(raw_ctx = render_raw_init(render))) + if (render_raw_init(&raw_ctx, render)) ERROR("render_raw_init"); // set render_* to use the render_raw - if (render_local_mem(render, &rowbuf, (int(*)(void *arg, unsigned char *)) &render_raw_row, raw_ctx)) + if (render_local_mem(render, &rowbuf, (int(*)(void *arg, unsigned char *)) &render_raw_row, &raw_ctx)) ERROR("render_local_mem"); break; @@ -68,11 +74,8 @@ error: free(rowbuf); - if (png_ctx) - render_png_abort(png_ctx); - - if (raw_ctx) - render_raw_abort(raw_ctx); + render_png_deinit(&png_ctx); + render_raw_deinit(&raw_ctx); return -1; } diff -r 50995bbe442a -r 8e8b56b0e0f5 render_multi.c --- a/render_multi.c Sun Jun 08 23:10:36 2008 +0300 +++ b/render_multi.c Mon Jun 09 03:15:34 2008 +0300 @@ -4,11 +4,13 @@ #include #include "common.h" -#include "render_internal.h" +#include "render_struct.h" #include "render_multi.h" #include "render_remote.h" #include "remote_node.h" -#include "render_png.h" +#include "remote_pool.h" +#include "render_slices_struct.h" +#include "render_slices.h" /* // the states we can go through @@ -21,8 +23,8 @@ STATE_FAILED, // we failed }; -enum render_multi_sub_state { - STATE_INIT, // the render_multi_sub is in the process of being initialized +enum render_multi_node_state { + STATE_INIT, // the render_multi_node is in the process of being initialized STATE_SENDING, // we're waiting for the requests to be sent STATE_FILL_ROW, // we're filling the row with data STATE_ROW_FULL, // our row is full @@ -35,22 +37,16 @@ struct render_multi { // these are used as arguments to render_remote - struct render_multi_sub { - // our offset in the list - int index; + struct render_multi_node { + // the slice info + struct render_slice_info *info; // the render_remote_ctx struct render_remote *render_remote; - // a pointer to ourself - struct render_multi *self; - // _render_multi_sent called for this? int render_sent; - // our offset into the row, static - size_t row_offset; - // how wide our slice is, static size_t slice_width; @@ -59,11 +55,14 @@ // _render_multi_done called for this? int render_done; + + // a pointer to ourself + struct render_multi *self; - } remote_renders[RENDER_MULTI_NODES_MAX]; + } nodes[RENDER_SLICES_MAX]; - // how many remote_renders we have - int remote_render_count; + // how many nodes we have + int node_count; // is this still alive? int alive; @@ -77,15 +76,12 @@ // have we called cb_sent? int have_sent; - // the png thing - struct render_png *png_info; + // the render_slices thing + struct render_slices slices; // has render_png_done returned? int png_done; - // our pixel data row - unsigned char *rowbuf; - // buffer render_png output in this struct evbuffer *out_buf; @@ -115,10 +111,7 @@ static void _render_multi_do_free (struct render_multi *ctx) { assert(ctx && ctx->alive == 0); - if (ctx->rowbuf) { - free(ctx->rowbuf); - ctx->rowbuf = NULL; - } + render_slices_deinit(&ctx->slices); if (ctx->out_buf) { evbuffer_free(ctx->out_buf); @@ -132,9 +125,9 @@ static void _render_multi_do_sent (struct render_multi *ctx) { int i; - // check that all the remote_renders have indeed been sent - for (i = 0; i < ctx->remote_render_count; i++) { - assert(ctx->remote_renders[i].render_sent); + // check that all the nodes have indeed been sent + for (i = 0; i < ctx->node_count; i++) { + assert(ctx->nodes[i].render_sent); } // assert the callbacks are still valid @@ -186,37 +179,30 @@ // the request completed normally, flush the png data and return // _render_multi_png_done takes care of calling cb_done, not us! static void _render_multi_do_done (struct render_multi *ctx) { - assert(ctx->alive && ctx->png_info); + assert(ctx->alive); int i; // check that all the remote_renders are indeed complete - for (i = 0; i < ctx->remote_render_count; i++) { - assert(ctx->remote_renders[i].render_remote == NULL); - assert(ctx->remote_renders[i].col == 0); + for (i = 0; i < ctx->node_count; i++) { + assert(ctx->nodes[i].render_remote == NULL); + assert(ctx->nodes[i].col == 0); } + + // and that the PNG stuff is complete + assert(ctx->png_done); - // we need to make sure this render_png_done call only happens once (render_multi_do_fail, state bugs) - if (render_png_done(ctx->png_info)) { - ctx->png_info = NULL; - - ERROR("render_png_done"); - } - - ctx->png_info = NULL; - - // mark the png as done now - ctx->png_done = 1; - // if that all the data handled now, we're done _render_multi_do_png_data(ctx); // don't free ourself, our user does that (probably already did, via render_png_done) return; +/* error: - /* render_png_done failed, probably because we didn't have enough data */ + / * render_png_done failed, probably because we didn't have enough data * / _render_multi_do_fail(ctx, FAIL_PARTIAL); +*/ } // the request completed abnormally. Flags: @@ -232,17 +218,13 @@ ctx->alive = 0; // cancel any in-progress remote renders - for (i = 0; i < ctx->remote_render_count; i++) - if (ctx->remote_renders[i].render_remote) { - render_remote_cancel(ctx->remote_renders[i].render_remote); - ctx->remote_renders[i].render_remote = NULL; + for (i = 0; i < ctx->node_count; i++) + if (ctx->nodes[i].render_remote) { + render_remote_cancel(ctx->nodes[i].render_remote); + ctx->nodes[i].render_remote = NULL; } - if (!(flags & FAIL_PARTIAL) || ctx->png_info) { - // abort the render_png - render_png_abort(ctx->png_info); - ctx->png_info = NULL; - } + // XXX: does render_slices need an abort? // check that both callbacks are still valid assert(ctx->cb_fail && ctx->cb_done); @@ -263,14 +245,14 @@ * Once all of these commands have been sent, invoke our cb_sent. */ static void _render_multi_sent (void *arg) { - struct render_multi_sub *ctx = arg; + struct render_multi_node *ctx = arg; // mark these as sent ctx->render_sent = 1; ctx->self->renders_sent++; // have all render_sub_ctxs been sent? - if (ctx->self->renders_sent == ctx->self->remote_render_count) { + if (ctx->self->renders_sent == ctx->self->node_count) { // tell our user _render_multi_do_sent(ctx->self); } @@ -280,7 +262,7 @@ * One render node failed, abort the whole thing */ static void _render_multi_fail (void *arg) { - struct render_multi_sub *ctx = arg; + struct render_multi_node *ctx = arg; // free this ctx's remote render render_remote_free(ctx->render_remote); @@ -294,7 +276,7 @@ * Got new data for some remote render */ static void _render_multi_data_raw (int fd, short event, void *arg) { - struct render_multi_sub *ctx = arg; + struct render_multi_node *ctx = arg; int ret; assert(ctx->col <= ctx->slice_width); // check it isn't out of range @@ -305,8 +287,8 @@ // read new data into our slice ret = read(fd, - ctx->self->rowbuf + ctx->row_offset + ctx->col, // our fixed offset + partial row offset - ctx->slice_width - ctx->col // how many bytes left in the window + ctx->info->render_buf + ctx->col, // our segment buffer + partial segment offset + ctx->slice_width - ctx->col // how many bytes left in the segment ); // errors/EOF? @@ -327,12 +309,12 @@ render_remote_done(ctx->render_remote); ctx->render_remote = NULL; - // is the data incomplete? - if (!(ctx->col == ctx->slice_width || ctx->col == 0)) - ERROR("incomplete data for slice %d: %zu/%zu bytes", ctx->index, ctx->col, ctx->slice_width); + // we should only receive an EOF when ctx->col is zero or full + if (ctx->col != 0 || ctx->col != ctx->slice_width) + ERROR("incomplete data for slice %zu: %zu/%zu bytes", ctx->info->index, ctx->col, ctx->slice_width); // are all of them done? - if (ctx->self->renders_done == ctx->self->remote_render_count) { + if (ctx->self->renders_done == ctx->self->node_count) { // finish it off _render_multi_do_done(ctx->self); @@ -341,30 +323,45 @@ // do *NOT* reschedule ourself, ctx->render_remote is invalid anyways (as is ctx!) return; } + + // check if we were expecting // ok, we received some data normally ctx->col += ret; // is our slice full now? if (ctx->col == ctx->slice_width) { - // is the row complete now? - int i; - for (i = 0; i < ctx->self->remote_render_count; i++) { - if (ctx->self->remote_renders[i].col < ctx->self->remote_renders[i].slice_width) - break; - } + // yes! + int status; - if (i == ctx->self->remote_render_count) { - // pass the data to render_png, this results in calls to _render_multi_png_data - if (render_png_row(ctx->self->png_info, ctx->self->rowbuf)) - ERROR("render_png_row"); + if ((status = render_slices_segment_done(&ctx->self->slices, ctx->info->index)) == -1) + ERROR("render_slices_segment_done"); + + // row done? + if (status & SLICE_PROCESS_ROW) { + // XXX: ignore SLICE_PROCESS_ROW from render_slices_process_row + status = render_slices_process_row(&ctx->self->slices); - // clear the col values and reschedule the reads in case they were paused - for (i = 0; i < ctx->self->remote_render_count; i++) { - ctx->self->remote_renders[i].col = 0; - render_remote_reschedule(ctx->self->remote_renders[i].render_remote); + // we should have SLICE_CONTINUE by now, unless the PNG is done + if (status & SLICE_CONTINUE) { + // clear the col values and reschedule the reads in case they were ~SLICE_CONTINUE + int i; + for (i = 0; i < ctx->self->node_count; i++) { + ctx->self->nodes[i].col = 0; + render_remote_reschedule(ctx->self->nodes[i].render_remote); + } + } else { + // XXX: assume render_slices_process_row doesn't return a SLICE_PROCESS_ROW alone + assert(status == 0); + + ctx->self->png_done = 1; + + // and wait for the EOF... } } + + // if we got SLICE_CONTINUE here, I don't care, don't try and get another row now + // just fall through and reschedule } // ok, reschedule ourselves @@ -402,11 +399,6 @@ return -1; } -#define ROUND_DOWN(dividend, divisor) ((dividend) / (divisor)) -#define ROUND_UP(dividend, divisor) (((dividend) / (divisor)) + ((dividend) % (divisor))) - -#define HALF(a, b) (( a + b) / 2) - struct render_multi *render_multi ( struct render *render, // what to render struct remote_pool *pool_info, // what render pool to use @@ -417,7 +409,6 @@ void *cb_arg ) { struct render_multi *ctx = NULL; - struct render r_left, r_right; // alloc the render_multi ctx = calloc(1, sizeof(struct render_multi)); @@ -425,32 +416,6 @@ if (!ctx) ERROR("calloc"); - // init the remote_render - // for now, just split it in half into two render_ts - ctx->remote_renders[0].index = 0; - ctx->remote_renders[0].self = ctx; - ctx->remote_renders[0].slice_width = render->img_w / 2; - ctx->remote_renders[0].row_offset = 0; - - ctx->remote_renders[1].index = 1; - ctx->remote_renders[1].self = ctx; - ctx->remote_renders[1].slice_width = render->img_w / 2 + render->img_w % 2; - ctx->remote_renders[1].row_offset = render->img_w / 2; - - ctx->remote_render_count = 2; - - assert(RENDER_MULTI_NODES_MAX >= 2); - - if ( - render_init(&r_left, RENDER_RAW) - || render_init(&r_right, RENDER_RAW) - || render_set_size(&r_left, ctx->remote_renders[0].slice_width, render->img_h) - || render_set_size(&r_right, ctx->remote_renders[1].slice_width, render->img_h) - || render_region_raw(&r_left, render->x1, render->y1, HALF(render->x1, render->x2), render->y2) - || render_region_raw(&r_right, HALF(render->x1, render->x2), render->y1, render->x2, render->y2) - ) - ERROR("render_{init,set_size,set_region_raw}"); - // store the provided callback functions ctx->cb_sent = cb_sent; ctx->cb_data = cb_data; @@ -458,10 +423,6 @@ ctx->cb_fail = cb_fail; ctx->cb_arg = cb_arg; - // our rowbuf - if (!(ctx->rowbuf = malloc(render->img_w))) - ERROR("malloc"); - // store our render_png callbacks, must be before png_info if (render_io_custom(render, &_render_multi_png_data, NULL, ctx)) ERROR("render_io_custom"); @@ -470,28 +431,37 @@ if (!(ctx->out_buf = evbuffer_new())) ERROR("evbuffer_new"); - // png info - if (!(ctx->png_info = render_png_init(render))) - ERROR("render_png_init"); - - // pull two nodes from the pool - struct remote_node *node_left, *node_right; + // then initialize the render_slices + if (render_slices_init(&ctx->slices, render)) + ERROR("render_slices_init"); + + // how many nodes? + ctx->node_count = render_slices_get_count(&ctx->slices); - if ( - !(node_left = remote_pool_get(pool_info)) - || !(node_right = remote_pool_get(pool_info)) - ) - ERROR("remote_pool_get"); + // load them + int i; + + for (i = 0; i < ctx->node_count; i++) { + struct remote_node *node_info; + + // store the info struct + ctx->nodes[i].info = render_slices_get_slice_info(&ctx->slices, i); + + // some simple attributes + ctx->nodes[i].slice_width = ctx->nodes[i].info->render_info->img_w; + ctx->nodes[i].self = ctx; + + // get a node from the pool + if (!(node_info = remote_pool_get(pool_info))) + ERROR("remote_pool_get"); + + // the render_remote + if (!(ctx->nodes[i].render_remote = render_remote_rawio(ctx->nodes[i].info->render_info, node_info, + &_render_multi_sent, &_render_multi_fail, &_render_multi_data_raw, &ctx->nodes[i])) + ) + ERROR("render_remote_rawio"); + } - // the two render_remote calls - if ( - !(ctx->remote_renders[0].render_remote = render_remote_rawio(&r_left, node_left, - &_render_multi_sent, &_render_multi_fail, &_render_multi_data_raw, &ctx->remote_renders[0])) - || !(ctx->remote_renders[1].render_remote = render_remote_rawio(&r_right, node_right, - &_render_multi_sent, &_render_multi_fail, &_render_multi_data_raw, &ctx->remote_renders[1])) - ) - ERROR("render_remote"); - // we are now alive ctx->alive = 1; diff -r 50995bbe442a -r 8e8b56b0e0f5 render_png.c --- a/render_png.c Sun Jun 08 23:10:36 2008 +0300 +++ b/render_png.c Mon Jun 09 03:15:34 2008 +0300 @@ -3,19 +3,10 @@ #include #include "common.h" -#include "render_internal.h" +#include "render_struct.h" +#include "render_png_struct.h" #include "render_png.h" -struct render_png { - // libpng handles - png_structp png_ptr; - png_infop info_ptr; - - // some info that we need to keep from the struct render - render_ctx_write_cb io_write_fn; - render_ctx_flush_cb io_flush_fn; - void *cb_arg; -}; static void _render_png_write(png_structp png_ptr, png_bytep data, png_size_t length) { struct render_png *ctx = png_get_io_ptr(png_ptr); @@ -38,21 +29,37 @@ } static void _render_png_free (struct render_png *ctx) { - if (ctx) - png_destroy_write_struct(&ctx->png_ptr, &ctx->info_ptr); - - free(ctx); + render_png_deinit(ctx); + + if (ctx->owned_by_me) + free(ctx); } - -struct render_png *render_png_init (struct render *render) { +int render_png_deinit (struct render_png *ctx) { + // not initialized? Just return a positive nonzero value + if (!ctx->png_ptr) + return 1; - struct render_png *ctx = NULL; + // libpng error handling + if (setjmp(png_jmpbuf(ctx->png_ptr))) + ERROR("libpng"); + + png_destroy_write_struct(&ctx->png_ptr, &ctx->info_ptr); - // calloc the render_png - if (!(ctx = calloc(1, sizeof(struct render_png)))) - ERROR("calloc"); + // success + return 0; +error: + free(ctx); + return -1; +} + +/* + * Note that it's vitally important not to call any libpng functions directly, + * the error-handling setjmp will be invalid. + */ + +int render_png_init (struct render_png *ctx, struct render *render) { // store some info from the struct render ctx->io_write_fn = render->io_write_fn; ctx->io_flush_fn = render->io_flush_fn; @@ -83,6 +90,28 @@ // write out the PNG header png_write_info(ctx->png_ptr, ctx->info_ptr); + + // success + return 0; + +error: + render_png_deinit(ctx); + return -1; +} + +struct render_png *render_png_alloc (struct render *render) { + struct render_png *ctx = NULL; + + // calloc the render_png + if (!(ctx = calloc(1, sizeof(struct render_png)))) + ERROR("calloc"); + + // I need to free it + ctx->owned_by_me = 1; + + // init it + if (render_png_init(ctx, render)) + goto error; // success return ctx; diff -r 50995bbe442a -r 8e8b56b0e0f5 render_png.h --- a/render_png.h Sun Jun 08 23:10:36 2008 +0300 +++ b/render_png.h Mon Jun 09 03:15:34 2008 +0300 @@ -19,7 +19,7 @@ * * returns NULL on failure. */ -struct render_png *render_png_init (struct render *render); +struct render_png *render_png_alloc (struct render *render); /* * Feed a full row of raw pixel data into the PNG image. diff -r 50995bbe442a -r 8e8b56b0e0f5 render_png_struct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/render_png_struct.h Mon Jun 09 03:15:34 2008 +0300 @@ -0,0 +1,26 @@ +#ifndef RENDER_PNG_INTERNAL_H +#define RENDER_PNG_INTERNAL_H + +#include + +#include "render.h" +#include "render_png.h" + +struct render_png { + // do I need to free it? + int owned_by_me; + + // libpng handles + png_structp png_ptr; + png_infop info_ptr; + + // some info that we need to keep from the struct render + render_ctx_write_cb io_write_fn; + render_ctx_flush_cb io_flush_fn; + void *cb_arg; +}; + +int render_png_init (struct render_png *ctx, struct render *render); +int render_png_deinit (struct render_png *ctx); + +#endif /* RENDER_PNG_INTERNAL_H */ diff -r 50995bbe442a -r 8e8b56b0e0f5 render_raw.c --- a/render_raw.c Sun Jun 08 23:10:36 2008 +0300 +++ b/render_raw.c Mon Jun 09 03:15:34 2008 +0300 @@ -1,31 +1,25 @@ #include #include "common.h" -#include "render_internal.h" +#include "render_struct.h" +#include "render.h" +#include "render_raw_struct.h" #include "render_raw.h" -struct render_raw { - // some info that we need to keep from the struct render - u_int32_t img_w; - // cb or stream? - FILE *io_stream; - render_ctx_write_cb io_write_fn; - render_ctx_flush_cb io_flush_fn; - void *cb_arg; -}; -static void _render_raw_free (struct render_raw *ctx) { - free(ctx); +int render_raw_deinit (struct render_raw *ctx) { + return 0; } -struct render_raw *render_raw_init (struct render *render) { - struct render_raw *ctx = NULL; +void render_raw_free (struct render_raw *ctx) { + render_raw_deinit(ctx); + + if (ctx->owned_by_me) + free(ctx); +} - // calloc the render_png - if (!(ctx = calloc(1, sizeof(struct render_raw)))) - ERROR("calloc"); - +int render_raw_init (struct render_raw *ctx, struct render *render) { // store some info from the struct render ctx->img_w = render->img_w; ctx->io_stream = render->io_stream; @@ -34,10 +28,33 @@ ctx->cb_arg = render->cb_arg; // success + return 0; + +/* +error: + _render_raw_deinit(ctx); + return -1; +*/ +} + +struct render_raw *render_raw_alloc (struct render *render) { + struct render_raw *ctx = NULL; + + // calloc the render_png + if (!(ctx = calloc(1, sizeof(struct render_raw)))) + ERROR("calloc"); + + // mark it to be freed + ctx->owned_by_me = 1; + + // initialize + if (render_raw_init(ctx, render)) + goto error; + return ctx; error: - _render_raw_free(ctx); + render_raw_free(ctx); return NULL; } @@ -78,19 +95,19 @@ } // free everything - _render_raw_free(ctx); + render_raw_free(ctx); // success return 0; error: - _render_raw_free(ctx); + render_raw_free(ctx); return -1; } int render_raw_abort (struct render_raw *ctx) { // just free it - _render_raw_free(ctx); + render_raw_free(ctx); // success return 0; diff -r 50995bbe442a -r 8e8b56b0e0f5 render_raw.h --- a/render_raw.h Sun Jun 08 23:10:36 2008 +0300 +++ b/render_raw.h Mon Jun 09 03:15:34 2008 +0300 @@ -19,7 +19,7 @@ * * returns NULL on failure. */ -struct render_raw *render_raw_init (struct render *render); +struct render_raw *render_raw_alloc (struct render *render); /* * Feed a full row of raw pixel data to be handled diff -r 50995bbe442a -r 8e8b56b0e0f5 render_raw_struct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/render_raw_struct.h Mon Jun 09 03:15:34 2008 +0300 @@ -0,0 +1,25 @@ +#ifndef RENDER_RAW_STRUCT_H +#define RENDER_RAW_STRUCT_H + +#include + +#include "render_raw.h" + +struct render_raw { + // do I have to free it? + int owned_by_me; + + // some info that we need to keep from the struct render + u_int32_t img_w; + + // cb or stream? + FILE *io_stream; + render_ctx_write_cb io_write_fn; + render_ctx_flush_cb io_flush_fn; + void *cb_arg; +}; + +int render_raw_init (struct render_raw *ctx, struct render *render); +int render_raw_deinit (struct render_raw *ctx); + +#endif /* RENDER_RAW_STRUCT_H */ diff -r 50995bbe442a -r 8e8b56b0e0f5 render_slices.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/render_slices.c Mon Jun 09 03:15:34 2008 +0300 @@ -0,0 +1,171 @@ +#include +#include + +#include "common.h" +#include "render_struct.h" +#include "render_slices_struct.h" +#include "render_slices.h" + +void render_slices_free (struct render_slices *ctx) { + render_slices_deinit(ctx); + + if (ctx->owned_by_me) + free(ctx); +} + +int render_slices_deinit (struct render_slices *ctx) { + // if it's not initialized, just ignore + if (!ctx->rowbuf) + return 1; + + free(ctx->rowbuf); + + render_png_deinit(&ctx->png_info); + + return 0; +} + +#define HALF(a, b) (( a + b) / 2) + +int render_slices_init (struct render_slices *ctx, struct render *render) { + // initialize the slices + // for now, just split it in half into two render_ts + ctx->slices[0].info.index = 0; + ctx->slices[0].info.render_info = &ctx->slices[0].render_info; + ctx->slices[0].self = ctx; + ctx->slices[0].row_offset = 0; + + ctx->slices[1].info.index = 1; + ctx->slices[1].info.render_info = &ctx->slices[1].render_info; + ctx->slices[1].self = ctx; + ctx->slices[1].row_offset = render->img_w / 2; + + ctx->num_slices = 2; + ctx->render_row = 0; + ctx->done_row = -1; + + assert(RENDER_SLICES_MAX >= 2); + + if ( + render_init (&ctx->slices[0].render_info, RENDER_RAW) + || render_init (&ctx->slices[1].render_info, RENDER_RAW) + + || render_set_size (&ctx->slices[0].render_info, render->img_w / 2, render->img_h) + || render_set_size (&ctx->slices[1].render_info, render->img_w / 2 + render->img_w % 2, render->img_h) + + || render_region_raw (&ctx->slices[0].render_info, render->x1, render->y1, HALF(render->x1, render->x2), render->y2) + || render_region_raw (&ctx->slices[1].render_info, HALF(render->x1, render->x2), render->y1, render->x2, render->y2) + ) + ERROR("render_{init,set_size,set_region_raw}"); + + // allocate the rowbuf + if (!(ctx->rowbuf = malloc(render->img_w * 2))) + ERROR("malloc"); + + // update the slice_buf pointers + ctx->rows[0] = ctx->rowbuf; + ctx->rows[1] = ctx->rowbuf + render->img_w; + ctx->slices[0].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[0].row_offset; + ctx->slices[1].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[1].row_offset; + + // png info + if (render_png_init(&ctx->png_info, render)) + ERROR("render_png_init"); + + // great success! + return 0; + +error: + render_slices_deinit(ctx); + return -1; +} + +struct render_slices *render_slices_alloc (struct render *render) { + struct render_slices *ctx = NULL; + + // allocate it + if (!(ctx = calloc(1, sizeof(*ctx)))) + ERROR("calloc"); + + // mark it for free()ing + ctx->owned_by_me = 1; + + // initialize it + if (render_slices_init(ctx, render)) + goto error; + + return ctx; + +error : + render_slices_free(ctx); + return NULL; +} + +int render_slices_get_count (struct render_slices *ctx) { + return ctx->num_slices; +} + +struct render_slice_info *render_slices_get_slice_info (struct render_slices *ctx, int index) { + assert(index >= 0 && index < ctx->num_slices); + + return &ctx->slices[index].info; +} + +int render_slices_segment_done (struct render_slices *ctx, int index) { + assert(index >= 0 && index < ctx->num_slices); + assert(ctx->slices_done < ctx->num_slices); + + // keep track of the number of full slices + ctx->slices_done++; + + // is the row complete? + if (ctx->slices_done == ctx->num_slices) { + // the row is complete + ctx->slices_done = 0; + + // is the other row waiting for it to get processed? + if (ctx->done_row < 0) { + // no, point the done_row at this row, point the render buffers to the unused row + ctx->done_row = ctx->render_row; + ctx->render_row = (ctx->render_row == 0 ? 1 : 0); + + int i ; + for (i = 0; i < ctx->num_slices; i++) { + ctx->slices[i].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[i].row_offset; + } + + // can now continue rendering as well as call process_row + return SLICE_PROCESS_ROW & SLICE_CONTINUE; + + } else { + // cannot continue rendering, need to have process_row complete first + return SLICE_PROCESS_ROW; + + } + + } else { + // the row is not complete, do not render the next segment, do not call process_row + return 0; + + } +} + +int render_slices_process_row (struct render_slices *ctx) { + assert(ctx->done_row >= 0); + + // pass the data to render_png, this results in calls to _render_multi_png_data + if (render_png_row(&ctx->png_info, ctx->rows[ctx->done_row])) + ERROR("render_png_row"); + + // mark the row as processed + ctx->done_row = -1; + + // ok, but don't call me again until I tell you to. + return SLICE_CONTINUE; + +error: + // user needs to deinit/free us + return -1; +} + + diff -r 50995bbe442a -r 8e8b56b0e0f5 render_slices.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/render_slices.h Mon Jun 09 03:15:34 2008 +0300 @@ -0,0 +1,113 @@ +#ifndef RENDER_SLICES_H +#define RENDER_SLICES_H + +#include "render.h" + +#define RENDER_SLICES_MAX 2 + +struct render_slices; + +struct render_slice_info { + // our index + size_t index; + + // the render info + struct render *render_info; + + // where to put the pixel data + unsigned char *render_buf; +}; + +/* + * Split the given render operation into multiple slices that can be rendered + * induvidually. + * + * A segment is a single row of a slice. The raw pixel data for each segment + * should be stored into the render_buf item in that slice's render_slice_info. + * When a full segment has been stored into the render_buf, you should call + * render_slices_segment_done with that slice's index as an argument, and then + * proceed based on its return code. + * + * Returns a struct render_slices handle which can be used to operate on the + * slices, or NULL on failure. + */ +struct render_slices *render_slices_alloc (struct render *render); + +/* + * Get the number of slices that need to be rendered, which is also the valid + * range of index values for render_slices_get_slice_info. + */ +int render_slices_get_count (struct render_slices *ctx); + +/* + * Get the struct render_slice_info corresponding to the given index. This + * the information required to render the segment. The index is used as an + * argument to render_slices_segment_done. + */ +struct render_slice_info *render_slices_get_slice_info (struct render_slices *ctx, int index); + +/* + * You may call render_slices_segment_done again for any slice now, including + * those which returned ~SLICE_CONTINUE earlier. + */ +#define SLICE_CONTINUE 0x01 + +/* + * You may call render_slices_process_row next. + */ +#define SLICE_PROCESS_ROW 0x02 + +/* + * The render_buf for the render_slice_info with the given index value contains + * the full information for the next row of the render_info render. Returns a + * bitwise-AND of the SLICE_* flags, or -1 for an error: + * + * Valid return values: + * zero + * Do not call segment_done for this index, or process_row right now. + * Information for some slice needed to complete the next row is missing, + * and the other segments must call segment_done first. + * + * SLICE_PROCESS_ROW + * Do not call segment_done for this index or any others, but do call + * process_row as soon as possible, and then continue once it returns + * (see render_slices_process_row). + * + * SLICE_CONTINUE & SLICE_PROCESS_ROW + * You should call process_row next, but you can also call segment_done + * for all segments that returned ~SLICE_CONTINUE earlier. + * + * -1 - An error occured. Rendering must be aborted. + * + */ +int render_slices_segment_done (struct render_slices *ctx, int index); + +/* + * Process a completed row and generate output in the PNG format (how that is + * handled depends on the render given to render_slices_alloc/init). Returns a + * bitwise-AND of the SLICE_* flags, or -1 for an error: + * + * Valid return values : + * zero + * The PNG is done - you don't need to call segment_done or process_row + * anymore, doing so will result in an error. You don't need to deinit + * ctx, but you may need to free it. + * + * SLICE_CONTINUE + * You may call render_slices_segment_done again for those slices that + * returned ~SLICE_CONTINUE earlier. + * + * SLICE_CONTINUE & SLICE_PROCESS_ROW + * In addition to calling render_slices_segment_done again, you may also + * call render_slices_process_row again. + * + * -1 - An error occured. Rendering must be aborted. + */ +int render_slices_process_row (struct render_slices *ctx); + +/* + * Free a render_slices. The rendering may or may not be complete. + */ +void render_slices_free (struct render_slices *ctx); + +#endif /* RENDER_SLICES_H */ diff -r 50995bbe442a -r 8e8b56b0e0f5 render_slices_struct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/render_slices_struct.h Mon Jun 09 03:15:34 2008 +0300 @@ -0,0 +1,46 @@ + +#include "render_struct.h" +#include "render_png_struct.h" +#include "render_slices.h" + +struct render_slices { + // do I have to free it? + int owned_by_me; + + // the induvidual slices + struct render_slice { + // the public info + struct render_slice_info info; + + // the render info + struct render render_info; + + // our offset into rowbuf + size_t row_offset; + + // pointer back to parent + struct render_slices *self; + } slices[RENDER_SLICES_MAX]; + + // how many slices are in use + size_t num_slices; + + // how many slices have reported the current row as done + size_t slices_done; + + // the a pointer to the raw memory buffer + unsigned char *rowbuf; + + // the two rows of memory area used to a) render b) build the png + unsigned char *rows[2]; + + // which of the two rows is is used for png-building (default = 0, 1) + int render_row, done_row; + + // the png struct + struct render_png png_info; +}; + +int render_slices_init (struct render_slices *ctx, struct render *render); +int render_slices_deinit (struct render_slices *ctx); + diff -r 50995bbe442a -r 8e8b56b0e0f5 render_struct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/render_struct.h Mon Jun 09 03:15:34 2008 +0300 @@ -0,0 +1,39 @@ +#ifndef RENDER_STRUCT_H +#define RENDER_STRUCT_H + +#include "render.h" + +struct render { +/* render mode */ + int mode; + +/* image size */ + u_int32_t img_w; + u_int32_t img_h; + +/* mandelbrot region */ + double x1; + double y1; + double x2; + double y2; + +/* local rendering */ + unsigned char **local_rowbuf_addr; + render_ctx_row_cb local_row_fn; + +/* local I/O parameters */ + // if this is non-NULL, the image data is simply fwrite():en to this stream + FILE *io_stream; + + // called to handle the output data + render_ctx_write_cb io_write_fn; + + // called when the output data should be flushed - can be safely ignored if not needed + render_ctx_flush_cb io_flush_fn; + + // the callback argument for all of the above *_fn + void *cb_arg; +}; + +#endif /* RENDER_STRUCT_H */ +