void D3D12ResourceManager::Create_InitialState(ResourceId id, ID3D12DeviceChild *live, bool hasData) { D3D12ResourceType type = IdentifyTypeByPtr(live); if(type == Resource_DescriptorHeap) { // set a NULL heap, if there are no initial contents for a descriptor heap we just leave // it all entirely undefined. SetInitialContents(id, D3D12ResourceManager::InitialContentData(NULL, 1, NULL)); } else if(type == Resource_Resource) { D3D12NOTIMP("Creating init states for resources"); // not handling any missing states at the moment } else { RDCERR("Unexpected type needing an initial state created: %d", type); } }
bool D3D11ResourceManager::Need_InitialStateChunk(ID3D11DeviceChild *res) { return IdentifyTypeByPtr(res) != Resource_Buffer; }
bool D3D11ResourceManager::Force_InitialState(ID3D11DeviceChild *res, bool prepare) { return IdentifyTypeByPtr(res) == Resource_UnorderedAccessView; }
bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) { ResourceId id = GetResID(res); D3D12ResourceType type = IdentifyTypeByPtr(res); if(type == Resource_DescriptorHeap) { WrappedID3D12DescriptorHeap *heap = (WrappedID3D12DescriptorHeap *)res; UINT numElems = heap->GetDesc().NumDescriptors; D3D12Descriptor *descs = (D3D12Descriptor *)Serialiser::AllocAlignedBuffer(sizeof(D3D12Descriptor) * numElems); memcpy(descs, heap->GetDescriptors(), sizeof(D3D12Descriptor) * numElems); SetInitialContents(heap->GetResourceID(), D3D12ResourceManager::InitialContentData(NULL, numElems, (byte *)descs)); return true; } else if(type == Resource_Resource) { WrappedID3D12Resource *r = (WrappedID3D12Resource *)res; ID3D12Pageable *pageable = r; bool nonresident = false; if(!r->Resident()) nonresident = true; D3D12_RESOURCE_DESC desc = r->GetDesc(); if(desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && desc.SampleDesc.Count > 1) { D3D12NOTIMP("Multisampled initial contents"); SetInitialContents(GetResID(r), D3D12ResourceManager::InitialContentData(NULL, 2, NULL)); return true; } else if(desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { D3D12_HEAP_PROPERTIES heapProps; r->GetHeapProperties(&heapProps, NULL); if(heapProps.Type == D3D12_HEAP_TYPE_READBACK) { // already on readback heap, just mark that we can map it directly and continue SetInitialContents(GetResID(r), D3D12ResourceManager::InitialContentData(NULL, 1, NULL)); return true; } heapProps.Type = D3D12_HEAP_TYPE_READBACK; heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; heapProps.CreationNodeMask = 1; heapProps.VisibleNodeMask = 1; desc.Flags = D3D12_RESOURCE_FLAG_NONE; ID3D12Resource *copyDst = NULL; HRESULT hr = m_Device->GetReal()->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, __uuidof(ID3D12Resource), (void **)©Dst); if(nonresident) m_Device->MakeResident(1, &pageable); if(SUCCEEDED(hr)) { ID3D12GraphicsCommandList *list = Unwrap(m_Device->GetInitialStateList()); list->CopyResource(copyDst, r->GetReal()); } else { RDCERR("Couldn't create readback buffer: 0x%08x", hr); } if(nonresident) { m_Device->CloseInitialStateList(); m_Device->ExecuteLists(); m_Device->FlushLists(); m_Device->Evict(1, &pageable); } SetInitialContents(GetResID(r), D3D12ResourceManager::InitialContentData(copyDst, 0, NULL)); return true; } else { D3D12_HEAP_PROPERTIES heapProps; heapProps.Type = D3D12_HEAP_TYPE_READBACK; heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; heapProps.CreationNodeMask = 1; heapProps.VisibleNodeMask = 1; D3D12_RESOURCE_DESC bufDesc; bufDesc.Alignment = 0; bufDesc.DepthOrArraySize = 1; bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; bufDesc.Flags = D3D12_RESOURCE_FLAG_NONE; bufDesc.Format = DXGI_FORMAT_UNKNOWN; bufDesc.Height = 1; bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; bufDesc.MipLevels = 1; bufDesc.SampleDesc.Count = 1; bufDesc.SampleDesc.Quality = 0; bufDesc.Width = 1; UINT numSubresources = desc.MipLevels; if(desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D) numSubresources *= desc.DepthOrArraySize; D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts = new D3D12_PLACED_SUBRESOURCE_FOOTPRINT[numSubresources]; m_Device->GetCopyableFootprints(&desc, 0, numSubresources, 0, layouts, NULL, NULL, &bufDesc.Width); ID3D12Resource *copyDst = NULL; HRESULT hr = m_Device->GetReal()->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &bufDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, __uuidof(ID3D12Resource), (void **)©Dst); if(nonresident) m_Device->MakeResident(1, &pageable); if(SUCCEEDED(hr)) { ID3D12GraphicsCommandList *list = Unwrap(m_Device->GetInitialStateList()); vector<D3D12_RESOURCE_BARRIER> barriers; const vector<D3D12_RESOURCE_STATES> &states = m_Device->GetSubresourceStates(GetResID(r)); barriers.reserve(states.size()); for(size_t i = 0; i < states.size(); i++) { if(states[i] & D3D12_RESOURCE_STATE_COPY_SOURCE) continue; D3D12_RESOURCE_BARRIER barrier; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = r->GetReal(); barrier.Transition.Subresource = (UINT)i; barrier.Transition.StateBefore = states[i]; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; barriers.push_back(barrier); } // transition to copy dest if(!barriers.empty()) list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); for(UINT i = 0; i < numSubresources; i++) { D3D12_TEXTURE_COPY_LOCATION dst, src; src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; src.pResource = r->GetReal(); src.SubresourceIndex = i; dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; dst.pResource = copyDst; dst.PlacedFootprint = layouts[i]; list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); } // transition back for(size_t i = 0; i < barriers.size(); i++) std::swap(barriers[i].Transition.StateBefore, barriers[i].Transition.StateAfter); if(!barriers.empty()) list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); } else { RDCERR("Couldn't create readback buffer: 0x%08x", hr); } if(nonresident) { m_Device->CloseInitialStateList(); m_Device->ExecuteLists(); m_Device->FlushLists(); m_Device->Evict(1, &pageable); } SAFE_DELETE_ARRAY(layouts); SetInitialContents(GetResID(r), D3D12ResourceManager::InitialContentData(copyDst, 0, NULL)); return true; } } else { RDCERR("Unexpected type needing an initial state prepared: %d", type); } return false; }
void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, InitialContentData data) { D3D12ResourceType type = IdentifyTypeByPtr(live); if(type == Resource_DescriptorHeap) { ID3D12DescriptorHeap *dstheap = (ID3D12DescriptorHeap *)live; ID3D12DescriptorHeap *srcheap = (ID3D12DescriptorHeap *)data.resource; if(srcheap) { // copy the whole heap m_Device->CopyDescriptorsSimple( srcheap->GetDesc().NumDescriptors, dstheap->GetCPUDescriptorHandleForHeapStart(), srcheap->GetCPUDescriptorHandleForHeapStart(), srcheap->GetDesc().Type); } } else if(type == Resource_Resource) { if(data.num == 1 && data.resource) { ID3D12Resource *copyDst = Unwrap((ID3D12Resource *)live); ID3D12Resource *copySrc = (ID3D12Resource *)data.resource; D3D12_HEAP_PROPERTIES heapProps = {}; copyDst->GetHeapProperties(&heapProps, NULL); // if destination is on the upload heap, it's impossible to copy via the device, // so we have to map both sides and CPU copy. if(heapProps.Type == D3D12_HEAP_TYPE_UPLOAD) { byte *src = NULL, *dst = NULL; HRESULT hr = S_OK; hr = copySrc->Map(0, NULL, (void **)&src); if(FAILED(hr)) { RDCERR("Doing CPU-side copy, couldn't map source: 0x%08x", hr); src = NULL; } if(copyDst->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { hr = copyDst->Map(0, NULL, (void **)&dst); if(FAILED(hr)) { RDCERR("Doing CPU-side copy, couldn't map source: 0x%08x", hr); dst = NULL; } if(src && dst) { memcpy(dst, src, (size_t)copySrc->GetDesc().Width); } if(dst) copyDst->Unmap(0, NULL); } else { D3D12_RESOURCE_DESC desc = copyDst->GetDesc(); UINT numSubresources = desc.MipLevels; if(desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D) numSubresources *= desc.DepthOrArraySize; D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts = new D3D12_PLACED_SUBRESOURCE_FOOTPRINT[numSubresources]; UINT *numrows = new UINT[numSubresources]; UINT64 *rowsizes = new UINT64[numSubresources]; m_Device->GetCopyableFootprints(&desc, 0, numSubresources, 0, layouts, numrows, rowsizes, NULL); for(UINT i = 0; i < numSubresources; i++) { hr = copyDst->Map(i, NULL, (void **)&dst); if(FAILED(hr)) { RDCERR("Doing CPU-side copy, couldn't map source: 0x%08x", hr); dst = NULL; } if(src && dst) { byte *bufPtr = src + layouts[i].Offset; byte *texPtr = dst; for(UINT d = 0; d < layouts[i].Footprint.Depth; d++) { for(UINT r = 0; r < numrows[i]; r++) { memcpy(bufPtr, texPtr, (size_t)rowsizes[i]); bufPtr += layouts[i].Footprint.RowPitch; texPtr += rowsizes[i]; } } } if(dst) copyDst->Unmap(0, NULL); } delete[] layouts; delete[] numrows; delete[] rowsizes; } if(src) copySrc->Unmap(0, NULL); } else { ID3D12GraphicsCommandList *list = Unwrap(m_Device->GetInitialStateList()); vector<D3D12_RESOURCE_BARRIER> barriers; const vector<D3D12_RESOURCE_STATES> &states = m_Device->GetSubresourceStates(GetResID(live)); barriers.reserve(states.size()); for(size_t i = 0; i < states.size(); i++) { if(states[i] & D3D12_RESOURCE_STATE_COPY_DEST) continue; D3D12_RESOURCE_BARRIER barrier; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = copyDst; barrier.Transition.Subresource = (UINT)i; barrier.Transition.StateBefore = states[i]; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; barriers.push_back(barrier); } // transition to copy dest if(!barriers.empty()) list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); if(copyDst->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { list->CopyBufferRegion(copyDst, 0, copySrc, 0, copySrc->GetDesc().Width); } else { D3D12_RESOURCE_DESC desc = copyDst->GetDesc(); UINT numSubresources = desc.MipLevels; if(desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D) numSubresources *= desc.DepthOrArraySize; D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts = new D3D12_PLACED_SUBRESOURCE_FOOTPRINT[numSubresources]; m_Device->GetCopyableFootprints(&desc, 0, numSubresources, 0, layouts, NULL, NULL, NULL); for(UINT i = 0; i < numSubresources; i++) { D3D12_TEXTURE_COPY_LOCATION dst, src; dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dst.pResource = copyDst; dst.SubresourceIndex = i; src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; src.pResource = copySrc; src.PlacedFootprint = layouts[i]; list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); } delete[] layouts; } // transition back to whatever it was before for(size_t i = 0; i < barriers.size(); i++) std::swap(barriers[i].Transition.StateBefore, barriers[i].Transition.StateAfter); if(!barriers.empty()) list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); #if ENABLED(SINGLE_FLUSH_VALIDATE) m_Device->CloseInitialStateList(); m_Device->ExecuteLists(); m_Device->FlushLists(true); #endif } } else { RDCERR("Unexpected num or NULL resource: %d, %p", data.num, data.resource); } } else { RDCERR("Unexpected type needing an initial state created: %d", type); } }
bool WrappedVulkan::ReleaseResource(WrappedVkRes *res) { if(res == NULL) return true; // MULTIDEVICE need to get the actual device that created this object VkDevice dev = GetDev(); const VkLayerDispatchTable *vt = ObjDisp(dev); WrappedVkNonDispRes *nondisp = (WrappedVkNonDispRes *)res; WrappedVkDispRes *disp = (WrappedVkDispRes *)res; uint64_t handle = (uint64_t)nondisp; switch(IdentifyTypeByPtr(res)) { case eResSurface: case eResSwapchain: if(m_State >= WRITING) RDCERR("Swapchain/swapchain object is leaking"); else RDCERR("Should be no swapchain/surface objects created on replay"); break; case eResUnknown: RDCERR("Unknown resource type!"); break; case eResCommandBuffer: // special case here, on replay we don't have the tracking // to remove these with the parent object so do it here. // This ensures we clean up after ourselves with a well- // behaved application. if(m_State < WRITING) GetResourceManager()->ReleaseWrappedResource((VkCommandBuffer)res); break; case eResDescriptorSet: if(m_State < WRITING) GetResourceManager()->ReleaseWrappedResource(VkDescriptorSet(handle)); break; case eResPhysicalDevice: if(m_State < WRITING) GetResourceManager()->ReleaseWrappedResource((VkPhysicalDevice)disp); break; case eResQueue: if(m_State < WRITING) GetResourceManager()->ReleaseWrappedResource((VkQueue)disp); break; case eResDevice: // these are explicitly released elsewhere, do not need to destroy // any API objects. // On replay though we do need to tidy up book-keeping for these. if(m_State < WRITING) { GetResourceManager()->ReleaseCurrentResource(disp->id); GetResourceManager()->RemoveWrapper(ToTypedHandle(disp->real.As<VkDevice>())); } break; case eResInstance: if(m_State < WRITING) { GetResourceManager()->ReleaseCurrentResource(disp->id); GetResourceManager()->RemoveWrapper(ToTypedHandle(disp->real.As<VkInstance>())); } break; case eResDeviceMemory: { VkDeviceMemory real = nondisp->real.As<VkDeviceMemory>(); GetResourceManager()->ReleaseWrappedResource(VkDeviceMemory(handle)); vt->FreeMemory(Unwrap(dev), real, NULL); break; } case eResBuffer: { VkBuffer real = nondisp->real.As<VkBuffer>(); GetResourceManager()->ReleaseWrappedResource(VkBuffer(handle)); vt->DestroyBuffer(Unwrap(dev), real, NULL); break; } case eResBufferView: { VkBufferView real = nondisp->real.As<VkBufferView>(); GetResourceManager()->ReleaseWrappedResource(VkBufferView(handle)); vt->DestroyBufferView(Unwrap(dev), real, NULL); break; } case eResImage: { VkImage real = nondisp->real.As<VkImage>(); GetResourceManager()->ReleaseWrappedResource(VkImage(handle)); vt->DestroyImage(Unwrap(dev), real, NULL); break; } case eResImageView: { VkImageView real = nondisp->real.As<VkImageView>(); GetResourceManager()->ReleaseWrappedResource(VkImageView(handle)); vt->DestroyImageView(Unwrap(dev), real, NULL); break; } case eResFramebuffer: { VkFramebuffer real = nondisp->real.As<VkFramebuffer>(); GetResourceManager()->ReleaseWrappedResource(VkFramebuffer(handle)); vt->DestroyFramebuffer(Unwrap(dev), real, NULL); break; } case eResRenderPass: { VkRenderPass real = nondisp->real.As<VkRenderPass>(); GetResourceManager()->ReleaseWrappedResource(VkRenderPass(handle)); vt->DestroyRenderPass(Unwrap(dev), real, NULL); break; } case eResShaderModule: { VkShaderModule real = nondisp->real.As<VkShaderModule>(); GetResourceManager()->ReleaseWrappedResource(VkShaderModule(handle)); vt->DestroyShaderModule(Unwrap(dev), real, NULL); break; } case eResPipelineCache: { VkPipelineCache real = nondisp->real.As<VkPipelineCache>(); GetResourceManager()->ReleaseWrappedResource(VkPipelineCache(handle)); vt->DestroyPipelineCache(Unwrap(dev), real, NULL); break; } case eResPipelineLayout: { VkPipelineLayout real = nondisp->real.As<VkPipelineLayout>(); GetResourceManager()->ReleaseWrappedResource(VkPipelineLayout(handle)); vt->DestroyPipelineLayout(Unwrap(dev), real, NULL); break; } case eResPipeline: { VkPipeline real = nondisp->real.As<VkPipeline>(); GetResourceManager()->ReleaseWrappedResource(VkPipeline(handle)); vt->DestroyPipeline(Unwrap(dev), real, NULL); break; } case eResSampler: { VkSampler real = nondisp->real.As<VkSampler>(); GetResourceManager()->ReleaseWrappedResource(VkSampler(handle)); vt->DestroySampler(Unwrap(dev), real, NULL); break; } case eResDescriptorPool: { VkDescriptorPool real = nondisp->real.As<VkDescriptorPool>(); GetResourceManager()->ReleaseWrappedResource(VkDescriptorPool(handle)); vt->DestroyDescriptorPool(Unwrap(dev), real, NULL); break; } case eResDescriptorSetLayout: { VkDescriptorSetLayout real = nondisp->real.As<VkDescriptorSetLayout>(); GetResourceManager()->ReleaseWrappedResource(VkDescriptorSetLayout(handle)); vt->DestroyDescriptorSetLayout(Unwrap(dev), real, NULL); break; } case eResCommandPool: { VkCommandPool real = nondisp->real.As<VkCommandPool>(); GetResourceManager()->ReleaseWrappedResource(VkCommandPool(handle)); vt->DestroyCommandPool(Unwrap(dev), real, NULL); break; } case eResFence: { VkFence real = nondisp->real.As<VkFence>(); GetResourceManager()->ReleaseWrappedResource(VkFence(handle)); vt->DestroyFence(Unwrap(dev), real, NULL); break; } case eResEvent: { VkEvent real = nondisp->real.As<VkEvent>(); GetResourceManager()->ReleaseWrappedResource(VkEvent(handle)); vt->DestroyEvent(Unwrap(dev), real, NULL); break; } case eResQueryPool: { VkQueryPool real = nondisp->real.As<VkQueryPool>(); GetResourceManager()->ReleaseWrappedResource(VkQueryPool(handle)); vt->DestroyQueryPool(Unwrap(dev), real, NULL); break; } case eResSemaphore: { VkSemaphore real = nondisp->real.As<VkSemaphore>(); GetResourceManager()->ReleaseWrappedResource(VkSemaphore(handle)); vt->DestroySemaphore(Unwrap(dev), real, NULL); break; } } return true; }