freedreno: Move a6xx's setup_slices() to a shareable helper function.
authorEric Anholt <eric@anholt.net>
Tue, 26 Nov 2019 20:02:34 +0000 (12:02 -0800)
committerEric Anholt <eric@anholt.net>
Wed, 11 Dec 2019 04:24:18 +0000 (04:24 +0000)
We pass in all the parameters for setting up the layout, though freedreno
still sets a few of them up early (since it uses layout helpers in making
some decisions about the layout setup parameters that will be cleaned up
once krh's blitter work lands).

src/freedreno/Makefile.sources
src/freedreno/fdl/fd6_layout.c [new file with mode: 0644]
src/freedreno/fdl/freedreno_layout.c [new file with mode: 0644]
src/freedreno/fdl/freedreno_layout.h
src/freedreno/fdl/meson.build [new file with mode: 0644]
src/freedreno/meson.build
src/freedreno/vulkan/meson.build
src/gallium/drivers/freedreno/a6xx/fd6_resource.c
src/gallium/drivers/freedreno/freedreno_resource.c
src/gallium/drivers/freedreno/meson.build

index f6e28520acd60d15e683e7760f07cb070fe5e74c..fb0b9f2159f720be4fc43296f4865a079483cf51 100644 (file)
@@ -15,6 +15,8 @@ drm_SOURCES := \
        drm/msm_ringbuffer.c
 
 ir3_SOURCES := \
+       fdl/fd6_layout.c \
+       fdl/freedreno_layout.c \
        ir3/disasm-a3xx.c \
        ir3/instr-a3xx.h \
        ir3/ir3.c \
diff --git a/src/freedreno/fdl/fd6_layout.c b/src/freedreno/fdl/fd6_layout.c
new file mode 100644 (file)
index 0000000..f9499b3
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2018 Rob Clark <robclark@freedesktop.org>
+ * Copyright © 2018-2019 Google, Inc.
+ *
+ * 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.
+ *
+ * Authors:
+ *    Rob Clark <robclark@freedesktop.org>
+ */
+
+#include <stdio.h>
+
+#include "freedreno_layout.h"
+
+/* indexed by cpp, including msaa 2x and 4x: */
+static const struct {
+       unsigned pitchalign;
+       unsigned heightalign;
+} tile_alignment[] = {
+       [1]  = { 128, 32 },
+       [2]  = {  64, 32 },
+       [3]  = {  64, 32 },
+       [4]  = {  64, 16 },
+       [6]  = {  64, 16 },
+       [8]  = {  64, 16 },
+       [12] = {  64, 16 },
+       [16] = {  64, 16 },
+       [24] = {  64, 16 },
+       [32] = {  64, 16 },
+       [48] = {  64, 16 },
+       [64] = {  64, 16 },
+
+       /* special cases for r16: */
+       [0]  = { 128, 16 },
+};
+
+/* NOTE: good way to test this is:  (for example)
+ *  piglit/bin/texelFetch fs sampler3D 100x100x8
+ */
+void
+fdl6_layout(struct fdl_layout *layout,
+               enum pipe_format format, uint32_t nr_samples,
+               uint32_t width0, uint32_t height0, uint32_t depth0,
+               uint32_t mip_levels, uint32_t array_size, bool is_3d)
+{
+       assert(nr_samples > 0);
+       layout->width0 = width0;
+       layout->height0 = height0;
+       layout->depth0 = depth0;
+
+       layout->cpp = util_format_get_blocksize(format);
+       layout->cpp *= nr_samples;
+
+       const struct util_format_description *format_desc =
+               util_format_description(format);
+       uint32_t level;
+       uint32_t depth = depth0;
+       /* linear dimensions: */
+       uint32_t lwidth = width0;
+       uint32_t lheight = height0;
+       /* tile_mode dimensions: */
+       uint32_t twidth = util_next_power_of_two(lwidth);
+       uint32_t theight = util_next_power_of_two(lheight);
+       int ta = layout->cpp;
+
+       /* The z16/r16 formats seem to not play by the normal tiling rules: */
+       if ((layout->cpp == 2) && (util_format_get_nr_components(format) == 1))
+               ta = 0;
+
+       uint32_t alignment;
+       if (is_3d) {
+               layout->layer_first = false;
+               alignment = 4096;
+       } else {
+               layout->layer_first = true;
+               alignment = 1;
+       }
+       /* in layer_first layout, the level (slice) contains just one
+        * layer (since in fact the layer contains the slices)
+        */
+       uint32_t layers_in_level = layout->layer_first ? 1 : array_size;
+
+       debug_assert(ta < ARRAY_SIZE(tile_alignment));
+       debug_assert(tile_alignment[ta].pitchalign);
+
+       for (level = 0; level < mip_levels; level++) {
+               struct fdl_slice *slice = &layout->slices[level];
+               uint32_t tile_mode = fdl_tile_mode(layout, level);
+               uint32_t width, height;
+
+               /* tiled levels of 3D textures are rounded up to PoT dimensions: */
+               if (is_3d && tile_mode) {
+                       width = twidth;
+                       height = theight;
+               } else {
+                       width = lwidth;
+                       height = lheight;
+               }
+               uint32_t aligned_height = height;
+               uint32_t pitchalign;
+
+               if (tile_mode) {
+                       pitchalign = tile_alignment[ta].pitchalign;
+                       aligned_height = align(aligned_height,
+                                       tile_alignment[ta].heightalign);
+               } else {
+                       pitchalign = 64;
+               }
+
+               /* The blits used for mem<->gmem work at a granularity of
+                * 32x32, which can cause faults due to over-fetch on the
+                * last level.  The simple solution is to over-allocate a
+                * bit the last level to ensure any over-fetch is harmless.
+                * The pitch is already sufficiently aligned, but height
+                * may not be:
+                */
+               if (level == mip_levels - 1)
+                       aligned_height = align(aligned_height, 32);
+
+               if (format_desc->layout == UTIL_FORMAT_LAYOUT_ASTC)
+                       slice->pitch =
+                               util_align_npot(width, pitchalign * util_format_get_blockwidth(format));
+               else
+                       slice->pitch = align(width, pitchalign);
+
+               slice->offset = layout->size;
+               uint32_t blocks = util_format_get_nblocks(format,
+                               slice->pitch, aligned_height);
+
+               /* 1d array and 2d array textures must all have the same layer size
+                * for each miplevel on a6xx. 3d textures can have different layer
+                * sizes for high levels, but the hw auto-sizer is buggy (or at least
+                * different than what this code does), so as soon as the layer size
+                * range gets into range, we stop reducing it.
+                */
+               if (is_3d) {
+                       if (level < 1 || layout->slices[level - 1].size0 > 0xf000) {
+                               slice->size0 = align(blocks * layout->cpp, alignment);
+                       } else {
+                               slice->size0 = layout->slices[level - 1].size0;
+                       }
+               } else {
+                       slice->size0 = align(blocks * layout->cpp, alignment);
+               }
+
+               layout->size += slice->size0 * depth * layers_in_level;
+
+               if (false) {
+                       fprintf(stderr, "%s: %ux%ux%u@%u:\t%2u: stride=%4u, size=%6u,%7u, aligned_height=%3u, blocks=%u, offset=0x%x tiling=%d\n",
+                                       util_format_name(format),
+                                       width, height, depth, layout->cpp,
+                                       level, slice->pitch * layout->cpp,
+                                       slice->size0, layout->size, aligned_height, blocks,
+                                       slice->offset, tile_mode);
+               }
+
+               depth = u_minify(depth, 1);
+               lwidth = u_minify(lwidth, 1);
+               lheight = u_minify(lheight, 1);
+               twidth = u_minify(twidth, 1);
+               theight = u_minify(theight, 1);
+       }
+
+       if (layout->layer_first) {
+               layout->layer_size = align(layout->size, 4096);
+               layout->size = layout->layer_size * array_size;
+       }
+}
diff --git a/src/freedreno/fdl/freedreno_layout.c b/src/freedreno/fdl/freedreno_layout.c
new file mode 100644 (file)
index 0000000..6f60433
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 Rob Clark <robclark@freedesktop.org>
+ * Copyright © 2018 Google, Inc.
+ *
+ * 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.
+ *
+ * Authors:
+ *    Rob Clark <robclark@freedesktop.org>
+ */
+
+#include <stdio.h>
+
+#include "freedreno_layout.h"
+
+void
+fdl_layout_buffer(struct fdl_layout *layout, uint32_t size)
+{
+       layout->width0 = size;
+       layout->height0 = 1;
+       layout->depth0 = 1;
+       layout->cpp = 1;
+       layout->size = size;
+}
index 714a6fcf42e1a3d2df7efc7c4f181370e9b5bf17..be73a24ccc56988a67a71938d6d61f0f642fc12a 100644 (file)
 #ifndef FREEDRENO_LAYOUT_H_
 #define FREEDRENO_LAYOUT_H_
 
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "util/u_debug.h"
+#include "util/u_math.h"
+#include "util/format/u_format.h"
+
 /* Shared freedreno mipmap layout helper
  *
  * It does *not* attempt to track surface transitions, in particular
@@ -102,6 +109,8 @@ struct fdl_layout {
 
        uint32_t width0, height0, depth0;
 
+       uint32_t size; /* Size of the whole image, in bytes. */
+
        uint32_t ubwc_size;
 };
 
