r300_texture_desc.c revision d0408cf55d9e8d1d376bd844386ef5c9789a3597
1/*
2 * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com>
3 * Copyright 2010 Marek Olšák <maraeo@gmail.com>
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
23
24#include "r300_texture_desc.h"
25
26#include "r300_context.h"
27#include "r300_winsys.h"
28
29#include "util/u_format.h"
30
31/* Returns the number of pixels that the texture should be aligned to
32 * in the given dimension. */
33unsigned r300_get_pixel_alignment(enum pipe_format format,
34                                  unsigned num_samples,
35                                  enum r300_buffer_tiling microtile,
36                                  enum r300_buffer_tiling macrotile,
37                                  enum r300_dim dim)
38{
39    static const unsigned table[2][5][3][2] =
40    {
41        {
42    /* Macro: linear    linear    linear
43       Micro: linear    tiled  square-tiled */
44            {{ 32, 1}, { 8,  4}, { 0,  0}}, /*   8 bits per pixel */
45            {{ 16, 1}, { 8,  2}, { 4,  4}}, /*  16 bits per pixel */
46            {{  8, 1}, { 4,  2}, { 0,  0}}, /*  32 bits per pixel */
47            {{  4, 1}, { 2,  2}, { 0,  0}}, /*  64 bits per pixel */
48            {{  2, 1}, { 0,  0}, { 0,  0}}  /* 128 bits per pixel */
49        },
50        {
51    /* Macro: tiled     tiled     tiled
52       Micro: linear    tiled  square-tiled */
53            {{256, 8}, {64, 32}, { 0,  0}}, /*   8 bits per pixel */
54            {{128, 8}, {64, 16}, {32, 32}}, /*  16 bits per pixel */
55            {{ 64, 8}, {32, 16}, { 0,  0}}, /*  32 bits per pixel */
56            {{ 32, 8}, {16, 16}, { 0,  0}}, /*  64 bits per pixel */
57            {{ 16, 8}, { 0,  0}, { 0,  0}}  /* 128 bits per pixel */
58        }
59    };
60    static const unsigned aa_block[2] = {4, 8};
61    unsigned tile = 0;
62    unsigned pixsize = util_format_get_blocksize(format);
63
64    assert(macrotile <= R300_BUFFER_TILED);
65    assert(microtile <= R300_BUFFER_SQUARETILED);
66    assert(pixsize <= 16);
67    assert(dim <= DIM_HEIGHT);
68
69    if (num_samples > 1) {
70        /* Multisampled textures have their own alignment scheme. */
71        if (pixsize == 4)
72            tile = aa_block[dim];
73        /* XXX FP16 AA. */
74    } else {
75        /* Standard alignment. */
76        tile = table[macrotile][util_logbase2(pixsize)][microtile][dim];
77    }
78
79    assert(tile);
80    return tile;
81}
82
83/* Return true if macrotiling should be enabled on the miplevel. */
84static boolean r300_texture_macro_switch(struct r300_texture_desc *desc,
85                                         unsigned level,
86                                         boolean rv350_mode,
87                                         enum r300_dim dim)
88{
89    unsigned tile, texdim;
90
91    tile = r300_get_pixel_alignment(desc->b.b.format, desc->b.b.nr_samples,
92                                    desc->microtile, R300_BUFFER_TILED, dim);
93    if (dim == DIM_WIDTH) {
94        texdim = u_minify(desc->width0, level);
95    } else {
96        texdim = u_minify(desc->height0, level);
97    }
98
99    /* See TX_FILTER1_n.MACRO_SWITCH. */
100    if (rv350_mode) {
101        return texdim >= tile;
102    } else {
103        return texdim > tile;
104    }
105}
106
107/**
108 * Return the stride, in bytes, of the texture image of the given texture
109 * at the given level.
110 */
111static unsigned r300_texture_get_stride(struct r300_screen *screen,
112                                        struct r300_texture_desc *desc,
113                                        unsigned level)
114{
115    unsigned tile_width, width, stride;
116
117    if (desc->stride_in_bytes_override)
118        return desc->stride_in_bytes_override;
119
120    /* Check the level. */
121    if (level > desc->b.b.last_level) {
122        SCREEN_DBG(screen, DBG_TEX, "%s: level (%u) > last_level (%u)\n",
123                   __FUNCTION__, level, desc->b.b.last_level);
124        return 0;
125    }
126
127    width = u_minify(desc->width0, level);
128
129    if (util_format_is_plain(desc->b.b.format)) {
130        tile_width = r300_get_pixel_alignment(desc->b.b.format,
131                                              desc->b.b.nr_samples,
132                                              desc->microtile,
133                                              desc->macrotile[level],
134                                              DIM_WIDTH);
135        width = align(width, tile_width);
136
137        stride = util_format_get_stride(desc->b.b.format, width);
138
139        /* Some IGPs need a minimum stride of 64 bytes, hmm... */
140        if (!desc->macrotile[level] &&
141            (screen->caps.family == CHIP_FAMILY_RS600 ||
142             screen->caps.family == CHIP_FAMILY_RS690 ||
143             screen->caps.family == CHIP_FAMILY_RS740)) {
144            unsigned min_stride;
145
146            if (desc->microtile) {
147                unsigned tile_height =
148                        r300_get_pixel_alignment(desc->b.b.format,
149                                                 desc->b.b.nr_samples,
150                                                 desc->microtile,
151                                                 desc->macrotile[level],
152                                                 DIM_HEIGHT);
153
154                min_stride = 64 / tile_height;
155            } else {
156                min_stride = 64;
157            }
158
159            return stride < min_stride ? min_stride : stride;
160        }
161
162        /* The alignment to 32 bytes is sort of implied by the layout... */
163        return stride;
164    } else {
165        return align(util_format_get_stride(desc->b.b.format, width), 32);
166    }
167}
168
169static unsigned r300_texture_get_nblocksy(struct r300_texture_desc *desc,
170                                          unsigned level,
171                                          boolean *out_aligned_for_cbzb)
172{
173    unsigned height, tile_height;
174
175    height = u_minify(desc->height0, level);
176
177    if (util_format_is_plain(desc->b.b.format)) {
178        tile_height = r300_get_pixel_alignment(desc->b.b.format,
179                                               desc->b.b.nr_samples,
180                                               desc->microtile,
181                                               desc->macrotile[level],
182                                               DIM_HEIGHT);
183        height = align(height, tile_height);
184
185        /* This is needed for the kernel checker, unfortunately. */
186        if ((desc->b.b.target != PIPE_TEXTURE_1D &&
187             desc->b.b.target != PIPE_TEXTURE_2D &&
188             desc->b.b.target != PIPE_TEXTURE_RECT) ||
189            desc->b.b.last_level != 0) {
190            height = util_next_power_of_two(height);
191        }
192
193        /* See if the CBZB clear can be used on the buffer,
194         * taking the texture size into account. */
195        if (out_aligned_for_cbzb) {
196            if (desc->macrotile[level]) {
197                /* When clearing, the layer (width*height) is horizontally split
198                 * into two, and the upper and lower halves are cleared by the CB
199                 * and ZB units, respectively. Therefore, the number of macrotiles
200                 * in the Y direction must be even. */
201
202                /* Align the height so that there is an even number of macrotiles.
203                 * Do so for 3 or more macrotiles in the Y direction. */
204                if (level == 0 && desc->b.b.last_level == 0 &&
205                    (desc->b.b.target == PIPE_TEXTURE_1D ||
206                     desc->b.b.target == PIPE_TEXTURE_2D ||
207                     desc->b.b.target == PIPE_TEXTURE_RECT) &&
208                    height >= tile_height * 3) {
209                    height = align(height, tile_height * 2);
210                }
211
212                *out_aligned_for_cbzb = height % (tile_height * 2) == 0;
213            } else {
214                *out_aligned_for_cbzb = FALSE;
215            }
216        }
217    }
218
219    return util_format_get_nblocksy(desc->b.b.format, height);
220}
221
222static void r300_texture_3d_fix_mipmapping(struct r300_screen *screen,
223                                           struct r300_texture_desc *desc)
224{
225    /* The kernels <= 2.6.34-rc4 compute the size of mipmapped 3D textures
226     * incorrectly. This is a workaround to prevent CS from being rejected. */
227
228    unsigned i, size;
229
230    if (!screen->rws->get_value(screen->rws, R300_VID_DRM_2_3_0) &&
231        desc->b.b.target == PIPE_TEXTURE_3D &&
232        desc->b.b.last_level > 0) {
233        size = 0;
234
235        for (i = 0; i <= desc->b.b.last_level; i++) {
236            size += desc->stride_in_bytes[i] *
237                    r300_texture_get_nblocksy(desc, i, FALSE);
238        }
239
240        size *= desc->depth0;
241        desc->size_in_bytes = size;
242    }
243}
244
245/* Get a width in pixels from a stride in bytes. */
246static unsigned stride_to_width(enum pipe_format format,
247                                unsigned stride_in_bytes)
248{
249    return (stride_in_bytes / util_format_get_blocksize(format)) *
250            util_format_get_blockwidth(format);
251}
252
253static void r300_setup_miptree(struct r300_screen *screen,
254                               struct r300_texture_desc *desc,
255                               boolean align_for_cbzb)
256{
257    struct pipe_resource *base = &desc->b.b;
258    unsigned stride, size, layer_size, nblocksy, i;
259    boolean rv350_mode = screen->caps.family >= CHIP_FAMILY_R350;
260    boolean aligned_for_cbzb;
261
262    desc->size_in_bytes = 0;
263
264    SCREEN_DBG(screen, DBG_TEXALLOC,
265        "r300: Making miptree for texture, format %s\n",
266        util_format_short_name(base->format));
267
268    for (i = 0; i <= base->last_level; i++) {
269        /* Let's see if this miplevel can be macrotiled. */
270        desc->macrotile[i] =
271            (desc->macrotile[0] == R300_BUFFER_TILED &&
272             r300_texture_macro_switch(desc, i, rv350_mode, DIM_WIDTH) &&
273             r300_texture_macro_switch(desc, i, rv350_mode, DIM_HEIGHT)) ?
274             R300_BUFFER_TILED : R300_BUFFER_LINEAR;
275
276        stride = r300_texture_get_stride(screen, desc, i);
277
278        /* Compute the number of blocks in Y, see if the CBZB clear can be
279         * used on the texture. */
280        aligned_for_cbzb = FALSE;
281        if (align_for_cbzb && desc->cbzb_allowed[i])
282            nblocksy = r300_texture_get_nblocksy(desc, i, &aligned_for_cbzb);
283        else
284            nblocksy = r300_texture_get_nblocksy(desc, i, NULL);
285
286        layer_size = stride * nblocksy;
287
288        if (base->nr_samples) {
289            layer_size *= base->nr_samples;
290        }
291
292        if (base->target == PIPE_TEXTURE_CUBE)
293            size = layer_size * 6;
294        else
295            size = layer_size * u_minify(desc->depth0, i);
296
297        desc->offset_in_bytes[i] = desc->size_in_bytes;
298        desc->size_in_bytes = desc->offset_in_bytes[i] + size;
299        desc->layer_size_in_bytes[i] = layer_size;
300        desc->stride_in_bytes[i] = stride;
301        desc->stride_in_pixels[i] = stride_to_width(desc->b.b.format, stride);
302        desc->cbzb_allowed[i] = desc->cbzb_allowed[i] && aligned_for_cbzb;
303
304        SCREEN_DBG(screen, DBG_TEXALLOC, "r300: Texture miptree: Level %d "
305                "(%dx%dx%d px, pitch %d bytes) %d bytes total, macrotiled %s\n",
306                i, u_minify(desc->width0, i), u_minify(desc->height0, i),
307                u_minify(desc->depth0, i), stride, desc->size_in_bytes,
308                desc->macrotile[i] ? "TRUE" : "FALSE");
309    }
310}
311
312static void r300_setup_flags(struct r300_texture_desc *desc)
313{
314    desc->uses_stride_addressing =
315        !util_is_power_of_two(desc->b.b.width0) ||
316        (desc->stride_in_bytes_override &&
317         stride_to_width(desc->b.b.format,
318                         desc->stride_in_bytes_override) != desc->b.b.width0);
319
320    desc->is_npot =
321        desc->uses_stride_addressing ||
322        !util_is_power_of_two(desc->b.b.height0) ||
323        !util_is_power_of_two(desc->b.b.depth0);
324}
325
326static void r300_setup_cbzb_flags(struct r300_screen *rscreen,
327                                  struct r300_texture_desc *desc)
328{
329    unsigned i, bpp;
330    boolean first_level_valid;
331
332    bpp = util_format_get_blocksizebits(desc->b.b.format);
333
334    /* 1) The texture must be point-sampled,
335     * 2) The depth must be 16 or 32 bits.
336     * 3) If the midpoint ZB offset is not aligned to 2048, it returns garbage
337     *    with certain texture sizes. Macrotiling ensures the alignment. */
338    first_level_valid = desc->b.b.nr_samples <= 1 &&
339                       (bpp == 16 || bpp == 32) &&
340                       desc->macrotile[0];
341
342    if (SCREEN_DBG_ON(rscreen, DBG_NO_CBZB))
343        first_level_valid = FALSE;
344
345    for (i = 0; i <= desc->b.b.last_level; i++)
346        desc->cbzb_allowed[i] = first_level_valid && desc->macrotile[i];
347}
348
349static void r300_setup_tiling(struct r300_screen *screen,
350                              struct r300_texture_desc *desc)
351{
352    struct r300_winsys_screen *rws = screen->rws;
353    enum pipe_format format = desc->b.b.format;
354    boolean rv350_mode = screen->caps.family >= CHIP_FAMILY_R350;
355    boolean is_zb = util_format_is_depth_or_stencil(format);
356    boolean dbg_no_tiling = SCREEN_DBG_ON(screen, DBG_NO_TILING);
357
358    if (!util_format_is_plain(format)) {
359        return;
360    }
361
362    /* If height == 1, disable microtiling except for zbuffer. */
363    if (!is_zb && (desc->b.b.height0 == 1 || dbg_no_tiling)) {
364        return;
365    }
366
367    /* Set microtiling. */
368    switch (util_format_get_blocksize(format)) {
369        case 1:
370        case 4:
371        case 8:
372            desc->microtile = R300_BUFFER_TILED;
373            break;
374
375        case 2:
376            if (rws->get_value(rws, R300_VID_SQUARE_TILING_SUPPORT)) {
377                desc->microtile = R300_BUFFER_SQUARETILED;
378            }
379            break;
380    }
381
382    if (dbg_no_tiling) {
383        return;
384    }
385
386    /* Set macrotiling. */
387    if (r300_texture_macro_switch(desc, 0, rv350_mode, DIM_WIDTH) &&
388        r300_texture_macro_switch(desc, 0, rv350_mode, DIM_HEIGHT)) {
389        desc->macrotile[0] = R300_BUFFER_TILED;
390    }
391}
392
393static void r300_tex_print_info(struct r300_screen *rscreen,
394                                struct r300_texture_desc *desc,
395                                const char *func)
396{
397    fprintf(stderr,
398            "r300: %s: Macro: %s, Micro: %s, Pitch: %i, Dim: %ix%ix%i, "
399            "LastLevel: %i, Size: %i, Format: %s\n",
400            func,
401            desc->macrotile[0] ? "YES" : " NO",
402            desc->microtile ? "YES" : " NO",
403            desc->stride_in_pixels[0],
404            desc->b.b.width0, desc->b.b.height0, desc->b.b.depth0,
405            desc->b.b.last_level, desc->size_in_bytes,
406            util_format_short_name(desc->b.b.format));
407}
408
409boolean r300_texture_desc_init(struct r300_screen *rscreen,
410                               struct r300_texture_desc *desc,
411                               const struct pipe_resource *base,
412                               enum r300_buffer_tiling microtile,
413                               enum r300_buffer_tiling macrotile,
414                               unsigned stride_in_bytes_override,
415                               unsigned max_buffer_size)
416{
417    desc->b.b = *base;
418    desc->b.b.screen = &rscreen->screen;
419    desc->stride_in_bytes_override = stride_in_bytes_override;
420    desc->width0 = base->width0;
421    desc->height0 = base->height0;
422    desc->depth0 = base->depth0;
423
424    r300_setup_flags(desc);
425
426    /* Align a 3D NPOT texture to POT. */
427    if (base->target == PIPE_TEXTURE_3D && desc->is_npot) {
428        desc->width0 = util_next_power_of_two(desc->width0);
429        desc->height0 = util_next_power_of_two(desc->height0);
430        desc->depth0 = util_next_power_of_two(desc->depth0);
431    }
432
433    /* Setup tiling. */
434    if (microtile == R300_BUFFER_SELECT_LAYOUT ||
435        macrotile == R300_BUFFER_SELECT_LAYOUT) {
436        r300_setup_tiling(rscreen, desc);
437    } else {
438        desc->microtile = microtile;
439        desc->macrotile[0] = macrotile;
440        assert(desc->b.b.last_level == 0);
441    }
442
443    r300_setup_cbzb_flags(rscreen, desc);
444
445    /* Setup the miptree description. */
446    r300_setup_miptree(rscreen, desc, TRUE);
447    /* If the required buffer size is larger the given max size,
448     * try again without the alignment for the CBZB clear. */
449    if (max_buffer_size && desc->size_in_bytes > max_buffer_size) {
450        r300_setup_miptree(rscreen, desc, FALSE);
451    }
452
453    r300_texture_3d_fix_mipmapping(rscreen, desc);
454
455    if (max_buffer_size) {
456        /* Make sure the buffer we got is large enough. */
457        if (desc->size_in_bytes > max_buffer_size) {
458            fprintf(stderr, "r300: texture_desc_init: The buffer is not "
459                            "large enough. Got: %i, Need: %i, Info:\n",
460                            max_buffer_size, desc->size_in_bytes);
461            r300_tex_print_info(rscreen, desc, "texture_desc_init");
462            return FALSE;
463        }
464
465        desc->buffer_size_in_bytes = max_buffer_size;
466    } else {
467        desc->buffer_size_in_bytes = desc->size_in_bytes;
468    }
469
470    if (SCREEN_DBG_ON(rscreen, DBG_TEX))
471        r300_tex_print_info(rscreen, desc, "texture_desc_init");
472
473    return TRUE;
474}
475
476unsigned r300_texture_get_offset(struct r300_texture_desc *desc,
477                                 unsigned level, unsigned zslice,
478                                 unsigned face)
479{
480    unsigned offset = desc->offset_in_bytes[level];
481
482    switch (desc->b.b.target) {
483        case PIPE_TEXTURE_3D:
484            assert(face == 0);
485            return offset + zslice * desc->layer_size_in_bytes[level];
486
487        case PIPE_TEXTURE_CUBE:
488            assert(zslice == 0);
489            return offset + face * desc->layer_size_in_bytes[level];
490
491        default:
492            assert(zslice == 0 && face == 0);
493            return offset;
494    }
495}
496