# HG changeset patch # User Tero Marttila # Date 1212189747 -10800 # Node ID 6aa1a0d1f88d927aa79381c11584ab603e9febfb # Parent 5b010627d7ed2e8acca0fd8e9c51578fa16c6572 partial commit of new render module, render_file should work, web_main doesn't committer: Tero Marttila diff -r 5b010627d7ed -r 6aa1a0d1f88d Makefile --- a/Makefile Fri May 30 14:24:23 2008 +0300 +++ b/Makefile Sat May 31 02:22:27 2008 +0300 @@ -1,9 +1,12 @@ LDFLAGS = -L/usr/local/lib -levent -lpng CFLAGS = -Wall -g -render_file: mandelbrot.o common.o +OBJS = common.o mandelbrot.o render.o +HEADERS = common.h mandelbrot.h render.h -web_main: mandelbrot.o common.o +render_file: ${OBJS} -render_node: mandelbrot.o common.o +web_main: ${OBJS} +render_node: ${OBJS} + diff -r 5b010627d7ed -r 6aa1a0d1f88d mandelbrot.c --- a/mandelbrot.c Fri May 30 14:24:23 2008 +0300 +++ b/mandelbrot.c Sat May 31 02:22:27 2008 +0300 @@ -1,39 +1,23 @@ -#include #include #include -#include #include +#include "render.h" #include "mandelbrot.h" #include "common.h" - #define DETAIL 255 #define absdelta(a, b) (a>b ? a-b : b-a) -void render_ctx_set (struct render_ctx *ctx, render_ctx_write_cb write_fn, render_ctx_flush_cb flush_fn, void *arg) { - memset(ctx, 0, sizeof(*ctx)); - - ctx->write_fn = write_fn; - ctx->flush_fn = flush_fn; - ctx->cb_arg = arg; -} - -void render_ctx_stream (struct render_ctx *ctx, FILE *fh) { - memset(ctx, 0, sizeof(*ctx)); - - ctx->stream = fh; -} - void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { struct render_ctx *ctx = (struct render_ctx *) png_get_io_ptr(png_ptr); - if (ctx->write_fn) - switch (ctx->write_fn(data, length, ctx->cb_arg)) { + if (ctx->io_write_fn) + switch (ctx->io_write_fn(data, length, ctx->io_cb_arg)) { case RENDER_CB_ERR : - ctx->_error = 1; + ctx->io_error = 1; break; case RENDER_CB_OK : @@ -45,10 +29,10 @@ void user_flush_data(png_structp png_ptr) { struct render_ctx *ctx = (struct render_ctx *) png_get_io_ptr(png_ptr); - if (ctx->flush_fn) - switch (ctx->flush_fn(ctx->cb_arg)) { + if (ctx->io_flush_fn) + switch (ctx->io_flush_fn(ctx->io_cb_arg)) { case RENDER_CB_ERR : - ctx->_error = 1; + ctx->io_error = 1; break; case RENDER_CB_OK : @@ -57,94 +41,70 @@ } } -int _validate_render ( - u_int32_t img_w, u_int32_t img_h, - double x1, double y1, double x2, double y2 -) { - if ( - (img_w == 0 || img_h == 0) // zero-size image - || (x1 >= x2 || y1 >= y2) // invalid region - ) - return MANDELBROT_ERR_INVALID; - else - return MANDELBROT_OK; -} +int mandelbrot_render (render_t *ctx) { + // libpng handles + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; - -int mandelbrot_render_region ( - struct render_ctx *ctx, - u_int32_t img_w, u_int32_t img_h, - double x1, double y1, double x2, double y2 -) { + // render algorithm vars u_int32_t img_x, img_y; double x0, y0, x, y, _x, _y, w_scale, h_scale; u_int8_t iter; u_int8_t *row; - // validate! - int valid = _validate_render(img_w, img_h, x1, y1, x2, y2); - - if (valid != MANDELBROT_OK) - return valid; - // clear out any potential error in ctx - ctx->_error = 0; + ctx->io_error = 0; // calcluate the scale factors - w_scale = img_w/absdelta(x1, x2); - h_scale = img_h/absdelta(y1, y2); + w_scale = ctx->img_w/absdelta(ctx->x1, ctx->x2); + h_scale = ctx->img_h/absdelta(ctx->y1, ctx->y2); // malloc the memory used to render each row - row = (u_int8_t *) malloc(img_w); + row = (u_int8_t *) malloc(ctx->img_w); if (!row) - return MANDELBROT_ERR_MALLOC; - - // libpng initialization - png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - if (!png_ptr) { - free(row); - return MANDELBROT_ERR_PNG_INIT; - } - - png_infop info_ptr = png_create_info_struct(png_ptr); - - if (!info_ptr) { - png_destroy_write_struct(&png_ptr, (png_infopp)NULL); - free(row); - return MANDELBROT_ERR_PNG_INIT; - } + goto error; - if (ctx->stream) { - // use normal libpng I/O - png_init_io(png_ptr, ctx->stream); - } else { - // setup our custom I/O callbacks - png_set_write_fn(png_ptr, ctx, &user_write_data, &user_flush_data); - } + // PNG or not? + if (ctx->mode == RENDER_PNG) { + // libpng initialization + png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - // some PNG metadata - png_set_IHDR(png_ptr, info_ptr, img_w, img_h, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + if (!png_ptr) + goto error; - // write out the PNG header - png_write_info(png_ptr, info_ptr); + info_ptr = png_create_info_struct(png_ptr); - // possible error return - if (ctx->_error) { - free(row); - png_destroy_write_struct(&png_ptr, &info_ptr); - return MANDELBROT_ERR_CB; + if (!info_ptr) + goto error; + + if (ctx->io_stream) { + // use normal libpng I/O + png_init_io(png_ptr, ctx->io_stream); + } else { + // setup our custom I/O callbacks + png_set_write_fn(png_ptr, ctx, &user_write_data, &user_flush_data); + } + + // some PNG metadata + png_set_IHDR(png_ptr, info_ptr, ctx->img_w, ctx->img_h, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + // write out the PNG header + png_write_info(png_ptr, info_ptr); + + // possible error return + if (ctx->io_error) + goto error; } // start rendering! - for (img_y=0; img_y < img_h; img_y++) { + for (img_y=0; img_y < ctx->img_h; img_y++) { // render the current row - for (img_x=0; img_x < img_w; img_x++) { + for (img_x=0; img_x < ctx->img_w; img_x++) { x = 0; y = 0; - x0 = img_x/w_scale + x1; - y0 = img_y/h_scale + y1; + x0 = img_x/w_scale + ctx->x1; + y0 = img_y/h_scale + ctx->y1; iter = DETAIL; while (x*x + y*y < (2*2) && iter > 0) { @@ -160,40 +120,53 @@ row[img_x] = iter; } - // write the raw pixels to libpng - png_write_row(png_ptr, row); - - // check for user errors return - if (ctx->_error) { - free(row); - png_destroy_write_struct(&png_ptr, &info_ptr); - return MANDELBROT_ERR_CB; + if (ctx->mode == RENDER_PNG) { + // write the raw pixels to libpng + png_write_row(png_ptr, row); + + // check for user errors return + if (ctx->io_error) + goto error; + } else { + // pass on the pixels to the io callback + if (ctx->io_write_fn(row, ctx->img_w, ctx->io_cb_arg) == RENDER_CB_ERR) { + ctx->io_error = 1; + goto error; + } } } - - // finished writing - png_write_end(png_ptr, info_ptr); + + if (ctx->mode == RENDER_PNG) { + // finished writing + png_write_end(png_ptr, info_ptr); + } // clean up png_destroy_write_struct(&png_ptr, &info_ptr); - free(row); + free(row); row = NULL; // check for user errors return - if (ctx->_error) - return MANDELBROT_ERR_CB; + if (ctx->io_error) + goto error; // return succesfully return MANDELBROT_OK; + +error: + if (png_ptr || info_ptr) + png_destroy_write_struct(&png_ptr, &info_ptr); + + if (row) + free(row); + + row = NULL; + + return MANDELBROT_ERR; } -int mandelbrot_render_region_timed ( - struct render_ctx *ctx, - u_int32_t img_w, u_int32_t img_h, - double x1, double y1, double x2, double y2, - double *duration -) { +int mandelbrot_render_timed (render_t *ctx, double *duration) { clock_t t1 = clock(); - int ret = mandelbrot_render_region(ctx, img_w, img_h, x1, y1, x2, y2); + int ret = mandelbrot_render(ctx); clock_t t2 = clock(); *duration = ((double)(t2 - t1))/CLOCKS_PER_SEC; @@ -201,24 +174,3 @@ return ret; } -int render_cmd_set ( - struct render_cmd *cmd, - u_int32_t img_w, u_int32_t img_h, - double x1, double y1, double x2, double y2 -) { - // validate! - int valid = _validate_render(img_w, img_h, x1, y1, x2, y2); - - if (valid != MANDELBROT_OK) - return valid; - - cmd->img_w = htonl(img_w); - cmd->img_h = htonl(img_h); - cmd->x1 = x1; - cmd->y1 = y1; - cmd->x2 = x2; - cmd->y2 = y2; - - return MANDELBROT_OK; -} - diff -r 5b010627d7ed -r 6aa1a0d1f88d mandelbrot.h --- a/mandelbrot.h Fri May 30 14:24:23 2008 +0300 +++ b/mandelbrot.h Sat May 31 02:22:27 2008 +0300 @@ -1,117 +1,18 @@ -/* - * code to render a mandelbrot - */ - -#include - -typedef int (*render_ctx_write_cb)(const unsigned char *data, size_t length, void *arg); -typedef int (*render_ctx_flush_cb)(void *arg); - -#define RENDER_CB_OK 0 -#define RENDER_CB_ERR 1 - -struct render_ctx { - /* - * If we just use normal FILE* stream operations - */ - FILE *stream; - - /* - * These callback functions are used to handle the PNG data as it's rendered. - * - * If they return RENDER_CB_OK, all is fine and rendering will continue normally. - * If they return RENDER_CB_ERR, rendering will abort. - */ - - // called to handle the output data - render_ctx_write_cb write_fn; - - // called when the output data should be flushed - can be safely ignored if not needed - render_ctx_flush_cb flush_fn; - - // the callback argument - void *cb_arg; - - // error status - int _error; -}; +#include "render.h" /* - * initialize the given struct render_ctx + * the mandelbrot-rendering algorithm */ -void render_ctx_set (struct render_ctx *ctx, render_ctx_write_cb write_fn, render_ctx_flush_cb flush_fn, void *arg); -void render_ctx_stream (struct render_ctx *ctx, FILE *fh); /* * return codes for mandelbrot_render */ #define MANDELBROT_OK 0 -#define MANDELBROT_ERR_MALLOC 1 -#define MANDELBROT_ERR_PNG_INIT 2 -#define MANDELBROT_ERR_CB 3 -#define MANDELBROT_ERR_INVALID 4 - -/* - * render an x PNG image of the mandelbrot region bounded by (x1, y1) -> (x2, y2) - */ -int mandelbrot_render_region ( - struct render_ctx *ctx, - u_int32_t img_w, u_int32_t img_h, - double x1, double y1, double x2, double y2 -); - -int mandelbrot_render_region_timed ( - struct render_ctx *ctx, - u_int32_t img_w, u_int32_t img_h, - double x1, double y1, double x2, double y2, - double *duration -); +#define MANDELBROT_ERR 1 /* - * remote rendering + * Render the image specified by the given render context */ - -#pragma pack(push) -#pragma pack(1) - -struct render_cmd { - u_int32_t img_w; - u_int32_t img_h; - - double x1; - double y1; - double x2; - double y2; -}; - -#pragma pack(pop) - -#define RENDER_PORT 6159 -#define RENDER_CMD_SIZE sizeof(struct render_cmd) +int mandelbrot_render (render_t *ctx); +int mandelbrot_render_timed (render_t *ctx, double *duration); -/* - * build the command to send for remote rendering - */ -int render_cmd_set ( - struct render_cmd *cmd, - u_int32_t img_w, u_int32_t img_h, - double x1, double y1, double x2, double y2 -); - -/* - * The "full" mandelbrot region - */ -#define REGION_X1 -2.0 -#define REGION_Y1 -1.5 -#define REGION_X2 1.0 -#define REGION_Y2 1.5 - -#define mandelbrot_render_full(ctx, img_w, img_h) \ - mandelbrot_render_region(ctx, img_w, img_h, REGION_X1, REGION_Y1, REGION_X2, REGION_Y2) - -#define mandelbrot_render_full_timed(ctx, img_w, img_h, duration) \ - mandelbrot_render_region_timed(ctx, img_w, img_h, REGION_X1, REGION_Y1, REGION_X2, REGION_Y2, duration) - -#define render_cmd_set_full(cmd, img_w, img_h) \ - render_cmd_set(cmd, img_w, img_h, REGION_X1, REGION_Y1, REGION_X2, REGION_Y2) - diff -r 5b010627d7ed -r 6aa1a0d1f88d render.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/render.c Sat May 31 02:22:27 2008 +0300 @@ -0,0 +1,77 @@ +#include +#include + +#include "render.h" + +int render_init (render_t *ctx, int mode) { + memset(ctx, 0, sizeof(*ctx)); + + return render_set_mode(ctx, mode); +} + +int render_set_mode (render_t *ctx, int mode) { + if (mode != RENDER_RAW && mode != RENDER_PNG) + return RENDER_ERR; + + ctx->mode = mode; + + return RENDER_OK; +} + +int render_set_size (render_t *ctx, u_int32_t img_w, u_int32_t img_h) { + if (img_w == 0 || img_h == 0) + return RENDER_ERR; + + ctx->img_w = img_w; + ctx->img_h = img_h; + + return RENDER_OK; +} + +int render_region_full (render_t *ctx) { + return render_region_raw(ctx, REGION_X1, REGION_Y1, REGION_X2, REGION_Y2); +} + +int render_region_raw (render_t *ctx, double x1, double y1, double x2, double y2) { + if ((x1 >= x2) || (y1 >= y2)) + return RENDER_ERR; + + ctx->x1 = x1; + ctx->y1 = y1; + ctx->x2 = x2; + ctx->y2 = y2; + + return RENDER_OK; +} + +int render_io_custom (render_t *ctx, render_ctx_write_cb write_fn, render_ctx_flush_cb flush_fn, void *arg) { + if (!write_fn) + return RENDER_ERR; + + ctx->io_write_fn = write_fn; + ctx->io_flush_fn = flush_fn; + ctx->io_cb_arg = arg; + + return RENDER_OK; +} + +int render_io_stream (render_t *ctx, FILE *fh) { + if (!fh) + return RENDER_ERR; + + ctx->io_stream = fh; + + return RENDER_OK; +} + +int render_cmd_build (render_t *ctx, struct render_cmd *cmd) { + cmd->img_w = htonl(ctx->img_w); + cmd->img_h = htonl(ctx->img_h); + cmd->x1 = ctx->x1; + cmd->y1 = ctx->y1; + cmd->x2 = ctx->x2; + cmd->y2 = ctx->y2; + + return RENDER_OK; +} + diff -r 5b010627d7ed -r 6aa1a0d1f88d render.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/render.h Sat May 31 02:22:27 2008 +0300 @@ -0,0 +1,120 @@ +#ifndef RENDER_H +#define RENDER_H + +#include +#include + +/* + * This module provides various ways to render mandelbrot images in various formats + */ + +// custom I/O callbacks function signatures +typedef int (*render_ctx_write_cb)(const unsigned char *data, size_t length, void *arg); +typedef int (*render_ctx_flush_cb)(void *arg); + +// callback return codes +#define RENDER_CB_OK 0 +#define RENDER_CB_ERR 1 + +#define RENDER_OK 0 +#define RENDER_ERR 1 + +// output types +enum { + RENDER_RAW, // raw pixel data + RENDER_PNG, // a png image +}; + +typedef struct render_ctx { +/* 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; + +/* I/O parameters */ + // if this is non-NULL, use libpng's normal IO on 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 + void *io_cb_arg; + + // error status + int io_error; +} render_t; + +/* + * Clear out the render context and set the mode + */ +int render_init (render_t *ctx, int mode); + +/* + * What kind of image to render, PNG or RAW? + */ +int render_set_mode (render_t *ctx, int mode); + +/* + * What size of image to render + */ +int render_set_size (render_t *ctx, u_int32_t img_w, u_int32_t img_h); + +/* + * Select what region to render + */ + +// the "full" mandelbrot region +#define REGION_X1 -2.0 +#define REGION_Y1 -1.5 +#define REGION_X2 1.0 +#define REGION_Y2 1.5 + +int render_region_full (render_t *ctx); +int render_region_raw (render_t *ctx, double x1, double y1, double x2, double y2); + +/* + * How to handle the I/O + */ +int render_io_custom (render_t *ctx, render_ctx_write_cb write_fn, render_ctx_flush_cb flush_fn, void *arg); +int render_io_stream (render_t *ctx, FILE *fh); + +/* + * Remote rendering + */ + +#pragma pack(push) +#pragma pack(1) + +struct render_cmd { + u_int32_t img_w; + u_int32_t img_h; + + double x1; + double y1; + double x2; + double y2; +}; + +#pragma pack(pop) + +#define RENDER_PORT 6159 +#define RENDER_CMD_SIZE sizeof(struct render_cmd) + +/* + * build the command to send for remote rendering + */ +int render_cmd_build (render_t *ctx, struct render_cmd *cmd); + +#endif /* RENDER_H */ diff -r 5b010627d7ed -r 6aa1a0d1f88d render_file.c --- a/render_file.c Fri May 30 14:24:23 2008 +0300 +++ b/render_file.c Sat May 31 02:22:27 2008 +0300 @@ -11,24 +11,17 @@ static int verbose; -int file_write (const unsigned char *data, size_t length, void *arg) { - size_t ret = fwrite(data, length, 1, (FILE *) arg); - - return (ret == 1) ? RENDER_CB_OK : RENDER_CB_ERR; -} +void render_local (int img_w, int img_h, FILE *output) { + render_t ctx; -void render_local (int img_w, int img_h, FILE *output) { - struct render_ctx ctx; - - render_ctx_set(&ctx, &file_write, NULL, output); + render_init(&ctx, RENDER_PNG); + render_set_size(&ctx, img_w, img_h); + render_region_full(&ctx); + render_io_stream(&ctx, output); double duration; - if (mandelbrot_render_full_timed( - &ctx, - img_w, img_h, - &duration - ) != MANDELBROT_OK) + if (mandelbrot_render_timed(&ctx, &duration) != MANDELBROT_OK) err_exit("mandelbrot_render_region failed"); if (verbose) @@ -36,11 +29,15 @@ } void render_remote (int img_w, int img_h, FILE *output, FILE *remote) { + render_t ctx; struct render_cmd cmd; - if (render_cmd_set_full(&cmd, img_w, img_h) != MANDELBROT_OK) { + render_init(&ctx, RENDER_PNG); + render_set_size(&ctx, img_w, img_h); + render_region_full(&ctx); + + if (render_cmd_build(&ctx, &cmd)) err_exit("mandelbrot_render_remote failed"); - } int ret = fwrite((void *) &cmd, sizeof(cmd), 1, remote); diff -r 5b010627d7ed -r 6aa1a0d1f88d render_node.c --- a/render_node.c Fri May 30 14:24:23 2008 +0300 +++ b/render_node.c Sat May 31 02:22:27 2008 +0300 @@ -7,36 +7,37 @@ #include "mandelbrot.h" #include "common.h" -int read_int (FILE *fh, u_int32_t *i) { - printf("read_int: fread(%p, %zu, 1, %p)... ", i, sizeof(*i), fh); - fflush(stdout); - int ret = fread(i, sizeof(*i), 1, fh); - printf("ok: %d\n", ret); +int my_fread(FILE *fh, void *ptr, size_t size) { + int ret = fread(ptr, size, 1, fh); if (ret == 0) { error("EOF"); return 0; + } else if (ret != 1) { - perror("read_int"); + perror("fread"); return 0; } + return 1; +} + +int read_byte (FILE *fh, u_int8_t *byte) { + return my_fread(fh, byte, sizeof(*byte)); +} + +int read_int (FILE *fh, u_int32_t *i) { + if (!my_fread(fh, i, sizeof(*i))) + return 0; + *i = ntohl(*i); - printf("read_int: %i\n", *i); - return 1; } int read_double (FILE *fh, double *dbl) { - int ret = fread(dbl, sizeof(*dbl), 1, fh); - - if (ret != 1) { - perror("read_double"); + if (!my_fread(fh, dbl, sizeof(*dbl))) return 0; - } - - printf("read_double: %f\n", *dbl); return 1; } @@ -46,10 +47,12 @@ FILE *fh = fdopen(sock, "r+"); // read the parameters + u_int8_t mode; u_int32_t img_w, img_h; double x1, y1, x2, y2; if ( + !read_byte(fh, &mode) || !read_int(fh, &img_w) || !read_int(fh, &img_h) || !read_double(fh, &x1) ||