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 #include "drm-uapi/drm_fourcc.h"
29
30 #include "fd6_format.h"
31 #include "fd6_resource.h"
32
33 #include "a6xx.xml.h"
34
35 /* A subset of the valid tiled formats can be compressed. We do
36 * already require tiled in order to be compressed, but just because
37 * it can be tiled doesn't mean it can be compressed.
38 */
39 static bool
ok_ubwc_format(struct pipe_screen * pscreen,enum pipe_format pfmt)40 ok_ubwc_format(struct pipe_screen *pscreen, enum pipe_format pfmt)
41 {
42 const struct fd_dev_info *info = fd_screen(pscreen)->info;
43
44 switch (pfmt) {
45 case PIPE_FORMAT_X24S8_UINT:
46 case PIPE_FORMAT_Z24_UNORM_S8_UINT:
47 /* We can't sample stencil with UBWC on a630, and we may need to be able
48 * to sample stencil at some point. We can't just use
49 * fd_resource_uncompress() at the point of stencil sampling because
50 * that itself uses stencil sampling in the fd_blitter_blit path.
51 */
52 return info->a6xx.has_z24uint_s8uint;
53
54 case PIPE_FORMAT_R8_G8B8_420_UNORM:
55 return true;
56
57 default:
58 break;
59 }
60
61 switch (fd6_color_format(pfmt, TILE6_LINEAR)) {
62 case FMT6_10_10_10_2_UINT:
63 case FMT6_10_10_10_2_UNORM_DEST:
64 case FMT6_11_11_10_FLOAT:
65 case FMT6_16_FLOAT:
66 case FMT6_16_16_16_16_FLOAT:
67 case FMT6_16_16_16_16_SINT:
68 case FMT6_16_16_16_16_UINT:
69 case FMT6_16_16_FLOAT:
70 case FMT6_16_16_SINT:
71 case FMT6_16_16_UINT:
72 case FMT6_16_SINT:
73 case FMT6_16_UINT:
74 case FMT6_32_32_32_32_SINT:
75 case FMT6_32_32_32_32_UINT:
76 case FMT6_32_32_SINT:
77 case FMT6_32_32_UINT:
78 case FMT6_5_6_5_UNORM:
79 case FMT6_5_5_5_1_UNORM:
80 case FMT6_8_8_8_8_SINT:
81 case FMT6_8_8_8_8_UINT:
82 case FMT6_8_8_8_8_UNORM:
83 case FMT6_8_8_8_X8_UNORM:
84 case FMT6_8_8_SINT:
85 case FMT6_8_8_UINT:
86 case FMT6_8_8_UNORM:
87 case FMT6_Z24_UNORM_S8_UINT:
88 case FMT6_Z24_UNORM_S8_UINT_AS_R8G8B8A8:
89 return true;
90 case FMT6_8_UNORM:
91 return info->a6xx.has_8bpp_ubwc;
92 default:
93 return false;
94 }
95 }
96
97 static bool
can_do_ubwc(struct pipe_resource * prsc)98 can_do_ubwc(struct pipe_resource *prsc)
99 {
100 /* limit things to simple single level 2d for now: */
101 if ((prsc->depth0 != 1) || (prsc->array_size != 1) ||
102 (prsc->last_level != 0))
103 return false;
104 if (prsc->target != PIPE_TEXTURE_2D)
105 return false;
106 if (!ok_ubwc_format(prsc->screen, prsc->format))
107 return false;
108 return true;
109 }
110
111 static bool
is_norm(enum pipe_format format)112 is_norm(enum pipe_format format)
113 {
114 const struct util_format_description *desc = util_format_description(format);
115
116 return desc->is_snorm || desc->is_unorm;
117 }
118
119 static bool
valid_format_cast(struct fd_resource * rsc,enum pipe_format format)120 valid_format_cast(struct fd_resource *rsc, enum pipe_format format)
121 {
122 /* Special case "casting" format in hw: */
123 if (format == PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8)
124 return true;
125
126 /* For some color values (just "solid white") compression metadata maps to
127 * different pixel values for uint/sint vs unorm/snorm, so we can't reliably
128 * "cast" u/snorm to u/sint and visa versa:
129 */
130 if (is_norm(format) != is_norm(rsc->b.b.format))
131 return false;
132
133 /* The UBWC formats can be re-interpreted so long as the components
134 * have the same # of bits
135 */
136 for (unsigned i = 0; i < 4; i++) {
137 unsigned sb, db;
138
139 sb = util_format_get_component_bits(rsc->b.b.format, UTIL_FORMAT_COLORSPACE_RGB, i);
140 db = util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, i);
141
142 if (sb != db)
143 return false;
144 }
145
146 return true;
147 }
148
149 /**
150 * R8G8 have a different block width/height and height alignment from other
151 * formats that would normally be compatible (like R16), and so if we are
152 * trying to, for example, sample R16 as R8G8 we need to demote to linear.
153 */
154 static bool
is_r8g8(enum pipe_format format)155 is_r8g8(enum pipe_format format)
156 {
157 return (util_format_get_blocksize(format) == 2) &&
158 (util_format_get_nr_components(format) == 2);
159 }
160
161 /**
162 * Ensure the rsc is in an ok state to be used with the specified format.
163 * This handles the case of UBWC buffers used with non-UBWC compatible
164 * formats, by triggering an uncompress.
165 */
166 void
fd6_validate_format(struct fd_context * ctx,struct fd_resource * rsc,enum pipe_format format)167 fd6_validate_format(struct fd_context *ctx, struct fd_resource *rsc,
168 enum pipe_format format)
169 {
170 enum pipe_format orig_format = rsc->b.b.format;
171
172 tc_assert_driver_thread(ctx->tc);
173
174 if (orig_format == format)
175 return;
176
177 if (rsc->layout.tile_mode && (is_r8g8(orig_format) != is_r8g8(format))) {
178 perf_debug_ctx(ctx,
179 "%" PRSC_FMT ": demoted to linear+uncompressed due to use as %s",
180 PRSC_ARGS(&rsc->b.b), util_format_short_name(format));
181
182 fd_resource_uncompress(ctx, rsc, true);
183 return;
184 }
185
186 if (!rsc->layout.ubwc)
187 return;
188
189 if (ok_ubwc_format(rsc->b.b.screen, format) && valid_format_cast(rsc, format))
190 return;
191
192 perf_debug_ctx(ctx,
193 "%" PRSC_FMT ": demoted to uncompressed due to use as %s",
194 PRSC_ARGS(&rsc->b.b), util_format_short_name(format));
195
196 fd_resource_uncompress(ctx, rsc, false);
197 }
198
199 static void
setup_lrz(struct fd_resource * rsc)200 setup_lrz(struct fd_resource *rsc)
201 {
202 struct fd_screen *screen = fd_screen(rsc->b.b.screen);
203 unsigned width0 = rsc->b.b.width0;
204 unsigned height0 = rsc->b.b.height0;
205
206 /* LRZ buffer is super-sampled: */
207 switch (rsc->b.b.nr_samples) {
208 case 4:
209 width0 *= 2;
210 FALLTHROUGH;
211 case 2:
212 height0 *= 2;
213 }
214
215 unsigned lrz_pitch = align(DIV_ROUND_UP(width0, 8), 32);
216 unsigned lrz_height = align(DIV_ROUND_UP(height0, 8), 16);
217
218 unsigned size = lrz_pitch * lrz_height * 2;
219
220 rsc->lrz_height = lrz_height;
221 rsc->lrz_width = lrz_pitch;
222 rsc->lrz_pitch = lrz_pitch;
223 rsc->lrz = fd_bo_new(screen->dev, size, 0, "lrz");
224 }
225
226 static uint32_t
fd6_setup_slices(struct fd_resource * rsc)227 fd6_setup_slices(struct fd_resource *rsc)
228 {
229 struct pipe_resource *prsc = &rsc->b.b;
230
231 if (!FD_DBG(NOLRZ) && has_depth(rsc->b.b.format))
232 setup_lrz(rsc);
233
234 if (rsc->layout.ubwc && !ok_ubwc_format(rsc->b.b.screen, rsc->b.b.format))
235 rsc->layout.ubwc = false;
236
237 fdl6_layout(&rsc->layout, prsc->format, fd_resource_nr_samples(prsc),
238 prsc->width0, prsc->height0, prsc->depth0, prsc->last_level + 1,
239 prsc->array_size, prsc->target == PIPE_TEXTURE_3D, NULL);
240
241 return rsc->layout.size;
242 }
243
244 static int
fill_ubwc_buffer_sizes(struct fd_resource * rsc)245 fill_ubwc_buffer_sizes(struct fd_resource *rsc)
246 {
247 struct pipe_resource *prsc = &rsc->b.b;
248 struct fdl_explicit_layout explicit = {
249 .offset = rsc->layout.slices[0].offset,
250 .pitch = rsc->layout.pitch0,
251 };
252
253 if (!can_do_ubwc(prsc))
254 return -1;
255
256 rsc->layout.ubwc = true;
257 rsc->layout.tile_mode = TILE6_3;
258
259 if (!fdl6_layout(&rsc->layout, prsc->format, fd_resource_nr_samples(prsc),
260 prsc->width0, prsc->height0, prsc->depth0,
261 prsc->last_level + 1, prsc->array_size, false, &explicit))
262 return -1;
263
264 if (rsc->layout.size > fd_bo_size(rsc->bo))
265 return -1;
266
267 return 0;
268 }
269
270 static int
fd6_layout_resource_for_modifier(struct fd_resource * rsc,uint64_t modifier)271 fd6_layout_resource_for_modifier(struct fd_resource *rsc, uint64_t modifier)
272 {
273 switch (modifier) {
274 case DRM_FORMAT_MOD_QCOM_COMPRESSED:
275 return fill_ubwc_buffer_sizes(rsc);
276 case DRM_FORMAT_MOD_LINEAR:
277 if (can_do_ubwc(&rsc->b.b)) {
278 perf_debug("%" PRSC_FMT
279 ": not UBWC: imported with DRM_FORMAT_MOD_LINEAR!",
280 PRSC_ARGS(&rsc->b.b));
281 }
282 return 0;
283 case DRM_FORMAT_MOD_INVALID:
284 if (can_do_ubwc(&rsc->b.b)) {
285 perf_debug("%" PRSC_FMT
286 ": not UBWC: imported with DRM_FORMAT_MOD_INVALID!",
287 PRSC_ARGS(&rsc->b.b));
288 }
289 return 0;
290 default:
291 return -1;
292 }
293 }
294
295 static const uint64_t supported_modifiers[] = {
296 DRM_FORMAT_MOD_LINEAR,
297 DRM_FORMAT_MOD_QCOM_COMPRESSED,
298 };
299
300 void
fd6_resource_screen_init(struct pipe_screen * pscreen)301 fd6_resource_screen_init(struct pipe_screen *pscreen)
302 {
303 struct fd_screen *screen = fd_screen(pscreen);
304
305 screen->setup_slices = fd6_setup_slices;
306 screen->layout_resource_for_modifier = fd6_layout_resource_for_modifier;
307 screen->supported_modifiers = supported_modifiers;
308 screen->num_supported_modifiers = ARRAY_SIZE(supported_modifiers);
309 }
310