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 #include "dev/intel_device_info.h"
26
27 #ifdef IN_UNIT_TEST
28 /* STATIC_ASSERT is a do { ... } while(0) statement */
static_assert_func(void)29 UNUSED static void static_assert_func(void) {
30 STATIC_ASSERT(ISL_AUX_OP_ASSERT == ((enum isl_aux_op) 0));
31 STATIC_ASSERT(ISL_AUX_STATE_ASSERT == ((enum isl_aux_state) 0));
32 }
33
34 #undef unreachable
35 #define unreachable(str) return 0
36
37 #undef assert
38 #define assert(cond) do { \
39 if (!(cond)) { \
40 return 0; \
41 } \
42 } while (0)
43 #endif
44
45 /* How writes with an isl_aux_usage behave. */
46 enum write_behavior {
47 /* Writes only touch the main surface. */
48 WRITES_ONLY_TOUCH_MAIN = 0,
49
50 /* Writes using the 3D engine are compressed. */
51 WRITES_COMPRESS,
52
53 /* Writes using the 3D engine are either compressed or substituted with
54 * fast-cleared blocks.
55 */
56 WRITES_COMPRESS_CLEAR,
57
58 /* Writes implicitly fully resolve the compression block and write the data
59 * uncompressed into the main surface. The resolved aux blocks are
60 * ambiguated and left in the pass-through state.
61 */
62 WRITES_RESOLVE_AMBIGUATE,
63 };
64
65 /* A set of features supported by an isl_aux_usage. */
66 struct aux_usage_info {
67
68 /* How writes affect the surface(s) in use. */
69 enum write_behavior write_behavior;
70
71 /* Aux supports "real" compression beyond just fast-clears. */
72 bool compressed;
73
74 /* SW can perform ISL_AUX_OP_FAST_CLEAR. */
75 bool fast_clear;
76
77 /* SW can perform ISL_AUX_OP_PARTIAL_RESOLVE. */
78 bool partial_resolve;
79
80 /* Performing ISL_AUX_OP_FULL_RESOLVE includes ISL_AUX_OP_AMBIGUATE. */
81 bool full_resolves_ambiguate;
82 };
83
84 #define AUX(wb, c, fc, pr, fra, type) \
85 [ISL_AUX_USAGE_ ## type] = { WRITES_ ## wb, c, fc, pr, fra},
86 #define Y true
87 #define x false
88 static const struct aux_usage_info info[] = {
89 /* write_behavior c fc pr fra */
90 AUX( COMPRESS, Y, Y, x, x, HIZ)
91 AUX( COMPRESS, Y, Y, x, x, HIZ_CCS)
92 AUX( COMPRESS, Y, Y, x, x, HIZ_CCS_WT)
93 AUX( COMPRESS, Y, Y, Y, x, MCS)
94 AUX( COMPRESS, Y, Y, Y, x, MCS_CCS)
95 AUX( COMPRESS, Y, Y, Y, Y, CCS_E)
96 AUX( COMPRESS_CLEAR, Y, Y, Y, Y, FCV_CCS_E)
97 AUX(RESOLVE_AMBIGUATE, x, Y, x, Y, CCS_D)
98 AUX(RESOLVE_AMBIGUATE, Y, x, x, Y, MC)
99 AUX( COMPRESS, Y, x, x, Y, STC_CCS)
100 };
101 #undef x
102 #undef Y
103 #undef AUX
104
105 ASSERTED static bool
aux_state_possible(enum isl_aux_state state,enum isl_aux_usage usage)106 aux_state_possible(enum isl_aux_state state,
107 enum isl_aux_usage usage)
108 {
109 switch (state) {
110 case ISL_AUX_STATE_CLEAR:
111 case ISL_AUX_STATE_PARTIAL_CLEAR:
112 return info[usage].fast_clear;
113 case ISL_AUX_STATE_COMPRESSED_CLEAR:
114 return info[usage].fast_clear && info[usage].compressed;
115 case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
116 return info[usage].compressed;
117 case ISL_AUX_STATE_RESOLVED:
118 case ISL_AUX_STATE_PASS_THROUGH:
119 case ISL_AUX_STATE_AUX_INVALID:
120 return true;
121 #ifdef IN_UNIT_TEST
122 case ISL_AUX_STATE_ASSERT:
123 break;
124 #endif
125 }
126
127 unreachable("Invalid aux state.");
128 }
129
130 enum isl_aux_state
isl_aux_get_initial_state(const struct intel_device_info * devinfo,enum isl_aux_usage usage,bool zeroed)131 isl_aux_get_initial_state(const struct intel_device_info *devinfo,
132 enum isl_aux_usage usage,
133 bool zeroed)
134 {
135 switch (usage) {
136 case ISL_AUX_USAGE_HIZ:
137 case ISL_AUX_USAGE_HIZ_CCS:
138 case ISL_AUX_USAGE_HIZ_CCS_WT:
139 return ISL_AUX_STATE_AUX_INVALID;
140 case ISL_AUX_USAGE_MCS:
141 case ISL_AUX_USAGE_MCS_CCS:
142 if (zeroed) {
143 /* From the Sky Lake PRM, "Compressed Multisampled Surfaces":
144 *
145 * "An MCS value of 0x00 indicates that both samples are stored in
146 * sample slice 0 (thus have the same color). This is the fully
147 * compressed case."
148 *
149 * This quote is from the 2x MSAA section, but the same mapping
150 * exists for 4-16x MSAA. This state can avoid the need to ambiguate
151 * in some cases.
152 */
153 return ISL_AUX_STATE_COMPRESSED_NO_CLEAR;
154 } else {
155 return ISL_AUX_STATE_AUX_INVALID;
156 }
157 case ISL_AUX_USAGE_CCS_D:
158 case ISL_AUX_USAGE_CCS_E:
159 case ISL_AUX_USAGE_FCV_CCS_E:
160 case ISL_AUX_USAGE_STC_CCS:
161 if (zeroed) {
162 /* From the Sky Lake PRM, "MCS Buffer for Render Target(s)":
163 *
164 * "If Software wants to enable Color Compression without Fast
165 * clear, Software needs to initialize MCS with zeros."
166 *
167 * Although MCS is mentioned, CCS seems to have been intended. This
168 * can be seen in Bspec 14091, in the row containing
169 * WaDisableCCSClearsIfRtCompressionEnabledInGT3.
170 *
171 * A CCS surface initialized to zero is in the pass-through state.
172 * This state can avoid the need to ambiguate in some cases.
173 */
174 return ISL_AUX_STATE_PASS_THROUGH;
175 } else if (devinfo->ver >= 12) {
176 assert(!devinfo->has_illegal_ccs_values);
177 /* From Bspec 47709, "MCS/CCS Buffers for Render Target(s)":
178 *
179 * "CCS surface does not require initialization. Illegal CCS
180 * [values] are treated as uncompressed memory."
181 *
182 * The above quote is from the render target section, but we assume
183 * it applies to CCS in general (e.g., STC_CCS). The uninitialized
184 * CCS may be in any aux state. We choose the one which is most
185 * convenient.
186 *
187 * We avoid states with CLEAR because stencil does not support it.
188 * Those states also create a dependency on the clear color, which
189 * can have negative performance implications. Even though some
190 * blocks may actually be encoded with CLEAR, we can get away with
191 * ignoring them - there are no known issues that require fast
192 * cleared blocks to be tracked and avoided.
193 *
194 * We specifically avoid the AUX_INVALID state because it could
195 * trigger an ambiguate. BLORP does not have support for ambiguating
196 * stencil. Also, ambiguating some LODs of mipmapped 8bpp surfaces
197 * seems to stomp on neighboring miplevels.
198 *
199 * There is only one remaining aux state which can give us correct
200 * behavior, COMPRESSED_NO_CLEAR.
201 */
202 return ISL_AUX_STATE_COMPRESSED_NO_CLEAR;
203 } else {
204 unreachable("Unsupported gfx version");
205 }
206 default:
207 unreachable("Unsupported aux mode");
208 }
209 }
210
211 enum isl_aux_op
isl_aux_prepare_access(enum isl_aux_state initial_state,enum isl_aux_usage usage,bool fast_clear_supported)212 isl_aux_prepare_access(enum isl_aux_state initial_state,
213 enum isl_aux_usage usage,
214 bool fast_clear_supported)
215 {
216 if (usage != ISL_AUX_USAGE_NONE) {
217 UNUSED const enum isl_aux_usage state_superset_usage =
218 usage == ISL_AUX_USAGE_CCS_D ? ISL_AUX_USAGE_CCS_E : usage;
219 assert(aux_state_possible(initial_state, state_superset_usage));
220 }
221 assert(!fast_clear_supported || info[usage].fast_clear);
222
223 switch (initial_state) {
224 case ISL_AUX_STATE_COMPRESSED_CLEAR:
225 if (!info[usage].compressed)
226 return ISL_AUX_OP_FULL_RESOLVE;
227 FALLTHROUGH;
228 case ISL_AUX_STATE_CLEAR:
229 case ISL_AUX_STATE_PARTIAL_CLEAR:
230 return fast_clear_supported ?
231 ISL_AUX_OP_NONE :
232 info[usage].partial_resolve ?
233 ISL_AUX_OP_PARTIAL_RESOLVE : ISL_AUX_OP_FULL_RESOLVE;
234 case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
235 return info[usage].compressed ?
236 ISL_AUX_OP_NONE : ISL_AUX_OP_FULL_RESOLVE;
237 case ISL_AUX_STATE_RESOLVED:
238 case ISL_AUX_STATE_PASS_THROUGH:
239 return ISL_AUX_OP_NONE;
240 case ISL_AUX_STATE_AUX_INVALID:
241 return info[usage].write_behavior == WRITES_ONLY_TOUCH_MAIN ?
242 ISL_AUX_OP_NONE : ISL_AUX_OP_AMBIGUATE;
243 #ifdef IN_UNIT_TEST
244 case ISL_AUX_STATE_ASSERT:
245 break;
246 #endif
247 }
248
249 unreachable("Invalid aux state.");
250 }
251
252 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)253 isl_aux_state_transition_aux_op(enum isl_aux_state initial_state,
254 enum isl_aux_usage usage,
255 enum isl_aux_op op)
256 {
257 assert(aux_state_possible(initial_state, usage));
258 assert(usage != ISL_AUX_USAGE_NONE || op == ISL_AUX_OP_NONE);
259
260 switch (op) {
261 case ISL_AUX_OP_NONE:
262 return initial_state;
263 case ISL_AUX_OP_FAST_CLEAR:
264 assert(info[usage].fast_clear);
265 return ISL_AUX_STATE_CLEAR;
266 case ISL_AUX_OP_PARTIAL_RESOLVE:
267 assert(isl_aux_state_has_valid_aux(initial_state));
268 assert(info[usage].partial_resolve);
269 return initial_state == ISL_AUX_STATE_CLEAR ||
270 initial_state == ISL_AUX_STATE_PARTIAL_CLEAR ||
271 initial_state == ISL_AUX_STATE_COMPRESSED_CLEAR ?
272 ISL_AUX_STATE_COMPRESSED_NO_CLEAR : initial_state;
273 case ISL_AUX_OP_FULL_RESOLVE:
274 assert(isl_aux_state_has_valid_aux(initial_state));
275 return info[usage].full_resolves_ambiguate ||
276 initial_state == ISL_AUX_STATE_PASS_THROUGH ?
277 ISL_AUX_STATE_PASS_THROUGH : ISL_AUX_STATE_RESOLVED;
278 case ISL_AUX_OP_AMBIGUATE:
279 return ISL_AUX_STATE_PASS_THROUGH;
280 #if IN_UNIT_TEST
281 case ISL_AUX_OP_ASSERT:
282 break;
283 #endif
284 }
285
286 unreachable("Invalid aux op.");
287 }
288
289 enum isl_aux_state
isl_aux_state_transition_write(enum isl_aux_state initial_state,enum isl_aux_usage usage,bool full_surface)290 isl_aux_state_transition_write(enum isl_aux_state initial_state,
291 enum isl_aux_usage usage,
292 bool full_surface)
293 {
294 if (info[usage].write_behavior == WRITES_ONLY_TOUCH_MAIN) {
295 assert(full_surface || isl_aux_state_has_valid_primary(initial_state));
296
297 return initial_state == ISL_AUX_STATE_PASS_THROUGH ?
298 ISL_AUX_STATE_PASS_THROUGH : ISL_AUX_STATE_AUX_INVALID;
299 }
300
301 assert(isl_aux_state_has_valid_aux(initial_state));
302 assert(aux_state_possible(initial_state, usage));
303 assert(info[usage].write_behavior == WRITES_COMPRESS ||
304 info[usage].write_behavior == WRITES_COMPRESS_CLEAR ||
305 info[usage].write_behavior == WRITES_RESOLVE_AMBIGUATE);
306
307 if (full_surface) {
308 return info[usage].write_behavior == WRITES_COMPRESS ?
309 ISL_AUX_STATE_COMPRESSED_NO_CLEAR :
310 info[usage].write_behavior == WRITES_COMPRESS_CLEAR ?
311 ISL_AUX_STATE_COMPRESSED_CLEAR : ISL_AUX_STATE_PASS_THROUGH;
312 }
313
314 switch (initial_state) {
315 case ISL_AUX_STATE_CLEAR:
316 case ISL_AUX_STATE_PARTIAL_CLEAR:
317 return info[usage].write_behavior == WRITES_RESOLVE_AMBIGUATE ?
318 ISL_AUX_STATE_PARTIAL_CLEAR : ISL_AUX_STATE_COMPRESSED_CLEAR;
319 case ISL_AUX_STATE_RESOLVED:
320 case ISL_AUX_STATE_PASS_THROUGH:
321 case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
322 return info[usage].write_behavior == WRITES_COMPRESS ?
323 ISL_AUX_STATE_COMPRESSED_NO_CLEAR :
324 info[usage].write_behavior == WRITES_COMPRESS_CLEAR ?
325 ISL_AUX_STATE_COMPRESSED_CLEAR : initial_state;
326 case ISL_AUX_STATE_COMPRESSED_CLEAR:
327 case ISL_AUX_STATE_AUX_INVALID:
328 return initial_state;
329 #ifdef IN_UNIT_TEST
330 case ISL_AUX_STATE_ASSERT:
331 break;
332 #endif
333 }
334
335 unreachable("Invalid aux state.");
336 }
337
338 bool
isl_aux_usage_has_fast_clears(enum isl_aux_usage usage)339 isl_aux_usage_has_fast_clears(enum isl_aux_usage usage)
340 {
341 return info[usage].fast_clear;
342 }
343
344 bool
isl_aux_usage_has_compression(enum isl_aux_usage usage)345 isl_aux_usage_has_compression(enum isl_aux_usage usage)
346 {
347 return info[usage].compressed;
348 }
349