d3d12: Handle memory barriers
This is a bit fragile. The algorithm is essentially: - Let the driver track state for non-dual-bound resources. - For resources that are dual-bound as SSBO/image and a second bind point, assume they're being used as UAVs. - When a MemoryBarrier is issued, dirty all destination bind points so they re-assert their state, and if the destination is not UAV, temporarily suppress UAV state re-assertion. Reviewed-by: Sil Vilerino <sivileri@microsoft.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14342>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user