gallium/u_vbuf: use signed vertex buffers offsets for optimal uploads
authorMarek Olšák <marek.olsak@amd.com>
Thu, 26 Oct 2017 01:17:29 +0000 (03:17 +0200)
committerMarek Olšák <marek.olsak@amd.com>
Mon, 6 Nov 2017 18:09:12 +0000 (19:09 +0100)
Uploaded data must start at (stride * start), because we can't modify
start in all cases. If it's the first allocation, it's also the amount
of memory wasted. If the starting offset is larger than the size of
the upload buffer, the buffer is re-created, used for 1 upload, and then
thrown away. If the upload is small, most of the buffer space is unused
and wasted. Keep doing that and the OOM killer comes. It's actually
pretty quick.

With signed VB offsets, we can set min_out_offset = 0
in u_upload_alloc/u_upload_data.

This fixes OOM situations with SPECviewperf.

src/gallium/auxiliary/util/u_vbuf.c

index 80c30acc76752a4e2a755d843279e257534f0ac9..d30a702210acaf5f9e62d0224299b712b982c2be 100644 (file)
@@ -142,6 +142,7 @@ enum {
 
 struct u_vbuf {
    struct u_vbuf_caps caps;
+   bool has_signed_vb_offset;
 
    struct pipe_context *pipe;
    struct translate_cache *translate_cache;
@@ -311,6 +312,10 @@ u_vbuf_create(struct pipe_context *pipe,
    mgr->translate_cache = translate_cache_create();
    memset(mgr->fallback_vbs, ~0, sizeof(mgr->fallback_vbs));
 
+   mgr->has_signed_vb_offset =
+      pipe->screen->get_param(pipe->screen,
+                              PIPE_CAP_SIGNED_VERTEX_BUFFER_OFFSET);
+
    return mgr;
 }
 
@@ -486,7 +491,8 @@ u_vbuf_translate_buffers(struct u_vbuf *mgr, struct translate_key *key,
    } else {
       /* Create and map the output buffer. */
       u_upload_alloc(mgr->pipe->stream_uploader,
-                     key->output_stride * start_vertex,
+                     mgr->has_signed_vb_offset ?
+                        0 : key->output_stride * start_vertex,
                      key->output_stride * num_vertices, 4,
                      &out_offset, &out_buffer,
                      (void**)&out_map);
@@ -970,7 +976,9 @@ u_vbuf_upload_buffers(struct u_vbuf *mgr,
       real_vb = &mgr->real_vertex_buffer[i];
       ptr = mgr->vertex_buffer[i].buffer.user;
 
-      u_upload_data(mgr->pipe->stream_uploader, start, end - start, 4,
+      u_upload_data(mgr->pipe->stream_uploader,
+                    mgr->has_signed_vb_offset ? 0 : start,
+                    end - start, 4,
                     ptr + start, &real_vb->buffer_offset, &real_vb->buffer.resource);
       if (!real_vb->buffer.resource)
          return PIPE_ERROR_OUT_OF_MEMORY;