softpipe: Make softpipe transfers in-order.
authorJosé Fonseca <jfonseca@vmware.com>
Sun, 25 Apr 2010 16:03:48 +0000 (17:03 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Sun, 25 Apr 2010 22:41:48 +0000 (23:41 +0100)
Transfer, being now a context operation, should happen in order with
all other contexts operations. If there is rendering pending on the
resource then the driver must flush and potentially wait itself
internally.

Instead of avoiding using transfers internally (as done in llvmpipe) I've
opted to simply pass PIPE_TRANSFER_UNSYNCHRONIZED in all internal
transfers, to avoid infinite recursion.

src/gallium/drivers/softpipe/sp_flush.c
src/gallium/drivers/softpipe/sp_flush.h
src/gallium/drivers/softpipe/sp_tex_tile_cache.c
src/gallium/drivers/softpipe/sp_texture.c
src/gallium/drivers/softpipe/sp_tile_cache.c

index 508fe8f764d06aabb1b4e8102a3128041d85a4f6..5024fc8a81941147c54ca6c0762b678df9aeb96a 100644 (file)
@@ -104,3 +104,71 @@ softpipe_flush( struct pipe_context *pipe,
       *fence = NULL;
 }
 
+
+/**
+ * Flush context if necessary.
+ *
+ * Returns FALSE if it would have block, but do_not_block was set, TRUE
+ * otherwise.
+ *
+ * TODO: move this logic to an auxiliary library?
+ */
+boolean
+softpipe_flush_resource(struct pipe_context *pipe,
+                        struct pipe_resource *texture,
+                        unsigned face,
+                        unsigned level,
+                        unsigned flush_flags,
+                        boolean read_only,
+                        boolean cpu_access,
+                        boolean do_not_block)
+{
+   unsigned referenced;
+
+   referenced = pipe->is_resource_referenced(pipe, texture, face, level);
+
+   if ((referenced & PIPE_REFERENCED_FOR_WRITE) ||
+       ((referenced & PIPE_REFERENCED_FOR_READ) && !read_only)) {
+
+      /*
+       * TODO: The semantics of these flush flags are too obtuse. They should
+       * disappear and the pipe driver should just ensure that all visible
+       * side-effects happen when they need to happen.
+       */
+      if (referenced & PIPE_REFERENCED_FOR_WRITE)
+         flush_flags |= PIPE_FLUSH_RENDER_CACHE;
+
+      if (referenced & PIPE_REFERENCED_FOR_READ)
+         flush_flags |= PIPE_FLUSH_TEXTURE_CACHE;
+
+      if (cpu_access) {
+         /*
+          * Flush and wait.
+          */
+
+         struct pipe_fence_handle *fence = NULL;
+
+         if (do_not_block)
+            return FALSE;
+
+         pipe->flush(pipe, flush_flags, &fence);
+
+         if (fence) {
+            /*
+             * This is for illustrative purposes only, as softpipe does not
+             * have fences.
+             */
+            pipe->screen->fence_finish(pipe->screen, fence, 0);
+            pipe->screen->fence_reference(pipe->screen, &fence, NULL);
+         }
+      } else {
+         /*
+          * Just flush.
+          */
+
+         pipe->flush(pipe, flush_flags, NULL);
+      }
+   }
+
+   return TRUE;
+}
index 68d9b5fa835cb8646263b7e20f98dd263b2716e7..cb97482a71b33300c2117ba0efaf3a17f43ae50a 100644 (file)
 #ifndef SP_FLUSH_H
 #define SP_FLUSH_H
 
+#include "pipe/p_compiler.h"
+
 struct pipe_context;
 struct pipe_fence_handle;
 
-void softpipe_flush(struct pipe_context *pipe, unsigned flags,
-                    struct pipe_fence_handle **fence);
+void
+softpipe_flush(struct pipe_context *pipe, unsigned flags,
+               struct pipe_fence_handle **fence);
+
+boolean
+softpipe_flush_resource(struct pipe_context *pipe,
+                        struct pipe_resource *texture,
+                        unsigned face,
+                        unsigned level,
+                        unsigned flush_flags,
+                        boolean read_only,
+                        boolean cpu_access,
+                        boolean do_not_block);
 
 #endif
index c79f5fb05a125882ec5d83c283d74fca35f82d2e..fbce9e042ba3522e669a8059d921290181a86387 100644 (file)
@@ -248,7 +248,8 @@ sp_find_cached_tile_tex(struct softpipe_tex_tile_cache *tc,
                              addr.bits.face, 
                              addr.bits.level, 
                              addr.bits.z, 
-                             PIPE_TRANSFER_READ, 0, 0,
+                             PIPE_TRANSFER_READ | PIPE_TRANSFER_UNSYNCHRONIZED,
+                             0, 0,
                              u_minify(tc->texture->width0, addr.bits.level),
                              u_minify(tc->texture->height0, addr.bits.level));
          
index 167b6b116175b6e9ecd011f5b06a04dc4e89b0cc..3533c4fd4f0d7d07d41db52a76f28156871181fe 100644 (file)
@@ -39,6 +39,7 @@
 #include "util/u_transfer.h"
 
 #include "sp_context.h"
+#include "sp_flush.h"
 #include "sp_texture.h"
 #include "sp_screen.h"
 
@@ -301,6 +302,27 @@ softpipe_get_transfer(struct pipe_context *pipe,
    assert(box->y + box->height <= u_minify(resource->height0, sr.level));
    assert(box->z + box->depth <= u_minify(resource->depth0, sr.level));
 
+   /*
+    * Transfers, like other pipe operations, must happen in order, so flush the
+    * context if necessary.
+    */
+   if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
+      boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
+      boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
+      if (!softpipe_flush_resource(pipe, resource,
+                                   sr.face, sr.level,
+                                   0, /* flush_flags */
+                                   read_only,
+                                   TRUE, /* cpu_access */
+                                   do_not_block)) {
+         /*
+          * It would have blocked, but state tracker requested no to.
+          */
+         assert(do_not_block);
+         return NULL;
+      }
+   }
+
    spr = CALLOC_STRUCT(softpipe_transfer);
    if (spr) {
       struct pipe_transfer *pt = &spr->base;
index 4e5a13ba0516e79d9c3be18913b88ec95aa7d149..f4db6f6ef00c631571b0ab4741fe0ff08f0c7105 100644 (file)
@@ -155,7 +155,8 @@ sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
    if (ps) {
       tc->transfer = pipe_get_transfer(pipe, ps->texture, ps->face,
                                           ps->level, ps->zslice,
-                                          PIPE_TRANSFER_READ_WRITE,
+                                          PIPE_TRANSFER_READ_WRITE |
+                                          PIPE_TRANSFER_UNSYNCHRONIZED,
                                           0, 0, ps->width, ps->height);
 
       tc->depth_stencil = (ps->format == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||