xref: /aosp_15_r20/external/mesa3d/src/intel/isl/isl_aux_info.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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