isl: Add func isl_surf_get_image_offset_sa
authorChad Versace <chad.versace@intel.com>
Sat, 12 Dec 2015 01:14:52 +0000 (17:14 -0800)
committerChad Versace <chad.versace@intel.com>
Tue, 15 Dec 2015 16:46:09 +0000 (08:46 -0800)
The function calculates the offset to a subimage within the surface, in
units of surface samples.

All unit tests pass with `make check`. (Admittedly, though, there are
too few unit tests).

src/isl/Makefile.am
src/isl/isl.c
src/isl/isl.h
src/isl/tests/.gitignore [new file with mode: 0644]
src/isl/tests/isl_surf_get_image_offset_test.c [new file with mode: 0644]

index 6a5c29c67cb6a01eedba7d9165c7e0f54571f1e4..134e62ad10530a2cacf33787c947c95842df0591 100644 (file)
@@ -23,6 +23,8 @@ SUBDIRS = .
 
 noinst_LTLIBRARIES = libisl.la
 
+EXTRA_DIST = tests
+
 # The gallium includes are for the util/u_math.h include from main/macros.h
 AM_CPPFLAGS = \
        $(INTEL_CFLAGS) \
@@ -64,4 +66,23 @@ isl_format_layout.c: isl_format_layout_gen.bash \
        $(AM_V_GEN)$(srcdir)/isl_format_layout_gen.bash \
            <$(srcdir)/isl_format_layout.csv >$@
 
+# ----------------------------------------------------------------------------
+#  Tests
+# ----------------------------------------------------------------------------
+
+TESTS = tests/isl_surf_get_image_offset_test
+
+check_PROGRAMS = $(TESTS)
+
+# Link tests to lib965_compiler.la for brw_get_device_info().
+tests_ldadd =                                          \
+       libisl.la                                       \
+       $(top_builddir)/src/mesa/drivers/dri/i965/libi965_compiler.la
+
+tests_isl_surf_get_image_offset_test_SOURCES =         \
+       tests/isl_surf_get_image_offset_test.c
+tests_isl_surf_get_image_offset_test_LDADD = $(tests_ldadd)
+
+# ----------------------------------------------------------------------------
+
 include $(top_srcdir)/install-lib-links.mk
index 333a517f2741e32f292a3f863ebffa0f41ad58b8..df0aeed01dff747adf91a6b6770e5a29dabb151f 100644 (file)
@@ -225,8 +225,10 @@ isl_msaa_interleaved_scale_px_to_sa(uint32_t samples,
     *    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);
+   if (width)
+      *width = isl_align(*width, 2) << ((ffs(samples) - 0) / 2);
+   if (height)
+      *height = isl_align(*height, 2) << ((ffs(samples) - 1) / 2);
 }
 
 static enum isl_array_pitch_span
@@ -1045,3 +1047,121 @@ isl_surf_init_s(const struct isl_device *dev,
 
    return true;
 }
