Mesa (main): gallium/u_threaded: clear valid buffer range only if it's not bound for write

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Jun 14 23:38:30 UTC 2021


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

Author: Marek Olšák <marek.olsak at amd.com>
Date:   Thu May 20 05:05:01 2021 -0400

gallium/u_threaded: clear valid buffer range only if it's not bound for write

We can't invalidate the range if a buffer is bound for write because we
would need to add the range that is bound, which we don't track.

This fixes buffer mappings incorrectly promoted to unsynchronized because
the valid range was cleared while the buffers were bound for write.

It also clears the valid range if the invalidation is allowed but skipped.

Reviewed-by: Rob Clark <robdclark at chromium.org>
Reviewed-By: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11335>

---

 src/gallium/auxiliary/util/u_threaded_context.c | 80 ++++++++++++++++++++++++-
 src/gallium/auxiliary/util/u_threaded_context.h |  2 +
 2 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/src/gallium/auxiliary/util/u_threaded_context.c b/src/gallium/auxiliary/util/u_threaded_context.c
index 54ee6e76dc7..5917fb52e36 100644
--- a/src/gallium/auxiliary/util/u_threaded_context.c
+++ b/src/gallium/auxiliary/util/u_threaded_context.c
@@ -567,6 +567,61 @@ tc_rebind_buffer(struct threaded_context *tc, uint32_t old_id, uint32_t new_id,
    return rebound;
 }
 
+static bool
+tc_is_buffer_bound_with_mask(uint32_t id, uint32_t *bindings, unsigned binding_mask)
+{
+   while (binding_mask) {
+      if (bindings[u_bit_scan(&binding_mask)] == id)
+         return true;
+   }
+   return false;
+}
+
+static bool
+tc_is_buffer_shader_bound_for_write(struct threaded_context *tc, uint32_t id,
+                                    enum pipe_shader_type shader)
+{
+   if (tc->seen_shader_buffers[shader] &&
+       tc_is_buffer_bound_with_mask(id, tc->shader_buffers[shader],
+                                    tc->shader_buffers_writeable_mask[shader]))
+      return true;
+
+   if (tc->seen_image_buffers[shader] &&
+       tc_is_buffer_bound_with_mask(id, tc->image_buffers[shader],
+                                    tc->image_buffers_writeable_mask[shader]))
+      return true;
+
+   return false;
+}
+
+static bool
+tc_is_buffer_bound_for_write(struct threaded_context *tc, uint32_t id)
+{
+   if (tc->seen_streamout_buffers &&
+       tc_is_buffer_bound_with_mask(id, tc->streamout_buffers,
+                                    BITFIELD_MASK(PIPE_MAX_SO_BUFFERS)))
+      return true;
+
+   if (tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_VERTEX) ||
+       tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_FRAGMENT) ||
+       tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_COMPUTE))
+      return true;
+
+   if (tc->seen_tcs &&
+       tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_TESS_CTRL))
+      return true;
+
+   if (tc->seen_tes &&
+       tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_TESS_EVAL))
+      return true;
+
+   if (tc->seen_gs &&
+       tc_is_buffer_shader_bound_for_write(tc, id, PIPE_SHADER_GEOMETRY))
+      return true;
+
+   return false;
+}
+
 static bool
 tc_is_buffer_busy(struct threaded_context *tc, struct threaded_resource *tbuf,
                   unsigned map_usage)
