D3D12ResourceState.cpp revision 7ec681f3
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#include "D3D12ResourceState.h" 25 26//---------------------------------------------------------------------------------------------------------------------------------- 27 D3D12_RESOURCE_STATES CDesiredResourceState::GetSubresourceState(UINT SubresourceIndex) const 28{ 29 if (AreAllSubresourcesSame()) 30 { 31 SubresourceIndex = 0; 32 } 33 return m_spSubresourceStates[SubresourceIndex]; 34} 35 36//---------------------------------------------------------------------------------------------------------------------------------- 37void CDesiredResourceState::UpdateSubresourceState(unsigned SubresourceIndex, D3D12_RESOURCE_STATES state) 38{ 39 assert(SubresourceIndex < m_spSubresourceStates.size()); 40 if (m_spSubresourceStates[SubresourceIndex] == UNKNOWN_RESOURCE_STATE || 41 state == UNKNOWN_RESOURCE_STATE || 42 IsD3D12WriteState(state)) 43 { 44 m_spSubresourceStates[SubresourceIndex] = state; 45 } 46 else 47 { 48 // Accumulate read state state bits 49 m_spSubresourceStates[SubresourceIndex] |= state; 50 } 51} 52 53//---------------------------------------------------------------------------------------------------------------------------------- 54void CDesiredResourceState::SetResourceState(D3D12_RESOURCE_STATES state) 55{ 56 m_bAllSubresourcesSame = true; 57 UpdateSubresourceState(0, state); 58} 59 60//---------------------------------------------------------------------------------------------------------------------------------- 61void CDesiredResourceState::SetSubresourceState(UINT SubresourceIndex, D3D12_RESOURCE_STATES state) 62{ 63 if (m_bAllSubresourcesSame && m_spSubresourceStates.size() > 1) 64 { 65 std::fill(m_spSubresourceStates.begin() + 1, m_spSubresourceStates.end(), m_spSubresourceStates[0]); 66 m_bAllSubresourcesSame = false; 67 } 68 if (m_spSubresourceStates.size() == 1) 69 { 70 SubresourceIndex = 0; 71 } 72 UpdateSubresourceState(SubresourceIndex, state); 73} 74 75//---------------------------------------------------------------------------------------------------------------------------------- 76void CDesiredResourceState::Reset() 77{ 78 SetResourceState(UNKNOWN_RESOURCE_STATE); 79} 80 81//---------------------------------------------------------------------------------------------------------------------------------- 82void CCurrentResourceState::ConvertToSubresourceTracking() 83{ 84 if (m_bAllSubresourcesSame && m_spLogicalState.size() > 1) 85 { 86 std::fill(m_spLogicalState.begin() + 1, m_spLogicalState.end(), m_spLogicalState[0]); 87 m_bAllSubresourcesSame = false; 88 } 89} 90 91//---------------------------------------------------------------------------------------------------------------------------------- 92CCurrentResourceState::CCurrentResourceState(UINT SubresourceCount, bool bSimultaneousAccess) 93 : m_bSimultaneousAccess(bSimultaneousAccess) 94 , m_spLogicalState(SubresourceCount) 95{ 96 m_spLogicalState[0] = LogicalState{}; 97} 98 99//---------------------------------------------------------------------------------------------------------------------------------- 100D3D12_RESOURCE_STATES CCurrentResourceState::StateIfPromoted(D3D12_RESOURCE_STATES State, UINT SubresourceIndex) 101{ 102 D3D12_RESOURCE_STATES Result = D3D12_RESOURCE_STATE_COMMON; 103 104 if (m_bSimultaneousAccess || !!(State & ( 105 D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | 106 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | 107 D3D12_RESOURCE_STATE_COPY_SOURCE | 108 D3D12_RESOURCE_STATE_COPY_DEST))) 109 { 110 auto CurState = GetLogicalSubresourceState(SubresourceIndex); 111 112 // If the current state is COMMON... 113 if(CurState.State == D3D12_RESOURCE_STATE_COMMON) 114 { 115 // ...then promotion is allowed 116 Result = State; 117 } 118 // If the current state is a read state resulting from previous promotion... 119 else if(CurState.IsPromotedState && !!(CurState.State & D3D12_RESOURCE_STATE_GENERIC_READ)) 120 { 121 // ...then (accumulated) promotion is allowed 122 Result = State |= CurState.State; 123 } 124 } 125 126 return Result; 127} 128 129 130 131//---------------------------------------------------------------------------------------------------------------------------------- 132void CCurrentResourceState::SetLogicalResourceState(LogicalState const& State) 133{ 134 m_bAllSubresourcesSame = true; 135 m_spLogicalState[0] = State; 136} 137 138//---------------------------------------------------------------------------------------------------------------------------------- 139void CCurrentResourceState::SetLogicalSubresourceState(UINT SubresourceIndex, LogicalState const& State) 140{ 141 ConvertToSubresourceTracking(); 142 m_spLogicalState[SubresourceIndex] = State; 143} 144 145//---------------------------------------------------------------------------------------------------------------------------------- 146auto CCurrentResourceState::GetLogicalSubresourceState(UINT SubresourceIndex) const -> LogicalState const& 147{ 148 if (AreAllSubresourcesSame()) 149 { 150 SubresourceIndex = 0; 151 } 152 return m_spLogicalState[SubresourceIndex]; 153} 154 155//---------------------------------------------------------------------------------------------------------------------------------- 156void CCurrentResourceState::Reset() 157{ 158 m_bAllSubresourcesSame = true; 159 m_spLogicalState[0] = LogicalState{}; 160} 161 162//---------------------------------------------------------------------------------------------------------------------------------- 163ResourceStateManager::ResourceStateManager() 164{ 165 list_inithead(&m_TransitionListHead); 166 // Reserve some space in these vectors upfront. Values are arbitrary. 167 m_vResourceBarriers.reserve(50); 168} 169 170//---------------------------------------------------------------------------------------------------------------------------------- 171void ResourceStateManager::TransitionResource(TransitionableResourceState& Resource, 172 D3D12_RESOURCE_STATES state) 173{ 174 Resource.m_DesiredState.SetResourceState(state); 175 if (!Resource.IsTransitionPending()) 176 { 177 list_add(&Resource.m_TransitionListEntry, &m_TransitionListHead); 178 } 179} 180 181//---------------------------------------------------------------------------------------------------------------------------------- 182void ResourceStateManager::TransitionSubresource(TransitionableResourceState& Resource, 183 UINT SubresourceIndex, 184 D3D12_RESOURCE_STATES state) 185{ 186 Resource.m_DesiredState.SetSubresourceState(SubresourceIndex, state); 187 if (!Resource.IsTransitionPending()) 188 { 189 list_add(&Resource.m_TransitionListEntry, &m_TransitionListHead); 190 } 191} 192 193//---------------------------------------------------------------------------------------------------------------------------------- 194void ResourceStateManager::ApplyResourceTransitionsPreamble() 195{ 196 m_vResourceBarriers.clear(); 197} 198 199//---------------------------------------------------------------------------------------------------------------------------------- 200/*static*/ bool ResourceStateManager::TransitionRequired(D3D12_RESOURCE_STATES CurrentState, D3D12_RESOURCE_STATES& DestinationState) 201{ 202 // An exact match never needs a transition. 203 if (CurrentState == DestinationState) 204 { 205 return false; 206 } 207 208 if ( 209 CurrentState == D3D12_RESOURCE_STATE_COMMON || 210 DestinationState == D3D12_RESOURCE_STATE_COMMON) 211 { 212 return true; 213 } 214 215 // Current state already contains the destination state, we're good. 216 if ((CurrentState & DestinationState) == DestinationState) 217 { 218 DestinationState = CurrentState; 219 return false; 220 } 221 222 // If the transition involves a write state, then the destination should just be the requested destination. 223 // Otherwise, accumulate read states to minimize future transitions (by triggering the above condition). 224 if (!IsD3D12WriteState(DestinationState) && !IsD3D12WriteState(CurrentState)) 225 { 226 DestinationState |= CurrentState; 227 } 228 return true; 229} 230 231//---------------------------------------------------------------------------------------------------------------------------------- 232void ResourceStateManager::AddCurrentStateUpdate(TransitionableResourceState& Resource, 233 CCurrentResourceState& CurrentState, 234 UINT SubresourceIndex, 235 const CCurrentResourceState::LogicalState &NewLogicalState) 236{ 237 if (SubresourceIndex == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES) 238 { 239 CurrentState.SetLogicalResourceState(NewLogicalState); 240 } 241 else 242 { 243 CurrentState.SetLogicalSubresourceState(SubresourceIndex, NewLogicalState); 244 } 245} 246 247//---------------------------------------------------------------------------------------------------------------------------------- 248void ResourceStateManager::ProcessTransitioningResource(ID3D12Resource* pTransitioningResource, 249 TransitionableResourceState& TransitionableResourceState, 250 CCurrentResourceState& CurrentState, 251 UINT NumTotalSubresources, 252 UINT64 ExecutionId) 253{ 254 // Figure out the set of subresources that are transitioning 255 auto& DestinationState = TransitionableResourceState.m_DesiredState; 256 bool bAllSubresourcesAtOnce = CurrentState.AreAllSubresourcesSame() && DestinationState.AreAllSubresourcesSame(); 257 258 D3D12_RESOURCE_BARRIER TransitionDesc; 259 memset(&TransitionDesc, 0, sizeof(TransitionDesc)); 260 TransitionDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 261 TransitionDesc.Transition.pResource = pTransitioningResource; 262 263 UINT numSubresources = bAllSubresourcesAtOnce ? 1 : NumTotalSubresources; 264 for (UINT i = 0; i < numSubresources; ++i) 265 { 266 D3D12_RESOURCE_STATES SubresourceDestinationState = DestinationState.GetSubresourceState(i); 267 TransitionDesc.Transition.Subresource = bAllSubresourcesAtOnce ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : i; 268 269 // Is this subresource currently being used, or is it just being iterated over? 270 D3D12_RESOURCE_STATES after = DestinationState.GetSubresourceState(i); 271 if (after == UNKNOWN_RESOURCE_STATE) 272 { 273 // This subresource doesn't have any transition requested - move on to the next. 274 continue; 275 } 276 277 ProcessTransitioningSubresourceExplicit( 278 CurrentState, 279 i, 280 SubresourceDestinationState, 281 after, 282 TransitionableResourceState, 283 TransitionDesc, 284 ExecutionId); // throw( bad_alloc ) 285 } 286 287 // Update destination states. 288 // Coalesce destination state to ensure that it's set for the entire resource. 289 DestinationState.SetResourceState(UNKNOWN_RESOURCE_STATE); 290 291} 292 293//---------------------------------------------------------------------------------------------------------------------------------- 294void ResourceStateManager::ProcessTransitioningSubresourceExplicit( 295 CCurrentResourceState& CurrentState, 296 UINT SubresourceIndex, 297 D3D12_RESOURCE_STATES state, 298 D3D12_RESOURCE_STATES after, 299 TransitionableResourceState& TransitionableResourceState, 300 D3D12_RESOURCE_BARRIER& TransitionDesc, 301 UINT64 ExecutionId) 302{ 303 // Simultaneous access resources currently in the COMMON 304 // state can be implicitly promoted to any state other state. 305 // Any non-simultaneous-access resources currently in the 306 // COMMON state can still be implicitly promoted to SRV, 307 // NON_PS_SRV, COPY_SRC, or COPY_DEST. 308 CCurrentResourceState::LogicalState CurrentLogicalState = CurrentState.GetLogicalSubresourceState(SubresourceIndex); 309 310 // If the last time this logical state was set was in a different 311 // execution period and is decayable then decay the current state 312 // to COMMON 313 if(ExecutionId != CurrentLogicalState.ExecutionId && CurrentLogicalState.MayDecay) 314 { 315 CurrentLogicalState.State = D3D12_RESOURCE_STATE_COMMON; 316 CurrentLogicalState.IsPromotedState = false; 317 } 318 bool MayDecay = false; 319 bool IsPromotion = false; 320 321 // If not promotable then StateIfPromoted will be D3D12_RESOURCE_STATE_COMMON 322 auto StateIfPromoted = CurrentState.StateIfPromoted(after, SubresourceIndex); 323 324 if ( D3D12_RESOURCE_STATE_COMMON == StateIfPromoted ) 325 { 326 if (TransitionRequired(CurrentLogicalState.State, /*inout*/ after)) 327 { 328 // Insert a single concrete barrier (for non-simultaneous access resources). 329 TransitionDesc.Transition.StateBefore = D3D12_RESOURCE_STATES(CurrentLogicalState.State); 330 TransitionDesc.Transition.StateAfter = D3D12_RESOURCE_STATES(after); 331 assert(TransitionDesc.Transition.StateBefore != TransitionDesc.Transition.StateAfter); 332 m_vResourceBarriers.push_back(TransitionDesc); // throw( bad_alloc ) 333 334 MayDecay = CurrentState.SupportsSimultaneousAccess() && !IsD3D12WriteState(after); 335 IsPromotion = false; 336 } 337 } 338 else 339 { 340 // Handle identity state transition 341 if(after != StateIfPromoted) 342 { 343 after = StateIfPromoted; 344 MayDecay = !IsD3D12WriteState(after); 345 IsPromotion = true; 346 } 347 } 348 349 CCurrentResourceState::LogicalState NewLogicalState{after, ExecutionId, IsPromotion, MayDecay}; 350 AddCurrentStateUpdate(TransitionableResourceState, 351 CurrentState, 352 TransitionDesc.Transition.Subresource, 353 NewLogicalState); 354} 355 356//---------------------------------------------------------------------------------------------------------------------------------- 357void ResourceStateManager::SubmitResourceTransitions(ID3D12GraphicsCommandList *pCommandList) 358{ 359 // Submit any pending barriers on source command lists that are not the destination. 360 if (!m_vResourceBarriers.empty()) 361 { 362 pCommandList->ResourceBarrier((UINT)m_vResourceBarriers.size(), m_vResourceBarriers.data()); 363 } 364} 365 366//---------------------------------------------------------------------------------------------------------------------------------- 367void ResourceStateManager::TransitionResource(TransitionableResourceState* pResource, D3D12_RESOURCE_STATES State) 368{ 369 ResourceStateManager::TransitionResource(*pResource, State); 370} 371 372//---------------------------------------------------------------------------------------------------------------------------------- 373void ResourceStateManager::TransitionSubresource(TransitionableResourceState* pResource, UINT SubresourceIndex, D3D12_RESOURCE_STATES State) 374{ 375 ResourceStateManager::TransitionSubresource(*pResource, SubresourceIndex, State); 376} 377 378//---------------------------------------------------------------------------------------------------------------------------------- 379void ResourceStateManager::ApplyAllResourceTransitions(ID3D12GraphicsCommandList *pCommandList, UINT64 ExecutionId) 380{ 381 ApplyResourceTransitionsPreamble(); 382 383 ForEachTransitioningResource([=](TransitionableResourceState& ResourceBase) 384 { 385 TransitionableResourceState& CurResource = static_cast<TransitionableResourceState&>(ResourceBase); 386 387 ID3D12Resource *pResource = CurResource.GetD3D12Resource(); 388 389 ProcessTransitioningResource( 390 pResource, 391 CurResource, 392 CurResource.GetCurrentState(), 393 CurResource.NumSubresources(), 394 ExecutionId); 395 }); 396 397 SubmitResourceTransitions(pCommandList); 398} 399