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