Module: Mesa
Branch: main
Commit: 2fc0bbe8140547d180d293021f36abf8d19986b4
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=2fc0bbe8140547d180d293021f36abf8d19986b4

Author: Paulo Zanoni <[email protected]>
Date:   Thu Sep 28 13:53:25 2023 -0700

anv/sparse: join multiple bind operations when possible

If the next bind is just an extension of the previous one, join both
in the same bind operation. Due to how mip levels are laid in memory,
this can only happen for mip level 0.

As of today xe.ko doesn't try to join contiguous operations for us.
Due to how rebinds happen each additional rebind operation may end up
resulting in many extra things done, so these simple checks end up
saving us a lot of cycles the Kernel would otherwise waste. This will
be true even after we issue all binds in a single ioctl.

Reviewed-by: Lionel Landwerlin <[email protected]>
Signed-off-by: Paulo Zanoni <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26036>

---

 src/intel/vulkan/anv_sparse.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/src/intel/vulkan/anv_sparse.c b/src/intel/vulkan/anv_sparse.c
index 37c0b2abcb4..bcf7ddb8917 100644
--- a/src/intel/vulkan/anv_sparse.c
+++ b/src/intel/vulkan/anv_sparse.c
@@ -656,11 +656,6 @@ anv_sparse_bind_image_memory(struct anv_queue *queue,
     * they're guaranteed to be contiguous, so we calculate how many blocks
     * that is and how big is each block to figure the bind size of a whole
     * line.
-    *
-    * TODO: if we're binding mip_level 0 and bind_extent_el.width is the total
-    * line, the whole rectangle is contiguous so we could do this with a
-    * single bind instead of per-line. We should figure out how common this is
-    * and consider implementing this special-case.
     */
    uint64_t line_bind_size_in_blocks = bind_extent_el.width /
                                        block_shape_el.width;
@@ -712,13 +707,29 @@ anv_sparse_bind_image_memory(struct anv_queue *queue,
          assert(opaque_bind.size % block_size_B == 0);
 
          assert(num_binds < binds_array_len);
-         binds[num_binds] = vk_bind_to_anv_vm_bind(sparse_data,
-                                                   &opaque_bind);
-         dump_anv_vm_bind(device, sparse_data, &binds[num_binds]);
-         num_binds++;
+
+         struct anv_vm_bind anv_bind = vk_bind_to_anv_vm_bind(sparse_data,
+                                                              &opaque_bind);
+         struct anv_vm_bind *prev_bind = num_binds > 0 ?
+                                          &binds[num_binds - 1] : NULL;
+         if (prev_bind &&
+             anv_bind.op == prev_bind->op &&
+             anv_bind.bo == prev_bind->bo &&
+             anv_bind.address == prev_bind->address + prev_bind->size &&
+             anv_bind.bo_offset == prev_bind->bo_offset + prev_bind->size) {
+            prev_bind->size += anv_bind.size;
+         } else {
+            binds[num_binds] = anv_bind;
+            num_binds++;
+         }
       }
    }
 
+   if (INTEL_DEBUG(DEBUG_SPARSE)) {
+      for (int b = 0; b < num_binds; b++)
+         dump_anv_vm_bind(device, sparse_data, &binds[b]);
+   }
+
    /* FIXME: here we were supposed to issue a single vm_bind ioctl by calling
     * vm_bind(device, num_binds, binds), but for an unknown reason some
     * shader-related tests fail when we do that, so work around it for now.

Reply via email to