render_slices.c
changeset 17 8e8b56b0e0f5
child 18 86f2e5b7191b
--- /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;
+}   
+
+