render_multi.c
changeset 17 8e8b56b0e0f5
parent 16 50995bbe442a
child 18 86f2e5b7191b
--- 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;