svga: invalidate gb surface before it is reused
authorCharmaine Lee <charmainel@vmware.com>
Tue, 8 Mar 2016 19:18:51 +0000 (11:18 -0800)
committerBrian Paul <brianp@vmware.com>
Fri, 8 Jul 2016 18:53:20 +0000 (12:53 -0600)
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 <brianp@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
src/gallium/drivers/svga/svga_screen_cache.c
src/gallium/drivers/svga/svga_screen_cache.h
src/gallium/drivers/svga/svga_winsys.h
src/gallium/winsys/svga/drm/vmw_screen_svga.c

index eaa589c4c2697402a21e6950b92a09edb3432315..4344a87348c9737a743fbb08c2c6d4255deb0a9d 100644 (file)
@@ -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 {
index 05d8c56d83c18bcc2d102c7f9112125997a7e217..9365f751f72c634adda37f676c07333ff02ab19d 100644 (file)
@@ -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;
 
index b96a8e46c4db55469c3cd141cf0607abaedce1d3..90e4f81da8de3e6e6e55f1ec7f8e2e647d3d62fd 100644 (file)
@@ -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.
     *
index a18dd827c647499f137cbc8e1e35ae842acad8b2..f8c9180e9bc3b18f510d33ee94c6da6126a00ce7 100644 (file)
@@ -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;