svga: do not unconditionally enable streamout bind flag
authorCharmaine Lee <charmainel@vmware.com>
Tue, 15 Nov 2016 18:15:46 +0000 (10:15 -0800)
committerBrian Paul <brianp@vmware.com>
Tue, 27 Jun 2017 13:49:02 +0000 (07:49 -0600)
Currently we unconditionally enable streamout bind flag at
buffer resource creation time. This is not necessary if the buffer
is never used as a streamout buffer. With this patch, we enable
streamout bind flag as indicated by the state tracker. If the buffer
is later bound to streamout and does not already has streamout bind
flag enabled, we will recreate the buffer with
the new set of bind flags. Buffer content will be copied
from the old buffer to the new one.

Tested with MTT piglit, Nature, Tropics, Lightsmark.

v2: Fix bind flags check as suggested by Brian.

Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
src/gallium/drivers/svga/svga_pipe_streamout.c
src/gallium/drivers/svga/svga_resource_buffer.c
src/gallium/drivers/svga/svga_resource_buffer_upload.c
src/gallium/drivers/svga/svga_resource_buffer_upload.h

index 18cc804d0c99b792a64b5809d24ac6d895b4acd4..4add087888f6dd68e94418799f269cc4fa3045ee 100644 (file)
@@ -276,14 +276,14 @@ svga_set_stream_output_targets(struct pipe_context *pipe,
    for (i = 0; i < num_targets; i++) {
       struct svga_stream_output_target *sot
          = svga_stream_output_target(targets[i]);
-      struct svga_buffer *sbuf = svga_buffer(sot->base.buffer);
       unsigned size;
 
-      assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT);
-      (void) sbuf;
-
       svga->so_surfaces[i] = svga_buffer_handle(svga, sot->base.buffer,
                                                 PIPE_BIND_STREAM_OUTPUT);
+
+      assert(svga_buffer(sot->base.buffer)->key.flags
+             & SVGA3D_SURFACE_BIND_STREAM_OUTPUT);
+
       svga->so_targets[i] = &sot->base;
       soBindings[i].offset = sot->base.buffer_offset;
 
index 4448b7d030867231e128b668120ff2ba33a3e26a..39aa530a6727e04f365e8624608f81f459a186d1 100644 (file)
@@ -427,20 +427,22 @@ svga_buffer_create(struct pipe_screen *screen,
 
    if (svga_buffer_needs_hw_storage(bind_flags)) {
 
-      /* If the buffer will be used for vertex/index/stream data, set all
-       * the flags so that the buffer will be accepted for all those uses.
+      /* If the buffer will be used for vertex/index/stream data, set
+       * the vertex/index bind flags as well so that the buffer will be
+       * accepted for those uses.
        * Note that the PIPE_BIND_ flags we get from the state tracker are
        * just a hint about how the buffer may be used.  And OpenGL buffer
        * object may be used for many different things.
+       * Also note that we do not unconditionally set the streamout
+       * bind flag since streamout buffer is an output buffer and
+       * might have performance implication.
        */
       if (!(template->bind & PIPE_BIND_CONSTANT_BUFFER)) {
-         /* Not a constant buffer.  The buffer may be used for vertex data,
-          * indexes or stream-out.
+         /* Not a constant buffer.  The buffer may be used for vertex data
+          * or indexes.
           */
          bind_flags |= (PIPE_BIND_VERTEX_BUFFER |
                         PIPE_BIND_INDEX_BUFFER);
-         if (ss->sws->have_vgpu10)
-            bind_flags |= PIPE_BIND_STREAM_OUTPUT;
       }
 
       if (svga_buffer_create_host_surface(ss, sbuf, bind_flags) != PIPE_OK)
index 40429a8dc80161a870d701591d123e30bbe62551..d18d026bfa1284646363678453974a64560d7a38 100644 (file)
@@ -213,6 +213,53 @@ svga_buffer_create_host_surface(struct svga_screen *ss,
 }
 
 
+/**
+ * Recreates a host surface with the new bind flags.
+ */
+enum pipe_error
+svga_buffer_recreate_host_surface(struct svga_context *svga,
+                                  struct svga_buffer *sbuf,
+                                  unsigned bind_flags)
+{
+   struct svga_screen *ss = svga_screen(sbuf->b.b.screen);
+   struct svga_winsys_surface *old_handle;
+   struct svga_host_surface_cache_key old_key;
+   enum pipe_error ret = PIPE_OK;
+
+   assert(sbuf->bind_flags != bind_flags);
+
+   /* Flush any pending upload first */
+   svga_buffer_upload_flush(svga, sbuf);
+
+   /* Save the old resource handle and key */
+   old_handle = sbuf->handle;
+   old_key = sbuf->key;
+   sbuf->handle = NULL;
+   /* Create a new resource with the required bind_flags */
+   ret = svga_buffer_create_host_surface(ss, sbuf, bind_flags);
+   if (ret == PIPE_OK) {
+      /* Copy the surface data */
+      assert(sbuf->handle);
+      ret = SVGA3D_vgpu10_BufferCopy(svga->swc, old_handle, sbuf->handle,
+                                     0, 0, sbuf->b.b.width0);
+      if (ret != PIPE_OK) {
+         svga_context_flush(svga, NULL);
+         ret = SVGA3D_vgpu10_BufferCopy(svga->swc, old_handle, sbuf->handle,
+                                        0, 0, sbuf->b.b.width0);
+         assert(ret == PIPE_OK);
+      }
+   }
+
+   /* Set the new bind flags for this buffer resource */
+   sbuf->bind_flags = bind_flags;
+
+   /* Destroy the old resource handle */
+   svga_screen_surface_destroy(ss, &old_key, &old_handle);
+
+   return ret;
+}
+
 void
 svga_buffer_destroy_host_surface(struct svga_screen *ss,
                                  struct svga_buffer *sbuf)
@@ -791,7 +838,20 @@ svga_buffer_handle(struct svga_context *svga, struct pipe_resource *buf,
 
    assert(!sbuf->user);
 
-   if (!sbuf->handle) {
+   if (sbuf->handle) {
+      if ((sbuf->bind_flags & tobind_flags) != tobind_flags) {
+         /* If the allocated resource's bind flags do not include the
+          * requested bind flags, create a new resource to include the
+          * new bind flags, and do a BufferCopy from the old resource to
+          * the new one.
+          */
+         assert(svga_have_vgpu10(svga));
+         ret = svga_buffer_recreate_host_surface(svga, sbuf,
+                                                 sbuf->bind_flags|tobind_flags);
+         if (ret != PIPE_OK)
+            return NULL;
+      }
+   } else {
       /* This call will set sbuf->handle */
       if (svga_have_gb_objects(svga)) {
         ret = svga_buffer_update_hw(svga, sbuf, sbuf->bind_flags);
index f718f24c905d0f62208e61c7ae0e28711b1703d1..877ae5499a1485a3971f0be865b101c28521d697 100644 (file)
@@ -50,6 +50,11 @@ svga_buffer_create_host_surface(struct svga_screen *ss,
                                 struct svga_buffer *sbuf,
                                 unsigned bind_flags);
 
+enum pipe_error
+svga_buffer_recreate_host_surface(struct svga_context *svga,
+                                  struct svga_buffer *sbuf,
+                                  unsigned bind_flags);
+
 void
 svga_buffer_destroy_host_surface(struct svga_screen *ss,
                                  struct svga_buffer *sbuf);