sp_tile_cache.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  * 
00003  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  * 
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * 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, sub license, 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 portions
00016  * of the Software.
00017  * 
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  * 
00026  **************************************************************************/
00027 
00035 #include "pipe/p_inlines.h"
00036 #include "util/u_memory.h"
00037 #include "util/u_tile.h"
00038 #include "sp_context.h"
00039 #include "sp_surface.h"
00040 #include "sp_texture.h"
00041 #include "sp_tile_cache.h"
00042 
00043 #define NUM_ENTRIES 50
00044 
00045 
00047 #define MAX_WIDTH 2048
00048 #define MAX_HEIGHT 2048
00049 
00050 
00051 struct softpipe_tile_cache
00052 {
00053    struct pipe_screen *screen;
00054    struct pipe_surface *surface;  
00055    void *surface_map;
00056    struct pipe_texture *texture;  
00057    struct softpipe_cached_tile entries[NUM_ENTRIES];
00058    uint clear_flags[(MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32];
00059    float clear_color[4];
00060    uint clear_val;
00061    boolean depth_stencil; 
00063    struct pipe_surface *tex_surf;
00064    void *tex_surf_map;
00065    int tex_face, tex_level, tex_z;
00066 
00067    struct softpipe_cached_tile tile;  
00068 };
00069 
00070 
00077 #define CACHE_POS(x, y) \
00078    (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
00079 
00080 
00081 
00085 static INLINE uint
00086 is_clear_flag_set(const uint *bitvec, int x, int y)
00087 {
00088    int pos, bit;
00089    x /= TILE_SIZE;
00090    y /= TILE_SIZE;
00091    pos = y * (MAX_WIDTH / TILE_SIZE) + x;
00092    assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
00093    bit = bitvec[pos / 32] & (1 << (pos & 31));
00094    return bit;
00095 }
00096    
00097 
00101 static INLINE void
00102 clear_clear_flag(uint *bitvec, int x, int y)
00103 {
00104    int pos;
00105    x /= TILE_SIZE;
00106    y /= TILE_SIZE;
00107    pos = y * (MAX_WIDTH / TILE_SIZE) + x;
00108    assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
00109    bitvec[pos / 32] &= ~(1 << (pos & 31));
00110 }
00111    
00112 
00113 struct softpipe_tile_cache *
00114 sp_create_tile_cache( struct pipe_screen *screen )
00115 {
00116    struct softpipe_tile_cache *tc;
00117    uint pos;
00118 
00119    tc = CALLOC_STRUCT( softpipe_tile_cache );
00120    if (tc) {
00121       tc->screen = screen;
00122       for (pos = 0; pos < NUM_ENTRIES; pos++) {
00123          tc->entries[pos].x =
00124          tc->entries[pos].y = -1;
00125       }
00126    }
00127    return tc;
00128 }
00129 
00130 
00131 void
00132 sp_destroy_tile_cache(struct softpipe_tile_cache *tc)
00133 {
00134    uint pos;
00135 
00136    for (pos = 0; pos < NUM_ENTRIES; pos++) {
00137       /*assert(tc->entries[pos].x < 0);*/
00138    }
00139    if (tc->surface) {
00140       pipe_surface_reference(&tc->surface, NULL);
00141    }
00142    if (tc->tex_surf) {
00143       pipe_surface_reference(&tc->tex_surf, NULL);
00144    }
00145 
00146    FREE( tc );
00147 }
00148 
00149 
00153 void
00154 sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
00155                           struct pipe_surface *ps)
00156 {
00157    assert(!tc->texture);
00158 
00159    if (tc->surface_map) {
00160       tc->screen->surface_unmap(tc->screen, tc->surface);
00161       tc->surface_map = NULL;
00162    }
00163 
00164    pipe_surface_reference(&tc->surface, ps);
00165 
00166    if (tc->surface) {
00167       if (tc->surface_map) /* XXX: this is always NULL!? */
00168          tc->surface_map = tc->screen->surface_map(tc->screen, tc->surface,
00169                                                    PIPE_BUFFER_USAGE_CPU_READ | 
00170                                                    PIPE_BUFFER_USAGE_CPU_WRITE);
00171 
00172       tc->depth_stencil = (ps->format == PIPE_FORMAT_S8Z24_UNORM ||
00173                            ps->format == PIPE_FORMAT_X8Z24_UNORM ||
00174                            ps->format == PIPE_FORMAT_Z24S8_UNORM ||
00175                            ps->format == PIPE_FORMAT_Z24X8_UNORM ||
00176                            ps->format == PIPE_FORMAT_Z16_UNORM ||
00177                            ps->format == PIPE_FORMAT_Z32_UNORM ||
00178                            ps->format == PIPE_FORMAT_S8_UNORM);
00179    }
00180 }
00181 
00182 
00186 struct pipe_surface *
00187 sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
00188 {
00189    return tc->surface;
00190 }
00191 
00192 
00193 void
00194 sp_tile_cache_map_surfaces(struct softpipe_tile_cache *tc)
00195 {
00196    if (tc->surface && !tc->surface_map)
00197       tc->surface_map = tc->screen->surface_map(tc->screen, tc->surface,
00198                                                 PIPE_BUFFER_USAGE_CPU_WRITE |
00199                                                 PIPE_BUFFER_USAGE_CPU_READ);
00200 
00201    if (tc->tex_surf && !tc->tex_surf_map)
00202       tc->tex_surf_map = tc->screen->surface_map(tc->screen, tc->tex_surf,
00203                                                  PIPE_BUFFER_USAGE_CPU_READ);
00204 }
00205 
00206 
00207 void
00208 sp_tile_cache_unmap_surfaces(struct softpipe_tile_cache *tc)
00209 {
00210    if (tc->surface_map) {
00211       tc->screen->surface_unmap(tc->screen, tc->surface);
00212       tc->surface_map = NULL;
00213    }
00214 
00215    if (tc->tex_surf_map) {
00216       tc->screen->surface_unmap(tc->screen, tc->tex_surf);
00217       tc->tex_surf_map = NULL;
00218    }
00219 }
00220 
00221 
00225 void
00226 sp_tile_cache_set_texture(struct pipe_context *pipe,
00227                           struct softpipe_tile_cache *tc,
00228                           struct pipe_texture *texture)
00229 {
00230    uint i;
00231 
00232    assert(!tc->surface);
00233 
00234    pipe_texture_reference(&tc->texture, texture);
00235 
00236    if (tc->tex_surf_map) {
00237       tc->screen->surface_unmap(tc->screen, tc->tex_surf);
00238       tc->tex_surf_map = NULL;
00239    }
00240    pipe_surface_reference(&tc->tex_surf, NULL);
00241 
00242    /* mark as entries as invalid/empty */
00243    /* XXX we should try to avoid this when the teximage hasn't changed */
00244    for (i = 0; i < NUM_ENTRIES; i++) {
00245       tc->entries[i].x = -1;
00246    }
00247 
00248    tc->tex_face = -1; /* any invalid value here */
00249 }
00250 
00251 
00255 static void
00256 clear_tile_rgba(struct softpipe_cached_tile *tile,
00257                 enum pipe_format format,
00258                 const float clear_value[4])
00259 {
00260    if (clear_value[0] == 0.0 &&
00261        clear_value[1] == 0.0 &&
00262        clear_value[2] == 0.0 &&
00263        clear_value[3] == 0.0) {
00264       memset(tile->data.color, 0, sizeof(tile->data.color));
00265    }
00266    else {
00267       uint i, j;
00268       for (i = 0; i < TILE_SIZE; i++) {
00269          for (j = 0; j < TILE_SIZE; j++) {
00270             tile->data.color[i][j][0] = clear_value[0];
00271             tile->data.color[i][j][1] = clear_value[1];
00272             tile->data.color[i][j][2] = clear_value[2];
00273             tile->data.color[i][j][3] = clear_value[3];
00274          }
00275       }
00276    }
00277 }
00278 
00279 
00283 static void
00284 clear_tile(struct softpipe_cached_tile *tile,
00285            enum pipe_format format,
00286            uint clear_value)
00287 {
00288    uint i, j;
00289 
00290    switch (pf_get_size(format)) {
00291    case 1:
00292       memset(tile->data.any, 0, TILE_SIZE * TILE_SIZE);
00293       break;
00294    case 2:
00295       if (clear_value == 0) {
00296          memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE);
00297       }
00298       else {
00299          for (i = 0; i < TILE_SIZE; i++) {
00300             for (j = 0; j < TILE_SIZE; j++) {
00301                tile->data.depth16[i][j] = (ushort) clear_value;
00302             }
00303          }
00304       }
00305       break;
00306    case 4:
00307       if (clear_value == 0) {
00308          memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE);
00309       }
00310       else {
00311          for (i = 0; i < TILE_SIZE; i++) {
00312             for (j = 0; j < TILE_SIZE; j++) {
00313                tile->data.color32[i][j] = clear_value;
00314             }
00315          }
00316       }
00317       break;
00318    default:
00319       assert(0);
00320    }
00321 }
00322 
00323 
00327 static void
00328 sp_tile_cache_flush_clear(struct pipe_context *pipe,
00329                           struct softpipe_tile_cache *tc)
00330 {
00331    struct pipe_surface *ps = tc->surface;
00332    const uint w = tc->surface->width;
00333    const uint h = tc->surface->height;
00334    uint x, y;
00335    uint numCleared = 0;
00336 
00337    /* clear the scratch tile to the clear value */
00338    clear_tile(&tc->tile, ps->format, tc->clear_val);
00339 
00340    /* push the tile to all positions marked as clear */
00341    for (y = 0; y < h; y += TILE_SIZE) {
00342       for (x = 0; x < w; x += TILE_SIZE) {
00343          if (is_clear_flag_set(tc->clear_flags, x, y)) {
00344             pipe_put_tile_raw(ps,
00345                               x, y, TILE_SIZE, TILE_SIZE,
00346                               tc->tile.data.color32, 0/*STRIDE*/);
00347 
00348             /* do this? */
00349             clear_clear_flag(tc->clear_flags, x, y);
00350 
00351             numCleared++;
00352          }
00353       }
00354    }
00355 #if 0
00356    debug_printf("num cleared: %u\n", numCleared);
00357 #endif
00358 }
00359 
00360 
00365 void
00366 sp_flush_tile_cache(struct softpipe_context *softpipe,
00367                     struct softpipe_tile_cache *tc)
00368 {
00369    struct pipe_surface *ps = tc->surface;
00370    int inuse = 0, pos;
00371 
00372    if (ps && ps->buffer) {
00373       /* caching a drawing surface */
00374       for (pos = 0; pos < NUM_ENTRIES; pos++) {
00375          struct softpipe_cached_tile *tile = tc->entries + pos;
00376          if (tile->x >= 0) {
00377             if (tc->depth_stencil) {
00378                pipe_put_tile_raw(ps,
00379                                  tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00380                                  tile->data.depth32, 0/*STRIDE*/);
00381             }
00382             else {
00383                pipe_put_tile_rgba(ps,
00384                                   tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00385                                   (float *) tile->data.color);
00386             }
00387             tile->x = tile->y = -1;  /* mark as empty */
00388             inuse++;
00389          }
00390       }
00391 
00392 #if TILE_CLEAR_OPTIMIZATION
00393       sp_tile_cache_flush_clear(&softpipe->pipe, tc);
00394 #endif
00395    }
00396    else if (tc->texture) {
00397       /* caching a texture, mark all entries as empty */
00398       for (pos = 0; pos < NUM_ENTRIES; pos++) {
00399          tc->entries[pos].x = -1;
00400       }
00401       tc->tex_face = -1;
00402    }
00403 
00404 #if 0
00405    debug_printf("flushed tiles in use: %d\n", inuse);
00406 #endif
00407 }
00408 
00409 
00414 struct softpipe_cached_tile *
00415 sp_get_cached_tile(struct softpipe_context *softpipe,
00416                    struct softpipe_tile_cache *tc, int x, int y)
00417 {
00418    struct pipe_surface *ps = tc->surface;
00419 
00420    /* tile pos in framebuffer: */
00421    const int tile_x = x & ~(TILE_SIZE - 1);
00422    const int tile_y = y & ~(TILE_SIZE - 1);
00423 
00424    /* cache pos/entry: */
00425    const int pos = CACHE_POS(x, y);
00426    struct softpipe_cached_tile *tile = tc->entries + pos;
00427 
00428    if (tile_x != tile->x ||
00429        tile_y != tile->y) {
00430 
00431       if (tile->x != -1) {
00432          /* put dirty tile back in framebuffer */
00433          if (tc->depth_stencil) {
00434             pipe_put_tile_raw(ps,
00435                               tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00436                               tile->data.depth32, 0/*STRIDE*/);
00437          }
00438          else {
00439             pipe_put_tile_rgba(ps,
00440                                tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00441                                (float *) tile->data.color);
00442          }
00443       }
00444 
00445       tile->x = tile_x;
00446       tile->y = tile_y;
00447 
00448       if (is_clear_flag_set(tc->clear_flags, x, y)) {
00449          /* don't get tile from framebuffer, just clear it */
00450          if (tc->depth_stencil) {
00451             clear_tile(tile, ps->format, tc->clear_val);
00452          }
00453          else {
00454             clear_tile_rgba(tile, ps->format, tc->clear_color);
00455          }
00456          clear_clear_flag(tc->clear_flags, x, y);
00457       }
00458       else {
00459          /* get new tile data from surface */
00460          if (tc->depth_stencil) {
00461             pipe_get_tile_raw(ps,
00462                               tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00463                               tile->data.depth32, 0/*STRIDE*/);
00464          }
00465          else {
00466             pipe_get_tile_rgba(ps,
00467                                tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00468                                (float *) tile->data.color);
00469          }
00470       }
00471    }
00472 
00473    return tile;
00474 }
00475 
00476 
00484 static INLINE uint
00485 tex_cache_pos(int x, int y, int z, int face, int level)
00486 {
00487    uint entry = x + y * 9 + z * 3 + face + level * 7;
00488    return entry % NUM_ENTRIES;
00489 }
00490 
00491 
00496 const struct softpipe_cached_tile *
00497 sp_get_cached_tile_tex(struct pipe_context *pipe,
00498                        struct softpipe_tile_cache *tc, int x, int y, int z,
00499                        int face, int level)
00500 {
00501    struct pipe_screen *screen = pipe->screen;
00502    /* tile pos in framebuffer: */
00503    const int tile_x = x & ~(TILE_SIZE - 1);
00504    const int tile_y = y & ~(TILE_SIZE - 1);
00505    /* cache pos/entry: */
00506    const uint pos = tex_cache_pos(x / TILE_SIZE, y / TILE_SIZE, z,
00507                                   face, level);
00508    struct softpipe_cached_tile *tile = tc->entries + pos;
00509 
00510    if (tc->texture) {
00511       struct softpipe_texture *spt = softpipe_texture(tc->texture);
00512       if (spt->modified) {
00513          /* texture was modified, invalidate all cached tiles */
00514          uint p;
00515          for (p = 0; p < NUM_ENTRIES; p++) {
00516             tile = tc->entries + p;
00517             tile->x = -1;
00518          }
00519          spt->modified = FALSE;
00520       }
00521    }
00522 
00523    if (tile_x != tile->x ||
00524        tile_y != tile->y ||
00525        z != tile->z ||
00526        face != tile->face ||
00527        level != tile->level) {
00528       /* cache miss */
00529 
00530 #if 0
00531       printf("miss at %u  x=%d y=%d z=%d face=%d level=%d\n", pos,
00532              x/TILE_SIZE, y/TILE_SIZE, z, face, level);
00533 #endif
00534       /* check if we need to get a new surface */
00535       if (!tc->tex_surf ||
00536           tc->tex_face != face ||
00537           tc->tex_level != level ||
00538           tc->tex_z != z) {
00539          /* get new surface (view into texture) */
00540 
00541          if (tc->tex_surf_map)
00542             tc->screen->surface_unmap(tc->screen, tc->tex_surf);
00543 
00544          tc->tex_surf = screen->get_tex_surface(screen, tc->texture, face, level, z, 
00545                                                 PIPE_BUFFER_USAGE_CPU_READ);
00546          tc->tex_surf_map = screen->surface_map(screen, tc->tex_surf,
00547                                                 PIPE_BUFFER_USAGE_CPU_READ);
00548 
00549          tc->tex_face = face;
00550          tc->tex_level = level;
00551          tc->tex_z = z;
00552       }
00553 
00554       /* get tile from the surface (view into texture) */
00555       pipe_get_tile_rgba(tc->tex_surf,
00556                          tile_x, tile_y, TILE_SIZE, TILE_SIZE,
00557                          (float *) tile->data.color);
00558       tile->x = tile_x;
00559       tile->y = tile_y;
00560       tile->z = z;
00561       tile->face = face;
00562       tile->level = level;
00563    }
00564 
00565    return tile;
00566 }
00567 
00568 
00574 void
00575 sp_tile_cache_clear(struct softpipe_tile_cache *tc, uint clearValue)
00576 {
00577    uint r, g, b, a;
00578    uint pos;
00579 
00580    tc->clear_val = clearValue;
00581 
00582    switch (tc->surface->format) {
00583    case PIPE_FORMAT_R8G8B8A8_UNORM:
00584    case PIPE_FORMAT_R8G8B8X8_UNORM:
00585       r = (clearValue >> 24) & 0xff;
00586       g = (clearValue >> 16) & 0xff;
00587       b = (clearValue >>  8) & 0xff;
00588       a = (clearValue      ) & 0xff;
00589       break;
00590    case PIPE_FORMAT_A8R8G8B8_UNORM:
00591    case PIPE_FORMAT_X8R8G8B8_UNORM:
00592       r = (clearValue >> 16) & 0xff;
00593       g = (clearValue >>  8) & 0xff;
00594       b = (clearValue      ) & 0xff;
00595       a = (clearValue >> 24) & 0xff;
00596       break;
00597    case PIPE_FORMAT_B8G8R8A8_UNORM:
00598    case PIPE_FORMAT_B8G8R8X8_UNORM:
00599       r = (clearValue >>  8) & 0xff;
00600       g = (clearValue >> 16) & 0xff;
00601       b = (clearValue >> 24) & 0xff;
00602       a = (clearValue      ) & 0xff;
00603       break;
00604    default:
00605       r = g = b = a = 0;
00606    }
00607 
00608    tc->clear_color[0] = r / 255.0f;
00609    tc->clear_color[1] = g / 255.0f;
00610    tc->clear_color[2] = b / 255.0f;
00611    tc->clear_color[3] = a / 255.0f;
00612 
00613 #if TILE_CLEAR_OPTIMIZATION
00614    /* set flags to indicate all the tiles are cleared */
00615    memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
00616 #else
00617    /* disable the optimization */
00618    memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
00619 #endif
00620 
00621    for (pos = 0; pos < NUM_ENTRIES; pos++) {
00622       struct softpipe_cached_tile *tile = tc->entries + pos;
00623       tile->x = tile->y = -1;
00624    }
00625 }

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