diff --git a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp index b23e88d60..208bc5041 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp @@ -92,6 +92,8 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists( // TODO apply barriers from command list to current resource state tracking + m_pDevice->ApplyBarriers(record->bakedCommands->cmdInfo->barriers); + // need to lock the whole section of code, not just the check on // m_State, as we also need to make sure we don't check the state, // start marking dirty resources then while we're doing so the diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index 3638f9bbc..e010e899e 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -45,6 +45,24 @@ enum D3D12ComponentMapping { }; +UINT GetNumSubresources(const D3D12_RESOURCE_DESC *desc) +{ + switch(desc->Dimension) + { + default: + case D3D12_RESOURCE_DIMENSION_UNKNOWN: + RDCERR("Unexpected resource dimension! %d", desc->Dimension); + break; + case D3D12_RESOURCE_DIMENSION_BUFFER: return 1; + case D3D12_RESOURCE_DIMENSION_TEXTURE1D: + case D3D12_RESOURCE_DIMENSION_TEXTURE2D: + return RDCMAX((UINT16)1, desc->DepthOrArraySize) * RDCMAX((UINT16)1, desc->MipLevels); + case D3D12_RESOURCE_DIMENSION_TEXTURE3D: return RDCMAX((UINT16)1, desc->MipLevels); + } + + return 1; +} + string ToStrHelper::Get(const D3D12ComponentMapping &el) { string ret; diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index f37aa6a0b..1f5f1f98e 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -37,6 +37,8 @@ // debugbreak. #define D3D12NOTIMP(...) RDCDEBUG("D3D12 not implemented - " __VA_ARGS__) +UINT GetNumSubresources(const D3D12_RESOURCE_DESC *desc); + class WrappedID3D12Device; template diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index 7025a293c..7ff93e65e 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -462,6 +462,12 @@ void WrappedID3D12Device::FirstFrame(WrappedIDXGISwapChain3 *swap) } } +void WrappedID3D12Device::ApplyBarriers(vector &barriers) +{ + SCOPED_LOCK(m_ResourceStatesLock); + GetResourceManager()->ApplyBarriers(barriers, m_ResourceStates); +} + void WrappedID3D12Device::ReleaseSwapchainResources(WrappedIDXGISwapChain3 *swap) { if(swap) @@ -502,9 +508,10 @@ bool WrappedID3D12Device::Serialise_WrapSwapchainBuffer(WrappedIDXGISwapChain3 * // the original type will be stored in the texture below Descriptor.Format = GetTypelessFormat(Descriptor.Format); - // create fake texture HRESULT hr = E_INVALIDARG; + // TODO create fake backbuffer texture + if(FAILED(hr)) { RDCERR("Failed to create fake back buffer, HRESULT: 0x%08x", hr); @@ -517,6 +524,10 @@ bool WrappedID3D12Device::Serialise_WrapSwapchainBuffer(WrappedIDXGISwapChain3 * fakeBB->SetName(L"Swap Chain Buffer"); GetResourceManager()->AddLiveResource(TexID, fakeBB); + + SubresourceStateVector &states = m_ResourceStates[wrapped->GetResourceID()]; + + states.resize(1, D3D12_RESOURCE_STATE_PRESENT); } } @@ -561,6 +572,13 @@ IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(WrappedIDXGISwapChain3 *swap, Serialise_WrapSwapchainBuffer(swap, swapDesc, buffer, pRes); record->AddChunk(scope.Get()); + + { + SCOPED_LOCK(m_ResourceStatesLock); + SubresourceStateVector &states = m_ResourceStates[id]; + + states.resize(1, D3D12_RESOURCE_STATE_PRESENT); + } } if(buffer == 0 && m_State >= WRITING) @@ -785,11 +803,18 @@ bool WrappedID3D12Device::Serialise_BeginCaptureFrame(bool applyInitialState) return true; } - // TODO save initial resource states + vector barriers; + + { + SCOPED_LOCK(m_ResourceStatesLock); // not needed on replay, but harmless also + GetResourceManager()->SerialiseResourceStates(barriers, m_ResourceStates); + } if(applyInitialState) { // apply initial resource states + for(size_t i = 0; i < barriers.size(); i++) + barriers[i].Transition.pResource = Unwrap(barriers[i].Transition.pResource); } return true; @@ -1068,6 +1093,13 @@ bool WrappedID3D12Device::Serialise_ReleaseResource(ID3D12DeviceChild *res) void WrappedID3D12Device::ReleaseResource(ID3D12DeviceChild *res) { D3D12NOTIMP("ReleaseResource"); + + ResourceId id = GetResID(res); + + { + SCOPED_LOCK(m_ResourceStatesLock); + m_ResourceStates.erase(id); + } } bool WrappedID3D12Device::Serialise_SetShaderDebugPath(ID3D12DeviceChild *res, const char *p) diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index f9b53d818..5ec7e02fa 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -256,6 +256,11 @@ private: ResourceId m_ResourceID; D3D12ResourceRecord *m_DeviceRecord; + // used both on capture and replay side to track resource states. Only locked + // in capture + map m_ResourceStates; + Threading::CriticalSection m_ResourceStatesLock; + struct SwapPresentInfo { D3D12_CPU_DESCRIPTOR_HANDLE rtvs[8]; @@ -297,6 +302,8 @@ public: void ReleaseSwapchainResources(IDXGISwapChain *swap, IUnknown **backbuffers, int numBackbuffers); void FirstFrame(WrappedIDXGISwapChain3 *swap); + void ApplyBarriers(vector &barriers); + void StartFrameCapture(void *dev, void *wnd); bool EndFrameCapture(void *dev, void *wnd); diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp index 3ea79d832..ee3532de2 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp @@ -604,6 +604,9 @@ bool WrappedID3D12Device::Serialise_CreateCommittedResource( ret = new WrappedID3D12Resource(ret, this); GetResourceManager()->AddLiveResource(Res, ret); + + SubresourceStateVector &states = m_ResourceStates[GetResID(ret)]; + states.resize(GetNumSubresources(&desc), state); } } @@ -659,6 +662,13 @@ HRESULT WrappedID3D12Device::CreateCommittedResource(const D3D12_HEAP_PROPERTIES } } + { + SCOPED_LOCK(m_ResourceStatesLock); + SubresourceStateVector &states = m_ResourceStates[wrapped->GetResourceID()]; + + states.resize(GetNumSubresources(pResourceDesc), InitialResourceState); + } + *ppvResource = (ID3D12Resource *)wrapped; } diff --git a/renderdoc/driver/d3d12/d3d12_manager.cpp b/renderdoc/driver/d3d12/d3d12_manager.cpp index 8f71f28b5..78df5f5e9 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.cpp +++ b/renderdoc/driver/d3d12/d3d12_manager.cpp @@ -131,6 +131,97 @@ D3D12_CPU_DESCRIPTOR_HANDLE FromPortableHandle(D3D12ResourceManager *manager, Po return D3D12_CPU_DESCRIPTOR_HANDLE(); } +// debugging logging for barriers +#if 1 +#define BARRIER_DBG RDCLOG +#define BARRIER_ASSERT RDCASSERTMSG +#else +#define BARRIER_DBG(...) +#define BARRIER_ASSERT(...) +#endif + +void D3D12ResourceManager::ApplyBarriers(vector &barriers, + map &states) +{ + for(size_t b = 0; b < barriers.size(); b++) + { + D3D12_RESOURCE_TRANSITION_BARRIER &trans = barriers[b].Transition; + ResourceId id = GetResID(trans.pResource); + SubresourceStateVector &st = states[id]; + + // skip non-transitions, or begin-halves of transitions + if(barriers[b].Type != D3D12_RESOURCE_BARRIER_TYPE_TRANSITION || + (barriers[b].Flags & D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY)) + continue; + + if(trans.Subresource == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES) + { + for(size_t i = 0; i < st.size(); i++) + { + BARRIER_ASSERT("Mismatching before state", st[i] == trans.StateBefore, st[i], + trans.StateBefore, i); + st[i] = trans.StateAfter; + } + } + else + { + BARRIER_ASSERT("Mismatching before state", st[trans.Subresource] == trans.StateBefore, + st[trans.Subresource], trans.StateBefore, trans.Subresource); + st[trans.Subresource] = trans.StateAfter; + } + } +} + +void D3D12ResourceManager::SerialiseResourceStates(vector &barriers, + map &states) +{ + SERIALISE_ELEMENT(uint32_t, NumMems, (uint32_t)states.size()); + + auto srcit = states.begin(); + + for(uint32_t i = 0; i < NumMems; i++) + { + SERIALISE_ELEMENT(ResourceId, id, srcit->first); + SERIALISE_ELEMENT(uint32_t, NumStates, (uint32_t)srcit->second.size()); + + ResourceId liveid; + if(m_State < WRITING && HasLiveResource(id)) + liveid = GetLiveID(id); + + for(uint32_t m = 0; m < NumStates; m++) + { + SERIALISE_ELEMENT(D3D12_RESOURCE_STATES, state, srcit->second[m]); + + if(m_State < WRITING && liveid != ResourceId() && srcit != states.end()) + { + D3D12_RESOURCE_BARRIER b; + b.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + b.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + b.Transition.pResource = (ID3D12Resource *)GetCurrentResource(liveid); + b.Transition.Subresource = m; + b.Transition.StateBefore = states[liveid][m]; + b.Transition.StateAfter = state; + + barriers.push_back(b); + } + } + + if(m_State >= WRITING) + srcit++; + } + + // erase any do-nothing barriers + for(auto it = barriers.begin(); it != barriers.end();) + { + if(it->Transition.StateBefore == it->Transition.StateAfter) + it = barriers.erase(it); + else + ++it; + } + + ApplyBarriers(barriers, states); +} + bool D3D12ResourceManager::SerialisableResource(ResourceId id, D3D12ResourceRecord *record) { if(record->SpecialResource) diff --git a/renderdoc/driver/d3d12/d3d12_manager.h b/renderdoc/driver/d3d12/d3d12_manager.h index d5bf5243c..c3d9332fd 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.h +++ b/renderdoc/driver/d3d12/d3d12_manager.h @@ -274,6 +274,8 @@ struct D3D12ResourceRecord : public ResourceRecord CmdListRecordingInfo *cmdInfo; }; +typedef vector SubresourceStateVector; + class D3D12ResourceManager : public ResourceManager { @@ -289,6 +291,12 @@ public: return (T *)GetLiveResource(id); } + void ApplyBarriers(vector &barriers, + map &states); + + void SerialiseResourceStates(vector &barriers, + map &states); + private: bool SerialisableResource(ResourceId id, D3D12ResourceRecord *record); ResourceId GetID(ID3D12DeviceChild *res);