r600g,radeonsi: attempt to fix racy multi-context apps calling BufferData
authorMarek Olšák <marek.olsak@amd.com>
Sat, 8 Mar 2014 22:34:36 +0000 (23:34 +0100)
committerMarek Olšák <marek.olsak@amd.com>
Tue, 11 Mar 2014 18:18:02 +0000 (19:18 +0100)
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=75061

v2: minimize the window where cs_buf != new_buf

src/gallium/drivers/r600/r600_state_common.c
src/gallium/drivers/radeon/r600_buffer_common.c
src/gallium/drivers/radeonsi/si_descriptors.c

index 96c18808ea8cbc3238c4c85533e04e3c70c940fe..7dbb0b777ed3e17c5ca65be8ae1677c565458ba8 100644 (file)
@@ -2292,10 +2292,7 @@ static void r600_invalidate_buffer(struct pipe_context *ctx, struct pipe_resourc
        struct r600_resource *rbuffer = r600_resource(buf);
        unsigned i, shader, mask, alignment = rbuffer->buf->alignment;
 
-       /* Discard the buffer. */
-       pb_reference(&rbuffer->buf, NULL);
-
-       /* Create a new one in the same pipe_resource. */
+       /* Reallocate the buffer in the same pipe_resource. */
        r600_init_resource(&rctx->screen->b, rbuffer, rbuffer->b.b.width0,
                           alignment, TRUE);
 
index d56a6441eae4d3b66f39e6b8137373b424168b3b..77e1b35862ad06c4ff44f78bdcae12d3a6a7d715 100644 (file)
@@ -106,6 +106,7 @@ bool r600_init_resource(struct r600_common_screen *rscreen,
                        bool use_reusable_pool)
 {
        struct r600_texture *rtex = (struct r600_texture*)res;
+       struct pb_buffer *old_buf, *new_buf;
 
        switch (res->b.b.usage) {
        case PIPE_USAGE_STAGING:
@@ -136,15 +137,23 @@ bool r600_init_resource(struct r600_common_screen *rscreen,
                res->domains = RADEON_DOMAIN_VRAM;
        }
 
-       /* Allocate the resource. */
-       res->buf = rscreen->ws->buffer_create(rscreen->ws, size, alignment,
-                                              use_reusable_pool,
-                                              res->domains);
-       if (!res->buf) {
+       /* Allocate a new resource. */
+       new_buf = rscreen->ws->buffer_create(rscreen->ws, size, alignment,
+                                            use_reusable_pool,
+                                            res->domains);
+       if (!new_buf) {
                return false;
        }
 
-       res->cs_buf = rscreen->ws->buffer_get_cs_handle(res->buf);
+       /* Replace the pointer such that if res->buf wasn't NULL, it won't be
+        * NULL. This should prevent crashes with multiple contexts using
+        * the same buffer where one of the contexts invalidates it while
+        * the others are using it. */
+       old_buf = res->buf;
+       res->cs_buf = rscreen->ws->buffer_get_cs_handle(new_buf); /* should be atomic */
+       res->buf = new_buf; /* should be atomic */
+       pb_reference(&old_buf, NULL);
+
        util_range_set_empty(&res->valid_buffer_range);
 
        if (rscreen->debug_flags & DBG_VM && res->b.b.target == PIPE_BUFFER) {
@@ -363,6 +372,7 @@ struct pipe_resource *r600_buffer_create(struct pipe_screen *screen,
        pipe_reference_init(&rbuffer->b.b.reference, 1);
        rbuffer->b.b.screen = screen;
        rbuffer->b.vtbl = &r600_buffer_vtbl;
+       rbuffer->buf = NULL;
        util_range_init(&rbuffer->valid_buffer_range);
 
        if (!r600_init_resource(rscreen, rbuffer, templ->width0, alignment, TRUE)) {
index bf2206dc1bc8485015658efbb95717e8dd578a55..0c58d5fd04585fb2dc555061d2561ad0a866a555 100644 (file)
@@ -723,10 +723,7 @@ static void si_invalidate_buffer(struct pipe_context *ctx, struct pipe_resource
        unsigned i, shader, alignment = rbuffer->buf->alignment;
        uint64_t old_va = r600_resource_va(ctx->screen, buf);
 
-       /* Discard the buffer. */
-       pb_reference(&rbuffer->buf, NULL);
-
-       /* Create a new one in the same pipe_resource. */
+       /* Reallocate the buffer in the same pipe_resource. */
        r600_init_resource(&sctx->screen->b, rbuffer, rbuffer->b.b.width0,
                           alignment, TRUE);