render_multi.c
changeset 13 ee426f453cf5
parent 11 082bfaf38cf0
child 15 e7f0697814dc
equal deleted inserted replaced
12:43297144f196 13:ee426f453cf5
     1 
     1 #include <stdlib.h>
     2 
     2 #include <assert.h>
       
     3 
       
     4 #include "common.h"
       
     5 #include "render_internal.h"
     3 #include "render_multi.h"
     6 #include "render_multi.h"
       
     7 #include "render_remote.h"
     4 #include "remote_node.h"
     8 #include "remote_node.h"
     5 
     9 #include "render_png.h"
     6 
    10 
     7 struct render_multi {
    11 struct render_multi {
     8     // these are used as arguments to render_remote
    12     // these are used as arguments to render_remote
     9     struct render_sub_ctx {
    13     struct render_multi_sub {
    10         // our offset in the list
    14         // our offset in the list
    11         int index;
    15         int index;
    12 
    16 
    13         // the remote_render_ctx
    17         // the remote_render_ctx
    14         struct remote_render_ctx *remote_render;
    18         struct remote_render_ctx *remote_render;
    15         
    19         
    16         // a pointer to ourself
    20         // a pointer to ourself
    17         struct render_multi *self;
    21         struct render_multi *self;
    18 
    22 
       
    23         // if the render connection is marked as done without us having read all the data, move it from render_remote's buffers into here
       
    24         struct evbuffer *in_buf;
       
    25 
    19         // _render_sent called for this?
    26         // _render_sent called for this?
    20         int render_sent;
    27         int render_sent;
       
    28 
       
    29         // our offset into the row, static
       
    30         size_t row_offset;
       
    31 
       
    32         // how wide our slice is, static
       
    33         size_t slice_width;
       
    34 
       
    35         // how many bytes we have already written into the current row
       
    36         size_t col;
       
    37 
       
    38         // is this render op done?
       
    39         int render_done;
    21     } remote_renders[RENDER_MULTI_NODES_MAX];
    40     } remote_renders[RENDER_MULTI_NODES_MAX];
    22     
    41     
    23     // how many remote_renders we have
    42     // how many remote_renders we have
    24     int remote_render_count;
    43     int remote_render_count;
       
    44 
       
    45     // have we called cb_sent?
       
    46     int have_sent;
       
    47 
       
    48     // the png thing
       
    49     struct render_png *png_info;
       
    50 
       
    51     // our pixel data row
       
    52     unsigned char *rowbuf;
       
    53 
       
    54     // buffer render_png output in this
       
    55     struct evbuffer *out_buf;
    25 
    56 
    26     // our own callbacks that we call
    57     // our own callbacks that we call
    27     void (*cb_sent)(void *arg);
    58     void (*cb_sent)(void *arg);
    28     void (*cb_data)(struct evbuffer *buf, void *arg);
    59     void (*cb_data)(struct evbuffer *buf, void *arg);
    29     void (*cb_done)(void *arg);
    60     void (*cb_done)(void *arg);
    30     void (*cb_fail)(void *arg);
    61     void (*cb_fail)(void *arg);
    31 
    62 
    32     void *cb_arg;
    63     void *cb_arg;
    33 
       
    34 };
    64 };
    35 
    65 
    36 // our render_remote callbacks
    66 #define FAIL_PARTIAL 0x01
    37 void _render_sent (void *arg) {
    67 #define FAIL_SILENT 0x02
    38     struct render_sub_ctx *ctx, *ctx2 = arg;
    68 
       
    69 // prototypes
       
    70 static void _render_multi_do_free (struct render_multi *ctx);
       
    71 static void _render_multi_do_sent (struct render_multi *ctx);
       
    72 static void _render_multi_do_done (struct render_multi *ctx);
       
    73 static void _render_multi_do_fail (struct render_multi *ctx, int flags);
       
    74 
       
    75 /*
       
    76  * Actually free the request. Should be de-initialized (either _render_multi_error, or _render_done when this is called
       
    77  */
       
    78 static void _render_multi_do_free (struct render_multi *ctx) {
       
    79     if (!ctx)
       
    80         return;
       
    81     
       
    82     int i;
       
    83     for (i = 0; i < ctx->remote_render_count; i++) {
       
    84         if (ctx->remote_renders[i].in_buf) {
       
    85             evbuffer_free(ctx->remote_renders[i].in_buf);
       
    86             ctx->remote_renders[i].in_buf = NULL;
       
    87         }
       
    88     }
       
    89 
       
    90     if (ctx->rowbuf) {
       
    91         free(ctx->rowbuf);
       
    92         ctx->rowbuf = NULL;
       
    93     }
       
    94 
       
    95     if (ctx->out_buf) {
       
    96         evbuffer_free(ctx->out_buf);
       
    97         ctx->out_buf = NULL;
       
    98     }
       
    99 
       
   100     free(ctx);
       
   101 }
       
   102 
       
   103 // the request has been sent
       
   104 static void _render_multi_do_sent (struct render_multi *ctx) {
       
   105     int i;
       
   106 
       
   107     // check that all the remote_renders have indeed been sent
       
   108     for (i = 0; i < ctx->remote_render_count; i++) {
       
   109         assert(ctx->remote_renders[i].render_sent);
       
   110     }
       
   111 
       
   112     // assert the callbacks are still valid
       
   113     assert(ctx->cb_sent && ctx->cb_fail && ctx->cb_done);
       
   114 
       
   115     // call cb_sent and then invalidate it
       
   116     ctx->cb_sent(ctx->cb_arg);
       
   117     ctx->cb_sent = NULL;
       
   118     ctx->have_sent = 1;
       
   119     
       
   120     // we're going to always have the PNG header data buffered at this point, so give that to the user right away
       
   121     assert(evbuffer_get_length(ctx->out_buf) > 0);
       
   122 
       
   123     ctx->cb_data(ctx->out_buf, ctx->cb_arg);
       
   124 
       
   125     // ok
       
   126     return;
       
   127 }
       
   128 
       
   129 // the request compelted normally
       
   130 static void _render_multi_do_done (struct render_multi *ctx) {
       
   131     int i;
       
   132 
       
   133     // check that all the remote_renders are indeed complete
       
   134     for (i = 0; i < ctx->remote_render_count; i++) {
       
   135         assert(ctx->remote_renders[i].remote_render == NULL);
       
   136         assert(ctx->remote_renders[i].col == 0);
       
   137     }
       
   138 
       
   139     // finish the png_info
       
   140     if (render_png_done(ctx->png_info)) {
       
   141         // don't free it twice, though...
       
   142         ctx->png_info = NULL;
       
   143 
       
   144         ERROR("render_png_done");
       
   145     }
       
   146 
       
   147     ctx->png_info = NULL;
       
   148 
       
   149     // check that both callbacks are still valid
       
   150     assert(ctx->cb_fail && ctx->cb_done);
       
   151 
       
   152     // call cb_done and then invalidate it
       
   153     ctx->cb_done(ctx->cb_arg);
       
   154     ctx->cb_fail = NULL;
       
   155 
       
   156     // free ourself
       
   157     _render_multi_do_free(ctx);
       
   158     
       
   159     // ok
       
   160     return;
       
   161 
       
   162 error:    
       
   163     /* O_o */
       
   164     _render_multi_do_fail(ctx, FAIL_PARTIAL);
       
   165 }
       
   166 
       
   167 // the request completed abnormally. Flags:
       
   168 //  FAIL_SILENT     - don't call cb_fail
       
   169 //  FAIL_PARTIAL    - assume png_info may be NULL
       
   170 static void _render_multi_do_fail (struct render_multi *ctx, int flags) {
       
   171     int i;
       
   172 
       
   173     // cancel any in-progress remote renders
       
   174     for (i = 0; i < ctx->remote_render_count; i++)
       
   175         if (ctx->remote_renders[i].remote_render) {
       
   176             render_remote_cancel(ctx->remote_renders[i].remote_render);
       
   177             ctx->remote_renders[i].remote_render = NULL;
       
   178         }
       
   179     
       
   180     if (!(flags & FAIL_PARTIAL) || ctx->png_info) {
       
   181         // abort the render_png
       
   182         render_png_abort(ctx->png_info);
       
   183         ctx->png_info = NULL;
       
   184     }
       
   185     
       
   186     // check that both callbacks are still valid
       
   187     assert(ctx->cb_fail && ctx->cb_done);
       
   188     
       
   189     if (!(flags & FAIL_SILENT)) {
       
   190         // call cb_fail and then invalidate it
       
   191         ctx->cb_fail(ctx->cb_arg);
       
   192     }
       
   193 
       
   194     ctx->cb_fail = NULL;
       
   195 
       
   196     // free ourselves
       
   197     _render_multi_do_free(ctx);
       
   198 }
       
   199 
       
   200 /*
       
   201  * One of the remote render commands has succesfully been sent.
       
   202  *
       
   203  * Once all of these commands have been sent, invoke our cb_sent.
       
   204  */
       
   205 static void _render_multi_sent (void *arg) {
       
   206     struct render_multi_sub *ctx = arg;
    39 
   207 
    40     ctx->render_sent = 1;
   208     ctx->render_sent = 1;
    41 
   209 
    42     // have all render_sub_ctxs been sent?
   210     // have all render_sub_ctxs been sent?
    43     int i;
   211     int i;
    44     for (i = 0; i < ctx->self->remote_render_count; i++) {
   212     for (i = 0; i < ctx->self->remote_render_count; i++) {
    45         if (!ctx->self->remote_renders[i].render_sent)
   213         if (!ctx->self->remote_renders[i].render_sent)
    46             break;
   214             break;
    47     }
   215     }
    48     
   216     
       
   217     // did we loop through all of them?
    49     if (i == ctx->self->remote_render_count) {
   218     if (i == ctx->self->remote_render_count) {
    50         // call cb_sent
   219         // tell our user
    51         ctx->self->cb_sent(ctx->self->cb_arg);
   220         _render_multi_do_sent(ctx->self);
    52     }
   221     }
    53 }
   222 }
    54 
   223 
    55 void _render_data (struct evbuffer *buf, void *arg) {
   224 /*
    56 
   225  * We have received data from a single render node.
    57 }
   226  *
    58 
   227  * Move the data into the row buffer if there's space in it, otherwise
    59 void _render_done (void *arg) {
   228  * leave it inside the buffer.
    60 
   229  *
    61 }
   230  * If this fills up our slice, check and see if the entire row is now full. If
    62 
   231  * it is, pass the row to render_png_row, clear out the col values, and call
    63 void _render_fail (void *arg) {
   232  * render_remote_shake for each remote render
    64 
   233  */
       
   234 static void _render_multi_data (struct evbuffer *buf, void *arg) {
       
   235     struct render_multi_sub *ctx = arg;
       
   236 
       
   237     assert(ctx->col <= ctx->slice_width);
       
   238 
       
   239     // are we being called from _render_multi_done?
       
   240     if (ctx->render_done && ctx->in_buf == NULL) {
       
   241         // move all the data into our own buffer
       
   242         if (!(ctx->in_buf = evbuffer_new()))
       
   243             ERROR("evbuffer_new");
       
   244 
       
   245         if (evbuffer_add_buffer(ctx->in_buf, buf))
       
   246             ERROR("evbuffer_add_buffer");
       
   247         
       
   248         // don't do anything else
       
   249         return;
       
   250     }
       
   251 
       
   252     // is our slice full?
       
   253     if (ctx->col == ctx->slice_width) {
       
   254         // don't care for new data
       
   255         return;
       
   256     }
       
   257     
       
   258     // read new data into our slice
       
   259 //    printf("rowbuf + %4d : %d");
       
   260     ctx->col += evbuffer_remove(buf, ctx->self->rowbuf + ctx->row_offset + ctx->col, ctx->slice_width - ctx->col);
       
   261 
       
   262     // is our slice full now?
       
   263     if (ctx->col == ctx->slice_width) {
       
   264         // is the row complete now?
       
   265         int i;
       
   266         for (i = 0; i < ctx->self->remote_render_count; i++) {
       
   267             if (ctx->self->remote_renders[i].col < ctx->self->remote_renders[i].slice_width)
       
   268                 break;
       
   269         }
       
   270         
       
   271         // are they all full?
       
   272         if (i == ctx->self->remote_render_count) {
       
   273             // pass the data to render_png, this results in calls to _render_multi_png_data
       
   274             if (render_png_row(ctx->self->png_info, ctx->self->rowbuf))
       
   275                 ERROR("render_png_row");
       
   276 
       
   277             // clear the col values
       
   278             for (i = 0; i < ctx->self->remote_render_count; i++) {
       
   279                 ctx->self->remote_renders[i].col = 0;
       
   280             }
       
   281             
       
   282             // shake the buffers
       
   283             // XXX: this will result in recursion
       
   284             for (i = 0; i < ctx->self->remote_render_count; i++) {
       
   285                 if (ctx->self->remote_renders[i].remote_render) {
       
   286                     if (render_remote_shake(ctx->self->remote_renders[i].remote_render))
       
   287                         ERROR("render_remote_shake");
       
   288                 } else {
       
   289                     // already disconnected, use in_buf instead
       
   290                     assert(ctx->self->remote_renders[i].in_buf);
       
   291 
       
   292                     // call it directly...
       
   293                     _render_multi_data(ctx->self->remote_renders[i].in_buf, &ctx->self->remote_renders[i]);
       
   294                 }
       
   295             }
       
   296         }
       
   297     }
       
   298 
       
   299     return;
       
   300 
       
   301 error:
       
   302     _render_multi_do_fail(ctx->self, 0);
       
   303 }
       
   304 
       
   305 /*
       
   306  * We fed a row of pixels into render_png, and this PNG data came out.
       
   307  *
       
   308  * We need to pass it back to our caller
       
   309  */
       
   310 static int _render_multi_png_data (const unsigned char *data, size_t length, void *arg) {
       
   311     struct render_multi *ctx = arg;
       
   312 
       
   313     // XXX: avoid these many data copies?
       
   314     if (evbuffer_add(ctx->out_buf, data, length))
       
   315         ERROR("evbuffer_add");
       
   316     
       
   317     // only call the data cb if we've already called cb_sent
       
   318     if (ctx->have_sent)
       
   319         ctx->cb_data(ctx->out_buf, ctx->cb_arg);
       
   320     
       
   321     // ok
       
   322     return 0;
       
   323 
       
   324 error:
       
   325     // don't do any failing here, this will return control to a _render_* function that will handle it
       
   326     return -1;
       
   327 }
       
   328 
       
   329 /*
       
   330  * The render node has rendered everything that it needs to render. Our slice
       
   331  * of the last row should be full (or empty) now. If all the remote_renders are
       
   332  * done, we can call render_png_done and then cb_done.
       
   333  */
       
   334 static void _render_multi_done (void *arg) {
       
   335     struct render_multi_sub *ctx = arg;
       
   336  
       
   337     // mark it as done
       
   338     ctx->render_done = 1;
       
   339 
       
   340     // shake out the rest of the data as needed, as render_multi won't keep it anymore
       
   341     render_remote_shake(ctx->remote_render);
       
   342    
       
   343     // invalidate this ctx's remote render
       
   344     ctx->remote_render = NULL;
       
   345 
       
   346     // is the data incomplete?
       
   347     if (!(ctx->col == ctx->slice_width || ctx->col == 0))
       
   348         ERROR("incomplete data for slice %d: %d/%d bytes", ctx->index, ctx->col, ctx->slice_width);
       
   349 
       
   350     // are all of them done?
       
   351     int i;
       
   352     for (i = 0; i < ctx->self->remote_render_count; i++) {
       
   353         if (!ctx->self->remote_renders[i].render_done)
       
   354             break;
       
   355     }
       
   356     
       
   357     // are they all done?
       
   358     if (i == ctx->self->remote_render_count) {
       
   359         // finish it off
       
   360         _render_multi_do_done(ctx->self);
       
   361     }
       
   362 
       
   363     // ok, wait for the rest to complete
       
   364     return;
       
   365     
       
   366 error:
       
   367     _render_multi_do_fail(ctx->self, 0);
       
   368 }
       
   369 
       
   370 /*
       
   371  * One render node failed, abort the whole thing
       
   372  */
       
   373 static void _render_multi_fail (void *arg) {
       
   374     struct render_multi_sub *ctx = arg;
       
   375 
       
   376     // invalidate this ctx's remote render
       
   377     ctx->remote_render = NULL;
       
   378 
       
   379     _render_multi_do_fail(ctx->self, 0);
    65 }
   380 }
    66 
   381 
    67 #define ROUND_DOWN(dividend, divisor) ((dividend) / (divisor))
   382 #define ROUND_DOWN(dividend, divisor) ((dividend) / (divisor))
    68 #define ROUND_UP(dividend, divisor) (((dividend) / (divisor)) + ((dividend) % (divisor)))
   383 #define ROUND_UP(dividend, divisor) (((dividend) / (divisor)) + ((dividend) % (divisor)))
    69 
   384 
    70 #define HALF(a, b) (( a + b) / 2)
   385 #define HALF(a, b) (( a + b) / 2)
    71 
   386 
    72 struct render_multi *render_multi (
   387 struct render_multi *render_multi (
    73         render_t *render_ctx,               // what to render
   388         struct render *render,               // what to render
    74         struct remote_pool *render_pool,    // what render pool to use
   389         struct remote_pool *pool_info,    // what render pool to use
    75         void (*cb_sent)(void *arg),
   390         void (*cb_sent)(void *arg),
    76         void (*cb_data)(struct evbuffer *buf, void *arg),
   391         void (*cb_data)(struct evbuffer *buf, void *arg),
    77         void (*cb_done)(void *arg),
   392         void (*cb_done)(void *arg),
    78         void (*cb_fail)(void *arg),
   393         void (*cb_fail)(void *arg),
    79         void *cb_arg
   394         void *cb_arg
    80 ) {
   395 ) {
    81     struct render_multi *ctx = NULL;
   396     struct render_multi *ctx = NULL;
    82     render_t r_left, r_right;
   397     struct render r_left, r_right;
    83 
   398     
       
   399     // alloc the render_multi
       
   400     ctx = calloc(1, sizeof(struct render_multi));
       
   401 
       
   402     if (!ctx)
       
   403         ERROR("calloc");
       
   404 
       
   405     // init the remote_render
    84     // for now, just split it in half into two render_ts
   406     // for now, just split it in half into two render_ts
       
   407     ctx->remote_renders[0].index = 0;
       
   408     ctx->remote_renders[0].self = ctx;
       
   409     ctx->remote_renders[0].slice_width = render->img_w / 2;
       
   410     ctx->remote_renders[0].row_offset = 0;
       
   411 
       
   412     ctx->remote_renders[1].index = 1;
       
   413     ctx->remote_renders[1].self = ctx;
       
   414     ctx->remote_renders[1].slice_width = render->img_w / 2 + render->img_w % 2;
       
   415     ctx->remote_renders[1].row_offset = render->img_w / 2;
       
   416 
       
   417     ctx->remote_render_count = 2;
       
   418 
    85     assert(RENDER_MULTI_NODES_MAX >= 2);
   419     assert(RENDER_MULTI_NODES_MAX >= 2);
    86 
   420 
    87     if (
   421     if (
    88             render_init(&r_left, RENDER_RAW)
   422             render_init(&r_left, RENDER_RAW)
    89          || render_init(&r_right, RENDER_RAW)
   423          || render_init(&r_right, RENDER_RAW)
    90          || render_set_size(&r_left, render_ctx->img_w / 2, render_ctx->img_h)
   424          || render_set_size(&r_left, ctx->remote_renders[0].slice_width, render->img_h)
    91          || render_set_size(&r_right, render_ctx->img_w / 2 +  render_ctx->img_w % 2, render_ctx->img_h)
   425          || render_set_size(&r_right, ctx->remote_renders[1].slice_width, render->img_h)
    92          || render_set_region_raw(&r_left, render_ctx->x1, render_ctx->y1, HALF(render_ctx->x1, render_ctx->x2), render_ctx->y2)
   426          || render_region_raw(&r_left, render->x1, render->y1, HALF(render->x1, render->x2), render->y2)
    93          || render_set_region_raw(&r_right, HALF(render_ctx->x1, render_ctx->x2), render_ctx->y1, render_ctx->x2, render_ctx->y2)
   427          || render_region_raw(&r_right, HALF(render->x1, render->x2), render->y1, render->x2, render->y2)
    94     )
   428     )
    95         ERROR("render_{init,set_size,set_region_raw}");
   429         ERROR("render_{init,set_size,set_region_raw}");
    96     
   430             
    97     // alloc the render_multi
       
    98     ctx = calloc(1, sizeof(struct render_multi));
       
    99 
       
   100     if (!ctx)
       
   101         ERROR("calloc");
       
   102         
       
   103     // store the provided callback functions
   431     // store the provided callback functions
   104     ctx->cb_sent = cb_sent;
   432     ctx->cb_sent = cb_sent;
   105     ctx->cb_data = cb_data;
   433     ctx->cb_data = cb_data;
   106     ctx->cb_done = cb_done;
   434     ctx->cb_done = cb_done;
   107     ctx->cb_fail = cb_fail;
   435     ctx->cb_fail = cb_fail;
   108     ctx->cb_arg = cb_arg;
   436     ctx->cb_arg = cb_arg;
   109 
   437 
       
   438     // our rowbuf
       
   439     if (!(ctx->rowbuf = malloc(render->img_w)))
       
   440         ERROR("malloc");
       
   441 
       
   442     // store our render_png callbacks, must be before png_info
       
   443     if (render_io_custom(render, &_render_multi_png_data, NULL, ctx))
       
   444         ERROR("render_io_custom");
       
   445 
       
   446     // evbuffer, must be before png_info
       
   447     if (!(ctx->out_buf = evbuffer_new()))
       
   448         ERROR("evbuffer_new");
       
   449 
       
   450     // png info
       
   451     if (!(ctx->png_info = render_png_init(render)))
       
   452         ERROR("render_png_init");
       
   453 
   110     // pull two nodes from the pool
   454     // pull two nodes from the pool
   111     struct remote_node *node_left, *node_right;
   455     struct remote_node *node_left, *node_right;
   112 
   456 
   113     if (
   457     if (
   114             !(node_left = remote_pool_get(pool_info))
   458             !(node_left = remote_pool_get(pool_info))
   115          || !(node_right = remote_pool_get(pool_info))
   459          || !(node_right = remote_pool_get(pool_info))
   116     )
   460     )
   117         ERROR("remote_pool_get");
   461         ERROR("remote_pool_get");
   118     
   462     
   119     // init the remote_render
       
   120     ctx->remote_renders[0].index = 0;
       
   121     ctx->remote_renders[0].self = &ctx
       
   122     ctx->remote_renders[1].index = 1;
       
   123     ctx->remote_renders[1].self = &ctx
       
   124     ctx->remote_render_count = 2;
       
   125 
       
   126     // the two render_remote calls
   463     // the two render_remote calls
   127     if (
   464     if (
   128             !(ctx->remote_renders[0].remote_render = render_remote(&r_left, node_left, 
   465             !(ctx->remote_renders[0].remote_render = render_remote(&r_left, node_left, 
   129                 &_render_sent, &_render_data, &_render_done, &_render_fail, &ctx->remote_renders[0]))
   466                 &_render_multi_sent, &_render_multi_data, &_render_multi_done, &_render_multi_fail, &ctx->remote_renders[0]))
   130          || !(ctx->remote_renders[1].remote_render = render_remote(&r_right, node_right,
   467          || !(ctx->remote_renders[1].remote_render = render_remote(&r_right, node_right,
   131                 &_render_sent, &_render_data, &_render_done, &_render_fail, &ctx->remote_renders[1]))
   468                 &_render_multi_sent, &_render_multi_data, &_render_multi_done, &_render_multi_fail, &ctx->remote_renders[1]))
   132     )
   469     )
   133         ERROR("render_remote");
   470         ERROR("render_remote");
   134     
   471     
   135     // I guess that's a succesfull start now
   472     // I guess that's a succesfull start now
       
   473     return ctx;
       
   474 
       
   475 error:
       
   476     _render_multi_do_fail(ctx, FAIL_SILENT | FAIL_PARTIAL);
       
   477 
       
   478     return NULL;
       
   479 }
       
   480 
       
   481 void render_multi_cancel (struct render_multi *ctx) {
       
   482     _render_multi_do_fail(ctx, FAIL_SILENT);
       
   483 }
       
   484 
       
   485 int render_multi_set_recv (struct render_multi *ctx, size_t recv_threshold, size_t unread_buffer) {
   136     return 0;
   486     return 0;
   137 
   487 }
   138 error:
   488 
   139     free(ctx);
   489 int render_multi_shake (struct render_multi *ctx) {
   140 
   490     // call the data cb
   141     return -1;
   491     ctx->cb_data(ctx->out_buf, ctx->cb_arg);
   142 }
   492 
   143 
   493     return 0;
       
   494 }