iris: Don't auto-flush/dirty on transfer unmap for coherent buffers
[mesa.git] / src / gallium / drivers / iris / iris_resource.c
index ec59436df798fbfb77624d784e81992770c21c26..0cf4b91f927c09f6ac94ec4db0cc2e5b3d71ef5f 100644 (file)
@@ -132,7 +132,7 @@ select_best_modifier(struct gen_device_info *devinfo, enum pipe_format pfmt,
    return priority_to_modifier[prio];
 }
 
-static enum isl_surf_dim
+enum isl_surf_dim
 target_to_isl_surf_dim(enum pipe_texture_target target)
 {
    switch (target) {
@@ -381,9 +381,7 @@ static unsigned
 iris_get_aux_clear_color_state_size(struct iris_screen *screen)
 {
    const struct gen_device_info *devinfo = &screen->devinfo;
-   return
-      (devinfo->gen >= 10 ? screen->isl_dev.ss.clear_color_state_size :
-       (devinfo->gen >= 9 ? screen->isl_dev.ss.clear_value_size : 0));
+   return devinfo->gen >= 10 ? screen->isl_dev.ss.clear_color_state_size : 0;
 }
 
 /**
@@ -1249,6 +1247,7 @@ iris_map_copy_region(struct iris_transfer *map)
       .nr_samples = xfer->resource->nr_samples,
       .nr_storage_samples = xfer->resource->nr_storage_samples,
       .array_size = box->depth,
+      .format = res->internal_format,
    };
 
    if (xfer->resource->target == PIPE_BUFFER)
@@ -1258,22 +1257,6 @@ iris_map_copy_region(struct iris_transfer *map)
    else
       templ.target = PIPE_TEXTURE_2D;
 
-   /* Depth, stencil, and ASTC can't be linear surfaces, so we can't use
-    * xfer->resource->format directly.  Pick a bpb compatible format so
-    * resource creation will succeed; blorp_copy will override it anyway.
-    */
-   switch (util_format_get_blocksizebits(res->internal_format)) {
-   case 8:   templ.format = PIPE_FORMAT_R8_UINT;           break;
-   case 16:  templ.format = PIPE_FORMAT_R8G8_UINT;         break;
-   case 24:  templ.format = PIPE_FORMAT_R8G8B8_UINT;       break;
-   case 32:  templ.format = PIPE_FORMAT_R8G8B8A8_UINT;     break;
-   case 48:  templ.format = PIPE_FORMAT_R16G16B16_UINT;    break;
-   case 64:  templ.format = PIPE_FORMAT_R16G16B16A16_UINT; break;
-   case 96:  templ.format = PIPE_FORMAT_R32G32B32_UINT;    break;
-   case 128: templ.format = PIPE_FORMAT_R32G32B32A32_UINT; break;
-   default: unreachable("Invalid bpb");
-   }
-
    map->staging = iris_resource_create(pscreen, &templ);
    assert(map->staging);
 
@@ -1315,6 +1298,109 @@ get_image_offset_el(const struct isl_surf *surf, unsigned level, unsigned z,
    }
 }
 
+/**
+ * This function computes the tile_w (in bytes) and tile_h (in rows) of
+ * different tiling patterns.
+ */
+static void
+iris_resource_get_tile_dims(enum isl_tiling tiling, uint32_t cpp,
+                            uint32_t *tile_w, uint32_t *tile_h)
+{
+   switch (tiling) {
+   case ISL_TILING_X:
+      *tile_w = 512;
+      *tile_h = 8;
+      break;
+   case ISL_TILING_Y0:
+      *tile_w = 128;
+      *tile_h = 32;
+      break;
+   case ISL_TILING_LINEAR:
+      *tile_w = cpp;
+      *tile_h = 1;
+      break;
+   default:
+      unreachable("not reached");
+   }
+
+}
+
+/**
+ * This function computes masks that may be used to select the bits of the X
+ * and Y coordinates that indicate the offset within a tile.  If the BO is
+ * untiled, the masks are set to 0.
+ */
+static void
+iris_resource_get_tile_masks(enum isl_tiling tiling, uint32_t cpp,
+                             uint32_t *mask_x, uint32_t *mask_y)
+{
+   uint32_t tile_w_bytes, tile_h;
+
+   iris_resource_get_tile_dims(tiling, cpp, &tile_w_bytes, &tile_h);
+
+   *mask_x = tile_w_bytes / cpp - 1;
+   *mask_y = tile_h - 1;
+}
+
+/**
+ * Compute the offset (in bytes) from the start of the BO to the given x
+ * and y coordinate.  For tiled BOs, caller must ensure that x and y are
+ * multiples of the tile size.
+ */
+static uint32_t
+iris_resource_get_aligned_offset(const struct iris_resource *res,
+                                 uint32_t x, uint32_t y)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(res->surf.format);
+   unsigned cpp = fmtl->bpb / 8;
+   uint32_t pitch = res->surf.row_pitch_B;
+
+   switch (res->surf.tiling) {
+   default:
+      unreachable("not reached");
+   case ISL_TILING_LINEAR:
+      return y * pitch + x * cpp;
+   case ISL_TILING_X:
+      assert((x % (512 / cpp)) == 0);
+      assert((y % 8) == 0);
+      return y * pitch + x / (512 / cpp) * 4096;
+   case ISL_TILING_Y0:
+      assert((x % (128 / cpp)) == 0);
+      assert((y % 32) == 0);
+      return y * pitch + x / (128 / cpp) * 4096;
+   }
+}
+
+/**
+ * Rendering with tiled buffers requires that the base address of the buffer
+ * be aligned to a page boundary.  For renderbuffers, and sometimes with
+ * textures, we may want the surface to point at a texture image level that
+ * isn't at a page boundary.
+ *
+ * This function returns an appropriately-aligned base offset
+ * according to the tiling restrictions, plus any required x/y offset
+ * from there.
+ */
+uint32_t
+iris_resource_get_tile_offsets(const struct iris_resource *res,
+                               uint32_t level, uint32_t z,
+                               uint32_t *tile_x, uint32_t *tile_y)
+{
+   uint32_t x, y;
+   uint32_t mask_x, mask_y;
+
+   const struct isl_format_layout *fmtl = isl_format_get_layout(res->surf.format);
+   const unsigned cpp = fmtl->bpb / 8;
+
+   iris_resource_get_tile_masks(res->surf.tiling, cpp, &mask_x, &mask_y);
+   get_image_offset_el(&res->surf, level, z, &x, &y);
+
+   *tile_x = x & mask_x;
+   *tile_y = y & mask_y;
+
+   return iris_resource_get_aligned_offset(res, x & ~mask_x, y & ~mask_y);
+}
+
 /**
  * Get pointer offset into stencil buffer.
  *
@@ -1332,7 +1418,7 @@ get_image_offset_el(const struct isl_surf *surf, unsigned level, unsigned z,
  *    mesa: Fix return type of  _mesa_get_format_bytes() (#37351)
  */
 static intptr_t
