From dadf4a14d5f8a3b8439b376d6babba287b22195f Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 26 Sep 2025 12:26:32 +0100 Subject: [PATCH] Serialise D3D12 buffer initial contents less memory-intensivesly --- .../driver/d3d12/d3d12_command_queue_wrap.cpp | 4 + renderdoc/driver/d3d12/d3d12_common.cpp | 4 + renderdoc/driver/d3d12/d3d12_device.h | 2 +- .../d3d12/d3d12_device_rescreate_wrap.cpp | 14 ++ renderdoc/driver/d3d12/d3d12_initstate.cpp | 222 ++++++++++++------ renderdoc/driver/d3d12/d3d12_manager.h | 45 +++- renderdoc/driver/d3d12/d3d12_resources.cpp | 34 +++ renderdoc/driver/d3d12/d3d12_resources.h | 10 +- 8 files changed, 263 insertions(+), 72 deletions(-) diff --git a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp index 6ffed812d..c45a897b1 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp @@ -102,6 +102,10 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::UpdateTileMappings( // register this heap as having been used for sparse binding m_pDevice->AddSparseHeap(GetResID(pHeap)); + // mark the heap as dirty if this is a buffer resource + if(pResource->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) + GetResourceManager()->MarkDirtyResource(GetResID(pHeap)); + // define macros to help provide the defaults for NULL arrays #define REGION_START(i) \ (pResourceRegionStartCoordinates ? pResourceRegionStartCoordinates[i] \ diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index d0e36fee7..a055c1fbc 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -537,6 +537,10 @@ bool D3D12InitParams::IsSupportedVersion(uint64_t ver) if(ver == 0x12) return true; + // 0x13 -> 0x14 - Reserved/placed buffers are serialised via their heaps not per-buffer + if(ver == 0x13) + return true; + return false; } diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index 9143d872f..f653a7724 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -64,7 +64,7 @@ struct D3D12InitParams UINT SDKVersion = 0; // check if a frame capture section version is supported - static const uint64_t CurrentVersion = 0x13; + static const uint64_t CurrentVersion = 0x14; static bool IsSupportedVersion(uint64_t ver); }; diff --git a/renderdoc/driver/d3d12/d3d12_device_rescreate_wrap.cpp b/renderdoc/driver/d3d12/d3d12_device_rescreate_wrap.cpp index ca0cc6b0f..3eb644bca 100644 --- a/renderdoc/driver/d3d12/d3d12_device_rescreate_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_rescreate_wrap.cpp @@ -257,6 +257,7 @@ bool WrappedID3D12Device::Serialise_CreateResource( case D3D12Chunk::Device_CreateReservedResource2: APIProps.SparseResources = true; m_SparseResources.insert(GetResID(ret)); + m_ModResources.insert(GetResID(ret)); default: break; } @@ -601,7 +602,20 @@ HRESULT WrappedID3D12Device::CreateResource( if(pHeap) record->AddParent(GetRecord(pHeap)); + // all resources are marked dirty here, but we will skip the bytes of initial contents for + // sparse buffers (only the sparse tables get serialised) and initial contents entirely for + // placed buffer resources. It would be slightly better to never mark placed buffer resources + // dirty but the logic for dirtying resources with write references is generic and it's not much + // cost to skip them at initial contents prepare time. GetResourceManager()->MarkDirtyResource(wrapped->GetResourceID()); + + // for placed buffers resources, the resource itself is not going to be serialised but the heap + // underlying is. Sparse resources mark the heap dirty when first bound to pages + if(desc0.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER && pHeap) + { + GetResourceManager()->MarkDirtyResource(GetResID(pHeap)); + GetResourceManager()->AddPlacedResource(wrapped->GetResourceID(), GetResID(pHeap)); + } } else { diff --git a/renderdoc/driver/d3d12/d3d12_initstate.cpp b/renderdoc/driver/d3d12/d3d12_initstate.cpp index e27c9d11f..1e33a072d 100644 --- a/renderdoc/driver/d3d12/d3d12_initstate.cpp +++ b/renderdoc/driver/d3d12/d3d12_initstate.cpp @@ -102,37 +102,65 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) SetInitialContents(heap->GetResourceID(), initContents); return true; } - else if(type == Resource_Resource) + else if(type == Resource_Resource || type == Resource_Heap) { - WrappedID3D12Resource *r = (WrappedID3D12Resource *)res; - ID3D12Pageable *unwrappedPageable = r->UnwrappedResidencyPageable(); + WrappedID3D12Resource *wrappedResource = (WrappedID3D12Resource *)res; + ID3D12Resource *unwrappedResource = NULL; + ID3D12Pageable *unwrappedPageable = NULL; bool nonresident = false; - if(!r->IsResident()) - nonresident = true; + if(type == Resource_Heap) + { + wrappedResource = NULL; + unwrappedResource = ((WrappedID3D12Heap *)res)->GetUnwrappedWholeMemBuffer(); + } + else + { + unwrappedResource = wrappedResource->GetReal(); + unwrappedPageable = wrappedResource->UnwrappedResidencyPageable(); - D3D12_RESOURCE_DESC desc = r->GetDesc(); + if(!wrappedResource->IsResident()) + nonresident = true; + } + + D3D12_RESOURCE_DESC desc = unwrappedResource->GetDesc(); D3D12InitialContents initContents; Sparse::PageTable *sparseTable = NULL; - if(GetRecord(r)->sparseTable) - sparseTable = new Sparse::PageTable(*GetRecord(r)->sparseTable); + if(wrappedResource && GetRecord(wrappedResource)->sparseTable) + sparseTable = new Sparse::PageTable(*GetRecord(wrappedResource)->sparseTable); if(desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { - if(r->IsAccelerationStructureResource()) + if(type == Resource_Resource && wrappedResource->IsAccelerationStructureResource()) { initContents = D3D12InitialContents(D3D12InitialContents::AccelerationStructure, NULL); - SetInitialContents(GetResID(r), initContents); + SetInitialContents(GetResID(res), initContents); + return true; + } + + // if this is a sparse buffer, we don't serialise its contents so just save the sparse table itself + if(sparseTable) + { + initContents = D3D12InitialContents(D3D12InitialContents::SparseOnly, NULL); + initContents.sparseTable = sparseTable; + + SetInitialContents(GetResID(res), initContents); + return true; + } + + // placed buffer resources do not serialise initial contents + if(type == Resource_Resource && wrappedResource->GetHeap()) + { return true; } D3D12_HEAP_PROPERTIES heapProps = {}; if(sparseTable == NULL) - r->GetHeapProperties(&heapProps, NULL); + unwrappedResource->GetHeapProperties(&heapProps, NULL); HRESULT hr = S_OK; @@ -144,21 +172,21 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) byte *buffer = AllocAlignedBuffer(RDCMAX(desc.Width, 64ULL)); byte *bufData = NULL; - hr = r->GetReal()->Map(0, NULL, (void **)&bufData); + hr = unwrappedResource->Map(0, NULL, (void **)&bufData); if(SUCCEEDED(hr)) { memcpy(buffer, bufData, size); D3D12_RANGE range = {}; - r->GetReal()->Unmap(0, &range); + unwrappedResource->Unmap(0, &range); } else { RDCERR("Couldn't map directly readback buffer: HRESULT: %s", ToStr(hr).c_str()); } - SetInitialContents(GetResID(r), D3D12InitialContents(buffer, size)); + SetInitialContents(GetResID(res), D3D12InitialContents(buffer, size)); return true; } @@ -172,20 +200,23 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) if(nonresident) m_Device->GetReal()->MakeResident(1, &unwrappedPageable); - const SubresourceStateVector &states = m_Device->GetSubresourceStates(GetResID(res)); - RDCASSERT(states.size() == 1); + const SubresourceStateVector empty; + const SubresourceStateVector &states = + type == Resource_Heap ? empty : m_Device->GetSubresourceStates(GetResID(res)); + RDCASSERT(type == Resource_Heap || states.size() == 1); D3D12_RESOURCE_BARRIER barrier; // upload heap resources can't be transitioned, and any resources in the new layouts don't // need to either since each submit does a big flush - const bool needsTransition = !isUploadHeap && states[0].IsStates() && + const bool needsTransition = type == Resource_Resource && !isUploadHeap && + states[0].IsStates() && (states[0].ToStates() & D3D12_RESOURCE_STATE_COPY_SOURCE) == 0; if(needsTransition) { barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = r->GetReal(); + barrier.Transition.pResource = unwrappedResource; barrier.Transition.Subresource = (UINT)0; barrier.Transition.StateBefore = states[0].ToStates(); barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; @@ -199,7 +230,7 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) if(SUCCEEDED(hr)) { - list->CopyResource(copyDst, r->GetReal()); + list->CopyResource(copyDst, unwrappedResource); } else { @@ -238,7 +269,7 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) ID3D12Resource *arrayTexture = NULL; BarrierSet::AccessType accessType = BarrierSet::CopySourceAccess; - ID3D12Resource *unwrappedCopySource = r->GetReal(); + ID3D12Resource *unwrappedCopySource = unwrappedResource; bool isDepth = IsDepthFormat(desc.Format) || (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) != 0; @@ -279,7 +310,8 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) BarrierSet barriers; - barriers.Configure(r, m_Device->GetSubresourceStates(GetResID(r)), accessType); + barriers.Configure(wrappedResource, m_Device->GetSubresourceStates(GetResID(wrappedResource)), + accessType); barriers.Apply(list); if(arrayTexture) @@ -291,7 +323,7 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) m_Device->FlushLists(); // expand multisamples out to array - m_Device->GetDebugManager()->CopyTex2DMSToArray(NULL, arrayTexture, r->GetReal()); + m_Device->GetDebugManager()->CopyTex2DMSToArray(NULL, arrayTexture, unwrappedResource); // open the initial state list again for the remainder of the work list = m_Device->GetInitialStateList(); @@ -431,7 +463,7 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) initContents.sparseTable = sparseTable; - SetInitialContents(GetResID(r), initContents); + SetInitialContents(GetResID(res), initContents); return true; } else if(type == Resource_AccelerationStructure) @@ -857,7 +889,7 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI SetInitialContents(id, D3D12InitialContents(copyheap)); } } - else if(type == Resource_Resource) + else if(type == Resource_Resource || type == Resource_Heap) { byte *ResourceContents = NULL; uint64_t ContentsLength = 0; @@ -868,7 +900,10 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI if(IsReplayingAndReading()) { - liveRes = (ID3D12Resource *)GetLiveResource(id); + ID3D12DeviceChild *live = GetLiveResource(id); + liveRes = (ID3D12Resource *)live; + if(type == Resource_Heap) + liveRes = ((WrappedID3D12Heap *)live)->GetUnwrappedWholeMemBuffer(); } SparseBinds *sparseBinds = NULL; @@ -906,7 +941,8 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI mappedBuffer = (ID3D12Resource *)initial->resource; - if(initial->tag == D3D12InitialContents::AccelerationStructure) + if(initial->tag == D3D12InitialContents::AccelerationStructure || + initial->tag == D3D12InitialContents::SparseOnly) { mappedBuffer = NULL; } @@ -943,7 +979,7 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI D3D12_RESOURCE_DESC resDesc = liveRes->GetDesc(); D3D12_HEAP_PROPERTIES heapProps = {}; - if(!m_Device->IsSparseResource(GetResID(liveRes))) + if(!m_Device->IsSparseResource(GetLiveID(id))) liveRes->GetHeapProperties(&heapProps, NULL); const bool isCPUCopyHeap = @@ -952,13 +988,25 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI heapProps.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE) && heapProps.MemoryPoolPreference == D3D12_MEMORY_POOL_L0; - if(((WrappedID3D12Resource *)liveRes)->IsAccelerationStructureResource()) + if(type == Resource_Resource && + ((WrappedID3D12Resource *)liveRes)->IsAccelerationStructureResource()) { mappedBuffer = NULL; D3D12InitialContents initContents(D3D12InitialContents::AccelerationStructure, NULL); SetInitialContents(id, initContents); } + // from verison 0x14 onwards we don't serialise the contents of sparse resources + else if(type == Resource_Resource && sparseBinds && ser.VersionAtLeast(0x14) && + ContentsLength == 0) + { + mappedBuffer = NULL; + + D3D12InitialContents initContents(D3D12InitialContents::SparseOnly, NULL); + initContents.sparseBinds = sparseBinds; + + SetInitialContents(id, initContents); + } else if(heapProps.Type == D3D12_HEAP_TYPE_UPLOAD || isCPUCopyHeap) { // if destination is on the upload heap, it's impossible to copy via the device, @@ -968,7 +1016,7 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI D3D12InitialContents initContents(D3D12InitialContents::Copy, type); ResourceContents = initContents.srcData = AllocAlignedBuffer(RDCMAX(ContentsLength, 64ULL)); - initContents.resourceType = Resource_Resource; + initContents.resourceType = type; SetInitialContents(id, initContents); } else @@ -1044,7 +1092,7 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI if(IsReplayingAndReading() && mappedBuffer) { D3D12InitialContents initContents(D3D12InitialContents::Copy, type); - initContents.resourceType = Resource_Resource; + initContents.resourceType = type; initContents.resource = mappedBuffer; initContents.sparseBinds = sparseBinds; @@ -1066,7 +1114,7 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI else { D3D12_HEAP_PROPERTIES heapProps = {}; - if(!m_Device->IsSparseResource(GetResID(liveRes))) + if(!m_Device->IsSparseResource(GetLiveID(id))) liveRes->GetHeapProperties(&heapProps, NULL); // if the resource is sparse, create on default heap @@ -1657,24 +1705,39 @@ void D3D12ResourceManager::Create_InitialState(ResourceId id, ID3D12DeviceChild // it all entirely undefined. SetInitialContents(id, D3D12InitialContents((ID3D12DescriptorHeap *)NULL)); } - else if(type == Resource_Resource) + else if(type == Resource_Resource || type == Resource_Heap) { ID3D12Resource *res = ((ID3D12Resource *)live); WrappedID3D12Resource *wrappedResource = (WrappedID3D12Resource *)res; - if(wrappedResource->IsAccelerationStructureResource()) + D3D12_HEAP_PROPERTIES heapProps = {}; + D3D12_RESOURCE_DESC resDesc = {}; + if(type == Resource_Heap) + { + wrappedResource = NULL; + res = NULL; + resDesc = ((WrappedID3D12Heap *)live)->GetUnwrappedWholeMemBuffer()->GetDesc(); + heapProps = ((WrappedID3D12Heap *)live)->GetDesc().Properties; + } + else if(wrappedResource->IsAccelerationStructureResource()) { SetInitialContents(id, D3D12InitialContents(D3D12InitialContents::AccelerationStructure, (ID3D12Resource *)NULL)); return; } + else if(wrappedResource->GetHeap()) + { + // don't create initial states for placed resources + return; + } + else + { + resDesc = res->GetDesc(); - D3D12_RESOURCE_DESC resDesc = res->GetDesc(); - - D3D12_HEAP_PROPERTIES heapProps = {}; - if(!m_Device->IsSparseResource(GetResID(live))) - res->GetHeapProperties(&heapProps, NULL); + if(!m_Device->IsSparseResource(GetResID(live))) + res->GetHeapProperties(&heapProps, NULL); + } const bool isCPUCopyHeap = heapProps.Type == D3D12_HEAP_TYPE_CUSTOM && (heapProps.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_BACK || @@ -1727,7 +1790,7 @@ void D3D12ResourceManager::Create_InitialState(ResourceId id, ID3D12DeviceChild else { D3D12InitialContents initContents(D3D12InitialContents::ForceCopy, type); - initContents.resourceType = Resource_Resource; + initContents.resourceType = type; initContents.resource = copy; if(m_Device->IsSparseResource(GetResID(live))) @@ -1768,7 +1831,7 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init srcheap->GetCPUDescriptorHandleForHeapStart(), srcheap->GetDesc().Type); } } - else if(type == Resource_Resource) + else if(type == Resource_Resource || type == Resource_Heap) { if(data.tag == D3D12InitialContents::AccelerationStructure) return; @@ -1778,13 +1841,32 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init if(IsActiveReplaying(m_State) && m_Device->IsReadOnlyResource(id)) { } + else if(data.tag == D3D12InitialContents::SparseOnly) + { + if(IsLoading(m_State) || m_Device->GetQueue()->IsSparseUpdatedResource(GetResID(live))) + data.sparseBinds->Apply(m_Device, (ID3D12Resource *)live); + + if(m_Device->HasFatalError()) + return; + } else if(data.tag == D3D12InitialContents::Copy || data.tag == D3D12InitialContents::ForceCopy) { - ID3D12Resource *copyDst = (ID3D12Resource *)live; + ID3D12Resource *wrappedCopyDst = NULL; + ID3D12Resource *unwrappedCopyDst = NULL; - if(!copyDst) + if(type == Resource_Heap) { - RDCERR("Missing copy destination in initial state apply (%p)", copyDst); + unwrappedCopyDst = ((WrappedID3D12Heap *)live)->GetUnwrappedWholeMemBuffer(); + } + else + { + wrappedCopyDst = (ID3D12Resource *)live; + unwrappedCopyDst = Unwrap(wrappedCopyDst); + } + + if(!unwrappedCopyDst) + { + RDCERR("Missing copy destination in initial state apply (%p)", unwrappedCopyDst); return; } @@ -1799,7 +1881,7 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init } else { - copyDst->GetHeapProperties(&heapProps, NULL); + unwrappedCopyDst->GetHeapProperties(&heapProps, NULL); } const bool isCPUCopyHeap = @@ -1823,11 +1905,11 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init HRESULT hr = S_OK; - D3D12_RESOURCE_DESC desc = copyDst->GetDesc(); + D3D12_RESOURCE_DESC desc = unwrappedCopyDst->GetDesc(); if(desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { - hr = Unwrap(copyDst)->Map(0, NULL, (void **)&dst); + hr = unwrappedCopyDst->Map(0, NULL, (void **)&dst); CHECK_HR(m_Device, hr); if(FAILED(hr)) @@ -1837,10 +1919,10 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init } if(src && dst) - memcpy(dst, src, (size_t)copyDst->GetDesc().Width); + memcpy(dst, src, (size_t)unwrappedCopyDst->GetDesc().Width); if(dst) - Unwrap(copyDst)->Unmap(0, NULL); + unwrappedCopyDst->Unmap(0, NULL); } else { @@ -1859,9 +1941,9 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init for(UINT i = 0; i < numSubresources; i++) { if(desc.Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN) - hr = Unwrap(copyDst)->Map(i, NULL, NULL); + hr = unwrappedCopyDst->Map(i, NULL, NULL); else - hr = Unwrap(copyDst)->Map(i, NULL, (void **)&dst); + hr = unwrappedCopyDst->Map(i, NULL, (void **)&dst); CHECK_HR(m_Device, hr); if(FAILED(hr)) @@ -1889,8 +1971,8 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init if(texPtr) memcpy(bufPtr, texPtr, (size_t)rowsizes[i]); else - copyDst->WriteToSubresource(i, &box, bufPtr, (UINT)rowsizes[i], - (UINT)rowsizes[i]); + unwrappedCopyDst->WriteToSubresource(i, &box, bufPtr, (UINT)rowsizes[i], + (UINT)rowsizes[i]); bufPtr += layouts[i].Footprint.RowPitch; if(texPtr) @@ -1906,7 +1988,7 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init } if(dst) - Unwrap(copyDst)->Unmap(i, NULL); + unwrappedCopyDst->Unmap(i, NULL); } delete[] layouts; @@ -1931,26 +2013,31 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init BarrierSet barriers; - barriers.Configure(copyDst, m_Device->GetSubresourceStates(GetResID(live)), - BarrierSet::CopyDestAccess); - barriers.Apply(list); + if(type != Resource_Heap) + { + barriers.Configure(wrappedCopyDst, m_Device->GetSubresourceStates(GetResID(live)), + BarrierSet::CopyDestAccess); + barriers.Apply(list); + } - if(copyDst->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) + if(unwrappedCopyDst->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { D3D12_RESOURCE_DESC srcDesc = copySrc->GetDesc(); - D3D12_RESOURCE_DESC dstDesc = copyDst->GetDesc(); + D3D12_RESOURCE_DESC dstDesc = unwrappedCopyDst->GetDesc(); - list->CopyBufferRegion(copyDst, 0, copySrc, 0, RDCMIN(srcDesc.Width, dstDesc.Width)); + Unwrap(list)->CopyBufferRegion(unwrappedCopyDst, 0, Unwrap(copySrc), 0, + RDCMIN(srcDesc.Width, dstDesc.Width)); } - else if(copyDst->GetDesc().SampleDesc.Count > 1 || data.tag == D3D12InitialContents::ForceCopy) + else if(unwrappedCopyDst->GetDesc().SampleDesc.Count > 1 || + data.tag == D3D12InitialContents::ForceCopy) { // MSAA texture was pre-uploaded and decoded, just copy the texture. // Similarly for created initial states - list->CopyResource(copyDst, copySrc); + Unwrap(list)->CopyResource(unwrappedCopyDst, Unwrap(copySrc)); } else { - D3D12_RESOURCE_DESC desc = copyDst->GetDesc(); + D3D12_RESOURCE_DESC desc = unwrappedCopyDst->GetDesc(); UINT numSubresources = desc.MipLevels; if(desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D) @@ -1995,11 +2082,11 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init D3D12_TEXTURE_COPY_LOCATION dst, src; dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dst.pResource = copyDst; + dst.pResource = unwrappedCopyDst; dst.SubresourceIndex = i; src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src.pResource = copySrc; + src.pResource = Unwrap(copySrc); m_Device->GetCopyableFootprints(&desc, i, 1, offset, &src.PlacedFootprint, NULL, NULL, &subSize); @@ -2010,7 +2097,7 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init continue; } - list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); + Unwrap(list)->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); offset += subSize; offset = AlignUp(offset, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); @@ -2025,7 +2112,10 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, D3D12Init } } - barriers.Unapply(list); + if(type != Resource_Heap) + { + barriers.Unapply(list); + } if(D3D12_Debug_SingleSubmitFlushing()) { diff --git a/renderdoc/driver/d3d12/d3d12_manager.h b/renderdoc/driver/d3d12/d3d12_manager.h index e15688253..aa3d58ebe 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.h +++ b/renderdoc/driver/d3d12/d3d12_manager.h @@ -717,7 +717,9 @@ struct D3D12InitialContents // for created initial states we always have an identical resource ForceCopy, // for handling acceleration structures - AccelerationStructure + AccelerationStructure, + // for sparse buffers with no contents + SparseOnly, }; D3D12InitialContents(D3D12Descriptor *d, uint32_t n) : D3D12InitialContents() { @@ -1486,6 +1488,44 @@ public: D3D12GpuBufferAllocator &GetGPUBufferAllocator() { return m_GPUBufferAllocator; } + void AddPlacedResource(ResourceId resId, ResourceId heapId) + { + SCOPED_LOCK(m_PlacedLock); + m_PlacedHeapForResource[resId] = heapId; + } + + void RemovePlacedResource(ResourceId resId) + { + SCOPED_LOCK(m_PlacedLock); + m_PlacedHeapForResource.erase(resId); + } + + ResourceId GetPlacedHeapForResource(ResourceId resId) + { + SCOPED_LOCK(m_PlacedLock); + auto it = m_PlacedHeapForResource.find(resId); + if(it == m_PlacedHeapForResource.end()) + return ResourceId(); + return it->second; + } + + template + void MarkResourceFrameReferenced(ResourceId id, FrameRefType refType, Compose comp) + { + ResourceManager::MarkResourceFrameReferenced(id, refType, comp); + ResourceId id2 = GetPlacedHeapForResource(id); + if(id2 != ResourceId()) + ResourceManager::MarkResourceFrameReferenced(id2, refType, comp); + } + + inline void MarkResourceFrameReferenced(ResourceId id, FrameRefType refType) + { + ResourceManager::MarkResourceFrameReferenced(id, refType); + ResourceId id2 = GetPlacedHeapForResource(id); + if(id2 != ResourceId()) + ResourceManager::MarkResourceFrameReferenced(id2, refType); + } + template void SerialiseResourceStates(SerialiserType &ser, BarrierSet &barriers, std::map &states, @@ -1517,6 +1557,9 @@ private: D3D12RTManager *m_RTManager; D3D12GpuBufferAllocator m_GPUBufferAllocator; + Threading::CriticalSection m_PlacedLock; + std::unordered_map m_PlacedHeapForResource; + // dummy handle to use - starting from near highest valid pointer to minimise risk of overlap with real handles static const uint64_t FirstDummyHandle = UINTPTR_MAX - 1024; uint64_t m_DummyHandle = FirstDummyHandle; diff --git a/renderdoc/driver/d3d12/d3d12_resources.cpp b/renderdoc/driver/d3d12/d3d12_resources.cpp index 68001eae5..a1494d2ca 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.cpp +++ b/renderdoc/driver/d3d12/d3d12_resources.cpp @@ -159,6 +159,38 @@ D3D12AccelerationStructure::~D3D12AccelerationStructure() Shutdown(); } +WrappedID3D12Heap::WrappedID3D12Heap(ID3D12Heap *real, WrappedID3D12Device *device) + : WrappedDeviceChild12(real, device) +{ + D3D12_HEAP_DESC desc = GetDesc(); + if((desc.Flags & D3D12_HEAP_FLAG_DENY_BUFFERS) == 0) + { + D3D12_RESOURCE_DESC resDesc = {}; + resDesc.Width = GetDesc().SizeInBytes; + resDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + resDesc.Height = 1; + resDesc.DepthOrArraySize = 1; + resDesc.MipLevels = 1; + resDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + resDesc.SampleDesc.Count = 1; + + if(desc.Flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER) + resDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER; + + D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON; + if(desc.Properties.Type == D3D12_HEAP_TYPE_UPLOAD) + state = D3D12_RESOURCE_STATE_GENERIC_READ; + else if(desc.Properties.Type == D3D12_HEAP_TYPE_READBACK) + state = D3D12_RESOURCE_STATE_COPY_DEST; + + HRESULT hr = + device->GetReal()->CreatePlacedResource(real, 0, &resDesc, D3D12_RESOURCE_STATE_COMMON, NULL, + __uuidof(ID3D12Resource), (void **)&m_WholeMem); + + RDCASSERT(SUCCEEDED(hr)); + } +} + bool WrappedID3D12Resource::CreateAccStruct(D3D12BufferOffset bufferOffset, D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE type, UINT64 byteSize, ResourceId id, @@ -216,6 +248,8 @@ WrappedID3D12Resource::~WrappedID3D12Resource() SAFE_RELEASE(it->second); } + m_pDevice->GetResourceManager()->RemovePlacedResource(GetResourceID()); + if(IsReplayMode(m_pDevice->GetState())) m_pDevice->RemoveReplayResource(GetResourceID()); diff --git a/renderdoc/driver/d3d12/d3d12_resources.h b/renderdoc/driver/d3d12/d3d12_resources.h index 58315cd24..368e069e0 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.h +++ b/renderdoc/driver/d3d12/d3d12_resources.h @@ -721,6 +721,8 @@ class WrappedID3D12Heap : public WrappedDeviceChild12, public ID3D12PageableTools { ID3D12PageableTools *m_Pageable = NULL; + + ID3D12Resource *m_WholeMem = NULL; public: ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12Heap); @@ -729,12 +731,12 @@ public: TypeEnum = Resource_Heap, }; - WrappedID3D12Heap(ID3D12Heap *real, WrappedID3D12Device *device) - : WrappedDeviceChild12(real, device) - { - } + ID3D12Resource *GetUnwrappedWholeMemBuffer() { return m_WholeMem; } + + WrappedID3D12Heap(ID3D12Heap *real, WrappedID3D12Device *device); virtual ~WrappedID3D12Heap() { + SAFE_RELEASE(m_WholeMem); SAFE_RELEASE(m_Pageable); Shutdown(); }