radeonsi: handle MultiDrawIndirect in si_get_draw_start_count
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Mon, 20 Feb 2017 09:46:13 +0000 (10:46 +0100)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Tue, 21 Feb 2017 09:45:02 +0000 (10:45 +0100)
Also handle the GL_ARB_indirect_parameters case where the count itself
is in a buffer.

Use transfers rather than mapping the buffers directly. This anticipates
the possibility that the buffers are sparse (once ARB_sparse_buffer is
implemented), in which case they cannot be mapped directly.

Fixes GL45-CTS.gtf43.GL3Tests.multi_draw_indirect.multi_draw_indirect_type
on <= CIK.

v2:
- unmap the indirect buffer correctly
- handle the corner case where we have indirect draws, but all of them
  have count 0.

Cc: mesa-stable@lists.freedesktop.org
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Acked-by: Edward O'Callaghan <funfunctor@folklore1984.net>
src/gallium/drivers/radeonsi/si_state_draw.c

index 141dd8f7526aff1e7b7c23be4327346b1e745ea2..1ff1547efe77bb8fc5716e652874eb01794762c7 100644 (file)
@@ -914,13 +914,59 @@ static void si_get_draw_start_count(struct si_context *sctx,
                                    unsigned *start, unsigned *count)
 {
        if (info->indirect) {
-               struct r600_resource *indirect =
-                       (struct r600_resource*)info->indirect;
-               int *data = r600_buffer_map_sync_with_rings(&sctx->b,
-                                       indirect, PIPE_TRANSFER_READ);
-                data += info->indirect_offset/sizeof(int);
-               *start = data[2];
-               *count = data[0];
+               unsigned indirect_count;
+               struct pipe_transfer *transfer;
+               unsigned begin, end;
+               unsigned map_size;
+               unsigned *data;
+
+               if (info->indirect_params) {
+                       data = pipe_buffer_map_range(&sctx->b.b,
+                                       info->indirect_params,
+                                       info->indirect_params_offset,
+                                       sizeof(unsigned),
+                                       PIPE_TRANSFER_READ, &transfer);
+
+                       indirect_count = *data;
+
+                       pipe_buffer_unmap(&sctx->b.b, transfer);
+               } else {
+                       indirect_count = info->indirect_count;
+               }
+
+               if (!indirect_count) {
+                       *start = *count = 0;
+                       return;
+               }
+
+               map_size = (indirect_count - 1) * info->indirect_stride + 3 * sizeof(unsigned);
+               data = pipe_buffer_map_range(&sctx->b.b, info->indirect,
+                                            info->indirect_offset, map_size,
+                                            PIPE_TRANSFER_READ, &transfer);
+
+               begin = UINT_MAX;
+               end = 0;
+
+               for (unsigned i = 0; i < indirect_count; ++i) {
+                       unsigned count = data[0];
+                       unsigned start = data[2];
+
+                       if (count > 0) {
+                               begin = MIN2(begin, start);
+                               end = MAX2(end, start + count);
+                       }
+
+                       data += info->indirect_stride / sizeof(unsigned);
+               }
+
+               pipe_buffer_unmap(&sctx->b.b, transfer);
+
+               if (begin < end) {
+                       *start = begin;
+                       *count = end - begin;
+               } else {
+                       *start = *count = 0;
+               }
        } else {
                *start = info->start;
                *count = info->count;