Skip to content

d3d12: Rewrite/rework resource state management

Jesse Natalie requested to merge jenatali/mesa:d3d12-resource-state-rewrite into main

The primary goal here is to make resource state tracking and management multi-context and multi-thread safe. Right now there's 2 problems, both related to the fact that the resource/bo stores global state, but it's manipulated by a context during command processing rather than submission.

  1. There's a list_head in the resource used to track resources that are accumulating state in anticipation of a barrier. If 2 contexts are both trying to accumulate state for the same resource, the list_head would only be valid for one of them, so the second one might skip issuing needed barriers.
  2. The state is updated as commands are being recorded, so if you have 2 contexts using a resource in an interleaved manner, you might get bogus transitions inserted on the relevant command lists. E.g. context A always reads from the resource, and context B always writes to it, you might get a read->write transition inserted on B, even though on B's command list, there were no prior reads.

The new model splits state tracking into two parts: there's still a global resource state, but now it's only modified during command list execution (i.e. context flush), and during context command recording, a per-context hash table is used to store per-bo state. This hash table operates on unique IDs rather than pointers so that locks aren't needed to access it. It's only modified by the thread that's using the context, and resources are removed from it only during flush, where that thread is able to synchronize with a list of deleted resources. During command list execution, these per-bo states are compared, and fixup command lists are inserted if needed to resolve differences between the two - e.g. if another context had flushed work that used the resource in a different way than was expected.

Other changes:

  • The state management is moved from a bolted-on piece of imported code to be properly integrated, no longer using C++ features that are unused in the rest of the driver, fixing style and naming conventions, and moving some data structures into the relevant driver structs instead of encapsulating them separately.
  • Simplifications are made so that most transition requests immediately resolve to a D3D12_RESOURCE_BARRIER struct, except the ones that are part of draw/dispatch, which continue to accumulate state while preparing bindings.
  • State tracking for buffers is moved to the leaf suballocated bos instead of the parent one that owns the ID3D12Resource. D3D12's debug layer will complain about this when using the classic state model instead of the new "enhanced barriers" model, but there's no real need to issue transitions for a buffer when two independent parts are used for different purposes - e.g. bytes [0, 512) used for data upload and bytes [512, 1024) used for data readback, we don't need to insert a barrier there. Theoretically there could be issues if two chunks operate on the same cache line, but suballocation granularity is likely large enough (512 bytes) for this to not be a concern in practice.

Merge request reports