From 2d7c25fb9dc037fbbeec9807a3864070f2b76c5d Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Thu, 11 Nov 2021 00:19:25 -0800 Subject: [PATCH] isl: Move some genxml surface state helpers into an include file On XeHP, the XY_BLOCK_COPY_BLT command has a number of fields that describe the layout of the surface, much like SURFACE_STATE does. Several of them are encoded in such a similar manner that we really would like to reuse the isl helpers for emitting those. This commit moves them into a new isl_genX_helpers.h file which I can include from the BLORP code. (The alternative would be to add XY_BLOCK_COPY_BLT filling commands to isl, but that...seems more like a BLORP feature.) Reviewed-by: Jason Ekstrand Part-of: --- src/intel/isl/isl_genX_helpers.h | 199 ++++++++++++++++++++++++++++++ src/intel/isl/isl_surface_state.c | 170 +------------------------ src/intel/isl/meson.build | 1 + 3 files changed, 204 insertions(+), 166 deletions(-) create mode 100644 src/intel/isl/isl_genX_helpers.h diff --git a/src/intel/isl/isl_genX_helpers.h b/src/intel/isl/isl_genX_helpers.h new file mode 100644 index 00000000000..feb69eaac2e --- /dev/null +++ b/src/intel/isl/isl_genX_helpers.h @@ -0,0 +1,199 @@ +/* + * Copyright 2016 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. + */ + +#ifndef ISL_SURFACE_STATE_H +#define ISL_SURFACE_STATE_H + +#include + +/** + * @file isl_surface_state.h + * + * ============================= GENXML CODE ============================= + * [This file is compiled once per generation.] + * ======================================================================= + * + * Helpers for encoding SURFACE_STATE and XY_BLOCK_COPY_BLT commands. + */ + +UNUSED static const uint8_t +isl_encode_halign(uint8_t halign) +{ + switch (halign) { +#if GFX_VERx10 >= 125 + case 16: return HALIGN_16; + case 32: return HALIGN_32; + case 64: return HALIGN_64; + case 128: return HALIGN_128; +#elif GFX_VER >= 8 + case 4: return HALIGN_4; + case 8: return HALIGN_8; + case 16: return HALIGN_16; +#elif GFX_VER >= 7 + case 4: return HALIGN_4; + case 8: return HALIGN_8; +#endif + default: unreachable("Invalid halign"); + } +} + +UNUSED static const uint8_t +isl_encode_valign(uint8_t valign) +{ + switch (valign) { +#if GFX_VER >= 8 + case 4: return VALIGN_4; + case 8: return VALIGN_8; + case 16: return VALIGN_16; +#elif GFX_VER >= 6 + case 2: return VALIGN_2; + case 4: return VALIGN_4; +#endif + default: unreachable("Invalid valign"); + } +} + +/** + * Get the horizontal and vertical alignment in the units expected by the + * hardware. Note that this does NOT give you the actual hardware enum values + * but an index into the isl_encode_[hv]align arrays above. + */ +UNUSED static struct isl_extent3d +isl_get_image_alignment(const struct isl_surf *surf) +{ + if (GFX_VERx10 >= 125) { + if (surf->tiling == ISL_TILING_64) { + /* The hardware ignores the alignment values. Anyway, the surface's + * true alignment is likely outside the enum range of HALIGN* and + * VALIGN*. + */ + return isl_extent3d(128, 4, 1); + } else if (isl_format_get_layout(surf->format)->bpb % 3 == 0) { + /* On XeHP, RENDER_SURFACE_STATE.SurfaceHorizontalAlignment is in + * units of elements for 24, 48, and 96 bpb formats. + */ + return isl_surf_get_image_alignment_el(surf); + } else { + /* On XeHP, RENDER_SURFACE_STATE.SurfaceHorizontalAlignment is in + * units of bytes for formats that are powers of two. + */ + const uint32_t bs = isl_format_get_layout(surf->format)->bpb / 8; + return isl_extent3d(surf->image_alignment_el.w * bs, + surf->image_alignment_el.h, + surf->image_alignment_el.d); + } + } else if (GFX_VER >= 9) { + if (isl_tiling_is_std_y(surf->tiling) || + surf->dim_layout == ISL_DIM_LAYOUT_GFX9_1D) { + /* The hardware ignores the alignment values. Anyway, the surface's + * true alignment is likely outside the enum range of HALIGN* and + * VALIGN*. + */ + return isl_extent3d(4, 4, 1); + } else { + /* In Skylake, RENDER_SUFFACE_STATE.SurfaceVerticalAlignment is in units + * of surface elements (not pixels nor samples). For compressed formats, + * a "surface element" is defined as a compression block. For example, + * if SurfaceVerticalAlignment is VALIGN_4 and SurfaceFormat is an ETC2 + * format (ETC2 has a block height of 4), then the vertical alignment is + * 4 compression blocks or, equivalently, 16 pixels. + */ + return isl_surf_get_image_alignment_el(surf); + } + } else { + /* Pre-Skylake, RENDER_SUFFACE_STATE.SurfaceVerticalAlignment is in + * units of surface samples. For example, if SurfaceVerticalAlignment + * is VALIGN_4 and the surface is singlesampled, then for any surface + * format (compressed or not) the vertical alignment is + * 4 pixels. + */ + return isl_surf_get_image_alignment_sa(surf); + } +} + +UNUSED static uint32_t +isl_get_qpitch(const struct isl_surf *surf) +{ + switch (surf->dim_layout) { + default: + unreachable("Bad isl_surf_dim"); + case ISL_DIM_LAYOUT_GFX4_2D: + if (GFX_VER >= 9) { + if (surf->dim == ISL_SURF_DIM_3D && surf->tiling == ISL_TILING_W) { + /* This is rather annoying and completely undocumented. It + * appears that the hardware has a bug (or undocumented feature) + * regarding stencil buffers most likely related to the way + * W-tiling is handled as modified Y-tiling. If you bind a 3-D + * stencil buffer normally, and use texelFetch on it, the z or + * array index will get implicitly multiplied by 2 for no obvious + * reason. The fix appears to be to divide qpitch by 2 for + * W-tiled surfaces. + */ + return isl_surf_get_array_pitch_el_rows(surf) / 2; + } else { + return isl_surf_get_array_pitch_el_rows(surf); + } + } else { + /* From the Broadwell PRM for RENDER_SURFACE_STATE.QPitch + * + * "This field must be set to an integer multiple of the Surface + * Vertical Alignment. For compressed textures (BC*, FXT1, + * ETC*, and EAC* Surface Formats), this field is in units of + * rows in the uncompressed surface, and must be set to an + * integer multiple of the vertical alignment parameter "j" + * defined in the Common Surface Formats section." + */ + return isl_surf_get_array_pitch_sa_rows(surf); + } + case ISL_DIM_LAYOUT_GFX9_1D: + /* QPitch is usually expressed as rows of surface elements (where + * a surface element is an compression block or a single surface + * sample). Skylake 1D is an outlier. + * + * From the Skylake BSpec >> Memory Views >> Common Surface + * Formats >> Surface Layout and Tiling >> 1D Surfaces: + * + * Surface QPitch specifies the distance in pixels between array + * slices. + */ + return isl_surf_get_array_pitch_el(surf); + case ISL_DIM_LAYOUT_GFX4_3D: + /* QPitch doesn't make sense for ISL_DIM_LAYOUT_GFX4_3D since it uses a + * different pitch at each LOD. Also, the QPitch field is ignored for + * these surfaces. From the Broadwell PRM documentation for QPitch: + * + * 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 + * + * None of the three conditions above can possibly apply to a 3D surface + * so it is safe to just set QPitch to 0. + */ + return 0; + } +} + +#endif diff --git a/src/intel/isl/isl_surface_state.c b/src/intel/isl/isl_surface_state.c index fcfb4c5cf87..78b460d4f86 100644 --- a/src/intel/isl/isl_surface_state.c +++ b/src/intel/isl/isl_surface_state.c @@ -38,45 +38,7 @@ __gen_combine_address(__attribute__((unused)) void *data, #include "genxml/genX_pack.h" #include "isl_priv.h" - -#if GFX_VER >= 7 -static const uint8_t isl_encode_halign(uint8_t halign) -{ - switch (halign) { -#if GFX_VERx10 >= 125 - case 16: return HALIGN_16; - case 32: return HALIGN_32; - case 64: return HALIGN_64; - case 128: return HALIGN_128; -#elif GFX_VER >= 8 - case 4: return HALIGN_4; - case 8: return HALIGN_8; - case 16: return HALIGN_16; -#else - case 4: return HALIGN_4; - case 8: return HALIGN_8; -#endif - default: unreachable("Invalid halign"); - } -} -#endif - -#if GFX_VER >= 6 -static const uint8_t isl_encode_valign(uint8_t valign) -{ - switch (valign) { -#if GFX_VER >= 8 - case 4: return VALIGN_4; - case 8: return VALIGN_8; - case 16: return VALIGN_16; -#else - case 2: return VALIGN_2; - case 4: return VALIGN_4; -#endif - default: unreachable("Invalid valign"); - } -} -#endif +#include "isl_genX_helpers.h" #if GFX_VER >= 8 static const uint8_t isl_encode_tiling[] = { @@ -158,131 +120,6 @@ get_surftype(enum isl_surf_dim dim, isl_surf_usage_flags_t usage) } } -/** - * Get the horizontal and vertical alignment in the units expected by the - * hardware. Note that this does NOT give you the actual hardware enum values - * but an index into the isl_encode_[hv]align arrays above. - */ -UNUSED static struct isl_extent3d -get_image_alignment(const struct isl_surf *surf) -{ - if (GFX_VERx10 >= 125) { - if (surf->tiling == ISL_TILING_64) { - /* The hardware ignores the alignment values. Anyway, the surface's - * true alignment is likely outside the enum range of HALIGN* and - * VALIGN*. - */ - return isl_extent3d(128, 4, 1); - } else if (isl_format_get_layout(surf->format)->bpb % 3 == 0) { - /* On XeHP, RENDER_SURFACE_STATE.SurfaceHorizontalAlignment is in - * units of elements for 24, 48, and 96 bpb formats. - */ - return isl_surf_get_image_alignment_el(surf); - } else { - /* On XeHP, RENDER_SURFACE_STATE.SurfaceHorizontalAlignment is in - * units of bytes for formats that are powers of two. - */ - const uint32_t bs = isl_format_get_layout(surf->format)->bpb / 8; - return isl_extent3d(surf->image_alignment_el.w * bs, - surf->image_alignment_el.h, - surf->image_alignment_el.d); - } - } else if (GFX_VER >= 9) { - if (isl_tiling_is_std_y(surf->tiling) || - surf->dim_layout == ISL_DIM_LAYOUT_GFX9_1D) { - /* The hardware ignores the alignment values. Anyway, the surface's - * true alignment is likely outside the enum range of HALIGN* and - * VALIGN*. - */ - return isl_extent3d(4, 4, 1); - } else { - /* In Skylake, RENDER_SUFFACE_STATE.SurfaceVerticalAlignment is in units - * of surface elements (not pixels nor samples). For compressed formats, - * a "surface element" is defined as a compression block. For example, - * if SurfaceVerticalAlignment is VALIGN_4 and SurfaceFormat is an ETC2 - * format (ETC2 has a block height of 4), then the vertical alignment is - * 4 compression blocks or, equivalently, 16 pixels. - */ - return isl_surf_get_image_alignment_el(surf); - } - } else { - /* Pre-Skylake, RENDER_SUFFACE_STATE.SurfaceVerticalAlignment is in - * units of surface samples. For example, if SurfaceVerticalAlignment - * is VALIGN_4 and the surface is singlesampled, then for any surface - * format (compressed or not) the vertical alignment is - * 4 pixels. - */ - return isl_surf_get_image_alignment_sa(surf); - } -} - -#if GFX_VER >= 8 -static uint32_t -get_qpitch(const struct isl_surf *surf) -{ - switch (surf->dim_layout) { - default: - unreachable("Bad isl_surf_dim"); - case ISL_DIM_LAYOUT_GFX4_2D: - if (GFX_VER >= 9) { - if (surf->dim == ISL_SURF_DIM_3D && surf->tiling == ISL_TILING_W) { - /* This is rather annoying and completely undocumented. It - * appears that the hardware has a bug (or undocumented feature) - * regarding stencil buffers most likely related to the way - * W-tiling is handled as modified Y-tiling. If you bind a 3-D - * stencil buffer normally, and use texelFetch on it, the z or - * array index will get implicitly multiplied by 2 for no obvious - * reason. The fix appears to be to divide qpitch by 2 for - * W-tiled surfaces. - */ - return isl_surf_get_array_pitch_el_rows(surf) / 2; - } else { - return isl_surf_get_array_pitch_el_rows(surf); - } - } else { - /* From the Broadwell PRM for RENDER_SURFACE_STATE.QPitch - * - * "This field must be set to an integer multiple of the Surface - * Vertical Alignment. For compressed textures (BC*, FXT1, - * ETC*, and EAC* Surface Formats), this field is in units of - * rows in the uncompressed surface, and must be set to an - * integer multiple of the vertical alignment parameter "j" - * defined in the Common Surface Formats section." - */ - return isl_surf_get_array_pitch_sa_rows(surf); - } - case ISL_DIM_LAYOUT_GFX9_1D: - /* QPitch is usually expressed as rows of surface elements (where - * a surface element is an compression block or a single surface - * sample). Skylake 1D is an outlier. - * - * From the Skylake BSpec >> Memory Views >> Common Surface - * Formats >> Surface Layout and Tiling >> 1D Surfaces: - * - * Surface QPitch specifies the distance in pixels between array - * slices. - */ - return isl_surf_get_array_pitch_el(surf); - case ISL_DIM_LAYOUT_GFX4_3D: - /* QPitch doesn't make sense for ISL_DIM_LAYOUT_GFX4_3D since it uses a - * different pitch at each LOD. Also, the QPitch field is ignored for - * these surfaces. From the Broadwell PRM documentation for QPitch: - * - * 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 - * - * None of the three conditions above can possibly apply to a 3D surface - * so it is safe to just set QPitch to 0. - */ - return 0; - } -} -#endif /* GFX_VER >= 8 */ - void isl_genX(surf_fill_state_s)(const struct isl_device *dev, void *state, const struct isl_surf_fill_state_info *restrict info) @@ -509,7 +346,8 @@ isl_genX(surf_fill_state_s)(const struct isl_device *dev, void *state, #endif #if GFX_VER >= 6 - const struct isl_extent3d image_align = get_image_alignment(info->surf); + const struct isl_extent3d image_align = + isl_get_image_alignment(info->surf); s.SurfaceVerticalAlignment = isl_encode_valign(image_align.height); #if GFX_VER >= 7 s.SurfaceHorizontalAlignment = isl_encode_halign(image_align.width); @@ -524,7 +362,7 @@ isl_genX(surf_fill_state_s)(const struct isl_device *dev, void *state, } #if GFX_VER >= 8 - s.SurfaceQPitch = get_qpitch(info->surf) >> 2; + s.SurfaceQPitch = isl_get_qpitch(info->surf) >> 2; #elif GFX_VER == 7 s.SurfaceArraySpacing = info->surf->array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT; diff --git a/src/intel/isl/meson.build b/src/intel/isl/meson.build index b91d8fe4ac1..891360fdd6d 100644 --- a/src/intel/isl/meson.build +++ b/src/intel/isl/meson.build @@ -21,6 +21,7 @@ isl_per_hw_ver_files = files( 'isl_emit_depth_stencil.c', 'isl_surface_state.c', + 'isl_genX_helpers.h', ) isl_gfx4_files = files(