tu: Move UBWC layout into fdl6_layout() and use that function.
[mesa.git] / src / gallium / drivers / freedreno / a6xx / fd6_resource.c
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 "fd6_resource.h"
29 #include "fd6_format.h"
30
31 #include "a6xx.xml.h"
32
33 /* A subset of the valid tiled formats can be compressed. We do
34 * already require tiled in order to be compressed, but just because
35 * it can be tiled doesn't mean it can be compressed.
36 */
37 static bool
38 ok_ubwc_format(enum pipe_format pfmt)
39 {
40 /* NOTE: both x24s8 and z24s8 map to RB6_X8Z24_UNORM, but UBWC
41 * does not seem to work properly when sampling x24s8.. possibly
42 * because we sample it as TFMT6_8_8_8_8_UINT.
43 *
44 * This could possibly be a hw limitation, or maybe something
45 * else wrong somewhere (although z24s8 blits and sampling with
46 * UBWC seem fine). Recheck on a later revision of a6xx
47 */
48 if (pfmt == PIPE_FORMAT_X24S8_UINT)
49 return false;
50
51 switch (fd6_pipe2color(pfmt)) {
52 case RB6_R10G10B10A2_UINT:
53 case RB6_R10G10B10A2_UNORM:
54 case RB6_R11G11B10_FLOAT:
55 case RB6_R16_FLOAT:
56 case RB6_R16G16B16A16_FLOAT:
57 case RB6_R16G16B16A16_SINT:
58 case RB6_R16G16B16A16_UINT:
59 case RB6_R16G16_FLOAT:
60 case RB6_R16G16_SINT:
61 case RB6_R16G16_UINT:
62 case RB6_R16_SINT:
63 case RB6_R16_UINT:
64 case RB6_R32G32B32A32_SINT:
65 case RB6_R32G32B32A32_UINT:
66 case RB6_R32G32_SINT:
67 case RB6_R32G32_UINT:
68 case RB6_R5G6B5_UNORM:
69 case RB6_R8G8B8A8_SINT:
70 case RB6_R8G8B8A8_UINT:
71 case RB6_R8G8B8A8_UNORM:
72 case RB6_R8G8B8_UNORM:
73 case RB6_R8G8_SINT:
74 case RB6_R8G8_UINT:
75 case RB6_R8G8_UNORM:
76 case RB6_Z24_UNORM_S8_UINT:
77 case RB6_Z24_UNORM_S8_UINT_AS_R8G8B8A8:
78 return true;
79 default:
80 return false;
81 }
82 }
83
84 uint32_t
85 fd6_fill_ubwc_buffer_sizes(struct fd_resource *rsc)
86 {
87 #define RBG_TILE_WIDTH_ALIGNMENT 64
88 #define RGB_TILE_HEIGHT_ALIGNMENT 16
89 #define UBWC_PLANE_SIZE_ALIGNMENT 4096
90
91 struct pipe_resource *prsc = &rsc->base;
92 uint32_t width = prsc->width0;
93 uint32_t height = prsc->height0;
94
95 if (!ok_ubwc_format(prsc->format))
96 return 0;
97
98 /* limit things to simple single level 2d for now: */
99 if ((prsc->depth0 != 1) || (prsc->array_size != 1) || (prsc->last_level != 0))
100 return 0;
101
102 uint32_t block_width, block_height;
103 switch (rsc->layout.cpp) {
104 case 2:
105 case 4:
106 block_width = 16;
107 block_height = 4;
108 break;
109 case 8:
110 block_width = 8;
111 block_height = 4;
112 break;
113 case 16:
114 block_width = 4;
115 block_height = 4;
116 break;
117 default:
118 return 0;
119 }
120
121 uint32_t meta_stride =
122 ALIGN_POT(DIV_ROUND_UP(width, block_width), RBG_TILE_WIDTH_ALIGNMENT);
123 uint32_t meta_height =
124 ALIGN_POT(DIV_ROUND_UP(height, block_height), RGB_TILE_HEIGHT_ALIGNMENT);
125 uint32_t meta_size =
126 ALIGN_POT(meta_stride * meta_height, UBWC_PLANE_SIZE_ALIGNMENT);
127
128 /* UBWC goes first, then color data.. this constraint is mainly only
129 * because it is what the kernel expects for scanout. For non-2D we
130 * could just use a separate UBWC buffer..
131 */
132 for (int level = 0; level <= prsc->last_level; level++) {
133 struct fdl_slice *slice = fd_resource_slice(rsc, level);
134 slice->offset += meta_size;
135 }
136
137 rsc->layout.ubwc_slices[0].offset = 0;
138 rsc->layout.ubwc_slices[0].pitch = meta_stride;
139 rsc->layout.ubwc_size = meta_size >> 2; /* in dwords??? */
140 rsc->layout.tile_mode = TILE6_3;
141
142 return meta_size;
143 }
144
145 /**
146 * Ensure the rsc is in an ok state to be used with the specified format.
147 * This handles the case of UBWC buffers used with non-UBWC compatible
148 * formats, by triggering an uncompress.
149 */
150 void
151 fd6_validate_format(struct fd_context *ctx, struct fd_resource *rsc,
152 enum pipe_format format)
153 {
154 if (!rsc->layout.ubwc_size)
155 return;
156
157 if (ok_ubwc_format(format))
158 return;
159
160 fd_resource_uncompress(ctx, rsc);
161 }
162
163 static void
164 setup_lrz(struct fd_resource *rsc)
165 {
166 struct fd_screen *screen = fd_screen(rsc->base.screen);
167 const uint32_t flags = DRM_FREEDRENO_GEM_CACHE_WCOMBINE |
168 DRM_FREEDRENO_GEM_TYPE_KMEM; /* TODO */
169 unsigned width0 = rsc->base.width0;
170 unsigned height0 = rsc->base.height0;
171
172 /* LRZ buffer is super-sampled: */
173 switch (rsc->base.nr_samples) {
174 case 4:
175 width0 *= 2;
176 /* fallthru */
177 case 2:
178 height0 *= 2;
179 }
180
181 unsigned lrz_pitch = align(DIV_ROUND_UP(width0, 8), 32);
182 unsigned lrz_height = align(DIV_ROUND_UP(height0, 8), 16);
183
184 unsigned size = lrz_pitch * lrz_height * 2;
185
186 rsc->lrz_height = lrz_height;
187 rsc->lrz_width = lrz_pitch;
188 rsc->lrz_pitch = lrz_pitch;
189 rsc->lrz = fd_bo_new(screen->dev, size, flags, "lrz");
190 }
191
192 uint32_t
193 fd6_setup_slices(struct fd_resource *rsc)
194 {
195 struct pipe_resource *prsc = &rsc->base;
196
197 if (!(fd_mesa_debug & FD_DBG_NOLRZ) && has_depth(rsc->base.format))
198 setup_lrz(rsc);
199
200 fdl6_layout(&rsc->layout, prsc->format, fd_resource_nr_samples(prsc),
201 prsc->width0, prsc->height0, prsc->depth0,
202 prsc->last_level + 1, prsc->array_size,
203 prsc->target == PIPE_TEXTURE_3D, false);
204
205 /* The caller does this bit of layout setup again. */
206 if (rsc->layout.layer_first)
207 return rsc->layout.size / prsc->array_size;
208 else
209 return rsc->layout.size;
210 }