virgl: fix some false positives in transfers_overlap
authorChia-I Wu <olvaffe@gmail.com>
Mon, 8 Jul 2019 23:12:29 +0000 (16:12 -0700)
committerChia-I Wu <olvaffe@gmail.com>
Tue, 9 Jul 2019 21:26:55 +0000 (14:26 -0700)
Rewrite the function and check z/depth more carefully.  We
intentionally avoid u_box_test_intersection_2d because it returns
true when two boxes touch but do not intersect and can be confusing.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
Reviewed-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
src/gallium/drivers/virgl/virgl_transfer_queue.c

index 970ee986cc118c6fa26c070adcccb86c64933d33..53fa6760e3b12429f3b050469ee823aeb7a29852 100644 (file)
@@ -53,6 +53,90 @@ struct list_iteration_args
    enum virgl_transfer_queue_lists type;
 };
 
+static int
+transfer_dim(const struct virgl_transfer *xfer)
+{
+   switch (xfer->base.resource->target) {
+   case PIPE_BUFFER:
+   case PIPE_TEXTURE_1D:
+      return 1;
+   case PIPE_TEXTURE_2D:
+   case PIPE_TEXTURE_RECT:
+      return 2;
+   default:
+      return 3;
+   }
+}
+
+static void
+box_min_max(const struct pipe_box *box, int dim, int *min, int *max)
+{
+   switch (dim) {
+   case 0:
+      if (box->width > 0) {
+         *min = box->x;
+         *max = box->x + box->width;
+      } else {
+         *max = box->x;
+         *min = box->x + box->width;
+      }
+      break;
+   case 1:
+      if (box->height > 0) {
+         *min = box->y;
+         *max = box->y + box->height;
+      } else {
+         *max = box->y;
+         *min = box->y + box->height;
+      }
+      break;
+   default:
+      if (box->depth > 0) {
+         *min = box->z;
+         *max = box->z + box->depth;
+      } else {
+         *max = box->z;
+         *min = box->z + box->depth;
+      }
+      break;
+   }
+}
+
+static bool
+transfer_overlap(const struct virgl_transfer *xfer,
+                 const struct virgl_hw_res *hw_res,
+                 unsigned level,
+                 const struct pipe_box *box,
+                 bool include_touching)
+{
+   const int dim_count = transfer_dim(xfer);
+
+   if (xfer->hw_res != hw_res || xfer->base.level != level)
+      return false;
+
+   for (int dim = 0; dim < dim_count; dim++) {
+      int xfer_min;
+      int xfer_max;
+      int box_min;
+      int box_max;
+
+      box_min_max(&xfer->base.box, dim, &xfer_min, &xfer_max);
+      box_min_max(box, dim, &box_min, &box_max);
+
+      if (include_touching) {
+         /* touching is considered overlapping */
+         if (xfer_min > box_max || xfer_max < box_min)
+            return false;
+      } else {
+         /* touching is not considered overlapping */
+         if (xfer_min >= box_max || xfer_max <= box_min)
+            return false;
+      }
+   }
+
+   return true;
+}
+
 static bool transfers_intersect(struct virgl_transfer *queued,
                                 struct virgl_transfer *current)
 {
@@ -68,33 +152,8 @@ static bool transfers_intersect(struct virgl_transfer *queued,
 static bool transfers_overlap(struct virgl_transfer *queued,
                               struct virgl_transfer *current)
 {
-   boolean tmp;
-
-   if (queued->hw_res != current->hw_res)
-      return false;
-
-   if (queued->base.level != current->base.level)
-      return false;
-
-   if (queued->base.box.z != current->base.box.z)
-      return true;
-
-   if (queued->base.box.depth != 1 || current->base.box.depth != 1)
-      return true;
-
-   /*
-    * Special case for boxes with [x: 0, width: 1] and [x: 1, width: 1].
-    */
-   if (queued->base.resource->target == PIPE_BUFFER) {
-      if (queued->base.box.x + queued->base.box.width == current->base.box.x)
-         return false;
-
-      if (current->base.box.x + current->base.box.width == queued->base.box.x)
-         return false;
-   }
-
-   tmp = u_box_test_intersection_2d(&queued->base.box, &current->base.box);
-   return (tmp == TRUE);
+   return transfer_overlap(queued, current->hw_res, current->base.level,
+         &current->base.box, false);
 }
 
 static void set_true(UNUSED struct virgl_transfer_queue *queue,