Home | History | Annotate | Download | only in i915
      1 /**************************************************************************
      2  *
      3  * Copyright 2006 VMware, Inc.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 /** @file i915_tex_layout.c
     29  * Code to layout images in a mipmap tree for i830M-GM915 and G945 and beyond.
     30  */
     31 
     32 #include "intel_mipmap_tree.h"
     33 #include "intel_tex_layout.h"
     34 #include "main/macros.h"
     35 #include "intel_context.h"
     36 
     37 #define FILE_DEBUG_FLAG DEBUG_TEXTURE
     38 
     39 static GLint initial_offsets[6][2] = {
     40    [FACE_POS_X] = {0, 0},
     41    [FACE_POS_Y] = {1, 0},
     42    [FACE_POS_Z] = {1, 1},
     43    [FACE_NEG_X] = {0, 2},
     44    [FACE_NEG_Y] = {1, 2},
     45    [FACE_NEG_Z] = {1, 3},
     46 };
     47 
     48 
     49 static GLint step_offsets[6][2] = {
     50    [FACE_POS_X] = {0, 2},
     51    [FACE_POS_Y] = {-1, 2},
     52    [FACE_POS_Z] = {-1, 1},
     53    [FACE_NEG_X] = {0, 2},
     54    [FACE_NEG_Y] = {-1, 2},
     55    [FACE_NEG_Z] = {-1, 1},
     56 };
     57 
     58 
     59 static GLint bottom_offsets[6] = {
     60    [FACE_POS_X] = 16 + 0 * 8,
     61    [FACE_POS_Y] = 16 + 1 * 8,
     62    [FACE_POS_Z] = 16 + 2 * 8,
     63    [FACE_NEG_X] = 16 + 3 * 8,
     64    [FACE_NEG_Y] = 16 + 4 * 8,
     65    [FACE_NEG_Z] = 16 + 5 * 8,
     66 };
     67 
     68 
     69 /**
     70  * Cube texture map layout for i830M-GM915 and
     71  * non-compressed cube texture map on GM945.
     72  *
     73  * Hardware layout looks like:
     74  *
     75  * +-------+-------+
     76  * |       |       |
     77  * |       |       |
     78  * |       |       |
     79  * |  +x   |  +y   |
     80  * |       |       |
     81  * |       |       |
     82  * |       |       |
     83  * |       |       |
     84  * +---+---+-------+
     85  * |   |   |       |
     86  * | +x| +y|       |
     87  * |   |   |       |
     88  * |   |   |       |
     89  * +-+-+---+  +z   |
     90  * | | |   |       |
     91  * +-+-+ +z|       |
     92  *   | |   |       |
     93  * +-+-+---+-------+
     94  * |       |       |
     95  * |       |       |
     96  * |       |       |
     97  * |  -x   |  -y   |
     98  * |       |       |
     99  * |       |       |
    100  * |       |       |
    101  * |       |       |
    102  * +---+---+-------+
    103  * |   |   |       |
    104  * | -x| -y|       |
    105  * |   |   |       |
    106  * |   |   |       |
    107  * +-+-+---+  -z   |
    108  * | | |   |       |
    109  * +-+-+ -z|       |
    110  *   | |   |       |
    111  *   +-+---+-------+
    112  *
    113  */
    114 static void
    115 i915_miptree_layout_cube(struct intel_mipmap_tree * mt)
    116 {
    117    const GLuint dim = mt->physical_width0;
    118    GLuint face;
    119    GLuint lvlWidth = mt->physical_width0, lvlHeight = mt->physical_height0;
    120    GLint level;
    121 
    122    assert(lvlWidth == lvlHeight); /* cubemap images are square */
    123 
    124    /* double pitch for cube layouts */
    125    mt->total_width = dim * 2;
    126    mt->total_height = dim * 4;
    127 
    128    for (level = mt->first_level; level <= mt->last_level; level++) {
    129       intel_miptree_set_level_info(mt, level,
    130 				   0, 0,
    131 				   lvlWidth, lvlHeight,
    132 				   6);
    133       lvlWidth /= 2;
    134       lvlHeight /= 2;
    135    }
    136 
    137    for (face = 0; face < 6; face++) {
    138       GLuint x = initial_offsets[face][0] * dim;
    139       GLuint y = initial_offsets[face][1] * dim;
    140       GLuint d = dim;
    141 
    142       for (level = mt->first_level; level <= mt->last_level; level++) {
    143 	 intel_miptree_set_image_offset(mt, level, face, x, y);
    144 
    145 	 if (d == 0)
    146 	    printf("cube mipmap %d/%d (%d..%d) is 0x0\n",
    147 		   face, level, mt->first_level, mt->last_level);
    148 
    149 	 d >>= 1;
    150 	 x += step_offsets[face][0] * d;
    151 	 y += step_offsets[face][1] * d;
    152       }
    153    }
    154 }
    155 
    156 static void
    157 i915_miptree_layout_3d(struct intel_mipmap_tree * mt)
    158 {
    159    GLuint width = mt->physical_width0;
    160    GLuint height = mt->physical_height0;
    161    GLuint depth = mt->physical_depth0;
    162    GLuint stack_height = 0;
    163    GLint level;
    164 
    165    /* Calculate the size of a single slice. */
    166    mt->total_width = mt->physical_width0;
    167 
    168    /* XXX: hardware expects/requires 9 levels at minimum. */
    169    for (level = mt->first_level; level <= MAX2(8, mt->last_level); level++) {
    170       intel_miptree_set_level_info(mt, level, 0, mt->total_height,
    171 				   width, height, depth);
    172 
    173       stack_height += MAX2(2, height);
    174 
    175       width = minify(width, 1);
    176       height = minify(height, 1);
    177       depth = minify(depth, 1);
    178    }
    179 
    180    /* Fixup depth image_offsets: */
    181    depth = mt->physical_depth0;
    182    for (level = mt->first_level; level <= mt->last_level; level++) {
    183       GLuint i;
    184       for (i = 0; i < depth; i++) {
    185 	 intel_miptree_set_image_offset(mt, level, i,
    186 					0, i * stack_height);
    187       }
    188 
    189       depth = minify(depth, 1);
    190    }
    191 
    192    /* Multiply slice size by texture depth for total size.  It's
    193     * remarkable how wasteful of memory the i915 texture layouts
    194     * are.  They are largely fixed in the i945.
    195     */
    196    mt->total_height = stack_height * mt->physical_depth0;
    197 }
    198 
    199 static void
    200 i915_miptree_layout_2d(struct intel_mipmap_tree * mt)
    201 {
    202    GLuint width = mt->physical_width0;
    203    GLuint height = mt->physical_height0;
    204    GLuint img_height;
    205    GLint level;
    206 
    207    mt->total_width = mt->physical_width0;
    208    mt->total_height = 0;
    209 
    210    for (level = mt->first_level; level <= mt->last_level; level++) {
    211       intel_miptree_set_level_info(mt, level,
    212 				   0, mt->total_height,
    213 				   width, height, 1);
    214 
    215       if (mt->compressed)
    216 	 img_height = ALIGN(height, 4) / 4;
    217       else
    218 	 img_height = ALIGN(height, 2);
    219 
    220       mt->total_height += img_height;
    221 
    222       width = minify(width, 1);
    223       height = minify(height, 1);
    224    }
    225 }
    226 
    227 void
    228 i915_miptree_layout(struct intel_mipmap_tree * mt)
    229 {
    230    switch (mt->target) {
    231    case GL_TEXTURE_CUBE_MAP:
    232       i915_miptree_layout_cube(mt);
    233       break;
    234    case GL_TEXTURE_3D:
    235       i915_miptree_layout_3d(mt);
    236       break;
    237    case GL_TEXTURE_1D:
    238    case GL_TEXTURE_2D:
    239    case GL_TEXTURE_RECTANGLE_ARB:
    240       i915_miptree_layout_2d(mt);
    241       break;
    242    default:
    243       _mesa_problem(NULL, "Unexpected tex target in i915_miptree_layout()");
    244       break;
    245    }
    246 
    247    DBG("%s: %dx%dx%d\n", __func__,
    248        mt->total_width, mt->total_height, mt->cpp);
    249 }
    250 
    251 
    252 /**
    253  * Compressed cube texture map layout for GM945 and later.
    254  *
    255  * The hardware layout looks like the 830-915 layout, except for the small
    256  * sizes.  A zoomed in view of the layout for 945 is:
    257  *
    258  * +-------+-------+
    259  * |  8x8  |  8x8  |
    260  * |       |       |
    261  * |       |       |
    262  * |  +x   |  +y   |
    263  * |       |       |
    264  * |       |       |
    265  * |       |       |
    266  * |       |       |
    267  * +---+---+-------+
    268  * |4x4|   |  8x8  |
    269  * | +x|   |       |
    270  * |   |   |       |
    271  * |   |   |       |
    272  * +---+   |  +z   |
    273  * |4x4|   |       |
    274  * | +y|   |       |
    275  * |   |   |       |
    276  * +---+   +-------+
    277  *
    278  * ...
    279  *
    280  * +-------+-------+
    281  * |  8x8  |  8x8  |
    282  * |       |       |
    283  * |       |       |
    284  * |  -x   |  -y   |
    285  * |       |       |
    286  * |       |       |
    287  * |       |       |
    288  * |       |       |
    289  * +---+---+-------+
    290  * |4x4|   |  8x8  |
    291  * | -x|   |       |
    292  * |   |   |       |
    293  * |   |   |       |
    294  * +---+   |  -z   |
    295  * |4x4|   |       |
    296  * | -y|   |       |
    297  * |   |   |       |
    298  * +---+   +---+---+---+---+---+---+---+---+---+
    299  * |4x4|   |4x4|   |2x2|   |2x2|   |2x2|   |2x2|
    300  * | +z|   | -z|   | +x|   | +y|   | +z|   | -x| ...
    301  * |   |   |   |   |   |   |   |   |   |   |   |
    302  * +---+   +---+   +---+   +---+   +---+   +---+
    303  *
    304  * The bottom row continues with the remaining 2x2 then the 1x1 mip contents
    305  * in order, with each of them aligned to a 8x8 block boundary.  Thus, for
    306  * 32x32 cube maps and smaller, the bottom row layout is going to dictate the
    307  * pitch of the tree.  For a tree with 4x4 images, the pitch is at least
    308  * 14 * 8 = 112 texels, for 2x2 it is at least 12 * 8 texels, and for 1x1
    309  * it is 6 * 8 texels.
    310  */
    311 
    312 static void
    313 i945_miptree_layout_cube(struct intel_mipmap_tree * mt)
    314 {
    315    const GLuint dim = mt->physical_width0;
    316    GLuint face;
    317    GLuint lvlWidth = mt->physical_width0, lvlHeight = mt->physical_height0;
    318    GLint level;
    319 
    320    assert(lvlWidth == lvlHeight); /* cubemap images are square */
    321 
    322    /* Depending on the size of the largest images, pitch can be
    323     * determined either by the old-style packing of cubemap faces,
    324     * or the final row of 4x4, 2x2 and 1x1 faces below this.
    325     */
    326    if (dim > 32)
    327       mt->total_width = dim * 2;
    328    else
    329       mt->total_width = 14 * 8;
    330 
    331    if (dim >= 4)
    332       mt->total_height = dim * 4 + 4;
    333    else
    334       mt->total_height = 4;
    335 
    336    /* Set all the levels to effectively occupy the whole rectangular region. */
    337    for (level = mt->first_level; level <= mt->last_level; level++) {
    338       intel_miptree_set_level_info(mt, level,
    339 				   0, 0,
    340 				   lvlWidth, lvlHeight, 6);
    341       lvlWidth /= 2;
    342       lvlHeight /= 2;
    343    }
    344 
    345    for (face = 0; face < 6; face++) {
    346       GLuint x = initial_offsets[face][0] * dim;
    347       GLuint y = initial_offsets[face][1] * dim;
    348       GLuint d = dim;
    349 
    350       if (dim == 4 && face >= 4) {
    351 	 y = mt->total_height - 4;
    352 	 x = (face - 4) * 8;
    353       } else if (dim < 4 && (face > 0 || mt->first_level > 0)) {
    354 	 y = mt->total_height - 4;
    355 	 x = face * 8;
    356       }
    357 
    358       for (level = mt->first_level; level <= mt->last_level; level++) {
    359 	 intel_miptree_set_image_offset(mt, level, face, x, y);
    360 
    361 	 d >>= 1;
    362 
    363 	 switch (d) {
    364 	 case 4:
    365 	    switch (face) {
    366 	    case FACE_POS_X:
    367 	    case FACE_NEG_X:
    368 	       x += step_offsets[face][0] * d;
    369 	       y += step_offsets[face][1] * d;
    370 	       break;
    371 	    case FACE_POS_Y:
    372 	    case FACE_NEG_Y:
    373 	       y += 12;
    374 	       x -= 8;
    375 	       break;
    376 	    case FACE_POS_Z:
    377 	    case FACE_NEG_Z:
    378 	       y = mt->total_height - 4;
    379 	       x = (face - 4) * 8;
    380 	       break;
    381 	    }
    382 	    break;
    383 
    384 	 case 2:
    385 	    y = mt->total_height - 4;
    386 	    x = bottom_offsets[face];
    387 	    break;
    388 
    389 	 case 1:
    390 	    x += 48;
    391 	    break;
    392 
    393 	 default:
    394 	    x += step_offsets[face][0] * d;
    395 	    y += step_offsets[face][1] * d;
    396 	    break;
    397 	 }
    398       }
    399    }
    400 }
    401 
    402 static void
    403 i945_miptree_layout_3d(struct intel_mipmap_tree * mt)
    404 {
    405    GLuint width = mt->physical_width0;
    406    GLuint height = mt->physical_height0;
    407    GLuint depth = mt->physical_depth0;
    408    GLuint pack_x_pitch, pack_x_nr;
    409    GLuint pack_y_pitch;
    410    GLuint level;
    411 
    412    mt->total_width = mt->physical_width0;
    413    mt->total_height = 0;
    414 
    415    pack_y_pitch = MAX2(mt->physical_height0, 2);
    416    pack_x_pitch = mt->total_width;
    417    pack_x_nr = 1;
    418 
    419    for (level = mt->first_level; level <= mt->last_level; level++) {
    420       GLint x = 0;
    421       GLint y = 0;
    422       GLint q, j;
    423 
    424       intel_miptree_set_level_info(mt, level,
    425 				   0, mt->total_height,
    426 				   width, height, depth);
    427 
    428       for (q = 0; q < depth;) {
    429 	 for (j = 0; j < pack_x_nr && q < depth; j++, q++) {
    430 	    intel_miptree_set_image_offset(mt, level, q, x, y);
    431 	    x += pack_x_pitch;
    432 	 }
    433 
    434 	 x = 0;
    435 	 y += pack_y_pitch;
    436       }
    437 
    438       mt->total_height += y;
    439 
    440       if (pack_x_pitch > 4) {
    441 	 pack_x_pitch >>= 1;
    442 	 pack_x_nr <<= 1;
    443 	 assert(pack_x_pitch * pack_x_nr <= mt->total_width);
    444       }
    445 
    446       if (pack_y_pitch > 2) {
    447 	 pack_y_pitch >>= 1;
    448       }
    449 
    450       width = minify(width, 1);
    451       height = minify(height, 1);
    452       depth = minify(depth, 1);
    453    }
    454 }
    455 
    456 void
    457 i945_miptree_layout(struct intel_mipmap_tree * mt)
    458 {
    459    switch (mt->target) {
    460    case GL_TEXTURE_CUBE_MAP:
    461       if (mt->compressed)
    462 	 i945_miptree_layout_cube(mt);
    463       else
    464 	 i915_miptree_layout_cube(mt);
    465       break;
    466    case GL_TEXTURE_3D:
    467       i945_miptree_layout_3d(mt);
    468       break;
    469    case GL_TEXTURE_1D:
    470    case GL_TEXTURE_2D:
    471    case GL_TEXTURE_RECTANGLE_ARB:
    472       i945_miptree_layout_2d(mt);
    473       break;
    474    default:
    475       _mesa_problem(NULL, "Unexpected tex target in i945_miptree_layout()");
    476       break;
    477    }
    478 
    479    DBG("%s: %dx%dx%d\n", __func__,
    480        mt->total_width, mt->total_height, mt->cpp);
    481 }
    482