diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 725e68dfd..9360f4215 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -179,9 +179,11 @@ private: { id = m_FakeBBImgId; im = m_FakeBBIm; extent = m_FakeBBExtent; fmt = m_FakeBBFmt; } // VKTODO all these m_*Info things need to be locked and ensure we only access - // them in slow path functions like creation + // them in slow path functions like creation, or just moved elsewhere like inside + // the wrapped objects map m_MemoryInfo; map m_ImageInfo; + map m_BufferMemBinds; struct CmdBufferInfo { diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 219dbc5e5..5e388270b 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -593,8 +593,6 @@ void VulkanReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_ vt->QueueWaitIdle(Unwrap(q)); } - // VKTODOHIGH ultra cheeky - map memory directly without copying - // to host-visible memory byte *pData = NULL; vt->MapMemory(Unwrap(dev), readbackmem, 0, 0, 0, (void **)&pData); @@ -909,7 +907,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay o void VulkanReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector &secondaryDraws, MeshDisplay cfg) { - RDCUNIMPLEMENTED("RenderMesh"); + VULKANNOTIMP("RenderMesh"); } bool VulkanReplay::CheckResizeOutputWindow(uint64_t id) @@ -1142,8 +1140,97 @@ uint64_t VulkanReplay::MakeOutputWindow(void *wn, bool depth) vector VulkanReplay::GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) { - RDCUNIMPLEMENTED("GetBufferData"); - return vector(); + VkDevice dev = m_pDriver->GetDev(); + VkCmdBuffer cmd = m_pDriver->GetCmd(); + VkQueue q = m_pDriver->GetQ(); + const VkLayerDispatchTable *vt = ObjDisp(dev); + + ResourceId memid = m_pDriver->m_BufferMemBinds[buff]; + + VkBuffer srcBuf = m_pDriver->GetResourceManager()->GetCurrentHandle(buff); + + if(len == 0) + { + len = uint32_t(m_pDriver->m_MemoryInfo[memid].size - offset); + } + + if(len > 0 && VkDeviceSize(offset+len) > m_pDriver->m_MemoryInfo[memid].size) + { + RDCWARN("Attempting to read off the end of the array. Will be clamped"); + len = RDCMIN(len, uint32_t(m_pDriver->m_MemoryInfo[memid].size - offset)); + } + + vector ret; + ret.resize(len); + + // VKTODOMED - coarse: wait for all writes to this buffer + vt->DeviceWaitIdle(Unwrap(dev)); + + VkDeviceMemory readbackmem = VK_NULL_HANDLE; + VkBuffer destbuf = VK_NULL_HANDLE; + VkResult vkr = VK_SUCCESS; + byte *pData = NULL; + + { + VkCmdBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, NULL, VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT }; + + vkr = vt->ResetCommandBuffer(Unwrap(cmd), 0); + RDCASSERT(vkr == VK_SUCCESS); + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERT(vkr == VK_SUCCESS); + + VkBufferCreateInfo bufInfo = { + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL, + (VkDeviceSize)ret.size(), VK_BUFFER_USAGE_GENERAL, 0, + VK_SHARING_MODE_EXCLUSIVE, 0, NULL, + }; + + VkResult vkr = vt->CreateBuffer(Unwrap(dev), &bufInfo, &destbuf); + RDCASSERT(vkr == VK_SUCCESS); + + VkMemoryRequirements mrq; + vkr = vt->GetBufferMemoryRequirements(Unwrap(dev), destbuf, &mrq); + RDCASSERT(vkr == VK_SUCCESS); + + VkMemoryAllocInfo allocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, NULL, + mrq.size, m_pDriver->GetReadbackMemoryIndex(mrq.memoryTypeBits), + }; + + vkr = vt->AllocMemory(Unwrap(dev), &allocInfo, &readbackmem); + RDCASSERT(vkr == VK_SUCCESS); + + vkr = vt->BindBufferMemory(Unwrap(dev), destbuf, readbackmem, 0); + RDCASSERT(vkr == VK_SUCCESS); + + VkBufferCopy region = { offset, 0, (VkDeviceSize)ret.size() }; + vt->CmdCopyBuffer(Unwrap(cmd), Unwrap(srcBuf), destbuf, 1, ®ion); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERT(vkr == VK_SUCCESS); + + vkr = vt->QueueSubmit(Unwrap(q), 1, UnwrapPtr(cmd), VK_NULL_HANDLE); + RDCASSERT(vkr == VK_SUCCESS); + + vkr = vt->QueueWaitIdle(Unwrap(q)); + RDCASSERT(vkr == VK_SUCCESS); + } + + vkr = vt->MapMemory(Unwrap(dev), readbackmem, 0, 0, 0, (void **)&pData); + RDCASSERT(vkr == VK_SUCCESS); + + RDCASSERT(pData != NULL); + memcpy(&ret[0], pData, ret.size()); + + vkr = vt->UnmapMemory(Unwrap(dev), readbackmem); + RDCASSERT(vkr == VK_SUCCESS); + + vt->DeviceWaitIdle(Unwrap(dev)); + + vt->DestroyBuffer(Unwrap(dev), destbuf); + vt->FreeMemory(Unwrap(dev), readbackmem); + + return ret; } bool VulkanReplay::IsRenderOutput(ResourceId id) diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index 2568fbf18..f65c87600 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -379,6 +379,8 @@ bool WrappedVulkan::Serialise_vkBindBufferMemory( buffer = GetResourceManager()->GetLiveHandle(bufId); mem = GetResourceManager()->GetLiveHandle(memId); + m_BufferMemBinds[GetResID(buffer)] = GetResID(mem); + ObjDisp(device)->BindBufferMemory(Unwrap(device), Unwrap(buffer), Unwrap(mem), offs); } @@ -496,6 +498,10 @@ bool WrappedVulkan::Serialise_vkCreateBuffer( device = GetResourceManager()->GetLiveHandle(devId); VkBuffer buf = VK_NULL_HANDLE; + // ensure we can always readback from buffers + if(info.usage != VK_BUFFER_USAGE_GENERAL) + info.usage |= VK_BUFFER_USAGE_TRANSFER_SOURCE_BIT; + VkResult ret = ObjDisp(device)->CreateBuffer(Unwrap(device), &info, &buf); if(ret != VK_SUCCESS)