isl: Implement isl_surf_init() for gen4-gen9
authorChad Versace <chad.versace@intel.com>
Sat, 14 Nov 2015 00:01:35 +0000 (16:01 -0800)
committerChad Versace <chad.versace@intel.com>
Thu, 3 Dec 2015 23:26:11 +0000 (15:26 -0800)
This is a big code push. The patch is about 3000 lines.

Function isl_surf_init() calculates the physical layout of a surface.

The implementation is "complete" (but untested) for all 1D, 2D, 3D, and
cube surfaces for gen4 through gen9, except:
    * gen9 1D surfaces
    * gen9 Ys multisampled surfaces
    * auxiliary surfaces (such as hiz, mcs, ccs)

14 files changed:
src/vulkan/Makefile.am
src/vulkan/isl.c
src/vulkan/isl.h
src/vulkan/isl_gen4.c [new file with mode: 0644]
src/vulkan/isl_gen4.h [new file with mode: 0644]
src/vulkan/isl_gen6.c [new file with mode: 0644]
src/vulkan/isl_gen6.h [new file with mode: 0644]
src/vulkan/isl_gen7.c [new file with mode: 0644]
src/vulkan/isl_gen7.h [new file with mode: 0644]
src/vulkan/isl_gen8.c [new file with mode: 0644]
src/vulkan/isl_gen8.h [new file with mode: 0644]
src/vulkan/isl_gen9.c [new file with mode: 0644]
src/vulkan/isl_gen9.h [new file with mode: 0644]
src/vulkan/isl_priv.h [new file with mode: 0644]

index 24391eafc0b40c91dec80ba100b855f6515bbdd0..fd74393be952f1b4e1fca1bc51437137aff8e053 100644 (file)
@@ -92,7 +92,18 @@ VULKAN_SOURCES =                                        \
        anv_wsi.c                                       \
        anv_wsi_x11.c                                   \
        isl.c                                           \
-       isl_format_layout.c
+       isl_format_layout.c                             \
+       isl_gen4.c                                      \
+       isl_gen4.h                                      \
+       isl_gen6.c                                      \
+       isl_gen6.h                                      \
+       isl_gen7.c                                      \
+       isl_gen7.h                                      \
+       isl_gen8.c                                      \
+       isl_gen8.h                                      \
+       isl_gen9.c                                      \
+       isl_gen9.h                                      \
+       $(NULL)
 
 BUILT_SOURCES =                                         \
        anv_entrypoints.h                               \
index 65b696a1003bbaa191c603b92c33bb3929e207c7..41b842dd79b54edd1abc26c0af2eb884484afcd6 100644 (file)
 
 #include <assert.h>
 
-#include "mesa/main/imports.h"
-
 #include "isl.h"
+#include "isl_gen4.h"
+#include "isl_gen6.h"
+#include "isl_gen7.h"
+#include "isl_gen8.h"
+#include "isl_gen9.h"
+#include "isl_priv.h"
 
-/**
- * Log base 2, rounding towards zero.
- */
-static inline uint32_t
-isl_log2u(uint32_t n)
+void PRINTFLIKE(3, 4) UNUSED
+__isl_finishme(const char *file, int line, const char *fmt, ...)
 {
-   assert(n != 0);
-   return 31 - __builtin_clz(n);
+   va_list ap;
+   char buf[512];
+
+   va_start(ap, fmt);
+   vsnprintf(buf, sizeof(buf), fmt, ap);
+   va_end(ap);
+
+   fprintf(stderr, "%s:%d: FINISHME: %s\n", file, line, buf);
 }
 
 void
@@ -42,50 +49,997 @@ isl_device_init(struct isl_device *dev,
                 const struct brw_device_info *info)
 {
    dev->info = info;
+   dev->use_separate_stencil = ISL_DEV_GEN(dev) >= 6;
+
+   /* The ISL_DEV macros may be defined in the CFLAGS, thus hardcoding some
+    * device properties at buildtime. Verify that the macros with the device
+    * properties chosen during runtime.
+    */
+   assert(ISL_DEV_GEN(dev) == dev->info->gen);
+   assert(ISL_DEV_USE_SEPARATE_STENCIL(dev) == dev->use_separate_stencil);
+
+   /* Did we break hiz or stencil? */
+   if (ISL_DEV_USE_SEPARATE_STENCIL(dev))
+      assert(info->has_hiz_and_separate_stencil);
+   if (info->must_use_separate_stencil)
+      assert(ISL_DEV_USE_SEPARATE_STENCIL(dev));
+}
+
+bool
+isl_format_has_sint_channel(enum isl_format fmt)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(fmt);
+
+   return fmtl->channels.r.type == ISL_SINT ||
+          fmtl->channels.g.type == ISL_SINT ||
+          fmtl->channels.b.type == ISL_SINT ||
+          fmtl->channels.a.type == ISL_SINT ||
+          fmtl->channels.l.type == ISL_SINT ||
+          fmtl->channels.i.type == ISL_SINT ||
+          fmtl->channels.p.type == ISL_SINT ||
+          fmtl->channels.g.type == ISL_SINT;
 }
 
 /**
- * The returned extent's units are (width=bytes, height=rows).
+ * @param[out] info is written only on success
  */
