diff --git a/src/gallium/auxiliary/util/u_draw.c b/src/gallium/auxiliary/util/u_draw.c index 57c78a9b859..d65ac6a6497 100644 --- a/src/gallium/auxiliary/util/u_draw.c +++ b/src/gallium/auxiliary/util/u_draw.c @@ -125,6 +125,66 @@ util_draw_max_index( return max_index + 1; } +struct u_indirect_params * +util_draw_indirect_read(struct pipe_context *pipe, + const struct pipe_draw_info *info_in, + const struct pipe_draw_indirect_info *indirect, + unsigned *num_draws) +{ + struct pipe_transfer *transfer; + uint32_t *params; + struct u_indirect_params *draws; + unsigned num_params = info_in->index_size ? 5 : 4; + + assert(indirect); + assert(!indirect->count_from_stream_output); + + uint32_t draw_count = indirect->draw_count; + if (indirect->indirect_draw_count) { + struct pipe_transfer *dc_transfer; + uint32_t *dc_param = pipe_buffer_map_range(pipe, + indirect->indirect_draw_count, + indirect->indirect_draw_count_offset, + 4, PIPE_MAP_READ, &dc_transfer); + if (!dc_transfer) { + debug_printf("%s: failed to map indirect draw count buffer\n", __FUNCTION__); + return NULL; + } + if (dc_param[0] < draw_count) + draw_count = dc_param[0]; + pipe_buffer_unmap(pipe, dc_transfer); + } + draws = malloc(sizeof(struct u_indirect_params) * draw_count); + if (!draws) + return NULL; + + if (indirect->stride) + num_params = MIN2(indirect->stride / 4, num_params); + params = pipe_buffer_map_range(pipe, + indirect->buffer, + indirect->offset, + (num_params * indirect->draw_count) * sizeof(uint32_t), + PIPE_MAP_READ, + &transfer); + if (!transfer) { + debug_printf("%s: failed to map indirect buffer\n", __FUNCTION__); + free(draws); + return NULL; + } + + for (unsigned i = 0; i < draw_count; i++) { + memcpy(&draws[i].info, info_in, sizeof(struct pipe_draw_info)); + draws[i].draw.count = params[0]; + draws[i].info.instance_count = params[1]; + draws[i].draw.start = params[2]; + draws[i].draw.index_bias = info_in->index_size ? params[3] : 0; + draws[i].info.start_instance = info_in->index_size ? params[4] : params[3]; + params += indirect->stride / 4; + } + pipe_buffer_unmap(pipe, transfer); + *num_draws = draw_count; + return draws; +} /* This extracts the draw arguments from the indirect resource, * puts them into a new instance of pipe_draw_info, and calls draw_vbo on it. diff --git a/src/gallium/auxiliary/util/u_draw.h b/src/gallium/auxiliary/util/u_draw.h index 6231d73dd29..7924061aed5 100644 --- a/src/gallium/auxiliary/util/u_draw.h +++ b/src/gallium/auxiliary/util/u_draw.h @@ -148,6 +148,17 @@ util_draw_elements_instanced(struct pipe_context *pipe, pipe->draw_vbo(pipe, &info, 0, NULL, &draw, 1); } +struct u_indirect_params { + struct pipe_draw_info info; + struct pipe_draw_start_count_bias draw; +}; + +/* caller must free the return value */ +struct u_indirect_params * +util_draw_indirect_read(struct pipe_context *pipe, + const struct pipe_draw_info *info_in, + const struct pipe_draw_indirect_info *indirect, + unsigned *num_draws); /* This converts an indirect draw into a direct draw by mapping the indirect * buffer, extracting its arguments, and calling pipe->draw_vbo.