• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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