+bool
+isl_tiling_get_info(const struct isl_device *dev,
+                    enum isl_tiling tiling,
+                    uint32_t format_block_size,
+                    struct isl_tile_info *tile_info)
+{
+   const uint32_t bs = format_block_size;
+   uint32_t width, height;
+
+   assert(bs > 0);
+
+   switch (tiling) {
+   case ISL_TILING_LINEAR:
+      width = 1;
+      height = 1;
+      break;
+
+   case ISL_TILING_X:
+      width = 1 << 9;
+      height = 1 << 3;
+      break;
+
+   case ISL_TILING_Y0:
+      width = 1 << 7;
+      height = 1 << 5;
+      break;
+
+   case ISL_TILING_W:
+      /* XXX: Should W tile be same as Y? */
+      width = 1 << 6;
+      height = 1 << 6;
+      break;
+
+   case ISL_TILING_Yf:
+   case ISL_TILING_Ys: {
+      if (ISL_DEV_GEN(dev) < 9)
+         return false;
+
+      if (!isl_is_pow2(bs))
+         return false;
+
+      bool is_Ys = tiling == ISL_TILING_Ys;
+
+      width = 1 << (6 + (ffs(bs) / 2) + (2 * is_Ys));
+      height = 1 << (6 - (ffs(bs) / 2) + (2 * is_Ys));
+      break;
+   }
+   } /* end switch */
+
+   *tile_info = (struct isl_tile_info) {
+      .tiling = tiling,
+      .width = width,
+      .height = height,
+      .size = width * height,
+   };
+
+   return true;
+}
+
 void
 isl_tiling_get_extent(const struct isl_device *dev,
                       enum isl_tiling tiling,
-                      uint32_t cpp,
+                      uint32_t format_block_size,
                       struct isl_extent2d *e)
 {
-   static const struct isl_extent2d legacy_extents[] = {
-      [ISL_TILING_LINEAR]  = {   1,   1 },
-      [ISL_TILING_X]       = { 512,   8 },
-      [ISL_TILING_Y0]      = { 128,  32 },
-      [ISL_TILING_W]       = { 128,  32 },
+   struct isl_tile_info tile_info;
+   isl_tiling_get_info(dev, tiling, format_block_size, &tile_info);
+   *e = isl_extent2d(tile_info.width, tile_info.height);
+}
+
+/**
+ * @param[out] tiling is set only on success
+ */
+bool
+isl_surf_choose_tiling(const struct isl_device *dev,
+                       const struct isl_surf_init_info *restrict info,
+                       enum isl_tiling *tiling)
+{
+   isl_tiling_flags_t tiling_flags = info->tiling_flags;
+
+   if (ISL_DEV_GEN(dev) >= 7) {
+      gen7_filter_tiling(dev, info, &tiling_flags);
+   } else {
+      isl_finishme("%s: gen%u", __func__, ISL_DEV_GEN(dev));
+      gen7_filter_tiling(dev, info, &tiling_flags);
+   }
+
+   #define CHOOSE(__tiling) \
+      do { \
+         if (tiling_flags & (1u << (__tiling))) { \
+            *tiling = (__tiling); \
+            return true; \
+          } \
+      } while (0)
+
+   /* Of the tiling modes remaining, choose the one that offers the best
+    * performance.
+    */
+   CHOOSE(ISL_TILING_Ys);
+   CHOOSE(ISL_TILING_Yf);
+   CHOOSE(ISL_TILING_Y0);
+   CHOOSE(ISL_TILING_X);
+   CHOOSE(ISL_TILING_W);
+   CHOOSE(ISL_TILING_LINEAR);
+
+   #undef CHOOSE
+
+   /* No tiling mode accomodates the inputs. */
+   return false;
+}
+
+static bool
+isl_choose_msaa_layout(const struct isl_device *dev,
+                 const struct isl_surf_init_info *info,
+                 enum isl_tiling tiling,
+                 enum isl_msaa_layout *msaa_layout)
+{
+   if (ISL_DEV_GEN(dev) >= 8) {
+      return gen8_choose_msaa_layout(dev, info, tiling, msaa_layout);
+   } else if (ISL_DEV_GEN(dev) >= 7) {
+      return gen7_choose_msaa_layout(dev, info, tiling, msaa_layout);
+   } else if (ISL_DEV_GEN(dev) >= 6) {
+      return gen6_choose_msaa_layout(dev, info, tiling, msaa_layout);
+   } else {
+      return gen4_choose_msaa_layout(dev, info, tiling, msaa_layout);
+   }
+}
+
+static void
+isl_msaa_interleaved_scale_px_to_sa(uint32_t samples,
+                                    uint32_t *width, uint32_t *height)
+{
+   assert(isl_is_pow2(samples));
+
+   /* From the Broadwell PRM >> Volume 5: Memory Views >> Computing Mip Level
+    * Sizes (p133):
+    *
+    *    If the surface is multisampled and it is a depth or stencil surface
+    *    or Multisampled Surface StorageFormat in SURFACE_STATE is
+    *    MSFMT_DEPTH_STENCIL, W_L and H_L must be adjusted as follows before
+    *    proceeding: [...]
+    */
+   *width = isl_align(*width, 2) << ((ffs(samples) - 0) / 2);
+   *height = isl_align(*height, 2) << ((ffs(samples) - 1) / 2);
+}
+
+static enum isl_array_pitch_span
+isl_choose_array_pitch_span(const struct isl_device *dev,
+                            const struct isl_surf_init_info *restrict info,
+                            enum isl_dim_layout dim_layout,
+                            const struct isl_extent4d *phys_level0_sa)
+{
+   switch (dim_layout) {
+   case ISL_DIM_LAYOUT_GEN9_1D:
+      if (ISL_DEV_GEN(dev) >= 9)
+         isl_finishme("%s:%s: [SKL+] 1d surface layout", __FILE__, __func__);
+      /* fallthrough */
+
+   case ISL_DIM_LAYOUT_GEN4_2D:
+      if (ISL_DEV_GEN(dev) >= 8) {
+         /* QPitch becomes programmable in Broadwell. So choose the
+          * most compact QPitch possible in order to conserve memory.
+          *
+          * From the Broadwell PRM >> Volume 2d: Command Reference: Structures
+          * >> RENDER_SURFACE_STATE Surface QPitch (p325):
+          *
+          *    - Software must ensure that this field is set to a value
+          *      sufficiently large such that the array slices in the surface
+          *      do not overlap. Refer to the Memory Data Formats section for
+          *      information on how surfaces are stored in memory.
+          *
+          *    - This field specifies the distance in rows between array
+          *      slices.  It is used only in the following cases:
+          *
+          *          - Surface Array is enabled OR
+          *          - Number of Mulitsamples is not NUMSAMPLES_1 and
+          *            Multisampled Surface Storage Format set to MSFMT_MSS OR
+          *          - Surface Type is SURFTYPE_CUBE
+          */
+         return ISL_ARRAY_PITCH_SPAN_COMPACT;
+      } else if (ISL_DEV_GEN(dev) >= 7) {
+         /* Note that Ivybridge introduces
+          * RENDER_SURFACE_STATE.SurfaceArraySpacing, which provides the
+          * driver more control over the QPitch.
+          */
+
+         if (phys_level0_sa->array_len == 1) {
+            /* The hardware will never use the QPitch. So choose the most
+             * compact QPitch possible in order to conserve memory.
+             */
+            return ISL_ARRAY_PITCH_SPAN_COMPACT;
+         }
+
+         if (isl_surf_usage_is_depth_or_stencil(info->usage)) {
+            /* From the Ivybridge PRM >> Volume 1 Part 1: Graphics Core >>
+             * Section 6.18.4.7: Surface Arrays (p112):
+             *
+             *    If Surface Array Spacing is set to ARYSPC_FULL (note that
+             *    the depth buffer and stencil buffer have an implied value of
+             *    ARYSPC_FULL):
+             */
+            return ISL_ARRAY_PITCH_SPAN_COMPACT;
+         }
+
+         if (info->levels == 1) {
+            /* We are able to set RENDER_SURFACE_STATE.SurfaceArraySpacing
+             * to ARYSPC_LOD0.
+             */
+            return ISL_ARRAY_PITCH_SPAN_COMPACT;
+         }
+
+         return ISL_ARRAY_PITCH_SPAN_FULL;
+      } else if ((ISL_DEV_GEN(dev) == 5 || ISL_DEV_GEN(dev) == 6) &&
+                 ISL_DEV_USE_SEPARATE_STENCIL(dev) &&
+                 isl_surf_usage_is_stencil(info->usage)) {
+         /* [ILK-SNB] Errata from the Sandy Bridge PRM >> Volume 4 Part 1:
+          * Graphics Core >> Section 7.18.3.7: Surface Arrays:
+          *
+          *    The separate stencil buffer does not support mip mapping, thus
+          *    the storage for LODs other than LOD 0 is not needed.
+          */
+         assert(info->levels == 1);
+         assert(phys_level0_sa->array_len == 1);
+         return ISL_ARRAY_PITCH_SPAN_COMPACT;
+      } else {
+         if ((ISL_DEV_GEN(dev) == 5 || ISL_DEV_GEN(dev) == 6) &&
+             ISL_DEV_USE_SEPARATE_STENCIL(dev) &&
+             isl_surf_usage_is_stencil(info->usage)) {
+            /* [ILK-SNB] Errata from the Sandy Bridge PRM >> Volume 4 Part 1:
+             * Graphics Core >> Section 7.18.3.7: Surface Arrays:
+             *
+             *    The separate stencil buffer does not support mip mapping,
+             *    thus the storage for LODs other than LOD 0 is not needed.
+             */
+            assert(info->levels == 1);
+            assert(phys_level0_sa->array_len == 1);
+            return ISL_ARRAY_PITCH_SPAN_COMPACT;
+         }
+
+         if (phys_level0_sa->array_len == 1) {
+            /* The hardware will never use the QPitch. So choose the most
+             * compact QPitch possible in order to conserve memory.
+             */
+            return ISL_ARRAY_PITCH_SPAN_COMPACT;
+         }
+
+         return ISL_ARRAY_PITCH_SPAN_FULL;
+      }
+
+   case ISL_DIM_LAYOUT_GEN4_3D:
+      /* The hardware will never use the QPitch. So choose the most
+       * compact QPitch possible in order to conserve memory.
+       */
+      return ISL_ARRAY_PITCH_SPAN_COMPACT;
+   }
+
+   unreachable("bad isl_dim_layout");
+   return ISL_ARRAY_PITCH_SPAN_FULL;
+}
+
+static void
+isl_choose_lod_alignment_el(const struct isl_device *dev,
+                            const struct isl_surf_init_info *restrict info,
+                            enum isl_tiling tiling,
+                            enum isl_msaa_layout msaa_layout,
+                            struct isl_extent3d *lod_align_el)
+{
+   if (ISL_DEV_GEN(dev) >= 9) {
+      gen9_choose_lod_alignment_el(dev, info, tiling, msaa_layout,
+                                   lod_align_el);
+   } else if (ISL_DEV_GEN(dev) >= 8) {
+      gen8_choose_lod_alignment_el(dev, info, tiling, msaa_layout,
+                                   lod_align_el);
+   } else if (ISL_DEV_GEN(dev) >= 7) {
+      gen7_choose_lod_alignment_el(dev, info, tiling, msaa_layout,
+                                   lod_align_el);
+   } else if (ISL_DEV_GEN(dev) >= 6) {
+      gen6_choose_lod_alignment_el(dev, info, tiling, msaa_layout,
+                                   lod_align_el);
+   } else {
+      gen4_choose_lod_alignment_el(dev, info, tiling, msaa_layout,
+                                   lod_align_el);
+   }
+}
+
+static enum isl_dim_layout
+isl_surf_choose_dim_layout(const struct isl_device *dev,
+                           enum isl_surf_dim logical_dim)
+{
+   if (ISL_DEV_GEN(dev) >= 9) {
+      switch (logical_dim) {
+      case ISL_SURF_DIM_1D:
+         return ISL_DIM_LAYOUT_GEN9_1D;
+      case ISL_SURF_DIM_2D:
+      case ISL_SURF_DIM_3D:
+         return ISL_DIM_LAYOUT_GEN4_2D;
+      }
+   } else {
+      switch (logical_dim) {
+      case ISL_SURF_DIM_1D:
+      case ISL_SURF_DIM_2D:
+         return ISL_DIM_LAYOUT_GEN4_2D;
+      case ISL_SURF_DIM_3D:
+         return ISL_DIM_LAYOUT_GEN4_3D;
+      }
+   }
+
+   unreachable("bad isl_surf_dim");
+   return ISL_DIM_LAYOUT_GEN4_2D;
+}
+
+/**
+ * Calculate the physical extent of the surface's first level, in units of
+ * surface samples.
+ */
+static void
+isl_calc_phys_level0_extent_sa(const struct isl_device *dev,
+                               const struct isl_surf_init_info *restrict info,
+                               enum isl_dim_layout dim_layout,
+                               enum isl_tiling tiling,
+                               enum isl_msaa_layout msaa_layout,
+                               struct isl_extent4d *phys_level0_sa)
+{
+   if (isl_format_is_yuv(info->format))
+      isl_finishme("%s:%s: YUV format", __FILE__, __func__);
+
+   switch (info->dim) {
+   case ISL_SURF_DIM_1D:
+      assert(info->height == 1);
+      assert(info->depth == 1);
+      assert(info->samples == 1);
+
+      switch (dim_layout) {
+      case ISL_DIM_LAYOUT_GEN4_3D:
+         unreachable("bad isl_dim_layout");
+
+      case ISL_DIM_LAYOUT_GEN9_1D:
+         if (ISL_DEV_GEN(dev) >= 9)
+            isl_finishme("%s:%s: [SKL+] 1d surface layout", __FILE__, __func__);
+         /* fallthrough */
+
+      case ISL_DIM_LAYOUT_GEN4_2D:
+         *phys_level0_sa = (struct isl_extent4d) {
+            .w = info->width,
+            .h = 1,
+            .d = 1,
+            .a = info->array_len,
+         };
+         break;
+      }
+      break;
+
+   case ISL_SURF_DIM_2D:
+      assert(dim_layout == ISL_DIM_LAYOUT_GEN4_2D);
+
+      if (tiling == ISL_TILING_Ys && info->samples > 1)
+         isl_finishme("%s:%s: multisample TileYs layout", __FILE__, __func__);
+
+      switch (msaa_layout) {
+      case ISL_MSAA_LAYOUT_NONE:
+         assert(info->depth == 1);
+         assert(info->samples == 1);
+
+         *phys_level0_sa = (struct isl_extent4d) {
+            .w = info->width,
+            .h = info->height,
+            .d = 1,
+            .a = info->array_len,
+         };
+         break;
+
+      case ISL_MSAA_LAYOUT_ARRAY:
+         assert(info->depth == 1);
+         assert(info->array_len == 1);
+         assert(!isl_format_is_compressed(info->format));
+
+         *phys_level0_sa = (struct isl_extent4d) {
+            .w = info->width,
+            .h = info->height,
+            .d = 1,
+            .a = info->samples,
+         };
+         break;
+
+      case ISL_MSAA_LAYOUT_INTERLEAVED:
+         assert(info->depth == 1);
+         assert(info->array_len == 1);
+         assert(!isl_format_is_compressed(info->format));
+
+         *phys_level0_sa = (struct isl_extent4d) {
+            .w = info->width,
+            .h = info->height,
+            .d = 1,
+            .a = 1,
+         };
+
+         isl_msaa_interleaved_scale_px_to_sa(info->samples,
+                                             &phys_level0_sa->w,
+                                             &phys_level0_sa->h);
+         break;
+      }
+      break;
+
+   case ISL_SURF_DIM_3D:
+      assert(info->array_len == 1);
+      assert(info->samples == 1);
+
+      switch (dim_layout) {
+      case ISL_DIM_LAYOUT_GEN9_1D:
+         unreachable("bad isl_dim_layout");
+
+      case ISL_DIM_LAYOUT_GEN4_2D:
+         assert(ISL_DEV_GEN(dev) >= 9);
+
+         *phys_level0_sa = (struct isl_extent4d) {
+            .w = info->width,
+            .h = info->height,
+            .d = 1,
+            .a = info->depth,
+         };
+         break;
+
+      case ISL_DIM_LAYOUT_GEN4_3D:
+         assert(ISL_DEV_GEN(dev) < 9);
+         *phys_level0_sa = (struct isl_extent4d) {
+            .w = info->width,
+            .h = info->height,
+            .d = info->depth,
+            .a = 1,
+         };
+         break;
+      }
+      break;
+   }
+}
+
+/**
+ * A variant of isl_calc_phys_slice0_extent_sa() specific to
+ * ISL_DIM_LAYOUT_GEN4_2D.
+ */
+static void
+isl_calc_phys_slice0_extent_sa_gen4_2d(
+      const struct isl_device *dev,
+      const struct isl_surf_init_info *restrict info,
+      enum isl_msaa_layout msaa_layout,
+      const struct isl_extent3d *lod_align_sa,
+      const struct isl_extent4d *phys_level0_sa,
+      struct isl_extent2d *phys_slice0_sa)
+{
+   assert(phys_level0_sa->depth == 1);
+
+   uint32_t slice_top_w = 0;
+   uint32_t slice_bottom_w = 0;
+   uint32_t slice_left_h = 0;
+   uint32_t slice_right_h = 0;
+
+   uint32_t W0 = phys_level0_sa->w;
+   uint32_t H0 = phys_level0_sa->h;
+
+   for (uint32_t l = 0; l < info->levels; ++l) {
+      uint32_t W = isl_minify(W0, l);
+      uint32_t H = isl_minify(H0, l);
+
+      if (msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED) {
+         /* From the Broadwell PRM >> Volume 5: Memory Views >> Computing Mip Level
+          * Sizes (p133):
+          *
+          *    If the surface is multisampled and it is a depth or stencil
+          *    surface or Multisampled Surface StorageFormat in
+          *    SURFACE_STATE is MSFMT_DEPTH_STENCIL, W_L and H_L must be
+          *    adjusted as follows before proceeding: [...]
+          */
+         isl_msaa_interleaved_scale_px_to_sa(info->samples, &W, &H);
+      }
+
+      uint32_t w = isl_align_npot(W, lod_align_sa->w);
+      uint32_t h = isl_align_npot(H, lod_align_sa->h);
+
+      if (l == 0) {
+         slice_top_w = w;
+         slice_left_h = h;
+         slice_right_h = h;
+      } else if (l == 1) {
+         slice_bottom_w = w;
+         slice_left_h += h;
+      } else if (l == 2) {
+         slice_bottom_w += w;
+      } else {
+         slice_right_h += h;
+      }
+   }
+
+   *phys_slice0_sa = (struct isl_extent2d) {
+      .w = MAX(slice_top_w, slice_bottom_w),
+      .h = MAX(slice_left_h, slice_right_h),
    };
+}
 
-   static const struct isl_extent2d yf_extents[] = {
-      /*cpp*/
-      /* 1*/ [0] = {   64, 64 },
-      /* 2*/ [1] = {  128, 32 },
-      /* 4*/ [2] = {  128, 32 },
-      /* 8*/ [3] = {  256, 16 },
-      /*16*/ [4] = {  256, 16 },
+/**
+ * A variant of isl_calc_phys_slice0_extent_sa() specific to
+ * ISL_DIM_LAYOUT_GEN4_3D.
+ */
+static void
+isl_calc_phys_slice0_extent_sa_gen4_3d(
+      const struct isl_device *dev,
+      const struct isl_surf_init_info *restrict info,
+      const struct isl_extent3d *lod_align_sa,
+      const struct isl_extent4d *phys_level0_sa,
+      struct isl_extent2d *phys_slice0_sa)
+{
+   assert(info->samples == 1);
+   assert(phys_level0_sa->array_len == 1);
+
+   uint32_t slice_w = 0;
+   uint32_t slice_h = 0;
+
+   uint32_t W0 = phys_level0_sa->w;
+   uint32_t H0 = phys_level0_sa->h;
+   uint32_t D0 = phys_level0_sa->d;
+
+   for (uint32_t l = 0; l < info->levels; ++l) {
+      uint32_t level_w = isl_align_npot(isl_minify(W0, l), lod_align_sa->w);
+      uint32_t level_h = isl_align_npot(isl_minify(H0, l), lod_align_sa->h);
+      uint32_t level_d = isl_align_npot(isl_minify(D0, l), lod_align_sa->d);
+
+      uint32_t max_layers_horiz = MIN(level_d, 1u << l);
+      uint32_t max_layers_vert = isl_align(level_d, 1u << l) / (1u << l);
+
+      slice_w = MAX(slice_w, level_w * max_layers_horiz);
+      slice_h += level_h * max_layers_vert;
+   }
+
+   *phys_slice0_sa = (struct isl_extent2d) {
+      .w = slice_w,
+      .h = slice_h,
    };
+}
+
+/**
+ * Calculate the physical extent of the surface's first array slice, in units
+ * of surface samples. The result is aligned to \a lod_align_sa.
+ */
+static void
+isl_calc_phys_slice0_extent_sa(const struct isl_device *dev,
+                               const struct isl_surf_init_info *restrict info,
+                               enum isl_dim_layout dim_layout,
+                               enum isl_msaa_layout msaa_layout,
+                               const struct isl_extent3d *lod_align_sa,
+                               const struct isl_extent4d *phys_level0_sa,
+                               struct isl_extent2d *phys_slice0_sa)
+{
+   switch (dim_layout) {
+   case ISL_DIM_LAYOUT_GEN9_1D:
+      if (ISL_DEV_GEN(dev) >= 9)
+         isl_finishme("%s:%s: [SKL+] physical layout of 1d surfaces",
+                      __FILE__, __func__);
+      /*fallthrough*/
+   case ISL_DIM_LAYOUT_GEN4_2D:
+      isl_calc_phys_slice0_extent_sa_gen4_2d(dev, info, msaa_layout,
+                                             lod_align_sa, phys_level0_sa,
+                                             phys_slice0_sa);
+      return;
+   case ISL_DIM_LAYOUT_GEN4_3D:
+      isl_calc_phys_slice0_extent_sa_gen4_3d(dev, info, lod_align_sa,
+                                             phys_level0_sa, phys_slice0_sa);
+      return;
+   }
+}
+
+/**
+ * Calculate the pitch between physical array slices, in units of rows of
+ * surface samples. The result is aligned to \a lod_align_sa.
+ */
+static uint32_t
+isl_calc_array_pitch_sa_rows(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_dim_layout dim_layout,
+                             enum isl_array_pitch_span array_pitch_span,
+                             const struct isl_extent3d *lod_align_sa,
+                             const struct isl_extent4d *phys_level0_sa,
+                             const struct isl_extent2d *phys_slice0_sa)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
 
-   assert(cpp > 0);
+   switch (dim_layout) {
+   case ISL_DIM_LAYOUT_GEN9_1D:
+      if (ISL_DEV_GEN(dev) >= 9)
+         isl_finishme("%s:%s: [SKL+] physical layout of 1d surfaces",
+                      __FILE__, __func__);
+      /*fallthrough*/
 
-   switch (tiling) {
+   case ISL_DIM_LAYOUT_GEN4_2D:
+      switch (array_pitch_span) {
+      case ISL_ARRAY_PITCH_SPAN_COMPACT:
+         return isl_align_npot(phys_slice0_sa->h, lod_align_sa->h);
+      case ISL_ARRAY_PITCH_SPAN_FULL: {
+         /* The QPitch equation is found in the Broadwell PRM >> Volume 5:
+          * Memory Views >> Common Surface Formats >> Surface Layout >> 2D
+          * Surfaces >> Surface Arrays.
+          */
+         uint32_t H0_sa = phys_level0_sa->h;
+         uint32_t H1_sa = isl_minify(H0_sa, 1);
+
+         uint32_t h0_sa = isl_align_npot(H0_sa, lod_align_sa->h);
+         uint32_t h1_sa = isl_align_npot(H1_sa, lod_align_sa->h);
+
+         uint32_t m;
+         if (ISL_DEV_GEN(dev) >= 7) {
+            /* The QPitch equation changed slightly in Ivybridge. */
+            m = 12;
+         } else {
+            m = 11;
+         }
+
+         uint32_t pitch_sa_rows = h0_sa + h1_sa + (m * lod_align_sa->h);
+
+         if (ISL_DEV_GEN(dev) == 6 && info->samples > 1 &&
+             (info->height % 4 == 1)) {
+            /* [SNB] Errata from the Sandy Bridge PRM >> Volume 4 Part 1:
+             * Graphics Core >> Section 7.18.3.7: Surface Arrays:
+             *
+             *    [SNB] Errata: Sampler MSAA Qpitch will be 4 greater than
+             *    the value calculated in the equation above , for every
+             *    other odd Surface Height starting from 1 i.e. 1,5,9,13.
+             *
+             * XXX(chadv): Is the errata natural corollary of the physical
+             * layout of interleaved samples?
+             */
+            pitch_sa_rows += 4;
+         }
+
+         pitch_sa_rows = isl_align_npot(pitch_sa_rows, fmtl->bh);
+
+         return pitch_sa_rows;
+         } /* end case */
+         break;
+      }
+      break;
+
+   case ISL_DIM_LAYOUT_GEN4_3D:
+      assert(array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT);
+      return isl_align_npot(phys_slice0_sa->h, lod_align_sa->h);
+   }
+
+   unreachable("bad isl_dim_layout");
+   return 0;
+}
+
+/**
+ * Calculate the pitch of each surface row, in bytes.
+ */
+static uint32_t
+isl_calc_row_pitch(const struct isl_device *dev,
+                   const struct isl_surf_init_info *restrict info,
+                   const struct isl_tile_info *tile_info,
+                   const struct isl_extent3d *lod_align_sa,
+                   const struct isl_extent2d *phys_slice0_sa)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
+
+   uint32_t row_pitch = info->min_pitch;
+
+   /* First, align the surface to a cache line boundary, as the PRM explains
+    * below.
+    *
+    * From the Broadwell PRM >> Volume 5: Memory Views >> Common Surface
+    * Formats >> Surface Padding Requirements >> Render Target and Media
+    * Surfaces:
+    *
+    *    The data port accesses data (pixels) outside of the surface if they
+    *    are contained in the same cache request as pixels that are within the
+    *    surface. These pixels will not be returned by the requesting message,
+    *    however if these pixels lie outside of defined pages in the GTT,
+    *    a GTT error will result when the cache request is processed. In order
+    *    to avoid these GTT errors, “padding” at the bottom of the surface is
+    *    sometimes necessary.
+    *
+    * From the Broadwell PRM >> Volume 5: Memory Views >> Common Surface
+    * Formats >> Surface Padding Requirements >> Sampling Engine Surfaces:
+    *
+    *    The sampling engine accesses texels outside of the surface if they
+    *    are contained in the same cache line as texels that are within the
+    *    surface.  These texels will not participate in any calculation
+    *    performed by the sampling engine and will not affect the result of
+    *    any sampling engine operation, however if these texels lie outside of
+    *    defined pages in the GTT, a GTT error will result when the cache line
+    *    is accessed. In order to avoid these GTT errors, “padding” at the
+    *    bottom and right side of a sampling engine surface is sometimes
+    *    necessary.
+    *
+    *    It is possible that a cache line will straddle a page boundary if the
+    *    base address or pitch is not aligned. All pages included in the cache
+    *    lines that are part of the surface must map to valid GTT entries to
+    *    avoid errors. To determine the necessary padding on the bottom and
+    *    right side of the surface, refer to the table in  Alignment Unit Size
+    *    section for the i and j parameters for the surface format in use. The
+    *    surface must then be extended to the next multiple of the alignment
+    *    unit size in each dimension, and all texels contained in this
+    *    extended surface must have valid GTT entries.
+    *
+    *    For example, suppose the surface size is 15 texels by 10 texels and
+    *    the alignment parameters are i=4 and j=2. In this case, the extended
+    *    surface would be 16 by 10. Note that these calculations are done in
+    *    texels, and must be converted to bytes based on the surface format
+    *    being used to determine whether additional pages need to be defined.
+    */
+   row_pitch = MAX(row_pitch,
+                   fmtl->bs * isl_align_div_npot(phys_slice0_sa->w, fmtl->bw));
+
+   switch (tile_info->tiling) {
    case ISL_TILING_LINEAR:
-   case ISL_TILING_X:
-   case ISL_TILING_Y0:
-   case ISL_TILING_W:
-      *e = legacy_extents[tiling];
-      return;
-   case ISL_TILING_Yf:
-   case ISL_TILING_Ys:
-      assert(_mesa_is_pow_two(cpp));
-      *e = yf_extents[isl_log2u(cpp)];
-      if (tiling == ISL_TILING_Ys) {
-         e->width *= 4;
-         e->height *= 4;
+      /* From the Broadwel PRM >> Volume 2d: Command Reference: Structures >>
+       * RENDER_SURFACE_STATE Surface Pitch (p349):
+       *
+       *    - For linear render target surfaces and surfaces accessed with the
+       *      typed data port messages, the pitch must be a multiple of the
+       *      element size for non-YUV surface formats.  Pitch must be
+       *      a multiple of 2 * element size for YUV surface formats.
+       *
+       *    - [Requirements for SURFTYPE_BUFFER and SURFTYPE_STRBUF, which we
+       *      ignore because isl doesn't do buffers.]
+       *
+       *    - For other linear surfaces, the pitch can be any multiple of
+       *      bytes.
+       */
+      if (info->usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) {
+         if (isl_format_is_yuv(info->format)) {
+            row_pitch = isl_align(row_pitch, fmtl->bs);
+         } else  {
+            row_pitch = isl_align(row_pitch, 2 * fmtl->bs);
+         }
       }
-      return;
+      break;
+   default:
+      /* From the Broadwel PRM >> Volume 2d: Command Reference: Structures >>
+       * RENDER_SURFACE_STATE Surface Pitch (p349):
+       *
+       *    - For tiled surfaces, the pitch must be a multiple of the tile
+       *      width.
+       */
+      row_pitch = isl_align(row_pitch, tile_info->width);
+      break;
    }
+
+   return row_pitch;
+}
+
+/**
+ * Calculate the surface's total height, including padding, in units of
+ * surface elements.
+ */
+static uint32_t
+isl_calc_total_height_el(const struct isl_device *dev,
+                         const struct isl_surf_init_info *restrict info,
+                         const struct isl_tile_info *tile_info,
+                         uint32_t phys_array_len,
+                         uint32_t row_pitch,
+                         uint32_t array_pitch_el_rows)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
+
+   uint32_t total_h_el = phys_array_len * array_pitch_el_rows;
+   uint32_t pad_bytes = 0;
+
+   /* From the Broadwell PRM >> Volume 5: Memory Views >> Common Surface
+    * Formats >> Surface Padding Requirements >> Render Target and Media
+    * Surfaces:
+    *
+    *   The data port accesses data (pixels) outside of the surface if they
+    *   are contained in the same cache request as pixels that are within the
+    *   surface. These pixels will not be returned by the requesting message,
+    *   however if these pixels lie outside of defined pages in the GTT,
+    *   a GTT error will result when the cache request is processed. In
+    *   order to avoid these GTT errors, “padding” at the bottom of the
+    *   surface is sometimes necessary.
+    *
+    * From the Broadwell PRM >> Volume 5: Memory Views >> Common Surface
+    * Formats >> Surface Padding Requirements >> Sampling Engine Surfaces:
+    *
+    *    ... Lots of padding requirements, all listed separately below.
+    */
+
+   /* We can safely ignore the first padding requirement, quoted below,
+    * because isl doesn't do buffers.
+    *
+    *    - [pre-BDW] For buffers, which have no inherent “height,” padding
+    *      requirements are different. A buffer must be padded to the next
+    *      multiple of 256 array elements, with an additional 16 bytes added
+    *      beyond that to account for the L1 cache line.
+    */
+
+   /*
+    *    - For compressed textures [...], padding at the bottom of the surface
+    *      is to an even compressed row.
+    */
+   if (isl_format_is_compressed(info->format))
+      total_h_el = isl_align(total_h_el, 2);
+
+   /*
+    *    - For cube surfaces, an additional two rows of padding are required
+    *      at the bottom of the surface.
+    */
+   if (info->usage & ISL_SURF_USAGE_CUBE_BIT)
+      total_h_el += 2;
+
+   /*
+    *    - For packed YUV, 96 bpt, 48 bpt, and 24 bpt surface formats,
+    *      additional padding is required. These surfaces require an extra row
+    *      plus 16 bytes of padding at the bottom in addition to the general
+    *      padding requirements.
+    */
+   if (isl_format_is_yuv(info->format) &&
+       (fmtl->bs == 96 || fmtl->bs == 48|| fmtl->bs == 24)) {
+      total_h_el += 1;
+      pad_bytes += 16;
+   }
+
+   /*
+    *    - For linear surfaces, additional padding of 64 bytes is required at
+    *      the bottom of the surface. This is in addition to the padding
+    *      required above.
+    */
+   if (tile_info->tiling == ISL_TILING_LINEAR)
+      pad_bytes += 64;
+
+   /* The below text weakens, not strengthens, the padding requirements for
+    * linear surfaces. Therefore we can safely ignore it.
+    *
+    *    - [BDW+] For SURFTYPE_BUFFER, SURFTYPE_1D, and SURFTYPE_2D non-array,
+    *      non-MSAA, non-mip-mapped surfaces in linear memory, the only
+    *      padding requirement is to the next aligned 64-byte boundary beyond
+    *      the end of the surface. The rest of the padding requirements
+    *      documented above do not apply to these surfaces.
+    */
+
+   /*
+    *    - [SKL+] For SURFTYPE_2D and SURFTYPE_3D with linear mode and
+    *      height % 4 != 0, the surface must be padded with
+    *      4-(height % 4)*Surface Pitch # of bytes.
+    */
+   if (ISL_DEV_GEN(dev) >= 9 &&
+       tile_info->tiling == ISL_TILING_LINEAR &&
+       (info->dim == ISL_SURF_DIM_2D || info->dim == ISL_SURF_DIM_3D)) {
+      total_h_el = isl_align(total_h_el, 4);
+   }
+
+   /*
+    *    - [SKL+] For SURFTYPE_1D with linear mode, the surface must be padded
+    *      to 4 times the Surface Pitch # of bytes
+    */
+   if (ISL_DEV_GEN(dev) >= 9 &&
+       tile_info->tiling == ISL_TILING_LINEAR &&
+       info->dim == ISL_SURF_DIM_1D) {
+      total_h_el += 4;
+   }
+
+   /* Be sloppy. Align any leftover padding to a row boundary. */
+   total_h_el += isl_align_div_npot(pad_bytes, row_pitch);
+
+   return total_h_el;
+}
+
+bool
+isl_surf_init_s(const struct isl_device *dev,
+                struct isl_surf *surf,
+                const struct isl_surf_init_info *restrict info)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
+
+   const struct isl_extent4d logical_level0_px = {
+      .w = info->width,
+      .h = info->height,
+      .d = info->depth,
+      .a = info->array_len,
+   };
+
+   enum isl_dim_layout dim_layout =
+      isl_surf_choose_dim_layout(dev, info->dim);
+
+   enum isl_tiling tiling;
+   if (!isl_surf_choose_tiling(dev, info, &tiling))
+      return false;
+
+   struct isl_tile_info tile_info;
+   if (!isl_tiling_get_info(dev, tiling, fmtl->bs, &tile_info))
+      return false;
+
+   enum isl_msaa_layout msaa_layout;
+   if (!isl_choose_msaa_layout(dev, info, tiling, &msaa_layout))
+       return false;
+
+   struct isl_extent3d lod_align_el;
+   isl_choose_lod_alignment_el(dev, info, tiling, msaa_layout, &lod_align_el);
+
+   struct isl_extent3d lod_align_sa =
+      isl_extent3d_el_to_sa(info->format, lod_align_el);
+
+   struct isl_extent4d phys_level0_sa;
+   isl_calc_phys_level0_extent_sa(dev, info, dim_layout, tiling, msaa_layout,
+                                  &phys_level0_sa);
+
+   enum isl_array_pitch_span array_pitch_span =
+      isl_choose_array_pitch_span(dev, info, dim_layout, &phys_level0_sa);
+
+   struct isl_extent2d phys_slice0_sa;
+   isl_calc_phys_slice0_extent_sa(dev, info, dim_layout, msaa_layout,
+                                  &lod_align_sa, &phys_level0_sa,
+                                  &phys_slice0_sa);
+   assert(phys_slice0_sa.w % fmtl->bw == 0);
+   assert(phys_slice0_sa.h % fmtl->bh == 0);
+
+   const uint32_t row_pitch = isl_calc_row_pitch(dev, info, &tile_info,
+                                                 &lod_align_sa,
+                                                 &phys_slice0_sa);
+
+   const uint32_t array_pitch_sa_rows =
+      isl_calc_array_pitch_sa_rows(dev, info, dim_layout, array_pitch_span,
+                                   &lod_align_sa, &phys_level0_sa,
+                                   &phys_slice0_sa);
+   assert(array_pitch_sa_rows % fmtl->bh == 0);
+
+   const uint32_t array_pitch_el_rows = array_pitch_sa_rows / fmtl->bh;
+
+   const uint32_t total_h_el =
+      isl_calc_total_height_el(dev, info, &tile_info,
+                               phys_level0_sa.array_len, row_pitch,
+                               array_pitch_el_rows);
+
+   const uint32_t total_h_sa = total_h_el * fmtl->bh;
+   const uint32_t size = row_pitch * total_h_sa;
+
+   /* Alignment of surface base address, in bytes */
+   uint32_t base_alignment = info->min_alignment;
+   base_alignment = isl_align(base_alignment, tile_info.size);
+
+   *surf = (struct isl_surf) {
+      .dim = info->dim,
+      .dim_layout = dim_layout,
+      .msaa_layout = msaa_layout,
+      .tiling = tiling,
+      .format = info->format,
+
+      .levels = info->levels,
+      .samples = info->samples,
+
+      .lod_alignment_el = lod_align_el,
+      .logical_level0_px = logical_level0_px,
+      .phys_level0_sa = phys_level0_sa,
+
+      .size = size,
+      .alignment = base_alignment,
+      .row_pitch = row_pitch,
+      .array_pitch_el_rows = array_pitch_el_rows,
+      .array_pitch_span = array_pitch_span,
+
+      .usage = info->usage,
+   };
+
+   return true;
 }
