From f1ce37f74aff4854071fe5740b055718b2c0c789 Mon Sep 17 00:00:00 2001 From: Keith Whitwell Date: Tue, 24 Nov 2009 21:13:18 +0000 Subject: [PATCH] svga: cache textures as well as buffers --- src/gallium/drivers/svga/svga_screen_buffer.c | 12 +- src/gallium/drivers/svga/svga_screen_cache.c | 93 +++++++----- src/gallium/drivers/svga/svga_screen_cache.h | 21 ++- .../drivers/svga/svga_screen_texture.c | 142 ++++++++++-------- .../drivers/svga/svga_screen_texture.h | 16 +- 5 files changed, 167 insertions(+), 117 deletions(-) diff --git a/src/gallium/drivers/svga/svga_screen_buffer.c b/src/gallium/drivers/svga/svga_screen_buffer.c index 3b7811734ed..101c7878bfe 100644 --- a/src/gallium/drivers/svga/svga_screen_buffer.c +++ b/src/gallium/drivers/svga/svga_screen_buffer.c @@ -71,7 +71,10 @@ svga_buffer_create_host_surface(struct svga_screen *ss, sbuf->key.numFaces = 1; sbuf->key.numMipLevels = 1; + sbuf->key.cachable = 1; + SVGA_DBG(DEBUG_DMA, "surface_create for buffer sz %d\n", sbuf->base.size); + sbuf->handle = svga_screen_surface_create(ss, &sbuf->key); if(!sbuf->handle) return PIPE_ERROR_OUT_OF_MEMORY; @@ -82,7 +85,7 @@ svga_buffer_create_host_surface(struct svga_screen *ss, */ sbuf->hw.flags.discard = TRUE; - SVGA_DBG(DEBUG_DMA, " grab sid %p sz %d\n", sbuf->handle, sbuf->base.size); + SVGA_DBG(DEBUG_DMA, " --> got sid %p sz %d (buffer)\n", sbuf->handle, sbuf->base.size); } return PIPE_OK; @@ -776,12 +779,11 @@ svga_screen_buffer_wrap_surface(struct pipe_screen *screen, /* * We are not the creator of this surface and therefore we must not - * cache it for reuse. The caching code only caches SVGA3D_BUFFER surfaces - * so make sure this isn't one of those. + * cache it for reuse. Set the cacheable flag to zero in the key to + * prevent this. */ - - assert(format != SVGA3D_BUFFER); sbuf->key.format = format; + sbuf->key.cachable = 0; sws->surface_reference(sws, &sbuf->handle, srf); return buf; diff --git a/src/gallium/drivers/svga/svga_screen_cache.c b/src/gallium/drivers/svga/svga_screen_cache.c index 7360c1688bb..65f5c07a72d 100644 --- a/src/gallium/drivers/svga/svga_screen_cache.c +++ b/src/gallium/drivers/svga/svga_screen_cache.c @@ -24,6 +24,7 @@ **********************************************************/ #include "util/u_memory.h" +#include "util/u_hash.h" #include "svga_debug.h" #include "svga_winsys.h" @@ -36,24 +37,11 @@ /** * Compute the bucket for this key. - * - * We simply compute log2(width) for now, but */ static INLINE unsigned svga_screen_cache_bucket(const struct svga_host_surface_cache_key *key) { - unsigned bucket = 0; - unsigned size = key->size.width; - - while ((size >>= 1)) - ++bucket; - - if(key->flags & SVGA3D_SURFACE_HINT_INDEXBUFFER) - bucket += 32; - - assert(bucket < SVGA_HOST_SURFACE_CACHE_BUCKETS); - - return bucket; + return util_hash_crc32( key, sizeof key ) % SVGA_HOST_SURFACE_CACHE_BUCKETS; } @@ -69,6 +57,8 @@ svga_screen_cache_lookup(struct svga_screen *svgascreen, unsigned bucket; unsigned tries = 0; + assert(key->cachable); + bucket = svga_screen_cache_bucket(key); pipe_mutex_lock(cache->mutex); @@ -104,11 +94,9 @@ svga_screen_cache_lookup(struct svga_screen *svgascreen, pipe_mutex_unlock(cache->mutex); -#if 0 - _debug_printf("%s: cache %s after %u tries\n", __FUNCTION__, handle ? "hit" : "miss", tries); -#else - (void)tries; -#endif + if (SVGA_DEBUG & DEBUG_DMA) + debug_printf("%s: cache %s after %u tries\n", __FUNCTION__, + handle ? "hit" : "miss", tries); return handle; } @@ -128,6 +116,7 @@ svga_screen_cache_add(struct svga_screen *svgascreen, struct svga_host_surface_cache_entry *entry = NULL; struct svga_winsys_surface *handle = *p_handle; + assert(key->cachable); assert(handle); if(!handle) @@ -137,15 +126,15 @@ svga_screen_cache_add(struct svga_screen *svgascreen, pipe_mutex_lock(cache->mutex); if(!LIST_IS_EMPTY(&cache->empty)) { - /* use the first empty entry */ - entry = LIST_ENTRY(struct svga_host_surface_cache_entry, cache->empty.next, head); + /* use the first empty entry */ + entry = LIST_ENTRY(struct svga_host_surface_cache_entry, cache->empty.next, head); - LIST_DEL(&entry->head); - } + LIST_DEL(&entry->head); + } else if(!LIST_IS_EMPTY(&cache->unused)) { /* free the last used buffer and reuse its entry */ entry = LIST_ENTRY(struct svga_host_surface_cache_entry, cache->unused.prev, head); - SVGA_DBG(DEBUG_DMA, "unref sid %p\n", entry->handle); + SVGA_DBG(DEBUG_DMA, "unref sid %p (make space)\n", entry->handle); sws->surface_reference(sws, &entry->handle, NULL); LIST_DEL(&entry->bucket_head); @@ -161,7 +150,7 @@ svga_screen_cache_add(struct svga_screen *svgascreen, } else { /* Couldn't cache the buffer -- this really shouldn't happen */ - SVGA_DBG(DEBUG_DMA, "unref sid %p\n", handle); + SVGA_DBG(DEBUG_DMA, "unref sid %p (couldn't find space)\n", handle); sws->surface_reference(sws, &handle, NULL); } @@ -220,7 +209,7 @@ svga_screen_cache_cleanup(struct svga_screen *svgascreen) for(i = 0; i < SVGA_HOST_SURFACE_CACHE_SIZE; ++i) { if(cache->entries[i].handle) { - SVGA_DBG(DEBUG_DMA, "unref sid %p\n", cache->entries[i].handle); + SVGA_DBG(DEBUG_DMA, "unref sid %p (shutdown)\n", cache->entries[i].handle); sws->surface_reference(sws, &cache->entries[i].handle, NULL); } @@ -261,18 +250,42 @@ svga_screen_surface_create(struct svga_screen *svgascreen, { struct svga_winsys_screen *sws = svgascreen->sws; struct svga_winsys_surface *handle = NULL; + boolean cachable = SVGA_SURFACE_CACHE_ENABLED && key->cachable; + + SVGA_DBG(DEBUG_DMA, "%s sz %dx%dx%d mips %d faces %d cachable %d\n", + __FUNCTION__, + key->size.width, + key->size.height, + key->size.depth, + key->numMipLevels, + key->numFaces, + key->cachable); + + if (cachable) { + if (key->format == SVGA3D_BUFFER) { + /* For buffers, round the buffer size up to the nearest power + * of two to increase the probability of cache hits. Keep + * texture surface dimensions unchanged. + */ + uint32_t size = 1; + while(size < key->size.width) + size <<= 1; + key->size.width = size; + } - if (SVGA_SURFACE_CACHE_ENABLED && key->format == SVGA3D_BUFFER) { - /* round the buffer size up to the nearest power of two to increase the - * probability of cache hits */ - uint32_t size = 1; - while(size < key->size.width) - size <<= 1; - key->size.width = size; - handle = svga_screen_cache_lookup(svgascreen, key); - if (handle) - SVGA_DBG(DEBUG_DMA, " reuse sid %p sz %d\n", handle, size); + if (handle) { + if (key->format == SVGA3D_BUFFER) + SVGA_DBG(DEBUG_DMA, " reuse sid %p sz %d (buffer)\n", handle, + key->size.width); + else + SVGA_DBG(DEBUG_DMA, " reuse sid %p sz %dx%dx%d mips %d faces %d\n", handle, + key->size.width, + key->size.height, + key->size.depth, + key->numMipLevels, + key->numFaces); + } } if (!handle) { @@ -297,11 +310,15 @@ svga_screen_surface_destroy(struct svga_screen *svgascreen, { struct svga_winsys_screen *sws = svgascreen->sws; - if(SVGA_SURFACE_CACHE_ENABLED && key->format == SVGA3D_BUFFER) { + /* We only set the cachable flag for surfaces of which we are the + * exclusive owner. So just hold onto our existing reference in + * that case. + */ + if(SVGA_SURFACE_CACHE_ENABLED && key->cachable) { svga_screen_cache_add(svgascreen, key, p_handle); } else { - SVGA_DBG(DEBUG_DMA, "unref sid %p\n", *p_handle); + SVGA_DBG(DEBUG_DMA, "unref sid %p (uncachable)\n", *p_handle); sws->surface_reference(sws, p_handle, NULL); } } diff --git a/src/gallium/drivers/svga/svga_screen_cache.h b/src/gallium/drivers/svga/svga_screen_cache.h index 1bbe9877688..b7457698484 100644 --- a/src/gallium/drivers/svga/svga_screen_cache.h +++ b/src/gallium/drivers/svga/svga_screen_cache.h @@ -36,10 +36,18 @@ #include "util/u_double_list.h" -/* TODO: Reduce this once we don't allocate an index buffer per draw call */ +/* Guess the storage size of cached surfaces and try and keep it under + * this amount: + */ +#define SVGA_HOST_SURFACE_CACHE_BYTES 16*1024*1024 + +/* Maximum number of discrete surfaces in the cache: + */ #define SVGA_HOST_SURFACE_CACHE_SIZE 1024 -#define SVGA_HOST_SURFACE_CACHE_BUCKETS 64 +/* Number of hash buckets: + */ +#define SVGA_HOST_SURFACE_CACHE_BUCKETS 256 struct svga_winsys_surface; @@ -50,11 +58,12 @@ struct svga_screen; */ struct svga_host_surface_cache_key { - SVGA3dSurfaceFlags flags; - SVGA3dSurfaceFormat format; SVGA3dSize size; - uint32_t numFaces; - uint32_t numMipLevels; + uint32_t flags:8; + uint32_t format:8; + uint32_t numFaces:8; + uint32_t numMipLevels:7; + uint32_t cachable:1; /* False if this is a shared surface */ }; diff --git a/src/gallium/drivers/svga/svga_screen_texture.c b/src/gallium/drivers/svga/svga_screen_texture.c index 8472dea04da..158a1e108dc 100644 --- a/src/gallium/drivers/svga/svga_screen_texture.c +++ b/src/gallium/drivers/svga/svga_screen_texture.c @@ -266,14 +266,8 @@ svga_texture_create(struct pipe_screen *screen, const struct pipe_texture *templat) { struct svga_screen *svgascreen = svga_screen(screen); - struct svga_winsys_screen *sws = svgascreen->sws; struct svga_texture *tex = CALLOC_STRUCT(svga_texture); unsigned width, height, depth; - SVGA3dSurfaceFlags flags = 0; - SVGA3dSurfaceFormat format; - SVGA3dSize size; - uint32 numFaces; - uint32 numMipLevels; unsigned level; if (!tex) @@ -301,23 +295,24 @@ svga_texture_create(struct pipe_screen *screen, depth = minify(depth); } - size.width = templat->width[0]; - size.height = templat->height[0]; - size.depth = templat->depth[0]; + tex->key.flags = 0; + tex->key.size.width = templat->width[0]; + tex->key.size.height = templat->height[0]; + tex->key.size.depth = templat->depth[0]; if(templat->target == PIPE_TEXTURE_CUBE) { - flags |= SVGA3D_SURFACE_CUBEMAP; - numFaces = 6; + tex->key.flags |= SVGA3D_SURFACE_CUBEMAP; + tex->key.numFaces = 6; } else { - numFaces = 1; + tex->key.numFaces = 1; } if(templat->tex_usage & PIPE_TEXTURE_USAGE_SAMPLER) - flags |= SVGA3D_SURFACE_HINT_TEXTURE; + tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE; if(templat->tex_usage & PIPE_TEXTURE_USAGE_PRIMARY) - flags |= SVGA3D_SURFACE_HINT_SCANOUT; + tex->key.flags |= SVGA3D_SURFACE_HINT_SCANOUT; /* * XXX: Never pass the SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot @@ -328,21 +323,24 @@ svga_texture_create(struct pipe_screen *screen, #if 0 if((templat->tex_usage & PIPE_TEXTURE_USAGE_RENDER_TARGET) && !pf_is_compressed(templat->format)) - flags |= SVGA3D_SURFACE_HINT_RENDERTARGET; + tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET; #endif if(templat->tex_usage & PIPE_TEXTURE_USAGE_DEPTH_STENCIL) - flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL; + tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL; - numMipLevels = templat->last_level + 1; + tex->key.numMipLevels = templat->last_level + 1; - format = svga_translate_format(templat->format); - if(format == SVGA3D_FORMAT_INVALID) + tex->key.format = svga_translate_format(templat->format); + if(tex->key.format == SVGA3D_FORMAT_INVALID) goto error2; + + tex->key.cachable = 1; - tex->handle = sws->surface_create(sws, flags, format, size, numFaces, numMipLevels); + SVGA_DBG(DEBUG_DMA, "surface_create for texture\n", tex->handle); + tex->handle = svga_screen_surface_create(svgascreen, &tex->key); if (tex->handle) - SVGA_DBG(DEBUG_DMA, "create sid %p (texture)\n", tex->handle); + SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture)\n", tex->handle); return &tex->base; @@ -398,6 +396,10 @@ svga_texture_blanket(struct pipe_screen * screen, return NULL; tex->base = *base; + + /* We don't own this storage, so don't try to cache it. + */ + tex->key.cachable = 0; if (sbuf->key.format == 1) tex->base.format = PIPE_FORMAT_X8R8G8B8_UNORM; @@ -407,6 +409,7 @@ svga_texture_blanket(struct pipe_screen * screen, pipe_reference_init(&tex->base.reference, 1); tex->base.screen = screen; + SVGA_DBG(DEBUG_DMA, "blanket sid %p\n", sbuf->handle); sws->surface_reference(sws, &tex->handle, sbuf->handle); return &tex->base; @@ -427,7 +430,7 @@ svga_texture_destroy(struct pipe_texture *pt) DBG("%s deleting %p\n", __FUNCTION__, (void *) tex); */ SVGA_DBG(DEBUG_DMA, "unref sid %p (texture)\n", tex->handle); - ss->sws->surface_reference(ss->sws, &tex->handle, NULL); + svga_screen_surface_destroy(ss, &tex->key, &tex->handle); FREE(tex); } @@ -518,43 +521,43 @@ svga_texture_view_surface(struct pipe_context *pipe, unsigned start_mip, unsigned num_mip, int face_pick, - int zslice_pick) + int zslice_pick, + struct svga_host_surface_cache_key *key) /* OUT */ { struct svga_screen *ss = svga_screen(tex->base.screen); - struct svga_winsys_screen *sws = ss->sws; struct svga_winsys_surface *handle; int i, j; - SVGA3dSurfaceFlags flags = 0; - SVGA3dSize size; - uint32 numFaces; - uint32 numMipLevels = num_mip; unsigned z_offset = 0; SVGA_DBG(DEBUG_PERF, "svga: Create surface view: face %d zslice %d mips %d..%d\n", face_pick, zslice_pick, start_mip, start_mip+num_mip-1); - size.width = tex->base.width[start_mip]; - size.height = tex->base.height[start_mip]; - size.depth = zslice_pick < 0 ? tex->base.depth[start_mip] : 1; - assert(size.depth == 1); + key->flags = 0; + key->format = format; + key->numMipLevels = num_mip; + key->size.width = tex->base.width[start_mip]; + key->size.height = tex->base.height[start_mip]; + key->size.depth = zslice_pick < 0 ? tex->base.depth[start_mip] : 1; + key->cachable = 1; + assert(key->size.depth == 1); if(tex->base.target == PIPE_TEXTURE_CUBE && face_pick < 0) { - flags |= SVGA3D_SURFACE_CUBEMAP; - numFaces = 6; + key->flags |= SVGA3D_SURFACE_CUBEMAP; + key->numFaces = 6; } else { - numFaces = 1; + key->numFaces = 1; } - if(format == SVGA3D_FORMAT_INVALID) + if(key->format == SVGA3D_FORMAT_INVALID) return NULL; - handle = sws->surface_create(sws, flags, format, size, numFaces, numMipLevels); - + SVGA_DBG(DEBUG_DMA, "surface_create for texture view\n", handle); + handle = svga_screen_surface_create(ss, key); if (!handle) return NULL; - SVGA_DBG(DEBUG_DMA, "create sid %p (texture view)\n", handle); + SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture view)\n", handle); if (face_pick < 0) face_pick = 0; @@ -562,14 +565,20 @@ svga_texture_view_surface(struct pipe_context *pipe, if (zslice_pick >= 0) z_offset = zslice_pick; - for (i = 0; i < num_mip; i++) { - for (j = 0; j < numFaces; j++) { + for (i = 0; i < key->numMipLevels; i++) { + for (j = 0; j < key->numFaces; j++) { if(tex->defined[j + face_pick][i + start_mip]) { unsigned depth = zslice_pick < 0 ? tex->base.depth[i + start_mip] : 1; - svga_texture_copy_handle(svga_context(pipe), ss, - tex->handle, 0, 0, z_offset, i + start_mip, j + face_pick, + svga_texture_copy_handle(svga_context(pipe), + ss, + tex->handle, + 0, 0, z_offset, + i + start_mip, + j + face_pick, handle, 0, 0, 0, i, j, - tex->base.width[i + start_mip], tex->base.height[i + start_mip], depth); + tex->base.width[i + start_mip], + tex->base.height[i + start_mip], + depth); } } } @@ -586,25 +595,23 @@ svga_get_tex_surface(struct pipe_screen *screen, { struct svga_texture *tex = svga_texture(pt); struct svga_surface *s; - struct pipe_surface *ps; boolean render = flags & PIPE_BUFFER_USAGE_GPU_WRITE ? TRUE : FALSE; boolean view = FALSE; SVGA3dSurfaceFormat format; s = CALLOC_STRUCT(svga_surface); - ps = &s->base; - if (!ps) + if (!s) return NULL; - pipe_reference_init(&ps->reference, 1); - pipe_texture_reference(&ps->texture, pt); - ps->format = pt->format; - ps->width = pt->width[level]; - ps->height = pt->height[level]; - ps->usage = flags; - ps->level = level; - ps->face = face; - ps->zslice = zslice; + pipe_reference_init(&s->base.reference, 1); + pipe_texture_reference(&s->base.texture, pt); + s->base.format = pt->format; + s->base.width = pt->width[level]; + s->base.height = pt->height[level]; + s->base.usage = flags; + s->base.level = level; + s->base.face = face; + s->base.zslice = zslice; if (!render) format = svga_translate_format(pt->format); @@ -619,11 +626,13 @@ svga_get_tex_surface(struct pipe_screen *screen, view = TRUE; /* Currently only used for compressed textures */ - if (render && (format != svga_translate_format(pt->format))) { + if (render && + format != svga_translate_format(pt->format)) { view = TRUE; } - if (level != 0 && svga_screen(screen)->debug.force_level_surface_view) + if (level != 0 && + svga_screen(screen)->debug.force_level_surface_view) view = TRUE; if (pt->target == PIPE_TEXTURE_3D) @@ -634,9 +643,10 @@ svga_get_tex_surface(struct pipe_screen *screen, if (view) { SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: yes %p, level %u face %u z %u, %p\n", - pt, level, face, zslice, ps); + pt, level, face, zslice, s); - s->handle = svga_texture_view_surface(NULL, tex, format, level, 1, face, zslice); + s->handle = svga_texture_view_surface(NULL, tex, format, level, 1, face, zslice, + &s->key); s->real_face = 0; s->real_level = 0; s->real_zslice = 0; @@ -644,15 +654,16 @@ svga_get_tex_surface(struct pipe_screen *screen, struct svga_winsys_screen *sws = svga_winsys_screen(screen); SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: no %p, level %u, face %u, z %u, %p\n", - pt, level, face, zslice, ps); + pt, level, face, zslice, s); sws->surface_reference(sws, &s->handle, tex->handle); s->real_face = face; s->real_level = level; s->real_zslice = zslice; + memset(&s->key, 0, sizeof s->key); } - return ps; + return &s->base; } @@ -663,7 +674,7 @@ svga_tex_surface_destroy(struct pipe_surface *surf) struct svga_screen *ss = svga_screen(surf->texture->screen); SVGA_DBG(DEBUG_DMA, "unref sid %p (tex surface)\n", s->handle); - ss->sws->surface_reference(ss->sws, &s->handle, NULL); + svga_screen_surface_destroy(ss, &s->key, &s->handle); pipe_texture_reference(&surf->texture, NULL); FREE(surf); } @@ -974,7 +985,8 @@ svga_get_tex_sampler_view(struct pipe_context *pipe, struct pipe_texture *pt, sv->handle = svga_texture_view_surface(pipe, tex, format, min_lod, max_lod - min_lod + 1, - -1, -1); + -1, -1, + &sv->key); if (!sv->handle) { assert(0); @@ -1030,7 +1042,7 @@ svga_destroy_sampler_view_priv(struct svga_sampler_view *v) struct svga_screen *ss = svga_screen(v->texture->base.screen); SVGA_DBG(DEBUG_DMA, "unref sid %p (sampler view)\n", v->handle); - ss->sws->surface_reference(ss->sws, &v->handle, NULL); + svga_screen_surface_destroy(ss, &v->key, &v->handle); FREE(v); } diff --git a/src/gallium/drivers/svga/svga_screen_texture.h b/src/gallium/drivers/svga/svga_screen_texture.h index 1e6fef59a39..1cc4063e653 100644 --- a/src/gallium/drivers/svga/svga_screen_texture.h +++ b/src/gallium/drivers/svga/svga_screen_texture.h @@ -29,7 +29,7 @@ #include "pipe/p_compiler.h" #include "pipe/p_state.h" - +#include "svga_screen_cache.h" struct pipe_context; struct pipe_screen; @@ -68,6 +68,7 @@ struct svga_sampler_view unsigned age; + struct svga_host_surface_cache_key key; struct svga_winsys_surface *handle; }; @@ -76,8 +77,6 @@ struct svga_texture { struct pipe_texture base; - struct svga_winsys_surface *handle; - boolean defined[6][PIPE_MAX_TEXTURE_LEVELS]; struct svga_sampler_view *cached_view; @@ -86,6 +85,16 @@ struct svga_texture unsigned age; boolean views_modified; + + /** + * Creation key for the host surface handle. + * + * This structure describes all the host surface characteristics so that it + * can be looked up in cache, since creating a host surface is often a slow + * operation. + */ + struct svga_host_surface_cache_key key; + struct svga_winsys_surface *handle; }; @@ -93,6 +102,7 @@ struct svga_surface { struct pipe_surface base; + struct svga_host_surface_cache_key key; struct svga_winsys_surface *handle; unsigned real_face; -- 2.30.2