@@ -128,8 +137,8 @@ fdl_ubwc_offset(const struct fdl_layout *layout, unsigned level, unsigned layer)
         * for multi layer/level images, it will.
         */
        if (layout->ubwc_size) {
-               debug_assert(level == 0);
-               debug_assert(layer == 0);
+               assert(level == 0);
+               assert(layer == 0);
        }
        return layout->ubwc_slices[0].offset;
 }
@@ -158,4 +167,13 @@ fdl_ubwc_enabled(const struct fdl_layout *layout, int level)
        return layout->ubwc_size && fdl_tile_mode(layout, level);
 }
 
+void
+fdl_layout_buffer(struct fdl_layout *layout, uint32_t size);
+
+void
+fdl6_layout(struct fdl_layout *layout,
+               enum pipe_format format, uint32_t nr_samples,
+               uint32_t width0, uint32_t height0, uint32_t depth0,
+               uint32_t mip_levels, uint32_t array_size, bool is_3d);
+
 #endif /* FREEDRENO_LAYOUT_H_ */
diff --git a/src/freedreno/fdl/meson.build b/src/freedreno/fdl/meson.build
new file mode 100644 (file)
index 0000000..429be17
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright © 2018 Rob Clark
+
+# 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 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.
+
+libfreedreno_layout = static_library(
+  'freedreno_layout',
+  [
+    'fd6_layout.c',
+    'freedreno_layout.c',
+  ],
+  include_directories : [inc_freedreno, inc_common],
+  c_args : [c_vis_args, no_override_init_args],
+  cpp_args : [cpp_vis_args],
+  dependencies : idep_nir_headers,
+  build_by_default : false,
+)
+
index 5764d4c38ea342a1bf66ee8efe7074927e60090e..1ff2a4fee317d6c64a76fc297ae61c670dc72cdd 100644 (file)
@@ -21,6 +21,7 @@
 inc_freedreno = include_directories(['.', './registers'])
 
 subdir('drm')
