[Mesa-dev] [PATCH 2/6] intel/blorp_blit: Split blorp blits if they are too large

Jordan Justen jordan.l.justen at intel.com
Wed Nov 23 03:03:59 UTC 2016


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.

Signed-off-by: Jordan Justen <jordan.l.justen at intel.com>
---
 src/intel/blorp/blorp_blit.c | 93 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 87 insertions(+), 6 deletions(-)

diff --git a/src/intel/blorp/blorp_blit.c b/src/intel/blorp/blorp_blit.c
index 24c4fd6..caa3e33 100644
--- a/src/intel/blorp/blorp_blit.c
+++ b/src/intel/blorp/blorp_blit.c
@@ -1530,11 +1530,18 @@ 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)
+#define BLIT_WIDTH_TOO_LARGE  1
+#define BLIT_HEIGHT_TOO_LARGE 2
+
+/* Try to blit. If the surface parameters exceed the size allowed by hardware,
+ * then a bitmask of BLIT_WIDTH_TOO_LARGE and BLIT_HEIGHT_TOO_LARGE will be
+ * returned. If 0 is returned, then the blit was successful.
+ */
+static unsigned
+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;
 
@@ -1737,7 +1744,81 @@ 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_coords(const struct blt_axis *orig,
+                    struct blt_axis *split_coords,
+                    float scale)
+{
+   float delta0 = scale * (split_coords->dst0 - orig->dst0);
+   float 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;
+   float w = orig->x.dst1 - orig->x.dst0;
+   float h = orig->y.dst1 - orig->y.dst0;
+   float x_scale = (orig->x.src1 - orig->x.src0) / w;
+   float 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 {
+      unsigned result =
+         try_blorp_blit(batch, params, wm_prog_key, &split_coords);
+
+      if (result & BLIT_WIDTH_TOO_LARGE) {
+         w /= 2.0;
+         assert(w >= 1.0);
+         split_coords.x.dst1 = MIN2(split_coords.x.dst0 + w, orig->x.dst1);
+         adjust_split_coords(&orig->x, &split_coords.x, x_scale);
+      }
+      if (result & BLIT_HEIGHT_TOO_LARGE) {
+         h /= 2.0;
+         assert(h >= 1.0);
+         split_coords.y.dst1 = MIN2(split_coords.y.dst0 + h, orig->y.dst1);
+         adjust_split_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;
+         adjust_split_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_coords(&orig->y, &split_coords.y, y_scale);
+      }
+   } while (true);
 }
 
 void
-- 
2.10.2



More information about the mesa-dev mailing list