1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2018 Rob Clark <[email protected]>
3*61046927SAndroid Build Coastguard Worker * Copyright © 2018-2019 Google, Inc.
4*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker *
6*61046927SAndroid Build Coastguard Worker * Authors:
7*61046927SAndroid Build Coastguard Worker * Rob Clark <[email protected]>
8*61046927SAndroid Build Coastguard Worker */
9*61046927SAndroid Build Coastguard Worker
10*61046927SAndroid Build Coastguard Worker #include <stdio.h>
11*61046927SAndroid Build Coastguard Worker
12*61046927SAndroid Build Coastguard Worker #include "freedreno_layout.h"
13*61046927SAndroid Build Coastguard Worker
14*61046927SAndroid Build Coastguard Worker static bool
is_r8g8(const struct fdl_layout * layout)15*61046927SAndroid Build Coastguard Worker is_r8g8(const struct fdl_layout *layout)
16*61046927SAndroid Build Coastguard Worker {
17*61046927SAndroid Build Coastguard Worker return layout->cpp == 2 &&
18*61046927SAndroid Build Coastguard Worker util_format_get_nr_components(layout->format) == 2;
19*61046927SAndroid Build Coastguard Worker }
20*61046927SAndroid Build Coastguard Worker
21*61046927SAndroid Build Coastguard Worker void
fdl6_get_ubwc_blockwidth(const struct fdl_layout * layout,uint32_t * blockwidth,uint32_t * blockheight)22*61046927SAndroid Build Coastguard Worker fdl6_get_ubwc_blockwidth(const struct fdl_layout *layout,
23*61046927SAndroid Build Coastguard Worker uint32_t *blockwidth, uint32_t *blockheight)
24*61046927SAndroid Build Coastguard Worker {
25*61046927SAndroid Build Coastguard Worker static const struct {
26*61046927SAndroid Build Coastguard Worker uint8_t width;
27*61046927SAndroid Build Coastguard Worker uint8_t height;
28*61046927SAndroid Build Coastguard Worker } blocksize[] = {
29*61046927SAndroid Build Coastguard Worker { 16, 4 }, /* cpp = 1 */
30*61046927SAndroid Build Coastguard Worker { 16, 4 }, /* cpp = 2 */
31*61046927SAndroid Build Coastguard Worker { 16, 4 }, /* cpp = 4 */
32*61046927SAndroid Build Coastguard Worker { 8, 4 }, /* cpp = 8 */
33*61046927SAndroid Build Coastguard Worker { 4, 4 }, /* cpp = 16 */
34*61046927SAndroid Build Coastguard Worker { 4, 2 }, /* cpp = 32 */
35*61046927SAndroid Build Coastguard Worker { 0, 0 }, /* cpp = 64 (TODO) */
36*61046927SAndroid Build Coastguard Worker };
37*61046927SAndroid Build Coastguard Worker
38*61046927SAndroid Build Coastguard Worker /* special case for r8g8: */
39*61046927SAndroid Build Coastguard Worker if (is_r8g8(layout)) {
40*61046927SAndroid Build Coastguard Worker *blockwidth = 16;
41*61046927SAndroid Build Coastguard Worker *blockheight = 8;
42*61046927SAndroid Build Coastguard Worker return;
43*61046927SAndroid Build Coastguard Worker }
44*61046927SAndroid Build Coastguard Worker
45*61046927SAndroid Build Coastguard Worker if (layout->format == PIPE_FORMAT_Y8_UNORM) {
46*61046927SAndroid Build Coastguard Worker *blockwidth = 32;
47*61046927SAndroid Build Coastguard Worker *blockheight = 8;
48*61046927SAndroid Build Coastguard Worker return;
49*61046927SAndroid Build Coastguard Worker }
50*61046927SAndroid Build Coastguard Worker
51*61046927SAndroid Build Coastguard Worker /* special case for 2bpp + MSAA (not layout->cpp is already
52*61046927SAndroid Build Coastguard Worker * pre-multiplied by nr_samples):
53*61046927SAndroid Build Coastguard Worker */
54*61046927SAndroid Build Coastguard Worker if ((layout->cpp / layout->nr_samples == 2) && (layout->nr_samples > 1)) {
55*61046927SAndroid Build Coastguard Worker if (layout->nr_samples == 2) {
56*61046927SAndroid Build Coastguard Worker *blockwidth = 8;
57*61046927SAndroid Build Coastguard Worker *blockheight = 4;
58*61046927SAndroid Build Coastguard Worker } else if (layout->nr_samples == 4) {
59*61046927SAndroid Build Coastguard Worker *blockwidth = 4;
60*61046927SAndroid Build Coastguard Worker *blockheight = 4;
61*61046927SAndroid Build Coastguard Worker } else {
62*61046927SAndroid Build Coastguard Worker unreachable("bad nr_samples");
63*61046927SAndroid Build Coastguard Worker }
64*61046927SAndroid Build Coastguard Worker return;
65*61046927SAndroid Build Coastguard Worker }
66*61046927SAndroid Build Coastguard Worker
67*61046927SAndroid Build Coastguard Worker uint32_t cpp = fdl_cpp_shift(layout);
68*61046927SAndroid Build Coastguard Worker assert(cpp < ARRAY_SIZE(blocksize));
69*61046927SAndroid Build Coastguard Worker *blockwidth = blocksize[cpp].width;
70*61046927SAndroid Build Coastguard Worker *blockheight = blocksize[cpp].height;
71*61046927SAndroid Build Coastguard Worker }
72*61046927SAndroid Build Coastguard Worker
73*61046927SAndroid Build Coastguard Worker static void
fdl6_tile_alignment(struct fdl_layout * layout,uint32_t * heightalign)74*61046927SAndroid Build Coastguard Worker fdl6_tile_alignment(struct fdl_layout *layout, uint32_t *heightalign)
75*61046927SAndroid Build Coastguard Worker {
76*61046927SAndroid Build Coastguard Worker layout->pitchalign = fdl_cpp_shift(layout);
77*61046927SAndroid Build Coastguard Worker *heightalign = 16;
78*61046927SAndroid Build Coastguard Worker
79*61046927SAndroid Build Coastguard Worker if (is_r8g8(layout) || layout->cpp == 1) {
80*61046927SAndroid Build Coastguard Worker layout->pitchalign = 1;
81*61046927SAndroid Build Coastguard Worker *heightalign = 32;
82*61046927SAndroid Build Coastguard Worker } else if (layout->cpp == 2) {
83*61046927SAndroid Build Coastguard Worker layout->pitchalign = 2;
84*61046927SAndroid Build Coastguard Worker }
85*61046927SAndroid Build Coastguard Worker
86*61046927SAndroid Build Coastguard Worker /* Empirical evidence suggests that images with UBWC could have much
87*61046927SAndroid Build Coastguard Worker * looser alignment requirements, however the validity of alignment is
88*61046927SAndroid Build Coastguard Worker * heavily undertested and the "officially" supported alignment is 4096b.
89*61046927SAndroid Build Coastguard Worker */
90*61046927SAndroid Build Coastguard Worker if (layout->ubwc || util_format_is_depth_or_stencil(layout->format))
91*61046927SAndroid Build Coastguard Worker layout->base_align = 4096;
92*61046927SAndroid Build Coastguard Worker else if (layout->cpp == 1)
93*61046927SAndroid Build Coastguard Worker layout->base_align = 64;
94*61046927SAndroid Build Coastguard Worker else if (layout->cpp == 2)
95*61046927SAndroid Build Coastguard Worker layout->base_align = 128;
96*61046927SAndroid Build Coastguard Worker else
97*61046927SAndroid Build Coastguard Worker layout->base_align = 256;
98*61046927SAndroid Build Coastguard Worker }
99*61046927SAndroid Build Coastguard Worker
100*61046927SAndroid Build Coastguard Worker /* NOTE: good way to test this is: (for example)
101*61046927SAndroid Build Coastguard Worker * piglit/bin/texelFetch fs sampler3D 100x100x8
102*61046927SAndroid Build Coastguard Worker */
103*61046927SAndroid Build Coastguard Worker bool
fdl6_layout(struct fdl_layout * layout,enum pipe_format format,uint32_t nr_samples,uint32_t width0,uint32_t height0,uint32_t depth0,uint32_t mip_levels,uint32_t array_size,bool is_3d,struct fdl_explicit_layout * explicit_layout)104*61046927SAndroid Build Coastguard Worker fdl6_layout(struct fdl_layout *layout, enum pipe_format format,
105*61046927SAndroid Build Coastguard Worker uint32_t nr_samples, uint32_t width0, uint32_t height0,
106*61046927SAndroid Build Coastguard Worker uint32_t depth0, uint32_t mip_levels, uint32_t array_size,
107*61046927SAndroid Build Coastguard Worker bool is_3d, struct fdl_explicit_layout *explicit_layout)
108*61046927SAndroid Build Coastguard Worker {
109*61046927SAndroid Build Coastguard Worker uint32_t offset = 0, heightalign;
110*61046927SAndroid Build Coastguard Worker uint32_t ubwc_blockwidth, ubwc_blockheight;
111*61046927SAndroid Build Coastguard Worker
112*61046927SAndroid Build Coastguard Worker assert(nr_samples > 0);
113*61046927SAndroid Build Coastguard Worker layout->width0 = width0;
114*61046927SAndroid Build Coastguard Worker layout->height0 = height0;
115*61046927SAndroid Build Coastguard Worker layout->depth0 = depth0;
116*61046927SAndroid Build Coastguard Worker layout->mip_levels = mip_levels;
117*61046927SAndroid Build Coastguard Worker
118*61046927SAndroid Build Coastguard Worker layout->cpp = util_format_get_blocksize(format);
119*61046927SAndroid Build Coastguard Worker layout->cpp *= nr_samples;
120*61046927SAndroid Build Coastguard Worker layout->cpp_shift = ffs(layout->cpp) - 1;
121*61046927SAndroid Build Coastguard Worker
122*61046927SAndroid Build Coastguard Worker layout->format = format;
123*61046927SAndroid Build Coastguard Worker layout->nr_samples = nr_samples;
124*61046927SAndroid Build Coastguard Worker layout->layer_first = !is_3d;
125*61046927SAndroid Build Coastguard Worker
126*61046927SAndroid Build Coastguard Worker fdl6_get_ubwc_blockwidth(layout, &ubwc_blockwidth, &ubwc_blockheight);
127*61046927SAndroid Build Coastguard Worker
128*61046927SAndroid Build Coastguard Worker if (depth0 > 1 || ubwc_blockwidth == 0)
129*61046927SAndroid Build Coastguard Worker layout->ubwc = false;
130*61046927SAndroid Build Coastguard Worker
131*61046927SAndroid Build Coastguard Worker if (layout->ubwc || util_format_is_depth_or_stencil(format))
132*61046927SAndroid Build Coastguard Worker layout->tile_all = true;
133*61046927SAndroid Build Coastguard Worker
134*61046927SAndroid Build Coastguard Worker /* in layer_first layout, the level (slice) contains just one
135*61046927SAndroid Build Coastguard Worker * layer (since in fact the layer contains the slices)
136*61046927SAndroid Build Coastguard Worker */
137*61046927SAndroid Build Coastguard Worker uint32_t layers_in_level = layout->layer_first ? 1 : array_size;
138*61046927SAndroid Build Coastguard Worker
139*61046927SAndroid Build Coastguard Worker /* note: for tiled+noubwc layouts, we can use a lower pitchalign
140*61046927SAndroid Build Coastguard Worker * which will affect the linear levels only, (the hardware will still
141*61046927SAndroid Build Coastguard Worker * expect the tiled alignment on the tiled levels)
142*61046927SAndroid Build Coastguard Worker */
143*61046927SAndroid Build Coastguard Worker if (layout->tile_mode) {
144*61046927SAndroid Build Coastguard Worker fdl6_tile_alignment(layout, &heightalign);
145*61046927SAndroid Build Coastguard Worker } else {
146*61046927SAndroid Build Coastguard Worker layout->base_align = 64;
147*61046927SAndroid Build Coastguard Worker layout->pitchalign = 0;
148*61046927SAndroid Build Coastguard Worker /* align pitch to at least 16 pixels:
149*61046927SAndroid Build Coastguard Worker * both turnip and galium assume there is enough alignment for 16x4
150*61046927SAndroid Build Coastguard Worker * aligned gmem store. turnip can use CP_BLIT to work without this
151*61046927SAndroid Build Coastguard Worker * extra alignment, but gallium driver doesn't implement it yet
152*61046927SAndroid Build Coastguard Worker */
153*61046927SAndroid Build Coastguard Worker if (layout->cpp > 4)
154*61046927SAndroid Build Coastguard Worker layout->pitchalign = fdl_cpp_shift(layout) - 2;
155*61046927SAndroid Build Coastguard Worker
156*61046927SAndroid Build Coastguard Worker /* when possible, use a bit more alignment than necessary
157*61046927SAndroid Build Coastguard Worker * presumably this is better for performance?
158*61046927SAndroid Build Coastguard Worker */
159*61046927SAndroid Build Coastguard Worker if (!explicit_layout)
160*61046927SAndroid Build Coastguard Worker layout->pitchalign = fdl_cpp_shift(layout);
161*61046927SAndroid Build Coastguard Worker
162*61046927SAndroid Build Coastguard Worker /* not used, avoid "may be used uninitialized" warning */
163*61046927SAndroid Build Coastguard Worker heightalign = 1;
164*61046927SAndroid Build Coastguard Worker }
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker fdl_set_pitchalign(layout, layout->pitchalign + 6);
167*61046927SAndroid Build Coastguard Worker
168*61046927SAndroid Build Coastguard Worker if (explicit_layout) {
169*61046927SAndroid Build Coastguard Worker offset = explicit_layout->offset;
170*61046927SAndroid Build Coastguard Worker layout->pitch0 = explicit_layout->pitch;
171*61046927SAndroid Build Coastguard Worker if (align(layout->pitch0, 1 << layout->pitchalign) != layout->pitch0)
172*61046927SAndroid Build Coastguard Worker return false;
173*61046927SAndroid Build Coastguard Worker }
174*61046927SAndroid Build Coastguard Worker
175*61046927SAndroid Build Coastguard Worker uint32_t ubwc_width0 = width0;
176*61046927SAndroid Build Coastguard Worker uint32_t ubwc_height0 = height0;
177*61046927SAndroid Build Coastguard Worker uint32_t ubwc_tile_height_alignment = RGB_TILE_HEIGHT_ALIGNMENT;
178*61046927SAndroid Build Coastguard Worker if (mip_levels > 1) {
179*61046927SAndroid Build Coastguard Worker /* With mipmapping enabled, UBWC layout is power-of-two sized,
180*61046927SAndroid Build Coastguard Worker * specified in log2 width/height in the descriptors. The height
181*61046927SAndroid Build Coastguard Worker * alignment is 64 for mipmapping, but for buffer sharing (always
182*61046927SAndroid Build Coastguard Worker * single level) other participants expect 16.
183*61046927SAndroid Build Coastguard Worker */
184*61046927SAndroid Build Coastguard Worker ubwc_width0 = util_next_power_of_two(width0);
185*61046927SAndroid Build Coastguard Worker ubwc_height0 = util_next_power_of_two(height0);
186*61046927SAndroid Build Coastguard Worker ubwc_tile_height_alignment = 64;
187*61046927SAndroid Build Coastguard Worker }
188*61046927SAndroid Build Coastguard Worker layout->ubwc_width0 = align(DIV_ROUND_UP(ubwc_width0, ubwc_blockwidth),
189*61046927SAndroid Build Coastguard Worker RGB_TILE_WIDTH_ALIGNMENT);
190*61046927SAndroid Build Coastguard Worker ubwc_height0 = align(DIV_ROUND_UP(ubwc_height0, ubwc_blockheight),
191*61046927SAndroid Build Coastguard Worker ubwc_tile_height_alignment);
192*61046927SAndroid Build Coastguard Worker
193*61046927SAndroid Build Coastguard Worker uint32_t min_3d_layer_size = 0;
194*61046927SAndroid Build Coastguard Worker
195*61046927SAndroid Build Coastguard Worker for (uint32_t level = 0; level < mip_levels; level++) {
196*61046927SAndroid Build Coastguard Worker uint32_t depth = u_minify(depth0, level);
197*61046927SAndroid Build Coastguard Worker struct fdl_slice *slice = &layout->slices[level];
198*61046927SAndroid Build Coastguard Worker struct fdl_slice *ubwc_slice = &layout->ubwc_slices[level];
199*61046927SAndroid Build Coastguard Worker uint32_t tile_mode = fdl_tile_mode(layout, level);
200*61046927SAndroid Build Coastguard Worker uint32_t pitch = fdl_pitch(layout, level);
201*61046927SAndroid Build Coastguard Worker uint32_t height = u_minify(height0, level);
202*61046927SAndroid Build Coastguard Worker
203*61046927SAndroid Build Coastguard Worker uint32_t nblocksy = util_format_get_nblocksy(format, height);
204*61046927SAndroid Build Coastguard Worker if (tile_mode)
205*61046927SAndroid Build Coastguard Worker nblocksy = align(nblocksy, heightalign);
206*61046927SAndroid Build Coastguard Worker
207*61046927SAndroid Build Coastguard Worker /* The blits used for mem<->gmem work at a granularity of
208*61046927SAndroid Build Coastguard Worker * 16x4, which can cause faults due to over-fetch on the
209*61046927SAndroid Build Coastguard Worker * last level. The simple solution is to over-allocate a
210*61046927SAndroid Build Coastguard Worker * bit the last level to ensure any over-fetch is harmless.
211*61046927SAndroid Build Coastguard Worker * The pitch is already sufficiently aligned, but height
212*61046927SAndroid Build Coastguard Worker * may not be. note this only matters if last level is linear
213*61046927SAndroid Build Coastguard Worker */
214*61046927SAndroid Build Coastguard Worker if (level == mip_levels - 1)
215*61046927SAndroid Build Coastguard Worker nblocksy = align(nblocksy, 4);
216*61046927SAndroid Build Coastguard Worker
217*61046927SAndroid Build Coastguard Worker slice->offset = offset + layout->size;
218*61046927SAndroid Build Coastguard Worker
219*61046927SAndroid Build Coastguard Worker /* 1d array and 2d array textures must all have the same layer size for
220*61046927SAndroid Build Coastguard Worker * each miplevel on a6xx. For 3D, the layer size automatically reduces
221*61046927SAndroid Build Coastguard Worker * until the value we specify in TEX_CONST_3_MIN_LAYERSZ, which is used to
222*61046927SAndroid Build Coastguard Worker * make sure that we follow alignment requirements after minification.
223*61046927SAndroid Build Coastguard Worker */
224*61046927SAndroid Build Coastguard Worker if (is_3d) {
225*61046927SAndroid Build Coastguard Worker if (level == 0) {
226*61046927SAndroid Build Coastguard Worker slice->size0 = align(nblocksy * pitch, 4096);
227*61046927SAndroid Build Coastguard Worker } else if (min_3d_layer_size) {
228*61046927SAndroid Build Coastguard Worker slice->size0 = min_3d_layer_size;
229*61046927SAndroid Build Coastguard Worker } else {
230*61046927SAndroid Build Coastguard Worker /* Note: level * 2 for minifying in both X and Y. */
231*61046927SAndroid Build Coastguard Worker slice->size0 = u_minify(layout->slices[0].size0, level * 2);
232*61046927SAndroid Build Coastguard Worker
233*61046927SAndroid Build Coastguard Worker /* If this level didn't reduce the pitch by half, then fix it up,
234*61046927SAndroid Build Coastguard Worker * and this is the end of layer size reduction.
235*61046927SAndroid Build Coastguard Worker */
236*61046927SAndroid Build Coastguard Worker uint32_t pitch = fdl_pitch(layout, level);
237*61046927SAndroid Build Coastguard Worker if (pitch != fdl_pitch(layout, level - 1) / 2)
238*61046927SAndroid Build Coastguard Worker min_3d_layer_size = slice->size0 = nblocksy * pitch;
239*61046927SAndroid Build Coastguard Worker
240*61046927SAndroid Build Coastguard Worker /* If the height is now less than the alignment requirement, then
241*61046927SAndroid Build Coastguard Worker * scale it up and let this be the minimum layer size.
242*61046927SAndroid Build Coastguard Worker */
243*61046927SAndroid Build Coastguard Worker if (tile_mode && util_format_get_nblocksy(format, height) < heightalign)
244*61046927SAndroid Build Coastguard Worker min_3d_layer_size = slice->size0 = nblocksy * pitch;
245*61046927SAndroid Build Coastguard Worker
246*61046927SAndroid Build Coastguard Worker /* If the size would become un-page-aligned, stay aligned instead. */
247*61046927SAndroid Build Coastguard Worker if (align(slice->size0, 4096) != slice->size0)
248*61046927SAndroid Build Coastguard Worker min_3d_layer_size = slice->size0 = align(slice->size0, 4096);
249*61046927SAndroid Build Coastguard Worker }
250*61046927SAndroid Build Coastguard Worker } else {
251*61046927SAndroid Build Coastguard Worker slice->size0 = nblocksy * pitch;
252*61046927SAndroid Build Coastguard Worker }
253*61046927SAndroid Build Coastguard Worker
254*61046927SAndroid Build Coastguard Worker layout->size += slice->size0 * depth * layers_in_level;
255*61046927SAndroid Build Coastguard Worker
256*61046927SAndroid Build Coastguard Worker if (layout->ubwc) {
257*61046927SAndroid Build Coastguard Worker /* with UBWC every level is aligned to 4K */
258*61046927SAndroid Build Coastguard Worker layout->size = align64(layout->size, 4096);
259*61046927SAndroid Build Coastguard Worker
260*61046927SAndroid Build Coastguard Worker uint32_t meta_pitch = fdl_ubwc_pitch(layout, level);
261*61046927SAndroid Build Coastguard Worker uint32_t meta_height =
262*61046927SAndroid Build Coastguard Worker align(u_minify(ubwc_height0, level), ubwc_tile_height_alignment);
263*61046927SAndroid Build Coastguard Worker
264*61046927SAndroid Build Coastguard Worker ubwc_slice->size0 =
265*61046927SAndroid Build Coastguard Worker align(meta_pitch * meta_height, UBWC_PLANE_SIZE_ALIGNMENT);
266*61046927SAndroid Build Coastguard Worker ubwc_slice->offset = offset + layout->ubwc_layer_size;
267*61046927SAndroid Build Coastguard Worker layout->ubwc_layer_size += ubwc_slice->size0;
268*61046927SAndroid Build Coastguard Worker }
269*61046927SAndroid Build Coastguard Worker }
270*61046927SAndroid Build Coastguard Worker
271*61046927SAndroid Build Coastguard Worker if (layout->layer_first) {
272*61046927SAndroid Build Coastguard Worker layout->layer_size = align64(layout->size, 4096);
273*61046927SAndroid Build Coastguard Worker layout->size = layout->layer_size * array_size;
274*61046927SAndroid Build Coastguard Worker }
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Worker /* Place the UBWC slices before the uncompressed slices, because the
277*61046927SAndroid Build Coastguard Worker * kernel expects UBWC to be at the start of the buffer. In the HW, we
278*61046927SAndroid Build Coastguard Worker * get to program the UBWC and non-UBWC offset/strides
279*61046927SAndroid Build Coastguard Worker * independently.
280*61046927SAndroid Build Coastguard Worker */
281*61046927SAndroid Build Coastguard Worker if (layout->ubwc) {
282*61046927SAndroid Build Coastguard Worker for (uint32_t level = 0; level < mip_levels; level++)
283*61046927SAndroid Build Coastguard Worker layout->slices[level].offset += layout->ubwc_layer_size * array_size;
284*61046927SAndroid Build Coastguard Worker layout->size += layout->ubwc_layer_size * array_size;
285*61046927SAndroid Build Coastguard Worker }
286*61046927SAndroid Build Coastguard Worker
287*61046927SAndroid Build Coastguard Worker /* include explicit offset in size */
288*61046927SAndroid Build Coastguard Worker layout->size += offset;
289*61046927SAndroid Build Coastguard Worker
290*61046927SAndroid Build Coastguard Worker return true;
291*61046927SAndroid Build Coastguard Worker }
292