+
+/**
+ * A variant of isl_surf_get_image_offset_sa() specific to
+ * ISL_DIM_LAYOUT_GEN4_2D.
+ */
+static void
+get_image_offset_sa_gen4_2d(const struct isl_surf *surf,
+                            uint32_t level, uint32_t layer,
+                            uint32_t *x_offset_sa,
+                            uint32_t *y_offset_sa)
+{
+   assert(level < surf->levels);
+   assert(layer < surf->phys_level0_sa.array_len);
+   assert(surf->phys_level0_sa.depth == 1);
+
+   const struct isl_extent3d image_align_sa =
+      isl_surf_get_image_alignment_sa(surf);
+
+   const uint32_t W0 = surf->phys_level0_sa.width;
+   const uint32_t H0 = surf->phys_level0_sa.height;
+
+   uint32_t x = 0;
+   uint32_t y = layer * isl_surf_get_array_pitch_sa_rows(surf);
+
+   for (uint32_t l = 0; l < level; ++l) {
+      if (l == 1) {
+         uint32_t W = isl_minify(W0, l);
+
+         if (surf->msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED)
+            isl_msaa_interleaved_scale_px_to_sa(surf->samples, &W, NULL);
+
+         x += isl_align_npot(W, image_align_sa.w);
+      } else {
+         uint32_t H = isl_minify(H0, l);
+
+         if (surf->msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED)
+            isl_msaa_interleaved_scale_px_to_sa(surf->samples, NULL, &H);
+
+         y += isl_align_npot(H, image_align_sa.h);
+      }
+   }
+
+   *x_offset_sa = x;
+   *y_offset_sa = y;
+}
+
+/**
+ * A variant of isl_surf_get_image_offset_sa() specific to
+ * ISL_DIM_LAYOUT_GEN4_3D.
+ */
+static void
+get_image_offset_sa_gen4_3d(const struct isl_surf *surf,
+                            uint32_t level, uint32_t logical_z_offset_px,
+                            uint32_t *x_offset_sa,
+                            uint32_t *y_offset_sa)
+{
+   assert(level < surf->levels);
+   assert(logical_z_offset_px < isl_minify(surf->phys_level0_sa.depth, level));
+   assert(surf->phys_level0_sa.array_len == 1);
+
+   const struct isl_extent3d image_align_sa =
+      isl_surf_get_image_alignment_sa(surf);
+
+   const uint32_t W0 = surf->phys_level0_sa.width;
+   const uint32_t H0 = surf->phys_level0_sa.height;
+   const uint32_t D0 = surf->phys_level0_sa.depth;
+
+   uint32_t x = 0;
+   uint32_t y = 0;
+
+   for (uint32_t l = 0; l < level; ++l) {
+      const uint32_t level_h = isl_align_npot(isl_minify(H0, l), image_align_sa.h);
+      const uint32_t level_d = isl_align_npot(isl_minify(D0, l), image_align_sa.d);
+      const uint32_t max_layers_vert = isl_align(level_d, 1u << l) / (1u << l);
+
+      y += level_h * max_layers_vert;
+   }
+
+   const uint32_t level_w = isl_align_npot(isl_minify(W0, level), image_align_sa.w);
+   const uint32_t level_h = isl_align_npot(isl_minify(H0, level), image_align_sa.h);
+   const uint32_t level_d = isl_align_npot(isl_minify(D0, level), image_align_sa.d);
+
+   const uint32_t max_layers_horiz = MIN(level_d, 1u << level);
+   const uint32_t max_layers_vert = isl_align_div(level_d, 1u << level);
+
+   x += level_w * (logical_z_offset_px % max_layers_horiz);
+   y += level_h * (logical_z_offset_px / max_layers_vert);
+
+   *x_offset_sa = x;
+   *y_offset_sa = y;
+}
+
+void
+isl_surf_get_image_offset_sa(const struct isl_surf *surf,
+                             uint32_t level,
+                             uint32_t logical_array_layer,
+                             uint32_t logical_z_offset_px,
+                             uint32_t *x_offset_sa,
+                             uint32_t *y_offset_sa)
+{
+   assert(level < surf->levels);
+   assert(logical_array_layer < surf->logical_level0_px.array_len);
+   assert(logical_z_offset_px
+          < isl_minify(surf->logical_level0_px.depth, level));
+
+   switch (surf->dim_layout) {
+   case ISL_DIM_LAYOUT_GEN9_1D:
+      isl_finishme("%s:%s: gen9 1d surfaces", __FILE__, __func__);
+   case ISL_DIM_LAYOUT_GEN4_2D:
+      get_image_offset_sa_gen4_2d(surf, level, logical_array_layer,
+                                  x_offset_sa, y_offset_sa);
+      break;
+   case ISL_DIM_LAYOUT_GEN4_3D:
+      get_image_offset_sa_gen4_3d(surf, level, logical_z_offset_px,
+                                  x_offset_sa, y_offset_sa);
+      break;
+   }
+}
index 184b0c5f70a6ff877d08bd7a77a348dec14978b9..6baac38bc2af3fa332add93d76fdad2ca096a143 100644 (file)
@@ -912,6 +912,22 @@ isl_surf_get_array_pitch(const struct isl_surf *surf)
    return isl_surf_get_array_pitch_sa_rows(surf) * surf->row_pitch;
 }
 
