X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fsoftpipe%2Fsp_tile_cache.c;h=65872cecc4fdfd0fc4ada4af11de0e1b1453808b;hb=0ea575d721821262a862ceef010db9b1a8b4a6d9;hp=ab76009375c9d62156b80e0c75f6acf903fb9bbd;hpb=53116910b10e3b8a05f42970eff311c21808699f;p=mesa.git diff --git a/src/gallium/drivers/softpipe/sp_tile_cache.c b/src/gallium/drivers/softpipe/sp_tile_cache.c index ab76009375c..65872cecc4f 100644 --- a/src/gallium/drivers/softpipe/sp_tile_cache.c +++ b/src/gallium/drivers/softpipe/sp_tile_cache.c @@ -26,7 +26,7 @@ **************************************************************************/ /** - * Framebuffer/surface tile caching. + * Render target tile caching. * * Author: * Brian Paul @@ -35,37 +35,8 @@ #include "pipe/p_inlines.h" #include "util/u_memory.h" #include "util/u_tile.h" -#include "sp_context.h" -#include "sp_surface.h" -#include "sp_texture.h" #include "sp_tile_cache.h" -#define NUM_ENTRIES 32 - - -/** XXX move these */ -#define MAX_WIDTH 2048 -#define MAX_HEIGHT 2048 - - -struct softpipe_tile_cache -{ - struct pipe_screen *screen; - struct pipe_surface *surface; /**< the surface we're caching */ - void *surface_map; - struct pipe_texture *texture; /**< if caching a texture */ - struct softpipe_cached_tile entries[NUM_ENTRIES]; - uint clear_flags[(MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32]; - float clear_color[4]; - uint clear_val; - boolean depth_stencil; /** Is the surface a depth/stencil format? */ - - struct pipe_surface *tex_surf; - void *tex_surf_map; - int tex_face, tex_level, tex_z; - - struct softpipe_cached_tile tile; /**< scratch tile for clears */ -}; /** @@ -75,7 +46,7 @@ struct softpipe_tile_cache * a LRU replacement policy. */ #define CACHE_POS(x, y) \ - (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES) + (((x) + (y) * 5) % NUM_ENTRIES) @@ -83,12 +54,10 @@ struct softpipe_tile_cache * Is the tile at (x,y) in cleared state? */ static INLINE uint -is_clear_flag_set(const uint *bitvec, int x, int y) +is_clear_flag_set(const uint *bitvec, union tile_address addr) { int pos, bit; - x /= TILE_SIZE; - y /= TILE_SIZE; - pos = y * (MAX_WIDTH / TILE_SIZE) + x; + pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x; assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32); bit = bitvec[pos / 32] & (1 << (pos & 31)); return bit; @@ -99,12 +68,10 @@ is_clear_flag_set(const uint *bitvec, int x, int y) * Mark the tile at (x,y) as not cleared. */ static INLINE void -clear_clear_flag(uint *bitvec, int x, int y) +clear_clear_flag(uint *bitvec, union tile_address addr) { int pos; - x /= TILE_SIZE; - y /= TILE_SIZE; - pos = y * (MAX_WIDTH / TILE_SIZE) + x; + pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x; assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32); bitvec[pos / 32] &= ~(1 << (pos & 31)); } @@ -115,14 +82,30 @@ sp_create_tile_cache( struct pipe_screen *screen ) { struct softpipe_tile_cache *tc; uint pos; + int maxLevels, maxTexSize; + + /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */ + maxLevels = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); + maxTexSize = 1 << (maxLevels - 1); + assert(MAX_WIDTH >= maxTexSize); tc = CALLOC_STRUCT( softpipe_tile_cache ); if (tc) { tc->screen = screen; for (pos = 0; pos < NUM_ENTRIES; pos++) { - tc->entries[pos].x = - tc->entries[pos].y = -1; + tc->entries[pos].addr.bits.invalid = 1; } + tc->last_tile = &tc->entries[0]; /* any tile */ + + /* XXX this code prevents valgrind warnings about use of uninitialized + * memory in programs that don't clear the surface before rendering. + * However, it breaks clearing in other situations (such as in + * progs/tests/drawbuffers, see bug 24402). + */ +#if 0 && TILE_CLEAR_OPTIMIZATION + /* set flags to indicate all the tiles are cleared */ + memset(tc->clear_flags, 255, sizeof(tc->clear_flags)); +#endif } return tc; } @@ -131,16 +114,15 @@ sp_create_tile_cache( struct pipe_screen *screen ) void sp_destroy_tile_cache(struct softpipe_tile_cache *tc) { + struct pipe_screen *screen; uint pos; for (pos = 0; pos < NUM_ENTRIES; pos++) { /*assert(tc->entries[pos].x < 0);*/ } - if (tc->surface) { - pipe_surface_reference(&tc->surface, NULL); - } - if (tc->tex_surf) { - pipe_surface_reference(&tc->tex_surf, NULL); + if (tc->transfer) { + screen = tc->transfer->texture->screen; + screen->tex_transfer_destroy(tc->transfer); } FREE( tc ); @@ -154,20 +136,30 @@ void sp_tile_cache_set_surface(struct softpipe_tile_cache *tc, struct pipe_surface *ps) { - assert(!tc->texture); + if (tc->transfer) { + struct pipe_screen *screen = tc->transfer->texture->screen; - if (tc->surface_map) { - tc->screen->surface_unmap(tc->screen, tc->surface); - tc->surface_map = NULL; + if (ps == tc->surface) + return; + + if (tc->transfer_map) { + screen->transfer_unmap(screen, tc->transfer); + tc->transfer_map = NULL; + } + + screen->tex_transfer_destroy(tc->transfer); + tc->transfer = NULL; } - pipe_surface_reference(&tc->surface, ps); + tc->surface = ps; + + if (ps) { + struct pipe_screen *screen = ps->texture->screen; - if (tc->surface) { - if (tc->surface_map) /* XXX: this is always NULL!? */ - tc->surface_map = tc->screen->surface_map(tc->screen, tc->surface, - PIPE_BUFFER_USAGE_CPU_READ | - PIPE_BUFFER_USAGE_CPU_WRITE); + tc->transfer = screen->get_tex_transfer(screen, ps->texture, ps->face, + ps->level, ps->zslice, + PIPE_TRANSFER_READ_WRITE, + 0, 0, ps->width, ps->height); tc->depth_stencil = (ps->format == PIPE_FORMAT_S8Z24_UNORM || ps->format == PIPE_FORMAT_X8Z24_UNORM || @@ -181,7 +173,7 @@ sp_tile_cache_set_surface(struct softpipe_tile_cache *tc, /** - * Return the surface being cached. + * Return the transfer being cached. */ struct pipe_surface * sp_tile_cache_get_surface(struct softpipe_tile_cache *tc) @@ -191,64 +183,23 @@ sp_tile_cache_get_surface(struct softpipe_tile_cache *tc) void -sp_tile_cache_map_surfaces(struct softpipe_tile_cache *tc) +sp_tile_cache_map_transfers(struct softpipe_tile_cache *tc) { - if (tc->surface && !tc->surface_map) - tc->surface_map = tc->screen->surface_map(tc->screen, tc->surface, - PIPE_BUFFER_USAGE_CPU_WRITE | - PIPE_BUFFER_USAGE_CPU_READ); - - if (tc->tex_surf && !tc->tex_surf_map) - tc->tex_surf_map = tc->screen->surface_map(tc->screen, tc->tex_surf, - PIPE_BUFFER_USAGE_CPU_READ); + if (tc->transfer && !tc->transfer_map) + tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer); } void -sp_tile_cache_unmap_surfaces(struct softpipe_tile_cache *tc) +sp_tile_cache_unmap_transfers(struct softpipe_tile_cache *tc) { - if (tc->surface_map) { - tc->screen->surface_unmap(tc->screen, tc->surface); - tc->surface_map = NULL; - } - - if (tc->tex_surf_map) { - tc->screen->surface_unmap(tc->screen, tc->tex_surf); - tc->tex_surf_map = NULL; + if (tc->transfer_map) { + tc->screen->transfer_unmap(tc->screen, tc->transfer); + tc->transfer_map = NULL; } } -/** - * Specify the texture to cache. - */ -void -sp_tile_cache_set_texture(struct pipe_context *pipe, - struct softpipe_tile_cache *tc, - struct pipe_texture *texture) -{ - uint i; - - assert(!tc->surface); - - pipe_texture_reference(&tc->texture, texture); - - if (tc->tex_surf_map) { - tc->screen->surface_unmap(tc->screen, tc->tex_surf); - tc->tex_surf_map = NULL; - } - pipe_surface_reference(&tc->tex_surf, NULL); - - /* mark as entries as invalid/empty */ - /* XXX we should try to avoid this when the teximage hasn't changed */ - for (i = 0; i < NUM_ENTRIES; i++) { - tc->entries[i].x = -1; - } - - tc->tex_face = -1; /* any invalid value here */ -} - - /** * Set pixels in a tile to the given clear color/value, float. */ @@ -289,7 +240,7 @@ clear_tile(struct softpipe_cached_tile *tile, switch (pf_get_size(format)) { case 1: - memset(tile->data.any, 0, TILE_SIZE * TILE_SIZE); + memset(tile->data.any, clear_value, TILE_SIZE * TILE_SIZE); break; case 2: if (clear_value == 0) { @@ -325,28 +276,29 @@ clear_tile(struct softpipe_cached_tile *tile, * Actually clear the tiles which were flagged as being in a clear state. */ static void -sp_tile_cache_flush_clear(struct pipe_context *pipe, - struct softpipe_tile_cache *tc) +sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc) { - struct pipe_surface *ps = tc->surface; - const uint w = tc->surface->width; - const uint h = tc->surface->height; + struct pipe_transfer *pt = tc->transfer; + const uint w = tc->transfer->width; + const uint h = tc->transfer->height; uint x, y; uint numCleared = 0; /* clear the scratch tile to the clear value */ - clear_tile(&tc->tile, ps->format, tc->clear_val); + clear_tile(&tc->tile, pt->format, tc->clear_val); /* push the tile to all positions marked as clear */ for (y = 0; y < h; y += TILE_SIZE) { for (x = 0; x < w; x += TILE_SIZE) { - if (is_clear_flag_set(tc->clear_flags, x, y)) { - pipe_put_tile_raw(ps, + union tile_address addr = tile_address(x, y); + + if (is_clear_flag_set(tc->clear_flags, addr)) { + pipe_put_tile_raw(pt, x, y, TILE_SIZE, TILE_SIZE, tc->tile.data.color32, 0/*STRIDE*/); /* do this? */ - clear_clear_flag(tc->clear_flags, x, y); + clear_clear_flag(tc->clear_flags, addr); numCleared++; } @@ -359,47 +311,43 @@ sp_tile_cache_flush_clear(struct pipe_context *pipe, /** - * Flush the tile cache: write all dirty tiles back to the surface. + * Flush the tile cache: write all dirty tiles back to the transfer. * any tiles "flagged" as cleared will be "really" cleared. */ void -sp_flush_tile_cache(struct softpipe_context *softpipe, - struct softpipe_tile_cache *tc) +sp_flush_tile_cache(struct softpipe_tile_cache *tc) { - struct pipe_surface *ps = tc->surface; + struct pipe_transfer *pt = tc->transfer; int inuse = 0, pos; - if (ps) { - /* caching a drawing surface */ + if (pt) { + /* caching a drawing transfer */ for (pos = 0; pos < NUM_ENTRIES; pos++) { struct softpipe_cached_tile *tile = tc->entries + pos; - if (tile->x >= 0) { + if (!tile->addr.bits.invalid) { if (tc->depth_stencil) { - pipe_put_tile_raw(ps, - tile->x, tile->y, TILE_SIZE, TILE_SIZE, + pipe_put_tile_raw(pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, tile->data.depth32, 0/*STRIDE*/); } else { - pipe_put_tile_rgba(ps, - tile->x, tile->y, TILE_SIZE, TILE_SIZE, + pipe_put_tile_rgba(pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, (float *) tile->data.color); } - tile->x = tile->y = -1; /* mark as empty */ + tile->addr.bits.invalid = 1; /* mark as empty */ inuse++; } } #if TILE_CLEAR_OPTIMIZATION - sp_tile_cache_flush_clear(&softpipe->pipe, tc); + sp_tile_cache_flush_clear(tc); #endif } - else if (tc->texture) { - /* caching a texture, mark all entries as empty */ - for (pos = 0; pos < NUM_ENTRIES; pos++) { - tc->entries[pos].x = -1; - } - tc->tex_face = -1; - } #if 0 debug_printf("flushed tiles in use: %d\n", inuse); @@ -412,151 +360,74 @@ sp_flush_tile_cache(struct softpipe_context *softpipe, * \param x, y position of tile, in pixels */ struct softpipe_cached_tile * -sp_get_cached_tile(struct softpipe_context *softpipe, - struct softpipe_tile_cache *tc, int x, int y) +sp_find_cached_tile(struct softpipe_tile_cache *tc, + union tile_address addr ) { - struct pipe_surface *ps = tc->surface; - - /* tile pos in framebuffer: */ - const int tile_x = x & ~(TILE_SIZE - 1); - const int tile_y = y & ~(TILE_SIZE - 1); - + struct pipe_transfer *pt = tc->transfer; + /* cache pos/entry: */ - const int pos = CACHE_POS(x, y); + const int pos = CACHE_POS(addr.bits.x, + addr.bits.y); struct softpipe_cached_tile *tile = tc->entries + pos; - if (tile_x != tile->x || - tile_y != tile->y) { + if (addr.value != tile->addr.value) { - if (tile->x != -1) { + if (tile->addr.bits.invalid == 0) { /* put dirty tile back in framebuffer */ if (tc->depth_stencil) { - pipe_put_tile_raw(ps, - tile->x, tile->y, TILE_SIZE, TILE_SIZE, + pipe_put_tile_raw(pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, tile->data.depth32, 0/*STRIDE*/); } else { - pipe_put_tile_rgba(ps, - tile->x, tile->y, TILE_SIZE, TILE_SIZE, + pipe_put_tile_rgba(pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, (float *) tile->data.color); } } - tile->x = tile_x; - tile->y = tile_y; + tile->addr = addr; - if (is_clear_flag_set(tc->clear_flags, x, y)) { + if (is_clear_flag_set(tc->clear_flags, addr)) { /* don't get tile from framebuffer, just clear it */ if (tc->depth_stencil) { - clear_tile(tile, ps->format, tc->clear_val); + clear_tile(tile, pt->format, tc->clear_val); } else { - clear_tile_rgba(tile, ps->format, tc->clear_color); + clear_tile_rgba(tile, pt->format, tc->clear_color); } - clear_clear_flag(tc->clear_flags, x, y); + clear_clear_flag(tc->clear_flags, addr); } else { - /* get new tile data from surface */ + /* get new tile data from transfer */ if (tc->depth_stencil) { - pipe_get_tile_raw(ps, - tile->x, tile->y, TILE_SIZE, TILE_SIZE, + pipe_get_tile_raw(pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, tile->data.depth32, 0/*STRIDE*/); } else { - pipe_get_tile_rgba(ps, - tile->x, tile->y, TILE_SIZE, TILE_SIZE, + pipe_get_tile_rgba(pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, (float *) tile->data.color); } } } + tc->last_tile = tile; return tile; } -/** - * Given the texture face, level, zslice, x and y values, compute - * the cache entry position/index where we'd hope to find the - * cached texture tile. - * This is basically a direct-map cache. - * XXX There's probably lots of ways in which we can improve this. - */ -static INLINE uint -tex_cache_pos(int x, int y, int z, int face, int level) -{ - uint entry = x + y * 5 + z * 4 + face + level; - return entry % NUM_ENTRIES; -} -/** - * Similar to sp_get_cached_tile() but for textures. - * Tiles are read-only and indexed with more params. - */ -const struct softpipe_cached_tile * -sp_get_cached_tile_tex(struct softpipe_context *sp, - struct softpipe_tile_cache *tc, int x, int y, int z, - int face, int level) -{ - struct pipe_screen *screen = sp->pipe.screen; - /* tile pos in framebuffer: */ - const int tile_x = x & ~(TILE_SIZE - 1); - const int tile_y = y & ~(TILE_SIZE - 1); - /* cache pos/entry: */ - const uint pos = tex_cache_pos(x / TILE_SIZE, y / TILE_SIZE, z, - face, level); - struct softpipe_cached_tile *tile = tc->entries + pos; - - if (tc->texture) { - struct softpipe_texture *spt = softpipe_texture(tc->texture); - if (spt->modified) { - /* texture was modified, force a cache reload */ - tile->x = -1; - spt->modified = FALSE; - } - } - - if (tile_x != tile->x || - tile_y != tile->y || - z != tile->z || - face != tile->face || - level != tile->level) { - /* cache miss */ - - /* check if we need to get a new surface */ - if (!tc->tex_surf || - tc->tex_face != face || - tc->tex_level != level || - tc->tex_z != z) { - /* get new surface (view into texture) */ - - if (tc->tex_surf_map) - tc->screen->surface_unmap(tc->screen, tc->tex_surf); - - tc->tex_surf = screen->get_tex_surface(screen, tc->texture, face, level, z, - PIPE_BUFFER_USAGE_CPU_READ); - tc->tex_surf_map = screen->surface_map(screen, tc->tex_surf, - PIPE_BUFFER_USAGE_CPU_READ); - - tc->tex_face = face; - tc->tex_level = level; - tc->tex_z = z; - } - - /* get tile from the surface (view into texture) */ - pipe_get_tile_rgba(tc->tex_surf, - tile_x, tile_y, TILE_SIZE, TILE_SIZE, - (float *) tile->data.color); - tile->x = tile_x; - tile->y = tile_y; - tile->z = z; - tile->face = face; - tile->level = level; - } - - return tile; -} - /** * When a whole surface is being cleared to a value we can avoid @@ -564,40 +435,17 @@ sp_get_cached_tile_tex(struct softpipe_context *sp, * Save the color and set a 'clearflag' for each tile of the screen. */ void -sp_tile_cache_clear(struct softpipe_tile_cache *tc, uint clearValue) +sp_tile_cache_clear(struct softpipe_tile_cache *tc, const float *rgba, + uint clearValue) { - uint r, g, b, a; uint pos; - tc->clear_val = clearValue; - - switch (tc->surface->format) { - case PIPE_FORMAT_R8G8B8A8_UNORM: - r = (clearValue >> 24) & 0xff; - g = (clearValue >> 16) & 0xff; - b = (clearValue >> 8) & 0xff; - a = (clearValue ) & 0xff; - break; - case PIPE_FORMAT_A8R8G8B8_UNORM: - r = (clearValue >> 16) & 0xff; - g = (clearValue >> 8) & 0xff; - b = (clearValue ) & 0xff; - a = (clearValue >> 24) & 0xff; - break; - case PIPE_FORMAT_B8G8R8A8_UNORM: - r = (clearValue >> 8) & 0xff; - g = (clearValue >> 16) & 0xff; - b = (clearValue >> 24) & 0xff; - a = (clearValue ) & 0xff; - break; - default: - r = g = b = a = 0; - } + tc->clear_color[0] = rgba[0]; + tc->clear_color[1] = rgba[1]; + tc->clear_color[2] = rgba[2]; + tc->clear_color[3] = rgba[3]; - tc->clear_color[0] = r / 255.0f; - tc->clear_color[1] = g / 255.0f; - tc->clear_color[2] = b / 255.0f; - tc->clear_color[3] = a / 255.0f; + tc->clear_val = clearValue; #if TILE_CLEAR_OPTIMIZATION /* set flags to indicate all the tiles are cleared */ @@ -609,6 +457,6 @@ sp_tile_cache_clear(struct softpipe_tile_cache *tc, uint clearValue) for (pos = 0; pos < NUM_ENTRIES; pos++) { struct softpipe_cached_tile *tile = tc->entries + pos; - tile->x = tile->y = -1; + tile->addr.bits.invalid = 1; } }