summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJordan Justen <[email protected]>2016-11-07 14:06:56 -0800
committerJordan Justen <[email protected]>2016-12-07 09:00:49 -0800
commit12e0a6e25967e097f9d18e9ee25b30248f617b28 (patch)
treea01bc531611bcbdff9b896c5f4e1b2e7ba179d40
parentb74d4f6ca02715470d8f7726d19aff342873dbc6 (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.c102
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