diff --git a/src/gallium/drivers/d3d12/d3d12_batch.cpp b/src/gallium/drivers/d3d12/d3d12_batch.cpp index 9cb571a19e6..406e5b0e672 100644 --- a/src/gallium/drivers/d3d12/d3d12_batch.cpp +++ b/src/gallium/drivers/d3d12/d3d12_batch.cpp @@ -136,6 +136,7 @@ d3d12_reset_batch(struct d3d12_context *ctx, struct d3d12_batch *batch, uint64_t return false; } batch->has_errors = false; + batch->pending_memory_barrier = false; return true; } diff --git a/src/gallium/drivers/d3d12/d3d12_batch.h b/src/gallium/drivers/d3d12/d3d12_batch.h index f49fe61179a..7eb29ad250b 100644 --- a/src/gallium/drivers/d3d12/d3d12_batch.h +++ b/src/gallium/drivers/d3d12/d3d12_batch.h @@ -53,6 +53,7 @@ struct d3d12_batch { struct d3d12_descriptor_heap *sampler_heap; struct d3d12_descriptor_heap *view_heap; bool has_errors; + bool pending_memory_barrier; }; bool diff --git a/src/gallium/drivers/d3d12/d3d12_context.cpp b/src/gallium/drivers/d3d12/d3d12_context.cpp index ff649a0cf67..b1e6065c3cb 100644 --- a/src/gallium/drivers/d3d12/d3d12_context.cpp +++ b/src/gallium/drivers/d3d12/d3d12_context.cpp @@ -2022,6 +2022,54 @@ d3d12_replace_buffer_storage(struct pipe_context *pctx, d3d12_bo_unreference(old_bo); } +static void +d3d12_memory_barrier(struct pipe_context *pctx, unsigned flags) +{ + struct d3d12_context *ctx = d3d12_context(pctx); + if (flags & PIPE_BARRIER_VERTEX_BUFFER) + ctx->state_dirty |= D3D12_DIRTY_VERTEX_BUFFERS; + if (flags & PIPE_BARRIER_INDEX_BUFFER) + ctx->state_dirty |= D3D12_DIRTY_INDEX_BUFFER; + if (flags & PIPE_BARRIER_FRAMEBUFFER) + ctx->state_dirty |= D3D12_DIRTY_FRAMEBUFFER; + if (flags & PIPE_BARRIER_STREAMOUT_BUFFER) + ctx->state_dirty |= D3D12_DIRTY_STREAM_OUTPUT; + + /* TODO: + * PIPE_BARRIER_INDIRECT_BUFFER + */ + + for (unsigned i = 0; i < D3D12_GFX_SHADER_STAGES; ++i) { + if (flags & PIPE_BARRIER_CONSTANT_BUFFER) + ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_CONSTBUF; + if (flags & PIPE_BARRIER_TEXTURE) + ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_SAMPLER_VIEWS; + if (flags & PIPE_BARRIER_SHADER_BUFFER) + ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_SSBO; + if (flags & PIPE_BARRIER_IMAGE) + ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_IMAGE; + } + + /* Indicate that UAVs shouldn't override transitions. Ignore barriers that are only + * for UAVs or other fixed-function state that doesn't need a draw to resolve. + */ + const unsigned ignored_barrier_flags = + PIPE_BARRIER_IMAGE | + PIPE_BARRIER_SHADER_BUFFER | + PIPE_BARRIER_UPDATE | + PIPE_BARRIER_MAPPED_BUFFER | + PIPE_BARRIER_QUERY_BUFFER; + d3d12_current_batch(ctx)->pending_memory_barrier = (flags & ~ignored_barrier_flags) != 0; + + if (flags & (PIPE_BARRIER_IMAGE | PIPE_BARRIER_SHADER_BUFFER)) { + D3D12_RESOURCE_BARRIER uavBarrier; + uavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + uavBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + uavBarrier.UAV.pResource = nullptr; + ctx->cmdlist->ResourceBarrier(1, &uavBarrier); + } +} + struct pipe_context * d3d12_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) { @@ -2099,6 +2147,8 @@ d3d12_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) ctx->base.flush = d3d12_flush; ctx->base.flush_resource = d3d12_flush_resource; + ctx->base.memory_barrier = d3d12_memory_barrier; + ctx->gfx_pipeline_state.sample_mask = ~0; d3d12_context_surface_init(&ctx->base); diff --git a/src/gallium/drivers/d3d12/d3d12_draw.cpp b/src/gallium/drivers/d3d12/d3d12_draw.cpp index b523ef8708b..53194c0fb34 100644 --- a/src/gallium/drivers/d3d12/d3d12_draw.cpp +++ b/src/gallium/drivers/d3d12/d3d12_draw.cpp @@ -303,21 +303,23 @@ fill_image_descriptors(struct d3d12_context *ctx, unreachable("Unexpected image view dimension"); } - if (res->base.b.target == PIPE_BUFFER) { - d3d12_transition_resource_state(ctx, res, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_BIND_INVALIDATE_NONE); - } else { - unsigned transition_first_layer = view->u.tex.first_layer; - unsigned transition_array_size = array_size; - if (res->base.b.target == PIPE_TEXTURE_3D) { - transition_first_layer = 0; - transition_array_size = 0; + if (!batch->pending_memory_barrier) { + if (res->base.b.target == PIPE_BUFFER) { + d3d12_transition_resource_state(ctx, res, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_BIND_INVALIDATE_NONE); + } else { + unsigned transition_first_layer = view->u.tex.first_layer; + unsigned transition_array_size = array_size; + if (res->base.b.target == PIPE_TEXTURE_3D) { + transition_first_layer = 0; + transition_array_size = 0; + } + d3d12_transition_subresources_state(ctx, res, + view->u.tex.level, 1, + transition_first_layer, transition_array_size, + 0, 1, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_BIND_INVALIDATE_NONE); } - d3d12_transition_subresources_state(ctx, res, - view->u.tex.level, 1, - transition_first_layer, transition_array_size, - 0, 1, - D3D12_RESOURCE_STATE_UNORDERED_ACCESS, - D3D12_BIND_INVALIDATE_NONE); } d3d12_batch_reference_resource(batch, res, true); @@ -930,6 +932,7 @@ d3d12_draw_vbo(struct pipe_context *pctx, draws[0].start, dinfo->start_instance); ctx->state_dirty = 0; + batch->pending_memory_barrier = false; if (index_buffer) ctx->cmdlist_dirty = 0; diff --git a/src/microsoft/resource_state_manager/D3D12ResourceState.cpp b/src/microsoft/resource_state_manager/D3D12ResourceState.cpp index 528e672fa36..5acb948c9bb 100644 --- a/src/microsoft/resource_state_manager/D3D12ResourceState.cpp +++ b/src/microsoft/resource_state_manager/D3D12ResourceState.cpp @@ -274,6 +274,18 @@ void ResourceStateManager::ProcessTransitioningResource(ID3D12Resource* pTransit continue; } + // This is a transition into a state that is both write and non-write. + // This is invalid according to D3D12. We're venturing into undefined behavior + // land, but let's just pick the write state. + if (IsD3D12WriteState(after) && + (after & ~RESOURCE_STATE_ALL_WRITE_BITS) != 0) + { + after &= RESOURCE_STATE_ALL_WRITE_BITS; + + // For now, this is the only way I've seen where this can happen. + assert(after == D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + } + ProcessTransitioningSubresourceExplicit( CurrentState, i,