index fd6b1c2b5ad635308fa9c2a6230a16f4af6166d5..ef42e2d69df0feeb7d0b0ebab295f3b3cc056978 100644 (file)
 /**
  * @file
  * @brief Intel Surface Layout
+ *
+ * Header Layout
+ * =============
+ *
+ * The header is ordered as:
+ *    - forward declarations
+ *    - macros that may be overridden at compile-time for specific gens
+ *    - enums and constants
+ *    - structs and unions
+ *    - functions
+ *
+ *
+ * Surface Units
+ * =============
+ *
+ * Some symbol names have a unit suffix.
+ *
+ *    - px: logical pixels
+ *    - sa: physical surface samples
+ *    - el: physical surface elements
+ *    - sa_rows: rows of physical surface samples
+ *    - el_rows: rows of physical surface elements
+ *
+ * The Broadwell PRM [1] defines a surface element as follows:
+ *
+ *    An element is defined as a pixel in uncompresed surface formats, and as
+ *    a compression block in compressed surface formats. For
+ *    MSFMT_DEPTH_STENCIL type multisampled surfaces, an element is a sample.
+ *
+ * [1]: Broadwell PRM >> Volume 2d: Command Reference: Structures >>
+ *      RENDER_SURFACE_STATE Surface Vertical Alignment (p325)
  */
 
 #pragma once
 