@@ -1367,6 +1422,7 @@ tc_set_shader_images(struct pipe_context *_pipe,
    struct tc_shader_images *p =
       tc_add_slot_based_call(tc, TC_CALL_set_shader_images, tc_shader_images,
                              images ? count : 0);
+   unsigned writable_buffers = 0;
 
    p->shader = shader;
    p->start = start;
@@ -1391,6 +1447,7 @@ tc_set_shader_images(struct pipe_context *_pipe,
                util_range_add(&tres->b, &tres->valid_buffer_range,
                               images[i].u.buf.offset,
                               images[i].u.buf.offset + images[i].u.buf.size);
+               writable_buffers |= BITFIELD_BIT(start + i);
             }
          } else {
             tc_unbind_buffer(&tc->image_buffers[shader][start + i]);
@@ -1408,6 +1465,9 @@ tc_set_shader_images(struct pipe_context *_pipe,
       tc_unbind_buffers(&tc->image_buffers[shader][start],
                         count + unbind_num_trailing_slots);
    }
+
+   tc->image_buffers_writeable_mask[shader] &= ~BITFIELD_RANGE(start, count);
+   tc->image_buffers_writeable_mask[shader] |= writable_buffers << start;
 }
 
 struct tc_shader_buffers {
@@ -1488,6 +1548,9 @@ tc_set_shader_buffers(struct pipe_context *_pipe,
    } else {
       tc_unbind_buffers(&tc->shader_buffers[shader][start], count);
    }
+
+   tc->shader_buffers_writeable_mask[shader] &= ~BITFIELD_RANGE(start, count);
+   tc->shader_buffers_writeable_mask[shader] |= writable_bitmask << start;
 }
 
 struct tc_vertex_buffers {
@@ -1855,8 +1918,17 @@ static bool
 tc_invalidate_buffer(struct threaded_context *tc,
                      struct threaded_resource *tbuf)
 {
-   if (!tc_is_buffer_busy(tc, tbuf, PIPE_MAP_READ_WRITE))
+   if (!tc_is_buffer_busy(tc, tbuf, PIPE_MAP_READ_WRITE)) {
+      /* It's idle, so invalidation would be a no-op, but we can still clear
+       * the valid range because we are technically doing invalidation, but
+       * skipping it because it's useless.
+       *
+       * If the buffer is bound for write, we can't invalidate the range.
+       */
+      if (!tc_is_buffer_bound_for_write(tc, tbuf->buffer_id_unique))
+         util_range_set_empty(&tbuf->valid_buffer_range);
       return true;
+   }
 
    struct pipe_screen *screen = tc->base.screen;
    struct pipe_resource *new_buf;
@@ -1892,10 +1964,14 @@ tc_invalidate_buffer(struct threaded_context *tc,
    p->rebind_mask = 0;
 
    /* Treat the current buffer as the new buffer. */
+   bool bound_for_write = tc_is_buffer_bound_for_write(tc, tbuf->buffer_id_unique);
    p->num_rebinds = tc_rebind_buffer(tc, tbuf->buffer_id_unique,
                                      threaded_resource(new_buf)->buffer_id_unique,
                                      &p->rebind_mask);
-   util_range_set_empty(&tbuf->valid_buffer_range);
+
+   /* If the buffer is not bound for write, clear the valid range. */
+   if (!bound_for_write)
+      util_range_set_empty(&tbuf->valid_buffer_range);
 
    tbuf->buffer_id_unique = threaded_resource(new_buf)->buffer_id_unique;
    threaded_resource(new_buf)->buffer_id_unique = 0;
diff --git a/src/gallium/auxiliary/util/u_threaded_context.h b/src/gallium/auxiliary/util/u_threaded_context.h
index 565236a0b01..952429d74ff 100644
--- a/src/gallium/auxiliary/util/u_threaded_context.h
+++ b/src/gallium/auxiliary/util/u_threaded_context.h
@@ -481,6 +481,8 @@ struct threaded_context {
    uint32_t const_buffers[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS];
    uint32_t shader_buffers[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_BUFFERS];
    uint32_t image_buffers[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_IMAGES];
+   uint32_t shader_buffers_writeable_mask[PIPE_SHADER_TYPES];
+   uint32_t image_buffers_writeable_mask[PIPE_SHADER_TYPES];
    /* Don't use PIPE_MAX_SHADER_SAMPLER_VIEWS because it's too large. */
    uint32_t sampler_buffers[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
 



More information about the mesa-commit mailing list