diff --git a/src/gallium/auxiliary/util/u_prim_restart.c b/src/gallium/auxiliary/util/u_prim_restart.c index 188f49e34c4..a6bfa16dc57 100644 --- a/src/gallium/auxiliary/util/u_prim_restart.c +++ b/src/gallium/auxiliary/util/u_prim_restart.c @@ -29,6 +29,33 @@ #include "util/u_memory.h" #include "u_prim_restart.h" +typedef struct { + uint32_t count; + uint32_t primCount; + uint32_t firstIndex; + int32_t baseVertex; + uint32_t reservedMustBeZero; +} DrawElementsIndirectCommand; + +static DrawElementsIndirectCommand +read_indirect_elements(struct pipe_context *context, struct pipe_draw_indirect_info *indirect) +{ + DrawElementsIndirectCommand ret; + struct pipe_transfer *transfer = NULL; + void *map = NULL; + /* we only need the first 3 members */ + unsigned read_size = 3 * sizeof(uint32_t); + assert(indirect->buffer->width0 > 3 * sizeof(uint32_t)); + map = pipe_buffer_map_range(context, indirect->buffer, + indirect->offset, + read_size, + PIPE_TRANSFER_READ, + &transfer); + assert(map); + memcpy(&ret, map, read_size); + pipe_buffer_unmap(context, transfer); + return ret; +} /** * Translate an index buffer for primitive restart. @@ -47,15 +74,24 @@ util_translate_prim_restart_ib(struct pipe_context *context, void *src_map = NULL, *dst_map = NULL; const unsigned src_index_size = info->index_size; unsigned dst_index_size; + DrawElementsIndirectCommand indirect; + unsigned count = info->count; + unsigned start = info->start; /* 1-byte indexes are converted to 2-byte indexes, 4-byte stays 4-byte */ dst_index_size = MAX2(2, info->index_size); assert(dst_index_size == 2 || dst_index_size == 4); + if (info->indirect) { + indirect = read_indirect_elements(context, info->indirect); + count = indirect.count; + start = indirect.firstIndex; + } + /* Create new index buffer */ *dst_buffer = pipe_buffer_create(screen, PIPE_BIND_INDEX_BUFFER, PIPE_USAGE_STREAM, - info->count * dst_index_size); + count * dst_index_size); if (!*dst_buffer) goto error; @@ -66,12 +102,12 @@ util_translate_prim_restart_ib(struct pipe_context *context, goto error; if (info->has_user_indices) - src_map = (unsigned char*)info->index.user + info->start * src_index_size; + src_map = (unsigned char*)info->index.user + start * src_index_size; else /* Map original / src index buffer */ src_map = pipe_buffer_map_range(context, info->index.resource, - info->start * src_index_size, - info->count * src_index_size, + start * src_index_size, + count * src_index_size, PIPE_TRANSFER_READ, &src_transfer); if (!src_map) @@ -81,7 +117,7 @@ util_translate_prim_restart_ib(struct pipe_context *context, uint8_t *src = (uint8_t *) src_map; uint16_t *dst = (uint16_t *) dst_map; unsigned i; - for (i = 0; i < info->count; i++) { + for (i = 0; i < count; i++) { dst[i] = (src[i] == info->restart_index) ? 0xffff : src[i]; } } @@ -89,7 +125,7 @@ util_translate_prim_restart_ib(struct pipe_context *context, uint16_t *src = (uint16_t *) src_map; uint16_t *dst = (uint16_t *) dst_map; unsigned i; - for (i = 0; i < info->count; i++) { + for (i = 0; i < count; i++) { dst[i] = (src[i] == info->restart_index) ? 0xffff : src[i]; } } @@ -99,7 +135,7 @@ util_translate_prim_restart_ib(struct pipe_context *context, unsigned i; assert(src_index_size == 4); assert(dst_index_size == 4); - for (i = 0; i < info->count; i++) { + for (i = 0; i < count; i++) { dst[i] = (src[i] == info->restart_index) ? 0xffffffff : src[i]; } } @@ -183,16 +219,27 @@ util_draw_vbo_without_prim_restart(struct pipe_context *context, struct pipe_draw_info new_info; struct pipe_transfer *src_transfer = NULL; unsigned i, start, count; + DrawElementsIndirectCommand indirect; + unsigned info_start = info->start; + unsigned info_count = info->count; + unsigned info_instance_count = info->instance_count; assert(info->index_size); assert(info->primitive_restart); + if (info->indirect) { + indirect = read_indirect_elements(context, info->indirect); + info_count = indirect.count; + info_start = indirect.firstIndex; + info_instance_count = indirect.primCount; + } + /* Get pointer to the index data */ if (!info->has_user_indices) { /* map the index buffer (only the range we need to scan) */ src_map = pipe_buffer_map_range(context, info->index.resource, - info->start * info->index_size, - info->count * info->index_size, + info_start * info->index_size, + info_count * info->index_size, PIPE_TRANSFER_READ, &src_transfer); if (!src_map) { @@ -205,16 +252,16 @@ util_draw_vbo_without_prim_restart(struct pipe_context *context, return PIPE_ERROR_BAD_INPUT; } src_map = (const uint8_t *) info->index.user - + info->start * info->index_size; + + info_start * info->index_size; } #define SCAN_INDEXES(TYPE) \ - for (i = 0; i <= info->count; i++) { \ - if (i == info->count || \ + for (i = 0; i <= info_count; i++) { \ + if (i == info_count || \ ((const TYPE *) src_map)[i] == info->restart_index) { \ /* cut / restart */ \ if (count > 0) { \ - if (!add_range(&ranges, info->start + start, count)) { \ + if (!add_range(&ranges, info_start + start, count)) { \ if (src_transfer) \ pipe_buffer_unmap(context, src_transfer); \ return PIPE_ERROR_OUT_OF_MEMORY; \ @@ -251,6 +298,9 @@ util_draw_vbo_without_prim_restart(struct pipe_context *context, /* draw ranges between the restart indexes */ new_info = *info; + /* we've effectively remapped this to a direct draw */ + new_info.indirect = NULL; + new_info.instance_count = info_instance_count; new_info.primitive_restart = FALSE; for (i = 0; i < ranges.count; i++) { new_info.start = ranges.ranges[i].start;