+#include <assert.h>
 #include <stdbool.h>
 #include <stdint.h>
 
+#include "util/macros.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 struct brw_device_info;
 
+#ifndef ISL_DEV_GEN
 /**
- * WARNING: These values differ from the hardware enum values, which are
- * unstable across hardware generations.
+ * @brief Get the hardware generation of isl_device.
  *
- * Note that legacy Y tiling is ISL_TILING_Y0 instead of ISL_TILING_Y, to
- * clearly distinguish it from Yf and Ys.
+ * You can define this as a compile-time constant in the CFLAGS. For example,
+ * `gcc -DISL_DEV_GEN(dev)=9 ...`.
  */
-enum isl_tiling {
-   ISL_TILING_LINEAR,
-   ISL_TILING_W,
-   ISL_TILING_X,
-   ISL_TILING_Y0, /**< Legacy Y tiling */
-   ISL_TILING_Yf,
-   ISL_TILING_Ys,
-};
+#define ISL_DEV_GEN(__dev) ((__dev)->info->gen)
+#endif
+
+#ifndef ISL_DEV_USE_SEPARATE_STENCIL
+/**
+ * You can define this as a compile-time constant in the CFLAGS. For example,
+ * `gcc -DISL_DEV_USE_SEPARATE_STENCIL(dev)=1 ...`.
+ */
+#define ISL_DEV_USE_SEPARATE_STENCIL(__dev) ((__dev)->use_separate_stencil)
+#endif
 
 /**
  * Hardware enumeration SURFACE_FORMAT.
@@ -286,6 +322,9 @@ enum isl_format {
    ISL_FORMAT_UNSUPPORTED =                             UINT16_MAX,
 };
 
+/**
+ * Numerical base type for channels of isl_format.
+ */
 enum isl_base_type {
    ISL_VOID,
    ISL_RAW,
@@ -301,6 +340,9 @@ enum isl_base_type {
    ISL_SSCALED,
 };
 
+/**
+ * Colorspace of isl_format.
+ */
 enum isl_colorspace {
    ISL_COLORSPACE_NONE = 0,
    ISL_COLORSPACE_LINEAR,
@@ -309,7 +351,7 @@ enum isl_colorspace {
 };
 
 /**
- * Texture compression mode
+ * Texture compression mode of isl_format.
  */
 enum isl_txc {
    ISL_TXC_NONE = 0,
@@ -324,19 +366,203 @@ enum isl_txc {
    ISL_TXC_ETC2,
 };
 
+/**
+ * @brief Hardware tile mode
+ *
+ * WARNING: These values differ from the hardware enum values, which are
+ * unstable across hardware generations.
+ *
+ * Note that legacy Y tiling is ISL_TILING_Y0 instead of ISL_TILING_Y, to
+ * clearly distinguish it from Yf and Ys.
+ */
+enum isl_tiling {
+   ISL_TILING_LINEAR = 0,
+   ISL_TILING_W,
+   ISL_TILING_X,
+   ISL_TILING_Y0, /**< Legacy Y tiling */
+   ISL_TILING_Yf,
+   ISL_TILING_Ys,
+};
+
+/**
+ * @defgroup Tiling Flags
+ * @{
+ */
+typedef uint32_t isl_tiling_flags_t;
+#define ISL_TILING_LINEAR_BIT             (1u << ISL_TILING_LINEAR)
+#define ISL_TILING_W_BIT                  (1u << ISL_TILING_W)
+#define ISL_TILING_X_BIT                  (1u << ISL_TILING_X)
+#define ISL_TILING_Y0_BIT                 (1u << ISL_TILING_Y0)
+#define ISL_TILING_Yf_BIT                 (1u << ISL_TILING_Yf)
+#define ISL_TILING_Ys_BIT                 (1u << ISL_TILING_Ys)
+#define ISL_TILING_ANY_MASK               (~0u)
+#define ISL_TILING_NON_LINEAR_MASK        (~ISL_TILING_LINEAR_BIT)
+
+/** Any Y tiling, including legacy Y tiling. */
+#define ISL_TILING_ANY_Y_MASK             (ISL_TILING_Y0_BIT | \
+                                           ISL_TILING_Yf_BIT | \
+                                           ISL_TILING_Ys_BIT)
+
+/** The Skylake BSpec refers to Yf and Ys as "standard tiling formats". */
+#define ISL_TILING_STD_Y_MASK             (ISL_TILING_Yf_BIT | \
+                                           ISL_TILING_Ys_BIT)
+/** @} */
+
+/**
+ * @brief Logical dimension of surface.
+ *
+ * Note: There is no dimension for cube map surfaces. ISL interprets cube maps
+ * as 2D array surfaces.
+ */
+enum isl_surf_dim {
+   ISL_SURF_DIM_1D,
+   ISL_SURF_DIM_2D,
+   ISL_SURF_DIM_3D,
+};
+
+/**
+ * @brief Physical layout of the surface's dimensions.
+ */
+enum isl_dim_layout {
+   /**
+    * For details, see the G35 PRM >> Volume 1: Graphics Core >> Section
+    * 6.17.3: 2D Surfaces.
+    *
+    * On many gens, 1D surfaces share the same layout as 2D surfaces.  From
+    * the G35 PRM >> Volume 1: Graphics Core >> Section 6.17.2: 1D Surfaces:
+    *
+    *    One-dimensional surfaces are identical to 2D surfaces with height of
+    *    one.
+    */
+   ISL_DIM_LAYOUT_GEN4_2D,
+
+   /**
+    * For details, see the G35 PRM >> Volume 1: Graphics Core >> Section
+    * 6.17.5: 3D Surfaces.
+    */
+   ISL_DIM_LAYOUT_GEN4_3D,
+
+   /**
+    * For details, see the Skylake BSpec >> Memory Views >> Common Surface
+    * Formats >> Surface Layout and Tiling >> » 1D Surfaces.
+    */
+   ISL_DIM_LAYOUT_GEN9_1D,
+};
+
+/* TODO(chadv): Explain */
+enum isl_array_pitch_span {
+   ISL_ARRAY_PITCH_SPAN_FULL,
+   ISL_ARRAY_PITCH_SPAN_COMPACT,
+};
+
+/**
+ * @defgroup Surface Usage
+ * @{
+ */
+typedef uint64_t isl_surf_usage_flags_t;
+#define ISL_SURF_USAGE_RENDER_TARGET_BIT       (1u << 0)
+#define ISL_SURF_USAGE_DEPTH_BIT               (1u << 1)
+#define ISL_SURF_USAGE_STENCIL_BIT             (1u << 2)
+#define ISL_SURF_USAGE_TEXTURE_BIT             (1u << 3)
+#define ISL_SURF_USAGE_CUBE_BIT                (1u << 4)
+#define ISL_SURF_USAGE_DISABLE_AUX_BIT         (1u << 5)
+#define ISL_SURF_USAGE_DISPLAY_BIT             (1u << 6)
+#define ISL_SURF_USAGE_DISPLAY_ROTATE_90_BIT   (1u << 7)
+#define ISL_SURF_USAGE_DISPLAY_ROTATE_180_BIT  (1u << 8)
+#define ISL_SURF_USAGE_DISPLAY_ROTATE_270_BIT  (1u << 9)
+#define ISL_SURF_USAGE_DISPLAY_FLIP_X_BIT      (1u << 10)
+#define ISL_SURF_USAGE_DISPLAY_FLIP_Y_BIT      (1u << 11)
+/** @} */
+
+/**
+ * @brief Multisample Format
+ */
+enum isl_msaa_layout {
+   /**
+    * @brief Suface is single-sampled.
+    */
+   ISL_MSAA_LAYOUT_NONE,
+
+   /**
+    * @brief [SNB+] Interleaved Multisample Format
+    *
+    * In this format, multiple samples are interleaved into each cacheline.
+    * In other words, the sample index is swizzled into the low 6 bits of the
+    * surface's virtual address space.
+    *
+    * For example, suppose the surface is legacy Y tiled, is 4x multisampled,
+    * and its pixel format is 32bpp. Then the first cacheline is arranged
+    * thus:
+    *
+    *    (0,0,0) (0,1,0)   (0,0,1) (1,0,1)
+    *    (1,0,0) (1,1,0)   (0,1,1) (1,1,1)
+    *
+    *    (0,0,2) (1,0,2)   (0,0,3) (1,0,3)
+    *    (0,1,2) (1,1,2)   (0,1,3) (1,1,3)
+    *
+    * The hardware docs refer to this format with multiple terms.  In
+    * Sandybridge, this is the only multisample format; so no term is used.
+    * The Ivybridge docs refer to surfaces in this format as IMS (Interleaved
+    * Multisample Surface). Later hardware docs additionally refer to this
+    * format as MSFMT_DEPTH_STENCIL (because the format is deprecated for
+    * color surfaces).
+    *
+    * See the Sandybridge PRM, Volume 4, Part 1, Section 2.7 "Multisampled
+    * Surface Behavior".
+    *
+    * See the Ivybridge PRM, Volume 1, Part 1, Section 6.18.4.1 "Interleaved
+    * Multisampled Surfaces".
+    */
+   ISL_MSAA_LAYOUT_INTERLEAVED,
+
+   /**
+    * @brief [IVB+] Array Multisample Format
+    *
+    * In this format, the surface's physical layout resembles that of a
+    * 2D array surface.
+    *
+    * Suppose the multisample surface's logical extent is (w, h) and its
+    * sample count is N. Then surface's physical extent is the same as
+    * a singlesample 2D surface whose logical extent is (w, h) and array
+    * length is N.  Array slice `i` contains the pixel values for sample
+    * index `i`.
+    *
+    * The Ivybridge docs refer to surfaces in this format as UMS
+    * (Uncompressed Multsample Layout) and CMS (Compressed Multisample
+    * Surface). The Broadwell docs additionally refer to this format as
+    * MSFMT_MSS (MSS=Multisample Surface Storage).
+    *
+    * See the Broadwell PRM, Volume 5 "Memory Views", Section "Uncompressed
+    * Multisample Surfaces".
+    *
+    * See the Broadwell PRM, Volume 5 "Memory Views", Section "Compressed
+    * Multisample Surfaces".
+    */
+   ISL_MSAA_LAYOUT_ARRAY,
+};
+
+
 struct isl_device {
    const struct brw_device_info *info;
+   bool use_separate_stencil;
 };
 
 struct isl_extent2d {
-   uint32_t width;
-   uint32_t height;
+   union { uint32_t w, width; };
+   union { uint32_t h, height; };
 };
 
 struct isl_extent3d {
-   uint32_t width;
-   uint32_t height;
-   uint32_t depth;
+   union { uint32_t w, width; };
+   union { uint32_t h, height; };
+   union { uint32_t d, depth; };
+};
+
+struct isl_extent4d {
+   union { uint32_t w, width; };
+   union { uint32_t h, height; };
+   union { uint32_t d, depth; };
+   union { uint32_t a, array_len; };
 };
 
 struct isl_channel_layout {
@@ -367,17 +593,319 @@ struct isl_format_layout {
    enum isl_txc txc;
 };
 
+struct isl_tile_info {
+   enum isl_tiling tiling;
+   uint32_t width; /**< in bytes */
+   uint32_t height; /**< in rows of memory */
+   uint32_t size; /**< in bytes */
+};
+
+/**
+ * @brief Input to surface initialization
+ *
+ * @invariant width >= 1
+ * @invariant height >= 1
+ * @invariant depth >= 1
+ * @invariant levels >= 1
+ * @invariant samples >= 1
+ * @invariant array_len >= 1
+ *
+ * @invariant if 1D then height == 1 and depth == 1 and samples == 1
+ * @invariant if 2D then depth == 1
+ * @invariant if 3D then array_len == 1 and samples == 1
+ */
+struct isl_surf_init_info {
+   enum isl_surf_dim dim;
+   enum isl_format format;
+
+   uint32_t width;
+   uint32_t height;
+   uint32_t depth;
+   uint32_t levels;
+   uint32_t array_len;
+   uint32_t samples;
+
+   /** Lower bound for isl_surf::alignment, in bytes. */
+   uint32_t min_alignment;
+
+   /** Lower bound for isl_surf::pitch, in bytes. */
+   uint32_t min_pitch;
+
+   isl_surf_usage_flags_t usage;
+
+   /** Flags that alter how ISL selects isl_surf::tiling.  */
+   isl_tiling_flags_t tiling_flags;
+};
+
+struct isl_surf {
+   enum isl_surf_dim dim;
+   enum isl_dim_layout dim_layout;
+   enum isl_msaa_layout msaa_layout;
+   enum isl_tiling tiling;
+   enum isl_format format;
+
+   /**
+    * Alignment of the upper-left sample of each LOD, in units of surface
+    * elements.
+    */
+   struct isl_extent3d lod_alignment_el;
+
+   /**
+    * Logical extent of the surface's base level, in units of pixels.  This is
+    * identical to the extent defined in isl_surf_init_info.
+    */
+   struct isl_extent4d logical_level0_px;
+
+   /**
+    * Physical extent of the surface's base level, in units of pixels.
+    *
+    * Consider isl_dim_layout as an operator that transforms a logical surface
+    * layout to a physical surface layout. Then
+    *
+    *    logical_layout := (isl_surf::dim, isl_surf::logical_level0_px)
+    *    isl_surf::phys_level0_sa := isl_surf::dim_layout * logical_layout
+    */
+   struct isl_extent4d phys_level0_sa;
+
+   uint32_t levels;
+   uint32_t samples;
+
+   /** Total size of the surface, in bytes. */
+   uint32_t size;
+
+   /** Required alignment for the surface's base address. */
+   uint32_t alignment;
+
+   /**
+    * Pitch between vertically adjacent samples, in bytes.
+    */
+   uint32_t row_pitch;
+
+   /**
+    * Pitch between physical array slices, in rows of surface elements.
+    */
+   uint32_t array_pitch_el_rows;
+
+   enum isl_array_pitch_span array_pitch_span;
+
+   /** Copy of isl_surf_init_info::usage. */
+   isl_surf_usage_flags_t usage;
+};
+
+extern const struct isl_format_layout isl_format_layouts[];
+
 void
 isl_device_init(struct isl_device *dev,
                 const struct brw_device_info *info);
 
+static inline const struct isl_format_layout * ATTRIBUTE_CONST
+isl_format_get_layout(enum isl_format fmt)
+{
+   return &isl_format_layouts[fmt];
+}
+
+bool
+isl_format_has_sint_channel(enum isl_format fmt) ATTRIBUTE_CONST;
+
+static inline bool
+isl_format_is_compressed(enum isl_format fmt)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(fmt);
+
+   return fmtl->txc != ISL_TXC_NONE;
+}
+
+static inline bool
+isl_format_has_bc_compression(enum isl_format fmt)
+{
+   switch (isl_format_get_layout(fmt)->txc) {
+   case ISL_TXC_DXT1:
+   case ISL_TXC_DXT3:
+   case ISL_TXC_DXT5:
+      return true;
+   case ISL_TXC_NONE:
+   case ISL_TXC_FXT1:
+   case ISL_TXC_RGTC1:
+   case ISL_TXC_RGTC2:
+   case ISL_TXC_BPTC:
+   case ISL_TXC_ETC1:
+   case ISL_TXC_ETC2:
+      return false;
+   }
+
+   unreachable("bad texture compression mode");
+   return false;
+}
+
+static inline bool
+isl_format_is_yuv(enum isl_format fmt)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(fmt);
+
+   return fmtl->colorspace == ISL_COLORSPACE_YUV;
+}
+
+static inline bool
+isl_format_block_is_1x1x1(enum isl_format fmt)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(fmt);
+
+   return fmtl->bw == 1 && fmtl->bh == 1 && fmtl->bd == 1;
+}
+
+static inline bool
+isl_tiling_is_std_y(enum isl_tiling tiling)
+{
+   return (1u << tiling) & ISL_TILING_STD_Y_MASK;
+}
+
+bool
+isl_tiling_get_info(const struct isl_device *dev,
+                    enum isl_tiling tiling,
+                    uint32_t format_block_size,
+                    struct isl_tile_info *info);
+
 void
 isl_tiling_get_extent(const struct isl_device *dev,
                       enum isl_tiling tiling,
-                      uint32_t cpp,
+                      uint32_t format_block_size,
                       struct isl_extent2d *e);
