brw_tex_layout.c

Go to the documentation of this file.
00001 /*
00002  Copyright (C) Intel Corp.  2006.  All Rights Reserved.
00003  Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
00004  develop this 3D driver.
00005 
00006  Permission is hereby granted, free of charge, to any person obtaining
00007  a copy of this software and associated documentation files (the
00008  "Software"), to deal in the Software without restriction, including
00009  without limitation the rights to use, copy, modify, merge, publish,
00010  distribute, sublicense, and/or sell copies of the Software, and to
00011  permit persons to whom the Software is furnished to do so, subject to
00012  the following conditions:
00013 
00014  The above copyright notice and this permission notice (including the
00015  next paragraph) shall be included in all copies or substantial
00016  portions of the Software.
00017 
00018  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00019  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00021  IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
00022  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00023  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00024  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025 
00026  **********************************************************************/
00027  /*
00028   * Authors:
00029   *   Keith Whitwell <keith@tungstengraphics.com>
00030   */
00031 
00032 
00033 /* Code to layout images in a mipmap tree for i965.
00034  */
00035 
00036 #include "pipe/p_state.h"
00037 #include "pipe/p_context.h"
00038 #include "pipe/p_defines.h"
00039 #include "pipe/p_inlines.h"
00040 #include "pipe/p_winsys.h"
00041 #include "util/u_math.h"
00042 #include "util/u_memory.h"
00043 #include "brw_context.h"
00044 #include "brw_tex_layout.h"
00045 
00046 
00047 #define FILE_DEBUG_FLAG DEBUG_TEXTURE
00048 
00049 #if 0
00050 unsigned intel_compressed_alignment(unsigned internalFormat)
00051 {
00052     unsigned alignment = 4;
00053 
00054     switch (internalFormat) {
00055     case GL_COMPRESSED_RGB_FXT1_3DFX:
00056     case GL_COMPRESSED_RGBA_FXT1_3DFX:
00057         alignment = 8;
00058         break;
00059 
00060     default:
00061         break;
00062     }
00063 
00064     return alignment;
00065 }
00066 #endif
00067 
00068 static unsigned minify( unsigned d )
00069 {
00070    return MAX2(1, d>>1);
00071 }
00072 
00073 
00074 static void intel_miptree_set_image_offset(struct brw_texture *tex,
00075                                            unsigned level,
00076                                            unsigned img,
00077                                            unsigned x, unsigned y)
00078 {
00079    struct pipe_texture *pt = &tex->base;
00080    if (img == 0 && level == 0)
00081       assert(x == 0 && y == 0);
00082    assert(img < tex->nr_images[level]);
00083 
00084    tex->image_offset[level][img] = y * tex->stride + x * pt->block.size;
00085 }
00086 
00087 static void intel_miptree_set_level_info(struct brw_texture *tex,
00088                                          unsigned level,
00089                                          unsigned nr_images,
00090                                          unsigned x, unsigned y,
00091                                          unsigned w, unsigned h, unsigned d)
00092 {
00093    struct pipe_texture *pt = &tex->base;
00094 
00095    assert(level < PIPE_MAX_TEXTURE_LEVELS);
00096 
00097    pt->width[level] = w;
00098    pt->height[level] = h;
00099    pt->depth[level] = d;
00100    
00101    pt->nblocksx[level] = pf_get_nblocksx(&pt->block, w);
00102    pt->nblocksy[level] = pf_get_nblocksy(&pt->block, h);
00103 
00104    tex->level_offset[level] = y * tex->stride + x * tex->base.block.size;
00105    tex->nr_images[level] = nr_images;
00106 
00107    /*
00108    DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
00109        level, w, h, d, x, y, tex->level_offset[level]);
00110    */
00111 
00112    /* Not sure when this would happen, but anyway: 
00113     */
00114    if (tex->image_offset[level]) {
00115       FREE(tex->image_offset[level]);
00116       tex->image_offset[level] = NULL;
00117    }
00118 
00119    assert(nr_images);
00120    assert(!tex->image_offset[level]);
00121 
00122    tex->image_offset[level] = (unsigned *) MALLOC(nr_images * sizeof(unsigned));
00123    tex->image_offset[level][0] = 0;
00124 }
00125 
00126 static void i945_miptree_layout_2d(struct brw_texture *tex)
00127 {
00128    struct pipe_texture *pt = &tex->base;
00129    const int align_x = 2, align_y = 4;
00130    unsigned level;
00131    unsigned x = 0;
00132    unsigned y = 0;
00133    unsigned width = pt->width[0];
00134    unsigned height = pt->height[0];
00135    unsigned nblocksx = pt->nblocksx[0];
00136    unsigned nblocksy = pt->nblocksy[0];
00137 
00138    tex->stride = align(pt->nblocksx[0] * pt->block.size, 4);
00139 
00140    /* May need to adjust pitch to accomodate the placement of
00141     * the 2nd mipmap level.  This occurs when the alignment
00142     * constraints of mipmap placement push the right edge of the
00143     * 2nd mipmap level out past the width of its parent.
00144     */
00145    if (pt->last_level > 0) {
00146       unsigned mip1_nblocksx 
00147          = align(pf_get_nblocksx(&pt->block, minify(width)), align_x)
00148          + pf_get_nblocksx(&pt->block, minify(minify(width)));
00149 
00150       if (mip1_nblocksx > nblocksx)
00151          tex->stride = mip1_nblocksx * pt->block.size;
00152    }
00153 
00154    /* Pitch must be a whole number of dwords
00155     */
00156    tex->stride = align(tex->stride, 64);
00157    tex->total_nblocksy = 0;
00158 
00159    for (level = 0; level <= pt->last_level; level++) {
00160       intel_miptree_set_level_info(tex, level, 1, x, y, width,
00161                                    height, 1);
00162 
00163       nblocksy = align(nblocksy, align_y);
00164 
00165       /* Because the images are packed better, the final offset
00166        * might not be the maximal one:
00167        */
00168       tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
00169 
00170       /* Layout_below: step right after second mipmap level.
00171        */
00172       if (level == 1) {
00173          x += align(nblocksx, align_x);
00174       }
00175       else {
00176          y += nblocksy;
00177       }
00178 
00179       width  = minify(width);
00180       height = minify(height);
00181       nblocksx = pf_get_nblocksx(&pt->block, width);
00182       nblocksy = pf_get_nblocksy(&pt->block, height);
00183    }
00184 }
00185 
00186 static boolean brw_miptree_layout(struct brw_texture *tex)
00187 {
00188    struct pipe_texture *pt = &tex->base;
00189    /* XXX: these vary depending on image format:
00190     */
00191 /*    int align_w = 4; */
00192 
00193    switch (pt->target) {
00194    case PIPE_TEXTURE_CUBE:
00195    case PIPE_TEXTURE_3D: {
00196       unsigned width  = pt->width[0];
00197       unsigned height = pt->height[0];
00198       unsigned depth = pt->depth[0];
00199       unsigned nblocksx = pt->nblocksx[0];
00200       unsigned nblocksy = pt->nblocksy[0];
00201       unsigned pack_x_pitch, pack_x_nr;
00202       unsigned pack_y_pitch;
00203       unsigned level;
00204       unsigned align_h = 2;
00205       unsigned align_w = 4;
00206 
00207       tex->total_nblocksy = 0;
00208 
00209       tex->stride = align(pt->nblocksx[0], 4);
00210       pack_y_pitch = align(pt->nblocksy[0], align_h);
00211 
00212       pack_x_pitch = tex->stride / pt->block.size;
00213       pack_x_nr = 1;
00214 
00215       for (level = 0; level <= pt->last_level; level++) {
00216          unsigned nr_images = pt->target == PIPE_TEXTURE_3D ? depth : 6;
00217          int x = 0;
00218          int y = 0;
00219          uint q, j;
00220 
00221          intel_miptree_set_level_info(tex, level, nr_images,
00222                                       0, tex->total_nblocksy,
00223                                       width, height, depth);
00224 
00225          for (q = 0; q < nr_images;) {
00226             for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) {
00227                intel_miptree_set_image_offset(tex, level, q, x, y);
00228                x += pack_x_pitch;
00229             }
00230 
00231             x = 0;
00232             y += pack_y_pitch;
00233          }
00234 
00235 
00236          tex->total_nblocksy += y;
00237          width  = minify(width);
00238          height = minify(height);
00239          depth  = minify(depth);
00240          nblocksx = pf_get_nblocksx(&pt->block, width);
00241          nblocksy = pf_get_nblocksy(&pt->block, height);
00242 
00243          if (pt->compressed) {
00244             pack_y_pitch = (height + 3) / 4;
00245 
00246             if (pack_x_pitch > align(width, align_w)) {
00247                pack_x_pitch = align(width, align_w);
00248                pack_x_nr <<= 1;
00249             }
00250          } else {
00251             if (pack_x_pitch > 4) {
00252                pack_x_pitch >>= 1;
00253                pack_x_nr <<= 1;
00254                assert(pack_x_pitch * pack_x_nr * pt->block.size <= tex->stride);
00255             }
00256 
00257             if (pack_y_pitch > 2) {
00258                pack_y_pitch >>= 1;
00259                pack_y_pitch = align(pack_y_pitch, align_h);
00260             }
00261          }
00262 
00263       }
00264       break;
00265    }
00266 
00267    default:
00268       i945_miptree_layout_2d(tex);
00269       break;
00270    }
00271 #if 0
00272    PRINT("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
00273        pt->pitch,
00274        pt->total_nblocksy,
00275        pt->block.size,
00276        pt->stride * pt->total_nblocksy );
00277 #endif
00278 
00279    return TRUE;
00280 }
00281 
00282 
00283 static struct pipe_texture *
00284 brw_texture_create_screen(struct pipe_screen *screen,
00285                           const struct pipe_texture *templat)
00286 {
00287    struct pipe_winsys *ws = screen->winsys;
00288    struct brw_texture *tex = CALLOC_STRUCT(brw_texture);
00289 
00290    if (tex) {
00291       tex->base = *templat;
00292       tex->base.refcount = 1;
00293 
00294       tex->base.nblocksx[0] = pf_get_nblocksx(&tex->base.block, tex->base.width[0]);
00295       tex->base.nblocksy[0] = pf_get_nblocksy(&tex->base.block, tex->base.height[0]);
00296    
00297       if (brw_miptree_layout(tex))
00298          tex->buffer = ws->buffer_create(ws, 64,
00299                                          PIPE_BUFFER_USAGE_PIXEL,
00300                                          tex->stride *
00301                                          tex->total_nblocksy);
00302 
00303       if (!tex->buffer) {
00304          FREE(tex);
00305          return NULL;
00306       }
00307    }
00308 
00309    return &tex->base;
00310 }
00311 
00312 
00313 static void
00314 brw_texture_release_screen(struct pipe_screen *screen,
00315                            struct pipe_texture **pt)
00316 {
00317    if (!*pt)
00318       return;
00319 
00320    /*
00321    DBG("%s %p refcount will be %d\n",
00322        __FUNCTION__, (void *) *pt, (*pt)->refcount - 1);
00323    */
00324    if (--(*pt)->refcount <= 0) {
00325       struct pipe_winsys *ws = screen->winsys;
00326       struct brw_texture *tex = (struct brw_texture *)*pt;
00327       uint i;
00328 
00329       /*
00330       DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
00331       */
00332 
00333       winsys_buffer_reference(ws, &tex->buffer, NULL);
00334 
00335       for (i = 0; i < PIPE_MAX_TEXTURE_LEVELS; i++)
00336          if (tex->image_offset[i])
00337             free(tex->image_offset[i]);
00338 
00339       free(tex);
00340    }
00341    *pt = NULL;
00342 }
00343 
00344 
00345 static struct pipe_surface *
00346 brw_get_tex_surface_screen(struct pipe_screen *screen,
00347                            struct pipe_texture *pt,
00348                            unsigned face, unsigned level, unsigned zslice)
00349 {
00350    struct pipe_winsys *ws = screen->winsys;
00351    struct brw_texture *tex = (struct brw_texture *)pt;
00352    struct pipe_surface *ps;
00353    unsigned offset;  /* in bytes */
00354 
00355    offset = tex->level_offset[level];
00356 
00357    if (pt->target == PIPE_TEXTURE_CUBE) {
00358       offset += tex->image_offset[level][face];
00359    }
00360    else if (pt->target == PIPE_TEXTURE_3D) {
00361       offset += tex->image_offset[level][zslice];
00362    }
00363    else {
00364       assert(face == 0);
00365       assert(zslice == 0);
00366    }
00367 
00368    ps = ws->surface_alloc(ws);
00369    if (ps) {
00370       assert(ps->format);
00371       assert(ps->refcount);
00372       winsys_buffer_reference(ws, &ps->buffer, tex->buffer);
00373       ps->format = pt->format;
00374       ps->width = pt->width[level];
00375       ps->height = pt->height[level];
00376       ps->block = pt->block;
00377       ps->nblocksx = pt->nblocksx[level];
00378       ps->nblocksy = pt->nblocksy[level];
00379       ps->stride = tex->stride;
00380       ps->offset = offset;
00381    }
00382    return ps;
00383 }
00384 
00385 
00386 void
00387 brw_init_texture_functions(struct brw_context *brw)
00388 {
00389 //   brw->pipe.texture_update = brw_texture_update;
00390 }
00391 
00392 
00393 void
00394 brw_init_screen_texture_funcs(struct pipe_screen *screen)
00395 {
00396    screen->texture_create  = brw_texture_create_screen;
00397    screen->texture_release = brw_texture_release_screen;
00398    screen->get_tex_surface = brw_get_tex_surface_screen;
00399 }
00400 

Generated on Tue Sep 29 06:25:17 2009 for Gallium3D by  doxygen 1.5.4