-s8_offset(uint32_t stride, uint32_t x, uint32_t y, bool swizzled)
+s8_offset(uint32_t stride, uint32_t x, uint32_t y)
 {
    uint32_t tile_size = 4096;
    uint32_t tile_width = 64;
@@ -1357,17 +1443,6 @@ s8_offset(uint32_t stride, uint32_t x, uint32_t y, bool swizzled)
                +   2 * (byte_y % 2)
                +   1 * (byte_x % 2);
 
-   if (swizzled) {
-      /* adjust for bit6 swizzling */
-      if (((byte_x / 8) % 2) == 1) {
-         if (((byte_y / 8) % 2) == 0) {
-            u += 64;
-         } else {
-            u -= 64;
-         }
-      }
-   }
-
    return u;
 }
 
@@ -1378,7 +1453,6 @@ iris_unmap_s8(struct iris_transfer *map)
    const struct pipe_box *box = &xfer->box;
    struct iris_resource *res = (struct iris_resource *) xfer->resource;
    struct isl_surf *surf = &res->surf;
-   const bool has_swizzling = false;
 
    if (xfer->usage & PIPE_TRANSFER_WRITE) {
       uint8_t *untiled_s8_map = map->ptr;
@@ -1393,8 +1467,7 @@ iris_unmap_s8(struct iris_transfer *map)
             for (uint32_t x = 0; x < box->width; x++) {
                ptrdiff_t offset = s8_offset(surf->row_pitch_B,
                                             x0_el + box->x + x,
-                                            y0_el + box->y + y,
-                                            has_swizzling);
+                                            y0_el + box->y + y);
                tiled_s8_map[offset] =
                   untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x];
             }
@@ -1423,8 +1496,6 @@ iris_map_s8(struct iris_transfer *map)
    map->buffer = map->ptr = malloc(xfer->layer_stride * box->depth);
    assert(map->buffer);
 
