summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Ekstrand <[email protected]>2017-05-29 21:45:00 -0700
committerJason Ekstrand <[email protected]>2017-06-01 15:33:47 -0700
commit757f7087a5d9b106767220393772043ba70c157b (patch)
treece4f38c79475ea0d3ce5d992599bd937c7a1aac3
parentcb8cdab8e8479488d4aabb2553c099f1f99c185b (diff)
intel/isl: Add a new layout for HiZ and stencil on Sandy Bridge
Reviewed-by: Topi Pohjolainen <[email protected]>
-rw-r--r--src/intel/isl/isl.c162
-rw-r--r--src/intel/isl/isl.h40
2 files changed, 197 insertions, 5 deletions
diff --git a/src/intel/isl/isl.c b/src/intel/isl/isl.c
index 77b8a4087df..1227238b186 100644
--- a/src/intel/isl/isl.c
+++ b/src/intel/isl/isl.c
@@ -479,6 +479,12 @@ isl_choose_array_pitch_span(const struct isl_device *dev,
* compact QPitch possible in order to conserve memory.
*/
return ISL_ARRAY_PITCH_SPAN_COMPACT;
+
+ case ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ:
+ /* Each array image in the gen6 stencil of HiZ surface is compact in the
+ * sense that every LOD is a compact array of the same size as LOD0.
+ */
+ return ISL_ARRAY_PITCH_SPAN_COMPACT;
}
unreachable("bad isl_dim_layout");
@@ -510,10 +516,15 @@ isl_choose_image_alignment_el(const struct isl_device *dev,
return;
} else if (info->format == ISL_FORMAT_HIZ) {
assert(ISL_DEV_GEN(dev) >= 6);
- /* HiZ surfaces are always aligned to 16x8 pixels in the primary surface
- * which works out to 2x2 HiZ elments.
- */
- *image_align_el = isl_extent3d(2, 2, 1);
+ if (ISL_DEV_GEN(dev) == 6) {
+ /* HiZ surfaces on Sandy Bridge are packed tightly. */
+ *image_align_el = isl_extent3d(1, 1, 1);
+ } else {
+ /* On gen7+, HiZ surfaces are always aligned to 16x8 pixels in the
+ * primary surface which works out to 2x2 HiZ elments.
+ */
+ *image_align_el = isl_extent3d(2, 2, 1);
+ }
return;
}
@@ -540,6 +551,11 @@ isl_surf_choose_dim_layout(const struct isl_device *dev,
enum isl_surf_dim logical_dim,
enum isl_tiling tiling)
{
+ /* Sandy bridge needs a special layout for HiZ and stencil. */
+ if (ISL_DEV_GEN(dev) == 6 &&
+ (tiling == ISL_TILING_W || tiling == ISL_TILING_HIZ))
+ return ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ;
+
if (ISL_DEV_GEN(dev) >= 9) {
switch (logical_dim) {
case ISL_SURF_DIM_1D:
@@ -608,6 +624,7 @@ isl_calc_phys_level0_extent_sa(const struct isl_device *dev,
case ISL_DIM_LAYOUT_GEN9_1D:
case ISL_DIM_LAYOUT_GEN4_2D:
+ case ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ:
*phys_level0_sa = (struct isl_extent4d) {
.w = isl_align_npot(info->width, fmtl->bw),
.h = fmtl->bh,
@@ -619,7 +636,8 @@ isl_calc_phys_level0_extent_sa(const struct isl_device *dev,
break;
case ISL_SURF_DIM_2D:
- assert(dim_layout == ISL_DIM_LAYOUT_GEN4_2D);
+ assert(dim_layout == ISL_DIM_LAYOUT_GEN4_2D ||
+ dim_layout == ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ);
if (tiling == ISL_TILING_Ys && info->samples > 1)
isl_finishme("%s:%s: multisample TileYs layout", __FILE__, __func__);
@@ -684,6 +702,7 @@ isl_calc_phys_level0_extent_sa(const struct isl_device *dev,
switch (dim_layout) {
case ISL_DIM_LAYOUT_GEN9_1D:
+ case ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ:
unreachable("bad isl_dim_layout");
case ISL_DIM_LAYOUT_GEN4_2D:
@@ -969,6 +988,67 @@ isl_calc_phys_total_extent_el_gen4_3d(
/**
* A variant of isl_calc_phys_slice0_extent_sa() specific to
+ * ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ.
+ */
+static void
+isl_calc_phys_total_extent_el_gen6_stencil_hiz(
+ const struct isl_device *dev,
+ const struct isl_surf_init_info *restrict info,
+ const struct isl_tile_info *tile_info,
+ const struct isl_extent3d *image_align_sa,
+ const struct isl_extent4d *phys_level0_sa,
+ uint32_t *array_pitch_el_rows,
+ struct isl_extent2d *phys_total_el)
+{
+ const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
+
+ const struct isl_extent2d tile_extent_sa = {
+ .w = tile_info->logical_extent_el.w * fmtl->bw,
+ .h = tile_info->logical_extent_el.h * fmtl->bh,
+ };
+ /* Tile size is a multiple of image alignment */
+ assert(tile_extent_sa.w % image_align_sa->w == 0);
+ assert(tile_extent_sa.h % image_align_sa->h == 0);
+
+ const uint32_t W0 = phys_level0_sa->w;
+ const uint32_t H0 = phys_level0_sa->h;
+
+ /* Each image has the same height as LOD0 because the hardware thinks
+ * everything is LOD0
+ */
+ const uint32_t H = isl_align(H0, image_align_sa->h) * phys_level0_sa->a;
+
+ uint32_t total_top_w = 0;
+ uint32_t total_bottom_w = 0;
+ uint32_t total_h = 0;
+
+ for (uint32_t l = 0; l < info->levels; ++l) {
+ const uint32_t W = isl_minify(W0, l);
+
+ const uint32_t w = isl_align(W, tile_extent_sa.w);
+ const uint32_t h = isl_align(H, tile_extent_sa.h);
+
+ if (l == 0) {
+ total_top_w = w;
+ total_h = h;
+ } else if (l == 1) {
+ total_bottom_w = w;
+ total_h += h;
+ } else {
+ total_bottom_w += w;
+ }
+ }
+
+ *array_pitch_el_rows =
+ isl_assert_div(isl_align(H0, image_align_sa->h), fmtl->bh);
+ *phys_total_el = (struct isl_extent2d) {
+ .w = isl_assert_div(MAX(total_top_w, total_bottom_w), fmtl->bw),
+ .h = isl_assert_div(total_h, fmtl->bh),
+ };
+}
+
+/**
+ * A variant of isl_calc_phys_slice0_extent_sa() specific to
* ISL_DIM_LAYOUT_GEN9_1D.
*/
static void
@@ -1035,6 +1115,14 @@ isl_calc_phys_total_extent_el(const struct isl_device *dev,
array_pitch_el_rows,
total_extent_el);
return;
+ case ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ:
+ assert(array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT);
+ isl_calc_phys_total_extent_el_gen6_stencil_hiz(dev, info, tile_info,
+ image_align_sa,
+ phys_level0_sa,
+ array_pitch_el_rows,
+ total_extent_el);
+ return;
case ISL_DIM_LAYOUT_GEN4_3D:
assert(array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT);
isl_calc_phys_total_extent_el_gen4_3d(dev, info,
@@ -1892,6 +1980,65 @@ get_image_offset_sa_gen4_3d(const struct isl_surf *surf,
*y_offset_sa = y;
}
+static void
+get_image_offset_sa_gen6_stencil_hiz(const struct isl_surf *surf,
+ uint32_t level,
+ uint32_t logical_array_layer,
+ uint32_t *x_offset_sa,
+ uint32_t *y_offset_sa)
+{
+ assert(level < surf->levels);
+ assert(surf->logical_level0_px.depth == 1);
+ assert(logical_array_layer < surf->logical_level0_px.array_len);
+
+ const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
+
+ const struct isl_extent3d image_align_sa =
+ isl_surf_get_image_alignment_sa(surf);
+
+ struct isl_tile_info tile_info;
+ isl_tiling_get_info(surf->tiling, fmtl->bpb, &tile_info);
+ const struct isl_extent2d tile_extent_sa = {
+ .w = tile_info.logical_extent_el.w * fmtl->bw,
+ .h = tile_info.logical_extent_el.h * fmtl->bh,
+ };
+ /* Tile size is a multiple of image alignment */
+ assert(tile_extent_sa.w % image_align_sa.w == 0);
+ assert(tile_extent_sa.h % image_align_sa.h == 0);
+
+ const uint32_t W0 = surf->phys_level0_sa.w;
+ const uint32_t H0 = surf->phys_level0_sa.h;
+
+ /* Each image has the same height as LOD0 because the hardware thinks
+ * everything is LOD0
+ */
+ const uint32_t H = isl_align(H0, image_align_sa.h);
+
+ /* Quick sanity check for consistency */
+ if (surf->phys_level0_sa.array_len > 1)
+ assert(surf->array_pitch_el_rows == isl_assert_div(H, fmtl->bh));
+
+ uint32_t x = 0, y = 0;
+ for (uint32_t l = 0; l < level; ++l) {
+ const uint32_t W = isl_minify(W0, l);
+
+ const uint32_t w = isl_align(W, tile_extent_sa.w);
+ const uint32_t h = isl_align(H * surf->phys_level0_sa.a,
+ tile_extent_sa.h);
+
+ if (l == 0) {
+ y += h;
+ } else {
+ x += w;
+ }
+ }
+
+ y += H * logical_array_layer;
+
+ *x_offset_sa = x;
+ *y_offset_sa = y;
+}
+
/**
* A variant of isl_surf_get_image_offset_sa() specific to
* ISL_DIM_LAYOUT_GEN9_1D.
@@ -1961,6 +2108,11 @@ isl_surf_get_image_offset_sa(const struct isl_surf *surf,
logical_z_offset_px,
x_offset_sa, y_offset_sa);
break;
+ case ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ:
+ get_image_offset_sa_gen6_stencil_hiz(surf, level, logical_array_layer +
+ logical_z_offset_px,
+ x_offset_sa, y_offset_sa);
+ break;
default:
unreachable("not reached");
diff --git a/src/intel/isl/isl.h b/src/intel/isl/isl.h
index 008ab5e819b..4bb3de78973 100644
--- a/src/intel/isl/isl.h
+++ b/src/intel/isl/isl.h
@@ -528,6 +528,46 @@ enum isl_dim_layout {
ISL_DIM_LAYOUT_GEN4_3D,
/**
+ * Special layout used for HiZ and stencil on Sandy Bridge to work around
+ * the hardware's lack of mipmap support. On gen6, HiZ and stencil buffers
+ * work the same as on gen7+ except that they don't technically support
+ * mipmapping. That does not, however, stop us from doing it. As far as
+ * Sandy Bridge hardware is concerned, HiZ and stencil always operates on a
+ * single miplevel 2D (possibly array) image. The dimensions of that image
+ * are NOT minified.
+ *
+ * In order to implement HiZ and stencil on Sandy Bridge, we create one
+ * full-sized 2D (possibly array) image for every LOD with every image
+ * aligned to a page boundary. When the surface is used with the stencil
+ * or HiZ hardware, we manually offset to the image for the given LOD.
+ *
+ * As a memory saving measure, we pretend that the width of each miplevel
+ * is minified and we place LOD1 and above below LOD0 but horizontally
+ * adjacent to each other. When considered as full-sized images, LOD1 and
+ * above technically overlap. However, since we only write to part of that
+ * image, the hardware will never notice the overlap.
+ *
+ * This layout looks something like this:
+ *
+ * +---------+
+ * | |
+ * | |
+ * +---------+
+ * | |
+ * | |
+ * +---------+
+ *
+ * +----+ +-+ .
+ * | | +-+
+ * +----+
+ *
+ * +----+ +-+ .
+ * | | +-+
+ * +----+
+ */
+ ISL_DIM_LAYOUT_GEN6_STENCIL_HIZ,
+
+ /**
* For details, see the Skylake BSpec >> Memory Views >> Common Surface
* Formats >> Surface Layout and Tiling >> ยป 1D Surfaces.
*/