intel: revive intel_layout_get_slice_tile_offset()

Surface Base Address are required to be page-aligned when the surface is
tiled.  When one wants to directly point to a single miplevel or a single
array layer, one has to leverage X Offset and Y Offset to keep Surface Base
Address page-aligned.  This function can return valid

  (Surface Base Address, X Offset, Y Offset)

for any given subresource.
diff --git a/icd/intel/layout.c b/icd/intel/layout.c
index 205b0b5..ccc11a8 100644
--- a/icd/intel/layout.c
+++ b/icd/intel/layout.c
@@ -1329,3 +1329,87 @@
 
    return true;
 }
+
+/**
+ * Return the offset (in bytes) to a slice within the bo.
+ *
+ * The returned offset is aligned to tile size.  Since slices are not
+ * guaranteed to start at tile boundaries, the X and Y offsets (in pixels)
+ * from the tile origin to the slice are also returned.  X offset is always a
+ * multiple of 4 and Y offset is always a multiple of 2.
+ */
+unsigned
+intel_layout_get_slice_tile_offset(const struct intel_layout *layout,
+                                   unsigned level, unsigned slice,
+                                   unsigned *x_offset, unsigned *y_offset)
+{
+   unsigned tile_w, tile_h, tile_size, row_size;
+   unsigned tile_offset, x, y;
+
+   /* see the Sandy Bridge PRM, volume 1 part 2, page 24 */
+
+   switch (layout->tiling) {
+   case INTEL_TILING_NONE:
+      /* W-tiled */
+      if (layout->format.numericFormat == XGL_NUM_FMT_DS &&
+          layout->format.channelFormat == XGL_CH_FMT_R8) {
+         tile_w = 64;
+         tile_h = 64;
+      }
+      else {
+         tile_w = 1;
+         tile_h = 1;
+      }
+      break;
+   case INTEL_TILING_X:
+      tile_w = 512;
+      tile_h = 8;
+      break;
+   case INTEL_TILING_Y:
+      tile_w = 128;
+      tile_h = 32;
+      break;
+   default:
+      assert(!"unknown tiling");
+      tile_w = 1;
+      tile_h = 1;
+      break;
+   }
+
+   tile_size = tile_w * tile_h;
+   row_size = layout->bo_stride * tile_h;
+
+   intel_layout_get_slice_pos(layout, level, slice, &x, &y);
+   /* in bytes */
+   intel_layout_pos_to_mem(layout, x, y, &x, &y);
+   tile_offset = row_size * (y / tile_h) + tile_size * (x / tile_w);
+
+   /*
+    * Since tex->bo_stride is a multiple of tile_w, slice_offset should be
+    * aligned at this point.
+    */
+   assert(tile_offset % tile_size == 0);
+
+   /*
+    * because of the possible values of align_i and align_j in
+    * tex_layout_init_alignments(), x_offset is guaranteed to be a multiple of
+    * 4 and y_offset is guaranteed to be a multiple of 2.
+    */
+   if (x_offset) {
+      /* in pixels */
+      x = (x % tile_w) / layout->block_size * layout->block_width;
+      assert(x % 4 == 0);
+
+      *x_offset = x;
+   }
+
+   if (y_offset) {
+      /* in pixels */
+      y = (y % tile_h) * layout->block_height;
+      assert(y % 2 == 0);
+
+      *y_offset = y;
+   }
+
+   return tile_offset;
+}