-   const bool has_swizzling = false;
-
    /* One of either READ_BIT or WRITE_BIT or both is set.  READ_BIT implies no
     * INVALIDATE_RANGE_BIT.  WRITE_BIT needs the original values read in unless
     * invalidate is set, since we'll be writing the whole rectangle from our
@@ -1443,8 +1514,7 @@ iris_map_s8(struct iris_transfer *map)
             for (uint32_t x = 0; x < box->width; x++) {
                ptrdiff_t offset = s8_offset(surf->row_pitch_B,
                                             x0_el + box->x + x,
-                                            y0_el + box->y + y,
-                                            has_swizzling);
+                                            y0_el + box->y + y);
                untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x] =
                   tiled_s8_map[offset];
             }
@@ -1621,21 +1691,29 @@ iris_transfer_map(struct pipe_context *ctx,
       usage |= PIPE_TRANSFER_DISCARD_RANGE;
    }
 
-   bool map_would_stall = false;
-
-   if (resource->target != PIPE_BUFFER) {
-      iris_resource_access_raw(ice, &ice->batches[IRIS_BATCH_RENDER], res,
-                               level, box->z, box->depth,
-                               usage & PIPE_TRANSFER_WRITE);
-   }
-
    if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
        can_promote_to_async(res, box, usage)) {
       usage |= PIPE_TRANSFER_UNSYNCHRONIZED;
    }
 
+   bool need_resolve = false;
+   bool need_color_resolve = false;
+
+   if (resource->target != PIPE_BUFFER) {
+      bool need_hiz_resolve = iris_resource_level_has_hiz(res, level);
+
+      need_color_resolve =
+         (res->aux.usage == ISL_AUX_USAGE_CCS_D ||
+          res->aux.usage == ISL_AUX_USAGE_CCS_E) &&
+         iris_has_color_unresolved(res, level, 1, box->z, box->depth);
+
+      need_resolve = need_color_resolve || need_hiz_resolve;
+   }
+
+   bool map_would_stall = false;
+
    if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
-      map_would_stall = resource_is_busy(ice, res);
+      map_would_stall = need_resolve || resource_is_busy(ice, res);
 
       if (map_would_stall && (usage & PIPE_TRANSFER_DONTBLOCK) &&
                              (usage & PIPE_TRANSFER_MAP_DIRECTLY))
@@ -1683,21 +1761,29 @@ iris_transfer_map(struct pipe_context *ctx,
     * temporary and map that, to avoid the resolve.  (It might be better to
     * a tiled temporary and use the tiled_memcpy paths...)
     */
-   if (!(usage & PIPE_TRANSFER_DISCARD_RANGE) &&
-       res->aux.usage != ISL_AUX_USAGE_CCS_E &&
-       res->aux.usage != ISL_AUX_USAGE_CCS_D) {
+   if (!(usage & PIPE_TRANSFER_DISCARD_RANGE) && !need_color_resolve)
+      no_gpu = true;
+
+   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
+   if (fmtl->txc == ISL_TXC_ASTC)
       no_gpu = true;
-   }
 
    if ((map_would_stall || res->aux.usage == ISL_AUX_USAGE_CCS_E) && !no_gpu) {
-      /* If we need a synchronous mapping and the resource is busy,
-       * we copy to/from a linear temporary buffer using the GPU.
+      /* If we need a synchronous mapping and the resource is busy, or needs
+       * resolving, we copy to/from a linear temporary buffer using the GPU.
        */
       map->batch = &ice->batches[IRIS_BATCH_RENDER];
       map->blorp = &ice->blorp;
       iris_map_copy_region(map);
    } else {
-      /* Otherwise we're free to map on the CPU.  Flush if needed. */
+      /* Otherwise we're free to map on the CPU. */
+
+      if (need_resolve) {
+         iris_resource_access_raw(ice, &ice->batches[IRIS_BATCH_RENDER], res,
+                                  level, box->z, box->depth,
+                                  usage & PIPE_TRANSFER_WRITE);
+      }
+
       if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
          for (int i = 0; i < IRIS_BATCH_COUNT; i++) {
             if (iris_batch_references(&ice->batches[i], res->bo))
@@ -1761,7 +1847,8 @@ iris_transfer_unmap(struct pipe_context *ctx, struct pipe_transfer *xfer)
    struct iris_context *ice = (struct iris_context *)ctx;
    struct iris_transfer *map = (void *) xfer;
 
-   if (!(xfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) {
+   if (!(xfer->usage & (PIPE_TRANSFER_FLUSH_EXPLICIT |
+                        PIPE_TRANSFER_COHERENT))) {
       struct pipe_box flush_box = {
          .x = 0, .y = 0, .z = 0,
          .width  = xfer->box.width,