1/* 2 * Copyright © Microsoft Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#ifndef D3D12_RESOURCE_STATE_H 25#define D3D12_RESOURCE_STATE_H 26 27#ifndef _WIN32 28#include <wsl/winadapter.h> 29#endif 30 31#include <vector> 32#include <assert.h> 33#include <directx/d3d12.h> 34 35#include "util/list.h" 36 37#if defined(__GNUC__) 38#pragma GCC diagnostic ignored "-Winvalid-offsetof" 39#endif 40 41#define UNKNOWN_RESOURCE_STATE (D3D12_RESOURCE_STATES)0x8000u 42#define RESOURCE_STATE_VALID_BITS 0x2f3fff 43#define RESOURCE_STATE_VALID_INTERNAL_BITS 0x2fffff 44constexpr D3D12_RESOURCE_STATES RESOURCE_STATE_ALL_WRITE_BITS = 45D3D12_RESOURCE_STATE_RENDER_TARGET | 46D3D12_RESOURCE_STATE_UNORDERED_ACCESS | 47D3D12_RESOURCE_STATE_DEPTH_WRITE | 48D3D12_RESOURCE_STATE_STREAM_OUT | 49D3D12_RESOURCE_STATE_COPY_DEST | 50D3D12_RESOURCE_STATE_RESOLVE_DEST | 51D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE | 52D3D12_RESOURCE_STATE_VIDEO_PROCESS_WRITE; 53 54//--------------------------------------------------------------------------------------------------------------------------------- 55inline bool IsD3D12WriteState(UINT State) 56{ 57 return (State & RESOURCE_STATE_ALL_WRITE_BITS) != 0; 58} 59 60inline bool SupportsSimultaneousAccess(const D3D12_RESOURCE_DESC &desc) 61{ 62 return D3D12_RESOURCE_DIMENSION_BUFFER == desc.Dimension || 63 !!(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS); 64} 65 66//================================================================================================================================== 67// CDesiredResourceState 68// Stores the current desired state of either an entire resource, or each subresource. 69//================================================================================================================================== 70class CDesiredResourceState 71{ 72private: 73 bool m_bAllSubresourcesSame = true; 74 75 std::vector<D3D12_RESOURCE_STATES> m_spSubresourceStates; 76 77public: 78 CDesiredResourceState(UINT SubresourceCount) : 79 m_spSubresourceStates(SubresourceCount) 80 { 81 } 82 83 bool AreAllSubresourcesSame() const { return m_bAllSubresourcesSame; } 84 85 D3D12_RESOURCE_STATES GetSubresourceState(UINT SubresourceIndex) const; 86 void SetResourceState(D3D12_RESOURCE_STATES state); 87 void SetSubresourceState(UINT SubresourceIndex, D3D12_RESOURCE_STATES state); 88 89 void Reset(); 90 91private: 92 void UpdateSubresourceState(unsigned SubresourceIndex, D3D12_RESOURCE_STATES state); 93}; 94 95//================================================================================================================================== 96// CCurrentResourceState 97// Stores the current state of either an entire resource, or each subresource. 98// Current state can either be shared read across multiple queues, or exclusive on a single queue. 99//================================================================================================================================== 100class CCurrentResourceState 101{ 102public: 103 struct LogicalState 104 { 105 D3D12_RESOURCE_STATES State = D3D12_RESOURCE_STATE_COMMON; 106 UINT64 ExecutionId = 0; 107 bool IsPromotedState = false; 108 bool MayDecay = false; 109 }; 110 111private: 112 const bool m_bSimultaneousAccess; 113 bool m_bAllSubresourcesSame = true; 114 115 std::vector<LogicalState> m_spLogicalState; 116 117 void ConvertToSubresourceTracking(); 118 119public: 120 CCurrentResourceState(UINT SubresourceCount, bool bSimultaneousAccess); 121 122 bool SupportsSimultaneousAccess() const { return m_bSimultaneousAccess; } 123 124 // Returns the destination state if the current state is promotable. 125 // Returns D3D12_RESOURCE_STATE_COMMON if not. 126 D3D12_RESOURCE_STATES StateIfPromoted(D3D12_RESOURCE_STATES state, UINT SubresourceIndex); 127 128 bool AreAllSubresourcesSame() const { return m_bAllSubresourcesSame; } 129 130 void SetLogicalResourceState(LogicalState const& State); 131 void SetLogicalSubresourceState(UINT SubresourceIndex, LogicalState const& State); 132 LogicalState const& GetLogicalSubresourceState(UINT SubresourceIndex) const; 133 134 void Reset(); 135}; 136 137//================================================================================================================================== 138// TransitionableResourceState 139// A base class that transitionable resources should inherit from. 140//================================================================================================================================== 141struct TransitionableResourceState 142{ 143 struct list_head m_TransitionListEntry; 144 CDesiredResourceState m_DesiredState; 145 146 TransitionableResourceState(ID3D12Resource *pResource, UINT TotalSubresources, bool SupportsSimultaneousAccess) : 147 m_DesiredState(TotalSubresources), 148 m_TotalSubresources(TotalSubresources), 149 m_currentState(TotalSubresources, SupportsSimultaneousAccess), 150 m_pResource(pResource) 151 { 152 list_inithead(&m_TransitionListEntry); 153 } 154 155 ~TransitionableResourceState() 156 { 157 if (IsTransitionPending()) 158 { 159 list_del(&m_TransitionListEntry); 160 } 161 } 162 163 bool IsTransitionPending() const { return !list_is_empty(&m_TransitionListEntry); } 164 165 UINT NumSubresources() { return m_TotalSubresources; } 166 167 CCurrentResourceState& GetCurrentState() { return m_currentState; } 168 169 inline ID3D12Resource* GetD3D12Resource() const { return m_pResource; } 170 171private: 172 unsigned m_TotalSubresources; 173 174 CCurrentResourceState m_currentState; 175 176 ID3D12Resource* m_pResource; 177}; 178 179//================================================================================================================================== 180// ResourceStateManager 181// The main business logic for handling resource transitions, including multi-queue sync and shared/exclusive state changes. 182// 183// Requesting a resource to transition simply updates destination state, and ensures it's in a list to be processed later. 184// 185// When processing ApplyAllResourceTransitions, we build up sets of vectors. 186// There's a source one for each command list type, and a single one for the dest because we are applying 187// the resource transitions for a single operation. 188// There's also a vector for "tentative" barriers, which are merged into the destination vector if 189// no flushing occurs as a result of submitting the final barrier operation. 190// 99% of the time, there will only be the source being populated, but sometimes there will be a destination as well. 191// If the source and dest of a transition require different types, we put a (source->COMMON) in the approriate source vector, 192// and a (COMMON->dest) in the destination vector. 193// 194// Once all resources are processed, we: 195// 1. Submit all source barriers, except ones belonging to the destination queue. 196// 2. Flush all source command lists, except ones belonging to the destination queue. 197// 3. Determine if the destination queue is going to be flushed. 198// If so: Submit source barriers on that command list first, then flush it. 199// If not: Accumulate source, dest, and tentative barriers so they can be sent to D3D12 in a single API call. 200// 4. Insert waits on the destination queue - deferred waits, and waits for work on other queues. 201// 5. Insert destination barriers. 202// 203// Only once all of this has been done do we update the "current" state of resources, 204// because this is the only way that we know whether or not the destination queue has been flushed, 205// and therefore, we can get the correct fence values to store in the subresources. 206//================================================================================================================================== 207class ResourceStateManager 208{ 209protected: 210 211 struct list_head m_TransitionListHead; 212 213 std::vector<D3D12_RESOURCE_BARRIER> m_vResourceBarriers; 214 215public: 216 ResourceStateManager(); 217 218 ~ResourceStateManager() 219 { 220 // All resources should be gone by this point, and each resource ensures it is no longer in this list. 221 assert(list_is_empty(&m_TransitionListHead)); 222 } 223 224 // Call the D3D12 APIs to perform the resource barriers, command list submission, and command queue sync 225 // that was determined by previous calls to ProcessTransitioningResource. 226 void SubmitResourceTransitions(ID3D12GraphicsCommandList *pCommandList); 227 228 // Transition the entire resource to a particular destination state on a particular command list. 229 void TransitionResource(TransitionableResourceState* pResource, 230 D3D12_RESOURCE_STATES State); 231 // Transition a single subresource to a particular destination state. 232 void TransitionSubresource(TransitionableResourceState* pResource, 233 UINT SubresourceIndex, 234 D3D12_RESOURCE_STATES State); 235 236 // Submit all barriers and queue sync. 237 void ApplyAllResourceTransitions(ID3D12GraphicsCommandList *pCommandList, UINT64 ExecutionId); 238 239private: 240 // These methods set the destination state of the resource/subresources and ensure it's in the transition list. 241 void TransitionResource(TransitionableResourceState& Resource, 242 D3D12_RESOURCE_STATES State); 243 void TransitionSubresource(TransitionableResourceState& Resource, 244 UINT SubresourceIndex, 245 D3D12_RESOURCE_STATES State); 246 247 // Clear out any state from previous iterations. 248 void ApplyResourceTransitionsPreamble(); 249 250 // What to do with the resource, in the context of the transition list, after processing it. 251 enum class TransitionResult 252 { 253 // There are no more pending transitions that may be processed at a later time (i.e. draw time), 254 // so remove it from the pending transition list. 255 Remove, 256 // There are more transitions to be done, so keep it in the list. 257 Keep 258 }; 259 260 // For every entry in the transition list, call a routine. 261 // This routine must return a TransitionResult which indicates what to do with the list. 262 template <typename TFunc> 263 void ForEachTransitioningResource(TFunc&& func) 264 { 265 list_for_each_entry_safe(TransitionableResourceState, pResource, &m_TransitionListHead, m_TransitionListEntry) 266 { 267 func(*pResource); 268 list_delinit(&pResource->m_TransitionListEntry); 269 } 270 } 271 272 // Updates vectors with the operations that should be applied to the requested resource. 273 // May update the destination state of the resource. 274 void ProcessTransitioningResource(ID3D12Resource* pTransitioningResource, 275 TransitionableResourceState& TransitionableResourceState, 276 CCurrentResourceState& CurrentState, 277 UINT NumTotalSubresources, 278 UINT64 ExecutionId); 279 280private: 281 // Helpers 282 static bool TransitionRequired(D3D12_RESOURCE_STATES CurrentState, D3D12_RESOURCE_STATES& DestinationState); 283 void AddCurrentStateUpdate(TransitionableResourceState& Resource, 284 CCurrentResourceState& CurrentState, 285 UINT SubresourceIndex, 286 const CCurrentResourceState::LogicalState &NewLogicalState); 287 void ProcessTransitioningSubresourceExplicit(CCurrentResourceState& CurrentState, 288 UINT i, 289 D3D12_RESOURCE_STATES state, 290 D3D12_RESOURCE_STATES after, 291 TransitionableResourceState& TransitionableResourceState, 292 D3D12_RESOURCE_BARRIER& TransitionDesc, 293 UINT64 ExecutionId); 294}; 295 296#endif // D3D12_RESOURCE_STATE_H 297