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 } |