terom@17: #include terom@17: #include terom@17: terom@17: #include "common.h" terom@17: #include "render_struct.h" terom@17: #include "render_slices_struct.h" terom@17: #include "render_slices.h" terom@17: terom@17: void render_slices_free (struct render_slices *ctx) { terom@17: render_slices_deinit(ctx); terom@17: terom@17: if (ctx->owned_by_me) terom@17: free(ctx); terom@17: } terom@17: terom@19: void render_slices_deinit (struct render_slices *ctx) { terom@19: if (ctx->rowbuf) { terom@19: free(ctx->rowbuf); terom@19: ctx->rowbuf = NULL; terom@19: } terom@17: terom@17: render_png_deinit(&ctx->png_info); terom@17: } terom@17: terom@17: #define HALF(a, b) (( a + b) / 2) terom@17: terom@17: int render_slices_init (struct render_slices *ctx, struct render *render) { terom@17: // initialize the slices terom@17: // for now, just split it in half into two render_ts terom@17: ctx->slices[0].info.index = 0; terom@17: ctx->slices[0].info.render_info = &ctx->slices[0].render_info; terom@17: ctx->slices[0].self = ctx; terom@17: ctx->slices[0].row_offset = 0; terom@17: terom@17: ctx->slices[1].info.index = 1; terom@17: ctx->slices[1].info.render_info = &ctx->slices[1].render_info; terom@17: ctx->slices[1].self = ctx; terom@17: ctx->slices[1].row_offset = render->img_w / 2; terom@17: terom@17: ctx->num_slices = 2; terom@17: ctx->render_row = 0; terom@17: ctx->done_row = -1; terom@17: terom@17: assert(RENDER_SLICES_MAX >= 2); terom@22: terom@22: // should probably use memcpy instead... terom@17: if ( terom@23: render_init (&ctx->slices[0].render_info) terom@23: || render_init (&ctx->slices[1].render_info) terom@23: terom@23: || render_set_mode (&ctx->slices[0].render_info, RENDER_RAW) terom@23: || render_set_mode (&ctx->slices[1].render_info, RENDER_RAW) terom@17: terom@22: || render_set_size (&ctx->slices[0].render_info, render->img_w, render->img_h) terom@22: || render_set_size (&ctx->slices[1].render_info, render->img_w, render->img_h) terom@17: terom@22: || render_region_raw (&ctx->slices[0].render_info, render->x1, render->y1, render->x2, render->y2) terom@22: || render_region_raw (&ctx->slices[1].render_info, render->x1, render->y1, render->x2, render->y2) terom@17: ) terom@17: ERROR("render_{init,set_size,set_region_raw}"); terom@22: terom@22: // set the offsets terom@22: ctx->slices[0].render_info.img_left = 0; terom@22: ctx->slices[0].render_info.img_right = render->img_w / 2; terom@22: ctx->slices[1].render_info.img_left = render->img_w / 2; terom@22: ctx->slices[1].render_info.img_right = render->img_w; terom@22: terom@17: // allocate the rowbuf terom@17: if (!(ctx->rowbuf = malloc(render->img_w * 2))) terom@17: ERROR("malloc"); terom@17: terom@17: // update the slice_buf pointers terom@17: ctx->rows[0] = ctx->rowbuf; terom@17: ctx->rows[1] = ctx->rowbuf + render->img_w; terom@17: ctx->slices[0].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[0].row_offset; terom@17: ctx->slices[1].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[1].row_offset; terom@17: terom@17: // png info terom@17: if (render_png_init(&ctx->png_info, render)) terom@17: ERROR("render_png_init"); terom@17: terom@17: // great success! terom@17: return 0; terom@17: terom@17: error: terom@17: render_slices_deinit(ctx); terom@17: return -1; terom@17: } terom@17: terom@17: struct render_slices *render_slices_alloc (struct render *render) { terom@17: struct render_slices *ctx = NULL; terom@17: terom@17: // allocate it terom@17: if (!(ctx = calloc(1, sizeof(*ctx)))) terom@17: ERROR("calloc"); terom@17: terom@17: // mark it for free()ing terom@17: ctx->owned_by_me = 1; terom@17: terom@17: // initialize it terom@17: if (render_slices_init(ctx, render)) terom@17: goto error; terom@17: terom@17: return ctx; terom@17: terom@17: error : terom@17: render_slices_free(ctx); terom@17: return NULL; terom@17: } terom@17: terom@17: int render_slices_get_count (struct render_slices *ctx) { terom@17: return ctx->num_slices; terom@17: } terom@17: terom@17: struct render_slice_info *render_slices_get_slice_info (struct render_slices *ctx, int index) { terom@17: assert(index >= 0 && index < ctx->num_slices); terom@17: terom@17: return &ctx->slices[index].info; terom@17: } terom@17: terom@17: int render_slices_segment_done (struct render_slices *ctx, int index) { terom@17: assert(index >= 0 && index < ctx->num_slices); terom@19: assert(ctx->render_row >= 0); terom@19: assert(ctx->segments_done >= 0 && ctx->segments_done < ctx->num_slices); terom@17: terom@18: // our return status terom@19: int i, status = 0; terom@18: terom@19: // is this row now complete? terom@19: if (++ctx->segments_done == ctx->num_slices) { terom@17: // the row is complete terom@18: ctx->segments_done = 0; terom@18: terom@18: // once we fill up a row we can always call process_row terom@18: status |= SLICE_PROCESS_ROW; terom@17: terom@19: // is the other row already rendered? terom@17: if (ctx->done_row < 0) { terom@19: // yes, point the done_row at this row, point the render buffers to the unused row terom@17: ctx->done_row = ctx->render_row; terom@17: ctx->render_row = (ctx->render_row == 0 ? 1 : 0); terom@17: terom@19: // can now continue rendering as well as call process_row terom@19: status |= SLICE_CONTINUE; terom@19: terom@18: // update the remaining render buffers terom@17: for (i = 0; i < ctx->num_slices; i++) { terom@17: ctx->slices[i].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[i].row_offset; terom@17: } terom@17: terom@17: } else { terom@17: // cannot continue rendering, need to have process_row complete first terom@19: terom@19: ctx->render_row = -1; terom@19: } terom@17: terom@17: terom@17: } else { terom@17: // the row is not complete, do not render the next segment, do not call process_row terom@17: terom@17: } terom@18: terom@18: return status; terom@17: } terom@17: terom@17: int render_slices_process_row (struct render_slices *ctx) { terom@17: assert(ctx->done_row >= 0); terom@17: terom@19: int i; terom@19: terom@17: // pass the data to render_png, this results in calls to _render_multi_png_data terom@17: if (render_png_row(&ctx->png_info, ctx->rows[ctx->done_row])) terom@17: ERROR("render_png_row"); terom@17: terom@19: // is the other row still in the process of being assembled? terom@19: if (ctx->render_row == -1) { terom@19: // no, both rows were full terom@19: ctx->render_row = ctx->done_row; terom@19: ctx->done_row = (ctx->done_row == 0 ? 1 : 0); terom@19: terom@19: // update the remaining render buffers terom@19: for (i = 0; i < ctx->num_slices; i++) { terom@19: ctx->slices[i].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[i].row_offset; terom@19: } terom@19: terom@19: // you can call me again, but also segment_done terom@19: return SLICE_PROCESS_ROW | SLICE_CONTINUE; terom@19: terom@19: } else { terom@19: // yes, so that still needs to be finished terom@19: ctx->done_row = -1; terom@19: terom@19: if (ctx->segments_done == 0) { terom@19: // that row is empty, then we can continue terom@19: return SLICE_CONTINUE; terom@19: terom@19: } else { terom@19: // that row is partially built, so some segment is still on the way - don't resume the other slices until that's arrived! terom@19: return 0; terom@19: } terom@19: } terom@17: terom@17: error: terom@17: // user needs to deinit/free us terom@17: return -1; terom@17: } terom@17: terom@18: int render_slices_done (struct render_slices *ctx) { terom@18: // finish off render_png terom@18: if (render_png_done(&ctx->png_info)) terom@19: goto error; terom@18: terom@18: return 0; terom@17: terom@18: error: terom@18: render_slices_free(ctx); terom@18: return -1; terom@18: } terom@19: