1/* 2 * Copyright 2019 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 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#include "isl/isl.h" 25 26#ifdef IN_UNIT_TEST 27/* STATIC_ASSERT is a do { ... } while(0) statement */ 28UNUSED static void static_assert_func(void) { 29 STATIC_ASSERT(ISL_AUX_OP_ASSERT == ((enum isl_aux_op) 0)); 30 STATIC_ASSERT(ISL_AUX_STATE_ASSERT == ((enum isl_aux_state) 0)); 31} 32 33#undef unreachable 34#define unreachable(str) return 0 35 36#undef assert 37#define assert(cond) do { \ 38 if (!(cond)) { \ 39 return 0; \ 40 } \ 41} while (0) 42#endif 43 44/* How writes with an isl_aux_usage behave. */ 45enum write_behavior { 46 /* Writes only touch the main surface. */ 47 WRITES_ONLY_TOUCH_MAIN = 0, 48 49 /* Writes using the 3D engine are compressed. */ 50 WRITES_COMPRESS, 51 52 /* Writes using the 3D engine are either compressed or substituted with 53 * fast-cleared blocks. 54 */ 55 WRITES_COMPRESS_CLEAR, 56 57 /* Writes implicitly fully resolve the compression block and write the data 58 * uncompressed into the main surface. The resolved aux blocks are 59 * ambiguated and left in the pass-through state. 60 */ 61 WRITES_RESOLVE_AMBIGUATE, 62}; 63 64/* A set of features supported by an isl_aux_usage. */ 65struct aux_usage_info { 66 67 /* How writes affect the surface(s) in use. */ 68 enum write_behavior write_behavior; 69 70 /* Aux supports "real" compression beyond just fast-clears. */ 71 bool compressed; 72 73 /* SW can perform ISL_AUX_OP_FAST_CLEAR. */ 74 bool fast_clear; 75 76 /* SW can perform ISL_AUX_OP_PARTIAL_RESOLVE. */ 77 bool partial_resolve; 78 79 /* Performing ISL_AUX_OP_FULL_RESOLVE includes ISL_AUX_OP_AMBIGUATE. */ 80 bool full_resolves_ambiguate; 81}; 82 83#define AUX(wb, c, fc, pr, fra, type) \ 84 [ISL_AUX_USAGE_ ## type] = { WRITES_ ## wb, c, fc, pr, fra}, 85#define Y true 86#define x false 87static const struct aux_usage_info info[] = { 88/* write_behavior c fc pr fra */ 89 AUX( COMPRESS, Y, Y, x, x, HIZ) 90 AUX( COMPRESS, Y, Y, x, x, HIZ_CCS) 91 AUX( COMPRESS, Y, Y, x, x, HIZ_CCS_WT) 92 AUX( COMPRESS, Y, Y, Y, x, MCS) 93 AUX( COMPRESS, Y, Y, Y, x, MCS_CCS) 94 AUX( COMPRESS, Y, Y, Y, Y, CCS_E) 95 AUX( COMPRESS_CLEAR, Y, Y, Y, Y, GFX12_CCS_E) 96 AUX(RESOLVE_AMBIGUATE, x, Y, x, Y, CCS_D) 97 AUX(RESOLVE_AMBIGUATE, Y, x, x, Y, MC) 98 AUX( COMPRESS, Y, x, x, Y, STC_CCS) 99}; 100#undef x 101#undef Y 102#undef AUX 103 104ASSERTED static bool 105aux_state_possible(enum isl_aux_state state, 106 enum isl_aux_usage usage) 107{ 108 switch (state) { 109 case ISL_AUX_STATE_CLEAR: 110 case ISL_AUX_STATE_PARTIAL_CLEAR: 111 return info[usage].fast_clear; 112 case ISL_AUX_STATE_COMPRESSED_CLEAR: 113 return info[usage].fast_clear && info[usage].compressed; 114 case ISL_AUX_STATE_COMPRESSED_NO_CLEAR: 115 return info[usage].compressed; 116 case ISL_AUX_STATE_RESOLVED: 117 case ISL_AUX_STATE_PASS_THROUGH: 118 case ISL_AUX_STATE_AUX_INVALID: 119 return true; 120#ifdef IN_UNIT_TEST 121 case ISL_AUX_STATE_ASSERT: 122 break; 123#endif 124 } 125 126 unreachable("Invalid aux state."); 127} 128 129enum isl_aux_op 130isl_aux_prepare_access(enum isl_aux_state initial_state, 131 enum isl_aux_usage usage, 132 bool fast_clear_supported) 133{ 134 if (usage != ISL_AUX_USAGE_NONE) { 135 UNUSED const enum isl_aux_usage state_superset_usage = 136 usage == ISL_AUX_USAGE_CCS_D ? ISL_AUX_USAGE_CCS_E : usage; 137 assert(aux_state_possible(initial_state, state_superset_usage)); 138 } 139 assert(!fast_clear_supported || info[usage].fast_clear); 140 141 switch (initial_state) { 142 case ISL_AUX_STATE_COMPRESSED_CLEAR: 143 if (!info[usage].compressed) 144 return ISL_AUX_OP_FULL_RESOLVE; 145 FALLTHROUGH; 146 case ISL_AUX_STATE_CLEAR: 147 case ISL_AUX_STATE_PARTIAL_CLEAR: 148 return fast_clear_supported ? 149 ISL_AUX_OP_NONE : 150 info[usage].partial_resolve ? 151 ISL_AUX_OP_PARTIAL_RESOLVE : ISL_AUX_OP_FULL_RESOLVE; 152 case ISL_AUX_STATE_COMPRESSED_NO_CLEAR: 153 return info[usage].compressed ? 154 ISL_AUX_OP_NONE : ISL_AUX_OP_FULL_RESOLVE; 155 case ISL_AUX_STATE_RESOLVED: 156 case ISL_AUX_STATE_PASS_THROUGH: 157 return ISL_AUX_OP_NONE; 158 case ISL_AUX_STATE_AUX_INVALID: 159 return info[usage].write_behavior == WRITES_ONLY_TOUCH_MAIN ? 160 ISL_AUX_OP_NONE : ISL_AUX_OP_AMBIGUATE; 161#ifdef IN_UNIT_TEST 162 case ISL_AUX_STATE_ASSERT: 163 break; 164#endif 165 } 166 167 unreachable("Invalid aux state."); 168} 169 170enum isl_aux_state 171isl_aux_state_transition_aux_op(enum isl_aux_state initial_state, 172 enum isl_aux_usage usage, 173 enum isl_aux_op op) 174{ 175 assert(aux_state_possible(initial_state, usage)); 176 assert(usage != ISL_AUX_USAGE_NONE || op == ISL_AUX_OP_NONE); 177 178 switch (op) { 179 case ISL_AUX_OP_NONE: 180 return initial_state; 181 case ISL_AUX_OP_FAST_CLEAR: 182 assert(info[usage].fast_clear); 183 return ISL_AUX_STATE_CLEAR; 184 case ISL_AUX_OP_PARTIAL_RESOLVE: 185 assert(isl_aux_state_has_valid_aux(initial_state)); 186 assert(info[usage].partial_resolve); 187 return initial_state == ISL_AUX_STATE_CLEAR || 188 initial_state == ISL_AUX_STATE_PARTIAL_CLEAR || 189 initial_state == ISL_AUX_STATE_COMPRESSED_CLEAR ? 190 ISL_AUX_STATE_COMPRESSED_NO_CLEAR : initial_state; 191 case ISL_AUX_OP_FULL_RESOLVE: 192 assert(isl_aux_state_has_valid_aux(initial_state)); 193 return info[usage].full_resolves_ambiguate || 194 initial_state == ISL_AUX_STATE_PASS_THROUGH ? 195 ISL_AUX_STATE_PASS_THROUGH : ISL_AUX_STATE_RESOLVED; 196 case ISL_AUX_OP_AMBIGUATE: 197 return ISL_AUX_STATE_PASS_THROUGH; 198#if IN_UNIT_TEST 199 case ISL_AUX_OP_ASSERT: 200 break; 201#endif 202 } 203 204 unreachable("Invalid aux op."); 205} 206 207enum isl_aux_state 208isl_aux_state_transition_write(enum isl_aux_state initial_state, 209 enum isl_aux_usage usage, 210 bool full_surface) 211{ 212 if (info[usage].write_behavior == WRITES_ONLY_TOUCH_MAIN) { 213 assert(full_surface || isl_aux_state_has_valid_primary(initial_state)); 214 215 return initial_state == ISL_AUX_STATE_PASS_THROUGH ? 216 ISL_AUX_STATE_PASS_THROUGH : ISL_AUX_STATE_AUX_INVALID; 217 } 218 219 assert(isl_aux_state_has_valid_aux(initial_state)); 220 assert(aux_state_possible(initial_state, usage)); 221 assert(info[usage].write_behavior == WRITES_COMPRESS || 222 info[usage].write_behavior == WRITES_COMPRESS_CLEAR || 223 info[usage].write_behavior == WRITES_RESOLVE_AMBIGUATE); 224 225 if (full_surface) { 226 return info[usage].write_behavior == WRITES_COMPRESS ? 227 ISL_AUX_STATE_COMPRESSED_NO_CLEAR : 228 info[usage].write_behavior == WRITES_COMPRESS_CLEAR ? 229 ISL_AUX_STATE_COMPRESSED_CLEAR : ISL_AUX_STATE_PASS_THROUGH; 230 } 231 232 switch (initial_state) { 233 case ISL_AUX_STATE_CLEAR: 234 case ISL_AUX_STATE_PARTIAL_CLEAR: 235 return info[usage].write_behavior == WRITES_RESOLVE_AMBIGUATE ? 236 ISL_AUX_STATE_PARTIAL_CLEAR : ISL_AUX_STATE_COMPRESSED_CLEAR; 237 case ISL_AUX_STATE_RESOLVED: 238 case ISL_AUX_STATE_PASS_THROUGH: 239 case ISL_AUX_STATE_COMPRESSED_NO_CLEAR: 240 return info[usage].write_behavior == WRITES_COMPRESS ? 241 ISL_AUX_STATE_COMPRESSED_NO_CLEAR : 242 info[usage].write_behavior == WRITES_COMPRESS_CLEAR ? 243 ISL_AUX_STATE_COMPRESSED_CLEAR : initial_state; 244 case ISL_AUX_STATE_COMPRESSED_CLEAR: 245 case ISL_AUX_STATE_AUX_INVALID: 246 return initial_state; 247#ifdef IN_UNIT_TEST 248 case ISL_AUX_STATE_ASSERT: 249 break; 250#endif 251 } 252 253 unreachable("Invalid aux state."); 254} 255 256bool 257isl_aux_usage_has_fast_clears(enum isl_aux_usage usage) 258{ 259 return info[usage].fast_clear; 260} 261 262bool 263isl_aux_usage_has_compression(enum isl_aux_usage usage) 264{ 265 return info[usage].compressed; 266} 267