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 eaa589c..4344a87 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 05d8c56..9365f75 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 b96a8e4..90e4f81 100644 (file)
@@ -419,6 +419,14 @@ struct svga_winsys_screen
                          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.
     *
     * @param usage bitmask of SVGA_BUFFER_USAGE_* flags.
index a18dd82..f8c9180 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;