void D3D12ResourceManager::SerialiseResourceStates(vector<D3D12_RESOURCE_BARRIER> &barriers, map<ResourceId, SubresourceStateVector> &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::Serialise_InitialState(ResourceId resid, ID3D12DeviceChild *liveRes) { D3D12ResourceRecord *record = NULL; if(m_State >= WRITING) record = GetResourceRecord(resid); SERIALISE_ELEMENT(ResourceId, id, resid); SERIALISE_ELEMENT(D3D12ResourceType, type, record->type); if(m_State >= WRITING) { D3D12ResourceManager::InitialContentData initContents = GetInitialContents(id); if(type == Resource_DescriptorHeap) { D3D12Descriptor *descs = (D3D12Descriptor *)initContents.blob; uint32_t numElems = initContents.num; m_pSerialiser->SerialiseComplexArray("Descriptors", descs, numElems); } else if(type == Resource_Resource) { m_Device->ExecuteLists(); m_Device->FlushLists(); ID3D12Resource *copiedBuffer = (ID3D12Resource *)initContents.resource; if(initContents.num == 1) { copiedBuffer = (ID3D12Resource *)liveRes; } if(initContents.num == 2) { D3D12NOTIMP("Multisampled initial contents"); return true; } byte dummy[4] = {}; byte *ptr = NULL; uint64_t size = 0; HRESULT hr = E_NOINTERFACE; if(copiedBuffer) { hr = copiedBuffer->Map(0, NULL, (void **)&ptr); size = (uint64_t)copiedBuffer->GetDesc().Width; } if(FAILED(hr) || ptr == NULL) { size = 4; ptr = dummy; RDCERR("Failed to map buffer for readback! 0x%08x", hr); } m_pSerialiser->Serialise("NumBytes", size); size_t sz = (size_t)size; m_pSerialiser->SerialiseBuffer("BufferData", ptr, sz); if(SUCCEEDED(hr) && ptr) copiedBuffer->Unmap(0, NULL); return true; } else { RDCERR("Unexpected type needing an initial state serialised out: %d", type); return false; } } else { ID3D12DeviceChild *res = GetLiveResource(id); RDCASSERT(res != NULL); ResourceId liveid = GetLiveID(id); if(type == Resource_DescriptorHeap) { WrappedID3D12DescriptorHeap *heap = (WrappedID3D12DescriptorHeap *)res; uint32_t numElems = 0; D3D12Descriptor *descs = NULL; m_pSerialiser->SerialiseComplexArray("Descriptors", descs, numElems); D3D12_DESCRIPTOR_HEAP_DESC desc = heap->GetDesc(); // this heap doesn't have to be shader visible, we just use it to copy from desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ID3D12DescriptorHeap *copyheap = NULL; HRESULT hr = m_Device->GetReal()->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)©heap); if(FAILED(hr)) { RDCERR("Failed to create CPU descriptor heap for initial state: 0x%08x", hr); return false; } copyheap = new WrappedID3D12DescriptorHeap(copyheap, m_Device, desc); D3D12_CPU_DESCRIPTOR_HANDLE handle = copyheap->GetCPUDescriptorHandleForHeapStart(); UINT increment = m_Device->GetDescriptorHandleIncrementSize(desc.Type); for(uint32_t i = 0; i < numElems; i++) { descs[i].Create(desc.Type, m_Device, handle); handle.ptr += increment; } SAFE_DELETE_ARRAY(descs); SetInitialContents(id, D3D12ResourceManager::InitialContentData(copyheap, 0, NULL)); } else if(type == Resource_Resource) { D3D12_RESOURCE_DESC resDesc = ((ID3D12Resource *)res)->GetDesc(); if(resDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && resDesc.SampleDesc.Count > 1) { D3D12NOTIMP("Multisampled initial contents"); return true; } uint64_t size = 0; m_pSerialiser->Serialise("NumBytes", size); D3D12_HEAP_PROPERTIES heapProps; heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; heapProps.CreationNodeMask = 1; heapProps.VisibleNodeMask = 1; D3D12_RESOURCE_DESC desc; desc.Alignment = 0; desc.DepthOrArraySize = 1; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; desc.Flags = D3D12_RESOURCE_FLAG_NONE; desc.Format = DXGI_FORMAT_UNKNOWN; desc.Height = 1; desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; desc.MipLevels = 1; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Width = size; ID3D12Resource *copySrc = NULL; HRESULT hr = m_Device->GetReal()->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, __uuidof(ID3D12Resource), (void **)©Src); if(FAILED(hr)) { RDCERR("Couldn't create upload buffer: 0x%08x", hr); return false; } byte *ptr = NULL; hr = copySrc->Map(0, NULL, (void **)&ptr); if(FAILED(hr)) { RDCERR("Couldn't map upload buffer: 0x%08x", hr); ptr = NULL; } size_t sz = (size_t)size; m_pSerialiser->SerialiseBuffer("BufferData", ptr, sz); if(SUCCEEDED(hr)) copySrc->Unmap(0, NULL); else SAFE_DELETE_ARRAY(ptr); SetInitialContents(id, D3D12ResourceManager::InitialContentData(copySrc, 1, NULL)); return true; } else { RDCERR("Unexpected type needing an initial state serialised in: %d", type); return false; } } return true; }
void VulkanResourceManager::SerialiseImageStates(map<ResourceId, ImageLayouts> &states, vector<VkImageMemoryBarrier> &barriers) { Serialiser *localSerialiser = m_pSerialiser; SERIALISE_ELEMENT(uint32_t, NumMems, (uint32_t)states.size()); auto srcit = states.begin(); vector<pair<ResourceId, ImageRegionState> > vec; for(uint32_t i = 0; i < NumMems; i++) { SERIALISE_ELEMENT(ResourceId, id, srcit->first); SERIALISE_ELEMENT(uint32_t, NumStates, (uint32_t)srcit->second.subresourceStates.size()); ResourceId liveid; if(m_State < WRITING && HasLiveResource(id)) liveid = GetLiveID(id); for(uint32_t m = 0; m < NumStates; m++) { SERIALISE_ELEMENT(ImageRegionState, state, srcit->second.subresourceStates[m]); if(m_State < WRITING && liveid != ResourceId() && srcit != states.end()) { VkImageMemoryBarrier t; t.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; t.pNext = NULL; // these access masks aren't used, we need to apply a global memory barrier // to memory each time we restart log replaying. These barriers are just // to get images into the right layout t.srcAccessMask = 0; t.dstAccessMask = 0; // MULTIDEVICE need to handle multiple queues t.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; t.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; t.image = Unwrap(GetCurrentHandle<VkImage>(liveid)); t.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; ReplacePresentableImageLayout(state.newLayout); t.newLayout = state.newLayout; t.subresourceRange = state.subresourceRange; barriers.push_back(t); vec.push_back(std::make_pair(liveid, state)); } } if(m_State >= WRITING) srcit++; } ApplyBarriers(vec, states); for(size_t i = 0; i < vec.size(); i++) barriers[i].oldLayout = vec[i].second.oldLayout; // erase any do-nothing barriers for(auto it = barriers.begin(); it != barriers.end();) { if(it->oldLayout == UNKNOWN_PREV_IMG_LAYOUT) it->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; if(it->oldLayout == it->newLayout) it = barriers.erase(it); else ++it; } }