+subdir('fdl')
 subdir('ir3')
 subdir('registers')
 subdir('perfcntrs')
index 45f9602abebd9ede86e5754e5f018ad7415fc643..27f731a98c2986c57c8395f18a212a11799aa253 100644 (file)
@@ -110,6 +110,7 @@ libvulkan_freedreno = shared_library(
     libvulkan_wsi,
     libfreedreno_drm, # required by ir3_shader_get_variant, which we don't use
     libfreedreno_ir3,
+    libfreedreno_layout,
   ],
   dependencies : [
     dep_dl,
index 4a35dd6db2fc649379263676f504fa5a76840ffc..8801982a7a74c44562d891e9a309a86a4a493044 100644 (file)
 
 #include "a6xx.xml.h"
 
-/* indexed by cpp, including msaa 2x and 4x: */
-static const struct {
-       unsigned pitchalign;
-       unsigned heightalign;
-} tile_alignment[] = {
-       [1]  = { 128, 32 },
-       [2]  = {  64, 32 },
-       [3]  = {  64, 32 },
-       [4]  = {  64, 16 },
-       [6]  = {  64, 16 },
-       [8]  = {  64, 16 },
-       [12] = {  64, 16 },
-       [16] = {  64, 16 },
-       [24] = {  64, 16 },
-       [32] = {  64, 16 },
-       [48] = {  64, 16 },
-       [64] = {  64, 16 },
-
-       /* special cases for r16: */
-       [0]  = { 128, 16 },
-};
-
-/* NOTE: good way to test this is:  (for example)
- *  piglit/bin/texelFetch fs sampler3D 100x100x8
- */
-static uint32_t
-setup_slices(struct fd_resource *rsc, uint32_t alignment, enum pipe_format format)
-{
-       struct pipe_resource *prsc = &rsc->base;
-       struct fd_screen *screen = fd_screen(prsc->screen);
-       enum util_format_layout layout = util_format_description(format)->layout;
-       uint32_t pitchalign = screen->gmem_alignw;
-       uint32_t level, size = 0;
-       uint32_t depth = prsc->depth0;
-       /* linear dimensions: */
-       uint32_t lwidth = prsc->width0;
-       uint32_t lheight = prsc->height0;
-       /* tile_mode dimensions: */
-       uint32_t twidth = util_next_power_of_two(lwidth);
-       uint32_t theight = util_next_power_of_two(lheight);
-       /* in layer_first layout, the level (slice) contains just one
-        * layer (since in fact the layer contains the slices)
-        */
-       uint32_t layers_in_level = rsc->layout.layer_first ? 1 : prsc->array_size;
-       int ta = rsc->layout.cpp;
-
-       /* The z16/r16 formats seem to not play by the normal tiling rules: */
-       if ((rsc->layout.cpp == 2) && (util_format_get_nr_components(format) == 1))
-               ta = 0;
-
-       debug_assert(ta < ARRAY_SIZE(tile_alignment));
-       debug_assert(tile_alignment[ta].pitchalign);
-
-       for (level = 0; level <= prsc->last_level; level++) {
-               struct fdl_slice *slice = fd_resource_slice(rsc, level);
-               uint32_t tile_mode = fd_resource_tile_mode(prsc, level);
-               uint32_t width, height;
-
-               /* tiled levels of 3D textures are rounded up to PoT dimensions: */
-               if ((prsc->target == PIPE_TEXTURE_3D) && tile_mode) {
-                       width = twidth;
-                       height = theight;
-               } else {
-                       width = lwidth;
-                       height = lheight;
-               }
-               uint32_t aligned_height = height;
-               uint32_t blocks;
-
-               if (tile_mode) {
-                       pitchalign = tile_alignment[ta].pitchalign;
-                       aligned_height = align(aligned_height,
-                                       tile_alignment[ta].heightalign);
-               } else {
-                       pitchalign = 64;
-               }
-
-               /* The blits used for mem<->gmem work at a granularity of
-                * 32x32, which can cause faults due to over-fetch on the
-                * last level.  The simple solution is to over-allocate a
-                * bit the last level to ensure any over-fetch is harmless.
-                * The pitch is already sufficiently aligned, but height
-                * may not be:
-                */
-               if ((level == prsc->last_level) && (prsc->target != PIPE_BUFFER))
-                       aligned_height = align(aligned_height, 32);
-
-               if (layout == UTIL_FORMAT_LAYOUT_ASTC)
-                       slice->pitch =
-                               util_align_npot(width, pitchalign * util_format_get_blockwidth(format));
-               else
-                       slice->pitch = align(width, pitchalign);
-
-               slice->offset = size;
-               blocks = util_format_get_nblocks(format, slice->pitch, aligned_height);
-
-               /* 1d array and 2d array textures must all have the same layer size
-                * for each miplevel on a6xx. 3d textures can have different layer
-                * sizes for high levels, but the hw auto-sizer is buggy (or at least
-                * different than what this code does), so as soon as the layer size
-                * range gets into range, we stop reducing it.
-                */
-               if (prsc->target == PIPE_TEXTURE_3D) {
-                       if (level < 1 || fd_resource_slice(rsc, level - 1)->size0 > 0xf000) {
-                               slice->size0 = align(blocks * rsc->layout.cpp, alignment);
-                       } else {
-                               slice->size0 = fd_resource_slice(rsc, level - 1)->size0;
-                       }
-               } else {
-                       slice->size0 = align(blocks * rsc->layout.cpp, alignment);
-               }
-
-               size += slice->size0 * depth * layers_in_level;
-
-#if 0
-               fprintf(stderr, "%s: %ux%ux%u@%u:\t%2u: stride=%4u, size=%6u,%7u, aligned_height=%3u, blocks=%u, offset=0x%x tiling=%d\n",
-                               util_format_name(prsc->format),
-                               width, height, depth, rsc->layout.cpp,
-                               level, slice->pitch * rsc->layout.cpp,
-                               slice->size0, size, aligned_height, blocks,
-                               slice->offset, fd_resource_tile_mode(prsc, level));
-#endif
-
-               depth = u_minify(depth, 1);
-               lwidth = u_minify(lwidth, 1);
-               lheight = u_minify(lheight, 1);
-               twidth = u_minify(twidth, 1);
-               theight = u_minify(theight, 1);
-       }
-
-       return size;
-}
-
 /* A subset of the valid tiled formats can be compressed.  We do
  * already require tiled in order to be compressed, but just because
  * it can be tiled doesn't mean it can be compressed.
@@ -325,21 +192,19 @@ setup_lrz(struct fd_resource *rsc)
 uint32_t
 fd6_setup_slices(struct fd_resource *rsc)
 {
-       uint32_t alignment;
+       struct pipe_resource *prsc = &rsc->base;
 
        if (!(fd_mesa_debug & FD_DBG_NOLRZ) && has_depth(rsc->base.format))
                setup_lrz(rsc);
 
-       switch (rsc->base.target) {
-       case PIPE_TEXTURE_3D:
-               rsc->layout.layer_first = false;
-               alignment = 4096;
-               break;
-       default:
-               rsc->layout.layer_first = true;
-               alignment = 1;
-               break;
-       }
+       fdl6_layout(&rsc->layout, prsc->format, fd_resource_nr_samples(prsc),
+                       prsc->width0, prsc->height0, prsc->depth0,
+                       prsc->last_level + 1, prsc->array_size,
+                       prsc->target == PIPE_TEXTURE_3D);
 
-       return setup_slices(rsc, alignment, rsc->base.format);
+       /* The caller does this bit of layout setup again. */
+       if (rsc->layout.layer_first)
+               return rsc->layout.size / prsc->array_size;
+       else
+               return rsc->layout.size;
 }
