Mesa (main): util/vbuf: handle multidraws
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Fri Jul 22 13:28:35 UTC 2022
Module: Mesa
Branch: main
Commit: 6b07893b31fe4e6cac7bc73155770672ce7753cb
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=6b07893b31fe4e6cac7bc73155770672ce7753cb
Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date: Thu Jul 21 12:48:17 2022 -0400
util/vbuf: handle multidraws
this moves the handling from cso_conext to vbuf, which reduces overhead
for draws that aren't rewritten
Reviewed-by: Marek Olšák <marek.olsak at amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17686>
---
src/gallium/auxiliary/cso_cache/cso_context.c | 16 +-
src/gallium/auxiliary/util/u_vbuf.c | 501 +++++++++++++-------------
src/gallium/auxiliary/util/u_vbuf.h | 3 +-
3 files changed, 260 insertions(+), 260 deletions(-)
diff --git a/src/gallium/auxiliary/cso_cache/cso_context.c b/src/gallium/auxiliary/cso_cache/cso_context.c
index 2684c75e1ce..b09643dcd8a 100644
--- a/src/gallium/auxiliary/cso_cache/cso_context.c
+++ b/src/gallium/auxiliary/cso_cache/cso_context.c
@@ -1642,7 +1642,7 @@ cso_draw_vbo(struct cso_context *cso,
indirect->count_from_stream_output == NULL);
if (vbuf) {
- u_vbuf_draw_vbo(vbuf, info, drawid_offset, indirect, draw);
+ u_vbuf_draw_vbo(vbuf, info, drawid_offset, indirect, &draw, 1);
} else {
struct pipe_context *pipe = cso->pipe;
pipe->draw_vbo(pipe, info, drawid_offset, indirect, &draw, 1);
@@ -1660,19 +1660,7 @@ cso_multi_draw(struct cso_context *cso,
struct u_vbuf *vbuf = cso->vbuf_current;
if (vbuf) {
- /* Increase refcount to be able to use take_index_buffer_ownership with
- * all draws.
- */
- if (num_draws > 1 && info->take_index_buffer_ownership)
- p_atomic_add(&info->index.resource->reference.count, num_draws - 1);
-
- unsigned drawid = drawid_offset;
- for (unsigned i = 0; i < num_draws; i++) {
- u_vbuf_draw_vbo(vbuf, info, drawid, NULL, draws[i]);
-
- if (info->increment_draw_id)
- drawid++;
- }
+ u_vbuf_draw_vbo(vbuf, info, drawid_offset, NULL, draws, num_draws);
} else {
struct pipe_context *pipe = cso->pipe;
diff --git a/src/gallium/auxiliary/util/u_vbuf.c b/src/gallium/auxiliary/util/u_vbuf.c
index 5e4f4f4b9c3..4a8f6cd284a 100644
--- a/src/gallium/auxiliary/util/u_vbuf.c
+++ b/src/gallium/auxiliary/util/u_vbuf.c
@@ -1450,14 +1450,15 @@ u_vbuf_split_indexed_multidraw(struct u_vbuf *mgr, struct pipe_draw_info *info,
draw.index_bias = indirect_data[offset + 3];
info->start_instance = indirect_data[offset + 4];
- u_vbuf_draw_vbo(mgr, info, drawid_offset, NULL, draw);
+ u_vbuf_draw_vbo(mgr, info, drawid_offset, NULL, &draw, 1);
}
}
void u_vbuf_draw_vbo(struct u_vbuf *mgr, const struct pipe_draw_info *info,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect,
- const struct pipe_draw_start_count_bias draw)
+ const struct pipe_draw_start_count_bias *draws,
+ unsigned num_draws)
{
struct pipe_context *pipe = mgr->pipe;
int start_vertex;
@@ -1495,287 +1496,297 @@ void u_vbuf_draw_vbo(struct u_vbuf *mgr, const struct pipe_draw_info *info,
u_vbuf_set_driver_vertex_buffers(mgr);
}
- pipe->draw_vbo(pipe, info, drawid_offset, indirect, &draw, 1);
+ pipe->draw_vbo(pipe, info, drawid_offset, indirect, draws, num_draws);
return;
}
+ /* Increase refcount to be able to use take_index_buffer_ownership with
+ * all draws.
+ */
+ if (num_draws > 1 && info->take_index_buffer_ownership)
+ p_atomic_add(&info->index.resource->reference.count, num_draws - 1);
new_info = *info;
- new_draw = draw;
- /* Handle indirect (multi)draws. */
- if (indirect && indirect->buffer) {
- unsigned draw_count = 0;
+ for (unsigned d = 0; d < num_draws; d++) {
+ new_draw = draws[d];
+ if (info->increment_draw_id)
+ drawid_offset++;
- /* Get the number of draws. */
- if (indirect->indirect_draw_count) {
- pipe_buffer_read(pipe, indirect->indirect_draw_count,
- indirect->indirect_draw_count_offset,
- 4, &draw_count);
- } else {
- draw_count = indirect->draw_count;
- }
+ /* Handle indirect (multi)draws. */
+ if (indirect && indirect->buffer) {
+ unsigned draw_count = 0;
- if (!draw_count)
- goto cleanup;
+ /* Get the number of draws. */
+ if (indirect->indirect_draw_count) {
+ pipe_buffer_read(pipe, indirect->indirect_draw_count,
+ indirect->indirect_draw_count_offset,
+ 4, &draw_count);
+ } else {
+ draw_count = indirect->draw_count;
+ }
- unsigned data_size = (draw_count - 1) * indirect->stride +
- (new_info.index_size ? 20 : 16);
- unsigned *data = malloc(data_size);
- if (!data)
- goto cleanup; /* report an error? */
+ if (!draw_count)
+ goto cleanup;
- /* Read the used buffer range only once, because the read can be
- * uncached.
- */
- pipe_buffer_read(pipe, indirect->buffer, indirect->offset, data_size,
- data);
-
- if (info->index_size) {
- /* Indexed multidraw. */
- unsigned index_bias0 = data[3];
- bool index_bias_same = true;
-
- /* If we invoke the translate path, we have to split the multidraw. */
- if (incompatible_vb_mask ||
- mgr->ve->incompatible_elem_mask) {
- u_vbuf_split_indexed_multidraw(mgr, &new_info, drawid_offset, data,
- indirect->stride, draw_count);
- free(data);
- return;
- }
+ unsigned data_size = (draw_count - 1) * indirect->stride +
+ (new_info.index_size ? 20 : 16);
+ unsigned *data = malloc(data_size);
+ if (!data)
+ goto cleanup; /* report an error? */
- /* See if index_bias is the same for all draws. */
- for (unsigned i = 1; i < draw_count; i++) {
- if (data[i * indirect->stride / 4 + 3] != index_bias0) {
- index_bias_same = false;
- break;
+ /* Read the used buffer range only once, because the read can be
+ * uncached.
+ */
+ pipe_buffer_read(pipe, indirect->buffer, indirect->offset, data_size,
+ data);
+
+ if (info->index_size) {
+ /* Indexed multidraw. */
+ unsigned index_bias0 = data[3];
+ bool index_bias_same = true;
+
+ /* If we invoke the translate path, we have to split the multidraw. */
+ if (incompatible_vb_mask ||
+ mgr->ve->incompatible_elem_mask) {
+ u_vbuf_split_indexed_multidraw(mgr, &new_info, drawid_offset, data,
+ indirect->stride, draw_count);
+ free(data);
+ return;
}
- }
- /* Split the multidraw if index_bias is different. */
- if (!index_bias_same) {
- u_vbuf_split_indexed_multidraw(mgr, &new_info, drawid_offset, data,
- indirect->stride, draw_count);
- free(data);
- return;
- }
+ /* See if index_bias is the same for all draws. */
+ for (unsigned i = 1; i < draw_count; i++) {
+ if (data[i * indirect->stride / 4 + 3] != index_bias0) {
+ index_bias_same = false;
+ break;
+ }
+ }
- /* If we don't need to use the translate path and index_bias is
- * the same, we can process the multidraw with the time complexity
- * equal to 1 draw call (except for the index range computation).
- * We only need to compute the index range covering all draw calls
- * of the multidraw.
- *
- * The driver will not look at these values because indirect != NULL.
- * These values determine the user buffer bounds to upload.
- */
- new_draw.index_bias = index_bias0;
- new_info.index_bounds_valid = true;
- new_info.min_index = ~0u;
- new_info.max_index = 0;
- new_info.start_instance = ~0u;
- unsigned end_instance = 0;
-
- struct pipe_transfer *transfer = NULL;
- const uint8_t *indices;
-
- if (info->has_user_indices) {
- indices = (uint8_t*)info->index.user;
- } else {
- indices = (uint8_t*)pipe_buffer_map(pipe, info->index.resource,
- PIPE_MAP_READ, &transfer);
- }
+ /* Split the multidraw if index_bias is different. */
+ if (!index_bias_same) {
+ u_vbuf_split_indexed_multidraw(mgr, &new_info, drawid_offset, data,
+ indirect->stride, draw_count);
+ free(data);
+ return;
+ }
- for (unsigned i = 0; i < draw_count; i++) {
- unsigned offset = i * indirect->stride / 4;
- unsigned start = data[offset + 2];
- unsigned count = data[offset + 0];
- unsigned start_instance = data[offset + 4];
- unsigned instance_count = data[offset + 1];
-
- if (!count || !instance_count)
- continue;
-
- /* Update the ranges of instances. */
- new_info.start_instance = MIN2(new_info.start_instance,
- start_instance);
- end_instance = MAX2(end_instance, start_instance + instance_count);
-
- /* Update the index range. */
- unsigned min, max;
- u_vbuf_get_minmax_index_mapped(&new_info, count,
- indices +
- new_info.index_size * start,
- &min, &max);
-
- new_info.min_index = MIN2(new_info.min_index, min);
- new_info.max_index = MAX2(new_info.max_index, max);
- }
- free(data);
+ /* If we don't need to use the translate path and index_bias is
+ * the same, we can process the multidraw with the time complexity
+ * equal to 1 draw call (except for the index range computation).
+ * We only need to compute the index range covering all draw calls
+ * of the multidraw.
+ *
+ * The driver will not look at these values because indirect != NULL.
+ * These values determine the user buffer bounds to upload.
+ */
+ new_draw.index_bias = index_bias0;
+ new_info.index_bounds_valid = true;
+ new_info.min_index = ~0u;
+ new_info.max_index = 0;
+ new_info.start_instance = ~0u;
+ unsigned end_instance = 0;
+
+ struct pipe_transfer *transfer = NULL;
+ const uint8_t *indices;
+
+ if (info->has_user_indices) {
+ indices = (uint8_t*)info->index.user;
+ } else {
+ indices = (uint8_t*)pipe_buffer_map(pipe, info->index.resource,
+ PIPE_MAP_READ, &transfer);
+ }
- if (transfer)
- pipe_buffer_unmap(pipe, transfer);
+ for (unsigned i = 0; i < draw_count; i++) {
+ unsigned offset = i * indirect->stride / 4;
+ unsigned start = data[offset + 2];
+ unsigned count = data[offset + 0];
+ unsigned start_instance = data[offset + 4];
+ unsigned instance_count = data[offset + 1];
+
+ if (!count || !instance_count)
+ continue;
+
+ /* Update the ranges of instances. */
+ new_info.start_instance = MIN2(new_info.start_instance,
+ start_instance);
+ end_instance = MAX2(end_instance, start_instance + instance_count);
+
+ /* Update the index range. */
+ unsigned min, max;
+ u_vbuf_get_minmax_index_mapped(&new_info, count,
+ indices +
+ new_info.index_size * start,
+ &min, &max);
+
+ new_info.min_index = MIN2(new_info.min_index, min);
+ new_info.max_index = MAX2(new_info.max_index, max);
+ }
+ free(data);
- /* Set the final instance count. */
- new_info.instance_count = end_instance - new_info.start_instance;
+ if (transfer)
+ pipe_buffer_unmap(pipe, transfer);
- if (new_info.start_instance == ~0u || !new_info.instance_count)
- goto cleanup;
- } else {
- /* Non-indexed multidraw.
- *
- * Keep the draw call indirect and compute minimums & maximums,
- * which will determine the user buffer bounds to upload, but
- * the driver will not look at these values because indirect != NULL.
- *
- * This efficiently processes the multidraw with the time complexity
- * equal to 1 draw call.
- */
- new_draw.start = ~0u;
- new_info.start_instance = ~0u;
- unsigned end_vertex = 0;
- unsigned end_instance = 0;
-
- for (unsigned i = 0; i < draw_count; i++) {
- unsigned offset = i * indirect->stride / 4;
- unsigned start = data[offset + 2];
- unsigned count = data[offset + 0];
- unsigned start_instance = data[offset + 3];
- unsigned instance_count = data[offset + 1];
-
- new_draw.start = MIN2(new_draw.start, start);
- new_info.start_instance = MIN2(new_info.start_instance,
- start_instance);
-
- end_vertex = MAX2(end_vertex, start + count);
- end_instance = MAX2(end_instance, start_instance + instance_count);
- }
- free(data);
+ /* Set the final instance count. */
+ new_info.instance_count = end_instance - new_info.start_instance;
- /* Set the final counts. */
- new_draw.count = end_vertex - new_draw.start;
- new_info.instance_count = end_instance - new_info.start_instance;
+ if (new_info.start_instance == ~0u || !new_info.instance_count)
+ goto cleanup;
+ } else {
+ /* Non-indexed multidraw.
+ *
+ * Keep the draw call indirect and compute minimums & maximums,
+ * which will determine the user buffer bounds to upload, but
+ * the driver will not look at these values because indirect != NULL.
+ *
+ * This efficiently processes the multidraw with the time complexity
+ * equal to 1 draw call.
+ */
+ new_draw.start = ~0u;
+ new_info.start_instance = ~0u;
+ unsigned end_vertex = 0;
+ unsigned end_instance = 0;
+
+ for (unsigned i = 0; i < draw_count; i++) {
+ unsigned offset = i * indirect->stride / 4;
+ unsigned start = data[offset + 2];
+ unsigned count = data[offset + 0];
+ unsigned start_instance = data[offset + 3];
+ unsigned instance_count = data[offset + 1];
+
+ new_draw.start = MIN2(new_draw.start, start);
+ new_info.start_instance = MIN2(new_info.start_instance,
+ start_instance);
+
+ end_vertex = MAX2(end_vertex, start + count);
+ end_instance = MAX2(end_instance, start_instance + instance_count);
+ }
+ free(data);
- if (new_draw.start == ~0u || !new_draw.count || !new_info.instance_count)
+ /* Set the final counts. */
+ new_draw.count = end_vertex - new_draw.start;
+ new_info.instance_count = end_instance - new_info.start_instance;
+
+ if (new_draw.start == ~0u || !new_draw.count || !new_info.instance_count)
+ goto cleanup;
+ }
+ } else {
+ if ((!indirect && !new_draw.count) || !new_info.instance_count)
goto cleanup;
}
- } else {
- if ((!indirect && !new_draw.count) || !new_info.instance_count)
- goto cleanup;
- }
- if (new_info.index_size) {
- /* See if anything needs to be done for per-vertex attribs. */
- if (u_vbuf_need_minmax_index(mgr, misaligned)) {
- unsigned max_index;
+ if (new_info.index_size) {
+ /* See if anything needs to be done for per-vertex attribs. */
+ if (u_vbuf_need_minmax_index(mgr, misaligned)) {
+ unsigned max_index;
+
+ if (new_info.index_bounds_valid) {
+ min_index = new_info.min_index;
+ max_index = new_info.max_index;
+ } else {
+ u_vbuf_get_minmax_index(mgr->pipe, &new_info, &new_draw,
+ &min_index, &max_index);
+ }
- if (new_info.index_bounds_valid) {
- min_index = new_info.min_index;
- max_index = new_info.max_index;
+ assert(min_index <= max_index);
+
+ start_vertex = min_index + new_draw.index_bias;
+ num_vertices = max_index + 1 - min_index;
+
+ /* Primitive restart doesn't work when unrolling indices.
+ * We would have to break this drawing operation into several ones. */
+ /* Use some heuristic to see if unrolling indices improves
+ * performance. */
+ if (!indirect &&
+ !new_info.primitive_restart &&
+ util_is_vbo_upload_ratio_too_large(new_draw.count, num_vertices) &&
+ !u_vbuf_mapping_vertex_buffer_blocks(mgr, misaligned)) {
+ unroll_indices = TRUE;
+ user_vb_mask &= ~(mgr->nonzero_stride_vb_mask &
+ mgr->ve->noninstance_vb_mask_any);
+ }
} else {
- u_vbuf_get_minmax_index(mgr->pipe, &new_info, &new_draw,
- &min_index, &max_index);
- }
-
- assert(min_index <= max_index);
-
- start_vertex = min_index + new_draw.index_bias;
- num_vertices = max_index + 1 - min_index;
-
- /* Primitive restart doesn't work when unrolling indices.
- * We would have to break this drawing operation into several ones. */
- /* Use some heuristic to see if unrolling indices improves
- * performance. */
- if (!indirect &&
- !new_info.primitive_restart &&
- util_is_vbo_upload_ratio_too_large(new_draw.count, num_vertices) &&
- !u_vbuf_mapping_vertex_buffer_blocks(mgr, misaligned)) {
- unroll_indices = TRUE;
- user_vb_mask &= ~(mgr->nonzero_stride_vb_mask &
- mgr->ve->noninstance_vb_mask_any);
+ /* Nothing to do for per-vertex attribs. */
+ start_vertex = 0;
+ num_vertices = 0;
+ min_index = 0;
}
} else {
- /* Nothing to do for per-vertex attribs. */
- start_vertex = 0;
- num_vertices = 0;
+ start_vertex = new_draw.start;
+ num_vertices = new_draw.count;
min_index = 0;
}
- } else {
- start_vertex = new_draw.start;
- num_vertices = new_draw.count;
- min_index = 0;
- }
- /* Translate vertices with non-native layouts or formats. */
- if (unroll_indices ||
- incompatible_vb_mask ||
- mgr->ve->incompatible_elem_mask) {
- if (!u_vbuf_translate_begin(mgr, &new_info, &new_draw,
- start_vertex, num_vertices,
- min_index, unroll_indices, misaligned)) {
- debug_warn_once("u_vbuf_translate_begin() failed");
- goto cleanup;
- }
+ /* Translate vertices with non-native layouts or formats. */
+ if (unroll_indices ||
+ incompatible_vb_mask ||
+ mgr->ve->incompatible_elem_mask) {
+ if (!u_vbuf_translate_begin(mgr, &new_info, &new_draw,
+ start_vertex, num_vertices,
+ min_index, unroll_indices, misaligned)) {
+ debug_warn_once("u_vbuf_translate_begin() failed");
+ goto cleanup;
+ }
- if (unroll_indices) {
- new_info.index_size = 0;
- new_draw.index_bias = 0;
- new_info.index_bounds_valid = true;
- new_info.min_index = 0;
- new_info.max_index = new_draw.count - 1;
- new_draw.start = 0;
+ if (unroll_indices) {
+ new_info.index_size = 0;
+ new_draw.index_bias = 0;
+ new_info.index_bounds_valid = true;
+ new_info.min_index = 0;
+ new_info.max_index = new_draw.count - 1;
+ new_draw.start = 0;
+ }
+
+ user_vb_mask &= ~(incompatible_vb_mask |
+ mgr->ve->incompatible_vb_mask_all);
}
- user_vb_mask &= ~(incompatible_vb_mask |
- mgr->ve->incompatible_vb_mask_all);
- }
+ /* Upload user buffers. */
+ if (user_vb_mask) {
+ if (u_vbuf_upload_buffers(mgr, start_vertex, num_vertices,
+ new_info.start_instance,
+ new_info.instance_count) != PIPE_OK) {
+ debug_warn_once("u_vbuf_upload_buffers() failed");
+ goto cleanup;
+ }
- /* Upload user buffers. */
- if (user_vb_mask) {
- if (u_vbuf_upload_buffers(mgr, start_vertex, num_vertices,
- new_info.start_instance,
- new_info.instance_count) != PIPE_OK) {
- debug_warn_once("u_vbuf_upload_buffers() failed");
- goto cleanup;
+ mgr->dirty_real_vb_mask |= user_vb_mask;
}
- mgr->dirty_real_vb_mask |= user_vb_mask;
- }
+ /*
+ if (unroll_indices) {
+ printf("unrolling indices: start_vertex = %i, num_vertices = %i\n",
+ start_vertex, num_vertices);
+ util_dump_draw_info(stdout, info);
+ printf("\n");
+ }
- /*
- if (unroll_indices) {
- printf("unrolling indices: start_vertex = %i, num_vertices = %i\n",
- start_vertex, num_vertices);
- util_dump_draw_info(stdout, info);
- printf("\n");
- }
+ unsigned i;
+ for (i = 0; i < mgr->nr_vertex_buffers; i++) {
+ printf("input %i: ", i);
+ util_dump_vertex_buffer(stdout, mgr->vertex_buffer+i);
+ printf("\n");
+ }
+ for (i = 0; i < mgr->nr_real_vertex_buffers; i++) {
+ printf("real %i: ", i);
+ util_dump_vertex_buffer(stdout, mgr->real_vertex_buffer+i);
+ printf("\n");
+ }
+ */
- unsigned i;
- for (i = 0; i < mgr->nr_vertex_buffers; i++) {
- printf("input %i: ", i);
- util_dump_vertex_buffer(stdout, mgr->vertex_buffer+i);
- printf("\n");
- }
- for (i = 0; i < mgr->nr_real_vertex_buffers; i++) {
- printf("real %i: ", i);
- util_dump_vertex_buffer(stdout, mgr->real_vertex_buffer+i);
- printf("\n");
+ u_upload_unmap(pipe->stream_uploader);
+ if (mgr->dirty_real_vb_mask)
+ u_vbuf_set_driver_vertex_buffers(mgr);
+
+ if ((new_info.index_size == 1 && mgr->caps.rewrite_ubyte_ibs) ||
+ (new_info.primitive_restart &&
+ ((new_info.restart_index != fixed_restart_index && mgr->caps.rewrite_restart_index) ||
+ !(mgr->caps.supported_restart_modes & BITFIELD_BIT(new_info.mode)))) ||
+ !(mgr->caps.supported_prim_modes & BITFIELD_BIT(new_info.mode))) {
+ util_primconvert_save_flatshade_first(mgr->pc, mgr->flatshade_first);
+ util_primconvert_draw_vbo(mgr->pc, &new_info, drawid_offset, indirect, &new_draw, 1);
+ } else
+ pipe->draw_vbo(pipe, &new_info, drawid_offset, indirect, &new_draw, 1);
}
- */
-
- u_upload_unmap(pipe->stream_uploader);
- if (mgr->dirty_real_vb_mask)
- u_vbuf_set_driver_vertex_buffers(mgr);
-
- if ((new_info.index_size == 1 && mgr->caps.rewrite_ubyte_ibs) ||
- (new_info.primitive_restart &&
- ((new_info.restart_index != fixed_restart_index && mgr->caps.rewrite_restart_index) ||
- !(mgr->caps.supported_restart_modes & BITFIELD_BIT(new_info.mode)))) ||
- !(mgr->caps.supported_prim_modes & BITFIELD_BIT(new_info.mode))) {
- util_primconvert_save_flatshade_first(mgr->pc, mgr->flatshade_first);
- util_primconvert_draw_vbo(mgr->pc, &new_info, drawid_offset, indirect, &new_draw, 1);
- } else
- pipe->draw_vbo(pipe, &new_info, drawid_offset, indirect, &new_draw, 1);
if (mgr->using_translate) {
u_vbuf_translate_end(mgr);
diff --git a/src/gallium/auxiliary/util/u_vbuf.h b/src/gallium/auxiliary/util/u_vbuf.h
index b0bd06bc979..2d6ca434df3 100644
--- a/src/gallium/auxiliary/util/u_vbuf.h
+++ b/src/gallium/auxiliary/util/u_vbuf.h
@@ -88,7 +88,8 @@ void u_vbuf_set_vertex_buffers(struct u_vbuf *mgr,
void u_vbuf_draw_vbo(struct u_vbuf *mgr, const struct pipe_draw_info *info,
unsigned drawid_offset,
const struct pipe_draw_indirect_info *indirect,
- const struct pipe_draw_start_count_bias draw);
+ const struct pipe_draw_start_count_bias *draws,
+ unsigned num_draws);
void u_vbuf_get_minmax_index(struct pipe_context *pipe,
const struct pipe_draw_info *info,
const struct pipe_draw_start_count_bias *draw,
More information about the mesa-commit
mailing list