u_prim_restart: handle indirect draws
authorMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Sat, 11 Jul 2020 15:19:43 +0000 (11:19 -0400)
committerMarge Bot <eric+marge@anholt.net>
Thu, 30 Jul 2020 19:34:03 +0000 (19:34 +0000)
this is pretty gross, but we need to map the indirect buffer to get the
index info and then use that for mapping the index buffer and translating
the restart index

Reviewed-by: Dave Airlie <airlied@redhat.com>
Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5886>

src/gallium/auxiliary/util/u_prim_restart.c

index 188f49e34c453f808b655bf827446bbdc5d1ce49..a6bfa16dc57587326e598797cd365662135e8ad5 100644 (file)
 #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;