1 /*
2 * Copyright (C) 2018 Rob Clark <robclark@freedesktop.org>
3 * Copyright © 2018 Google, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 * Authors:
25 * Rob Clark <robclark@freedesktop.org>
26 */
27
28 #define FD_BO_NO_HARDPIN 1
29
30 #include "drm-uapi/drm_fourcc.h"
31
32 #include "a6xx/fd6_blitter.h"
33 #include "fd6_resource.h"
34 #include "fdl/fd6_format_table.h"
35
36 #include "a6xx.xml.h"
37
38 /* A subset of the valid tiled formats can be compressed. We do
39 * already require tiled in order to be compressed, but just because
40 * it can be tiled doesn't mean it can be compressed.
41 */
42 static bool
ok_ubwc_format(struct pipe_screen * pscreen,enum pipe_format pfmt)43 ok_ubwc_format(struct pipe_screen *pscreen, enum pipe_format pfmt)
44 {
45 const struct fd_dev_info *info = fd_screen(pscreen)->info;
46
47 switch (pfmt) {
48 case PIPE_FORMAT_X24S8_UINT:
49 case PIPE_FORMAT_Z24_UNORM_S8_UINT:
50 /* We can't sample stencil with UBWC on a630, and we may need to be able
51 * to sample stencil at some point. We can't just use
52 * fd_resource_uncompress() at the point of stencil sampling because
53 * that itself uses stencil sampling in the fd_blitter_blit path.
54 */
55 return info->a6xx.has_z24uint_s8uint;
56
57 case PIPE_FORMAT_R8_G8B8_420_UNORM:
58 /* The difference between NV12 and R8_G8B8_420_UNORM is only where the
59 * conversion to RGB happens, with the latter it happens _after_ the
60 * texture samp instruction. But dri2_get_mapping_by_fourcc() doesn't
61 * know this, so it asks for NV12 when it really meant to ask for
62 * R8_G8B8_420_UNORM. Just treat them the same here to work around it:
63 */
64 case PIPE_FORMAT_NV12:
65 return true;
66
67 default:
68 break;
69 }
70
71 /* A690 seem to have broken UBWC for depth/stencil, it requires
72 * depth flushing where we cannot realistically place it, like between
73 * ordinary draw calls writing read/depth. WSL blob seem to use ubwc
74 * sometimes for depth/stencil.
75 */
76 if (info->a6xx.broken_ds_ubwc_quirk &&
77 util_format_is_depth_or_stencil(pfmt))
78 return false;
79
80 switch (fd6_color_format(pfmt, TILE6_LINEAR)) {
81 case FMT6_10_10_10_2_UINT:
82 case FMT6_10_10_10_2_UNORM_DEST:
83 case FMT6_11_11_10_FLOAT:
84 case FMT6_16_FLOAT:
85 case FMT6_16_16_16_16_FLOAT:
86 case FMT6_16_16_16_16_SINT:
87 case FMT6_16_16_16_16_UINT:
88 case FMT6_16_16_FLOAT:
89 case FMT6_16_16_SINT:
90 case FMT6_16_16_UINT:
91 case FMT6_16_SINT:
92 case FMT6_16_UINT:
93 case FMT6_32_32_32_32_SINT:
94 case FMT6_32_32_32_32_UINT:
95 case FMT6_32_32_SINT:
96 case FMT6_32_32_UINT:
97 case FMT6_5_6_5_UNORM:
98 case FMT6_5_5_5_1_UNORM:
99 case FMT6_8_8_8_8_SINT:
100 case FMT6_8_8_8_8_UINT:
101 case FMT6_8_8_8_8_UNORM:
102 case FMT6_8_8_8_X8_UNORM:
103 case FMT6_8_8_SINT:
104 case FMT6_8_8_UINT:
105 case FMT6_8_8_UNORM:
106 case FMT6_Z24_UNORM_S8_UINT:
107 case FMT6_Z24_UNORM_S8_UINT_AS_R8G8B8A8:
108 return true;
109 case FMT6_8_UNORM:
110 return info->a6xx.has_8bpp_ubwc;
111 default:
112 return false;
113 }
114 }
115
116 static bool
can_do_ubwc(struct pipe_resource * prsc)117 can_do_ubwc(struct pipe_resource *prsc)
118 {
119 /* limit things to simple single level 2d for now: */
120 if ((prsc->depth0 != 1) || (prsc->array_size != 1) ||
121 (prsc->last_level != 0))
122 return false;
123 if (prsc->target != PIPE_TEXTURE_2D)
124 return false;
125 if (!ok_ubwc_format(prsc->screen, prsc->format))
126 return false;
127 return true;
128 }
129
130 static bool
is_norm(enum pipe_format format)131 is_norm(enum pipe_format format)
132 {
133 const struct util_format_description *desc = util_format_description(format);
134
135 return desc->is_snorm || desc->is_unorm;
136 }
137
138 static bool
is_z24s8(enum pipe_format format)139 is_z24s8(enum pipe_format format)
140 {
141 switch (format) {
142 case PIPE_FORMAT_Z24_UNORM_S8_UINT:
143 case PIPE_FORMAT_Z24X8_UNORM:
144 case PIPE_FORMAT_X24S8_UINT:
145 case PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8:
146 return true;
147 default:
148 return false;
149 }
150 }
151
152 static bool
valid_format_cast(struct fd_resource * rsc,enum pipe_format format)153 valid_format_cast(struct fd_resource *rsc, enum pipe_format format)
154 {
155 /* Special case "casting" format in hw: */
156 if (format == PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8)
157 return true;
158
159 /* If we support z24s8 ubwc then allow casts between the various
160 * permutations of z24s8:
161 */
162 if (fd_screen(rsc->b.b.screen)->info->a6xx.has_z24uint_s8uint &&
163 is_z24s8(format) && is_z24s8(rsc->b.b.format))
164 return true;
165
166 /* For some color values (just "solid white") compression metadata maps to
167 * different pixel values for uint/sint vs unorm/snorm, so we can't reliably
168 * "cast" u/snorm to u/sint and visa versa:
169 */
170 if (is_norm(format) != is_norm(rsc->b.b.format))
171 return false;
172
173 /* The UBWC formats can be re-interpreted so long as the components
174 * have the same # of bits
175 */
176 for (unsigned i = 0; i < 4; i++) {
177 unsigned sb, db;
178
179 sb = util_format_get_component_bits(rsc->b.b.format, UTIL_FORMAT_COLORSPACE_RGB, i);
180 db = util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, i);
181
182 if (sb != db)
183 return false;
184 }
185
186 return true;
187 }
188
189 /**
190 * R8G8 have a different block width/height and height alignment from other
191 * formats that would normally be compatible (like R16), and so if we are
192 * trying to, for example, sample R16 as R8G8 we need to demote to linear.
193 */
194 static bool
is_r8g8(enum pipe_format format)195 is_r8g8(enum pipe_format format)
196 {
197 return (util_format_get_blocksize(format) == 2) &&
198 (util_format_get_nr_components(format) == 2);
199 }
200
201 /**
202 * Can a rsc as it is currently laid out be accessed as the specified format.
203 * Returns whether the access is ok or whether the rsc needs to be demoted
204 * to uncompressed tiled or linear.
205 */
206 enum fd6_format_status
fd6_check_valid_format(struct fd_resource * rsc,enum pipe_format format)207 fd6_check_valid_format(struct fd_resource *rsc, enum pipe_format format)
208 {
209 enum pipe_format orig_format = rsc->b.b.format;
210
211 if (orig_format == format)
212 return FORMAT_OK;
213
214 if (rsc->layout.tile_mode && (is_r8g8(orig_format) != is_r8g8(format)))
215 return DEMOTE_TO_LINEAR;
216
217 if (!rsc->layout.ubwc)
218 return FORMAT_OK;
219
220 if (ok_ubwc_format(rsc->b.b.screen, format) && valid_format_cast(rsc, format))
221 return FORMAT_OK;
222
223 return DEMOTE_TO_TILED;
224 }
225
226 /**
227 * Ensure the rsc is in an ok state to be used with the specified format.
228 * This handles the case of UBWC buffers used with non-UBWC compatible
229 * formats, by triggering an uncompress.
230 */
231 void
fd6_validate_format(struct fd_context * ctx,struct fd_resource * rsc,enum pipe_format format)232 fd6_validate_format(struct fd_context *ctx, struct fd_resource *rsc,
233 enum pipe_format format)
234 {
235 tc_assert_driver_thread(ctx->tc);
236
237 switch (fd6_check_valid_format(rsc, format)) {
238 case FORMAT_OK:
239 return;
240 case DEMOTE_TO_LINEAR:
241 perf_debug_ctx(ctx,
242 "%" PRSC_FMT ": demoted to linear+uncompressed due to use as %s",
243 PRSC_ARGS(&rsc->b.b), util_format_short_name(format));
244
245 fd_resource_uncompress(ctx, rsc, true);
246 return;
247 case DEMOTE_TO_TILED:
248 perf_debug_ctx(ctx,
249 "%" PRSC_FMT ": demoted to uncompressed due to use as %s",
250 PRSC_ARGS(&rsc->b.b), util_format_short_name(format));
251
252 fd_resource_uncompress(ctx, rsc, false);
253 return;
254 }
255 }
256
257 static void
setup_lrz(struct fd_resource * rsc)258 setup_lrz(struct fd_resource *rsc)
259 {
260 struct fd_screen *screen = fd_screen(rsc->b.b.screen);
261 unsigned width0 = rsc->b.b.width0;
262 unsigned height0 = rsc->b.b.height0;
263
264 /* LRZ buffer is super-sampled: */
265 switch (rsc->b.b.nr_samples) {
266 case 4:
267 width0 *= 2;
268 FALLTHROUGH;
269 case 2:
270 height0 *= 2;
271 }
272
273 unsigned lrz_pitch = align(DIV_ROUND_UP(width0, 8), 32);
274 unsigned lrz_height = align(DIV_ROUND_UP(height0, 8), 16);
275
276 unsigned size = lrz_pitch * lrz_height * 2;
277
278 rsc->lrz_height = lrz_height;
279 rsc->lrz_width = lrz_pitch;
280 rsc->lrz_pitch = lrz_pitch;
281 rsc->lrz = fd_bo_new(screen->dev, size, FD_BO_NOMAP, "lrz");
282 }
283
284 static uint32_t
fd6_setup_slices(struct fd_resource * rsc)285 fd6_setup_slices(struct fd_resource *rsc)
286 {
287 struct pipe_resource *prsc = &rsc->b.b;
288
289 if (!FD_DBG(NOLRZ) && has_depth(prsc->format) && !is_z32(prsc->format))
290 setup_lrz(rsc);
291
292 if (rsc->layout.ubwc && !ok_ubwc_format(prsc->screen, prsc->format))
293 rsc->layout.ubwc = false;
294
295 fdl6_layout(&rsc->layout, prsc->format, fd_resource_nr_samples(prsc),
296 prsc->width0, prsc->height0, prsc->depth0, prsc->last_level + 1,
297 prsc->array_size, prsc->target == PIPE_TEXTURE_3D, NULL);
298
299 return rsc->layout.size;
300 }
301
302 static int
fill_ubwc_buffer_sizes(struct fd_resource * rsc)303 fill_ubwc_buffer_sizes(struct fd_resource *rsc)
304 {
305 struct pipe_resource *prsc = &rsc->b.b;
306 struct fdl_explicit_layout l = {
307 .offset = rsc->layout.slices[0].offset,
308 .pitch = rsc->layout.pitch0,
309 };
310
311 if (!can_do_ubwc(prsc))
312 return -1;
313
314 rsc->layout.ubwc = true;
315 rsc->layout.tile_mode = TILE6_3;
316
317 if (!fdl6_layout(&rsc->layout, prsc->format, fd_resource_nr_samples(prsc),
318 prsc->width0, prsc->height0, prsc->depth0,
319 prsc->last_level + 1, prsc->array_size, false, &l))
320 return -1;
321
322 if (rsc->layout.size > fd_bo_size(rsc->bo))
323 return -1;
324
325 return 0;
326 }
327
328 static int
fd6_layout_resource_for_modifier(struct fd_resource * rsc,uint64_t modifier)329 fd6_layout_resource_for_modifier(struct fd_resource *rsc, uint64_t modifier)
330 {
331 switch (modifier) {
332 case DRM_FORMAT_MOD_QCOM_COMPRESSED:
333 return fill_ubwc_buffer_sizes(rsc);
334 case DRM_FORMAT_MOD_LINEAR:
335 if (can_do_ubwc(&rsc->b.b)) {
336 perf_debug("%" PRSC_FMT
337 ": not UBWC: imported with DRM_FORMAT_MOD_LINEAR!",
338 PRSC_ARGS(&rsc->b.b));
339 }
340 return 0;
341 case DRM_FORMAT_MOD_QCOM_TILED3:
342 rsc->layout.tile_mode = fd6_tile_mode(&rsc->b.b);
343 FALLTHROUGH;
344 case DRM_FORMAT_MOD_INVALID:
345 /* For now, without buffer metadata, we must assume that buffers
346 * imported with INVALID modifier are linear
347 */
348 if (can_do_ubwc(&rsc->b.b)) {
349 perf_debug("%" PRSC_FMT
350 ": not UBWC: imported with DRM_FORMAT_MOD_INVALID!",
351 PRSC_ARGS(&rsc->b.b));
352 }
353 return 0;
354 default:
355 return -1;
356 }
357 }
358
359 static bool
fd6_is_format_supported(struct pipe_screen * pscreen,enum pipe_format fmt,uint64_t modifier)360 fd6_is_format_supported(struct pipe_screen *pscreen,
361 enum pipe_format fmt,
362 uint64_t modifier)
363 {
364 switch (modifier) {
365 case DRM_FORMAT_MOD_LINEAR:
366 return true;
367 case DRM_FORMAT_MOD_QCOM_COMPRESSED:
368 return ok_ubwc_format(pscreen, fmt);
369 case DRM_FORMAT_MOD_QCOM_TILED3:
370 return fd6_tile_mode_for_format(fmt) == TILE6_3;
371 default:
372 return false;
373 }
374 }
375
376 void
fd6_resource_screen_init(struct pipe_screen * pscreen)377 fd6_resource_screen_init(struct pipe_screen *pscreen)
378 {
379 struct fd_screen *screen = fd_screen(pscreen);
380
381 screen->setup_slices = fd6_setup_slices;
382 screen->layout_resource_for_modifier = fd6_layout_resource_for_modifier;
383 screen->is_format_supported = fd6_is_format_supported;
384 }
385