diff --git a/src/gallium/drivers/d3d12/d3d12_query.cpp b/src/gallium/drivers/d3d12/d3d12_query.cpp index e58a4f16b12..d821fe819f9 100644 --- a/src/gallium/drivers/d3d12/d3d12_query.cpp +++ b/src/gallium/drivers/d3d12/d3d12_query.cpp @@ -203,7 +203,11 @@ accumulate_subresult_cpu(struct d3d12_context *ctx, struct d3d12_query *q_parent unsigned access = PIPE_MAP_READ; void *results; - access |= PIPE_MAP_UNSYNCHRONIZED; + /* When called from tc_get_query_result on the app thread (flushed query), + * the driver thread may be running concurrently. Use PIPE_MAP_THREAD_SAFE + * to avoid slab allocator races on transfer_pool. + */ + access |= PIPE_MAP_UNSYNCHRONIZED | PIPE_MAP_THREAD_SAFE; results = pipe_buffer_map_range(&ctx->base, q->buffer, q->buffer_offset, q->num_queries * q->query_size, diff --git a/src/gallium/drivers/d3d12/d3d12_resource.cpp b/src/gallium/drivers/d3d12/d3d12_resource.cpp index 88be1bce21e..2c4d500537c 100644 --- a/src/gallium/drivers/d3d12/d3d12_resource.cpp +++ b/src/gallium/drivers/d3d12/d3d12_resource.cpp @@ -1782,9 +1782,15 @@ d3d12_transfer_map(struct pipe_context *pctx, if (usage & PIPE_MAP_DIRECTLY || !res->bo) return NULL; - slab_child_pool* transfer_pool = (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) ? - &ctx->transfer_pool_unsync : &ctx->transfer_pool; - struct d3d12_transfer *trans = (struct d3d12_transfer *)slab_zalloc(transfer_pool); + slab_child_pool* transfer_pool = NULL; + struct d3d12_transfer *trans; + if (usage & PIPE_MAP_THREAD_SAFE) { + trans = (struct d3d12_transfer *)CALLOC_STRUCT(d3d12_transfer); + } else { + transfer_pool = (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) ? + &ctx->transfer_pool_unsync : &ctx->transfer_pool; + trans = (struct d3d12_transfer *)slab_zalloc(transfer_pool); + } struct pipe_transfer *ptrans = &trans->base.b; if (!trans) return NULL; @@ -1810,7 +1816,10 @@ d3d12_transfer_map(struct pipe_context *pctx, range = linear_range(box, ptrans->stride, ptrans->layer_stride); if (!synchronize(ctx, res, usage, &range)) { - slab_free(transfer_pool, trans); + if (usage & PIPE_MAP_THREAD_SAFE) + FREE(trans); + else + slab_free(transfer_pool, trans); return NULL; } ptr = d3d12_bo_map(res->bo, &range); @@ -1934,7 +1943,10 @@ d3d12_transfer_map(struct pipe_context *pctx, staging_usage, staging_res_size); if (!trans->staging_res) { - slab_free(transfer_pool, trans); + if (usage & PIPE_MAP_THREAD_SAFE) + FREE(trans); + else + slab_free(transfer_pool, trans); return NULL; } @@ -2062,7 +2074,15 @@ d3d12_transfer_unmap(struct pipe_context *pctx, } pipe_resource_reference(&ptrans->resource, NULL); - slab_free(&d3d12_context(pctx)->transfer_pool, ptrans); + if (ptrans->usage & PIPE_MAP_THREAD_SAFE) { + FREE(ptrans); + } else { + /* transfer_unmap is always called from the driver thread, so we use + * transfer_pool, not transfer_pool_unsync. Freeing an object into a + * different pool is allowed, however. + */ + slab_free(&d3d12_context(pctx)->transfer_pool, ptrans); + } } void