From: Jesse Natalie Date: Wed, 20 Jul 2022 19:03:21 +0000 (-0700) Subject: d3d12: Record a state fixup command list when necessary X-Git-Tag: upstream/22.3.5~5749 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=05d04c7a543ff739ad7580d7042cb4dd5310cd8d;p=platform%2Fupstream%2Fmesa.git d3d12: Record a state fixup command list when necessary Reviewed-by: Bill Kristiansen Part-of: --- diff --git a/src/gallium/drivers/d3d12/d3d12_batch.cpp b/src/gallium/drivers/d3d12/d3d12_batch.cpp index 77f37e7..7bc26c9 100644 --- a/src/gallium/drivers/d3d12/d3d12_batch.cpp +++ b/src/gallium/drivers/d3d12/d3d12_batch.cpp @@ -213,10 +213,16 @@ d3d12_end_batch(struct d3d12_context *ctx, struct d3d12_batch *batch) d3d12_process_batch_residency(screen, batch); - d3d12_context_state_resolve_submission(ctx, batch); - - ID3D12CommandList* cmdlists[] = { ctx->cmdlist }; - screen->cmdqueue->ExecuteCommandLists(1, cmdlists); + bool has_state_fixup = d3d12_context_state_resolve_submission(ctx, batch); + + ID3D12CommandList *cmdlists[] = { ctx->state_fixup_cmdlist, ctx->cmdlist }; + ID3D12CommandList **to_execute = cmdlists; + UINT count_to_execute = ARRAY_SIZE(cmdlists); + if (!has_state_fixup) { + to_execute++; + count_to_execute--; + } + screen->cmdqueue->ExecuteCommandLists(count_to_execute, to_execute); batch->fence = d3d12_create_fence(screen); mtx_unlock(&screen->submit_mutex); diff --git a/src/gallium/drivers/d3d12/d3d12_context.h b/src/gallium/drivers/d3d12/d3d12_context.h index 52fb276..84465ff 100644 --- a/src/gallium/drivers/d3d12/d3d12_context.h +++ b/src/gallium/drivers/d3d12/d3d12_context.h @@ -181,6 +181,7 @@ struct d3d12_context { unsigned current_batch_idx; struct util_dynarray recently_destroyed_bos; + struct util_dynarray barrier_scratch; struct pipe_constant_buffer cbufs[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS]; struct pipe_framebuffer_state fb; @@ -243,6 +244,7 @@ struct d3d12_context { uint64_t submit_id; ID3D12GraphicsCommandList *cmdlist; + ID3D12GraphicsCommandList *state_fixup_cmdlist; struct list_head active_queries; bool queries_disabled; diff --git a/src/gallium/drivers/d3d12/d3d12_resource_state.cpp b/src/gallium/drivers/d3d12/d3d12_resource_state.cpp index 44d451b..0910257 100644 --- a/src/gallium/drivers/d3d12/d3d12_resource_state.cpp +++ b/src/gallium/drivers/d3d12/d3d12_resource_state.cpp @@ -25,6 +25,9 @@ #include "d3d12_context.h" #include "d3d12_format.h" #include "d3d12_resource_state.h" +#include "d3d12_screen.h" + +#include #include @@ -149,7 +152,6 @@ d3d12_resource_state_if_promoted(D3D12_RESOURCE_STATES desired_state, bool simultaneous_access, const d3d12_subresource_state *current_state) { - D3D12_RESOURCE_STATES result = D3D12_RESOURCE_STATE_COMMON; const D3D12_RESOURCE_STATES promotable_states = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_COPY_DEST; @@ -211,6 +213,9 @@ d3d12_context_state_table_destroy(struct d3d12_context *ctx) hash_table_foreach(ctx->bo_state_table->table, entry) destroy_context_state_table_entry((d3d12_context_state_table_entry *)entry->data); _mesa_hash_table_u64_destroy(ctx->bo_state_table); + util_dynarray_fini(&ctx->barrier_scratch); + if (ctx->state_fixup_cmdlist) + ctx->state_fixup_cmdlist->Release(); } static unsigned @@ -253,7 +258,76 @@ find_or_create_state_entry(struct hash_table_u64 *table, d3d12_bo *bo) return bo_state; } -void +static ID3D12GraphicsCommandList * +ensure_state_fixup_cmdlist(struct d3d12_context *ctx, ID3D12CommandAllocator *alloc) +{ + if (!ctx->state_fixup_cmdlist) { + struct d3d12_screen *screen = d3d12_screen(ctx->base.screen); + screen->dev->CreateCommandList(0, + D3D12_COMMAND_LIST_TYPE_DIRECT, + alloc, + nullptr, + IID_PPV_ARGS(&ctx->state_fixup_cmdlist)); + } else if (FAILED(ctx->state_fixup_cmdlist->Reset(alloc, nullptr))) { + ctx->state_fixup_cmdlist->Release(); + ctx->state_fixup_cmdlist = nullptr; + } + + return ctx->state_fixup_cmdlist; +} + +static bool +transition_required(D3D12_RESOURCE_STATES current_state, D3D12_RESOURCE_STATES *destination_state) +{ + // An exact match never needs a transition. + if (current_state == *destination_state) { + return false; + } + + if (current_state == D3D12_RESOURCE_STATE_COMMON || *destination_state == D3D12_RESOURCE_STATE_COMMON) { + return true; + } + + // Current state already contains the destination state, we're good. + if ((current_state & *destination_state) == *destination_state) { + *destination_state = current_state; + return false; + } + + // If the transition involves a write state, then the destination should just be the requested destination. + // Otherwise, accumulate read states to minimize future transitions (by triggering the above condition). + if (!d3d12_is_write_state(*destination_state) && !d3d12_is_write_state(current_state)) { + *destination_state |= current_state; + } + return true; +} + +static void +resolve_global_state(struct d3d12_context *ctx, ID3D12Resource *res, d3d12_resource_state *batch_state, d3d12_resource_state *res_state) +{ + assert(batch_state->num_subresources == res_state->num_subresources); + unsigned num_subresources = batch_state->homogenous && res_state->homogenous ? 1 : batch_state->num_subresources; + for (unsigned i = 0; i < num_subresources; ++i) { + const d3d12_subresource_state *current_state = d3d12_get_subresource_state(res_state, i); + const d3d12_subresource_state *target_state = d3d12_get_subresource_state(batch_state, i); + D3D12_RESOURCE_STATES promotable_state = + d3d12_resource_state_if_promoted(target_state->state, false, current_state); + + D3D12_RESOURCE_STATES after = target_state->state; + if ((promotable_state & target_state->state) == target_state->state || + !transition_required(current_state->state, &after)) + continue; + + D3D12_RESOURCE_BARRIER barrier = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION }; + barrier.Transition.pResource = res; + barrier.Transition.StateBefore = current_state->state; + barrier.Transition.StateAfter = after; + barrier.Transition.Subresource = num_subresources == 1 ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : i; + util_dynarray_append(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER, barrier); + } +} + +bool d3d12_context_state_resolve_submission(struct d3d12_context *ctx, struct d3d12_batch *batch) { util_dynarray_foreach(&ctx->recently_destroyed_bos, uint64_t, id) { @@ -270,10 +344,26 @@ d3d12_context_state_resolve_submission(struct d3d12_context *ctx, struct d3d12_b d3d12_context_state_table_entry *bo_state = find_or_create_state_entry(ctx->bo_state_table, bo); if (!bo_state->batch_end.supports_simultaneous_access) { assert(bo->res && bo->global_state.subresource_states); + + resolve_global_state(ctx, bo->res, &bo_state->batch_begin, &bo->global_state); + d3d12_resource_state_copy(&bo_state->batch_begin, &bo_state->batch_end); d3d12_resource_state_copy(&bo->global_state, &bo_state->batch_end); } else { d3d12_reset_resource_state(&bo_state->batch_end); } } + + bool needs_execute_fixup = false; + if (ctx->barrier_scratch.size) { + ID3D12GraphicsCommandList *cmdlist = ensure_state_fixup_cmdlist(ctx, batch->cmdalloc); + if (cmdlist) { + cmdlist->ResourceBarrier(util_dynarray_num_elements(&ctx->barrier_scratch, D3D12_RESOURCE_BARRIER), + (D3D12_RESOURCE_BARRIER *)ctx->barrier_scratch.data); + needs_execute_fixup = SUCCEEDED(cmdlist->Close()); + } + + util_dynarray_clear(&ctx->barrier_scratch); + } + return needs_execute_fixup; } diff --git a/src/gallium/drivers/d3d12/d3d12_resource_state.h b/src/gallium/drivers/d3d12/d3d12_resource_state.h index 19ace51..ba3520a 100644 --- a/src/gallium/drivers/d3d12/d3d12_resource_state.h +++ b/src/gallium/drivers/d3d12/d3d12_resource_state.h @@ -129,7 +129,7 @@ d3d12_context_state_table_init(struct d3d12_context *ctx); void d3d12_context_state_table_destroy(struct d3d12_context *ctx); -void +bool d3d12_context_state_resolve_submission(struct d3d12_context *ctx, struct d3d12_batch *batch); #endif // D3D12_RESOURCE_STATE_H