a half-working render_slices. Render_multi is currently semantically broken/buggy, but it's time to go to sleep
committer: Tero Marttila <terom@fixme.fi>
--- 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}
--- 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 */
-
--- 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 <assert.h>
#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;
}
--- 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 <assert.h>
#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;
--- 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 <png.h>
#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;
--- 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.
--- /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 <png.h>
+
+#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 */
--- 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 <stdlib.h>
#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;
--- 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
--- /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 <stdio.h>
+
+#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 */
--- /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 <stdlib.h>
+#include <assert.h>
+
+#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;
+}
+
+
--- /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 */
--- /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);
+
--- /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 */
+