#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.
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;
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)
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];
}
}
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];
}
}
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];
}
}
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) {
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; \
/* 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;