index 5826e16c1545dd377971ce48752759c373f1bf94..10e9196886f7082f268d17cf1bcba57548323efa 100644 (file)
@@ -991,7 +991,13 @@ fd_resource_create_with_modifiers(struct pipe_screen *pscreen,
 
        rsc->internal_format = format;
 
-       size = screen->setup_slices(rsc);
+       if (prsc->target == PIPE_BUFFER) {
+               assert(prsc->format == PIPE_FORMAT_R8_UNORM);
+               size = prsc->width0;
+               fdl_layout_buffer(&rsc->layout, size);
+       } else {
+               size = screen->setup_slices(rsc);
+       }
 
        if (allow_ubwc && screen->fill_ubwc_buffer_sizes && rsc->layout.tile_mode)
                size += screen->fill_ubwc_buffer_sizes(rsc);
index 09cf125c61d731a45c8b002d2f54ba8ff854f7ca..7125ecd274f1ad2e0990016b4d04537755e5628f 100644 (file)
@@ -243,6 +243,7 @@ driver_freedreno = declare_dependency(
     libfreedreno,
     libfreedreno_drm,
     libfreedreno_ir3,
+    libfreedreno_layout,
     libfreedreno_perfcntrs
   ],
   dependencies : idep_nir,
@@ -260,6 +261,7 @@ ir3_compiler = executable(
     libfreedreno,
     libfreedreno_drm,
     libfreedreno_ir3,
+    libfreedreno_layout,
     libgallium,
     libglsl_standalone,
   ],