From: BillKristiansen Date: Wed, 27 May 2020 15:23:16 +0000 (+0200) Subject: microsoft: add resource state manager utility code X-Git-Tag: upstream/21.0.0~2761 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3f31cf64e49d9de57ea7dc2b0447840255bbca9e;p=platform%2Fupstream%2Fmesa.git microsoft: add resource state manager utility code The code originates from this repository: https://github.com/microsoft/D3D12TranslationLayer It will be used in the next commit. Acked-by: Jason Ekstrand Part-of: --- diff --git a/src/microsoft/meson.build b/src/microsoft/meson.build index 8bbb8ac..ed218ad 100644 --- a/src/microsoft/meson.build +++ b/src/microsoft/meson.build @@ -20,3 +20,4 @@ # IN THE SOFTWARE. subdir('compiler') +subdir('resource_state_manager') diff --git a/src/microsoft/resource_state_manager/D3D12ResourceState.cpp b/src/microsoft/resource_state_manager/D3D12ResourceState.cpp new file mode 100644 index 0000000..5487222 --- /dev/null +++ b/src/microsoft/resource_state_manager/D3D12ResourceState.cpp @@ -0,0 +1,398 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "D3D12ResourceState.h" + +//---------------------------------------------------------------------------------------------------------------------------------- + D3D12_RESOURCE_STATES CDesiredResourceState::GetSubresourceState(UINT SubresourceIndex) const +{ + if (AreAllSubresourcesSame()) + { + SubresourceIndex = 0; + } + return m_spSubresourceStates[SubresourceIndex]; +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void CDesiredResourceState::UpdateSubresourceState(unsigned SubresourceIndex, D3D12_RESOURCE_STATES state) +{ + assert(SubresourceIndex < m_spSubresourceStates.size()); + if (m_spSubresourceStates[SubresourceIndex] == UNKNOWN_RESOURCE_STATE || + state == UNKNOWN_RESOURCE_STATE || + IsD3D12WriteState(state)) + { + m_spSubresourceStates[SubresourceIndex] = state; + } + else + { + // Accumulate read state state bits + m_spSubresourceStates[SubresourceIndex] |= state; + } +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void CDesiredResourceState::SetResourceState(D3D12_RESOURCE_STATES state) +{ + m_bAllSubresourcesSame = true; + UpdateSubresourceState(0, state); +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void CDesiredResourceState::SetSubresourceState(UINT SubresourceIndex, D3D12_RESOURCE_STATES state) +{ + if (m_bAllSubresourcesSame && m_spSubresourceStates.size() > 1) + { + std::fill(m_spSubresourceStates.begin() + 1, m_spSubresourceStates.end(), m_spSubresourceStates[0]); + m_bAllSubresourcesSame = false; + } + if (m_spSubresourceStates.size() == 1) + { + SubresourceIndex = 0; + } + UpdateSubresourceState(SubresourceIndex, state); +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void CDesiredResourceState::Reset() +{ + SetResourceState(UNKNOWN_RESOURCE_STATE); +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void CCurrentResourceState::ConvertToSubresourceTracking() +{ + if (m_bAllSubresourcesSame && m_spLogicalState.size() > 1) + { + std::fill(m_spLogicalState.begin() + 1, m_spLogicalState.end(), m_spLogicalState[0]); + m_bAllSubresourcesSame = false; + } +} + +//---------------------------------------------------------------------------------------------------------------------------------- +CCurrentResourceState::CCurrentResourceState(UINT SubresourceCount, bool bSimultaneousAccess) + : m_bSimultaneousAccess(bSimultaneousAccess) + , m_spLogicalState(SubresourceCount) +{ + m_spLogicalState[0] = LogicalState{}; +} + +//---------------------------------------------------------------------------------------------------------------------------------- +D3D12_RESOURCE_STATES CCurrentResourceState::StateIfPromoted(D3D12_RESOURCE_STATES State, UINT SubresourceIndex) +{ + D3D12_RESOURCE_STATES Result = D3D12_RESOURCE_STATE_COMMON; + + if (m_bSimultaneousAccess || !!(State & ( + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | + D3D12_RESOURCE_STATE_COPY_SOURCE | + D3D12_RESOURCE_STATE_COPY_DEST))) + { + auto CurState = GetLogicalSubresourceState(SubresourceIndex); + + // If the current state is COMMON... + if(CurState.State == D3D12_RESOURCE_STATE_COMMON) + { + // ...then promotion is allowed + Result = State; + } + // If the current state is a read state resulting from previous promotion... + else if(CurState.IsPromotedState && !!(CurState.State & D3D12_RESOURCE_STATE_GENERIC_READ)) + { + // ...then (accumulated) promotion is allowed + Result = State |= CurState.State; + } + } + + return Result; +} + + + +//---------------------------------------------------------------------------------------------------------------------------------- +void CCurrentResourceState::SetLogicalResourceState(LogicalState const& State) +{ + m_bAllSubresourcesSame = true; + m_spLogicalState[0] = State; +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void CCurrentResourceState::SetLogicalSubresourceState(UINT SubresourceIndex, LogicalState const& State) +{ + ConvertToSubresourceTracking(); + m_spLogicalState[SubresourceIndex] = State; +} + +//---------------------------------------------------------------------------------------------------------------------------------- +auto CCurrentResourceState::GetLogicalSubresourceState(UINT SubresourceIndex) const -> LogicalState const& +{ + if (AreAllSubresourcesSame()) + { + SubresourceIndex = 0; + } + return m_spLogicalState[SubresourceIndex]; +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void CCurrentResourceState::Reset() +{ + m_bAllSubresourcesSame = true; + m_spLogicalState[0] = LogicalState{}; +} + +//---------------------------------------------------------------------------------------------------------------------------------- +ResourceStateManager::ResourceStateManager() +{ + list_inithead(&m_TransitionListHead); + // Reserve some space in these vectors upfront. Values are arbitrary. + m_vResourceBarriers.reserve(50); +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void ResourceStateManager::TransitionResource(TransitionableResourceState& Resource, + D3D12_RESOURCE_STATES state) +{ + Resource.m_DesiredState.SetResourceState(state); + if (!Resource.IsTransitionPending()) + { + list_add(&Resource.m_TransitionListEntry, &m_TransitionListHead); + } +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void ResourceStateManager::TransitionSubresource(TransitionableResourceState& Resource, + UINT SubresourceIndex, + D3D12_RESOURCE_STATES state) +{ + Resource.m_DesiredState.SetSubresourceState(SubresourceIndex, state); + if (!Resource.IsTransitionPending()) + { + list_add(&Resource.m_TransitionListEntry, &m_TransitionListHead); + } +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void ResourceStateManager::ApplyResourceTransitionsPreamble() +{ + m_vResourceBarriers.clear(); +} + +//---------------------------------------------------------------------------------------------------------------------------------- +/*static*/ bool ResourceStateManager::TransitionRequired(D3D12_RESOURCE_STATES CurrentState, D3D12_RESOURCE_STATES& DestinationState) +{ + // An exact match never needs a transition. + if (CurrentState == DestinationState) + { + return false; + } + + if ( + CurrentState == D3D12_RESOURCE_STATE_COMMON || + DestinationState == D3D12_RESOURCE_STATE_COMMON) + { + return true; + } + + // Current state already contains the destination state, we're good. + if ((CurrentState & DestinationState) == DestinationState) + { + DestinationState = CurrentState; + 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 (!IsD3D12WriteState(DestinationState) && !IsD3D12WriteState(CurrentState)) + { + DestinationState |= CurrentState; + } + return true; +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void ResourceStateManager::AddCurrentStateUpdate(TransitionableResourceState& Resource, + CCurrentResourceState& CurrentState, + UINT SubresourceIndex, + const CCurrentResourceState::LogicalState &NewLogicalState) +{ + if (SubresourceIndex == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES) + { + CurrentState.SetLogicalResourceState(NewLogicalState); + } + else + { + CurrentState.SetLogicalSubresourceState(SubresourceIndex, NewLogicalState); + } +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void ResourceStateManager::ProcessTransitioningResource(ID3D12Resource* pTransitioningResource, + TransitionableResourceState& TransitionableResourceState, + CCurrentResourceState& CurrentState, + UINT NumTotalSubresources, + UINT64 ExecutionId) +{ + // Figure out the set of subresources that are transitioning + auto& DestinationState = TransitionableResourceState.m_DesiredState; + bool bAllSubresourcesAtOnce = CurrentState.AreAllSubresourcesSame() && DestinationState.AreAllSubresourcesSame(); + + D3D12_RESOURCE_BARRIER TransitionDesc; + ZeroMemory(&TransitionDesc, sizeof(TransitionDesc)); + TransitionDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + TransitionDesc.Transition.pResource = pTransitioningResource; + + UINT numSubresources = bAllSubresourcesAtOnce ? 1 : NumTotalSubresources; + for (UINT i = 0; i < numSubresources; ++i) + { + D3D12_RESOURCE_STATES SubresourceDestinationState = DestinationState.GetSubresourceState(i); + TransitionDesc.Transition.Subresource = bAllSubresourcesAtOnce ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : i; + + // Is this subresource currently being used, or is it just being iterated over? + D3D12_RESOURCE_STATES after = DestinationState.GetSubresourceState(i); + if (after == UNKNOWN_RESOURCE_STATE) + { + // This subresource doesn't have any transition requested - move on to the next. + continue; + } + + ProcessTransitioningSubresourceExplicit( + CurrentState, + i, + SubresourceDestinationState, + after, + TransitionableResourceState, + TransitionDesc, + ExecutionId); // throw( bad_alloc ) + } + + // Update destination states. + // Coalesce destination state to ensure that it's set for the entire resource. + DestinationState.SetResourceState(UNKNOWN_RESOURCE_STATE); + +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void ResourceStateManager::ProcessTransitioningSubresourceExplicit( + CCurrentResourceState& CurrentState, + UINT SubresourceIndex, + D3D12_RESOURCE_STATES state, + D3D12_RESOURCE_STATES after, + TransitionableResourceState& TransitionableResourceState, + D3D12_RESOURCE_BARRIER& TransitionDesc, + UINT64 ExecutionId) +{ + // Simultaneous access resources currently in the COMMON + // state can be implicitly promoted to any state other state. + // Any non-simultaneous-access resources currently in the + // COMMON state can still be implicitly promoted to SRV, + // NON_PS_SRV, COPY_SRC, or COPY_DEST. + CCurrentResourceState::LogicalState CurrentLogicalState = CurrentState.GetLogicalSubresourceState(SubresourceIndex); + + // If the last time this logical state was set was in a different + // execution period and is decayable then decay the current state + // to COMMON + if(ExecutionId != CurrentLogicalState.ExecutionId && CurrentLogicalState.MayDecay) + { + CurrentLogicalState.State = D3D12_RESOURCE_STATE_COMMON; + CurrentLogicalState.IsPromotedState = false; + } + bool MayDecay = false; + bool IsPromotion = false; + + // If not promotable then StateIfPromoted will be D3D12_RESOURCE_STATE_COMMON + auto StateIfPromoted = CurrentState.StateIfPromoted(after, SubresourceIndex); + + if ( D3D12_RESOURCE_STATE_COMMON == StateIfPromoted ) + { + if (TransitionRequired(CurrentLogicalState.State, /*inout*/ after)) + { + // Insert a single concrete barrier (for non-simultaneous access resources). + TransitionDesc.Transition.StateBefore = D3D12_RESOURCE_STATES(CurrentLogicalState.State); + TransitionDesc.Transition.StateAfter = D3D12_RESOURCE_STATES(after); + assert(TransitionDesc.Transition.StateBefore != TransitionDesc.Transition.StateAfter); + m_vResourceBarriers.push_back(TransitionDesc); // throw( bad_alloc ) + + MayDecay = CurrentState.SupportsSimultaneousAccess() && !IsD3D12WriteState(after); + IsPromotion = false; + } + } + else + { + // Handle identity state transition + if(after != StateIfPromoted) + { + after = StateIfPromoted; + MayDecay = !IsD3D12WriteState(after); + IsPromotion = true; + } + } + + CCurrentResourceState::LogicalState NewLogicalState{after, ExecutionId, IsPromotion, MayDecay}; + AddCurrentStateUpdate(TransitionableResourceState, + CurrentState, + TransitionDesc.Transition.Subresource, + NewLogicalState); +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void ResourceStateManager::SubmitResourceTransitions(ID3D12GraphicsCommandList *pCommandList) +{ + // Submit any pending barriers on source command lists that are not the destination. + if (!m_vResourceBarriers.empty()) + { + pCommandList->ResourceBarrier((UINT)m_vResourceBarriers.size(), m_vResourceBarriers.data()); + } +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void ResourceStateManager::TransitionResource(TransitionableResourceState* pResource, D3D12_RESOURCE_STATES State) +{ + ResourceStateManager::TransitionResource(*pResource, State); +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void ResourceStateManager::TransitionSubresource(TransitionableResourceState* pResource, UINT SubresourceIndex, D3D12_RESOURCE_STATES State) +{ + ResourceStateManager::TransitionSubresource(*pResource, SubresourceIndex, State); +} + +//---------------------------------------------------------------------------------------------------------------------------------- +void ResourceStateManager::ApplyAllResourceTransitions(ID3D12GraphicsCommandList *pCommandList, UINT64 ExecutionId) +{ + ApplyResourceTransitionsPreamble(); + + ForEachTransitioningResource([=](TransitionableResourceState& ResourceBase) + { + TransitionableResourceState& CurResource = static_cast(ResourceBase); + + ID3D12Resource *pResource = CurResource.GetD3D12Resource(); + + ProcessTransitioningResource( + pResource, + CurResource, + CurResource.GetCurrentState(), + CurResource.NumSubresources(), + ExecutionId); + }); + + SubmitResourceTransitions(pCommandList); +} diff --git a/src/microsoft/resource_state_manager/D3D12ResourceState.h b/src/microsoft/resource_state_manager/D3D12ResourceState.h new file mode 100644 index 0000000..12342e0 --- /dev/null +++ b/src/microsoft/resource_state_manager/D3D12ResourceState.h @@ -0,0 +1,289 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef D3D12_RESOURCE_STATE_H +#define D3D12_RESOURCE_STATE_H + +#include +#include +#include + +#include "util/list.h" + +#define UNKNOWN_RESOURCE_STATE (D3D12_RESOURCE_STATES)0x8000u +#define RESOURCE_STATE_VALID_BITS 0x2f3fff +#define RESOURCE_STATE_VALID_INTERNAL_BITS 0x2fffff +constexpr D3D12_RESOURCE_STATES RESOURCE_STATE_ALL_WRITE_BITS = +D3D12_RESOURCE_STATE_RENDER_TARGET | +D3D12_RESOURCE_STATE_UNORDERED_ACCESS | +D3D12_RESOURCE_STATE_DEPTH_WRITE | +D3D12_RESOURCE_STATE_STREAM_OUT | +D3D12_RESOURCE_STATE_COPY_DEST | +D3D12_RESOURCE_STATE_RESOLVE_DEST | +D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE | +D3D12_RESOURCE_STATE_VIDEO_PROCESS_WRITE; + +//--------------------------------------------------------------------------------------------------------------------------------- +inline bool IsD3D12WriteState(UINT State) +{ + return (State & RESOURCE_STATE_ALL_WRITE_BITS) != 0; +} + +inline bool SupportsSimultaneousAccess(const D3D12_RESOURCE_DESC &desc) +{ + return D3D12_RESOURCE_DIMENSION_BUFFER == desc.Dimension || + !!(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS); +} + +//================================================================================================================================== +// CDesiredResourceState +// Stores the current desired state of either an entire resource, or each subresource. +//================================================================================================================================== +class CDesiredResourceState +{ +private: + bool m_bAllSubresourcesSame = true; + + std::vector m_spSubresourceStates; + +public: + CDesiredResourceState(UINT SubresourceCount) : + m_spSubresourceStates(SubresourceCount) + { + } + + bool AreAllSubresourcesSame() const { return m_bAllSubresourcesSame; } + + D3D12_RESOURCE_STATES GetSubresourceState(UINT SubresourceIndex) const; + void SetResourceState(D3D12_RESOURCE_STATES state); + void SetSubresourceState(UINT SubresourceIndex, D3D12_RESOURCE_STATES state); + + void Reset(); + +private: + void UpdateSubresourceState(unsigned SubresourceIndex, D3D12_RESOURCE_STATES state); +}; + +//================================================================================================================================== +// CCurrentResourceState +// Stores the current state of either an entire resource, or each subresource. +// Current state can either be shared read across multiple queues, or exclusive on a single queue. +//================================================================================================================================== +class CCurrentResourceState +{ +public: + struct LogicalState + { + D3D12_RESOURCE_STATES State = D3D12_RESOURCE_STATE_COMMON; + UINT64 ExecutionId = 0; + bool IsPromotedState = false; + bool MayDecay = false; + }; + +private: + const bool m_bSimultaneousAccess; + bool m_bAllSubresourcesSame = true; + + std::vector m_spLogicalState; + + void ConvertToSubresourceTracking(); + +public: + CCurrentResourceState(UINT SubresourceCount, bool bSimultaneousAccess); + + bool SupportsSimultaneousAccess() const { return m_bSimultaneousAccess; } + + // Returns the destination state if the current state is promotable. + // Returns D3D12_RESOURCE_STATE_COMMON if not. + D3D12_RESOURCE_STATES StateIfPromoted(D3D12_RESOURCE_STATES state, UINT SubresourceIndex); + + bool AreAllSubresourcesSame() const { return m_bAllSubresourcesSame; } + + void SetLogicalResourceState(LogicalState const& State); + void SetLogicalSubresourceState(UINT SubresourceIndex, LogicalState const& State); + LogicalState const& GetLogicalSubresourceState(UINT SubresourceIndex) const; + + void Reset(); +}; + +//================================================================================================================================== +// TransitionableResourceState +// A base class that transitionable resources should inherit from. +//================================================================================================================================== +struct TransitionableResourceState +{ + struct list_head m_TransitionListEntry; + CDesiredResourceState m_DesiredState; + + TransitionableResourceState(ID3D12Resource *pResource, UINT TotalSubresources, bool SupportsSimultaneousAccess) : + m_DesiredState(TotalSubresources), + m_TotalSubresources(TotalSubresources), + m_currentState(TotalSubresources, SupportsSimultaneousAccess), + m_pResource(pResource) + { + list_inithead(&m_TransitionListEntry); + } + + ~TransitionableResourceState() + { + if (IsTransitionPending()) + { + list_del(&m_TransitionListEntry); + } + } + + bool IsTransitionPending() const { return !list_is_empty(&m_TransitionListEntry); } + + UINT NumSubresources() { return m_TotalSubresources; } + + CCurrentResourceState& GetCurrentState() { return m_currentState; } + + inline ID3D12Resource* GetD3D12Resource() const { return m_pResource; } + +private: + unsigned m_TotalSubresources; + bool m_SupportsSimultaneousAccess; + + CCurrentResourceState m_currentState; + + ID3D12Resource* m_pResource; +}; + +//================================================================================================================================== +// ResourceStateManager +// The main business logic for handling resource transitions, including multi-queue sync and shared/exclusive state changes. +// +// Requesting a resource to transition simply updates destination state, and ensures it's in a list to be processed later. +// +// When processing ApplyAllResourceTransitions, we build up sets of vectors. +// There's a source one for each command list type, and a single one for the dest because we are applying +// the resource transitions for a single operation. +// There's also a vector for "tentative" barriers, which are merged into the destination vector if +// no flushing occurs as a result of submitting the final barrier operation. +// 99% of the time, there will only be the source being populated, but sometimes there will be a destination as well. +// If the source and dest of a transition require different types, we put a (source->COMMON) in the approriate source vector, +// and a (COMMON->dest) in the destination vector. +// +// Once all resources are processed, we: +// 1. Submit all source barriers, except ones belonging to the destination queue. +// 2. Flush all source command lists, except ones belonging to the destination queue. +// 3. Determine if the destination queue is going to be flushed. +// If so: Submit source barriers on that command list first, then flush it. +// If not: Accumulate source, dest, and tentative barriers so they can be sent to D3D12 in a single API call. +// 4. Insert waits on the destination queue - deferred waits, and waits for work on other queues. +// 5. Insert destination barriers. +// +// Only once all of this has been done do we update the "current" state of resources, +// because this is the only way that we know whether or not the destination queue has been flushed, +// and therefore, we can get the correct fence values to store in the subresources. +//================================================================================================================================== +class ResourceStateManager +{ +protected: + + struct list_head m_TransitionListHead; + + std::vector m_vResourceBarriers; + +public: + ResourceStateManager(); + + ~ResourceStateManager() + { + // All resources should be gone by this point, and each resource ensures it is no longer in this list. + assert(list_is_empty(&m_TransitionListHead)); + } + + // Call the D3D12 APIs to perform the resource barriers, command list submission, and command queue sync + // that was determined by previous calls to ProcessTransitioningResource. + void SubmitResourceTransitions(ID3D12GraphicsCommandList *pCommandList); + + // Transition the entire resource to a particular destination state on a particular command list. + void TransitionResource(TransitionableResourceState* pResource, + D3D12_RESOURCE_STATES State); + // Transition a single subresource to a particular destination state. + void TransitionSubresource(TransitionableResourceState* pResource, + UINT SubresourceIndex, + D3D12_RESOURCE_STATES State); + + // Submit all barriers and queue sync. + void ApplyAllResourceTransitions(ID3D12GraphicsCommandList *pCommandList, UINT64 ExecutionId); + +private: + // These methods set the destination state of the resource/subresources and ensure it's in the transition list. + void TransitionResource(TransitionableResourceState& Resource, + D3D12_RESOURCE_STATES State); + void TransitionSubresource(TransitionableResourceState& Resource, + UINT SubresourceIndex, + D3D12_RESOURCE_STATES State); + + // Clear out any state from previous iterations. + void ApplyResourceTransitionsPreamble(); + + // What to do with the resource, in the context of the transition list, after processing it. + enum class TransitionResult + { + // There are no more pending transitions that may be processed at a later time (i.e. draw time), + // so remove it from the pending transition list. + Remove, + // There are more transitions to be done, so keep it in the list. + Keep + }; + + // For every entry in the transition list, call a routine. + // This routine must return a TransitionResult which indicates what to do with the list. + template + void ForEachTransitioningResource(TFunc&& func) + { + list_for_each_entry_safe(TransitionableResourceState, pResource, &m_TransitionListHead, m_TransitionListEntry) + { + func(*pResource); + list_delinit(&pResource->m_TransitionListEntry); + } + } + + // Updates vectors with the operations that should be applied to the requested resource. + // May update the destination state of the resource. + void ProcessTransitioningResource(ID3D12Resource* pTransitioningResource, + TransitionableResourceState& TransitionableResourceState, + CCurrentResourceState& CurrentState, + UINT NumTotalSubresources, + UINT64 ExecutionId); + +private: + // Helpers + static bool TransitionRequired(D3D12_RESOURCE_STATES CurrentState, D3D12_RESOURCE_STATES& DestinationState); + void AddCurrentStateUpdate(TransitionableResourceState& Resource, + CCurrentResourceState& CurrentState, + UINT SubresourceIndex, + const CCurrentResourceState::LogicalState &NewLogicalState); + void ProcessTransitioningSubresourceExplicit(CCurrentResourceState& CurrentState, + UINT i, + D3D12_RESOURCE_STATES state, + D3D12_RESOURCE_STATES after, + TransitionableResourceState& TransitionableResourceState, + D3D12_RESOURCE_BARRIER& TransitionDesc, + UINT64 ExecutionId); +}; + +#endif // D3D12_RESOURCE_STATE_H diff --git a/src/microsoft/resource_state_manager/meson.build b/src/microsoft/resource_state_manager/meson.build new file mode 100644 index 0000000..f9167a6 --- /dev/null +++ b/src/microsoft/resource_state_manager/meson.build @@ -0,0 +1,37 @@ +# Copyright © Microsoft Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +files_libd3d12_resource_state = files( + 'D3D12ResourceState.cpp', +) + +libd3d12_resource_state = static_library( + 'd3d12_resource_state', + files_libd3d12_resource_state, + gnu_symbol_visibility : 'hidden', + include_directories : [inc_include, inc_src, inc_mesa], + dependencies: [], +) + +idep_libd3d12_resource_state = declare_dependency( + link_with : [libd3d12_resource_state], + include_directories : include_directories('.') +)