Mesa (main): d3d12: Record a state fixup command list when necessary

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Jul 22 14:58:07 UTC 2022


Module: Mesa
Branch: main
Commit: 05d04c7a543ff739ad7580d7042cb4dd5310cd8d
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=05d04c7a543ff739ad7580d7042cb4dd5310cd8d

Author: Jesse Natalie <jenatali at microsoft.com>
Date:   Wed Jul 20 12:03:21 2022 -0700

d3d12: Record a state fixup command list when necessary

Reviewed-by: Bill Kristiansen <billkris at microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17688>

---

 src/gallium/drivers/d3d12/d3d12_batch.cpp          | 14 +++-
 src/gallium/drivers/d3d12/d3d12_context.h          |  2 +
 src/gallium/drivers/d3d12/d3d12_resource_state.cpp | 94 +++++++++++++++++++++-
 src/gallium/drivers/d3d12/d3d12_resource_state.h   |  2 +-
 4 files changed, 105 insertions(+), 7 deletions(-)

diff --git a/src/gallium/drivers/d3d12/d3d12_batch.cpp b/src/gallium/drivers/d3d12/d3d12_batch.cpp
index 77f37e74b6d..7bc26c95756 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 52fb276905b..84465ff2932 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 44d451b42f7..091025723c2 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 <dxguids/dxguids.h>
 
 #include <assert.h>
 
@@ -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 19ace51fa86..ba3520afad9 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



More information about the mesa-commit mailing list