+/**
+ * Get the offset to an subimage within the surface, in units of surface
+ * samples.
+ *
+ * @invariant level < surface levels
+ * @invariant logical_array_layer < logical array length of surface
+ * @invariant logical_z_offset_px < logical depth of surface at level
+ */
+void
+isl_surf_get_image_offset_sa(const struct isl_surf *surf,
+                             uint32_t level,
+                             uint32_t logical_array_layer,
+                             uint32_t logical_z_offset_px,
+                             uint32_t *x_offset_sa,
+                             uint32_t *y_offset_sa);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/isl/tests/.gitignore b/src/isl/tests/.gitignore
new file mode 100644 (file)
index 0000000..ba70ecf
--- /dev/null
@@ -0,0 +1 @@
+/isl_surf_get_image_offset_test
diff --git a/src/isl/tests/isl_surf_get_image_offset_test.c b/src/isl/tests/isl_surf_get_image_offset_test.c
new file mode 100644 (file)
index 0000000..78362be
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * 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 <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "brw_device_info.h"
+#include "isl.h"
+
+#define BDW_GT2_DEVID 0x161a
+
+// An asssert that works regardless of NDEBUG.
+#define t_assert(cond) \
+   do { \
+      if (!(cond)) { \
+         fprintf(stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+         abort(); \
+      } \
+   } while (0)
+
+static void
+t_assert_extent4d(const struct isl_extent4d *e, uint32_t width,
+                  uint32_t height, uint32_t depth, uint32_t array_len)
+{
+   t_assert(e->width == width);
+   t_assert(e->height == height);
+   t_assert(e->depth == depth);
+   t_assert(e->array_len == array_len);
+}
+
+static void
+t_assert_image_alignment_el(const struct isl_surf *surf,
+                            uint32_t w, uint32_t h, uint32_t d)
+{
+   struct isl_extent3d align_el;
+
+   align_el = isl_surf_get_image_alignment_el(surf);
+   t_assert(align_el.w == w);
+   t_assert(align_el.h == h);
+   t_assert(align_el.d == d);
+
+}
+
+static void
+t_assert_image_alignment_sa(const struct isl_surf *surf,
+                            uint32_t w, uint32_t h, uint32_t d)
+{
+   struct isl_extent3d align_sa;
+
+   align_sa = isl_surf_get_image_alignment_sa(surf);
+   t_assert(align_sa.w == w);
+   t_assert(align_sa.h == h);
+   t_assert(align_sa.d == d);
+
+}
+
+static void
+t_assert_offset(const struct isl_surf *surf,
+                uint32_t level,
+                uint32_t logical_array_layer,
+                uint32_t logical_z_offset_px,
+                uint32_t expected_x_offset_sa,
+                uint32_t expected_y_offset_sa)
+{
+   uint32_t x, y;
+   isl_surf_get_image_offset_sa(surf, level, logical_array_layer,
+                                logical_z_offset_px, &x, &y);
+
+   t_assert(x == expected_x_offset_sa);
+   t_assert(y == expected_y_offset_sa);
+}
+
+static void
+t_assert_phys_level0_sa(const struct isl_surf *surf, uint32_t width,
+                        uint32_t height, uint32_t depth, uint32_t array_len)
+{
+   t_assert_extent4d(&surf->phys_level0_sa, width, height, depth, array_len);
+}
+
+static void
+test_bdw_2d_r8g8b8a8_unorm_512x512_a1_s1_noaux_y0(void)
+{
+   bool ok;
+
+   struct isl_device dev;
+   isl_device_init(&dev, brw_get_device_info(BDW_GT2_DEVID));
+
+   struct isl_surf surf;
+   ok = isl_surf_init(&dev, &surf,
+                      .dim = ISL_SURF_DIM_2D,
+                      .format = ISL_FORMAT_R8G8B8A8_UNORM,
+                      .width = 512,
+                      .height = 512,
+                      .depth = 1,
+                      .levels = 10,
+                      .array_len = 1,
+                      .samples = 1,
+                      .usage = ISL_SURF_USAGE_TEXTURE_BIT |
+                               ISL_SURF_USAGE_DISABLE_AUX_BIT,
+                      .tiling_flags = ISL_TILING_Y0_BIT);
+   t_assert(ok);
+
+   t_assert_image_alignment_el(&surf, 4, 4, 1);
+   t_assert_image_alignment_sa(&surf, 4, 4, 1);
+   t_assert_phys_level0_sa(&surf, 512, 512, 1, 1);
+   t_assert(isl_surf_get_array_pitch_el_rows(&surf) >= 772);
+   t_assert(isl_surf_get_array_pitch_sa_rows(&surf) >= 772);
+
+   t_assert_offset(&surf, 0, 0, 0, 0, 0); // +0, +0
+   t_assert_offset(&surf, 1, 0, 0, 0, 512); // +0, +512
+   t_assert_offset(&surf, 2, 0, 0, 256, 512); // +256, +0
+   t_assert_offset(&surf, 3, 0, 0, 256, 640); // +0, +128
+   t_assert_offset(&surf, 4, 0, 0, 256, 704); // +0, +64
+   t_assert_offset(&surf, 5, 0, 0, 256, 736); // +0, +32
+   t_assert_offset(&surf, 6, 0, 0, 256, 752); // +0, +16
+   t_assert_offset(&surf, 7, 0, 0, 256, 760); // +0, +8
+   t_assert_offset(&surf, 8, 0, 0, 256, 764); // +0, +4
+   t_assert_offset(&surf, 9, 0, 0, 256, 768); // +0, +4
+}
+
+static void
+test_bdw_2d_r8g8b8a8_unorm_1024x1024_a6_s1_noaux_y0(void)
+{
+   bool ok;
+
+   struct isl_device dev;
+   isl_device_init(&dev, brw_get_device_info(BDW_GT2_DEVID));
+
+   struct isl_surf surf;
+   ok = isl_surf_init(&dev, &surf,
+                      .dim = ISL_SURF_DIM_2D,
+                      .format = ISL_FORMAT_R8G8B8A8_UNORM,
+                      .width = 1024,
+                      .height = 1024,
+                      .depth = 1,
+                      .levels = 11,
+                      .array_len = 6,
+                      .samples = 1,
+                      .usage = ISL_SURF_USAGE_TEXTURE_BIT |
+                               ISL_SURF_USAGE_DISABLE_AUX_BIT,
+                      .tiling_flags = ISL_TILING_Y0_BIT);
+   t_assert(ok);
+
+   t_assert_image_alignment_el(&surf, 4, 4, 1);
+   t_assert_image_alignment_sa(&surf, 4, 4, 1);
+   t_assert_image_alignment_sa(&surf, 4, 4, 1);
+   t_assert(isl_surf_get_array_pitch_el_rows(&surf) >= 1540);
+   t_assert(isl_surf_get_array_pitch_sa_rows(&surf) >= 1540);
+
+   for (uint32_t a = 0; a < 6; ++a) {
+      uint32_t b = a * isl_surf_get_array_pitch_sa_rows(&surf);
+
+      t_assert_offset(&surf, 0, a, 0, 0, b + 0); // +0, +0
+      t_assert_offset(&surf, 1, a, 0, 0, b + 1024); // +0, +1024
+      t_assert_offset(&surf, 2, a, 0, 512, b + 1024); // +512, +0
+      t_assert_offset(&surf, 3, a, 0, 512, b + 1280); // +0, +256
+      t_assert_offset(&surf, 4, a, 0, 512, b + 1408); // +0, +128
+      t_assert_offset(&surf, 5, a, 0, 512, b + 1472); // +0, +64
+      t_assert_offset(&surf, 6, a, 0, 512, b + 1504); // +0, +32
+      t_assert_offset(&surf, 7, a, 0, 512, b + 1520); // +0, +16
+      t_assert_offset(&surf, 8, a, 0, 512, b + 1528); // +0, +8
+      t_assert_offset(&surf, 9, a, 0, 512, b + 1532); // +0, +4
+      t_assert_offset(&surf, 10, a, 0, 512, b + 1536); // +0, +4
+   }
+}
+
+int main(void)
+{
+   /* FINISHME: Add tests for npot sizes */
+   /* FINISHME: Add tests for 1D surfaces */
+   /* FINISHME: Add tests for 3D surfaces */
+
+   test_bdw_2d_r8g8b8a8_unorm_512x512_a1_s1_noaux_y0();
+   test_bdw_2d_r8g8b8a8_unorm_1024x1024_a6_s1_noaux_y0();
+}