+bool
+isl_surf_choose_tiling(const struct isl_device *dev,
+                       const struct isl_surf_init_info *restrict info,
+                       enum isl_tiling *tiling);
 
-extern const struct isl_format_layout isl_format_layouts[];
+static inline bool
+isl_surf_usage_is_display(isl_surf_usage_flags_t usage)
+{
+   return usage & ISL_SURF_USAGE_DISPLAY_BIT;
+}
+
+static inline bool
+isl_surf_usage_is_depth(isl_surf_usage_flags_t usage)
+{
+   return usage & ISL_SURF_USAGE_DEPTH_BIT;
+}
+
+static inline bool
+isl_surf_usage_is_stencil(isl_surf_usage_flags_t usage)
+{
+   return usage & ISL_SURF_USAGE_STENCIL_BIT;
+}
+
+static inline bool
+isl_surf_usage_is_depth_and_stencil(isl_surf_usage_flags_t usage)
+{
+   return (usage & ISL_SURF_USAGE_DEPTH_BIT) &&
+          (usage & ISL_SURF_USAGE_STENCIL_BIT);
+}
+
+static inline bool
+isl_surf_usage_is_depth_or_stencil(isl_surf_usage_flags_t usage)
+{
+   return usage & (ISL_SURF_USAGE_DEPTH_BIT | ISL_SURF_USAGE_STENCIL_BIT);
+}
+
+static inline bool
+isl_surf_info_is_z16(const struct isl_surf_init_info *info)
+{
+   return (info->usage & ISL_SURF_USAGE_DEPTH_BIT) &&
+          (info->format == ISL_FORMAT_R16_UNORM);
+}
+
+static inline bool
+isl_surf_info_is_z32_float(const struct isl_surf_init_info *info)
+{
+   return (info->usage & ISL_SURF_USAGE_DEPTH_BIT) &&
+          (info->format == ISL_FORMAT_R32_FLOAT);
+}
+
+static inline struct isl_extent2d
+isl_extent2d(uint32_t width, uint32_t height)
+{
+   return (struct isl_extent2d) { .w = width, .h = height };
+}
+
+static inline struct isl_extent3d
+isl_extent3d(uint32_t width, uint32_t height, uint32_t depth)
+{
+   return (struct isl_extent3d) { .w = width, .h = height, .d = depth };
+}
+
+static inline struct isl_extent4d
+isl_extent4d(uint32_t width, uint32_t height, uint32_t depth,
+             uint32_t array_len)
+{
+   return (struct isl_extent4d) {
+      .w = width,
+      .h = height,
+      .d = depth,
+      .a = array_len,
+   };
+}
+
+#define isl_surf_init(dev, surf, ...) \
+   isl_surf_init_s((dev), (surf), \
+                   &(struct isl_surf_init_info) {  __VA_ARGS__ });
+
+bool
+isl_surf_init_s(const struct isl_device *dev,
+                struct isl_surf *surf,
+                const struct isl_surf_init_info *restrict info);
+
+/**
+ * Alignment of the upper-left sample of each LOD, in units of surface
+ * elements.
+ */
+static inline struct isl_extent3d
+isl_surf_get_lod_alignment_el(const struct isl_surf *surf)
+{
+   return surf->lod_alignment_el;
+}
+
+/**
+ * Alignment of the upper-left sample of each LOD, in units of surface
+ * samples.
+ */
+static inline struct isl_extent3d
+isl_surf_get_lod_alignment_sa(const struct isl_surf *surf)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
+
+   return (struct isl_extent3d) {
+      .w = fmtl->bw * surf->lod_alignment_el.w,
+      .h = fmtl->bh * surf->lod_alignment_el.h,
+      .d = fmtl->bd * surf->lod_alignment_el.d,
+   };
+}
+
+/**
+ * Pitch between physical array slices, in rows of surface elements.
+ */
+static inline uint32_t
+isl_surf_get_array_pitch_el_rows(const struct isl_surf *surf)
+{
+   return surf->array_pitch_el_rows;
+}
+
+/**
+ * Pitch between physical array slices, in rows of surface samples.
+ */
+static inline uint32_t
+isl_surf_get_array_pitch_sa_rows(const struct isl_surf *surf)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
+   return fmtl->bh * isl_surf_get_array_pitch_el_rows(surf);
+}
+
+/**
+ * Pitch between physical array slices, in bytes.
+ */
+static inline uint32_t
+isl_surf_get_array_pitch(const struct isl_surf *surf)
+{
+   return isl_surf_get_array_pitch_sa_rows(surf) * surf->row_pitch;
+}
 
 #ifdef __cplusplus
 }
