1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2019 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "isl/isl.h"
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#ifdef IN_UNIT_TEST
27bf215546Sopenharmony_ci/* STATIC_ASSERT is a do { ... } while(0) statement */
28bf215546Sopenharmony_ciUNUSED static void static_assert_func(void) {
29bf215546Sopenharmony_ci   STATIC_ASSERT(ISL_AUX_OP_ASSERT == ((enum isl_aux_op) 0));
30bf215546Sopenharmony_ci   STATIC_ASSERT(ISL_AUX_STATE_ASSERT == ((enum isl_aux_state) 0));
31bf215546Sopenharmony_ci}
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#undef unreachable
34bf215546Sopenharmony_ci#define unreachable(str) return 0
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci#undef assert
37bf215546Sopenharmony_ci#define assert(cond) do { \
38bf215546Sopenharmony_ci   if (!(cond)) { \
39bf215546Sopenharmony_ci      return 0; \
40bf215546Sopenharmony_ci   } \
41bf215546Sopenharmony_ci} while (0)
42bf215546Sopenharmony_ci#endif
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci/* How writes with an isl_aux_usage behave. */
45bf215546Sopenharmony_cienum write_behavior {
46bf215546Sopenharmony_ci   /* Writes only touch the main surface. */
47bf215546Sopenharmony_ci   WRITES_ONLY_TOUCH_MAIN = 0,
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci   /* Writes using the 3D engine are compressed. */
50bf215546Sopenharmony_ci   WRITES_COMPRESS,
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci   /* Writes using the 3D engine are either compressed or substituted with
53bf215546Sopenharmony_ci    * fast-cleared blocks.
54bf215546Sopenharmony_ci    */
55bf215546Sopenharmony_ci   WRITES_COMPRESS_CLEAR,
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci   /* Writes implicitly fully resolve the compression block and write the data
58bf215546Sopenharmony_ci    * uncompressed into the main surface. The resolved aux blocks are
59bf215546Sopenharmony_ci    * ambiguated and left in the pass-through state.
60bf215546Sopenharmony_ci    */
61bf215546Sopenharmony_ci   WRITES_RESOLVE_AMBIGUATE,
62bf215546Sopenharmony_ci};
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci/* A set of features supported by an isl_aux_usage. */
65bf215546Sopenharmony_cistruct aux_usage_info {
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci   /* How writes affect the surface(s) in use. */
68bf215546Sopenharmony_ci   enum write_behavior write_behavior;
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci   /* Aux supports "real" compression beyond just fast-clears. */
71bf215546Sopenharmony_ci   bool compressed;
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci   /* SW can perform ISL_AUX_OP_FAST_CLEAR. */
74bf215546Sopenharmony_ci   bool fast_clear;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   /* SW can perform ISL_AUX_OP_PARTIAL_RESOLVE. */
77bf215546Sopenharmony_ci   bool partial_resolve;
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci   /* Performing ISL_AUX_OP_FULL_RESOLVE includes ISL_AUX_OP_AMBIGUATE. */
80bf215546Sopenharmony_ci   bool full_resolves_ambiguate;
81bf215546Sopenharmony_ci};
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci#define AUX(wb, c, fc, pr, fra, type)                   \
84bf215546Sopenharmony_ci   [ISL_AUX_USAGE_ ## type] = { WRITES_ ## wb, c, fc, pr, fra},
85bf215546Sopenharmony_ci#define Y true
86bf215546Sopenharmony_ci#define x false
87bf215546Sopenharmony_cistatic const struct aux_usage_info info[] = {
88bf215546Sopenharmony_ci/*         write_behavior c fc pr fra */
89bf215546Sopenharmony_ci   AUX(         COMPRESS, Y, Y, x, x, HIZ)
90bf215546Sopenharmony_ci   AUX(         COMPRESS, Y, Y, x, x, HIZ_CCS)
91bf215546Sopenharmony_ci   AUX(         COMPRESS, Y, Y, x, x, HIZ_CCS_WT)
92bf215546Sopenharmony_ci   AUX(         COMPRESS, Y, Y, Y, x, MCS)
93bf215546Sopenharmony_ci   AUX(         COMPRESS, Y, Y, Y, x, MCS_CCS)
94bf215546Sopenharmony_ci   AUX(         COMPRESS, Y, Y, Y, Y, CCS_E)
95bf215546Sopenharmony_ci   AUX(   COMPRESS_CLEAR, Y, Y, Y, Y, GFX12_CCS_E)
96bf215546Sopenharmony_ci   AUX(RESOLVE_AMBIGUATE, x, Y, x, Y, CCS_D)
97bf215546Sopenharmony_ci   AUX(RESOLVE_AMBIGUATE, Y, x, x, Y, MC)
98bf215546Sopenharmony_ci   AUX(         COMPRESS, Y, x, x, Y, STC_CCS)
99bf215546Sopenharmony_ci};
100bf215546Sopenharmony_ci#undef x
101bf215546Sopenharmony_ci#undef Y
102bf215546Sopenharmony_ci#undef AUX
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ciASSERTED static bool
105bf215546Sopenharmony_ciaux_state_possible(enum isl_aux_state state,
106bf215546Sopenharmony_ci                   enum isl_aux_usage usage)
107bf215546Sopenharmony_ci{
108bf215546Sopenharmony_ci   switch (state) {
109bf215546Sopenharmony_ci   case ISL_AUX_STATE_CLEAR:
110bf215546Sopenharmony_ci   case ISL_AUX_STATE_PARTIAL_CLEAR:
111bf215546Sopenharmony_ci      return info[usage].fast_clear;
112bf215546Sopenharmony_ci   case ISL_AUX_STATE_COMPRESSED_CLEAR:
113bf215546Sopenharmony_ci      return info[usage].fast_clear && info[usage].compressed;
114bf215546Sopenharmony_ci   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
115bf215546Sopenharmony_ci      return info[usage].compressed;
116bf215546Sopenharmony_ci   case ISL_AUX_STATE_RESOLVED:
117bf215546Sopenharmony_ci   case ISL_AUX_STATE_PASS_THROUGH:
118bf215546Sopenharmony_ci   case ISL_AUX_STATE_AUX_INVALID:
119bf215546Sopenharmony_ci      return true;
120bf215546Sopenharmony_ci#ifdef IN_UNIT_TEST
121bf215546Sopenharmony_ci   case ISL_AUX_STATE_ASSERT:
122bf215546Sopenharmony_ci      break;
123bf215546Sopenharmony_ci#endif
124bf215546Sopenharmony_ci   }
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_ci   unreachable("Invalid aux state.");
127bf215546Sopenharmony_ci}
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_cienum isl_aux_op
130bf215546Sopenharmony_ciisl_aux_prepare_access(enum isl_aux_state initial_state,
131bf215546Sopenharmony_ci                       enum isl_aux_usage usage,
132bf215546Sopenharmony_ci                       bool fast_clear_supported)
133bf215546Sopenharmony_ci{
134bf215546Sopenharmony_ci   if (usage != ISL_AUX_USAGE_NONE) {
135bf215546Sopenharmony_ci      UNUSED const enum isl_aux_usage state_superset_usage =
136bf215546Sopenharmony_ci         usage == ISL_AUX_USAGE_CCS_D ? ISL_AUX_USAGE_CCS_E : usage;
137bf215546Sopenharmony_ci      assert(aux_state_possible(initial_state, state_superset_usage));
138bf215546Sopenharmony_ci   }
139bf215546Sopenharmony_ci   assert(!fast_clear_supported || info[usage].fast_clear);
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   switch (initial_state) {
142bf215546Sopenharmony_ci   case ISL_AUX_STATE_COMPRESSED_CLEAR:
143bf215546Sopenharmony_ci      if (!info[usage].compressed)
144bf215546Sopenharmony_ci         return ISL_AUX_OP_FULL_RESOLVE;
145bf215546Sopenharmony_ci      FALLTHROUGH;
146bf215546Sopenharmony_ci   case ISL_AUX_STATE_CLEAR:
147bf215546Sopenharmony_ci   case ISL_AUX_STATE_PARTIAL_CLEAR:
148bf215546Sopenharmony_ci      return fast_clear_supported ?
149bf215546Sopenharmony_ci                ISL_AUX_OP_NONE :
150bf215546Sopenharmony_ci             info[usage].partial_resolve ?
151bf215546Sopenharmony_ci                ISL_AUX_OP_PARTIAL_RESOLVE : ISL_AUX_OP_FULL_RESOLVE;
152bf215546Sopenharmony_ci   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
153bf215546Sopenharmony_ci      return info[usage].compressed ?
154bf215546Sopenharmony_ci             ISL_AUX_OP_NONE : ISL_AUX_OP_FULL_RESOLVE;
155bf215546Sopenharmony_ci   case ISL_AUX_STATE_RESOLVED:
156bf215546Sopenharmony_ci   case ISL_AUX_STATE_PASS_THROUGH:
157bf215546Sopenharmony_ci      return ISL_AUX_OP_NONE;
158bf215546Sopenharmony_ci   case ISL_AUX_STATE_AUX_INVALID:
159bf215546Sopenharmony_ci      return info[usage].write_behavior == WRITES_ONLY_TOUCH_MAIN ?
160bf215546Sopenharmony_ci             ISL_AUX_OP_NONE : ISL_AUX_OP_AMBIGUATE;
161bf215546Sopenharmony_ci#ifdef IN_UNIT_TEST
162bf215546Sopenharmony_ci   case ISL_AUX_STATE_ASSERT:
163bf215546Sopenharmony_ci      break;
164bf215546Sopenharmony_ci#endif
165bf215546Sopenharmony_ci   }
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci   unreachable("Invalid aux state.");
168bf215546Sopenharmony_ci}
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_cienum isl_aux_state
171bf215546Sopenharmony_ciisl_aux_state_transition_aux_op(enum isl_aux_state initial_state,
172bf215546Sopenharmony_ci                                enum isl_aux_usage usage,
173bf215546Sopenharmony_ci                                enum isl_aux_op op)
174bf215546Sopenharmony_ci{
175bf215546Sopenharmony_ci   assert(aux_state_possible(initial_state, usage));
176bf215546Sopenharmony_ci   assert(usage != ISL_AUX_USAGE_NONE || op == ISL_AUX_OP_NONE);
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci   switch (op) {
179bf215546Sopenharmony_ci   case ISL_AUX_OP_NONE:
180bf215546Sopenharmony_ci      return initial_state;
181bf215546Sopenharmony_ci   case ISL_AUX_OP_FAST_CLEAR:
182bf215546Sopenharmony_ci      assert(info[usage].fast_clear);
183bf215546Sopenharmony_ci      return ISL_AUX_STATE_CLEAR;
184bf215546Sopenharmony_ci   case ISL_AUX_OP_PARTIAL_RESOLVE:
185bf215546Sopenharmony_ci      assert(isl_aux_state_has_valid_aux(initial_state));
186bf215546Sopenharmony_ci      assert(info[usage].partial_resolve);
187bf215546Sopenharmony_ci      return initial_state == ISL_AUX_STATE_CLEAR ||
188bf215546Sopenharmony_ci             initial_state == ISL_AUX_STATE_PARTIAL_CLEAR ||
189bf215546Sopenharmony_ci             initial_state == ISL_AUX_STATE_COMPRESSED_CLEAR ?
190bf215546Sopenharmony_ci             ISL_AUX_STATE_COMPRESSED_NO_CLEAR : initial_state;
191bf215546Sopenharmony_ci   case ISL_AUX_OP_FULL_RESOLVE:
192bf215546Sopenharmony_ci      assert(isl_aux_state_has_valid_aux(initial_state));
193bf215546Sopenharmony_ci      return info[usage].full_resolves_ambiguate ||
194bf215546Sopenharmony_ci             initial_state == ISL_AUX_STATE_PASS_THROUGH ?
195bf215546Sopenharmony_ci             ISL_AUX_STATE_PASS_THROUGH : ISL_AUX_STATE_RESOLVED;
196bf215546Sopenharmony_ci   case ISL_AUX_OP_AMBIGUATE:
197bf215546Sopenharmony_ci      return ISL_AUX_STATE_PASS_THROUGH;
198bf215546Sopenharmony_ci#if IN_UNIT_TEST
199bf215546Sopenharmony_ci   case ISL_AUX_OP_ASSERT:
200bf215546Sopenharmony_ci      break;
201bf215546Sopenharmony_ci#endif
202bf215546Sopenharmony_ci   }
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   unreachable("Invalid aux op.");
205bf215546Sopenharmony_ci}
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_cienum isl_aux_state
208bf215546Sopenharmony_ciisl_aux_state_transition_write(enum isl_aux_state initial_state,
209bf215546Sopenharmony_ci                               enum isl_aux_usage usage,
210bf215546Sopenharmony_ci                               bool full_surface)
211bf215546Sopenharmony_ci{
212bf215546Sopenharmony_ci   if (info[usage].write_behavior == WRITES_ONLY_TOUCH_MAIN) {
213bf215546Sopenharmony_ci      assert(full_surface || isl_aux_state_has_valid_primary(initial_state));
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci      return initial_state == ISL_AUX_STATE_PASS_THROUGH ?
216bf215546Sopenharmony_ci             ISL_AUX_STATE_PASS_THROUGH : ISL_AUX_STATE_AUX_INVALID;
217bf215546Sopenharmony_ci   }
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci   assert(isl_aux_state_has_valid_aux(initial_state));
220bf215546Sopenharmony_ci   assert(aux_state_possible(initial_state, usage));
221bf215546Sopenharmony_ci   assert(info[usage].write_behavior == WRITES_COMPRESS ||
222bf215546Sopenharmony_ci          info[usage].write_behavior == WRITES_COMPRESS_CLEAR ||
223bf215546Sopenharmony_ci          info[usage].write_behavior == WRITES_RESOLVE_AMBIGUATE);
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci   if (full_surface) {
226bf215546Sopenharmony_ci      return info[usage].write_behavior == WRITES_COMPRESS ?
227bf215546Sopenharmony_ci                ISL_AUX_STATE_COMPRESSED_NO_CLEAR :
228bf215546Sopenharmony_ci             info[usage].write_behavior == WRITES_COMPRESS_CLEAR ?
229bf215546Sopenharmony_ci                ISL_AUX_STATE_COMPRESSED_CLEAR : ISL_AUX_STATE_PASS_THROUGH;
230bf215546Sopenharmony_ci   }
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   switch (initial_state) {
233bf215546Sopenharmony_ci   case ISL_AUX_STATE_CLEAR:
234bf215546Sopenharmony_ci   case ISL_AUX_STATE_PARTIAL_CLEAR:
235bf215546Sopenharmony_ci      return info[usage].write_behavior == WRITES_RESOLVE_AMBIGUATE ?
236bf215546Sopenharmony_ci             ISL_AUX_STATE_PARTIAL_CLEAR : ISL_AUX_STATE_COMPRESSED_CLEAR;
237bf215546Sopenharmony_ci   case ISL_AUX_STATE_RESOLVED:
238bf215546Sopenharmony_ci   case ISL_AUX_STATE_PASS_THROUGH:
239bf215546Sopenharmony_ci   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
240bf215546Sopenharmony_ci      return info[usage].write_behavior == WRITES_COMPRESS ?
241bf215546Sopenharmony_ci                ISL_AUX_STATE_COMPRESSED_NO_CLEAR :
242bf215546Sopenharmony_ci             info[usage].write_behavior == WRITES_COMPRESS_CLEAR ?
243bf215546Sopenharmony_ci                ISL_AUX_STATE_COMPRESSED_CLEAR : initial_state;
244bf215546Sopenharmony_ci   case ISL_AUX_STATE_COMPRESSED_CLEAR:
245bf215546Sopenharmony_ci   case ISL_AUX_STATE_AUX_INVALID:
246bf215546Sopenharmony_ci      return initial_state;
247bf215546Sopenharmony_ci#ifdef IN_UNIT_TEST
248bf215546Sopenharmony_ci   case ISL_AUX_STATE_ASSERT:
249bf215546Sopenharmony_ci      break;
250bf215546Sopenharmony_ci#endif
251bf215546Sopenharmony_ci   }
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci   unreachable("Invalid aux state.");
254bf215546Sopenharmony_ci}
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_cibool
257bf215546Sopenharmony_ciisl_aux_usage_has_fast_clears(enum isl_aux_usage usage)
258bf215546Sopenharmony_ci{
259bf215546Sopenharmony_ci   return info[usage].fast_clear;
260bf215546Sopenharmony_ci}
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_cibool
263bf215546Sopenharmony_ciisl_aux_usage_has_compression(enum isl_aux_usage usage)
264bf215546Sopenharmony_ci{
265bf215546Sopenharmony_ci   return info[usage].compressed;
266bf215546Sopenharmony_ci}
267