diff options
author | Jordan Justen <[email protected]> | 2016-11-07 14:06:56 -0800 |
---|---|---|
committer | Jordan Justen <[email protected]> | 2016-12-07 09:00:49 -0800 |
commit | 12e0a6e25967e097f9d18e9ee25b30248f617b28 (patch) | |
tree | a01bc531611bcbdff9b896c5f4e1b2e7ba179d40 | |
parent | b74d4f6ca02715470d8f7726d19aff342873dbc6 (diff) |
intel/blorp_blit: Split blorp blits if they are too large
We rename do_blorp_blit() to try_blorp_blit(), and add a return error
if the surface size for the blit is too large. Now, do_blorp_blit() is
rewritten to try to split the blit into smaller operations if
try_blorp_blit() fails.
Note: In this commit, try_blorp_blit() will always attempt to blit and
never return an error, which matches the previous behavior. We will
enable the size checking and splitting in a future commit.
The motivation for this splitting is that in some cases when we
flatten an image, it's dimensions grow, and this can then exceed the
programmable hardware limits. An example is w-tiled+MSAA blits.
v2:
* Use double instead of float. (Jason)
Signed-off-by: Jordan Justen <[email protected]>
Reviewed-by: Jason Ekstrand <[email protected]>
-rw-r--r-- | src/intel/blorp/blorp_blit.c | 102 |
1 files changed, 96 insertions, 6 deletions
diff --git a/src/intel/blorp/blorp_blit.c b/src/intel/blorp/blorp_blit.c index fffc03e3554..05977f06b6c 100644 --- a/src/intel/blorp/blorp_blit.c +++ b/src/intel/blorp/blorp_blit.c @@ -1493,11 +1493,21 @@ struct blt_coords { struct blt_axis x, y; }; -static void -do_blorp_blit(struct blorp_batch *batch, - struct blorp_params *params, - struct brw_blorp_blit_prog_key *wm_prog_key, - const struct blt_coords *coords) +enum blit_shrink_status { + BLIT_NO_SHRINK = 0, + BLIT_WIDTH_SHRINK = 1, + BLIT_HEIGHT_SHRINK = 2, +}; + +/* Try to blit. If the surface parameters exceed the size allowed by hardware, + * then enum blit_shrink_status will be returned. If BLIT_NO_SHRINK is + * returned, then the blit was successful. + */ +static enum blit_shrink_status +try_blorp_blit(struct blorp_batch *batch, + struct blorp_params *params, + struct brw_blorp_blit_prog_key *wm_prog_key, + const struct blt_coords *coords) { const struct gen_device_info *devinfo = batch->blorp->isl_dev->info; @@ -1700,7 +1710,87 @@ do_blorp_blit(struct blorp_batch *batch, brw_blorp_get_blit_kernel(batch->blorp, params, wm_prog_key); - batch->blorp->exec(batch, params); + unsigned result = 0; + + if (result == 0) { + batch->blorp->exec(batch, params); + } + + return result; +} + +/* Adjust split blit source coordinates for the current destination + * coordinates. + */ +static void +adjust_split_source_coords(const struct blt_axis *orig, + struct blt_axis *split_coords, + double scale) +{ + /* When scale is greater than 0, then we are growing from the start, so + * src0 uses delta0, and src1 uses delta1. When scale is less than 0, the + * source range shrinks from the end. In that case src0 is adjusted by + * delta1, and src1 is adjusted by delta0. + */ + double delta0 = scale * (split_coords->dst0 - orig->dst0); + double delta1 = scale * (split_coords->dst1 - orig->dst1); + split_coords->src0 = orig->src0 + (scale >= 0.0 ? delta0 : delta1); + split_coords->src1 = orig->src1 + (scale >= 0.0 ? delta1 : delta0); +} + +static void +do_blorp_blit(struct blorp_batch *batch, + struct blorp_params *params, + struct brw_blorp_blit_prog_key *wm_prog_key, + const struct blt_coords *orig) +{ + struct blt_coords split_coords = *orig; + double w = orig->x.dst1 - orig->x.dst0; + double h = orig->y.dst1 - orig->y.dst0; + double x_scale = (orig->x.src1 - orig->x.src0) / w; + double y_scale = (orig->y.src1 - orig->y.src0) / h; + if (orig->x.mirror) + x_scale = -x_scale; + if (orig->y.mirror) + y_scale = -y_scale; + + bool x_done, y_done; + do { + enum blit_shrink_status result = + try_blorp_blit(batch, params, wm_prog_key, &split_coords); + + if (result & BLIT_WIDTH_SHRINK) { + w /= 2.0; + assert(w >= 1.0); + split_coords.x.dst1 = MIN2(split_coords.x.dst0 + w, orig->x.dst1); + adjust_split_source_coords(&orig->x, &split_coords.x, x_scale); + } + if (result & BLIT_HEIGHT_SHRINK) { + h /= 2.0; + assert(h >= 1.0); + split_coords.y.dst1 = MIN2(split_coords.y.dst0 + h, orig->y.dst1); + adjust_split_source_coords(&orig->y, &split_coords.y, y_scale); + } + + if (result != 0) + continue; + + y_done = (orig->y.dst1 - split_coords.y.dst1 < 0.5); + x_done = y_done && (orig->x.dst1 - split_coords.x.dst1 < 0.5); + if (x_done) { + break; + } else if (y_done) { + split_coords.x.dst0 += w; + split_coords.x.dst1 = MIN2(split_coords.x.dst0 + w, orig->x.dst1); + split_coords.y.dst0 = orig->y.dst0; + split_coords.y.dst1 = MIN2(split_coords.y.dst0 + h, orig->y.dst1); + adjust_split_source_coords(&orig->x, &split_coords.x, x_scale); + } else { + split_coords.y.dst0 += h; + split_coords.y.dst1 = MIN2(split_coords.y.dst0 + h, orig->y.dst1); + adjust_split_source_coords(&orig->y, &split_coords.y, y_scale); + } + } while (true); } void |