void afWriteTexture(SRVID id, const TexDesc& desc, const void* buf) { D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint; UINT numRow; UINT64 uploadSize, rowSizeInBytes; D3D12_RESOURCE_DESC destDesc = id->GetDesc(); deviceMan.GetDevice()->GetCopyableFootprints(&destDesc, 0, 1, 0, &footprint, &numRow, &rowSizeInBytes, &uploadSize); ComPtr<ID3D12Resource> uploadBuf = afCreateBuffer((int)uploadSize, buf); D3D12_TEXTURE_COPY_LOCATION uploadBufLocation = { uploadBuf.Get(), D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, footprint }, nativeBufLocation = { id.Get(), D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, 0 }; ID3D12GraphicsCommandList* list = deviceMan.GetCommandList(); D3D12_RESOURCE_BARRIER transition1 = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE, { id.Get(), 0, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COPY_DEST } }; list->ResourceBarrier(1, &transition1); list->CopyTextureRegion(&nativeBufLocation, 0, 0, 0, &uploadBufLocation, nullptr); D3D12_RESOURCE_BARRIER transition2 = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE, { id.Get(), 0, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ } }; list->ResourceBarrier(1, &transition2); deviceMan.Flush(); }
void RenderAPI_D3D12::EndModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int rowPitch, void* dataPtr) { ID3D12Device* device = s_D3D12->GetDevice(); const UINT64 kDataSize = textureWidth * textureHeight * 4; ID3D12Resource* upload = GetUploadResource(kDataSize); upload->Unmap(0, NULL); ID3D12Resource* resource = (ID3D12Resource*)textureHandle; D3D12_RESOURCE_DESC desc = resource->GetDesc(); assert(desc.Width == textureWidth); assert(desc.Height == textureHeight); D3D12_TEXTURE_COPY_LOCATION srcLoc = {}; srcLoc.pResource = upload; srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; device->GetCopyableFootprints(&desc, 0, 1, 0, &srcLoc.PlacedFootprint, nullptr, nullptr, nullptr); D3D12_TEXTURE_COPY_LOCATION dstLoc = {}; dstLoc.pResource = resource; dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dstLoc.SubresourceIndex = 0; // We inform Unity that we expect this resource to be in D3D12_RESOURCE_STATE_COPY_DEST state, // and because we do not barrier it ourselves, we tell Unity that no changes are done on our command list. UnityGraphicsD3D12ResourceState resourceState = {}; resourceState.resource = resource; resourceState.expected = D3D12_RESOURCE_STATE_COPY_DEST; resourceState.current = D3D12_RESOURCE_STATE_COPY_DEST; // Queue data upload s_D3D12CmdList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr); // Execute the command list s_D3D12CmdList->Close(); s_D3D12FenceValue = s_D3D12->ExecuteCommandList(s_D3D12CmdList, 1, &resourceState); }
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); } }