diff --git a/src/vulkan/isl_gen4.c b/src/vulkan/isl_gen4.c
new file mode 100644 (file)
index 0000000..bf9bec1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#include "isl_gen4.h"
+#include "isl_priv.h"
+
+bool
+gen4_choose_msaa_layout(const struct isl_device *dev,
+                        const struct isl_surf_init_info *info,
+                        enum isl_tiling tiling,
+                        enum isl_msaa_layout *msaa_layout)
+{
+   /* Gen4 and Gen5 do not support MSAA */
+   assert(info->samples >= 1);
+
+   *msaa_layout = ISL_MSAA_LAYOUT_NONE;
+   return true;
+}
+
+void
+gen4_choose_lod_alignment_el(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_tiling tiling,
+                             enum isl_msaa_layout msaa_layout,
+                             struct isl_extent3d *lod_align_el)
+{
+   assert(info->samples == 1);
+   assert(msaa_layout == ISL_MSAA_LAYOUT_NONE);
+   assert(!isl_tiling_is_std_y(tiling));
+
+   /* Note that neither the surface's horizontal nor vertical image alignment
+    * is programmable on gen4 nor gen5.
+    *
+    * From the G35 PRM (2008-01), Volume 1 Graphics Core, Section 6.17.3.4
+    * Alignment Unit Size:
+    *
+    *    Note that the compressed formats are padded to a full compression
+    *    cell.
+    *
+    *    +------------------------+--------+--------+
+    *    | format                 | halign | valign |
+    *    +------------------------+--------+--------+
+    *    | YUV 4:2:2 formats      |      4 |      2 |
+    *    | uncompressed formats   |      4 |      2 |
+    *    +------------------------+--------+--------+
+    */
+
+   if (isl_format_is_compressed(info->format)) {
+      *lod_align_el = isl_extent3d(1, 1, 1);
+      return;
+   }
+
+   *lod_align_el = isl_extent3d(4, 2, 1);
+}
diff --git a/src/vulkan/isl_gen4.h b/src/vulkan/isl_gen4.h
new file mode 100644 (file)
index 0000000..913a7c6
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "isl_priv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool
+gen4_choose_msaa_layout(const struct isl_device *dev,
+                        const struct isl_surf_init_info *info,
+                        enum isl_tiling tiling,
+                        enum isl_msaa_layout *msaa_layout);
+
+void
+gen4_choose_lod_alignment_el(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_tiling tiling,
+                             enum isl_msaa_layout msaa_layout,
+                             struct isl_extent3d *lod_align_el);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/vulkan/isl_gen6.c b/src/vulkan/isl_gen6.c
new file mode 100644 (file)
index 0000000..8d522c3
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#include "isl_gen6.h"
+#include "isl_priv.h"
+
+bool
+gen6_choose_msaa_layout(const struct isl_device *dev,
+                  const struct isl_surf_init_info *info,
+                  enum isl_tiling tiling,
+                  enum isl_msaa_layout *msaa_layout)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
+
+   assert(ISL_DEV_GEN(dev) == 6);
+   assert(info->samples >= 1);
+
+   if (info->samples == 1) {
+      *msaa_layout = ISL_MSAA_LAYOUT_NONE;
+      return false;
+   }
+
+   /* From the Sandybridge PRM, Volume 4 Part 1 p72, SURFACE_STATE, Surface
+    * Format:
+    *
+    *    If Number of Multisamples is set to a value other than
+    *    MULTISAMPLECOUNT_1, this field cannot be set to the following
+    *    formats:
+    *
+    *       - any format with greater than 64 bits per element
+    *       - any compressed texture format (BC*)
+    *       - any YCRCB* format
+    */
+   if (fmtl->bs > 8)
+      return false;
+   if (isl_format_is_compressed(info->format))
+      return false;
+   if (isl_format_is_yuv(info->format))
+      return false;
+
+   /* From the Sandybridge PRM, Volume 4 Part 1 p85, SURFACE_STATE, Number of
+    * Multisamples:
+    *
+    *    If this field is any value other than MULTISAMPLECOUNT_1 the
+    *    following restrictions apply:
+    *
+    *       - the Surface Type must be SURFTYPE_2D
+    *       - [...]
+    */
+   if (info->dim != ISL_SURF_DIM_2D)
+      return false;
+
+   /* More obvious restrictions */
+   if (isl_surf_usage_is_display(info->usage))
+      return false;
+   if (tiling == ISL_TILING_LINEAR)
+      return false;
+   if (info->levels > 1)
+      return false;
+
+   *msaa_layout = ISL_MSAA_LAYOUT_INTERLEAVED;
+   return true;
+}
+
+void
+gen6_choose_lod_alignment_el(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_tiling tiling,
+                             enum isl_msaa_layout msaa_layout,
+                             struct isl_extent3d *lod_align_el)
+{
+   /* Note that the surface's horizontal image alignment is not programmable
+    * on Sandybridge.
+    *
+    * From the Sandybridge PRM (2011-05), Volume 1, Part 1, Section 7.18.3.4
+    * Alignment Unit Size:
+    *
+    *    Note that the compressed formats are padded to a full compression cell.
+    *
+    *    +------------------------+--------+--------+
+    *    | format                 | halign | valign |
+    *    +------------------------+--------+--------+
+    *    | YUV 4:2:2 formats      |      4 |      * |
+    *    | uncompressed formats   |      4 |      * |
+    *    +------------------------+--------+--------+
+    *
+    *    * For these formats, the vertical alignment factor “j” is determined
+    *      as follows:
+    *       - j = 4 for any depth buffer
+    *       - j = 2 for separate stencil buffer
+    *       - j = 4 for any render target surface is multisampled (4x)
+    *       - j = 2 for all other render target surface
+    *
+    * From the Sandrybridge PRM (2011-05), Volume 4, Part 1, Section 2.11.2
+    * SURFACE_STATE, Surface Vertical Alignment:
+    *
+    *    - This field must be set to VALIGN_2 if the Surface Format is 96 bits
+    *      per element (BPE).
+    *
+    *    - Value of 1 [VALIGN_4] is not supported for format YCRCB_NORMAL
+    *      (0x182), YCRCB_SWAPUVY (0x183), YCRCB_SWAPUV (0x18f), YCRCB_SWAPY
+    *      (0x190)
+    */
+
+   if (isl_format_is_compressed(info->format)) {
+      *lod_align_el = isl_extent3d(1, 1, 1);
+      return;
+   }
+
+   if (isl_format_is_yuv(info->format)) {
+      *lod_align_el = isl_extent3d(4, 2, 1);
+      return;
+   }
+
+   if (info->samples > 1) {
+      *lod_align_el = isl_extent3d(4, 4, 1);
+      return;
+   }
+
+   if (isl_surf_usage_is_depth_or_stencil(info->usage) &&
+       !ISL_DEV_USE_SEPARATE_STENCIL(dev)) {
+      /* interleaved depthstencil buffer */
+      *lod_align_el = isl_extent3d(4, 4, 1);
+      return;
+   }
+
+   if (isl_surf_usage_is_depth(info->usage)) {
+      /* separate depth buffer */
+      *lod_align_el = isl_extent3d(4, 4, 1);
+      return;
+   }
+
+   if (isl_surf_usage_is_stencil(info->usage)) {
+      /* separate stencil buffer */
+      *lod_align_el = isl_extent3d(4, 2, 1);
+      return;
+   }
+
+   *lod_align_el = isl_extent3d(4, 2, 1);
+}
diff --git a/src/vulkan/isl_gen6.h b/src/vulkan/isl_gen6.h
new file mode 100644 (file)
index 0000000..56b7f2c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "isl_priv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool
+gen6_choose_msaa_layout(const struct isl_device *dev,
+                        const struct isl_surf_init_info *info,
+                        enum isl_tiling tiling,
+                        enum isl_msaa_layout *msaa_layout);
+
+void
+gen6_choose_lod_alignment_el(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_tiling tiling,
+                             enum isl_msaa_layout msaa_layout,
+                             struct isl_extent3d *lod_align_el);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/vulkan/isl_gen7.c b/src/vulkan/isl_gen7.c
new file mode 100644 (file)
index 0000000..2ac1852
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#include "isl_gen7.h"
+#include "isl_priv.h"
+
+bool
+gen7_choose_msaa_layout(const struct isl_device *dev,
+                        const struct isl_surf_init_info *info,
+                        enum isl_tiling tiling,
+                        enum isl_msaa_layout *msaa_layout)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
+
+   bool require_array = false;
+   bool require_interleaved = false;
+
+   assert(ISL_DEV_GEN(dev) == 7);
+   assert(info->samples >= 1);
+
+   if (info->samples == 1) {
+      *msaa_layout = ISL_MSAA_LAYOUT_NONE;
+      return true;
+   }
+
+   /* From the Ivybridge PRM, Volume 4 Part 1 p63, SURFACE_STATE, Surface
+    * Format:
+    *
+    *    If Number of Multisamples is set to a value other than
+    *    MULTISAMPLECOUNT_1, this field cannot be set to the following
+    *    formats: any format with greater than 64 bits per element, any
+    *    compressed texture format (BC*), and any YCRCB* format.
+    */
+   if (fmtl->bs > 8)
+      return false;
+   if (isl_format_is_compressed(info->format))
+      return false;
+   if (isl_format_is_yuv(info->format))
+      return false;
+
+   /* From the Ivybridge PRM, Volume 4 Part 1 p73, SURFACE_STATE, Number of
+    * Multisamples:
+    *
+    *    - If this field is any value other than MULTISAMPLECOUNT_1, the
+    *      Surface Type must be SURFTYPE_2D.
+    *
+    *    - If this field is any value other than MULTISAMPLECOUNT_1, Surface
+    *      Min LOD, Mip Count / LOD, and Resource Min LOD must be set to zero
+    */
+   if (info->dim != ISL_SURF_DIM_2D)
+      return false;
+   if (info->levels > 1)
+      return false;
+
+   /* The Ivyrbridge PRM insists twice that signed integer formats cannot be
+    * multisampled.
+    *
+    * From the Ivybridge PRM, Volume 4 Part 1 p73, SURFACE_STATE, Number of
+    * Multisamples:
+    *
+    *    - This field must be set to MULTISAMPLECOUNT_1 for SINT MSRTs when
+    *      all RT channels are not written.
+    *
+    * And errata from the Ivybridge PRM, Volume 4 Part 1 p77,
+    * RENDER_SURFACE_STATE, MCS Enable:
+    *
+    *   This field must be set to 0 [MULTISAMPLECOUNT_1] for all SINT MSRTs
+    *   when all RT channels are not written.
+    *
+    * Note that the above SINT restrictions apply only to *MSRTs* (that is,
+    * *multisampled* render targets). The restrictions seem to permit an MCS
+    * if the render target is singlesampled.
+    */
+   if (isl_format_has_sint_channel(info->format))
+      return false;
+
+   /* More obvious restrictions */
+   if (isl_surf_usage_is_display(info->usage))
+      return false;
+   if (tiling == ISL_TILING_LINEAR)
+      return false;
+
+   /* From the Ivybridge PRM, Volume 4 Part 1 p72, SURFACE_STATE, Multisampled
+    * Suface Storage Format:
+    *
+    *    +---------------------+----------------------------------------------------------------+
+    *    | MSFMT_MSS           | Multsampled surface was/is rendered as a render target         |
+    *    | MSFMT_DEPTH_STENCIL | Multisampled surface was rendered as a depth or stencil buffer |
+    *    +---------------------+----------------------------------------------------------------+
+    *
+    * In the table above, MSFMT_MSS refers to ISL_MSAA_LAYOUT_ARRAY, and
+    * MSFMT_DEPTH_STENCIL refers to ISL_MSAA_LAYOUT_INTERLEAVED.
+    */
+   if (isl_surf_usage_is_depth_or_stencil(info->usage))
+      require_interleaved = true;
+
+   /* From the Ivybridge PRM, Volume 4 Part 1 p72, SURFACE_STATE, Multisampled
+    * Suface Storage Format:
+    *
+    *    If the surface’s Number of Multisamples is MULTISAMPLECOUNT_8, Width
+    *    is >= 8192 (meaning the actual surface width is >= 8193 pixels), this
+    *    field must be set to MSFMT_MSS.
+    */
+   if (info->samples == 8 && info->width == 8192)
+      require_array = true;
+
+   /* From the Ivybridge PRM, Volume 4 Part 1 p72, SURFACE_STATE, Multisampled
+    * Suface Storage Format:
+    *
+    *    If the surface’s Number of Multisamples is MULTISAMPLECOUNT_8,
+    *    ((Depth+1) * (Height+1)) is > 4,194,304, OR if the surface’s Number
+    *    of Multisamples is MULTISAMPLECOUNT_4, ((Depth+1) * (Height+1)) is
+    *    > 8,388,608, this field must be set to MSFMT_DEPTH_STENCIL.
+    */
+   if ((info->samples == 8 && info->height > 4194304u) ||
+       (info->samples == 4 && info->height > 8388608u))
+      require_interleaved = true;
+
+   /* From the Ivybridge PRM, Volume 4 Part 1 p72, SURFACE_STATE, Multisampled
+    * Suface Storage Format:
+    *
+    *    This field must be set to MSFMT_DEPTH_STENCIL if Surface Format is
+    *    one of the following: I24X8_UNORM, L24X8_UNORM, A24X8_UNORM, or
+    *    R24_UNORM_X8_TYPELESS.
+    */
+   if (info->format == ISL_FORMAT_I24X8_UNORM ||
+       info->format == ISL_FORMAT_L24X8_UNORM ||
+       info->format == ISL_FORMAT_A24X8_UNORM ||
+       info->format == ISL_FORMAT_R24_UNORM_X8_TYPELESS)
+      require_interleaved = true;
+
+   if (require_array && require_interleaved)
+      return false;
+
+   if (require_interleaved) {
+      *msaa_layout = ISL_MSAA_LAYOUT_INTERLEAVED;
+      return true;
+   }
+
+   /* Default to the array layout because it permits multisample
+    * compression.
+    */
+   *msaa_layout = ISL_MSAA_LAYOUT_ARRAY;
+   return true;
+}
+
+static bool
+gen7_format_needs_valign2(const struct isl_device *dev,
+                          enum isl_format format)
+{
+   /* This workaround applies only to gen7 */
+   if (ISL_DEV_GEN(dev) > 7)
+      return false;
+
+   /* From the Ivybridge PRM (2012-05-31), Volume 4, Part 1, Section 2.12.1,
+    * RENDER_SURFACE_STATE Surface Vertical Alignment:
+    *
+    *    - Value of 1 [VALIGN_4] is not supported for format YCRCB_NORMAL
+    *      (0x182), YCRCB_SWAPUVY (0x183), YCRCB_SWAPUV (0x18f), YCRCB_SWAPY
+    *      (0x190)
+    *
+    *    - VALIGN_4 is not supported for surface format R32G32B32_FLOAT.
+    */
+   return isl_format_is_yuv(format) ||
+          format == ISL_FORMAT_R32G32B32_FLOAT;
+}
+
+void
+gen7_filter_tiling(const struct isl_device *dev,
+                   const struct isl_surf_init_info *restrict info,
+                   isl_tiling_flags_t *flags)
+{
+   /* IVB+ requires separate stencil */
+   assert(ISL_DEV_USE_SEPARATE_STENCIL(dev));
+
+   /* Clear flags unsupported on this hardware */
+   if (ISL_DEV_GEN(dev) < 9) {
+      *flags &= ~ISL_TILING_Yf_BIT;
+      *flags &= ~ISL_TILING_Ys_BIT;
+   }
+
+   /* And... clear the Yf and Ys bits anyway because Anvil doesn't support
+    * them yet.
+    */
+   *flags &= ~ISL_TILING_Yf_BIT; /* FINISHME[SKL]: Support Yf */
+   *flags &= ~ISL_TILING_Ys_BIT; /* FINISHME[SKL]: Support Ys */
+
+   if (isl_surf_usage_is_depth(info->usage)) {
+      /* Depth requires Y. */
+      *flags &= ISL_TILING_ANY_Y_MASK;
+   }
+
+   /* Separate stencil requires W tiling, and W tiling requires separate
+    * stencil.
+    */
+   if (isl_surf_usage_is_stencil(info->usage)) {
+      *flags &= ISL_TILING_W_BIT;
+   } else {
+      *flags &= ~ISL_TILING_W_BIT;
+   }
+
+   if (info->usage & (ISL_SURF_USAGE_DISPLAY_ROTATE_90_BIT |
+                      ISL_SURF_USAGE_DISPLAY_ROTATE_180_BIT |
+                      ISL_SURF_USAGE_DISPLAY_ROTATE_270_BIT)) {
+      assert(*flags & ISL_SURF_USAGE_DISPLAY_BIT);
+      isl_finishme("%s:%s: handle rotated display surfaces",
+                   __FILE__, __func__);
+   }
+
+   if (info->usage & (ISL_SURF_USAGE_DISPLAY_FLIP_X_BIT |
+                      ISL_SURF_USAGE_DISPLAY_FLIP_Y_BIT)) {
+      assert(*flags & ISL_SURF_USAGE_DISPLAY_BIT);
+      isl_finishme("%s:%s: handle flipped display surfaces",
+                   __FILE__, __func__);
+   }
+
+   if (info->usage & ISL_SURF_USAGE_DISPLAY_BIT) {
+      /* Before Skylake, the display engine does not accept Y */
+      /* FINISHME[SKL]: Y tiling for display surfaces */
+      *flags &= (ISL_TILING_LINEAR_BIT | ISL_TILING_X_BIT);
+   }
+
+   if (info->samples > 1) {
+      /* From the Sandybridge PRM, Volume 4 Part 1, SURFACE_STATE Tiled
+       * Surface:
+       *
+       *   For multisample render targets, this field must be 1 (true). MSRTs
+       *   can only be tiled.
+       *
+       * Multisample surfaces never require X tiling, and Y tiling generally
+       * performs better than X. So choose Y. (Unless it's stencil, then it
+       * must be W).
+       */
+      *flags &= (ISL_TILING_ANY_Y_MASK | ISL_TILING_W_BIT);
+   }
+
+   /* For 1D surfaces, use linear when possible. 1D surfaces (array and
+    * non-array) do not benefit from tiling. In fact, it leads to less
+    * efficient use of memory due to tile alignment.
+    */
+   if (info->dim == ISL_SURF_DIM_1D && (*flags & ISL_TILING_LINEAR_BIT)) {
+      *flags = ISL_TILING_LINEAR_BIT;
+   }
+
+   /* workaround */
+   if (ISL_DEV_GEN(dev) == 7 &&
+       gen7_format_needs_valign2(dev, info->format) &&
+       (info->usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) &&
+       info->samples == 1) {
+      /* Y tiling is illegal. From the Ivybridge PRM, Vol4 Part1 2.12.2.1,
+       * SURFACE_STATE Surface Vertical Alignment:
+       *
+       *     This field must be set to VALIGN_4 for all tiled Y Render Target
+       *     surfaces.
+       */
+      *flags &= ~ISL_TILING_Y0_BIT;
+   }
+}
+
+/**
+ * Choose horizontal LOD alignment, in units of surface elements.
+ */
+static uint32_t
+gen7_choose_halign_el(const struct isl_device *dev,
+                      const struct isl_surf_init_info *restrict info)
+{
+   if (isl_format_is_compressed(info->format))
+      return 1;
+
+   /* From the Ivybridge PRM (2012-05-31), Volume 4, Part 1, Section 2.12.1,
+    * RENDER_SURFACE_STATE Surface Hoizontal Alignment:
+    *
+    *    - This field is intended to be set to HALIGN_8 only if the surface
+    *      was rendered as a depth buffer with Z16 format or a stencil buffer,
+    *      since these surfaces support only alignment of 8. Use of HALIGN_8
+    *      for other surfaces is supported, but uses more memory.
+    */
+   if (isl_surf_info_is_z16(info) ||
+       isl_surf_usage_is_stencil(info->usage))
+      return 8;
+
+   return 4;
+}
+
+/**
+ * Choose vertical LOD alignment, in units of surface elements.
+ */
+static uint32_t
+gen7_choose_valign_el(const struct isl_device *dev,
+                      const struct isl_surf_init_info *restrict info,
+                      enum isl_tiling tiling)
+{
+   bool require_valign2 = false;
+   bool require_valign4 = false;
+
+   if (isl_format_is_compressed(info->format))
+      return 1;
+
+   if (gen7_format_needs_valign2(dev, info->format))
+      require_valign2 = true;
+
+   /* From the Ivybridge PRM, Volume 4, Part 1, Section 2.12.1:
+    * RENDER_SURFACE_STATE Surface Vertical Alignment:
+    *
+    *    - This field is intended to be set to VALIGN_4 if the surface was
+    *      rendered as a depth buffer, for a multisampled (4x) render target,
+    *      or for a multisampled (8x) render target, since these surfaces
+    *      support only alignment of 4.  Use of VALIGN_4 for other surfaces is
+    *      supported, but uses more memory.  This field must be set to
+    *      VALIGN_4 for all tiled Y Render Target surfaces.
+    *
+    */
+   if (isl_surf_usage_is_depth(info->usage) ||
+       info->samples > 1 ||
+       tiling == ISL_TILING_Y0) {
+      require_valign4 = true;
+   }
+
+   if (isl_surf_usage_is_stencil(info->usage)) {
+      /* The Ivybridge PRM states that the stencil buffer's vertical alignment
+       * is 8 [Ivybridge PRM, Volume 1, Part 1, Section 6.18.4.4 Alignment
+       * Unit Size]. However, valign=8 is outside the set of valid values of
+       * RENDER_SURFACE_STATE.SurfaceVerticalAlignment, which is VALIGN_2
+       * (0x0) and VALIGN_4 (0x1).
+       *
+       * The PRM is generally confused about the width, height, and alignment
+       * of the stencil buffer; and this confusion appears elsewhere. For
+       * example, the following PRM text effectively converts the stencil
+       * buffer's 8-pixel alignment to a 4-pixel alignment [Ivybridge PRM,
+       * Volume 1, Part 1, Section
+       * 6.18.4.2 Base Address and LOD Calculation]:
+       *
+       *    For separate stencil buffer, the width must be mutiplied by 2 and
+       *    height divided by 2 as follows:
+       *
+       *       w_L = 2*i*ceil(W_L/i)
+       *       h_L = 1/2*j*ceil(H_L/j)
+       *
+       * The root of the confusion is that, in W tiling, each pair of rows is
+       * interleaved into one.
+       *
+       * FINISHME(chadv): Decide to set valign=4 or valign=8 after isl's API
+       * is more polished.
+       */
+      require_valign4 = true;
+   }
+
+   assert(!require_valign2 || !require_valign4);
+
+   if (require_valign4)
+      return 4;
+
+   /* Prefer VALIGN_2 because it conserves memory. */
+   return 2;
+}
+
+void
+gen7_choose_lod_alignment_el(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_tiling tiling,
+                             enum isl_msaa_layout msaa_layout,
+                             struct isl_extent3d *lod_align_el)
+{
+   /* IVB+ does not support combined depthstencil. */
+   assert(!isl_surf_usage_is_depth_and_stencil(info->usage));
+
+   *lod_align_el = (struct isl_extent3d) {
+      .w = gen7_choose_halign_el(dev, info),
+      .h = gen7_choose_valign_el(dev, info, tiling),
+      .d = 1,
+   };
+}
diff --git a/src/vulkan/isl_gen7.h b/src/vulkan/isl_gen7.h
new file mode 100644 (file)
index 0000000..c39bd40
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "isl_priv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+gen7_filter_tiling(const struct isl_device *dev,
+                   const struct isl_surf_init_info *restrict info,
+                   isl_tiling_flags_t *flags);
+
+bool
+gen7_choose_msaa_layout(const struct isl_device *dev,
+                        const struct isl_surf_init_info *info,
+                        enum isl_tiling tiling,
+                        enum isl_msaa_layout *msaa_layout);
+
+void
+gen7_choose_lod_alignment_el(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_tiling tiling,
+                             enum isl_msaa_layout msaa_layout,
+                             struct isl_extent3d *lod_align_el);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/vulkan/isl_gen8.c b/src/vulkan/isl_gen8.c
new file mode 100644 (file)
index 0000000..fe118ca
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#include "isl_gen8.h"
+#include "isl_priv.h"
+
+bool
+gen8_choose_msaa_layout(const struct isl_device *dev,
+                        const struct isl_surf_init_info *info,
+                        enum isl_tiling tiling,
+                        enum isl_msaa_layout *msaa_layout)
+{
+   bool require_array = false;
+   bool require_interleaved = false;
+
+   assert(info->samples >= 1);
+
+   if (info->samples == 1) {
+      *msaa_layout = ISL_MSAA_LAYOUT_NONE;
+      return true;
+   }
+
+   /* From the Broadwell PRM >> Volume2d: Command Structures >>
+    * RENDER_SURFACE_STATE Tile Mode:
+    *
+    *    - If Number of Multisamples is not MULTISAMPLECOUNT_1, this field
+    *      must be YMAJOR.
+    *
+    * As usual, though, stencil is special.
+    */
+   if (!isl_tiling_is_std_y(tiling) && !isl_surf_usage_is_stencil(info->usage))
+      return false;
+
+   /* From the Broadwell PRM >> Volume2d: Command Structures >>
+    * RENDER_SURFACE_STATE Multisampled Surface Storage Format:
+    *
+    *    All multisampled render target surfaces must have this field set to
+    *    MSFMT_MSS
+    */
+   if (info->usage & ISL_SURF_USAGE_RENDER_TARGET_BIT)
+      require_array = true;
+
+   /* From the Broadwell PRM >> Volume2d: Command Structures >>
+    * RENDER_SURFACE_STATE Number of Multisamples:
+    *
+    *    - If this field is any value other than MULTISAMPLECOUNT_1, the
+    *      Surface Type must be SURFTYPE_2D This field must be set to
+    *      MULTISAMPLECOUNT_1 unless the surface is a Sampling Engine surface
+    *      or Render Target surface.
+    *
+    *    - If this field is any value other than MULTISAMPLECOUNT_1, Surface
+    *      Min LOD, Mip Count / LOD, and Resource Min LOD must be set to zero.
+    */
+   if (info->dim != ISL_SURF_DIM_2D)
+      return false;
+   if (info->levels > 1)
+      return false;
+
+   /* More obvious restrictions */
+   if (isl_surf_usage_is_display(info->usage))
+      return false;
+   if (isl_format_is_compressed(info->format))
+      return false;
+   if (isl_format_is_yuv(info->format))
+      return false;
+
+   if (isl_surf_usage_is_depth_or_stencil(info->usage))
+      require_interleaved = true;
+
+   if (require_array && require_interleaved)
+      return false;
+
+   if (require_interleaved) {
+      *msaa_layout = ISL_MSAA_LAYOUT_INTERLEAVED;
+      return true;
+   }
+
+   *msaa_layout = ISL_MSAA_LAYOUT_ARRAY;
+   return true;
+}
+
+/**
+ * Choose horizontal LOD alignment, in units of surface elements.
+ */
+static uint32_t
+gen8_choose_halign_el(const struct isl_device *dev,
+                      const struct isl_surf_init_info *restrict info)
+{
+   if (isl_format_is_compressed(info->format))
+      return 1;
+
+   /* From the Broadwell PRM, Volume 2d "Command Reference: Structures",
+    * RENDER_SURFACE_STATE Surface Horizontal Alignment, p326:
+    *
+    *    - This field is intended to be set to HALIGN_8 only if the surface
+    *      was rendered as a depth buffer with Z16 format or a stencil buffer.
+    *      In this case it must be set to HALIGN_8 since these surfaces
+    *      support only alignment of 8. [...]
+    */
+   if (isl_surf_info_is_z16(info))
+      return 8;
+   if (isl_surf_usage_is_stencil(info->usage))
+      return 8;
+
+   /* From the Broadwell PRM, Volume 2d "Command Reference: Structures",
+    * RENDER_SURFACE_STATE Surface Horizontal Alignment, p326:
+    *
+    *      [...] For Z32 formats it must be set to HALIGN_4.
+    */
+   if (isl_surf_usage_is_depth(info->usage))
+      return 4;
+
+   if (!(info->usage & ISL_SURF_USAGE_DISABLE_AUX_BIT)) {
+      /* From the Broadwell PRM, Volume 2d "Command Reference: Structures",
+       * RENDER_SURFACE_STATE Surface Horizontal Alignment, p326:
+       *
+       *    - When Auxiliary Surface Mode is set to AUX_CCS_D or AUX_CCS_E,
+       *      HALIGN 16 must be used.
+       *
+       * This case handles color surfaces that may own an auxiliary MCS, CCS_D,
+       * or CCS_E. Depth buffers, including those that own an auxiliary HiZ
+       * surface, are handled above and do not require HALIGN_16.
+       */
+      assert(!isl_surf_usage_is_depth(info->usage));
+      return 16;
+   }
+
+   /* XXX(chadv): I believe the hardware requires each image to be
+    * cache-aligned. If that's true, then defaulting to halign=4 is wrong for
+    * many formats. Depending on the format's block size, we may need to
+    * increase halign to 8.
+    */
+   return 4;
+}
+
+/**
+ * Choose vertical LOD alignment, in units of surface elements.
+ */
+static uint32_t
+gen8_choose_valign_el(const struct isl_device *dev,
+                      const struct isl_surf_init_info *restrict info)
+{
+   /* From the Broadwell PRM > Volume 2d: Command Reference: Structures
+    * > RENDER_SURFACE_STATE Surface Vertical Alignment (p325):
+    *
+    *    - For Sampling Engine and Render Target Surfaces: This field
+    *      specifies the vertical alignment requirement in elements for the
+    *      surface. [...] An element is defined as a pixel in uncompresed
+    *      surface formats, and as a compression block in compressed surface
+    *      formats. For MSFMT_DEPTH_STENCIL type multisampled surfaces, an
+    *      element is a sample.
+    *
+    *    - This field is intended to be set to VALIGN_4 if the surface was
+    *      rendered as a depth buffer, for a multisampled (4x) render target,
+    *      or for a multisampled (8x) render target, since these surfaces
+    *      support only alignment of 4. Use of VALIGN_4 for other surfaces is
+    *      supported, but increases memory usage.
+    *
+    *    - This field is intended to be set to VALIGN_8 only if the surface
+    *       was rendered as a stencil buffer, since stencil buffer surfaces
+    *       support only alignment of 8. If set to VALIGN_8, Surface Format
+    *       must be R8_UINT.
+    */
+
+   if (isl_format_is_compressed(info->format))
+      return 1;
+
+   if (isl_surf_usage_is_stencil(info->usage))
+      return 8;
+
+   return 4;
+}
+
+void
+gen8_choose_lod_alignment_el(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_tiling tiling,
+                             enum isl_msaa_layout msaa_layout,
+                             struct isl_extent3d *lod_align_el)
+{
+   assert(!isl_tiling_is_std_y(tiling));
+
+   /* The below text from the Broadwell PRM provides some insight into the
+    * hardware's requirements for LOD alignment.  From the Broadwell PRM >>
+    * Volume 5: Memory Views >> Surface Layout >> 2D Surfaces:
+    *
+    *    These [2D surfaces] must adhere to the following memory organization
+    *    rules:
+    *
+    *       - For non-compressed texture formats, each mipmap must start on an
+    *         even row within the monolithic rectangular area. For
+    *         1-texel-high mipmaps, this may require a row of padding below
+    *         the previous mipmap. This restriction does not apply to any
+    *         compressed texture formats; each subsequent (lower-res)
+    *         compressed mipmap is positioned directly below the previous
+    *         mipmap.
+    *
+    *       - Vertical alignment restrictions vary with memory tiling type:
+    *         1 DWord for linear, 16-byte (DQWord) for tiled. (Note that tiled
+    *         mipmaps are not required to start at the left edge of a tile
+    *         row.)
+    */
+
+   *lod_align_el = (struct isl_extent3d) {
+      .w = gen8_choose_halign_el(dev, info),
+      .h = gen8_choose_valign_el(dev, info),
+      .d = 1,
+   };
+}
diff --git a/src/vulkan/isl_gen8.h b/src/vulkan/isl_gen8.h
new file mode 100644 (file)
index 0000000..632d619
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "isl_priv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool
+gen8_choose_msaa_layout(const struct isl_device *dev,
+                        const struct isl_surf_init_info *info,
+                        enum isl_tiling tiling,
+                        enum isl_msaa_layout *msaa_layout);
+
+void
+gen8_choose_lod_alignment_el(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_tiling tiling,
+                             enum isl_msaa_layout msaa_layout,
+                             struct isl_extent3d *lod_align_el);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/vulkan/isl_gen9.c b/src/vulkan/isl_gen9.c
new file mode 100644 (file)
index 0000000..00634e4
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#include "isl_gen8.h"
+#include "isl_gen9.h"
+#include "isl_priv.h"
+
+/**
+ * Calculate the LOD alignment, in units of surface samples, for the standard
+ * tiling formats Yf and Ys.
+ */
+static void
+gen9_calc_std_lod_alignment_sa(const struct isl_device *dev,
+                               const struct isl_surf_init_info *restrict info,
+                               enum isl_tiling tiling,
+                               enum isl_msaa_layout msaa_layout,
+                               struct isl_extent3d *align_sa)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
+
+   assert(isl_tiling_is_std_y(tiling));
+
+   const uint32_t bs = fmtl->bs;
+   const uint32_t is_Ys = tiling == ISL_TILING_Ys;
+
+   switch (info->dim) {
+   case ISL_SURF_DIM_1D:
+      /* See the Skylake BSpec > Memory Views > Common Surface Formats > Surface
+       * Layout and Tiling > 1D Surfaces > 1D Alignment Requirements.
+       */
+      *align_sa = (struct isl_extent3d) {
+         .w = 1 << (12 - (ffs(bs) - 1) + (4 * is_Ys)),
+         .h = 1,
+         .d = 1,
+      };
+      return;
+   case ISL_SURF_DIM_2D:
+      /* See the Skylake BSpec > Memory Views > Common Surface Formats >
+       * Surface Layout and Tiling > 2D Surfaces > 2D/CUBE Alignment
+       * Requirements.
+       */
+      *align_sa = (struct isl_extent3d) {
+         .w = 1 << (6 - ((ffs(bs) - 1) / 2) + (4 * is_Ys)),
+         .h = 1 << (6 - ((ffs(bs) - 0) / 2) + (4 * is_Ys)),
+         .d = 1,
+      };
+
+      if (is_Ys) {
+         /* FINISHME(chadv): I don't trust this code. Untested. */
+         isl_finishme("%s:%s: [SKL+] multisample TileYs", __FILE__, __func__);
+
+         switch (msaa_layout) {
+         case ISL_MSAA_LAYOUT_NONE:
+         case ISL_MSAA_LAYOUT_INTERLEAVED:
+            break;
+         case ISL_MSAA_LAYOUT_ARRAY:
+            align_sa->w >>= (ffs(info->samples) - 0) / 2;
+            align_sa->h >>= (ffs(info->samples) - 1) / 2;
+            break;
+         }
+      }
+      return;
+
+   case ISL_SURF_DIM_3D:
+      /* See the Skylake BSpec > Memory Views > Common Surface Formats > Surface
+       * Layout and Tiling > 1D Surfaces > 1D Alignment Requirements.
+       */
+      *align_sa = (struct isl_extent3d) {
+         .w = 1 << (4 - ((ffs(bs) + 1) / 3) + (4 * is_Ys)),
+         .h = 1 << (4 - ((ffs(bs) - 1) / 3) + (2 * is_Ys)),
+         .d = 1 << (4 - ((ffs(bs) - 0) / 3) + (2 * is_Ys)),
+      };
+      return;
+   }
+
+   unreachable("bad isl_surface_type");
+}
+
+void
+gen9_choose_lod_alignment_el(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_tiling tiling,
+                             enum isl_msaa_layout msaa_layout,
+                             struct isl_extent3d *lod_align_el)
+{
+   /* This BSpec text provides some insight into the hardware's alignment
+    * requirements [Skylake BSpec > Memory Views > Common Surface Formats >
+    * Surface Layout and Tiling > 2D Surfaces]:
+    *
+    *    An LOD must be aligned to a cache-line except for some special cases
+    *    related to Planar YUV surfaces.  In general, the cache-alignment
+    *    restriction implies there is a minimum height for an LOD of 4 texels.
+    *    So, LODs which are smaller than 4 high are padded.
+    *
+    * From the Skylake BSpec, RENDER_SURFACE_STATE Surface Vertical Alignment:
+    *
+    *    - For Sampling Engine and Render Target Surfaces: This field
+    *      specifies the vertical alignment requirement in elements for the
+    *      surface. [...] An element is defined as a pixel in uncompresed
+    *      surface formats, and as a compression block in compressed surface
+    *      formats. For MSFMT_DEPTH_STENCIL type multisampled surfaces, an
+    *      element is a sample.
+    *
+    *    - This field is used for 2D, CUBE, and 3D surface alignment when Tiled
+    *      Resource Mode is TRMODE_NONE (Tiled Resource Mode is disabled).
+    *      This field is ignored for 1D surfaces and also when Tiled Resource
+    *      Mode is not TRMODE_NONE (e.g. Tiled Resource Mode is enabled).
+    *
+    *      See the appropriate Alignment  table in the "Surface Layout and
+    *      Tiling" section under Common Surface Formats for the table of
+    *      alignment values for Tiled Resrouces.
+    *
+    *    - For uncompressed surfaces, the units of "j" are rows of pixels on
+    *      the physical surface. For compressed texture formats, the units of
+    *      "j" are in compression blocks, thus each increment in "j" is equal
+    *      to h pixels, where h is the height of the compression block in
+    *      pixels.
+    *
+    *    - Valid Values: VALIGN_4, VALIGN_8, VALIGN_16
+    *
+    * From the Skylake BSpec, RENDER_SURFACE_STATE Surface Horizontal
+    * Alignment:
+    *
+    *    -  For uncompressed surfaces, the units of "i" are pixels on the
+    *       physical surface. For compressed texture formats, the units of "i"
+    *       are in compression blocks, thus each increment in "i" is equal to
+    *       w pixels, where w is the width of the compression block in pixels.
+    *
+    *    - Valid Values: HALIGN_4, HALIGN_8, HALIGN_16
+    */
+
+   if (isl_tiling_is_std_y(tiling)) {
+      struct isl_extent3d lod_align_sa;
+      gen9_calc_std_lod_alignment_sa(dev, info, tiling, msaa_layout,
+                                     &lod_align_sa);
+
+      *lod_align_el = isl_extent3d_sa_to_el(info->format, lod_align_sa);
+      return;
+   }
+
+   if (info->dim == ISL_SURF_DIM_1D) {
+      /* See the Skylake BSpec > Memory Views > Common Surface Formats > Surface
+       * Layout and Tiling > 1D Surfaces > 1D Alignment Requirements.
+       */
+      *lod_align_el = isl_extent3d(64, 1, 1);
+      return;
+   }
+
+   if (isl_format_is_compressed(info->format)) {
+      /* On Gen9, the meaning of RENDER_SURFACE_STATE's
+       * SurfaceHorizontalAlignment and SurfaceVerticalAlignment changed for
+       * compressed formats. They now indicate a multiple of the compression
+       * block.  For example, if the compression mode is ETC2 then HALIGN_4
+       * indicates a horizontal alignment of 16 pixels.
+       *
+       * To avoid wasting memory, choose the smallest alignment possible:
+       * HALIGN_4 and VALIGN_4.
+       */
+      *lod_align_el = isl_extent3d(4, 4, 1);
+      return;
+   }
+
+   gen8_choose_lod_alignment_el(dev, info, tiling, msaa_layout, lod_align_el);
+}
diff --git a/src/vulkan/isl_gen9.h b/src/vulkan/isl_gen9.h
new file mode 100644 (file)
index 0000000..14252b6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "isl_priv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+gen9_choose_lod_alignment_el(const struct isl_device *dev,
+                             const struct isl_surf_init_info *restrict info,
+                             enum isl_tiling tiling,
+                             enum isl_msaa_layout msaa_layout,
+                             struct isl_extent3d *lod_align_el);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/vulkan/isl_priv.h b/src/vulkan/isl_priv.h
new file mode 100644 (file)
index 0000000..1c9343a
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2015 Intel Corporation
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ *  IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <assert.h>
+
+#include "brw_device_info.h"
+#include "mesa/main/imports.h"
+#include "util/macros.h"
+
+#include "isl.h"
+
+#define isl_finishme(format, ...) \
+   __isl_finishme(__FILE__, __LINE__, format, ##__VA_ARGS__)
+
+void PRINTFLIKE(3, 4) UNUSED
+__isl_finishme(const char *file, int line, const char *fmt, ...);
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+static inline uint32_t
+ffs(uint32_t n) {
+   return __builtin_ffs(n);
+}
+
+static inline bool
+isl_is_pow2(uintmax_t n)
+{
+   return !(n & (n - 1));
+}
+
+/**
+ * Alignment must be a power of 2.
+ */
+static inline bool
+isl_is_aligned(uintmax_t n, uintmax_t a)
+{
+   assert(isl_is_pow2(a));
+   return (n & (a - 1)) == 0;
+}
+
+/**
+ * Alignment must be a power of 2.
+ */
+static inline uintmax_t
+isl_align(uintmax_t n, uintmax_t a)
+{
+   assert(isl_is_pow2(a));
+   return (n + a - 1) & ~(a - 1);
+}
+
+static inline uintmax_t
+isl_align_npot(uintmax_t n, uintmax_t a)
+{
+   assert(a > 0);
+   return ((n + a - 1) / a) * a;
+}
+
+/**
+ * Alignment must be a power of 2.
+ */
+static inline uintmax_t
+isl_align_div(uintmax_t n, uintmax_t a)
+{
+   return isl_align(n, a) / a;
+}
+
+static inline uintmax_t
+isl_align_div_npot(uintmax_t n, uintmax_t a)
+{
+   return isl_align_npot(n, a) / a;
+}
+
+/**
+ * Log base 2, rounding towards zero.
+ */
+static inline uint32_t
+isl_log2u(uint32_t n)
+{
+   assert(n != 0);
+   return 31 - __builtin_clz(n);
+}
+
+static inline uint32_t
+isl_minify(uint32_t n, uint32_t levels)
+{
+   if (unlikely(n == 0))
+      return 0;
+   else
+      return MAX(n >> levels, 1);
+}
+
+static inline struct isl_extent3d
+isl_extent3d_sa_to_el(enum isl_format fmt, struct isl_extent3d extent_sa)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(fmt);
+
+   assert(extent_sa.w % fmtl->bw == 0);
+   assert(extent_sa.h % fmtl->bh == 0);
+   assert(extent_sa.d % fmtl->bd == 0);
+
+   return (struct isl_extent3d) {
+      .w = extent_sa.w / fmtl->bw,
+      .h = extent_sa.h / fmtl->bh,
+      .d = extent_sa.d / fmtl->bd,
+   };
+}
+
+static inline struct isl_extent3d
+isl_extent3d_el_to_sa(enum isl_format fmt, struct isl_extent3d extent_el)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(fmt);
+
+   return (struct isl_extent3d) {
+      .w = extent_el.w * fmtl->bw,
+      .h = extent_el.h * fmtl->bh,
+      .d = extent_el.d * fmtl->bd,
+   };
+}