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 */
static_assert_func(void)28 UNUSED 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. */
45 enum 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. */
65 struct 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
87 static 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
104 ASSERTED static bool
aux_state_possible(enum isl_aux_state state,enum isl_aux_usage usage)105 aux_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
129 enum isl_aux_op
isl_aux_prepare_access(enum isl_aux_state initial_state,enum isl_aux_usage usage,bool fast_clear_supported)130 isl_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
170 enum isl_aux_state
isl_aux_state_transition_aux_op(enum isl_aux_state initial_state,enum isl_aux_usage usage,enum isl_aux_op op)171 isl_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
207 enum isl_aux_state
isl_aux_state_transition_write(enum isl_aux_state initial_state,enum isl_aux_usage usage,bool full_surface)208 isl_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
256 bool
isl_aux_usage_has_fast_clears(enum isl_aux_usage usage)257 isl_aux_usage_has_fast_clears(enum isl_aux_usage usage)
258 {
259 return info[usage].fast_clear;
260 }
261
262 bool
isl_aux_usage_has_compression(enum isl_aux_usage usage)263 isl_aux_usage_has_compression(enum isl_aux_usage usage)
264 {
265 return info[usage].compressed;
266 }
267