Mesa (main): gallium/u_threaded: implement draw_vertex_state
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Fri Oct 1 15:45:22 UTC 2021
Module: Mesa
Branch: main
Commit: 0842488859e63cab0d257dedb8a0c7c362754c0d
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=0842488859e63cab0d257dedb8a0c7c362754c0d
Author: Marek Olšák <marek.olsak at amd.com>
Date: Sat Sep 25 13:47:08 2021 -0400
gallium/u_threaded: implement draw_vertex_state
Reviewed-By: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer at amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13050>
---
src/gallium/auxiliary/util/u_threaded_context.c | 183 +++++++++++++++++++++
.../auxiliary/util/u_threaded_context_calls.h | 2 +
2 files changed, 185 insertions(+)
diff --git a/src/gallium/auxiliary/util/u_threaded_context.c b/src/gallium/auxiliary/util/u_threaded_context.c
index cfdd1280d57..6adb7fb9afb 100644
--- a/src/gallium/auxiliary/util/u_threaded_context.c
+++ b/src/gallium/auxiliary/util/u_threaded_context.c
@@ -128,6 +128,15 @@ tc_set_resource_reference(struct pipe_resource **dst, struct pipe_resource *src)
pipe_reference(NULL, &src->reference); /* only increment refcount */
}
+/* Assign src to dst while dst is uninitialized. */
+static inline void
+tc_set_vertex_state_reference(struct pipe_vertex_state **dst,
+ struct pipe_vertex_state *src)
+{
+ *dst = src;
+ pipe_reference(NULL, &src->reference); /* only increment refcount */
+}
+
/* Unreference dst but don't touch the dst pointer. */
static inline void
tc_drop_resource_reference(struct pipe_resource *dst)
@@ -160,6 +169,20 @@ tc_drop_so_target_reference(struct pipe_stream_output_target *dst)
dst->context->stream_output_target_destroy(dst->context, dst);
}
+/**
+ * Subtract the given number of references.
+ */
+static inline void
+tc_drop_vertex_state_references(struct pipe_vertex_state *dst, int num_refs)
+{
+ int count = p_atomic_add_return(&dst->reference.count, -num_refs);
+
+ assert(count >= 0);
+ /* Underflows shouldn't happen, but let's be safe. */
+ if (count <= 0)
+ dst->screen->vertex_state_destroy(dst->screen, dst);
+}
+
/* We don't want to read or write min_index and max_index, because
* it shouldn't be needed by drivers at this point.
*/
@@ -3306,6 +3329,165 @@ tc_draw_vbo(struct pipe_context *_pipe, const struct pipe_draw_info *info,
}
}
+struct tc_draw_vstate_single {
+ struct tc_call_base base;
+ struct pipe_draw_start_count_bias draw;
+
+ /* The following states must be together without holes because they are
+ * compared by draw merging.
+ */
+ struct pipe_vertex_state *state;
+ uint32_t partial_velem_mask;
+ struct pipe_draw_vertex_state_info info;
+};
+
+static bool
+is_next_call_a_mergeable_draw_vstate(struct tc_draw_vstate_single *first,
+ struct tc_draw_vstate_single *next)
+{
+ if (next->base.call_id != TC_CALL_draw_vstate_single)
+ return false;
+
+ return !memcmp(&first->state, &next->state,
+ offsetof(struct tc_draw_vstate_single, info) +
+ sizeof(struct pipe_draw_vertex_state_info) -
+ offsetof(struct tc_draw_vstate_single, state));
+}
+
+static uint16_t
+tc_call_draw_vstate_single(struct pipe_context *pipe, void *call, uint64_t *last_ptr)
+{
+ /* Draw call merging. */
+ struct tc_draw_vstate_single *first = to_call(call, tc_draw_vstate_single);
+ struct tc_draw_vstate_single *last = (struct tc_draw_vstate_single *)last_ptr;
+ struct tc_draw_vstate_single *next = get_next_call(first, tc_draw_vstate_single);
+
+ /* If at least 2 consecutive draw calls can be merged... */
+ if (next != last &&
+ is_next_call_a_mergeable_draw_vstate(first, next)) {
+ /* The maximum number of merged draws is given by the batch size. */
+ struct pipe_draw_start_count_bias draws[TC_SLOTS_PER_BATCH /
+ call_size(tc_draw_vstate_single)];
+ unsigned num_draws = 2;
+
+ draws[0] = first->draw;
+ draws[1] = next->draw;
+
+ /* Find how many other draws can be merged. */
+ next = get_next_call(next, tc_draw_vstate_single);
+ for (; next != last &&
+ is_next_call_a_mergeable_draw_vstate(first, next);
+ next = get_next_call(next, tc_draw_vstate_single),
+ num_draws++)
+ draws[num_draws] = next->draw;
+
+ pipe->draw_vertex_state(pipe, first->state, first->partial_velem_mask,
+ first->info, draws, num_draws);
+ /* Since all draws use the same state, drop all references at once. */
+ tc_drop_vertex_state_references(first->state, num_draws);
+
+ return call_size(tc_draw_vstate_single) * num_draws;
+ }
+
+ pipe->draw_vertex_state(pipe, first->state, first->partial_velem_mask,
+ first->info, &first->draw, 1);
+ tc_drop_vertex_state_references(first->state, 1);
+ return call_size(tc_draw_vstate_single);
+}
+
+struct tc_draw_vstate_multi {
+ struct tc_call_base base;
+ uint32_t partial_velem_mask;
+ struct pipe_draw_vertex_state_info info;
+ unsigned num_draws;
+ struct pipe_vertex_state *state;
+ struct pipe_draw_start_count_bias slot[0];
+};
+
+static uint16_t
+tc_call_draw_vstate_multi(struct pipe_context *pipe, void *call, uint64_t *last)
+{
+ struct tc_draw_vstate_multi *info = (struct tc_draw_vstate_multi*)call;
+
+ pipe->draw_vertex_state(pipe, info->state, info->partial_velem_mask,
+ info->info, info->slot, info->num_draws);
+ tc_drop_vertex_state_references(info->state, 1);
+ return info->base.num_slots;
+}
+
+static void
+tc_draw_vertex_state(struct pipe_context *_pipe,
+ struct pipe_vertex_state *state,
+ uint32_t partial_velem_mask,
+ struct pipe_draw_vertex_state_info info,
+ const struct pipe_draw_start_count_bias *draws,
+ unsigned num_draws)
+{
+ struct threaded_context *tc = threaded_context(_pipe);
+
+ if (unlikely(tc->add_all_gfx_bindings_to_buffer_list))
+ tc_add_all_gfx_bindings_to_buffer_list(tc);
+
+ if (num_draws == 1) {
+ /* Single draw. */
+ struct tc_draw_vstate_single *p =
+ tc_add_call(tc, TC_CALL_draw_vstate_single, tc_draw_vstate_single);
+ p->partial_velem_mask = partial_velem_mask;
+ p->draw = draws[0];
+ p->info.mode = info.mode;
+ p->info.take_vertex_state_ownership = false;
+
+ /* This should be always 0 for simplicity because we assume that
+ * index_bias doesn't vary.
+ */
+ assert(draws[0].index_bias == 0);
+
+ if (!info.take_vertex_state_ownership)
+ tc_set_vertex_state_reference(&p->state, state);
+ else
+ p->state = state;
+ return;
+ }
+
+ const int draw_overhead_bytes = sizeof(struct tc_draw_vstate_multi);
+ const int one_draw_slot_bytes = sizeof(((struct tc_draw_vstate_multi*)NULL)->slot[0]);
+ const int slots_for_one_draw = DIV_ROUND_UP(draw_overhead_bytes + one_draw_slot_bytes,
+ sizeof(struct tc_call_base));
+ /* Multi draw. */
+ int total_offset = 0;
+ bool take_vertex_state_ownership = info.take_vertex_state_ownership;
+ while (num_draws) {
+ struct tc_batch *next = &tc->batch_slots[tc->next];
+
+ int nb_slots_left = TC_SLOTS_PER_BATCH - next->num_total_slots;
+ /* If there isn't enough place for one draw, try to fill the next one */
+ if (nb_slots_left < slots_for_one_draw)
+ nb_slots_left = TC_SLOTS_PER_BATCH;
+ const int size_left_bytes = nb_slots_left * sizeof(struct tc_call_base);
+
+ /* How many draws can we fit in the current batch */
+ const int dr = MIN2(num_draws, (size_left_bytes - draw_overhead_bytes) / one_draw_slot_bytes);
+
+ /* Non-indexed call or indexed with a real index buffer. */
+ struct tc_draw_vstate_multi *p =
+ tc_add_slot_based_call(tc, TC_CALL_draw_vstate_multi, tc_draw_vstate_multi, dr);
+
+ if (!take_vertex_state_ownership)
+ tc_set_vertex_state_reference(&p->state, state);
+ else
+ p->state = state;
+
+ take_vertex_state_ownership = false;
+ p->info.mode = info.mode;
+ p->info.take_vertex_state_ownership = false;
+ p->num_draws = dr;
+ memcpy(p->slot, &draws[total_offset], sizeof(draws[0]) * dr);
+ num_draws -= dr;
+
+ total_offset += dr;
+ }
+}
+
struct tc_launch_grid_call {
struct tc_call_base base;
struct pipe_grid_info info;
@@ -4102,6 +4284,7 @@ threaded_context_create(struct pipe_context *pipe,
CTX_INIT(flush);
CTX_INIT(draw_vbo);
+ CTX_INIT(draw_vertex_state);
CTX_INIT(launch_grid);
CTX_INIT(resource_copy_region);
CTX_INIT(blit);
diff --git a/src/gallium/auxiliary/util/u_threaded_context_calls.h b/src/gallium/auxiliary/util/u_threaded_context_calls.h
index a425852211c..ab78d3de3ae 100644
--- a/src/gallium/auxiliary/util/u_threaded_context_calls.h
+++ b/src/gallium/auxiliary/util/u_threaded_context_calls.h
@@ -33,6 +33,8 @@ CALL(draw_single)
CALL(draw_single_drawid)
CALL(draw_multi)
CALL(draw_indirect)
+CALL(draw_vstate_single)
+CALL(draw_vstate_multi)
CALL(launch_grid)
CALL(resource_copy_region)
CALL(blit)
More information about the mesa-commit
mailing list