Path: blob/21.2-virgl/src/microsoft/resource_state_manager/D3D12ResourceState.h
4560 views
/*1* Copyright © Microsoft Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#ifndef D3D12_RESOURCE_STATE_H24#define D3D12_RESOURCE_STATE_H2526#ifndef _WIN3227#include <wsl/winadapter.h>28#endif2930#include <vector>31#include <assert.h>32#include <directx/d3d12.h>3334#include "util/list.h"3536#if defined(__GNUC__)37#pragma GCC diagnostic ignored "-Winvalid-offsetof"38#endif3940#define UNKNOWN_RESOURCE_STATE (D3D12_RESOURCE_STATES)0x8000u41#define RESOURCE_STATE_VALID_BITS 0x2f3fff42#define RESOURCE_STATE_VALID_INTERNAL_BITS 0x2fffff43constexpr D3D12_RESOURCE_STATES RESOURCE_STATE_ALL_WRITE_BITS =44D3D12_RESOURCE_STATE_RENDER_TARGET |45D3D12_RESOURCE_STATE_UNORDERED_ACCESS |46D3D12_RESOURCE_STATE_DEPTH_WRITE |47D3D12_RESOURCE_STATE_STREAM_OUT |48D3D12_RESOURCE_STATE_COPY_DEST |49D3D12_RESOURCE_STATE_RESOLVE_DEST |50D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE |51D3D12_RESOURCE_STATE_VIDEO_PROCESS_WRITE;5253//---------------------------------------------------------------------------------------------------------------------------------54inline bool IsD3D12WriteState(UINT State)55{56return (State & RESOURCE_STATE_ALL_WRITE_BITS) != 0;57}5859inline bool SupportsSimultaneousAccess(const D3D12_RESOURCE_DESC &desc)60{61return D3D12_RESOURCE_DIMENSION_BUFFER == desc.Dimension ||62!!(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS);63}6465//==================================================================================================================================66// CDesiredResourceState67// Stores the current desired state of either an entire resource, or each subresource.68//==================================================================================================================================69class CDesiredResourceState70{71private:72bool m_bAllSubresourcesSame = true;7374std::vector<D3D12_RESOURCE_STATES> m_spSubresourceStates;7576public:77CDesiredResourceState(UINT SubresourceCount) :78m_spSubresourceStates(SubresourceCount)79{80}8182bool AreAllSubresourcesSame() const { return m_bAllSubresourcesSame; }8384D3D12_RESOURCE_STATES GetSubresourceState(UINT SubresourceIndex) const;85void SetResourceState(D3D12_RESOURCE_STATES state);86void SetSubresourceState(UINT SubresourceIndex, D3D12_RESOURCE_STATES state);8788void Reset();8990private:91void UpdateSubresourceState(unsigned SubresourceIndex, D3D12_RESOURCE_STATES state);92};9394//==================================================================================================================================95// CCurrentResourceState96// Stores the current state of either an entire resource, or each subresource.97// Current state can either be shared read across multiple queues, or exclusive on a single queue.98//==================================================================================================================================99class CCurrentResourceState100{101public:102struct LogicalState103{104D3D12_RESOURCE_STATES State = D3D12_RESOURCE_STATE_COMMON;105UINT64 ExecutionId = 0;106bool IsPromotedState = false;107bool MayDecay = false;108};109110private:111const bool m_bSimultaneousAccess;112bool m_bAllSubresourcesSame = true;113114std::vector<LogicalState> m_spLogicalState;115116void ConvertToSubresourceTracking();117118public:119CCurrentResourceState(UINT SubresourceCount, bool bSimultaneousAccess);120121bool SupportsSimultaneousAccess() const { return m_bSimultaneousAccess; }122123// Returns the destination state if the current state is promotable.124// Returns D3D12_RESOURCE_STATE_COMMON if not.125D3D12_RESOURCE_STATES StateIfPromoted(D3D12_RESOURCE_STATES state, UINT SubresourceIndex);126127bool AreAllSubresourcesSame() const { return m_bAllSubresourcesSame; }128129void SetLogicalResourceState(LogicalState const& State);130void SetLogicalSubresourceState(UINT SubresourceIndex, LogicalState const& State);131LogicalState const& GetLogicalSubresourceState(UINT SubresourceIndex) const;132133void Reset();134};135136//==================================================================================================================================137// TransitionableResourceState138// A base class that transitionable resources should inherit from.139//==================================================================================================================================140struct TransitionableResourceState141{142struct list_head m_TransitionListEntry;143CDesiredResourceState m_DesiredState;144145TransitionableResourceState(ID3D12Resource *pResource, UINT TotalSubresources, bool SupportsSimultaneousAccess) :146m_DesiredState(TotalSubresources),147m_TotalSubresources(TotalSubresources),148m_currentState(TotalSubresources, SupportsSimultaneousAccess),149m_pResource(pResource)150{151list_inithead(&m_TransitionListEntry);152}153154~TransitionableResourceState()155{156if (IsTransitionPending())157{158list_del(&m_TransitionListEntry);159}160}161162bool IsTransitionPending() const { return !list_is_empty(&m_TransitionListEntry); }163164UINT NumSubresources() { return m_TotalSubresources; }165166CCurrentResourceState& GetCurrentState() { return m_currentState; }167168inline ID3D12Resource* GetD3D12Resource() const { return m_pResource; }169170private:171unsigned m_TotalSubresources;172173CCurrentResourceState m_currentState;174175ID3D12Resource* m_pResource;176};177178//==================================================================================================================================179// ResourceStateManager180// The main business logic for handling resource transitions, including multi-queue sync and shared/exclusive state changes.181//182// Requesting a resource to transition simply updates destination state, and ensures it's in a list to be processed later.183//184// When processing ApplyAllResourceTransitions, we build up sets of vectors.185// There's a source one for each command list type, and a single one for the dest because we are applying186// the resource transitions for a single operation.187// There's also a vector for "tentative" barriers, which are merged into the destination vector if188// no flushing occurs as a result of submitting the final barrier operation.189// 99% of the time, there will only be the source being populated, but sometimes there will be a destination as well.190// If the source and dest of a transition require different types, we put a (source->COMMON) in the approriate source vector,191// and a (COMMON->dest) in the destination vector.192//193// Once all resources are processed, we:194// 1. Submit all source barriers, except ones belonging to the destination queue.195// 2. Flush all source command lists, except ones belonging to the destination queue.196// 3. Determine if the destination queue is going to be flushed.197// If so: Submit source barriers on that command list first, then flush it.198// If not: Accumulate source, dest, and tentative barriers so they can be sent to D3D12 in a single API call.199// 4. Insert waits on the destination queue - deferred waits, and waits for work on other queues.200// 5. Insert destination barriers.201//202// Only once all of this has been done do we update the "current" state of resources,203// because this is the only way that we know whether or not the destination queue has been flushed,204// and therefore, we can get the correct fence values to store in the subresources.205//==================================================================================================================================206class ResourceStateManager207{208protected:209210struct list_head m_TransitionListHead;211212std::vector<D3D12_RESOURCE_BARRIER> m_vResourceBarriers;213214public:215ResourceStateManager();216217~ResourceStateManager()218{219// All resources should be gone by this point, and each resource ensures it is no longer in this list.220assert(list_is_empty(&m_TransitionListHead));221}222223// Call the D3D12 APIs to perform the resource barriers, command list submission, and command queue sync224// that was determined by previous calls to ProcessTransitioningResource.225void SubmitResourceTransitions(ID3D12GraphicsCommandList *pCommandList);226227// Transition the entire resource to a particular destination state on a particular command list.228void TransitionResource(TransitionableResourceState* pResource,229D3D12_RESOURCE_STATES State);230// Transition a single subresource to a particular destination state.231void TransitionSubresource(TransitionableResourceState* pResource,232UINT SubresourceIndex,233D3D12_RESOURCE_STATES State);234235// Submit all barriers and queue sync.236void ApplyAllResourceTransitions(ID3D12GraphicsCommandList *pCommandList, UINT64 ExecutionId);237238private:239// These methods set the destination state of the resource/subresources and ensure it's in the transition list.240void TransitionResource(TransitionableResourceState& Resource,241D3D12_RESOURCE_STATES State);242void TransitionSubresource(TransitionableResourceState& Resource,243UINT SubresourceIndex,244D3D12_RESOURCE_STATES State);245246// Clear out any state from previous iterations.247void ApplyResourceTransitionsPreamble();248249// What to do with the resource, in the context of the transition list, after processing it.250enum class TransitionResult251{252// There are no more pending transitions that may be processed at a later time (i.e. draw time),253// so remove it from the pending transition list.254Remove,255// There are more transitions to be done, so keep it in the list.256Keep257};258259// For every entry in the transition list, call a routine.260// This routine must return a TransitionResult which indicates what to do with the list.261template <typename TFunc>262void ForEachTransitioningResource(TFunc&& func)263{264list_for_each_entry_safe(TransitionableResourceState, pResource, &m_TransitionListHead, m_TransitionListEntry)265{266func(*pResource);267list_delinit(&pResource->m_TransitionListEntry);268}269}270271// Updates vectors with the operations that should be applied to the requested resource.272// May update the destination state of the resource.273void ProcessTransitioningResource(ID3D12Resource* pTransitioningResource,274TransitionableResourceState& TransitionableResourceState,275CCurrentResourceState& CurrentState,276UINT NumTotalSubresources,277UINT64 ExecutionId);278279private:280// Helpers281static bool TransitionRequired(D3D12_RESOURCE_STATES CurrentState, D3D12_RESOURCE_STATES& DestinationState);282void AddCurrentStateUpdate(TransitionableResourceState& Resource,283CCurrentResourceState& CurrentState,284UINT SubresourceIndex,285const CCurrentResourceState::LogicalState &NewLogicalState);286void ProcessTransitioningSubresourceExplicit(CCurrentResourceState& CurrentState,287UINT i,288D3D12_RESOURCE_STATES state,289D3D12_RESOURCE_STATES after,290TransitionableResourceState& TransitionableResourceState,291D3D12_RESOURCE_BARRIER& TransitionDesc,292UINT64 ExecutionId);293};294295#endif // D3D12_RESOURCE_STATE_H296297298