1/* 2 * Copyright 2016 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#ifndef ISL_SURFACE_STATE_H 25#define ISL_SURFACE_STATE_H 26 27#include <stdint.h> 28 29/** 30 * @file isl_surface_state.h 31 * 32 * ============================= GENXML CODE ============================= 33 * [This file is compiled once per generation.] 34 * ======================================================================= 35 * 36 * Helpers for encoding SURFACE_STATE and XY_BLOCK_COPY_BLT commands. 37 */ 38 39UNUSED static const uint8_t 40isl_encode_halign(uint8_t halign) 41{ 42 switch (halign) { 43#if GFX_VERx10 >= 125 44 case 16: return HALIGN_16; 45 case 32: return HALIGN_32; 46 case 64: return HALIGN_64; 47 case 128: return HALIGN_128; 48#elif GFX_VER >= 8 49 case 4: return HALIGN_4; 50 case 8: return HALIGN_8; 51 case 16: return HALIGN_16; 52#elif GFX_VER >= 7 53 case 4: return HALIGN_4; 54 case 8: return HALIGN_8; 55#endif 56 default: unreachable("Invalid halign"); 57 } 58} 59 60UNUSED static const uint8_t 61isl_encode_valign(uint8_t valign) 62{ 63 switch (valign) { 64#if GFX_VER >= 8 65 case 4: return VALIGN_4; 66 case 8: return VALIGN_8; 67 case 16: return VALIGN_16; 68#elif GFX_VER >= 6 69 case 2: return VALIGN_2; 70 case 4: return VALIGN_4; 71#endif 72 default: unreachable("Invalid valign"); 73 } 74} 75 76/** 77 * Get the horizontal and vertical alignment in the units expected by the 78 * hardware. Note that this does NOT give you the actual hardware enum values 79 * but an index into the isl_encode_[hv]align arrays above. 80 */ 81UNUSED static struct isl_extent3d 82isl_get_image_alignment(const struct isl_surf *surf) 83{ 84 if (GFX_VERx10 >= 125) { 85 if (surf->tiling == ISL_TILING_64) { 86 /* The hardware ignores the alignment values. Anyway, the surface's 87 * true alignment is likely outside the enum range of HALIGN* and 88 * VALIGN*. 89 */ 90 return isl_extent3d(128, 4, 1); 91 } else if (isl_format_get_layout(surf->format)->bpb % 3 == 0) { 92 /* On XeHP, RENDER_SURFACE_STATE.SurfaceHorizontalAlignment is in 93 * units of elements for 24, 48, and 96 bpb formats. 94 */ 95 return isl_surf_get_image_alignment_el(surf); 96 } else { 97 /* On XeHP, RENDER_SURFACE_STATE.SurfaceHorizontalAlignment is in 98 * units of bytes for formats that are powers of two. 99 */ 100 const uint32_t bs = isl_format_get_layout(surf->format)->bpb / 8; 101 return isl_extent3d(surf->image_alignment_el.w * bs, 102 surf->image_alignment_el.h, 103 surf->image_alignment_el.d); 104 } 105 } else if (GFX_VER >= 9) { 106 if (isl_tiling_is_std_y(surf->tiling) || 107 surf->dim_layout == ISL_DIM_LAYOUT_GFX9_1D) { 108 /* The hardware ignores the alignment values. Anyway, the surface's 109 * true alignment is likely outside the enum range of HALIGN* and 110 * VALIGN*. 111 */ 112 return isl_extent3d(4, 4, 1); 113 } else { 114 /* In Skylake, RENDER_SUFFACE_STATE.SurfaceVerticalAlignment is in units 115 * of surface elements (not pixels nor samples). For compressed formats, 116 * a "surface element" is defined as a compression block. For example, 117 * if SurfaceVerticalAlignment is VALIGN_4 and SurfaceFormat is an ETC2 118 * format (ETC2 has a block height of 4), then the vertical alignment is 119 * 4 compression blocks or, equivalently, 16 pixels. 120 */ 121 return isl_surf_get_image_alignment_el(surf); 122 } 123 } else { 124 /* Pre-Skylake, RENDER_SUFFACE_STATE.SurfaceVerticalAlignment is in 125 * units of surface samples. For example, if SurfaceVerticalAlignment 126 * is VALIGN_4 and the surface is singlesampled, then for any surface 127 * format (compressed or not) the vertical alignment is 128 * 4 pixels. 129 */ 130 return isl_surf_get_image_alignment_sa(surf); 131 } 132} 133 134UNUSED static uint32_t 135isl_get_qpitch(const struct isl_surf *surf) 136{ 137 switch (surf->dim_layout) { 138 default: 139 unreachable("Bad isl_surf_dim"); 140 case ISL_DIM_LAYOUT_GFX4_2D: 141 if (GFX_VER >= 9) { 142 if (surf->dim == ISL_SURF_DIM_3D && surf->tiling == ISL_TILING_W) { 143 /* This is rather annoying and completely undocumented. It 144 * appears that the hardware has a bug (or undocumented feature) 145 * regarding stencil buffers most likely related to the way 146 * W-tiling is handled as modified Y-tiling. If you bind a 3-D 147 * stencil buffer normally, and use texelFetch on it, the z or 148 * array index will get implicitly multiplied by 2 for no obvious 149 * reason. The fix appears to be to divide qpitch by 2 for 150 * W-tiled surfaces. 151 */ 152 return isl_surf_get_array_pitch_el_rows(surf) / 2; 153 } else { 154 return isl_surf_get_array_pitch_el_rows(surf); 155 } 156 } else { 157 /* From the Broadwell PRM for RENDER_SURFACE_STATE.QPitch 158 * 159 * "This field must be set to an integer multiple of the Surface 160 * Vertical Alignment. For compressed textures (BC*, FXT1, 161 * ETC*, and EAC* Surface Formats), this field is in units of 162 * rows in the uncompressed surface, and must be set to an 163 * integer multiple of the vertical alignment parameter "j" 164 * defined in the Common Surface Formats section." 165 */ 166 return isl_surf_get_array_pitch_sa_rows(surf); 167 } 168 case ISL_DIM_LAYOUT_GFX9_1D: 169 /* QPitch is usually expressed as rows of surface elements (where 170 * a surface element is an compression block or a single surface 171 * sample). Skylake 1D is an outlier. 172 * 173 * From the Skylake BSpec >> Memory Views >> Common Surface 174 * Formats >> Surface Layout and Tiling >> 1D Surfaces: 175 * 176 * Surface QPitch specifies the distance in pixels between array 177 * slices. 178 */ 179 return isl_surf_get_array_pitch_el(surf); 180 case ISL_DIM_LAYOUT_GFX4_3D: 181 /* QPitch doesn't make sense for ISL_DIM_LAYOUT_GFX4_3D since it uses a 182 * different pitch at each LOD. Also, the QPitch field is ignored for 183 * these surfaces. From the Broadwell PRM documentation for QPitch: 184 * 185 * This field specifies the distance in rows between array slices. It 186 * is used only in the following cases: 187 * - Surface Array is enabled OR 188 * - Number of Mulitsamples is not NUMSAMPLES_1 and Multisampled 189 * Surface Storage Format set to MSFMT_MSS OR 190 * - Surface Type is SURFTYPE_CUBE 191 * 192 * None of the three conditions above can possibly apply to a 3D surface 193 * so it is safe to just set QPitch to 0. 194 */ 195 return 0; 196 } 197} 198 199#endif 200