From da98cee067fcf61ac6f2c70c91b0c8eab27eba92 Mon Sep 17 00:00:00 2001 From: Charmaine Lee Date: Tue, 8 Mar 2016 11:18:51 -0800 Subject: [PATCH] svga: invalidate gb surface before it is reused With this patch, a guest-backed surface will be invalidated using the SVGA_3D_CMD_INVALIDATE_GB_SURFACE command before the surface is reused. This fixes the updating dirty image error from the device when a surface is reused. v2: Instead of invalidating the surface when it is reused, send the invalidate command before the surface is put into the recycle pool. v3: (1) surface invalidate is a noop operation in Linux winsys, since surface invalidation is not needed for DMA path. (2) Instead of invalidating the surface content in svga_screen_surface_destroy() when a surface is to be destroyed, it is done in svga_screen_cache_flush() when the surface is no longer referenced in a command buffer and is ready to be moved to the unused list. At this point, the surface will be moved to the invalidate list. When the surface invalidation is submitted, the surface will be moved to the unused list. Tested with piglit, glretrace. Reviewed-by: Brian Paul Reviewed-by: Sinclair Yeh --- src/gallium/drivers/svga/svga_screen_cache.c | 37 +++++++++++++++++-- src/gallium/drivers/svga/svga_screen_cache.h | 14 ++++--- src/gallium/drivers/svga/svga_winsys.h | 8 ++++ src/gallium/winsys/svga/drm/vmw_screen_svga.c | 13 +++++++ 4 files changed, 63 insertions(+), 9 deletions(-) diff --git a/src/gallium/drivers/svga/svga_screen_cache.c b/src/gallium/drivers/svga/svga_screen_cache.c index eaa589c4c26..4344a87348c 100644 --- a/src/gallium/drivers/svga/svga_screen_cache.c +++ b/src/gallium/drivers/svga/svga_screen_cache.c @@ -320,16 +320,16 @@ svga_screen_cache_flush(struct svga_screen *svgascreen, pipe_mutex_lock(cache->mutex); - /* Loop over entries in the validated list */ - curr = cache->validated.next; + /* Loop over entries in the invalidated list */ + curr = cache->invalidated.next; next = curr->next; - while (curr != &cache->validated) { + while (curr != &cache->invalidated) { entry = LIST_ENTRY(struct svga_host_surface_cache_entry, curr, head); assert(entry->handle); if (sws->surface_is_flushed(sws, entry->handle)) { - /* remove entry from LRU list */ + /* remove entry from the invalidated list */ LIST_DEL(&entry->head); svgascreen->sws->fence_reference(svgascreen->sws, &entry->fence, fence); @@ -346,6 +346,28 @@ svga_screen_cache_flush(struct svga_screen *svgascreen, next = curr->next; } + curr = cache->validated.next; + next = curr->next; + while (curr != &cache->validated) { + entry = LIST_ENTRY(struct svga_host_surface_cache_entry, curr, head); + + assert(entry->handle); + + if (sws->surface_is_flushed(sws, entry->handle)) { + /* remove entry from the validated list */ + LIST_DEL(&entry->head); + + /* it is now safe to invalidate the surface content. */ + sws->surface_invalidate(sws, entry->handle); + + /* add the entry to the invalidated list */ + LIST_ADD(&entry->head, &cache->invalidated); + } + + curr = next; + next = curr->next; + } + pipe_mutex_unlock(cache->mutex); } @@ -396,6 +418,8 @@ svga_screen_cache_init(struct svga_screen *svgascreen) LIST_INITHEAD(&cache->validated); + LIST_INITHEAD(&cache->invalidated); + LIST_INITHEAD(&cache->empty); for (i = 0; i < SVGA_HOST_SURFACE_CACHE_SIZE; ++i) LIST_ADDTAIL(&cache->entries[i].head, &cache->empty); @@ -535,6 +559,11 @@ svga_screen_surface_destroy(struct svga_screen *svgascreen, * that case. */ if (SVGA_SURFACE_CACHE_ENABLED && key->cachable) { + + /* Invalidate the surface before putting it into the recycle pool */ + if (key->format != SVGA3D_BUFFER) + sws->surface_invalidate(sws, *p_handle); + svga_screen_cache_add(svgascreen, key, p_handle); } else { diff --git a/src/gallium/drivers/svga/svga_screen_cache.h b/src/gallium/drivers/svga/svga_screen_cache.h index 05d8c56d83c..9365f751f72 100644 --- a/src/gallium/drivers/svga/svga_screen_cache.h +++ b/src/gallium/drivers/svga/svga_screen_cache.h @@ -95,12 +95,13 @@ struct svga_host_surface_cache_entry * A cache entry can be in the following stages: * 1. empty (entry->handle = NULL) * 2. holding a buffer in a validate list - * 3. holding a flushed buffer (not in any validate list) with an active fence - * 4. holding a flushed buffer with an expired fence + * 3. holding a buffer in an invalidate list + * 4. holding a flushed buffer (not in any validate list) with an active fence + * 5. holding a flushed buffer with an expired fence * - * An entry progresses from 1 -> 2 -> 3 -> 4. When we need an entry to put a + * An entry progresses from 1 -> 2 -> 3 -> 4 -> 5. When we need an entry to put a * buffer into we preferentially take from 1, or from the least recently used - * buffer from 3/4. + * buffer from 4/5. */ struct svga_host_surface_cache { @@ -113,9 +114,12 @@ struct svga_host_surface_cache * (3 and 4) */ struct list_head unused; - /* Entries with buffers still in validate lists (2) */ + /* Entries with buffers still in validate list (2) */ struct list_head validated; + /* Entries with buffers still in invalidate list (3) */ + struct list_head invalidated; + /** Empty entries (1) */ struct list_head empty; diff --git a/src/gallium/drivers/svga/svga_winsys.h b/src/gallium/drivers/svga/svga_winsys.h index b96a8e46c4d..90e4f81da8d 100644 --- a/src/gallium/drivers/svga/svga_winsys.h +++ b/src/gallium/drivers/svga/svga_winsys.h @@ -418,6 +418,14 @@ struct svga_winsys_screen uint32 numLayers, uint32 numMipLevels); + /** + * Invalidate the content of this surface + */ + void + (*surface_invalidate)(struct svga_winsys_screen *sws, + struct svga_winsys_surface *surface); + + /** * Buffer management. Buffer attributes are mostly fixed over its lifetime. * diff --git a/src/gallium/winsys/svga/drm/vmw_screen_svga.c b/src/gallium/winsys/svga/drm/vmw_screen_svga.c index a18dd827c64..f8c9180e9bc 100644 --- a/src/gallium/winsys/svga/drm/vmw_screen_svga.c +++ b/src/gallium/winsys/svga/drm/vmw_screen_svga.c @@ -280,6 +280,18 @@ vmw_svga_winsys_surface_can_create(struct svga_winsys_screen *sws, } +static void +vmw_svga_winsys_surface_invalidate(struct svga_winsys_screen *sws, + struct svga_winsys_surface *surf) +{ + /* this is a noop since surface invalidation is not needed for DMA path. + * DMA is enabled when guest-backed surface is not enabled or + * guest-backed dma is enabled. Since guest-backed dma is enabled + * when guest-backed surface is enabled, that implies DMA is always enabled; + * hence, surface invalidation is not needed. + */ +} + static boolean vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen *sws, struct svga_winsys_surface *surface) @@ -406,6 +418,7 @@ vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws) vws->base.surface_is_flushed = vmw_svga_winsys_surface_is_flushed; vws->base.surface_reference = vmw_svga_winsys_surface_ref; vws->base.surface_can_create = vmw_svga_winsys_surface_can_create; + vws->base.surface_invalidate = vmw_svga_winsys_surface_invalidate; vws->base.buffer_create = vmw_svga_winsys_buffer_create; vws->base.buffer_map = vmw_svga_winsys_buffer_map; vws->base.buffer_unmap = vmw_svga_winsys_buffer_unmap; -- 2.30.2