From f3ef0caa28f4659c7be9c9a2e8698e63eea44ac7 Mon Sep 17 00:00:00 2001 From: Aliya Pazylbekova Date: Tue, 16 Jul 2019 13:43:37 -0400 Subject: [PATCH] vulkan pixel history - Part 1 Copy pre and post modification values --- renderdoc/driver/vulkan/CMakeLists.txt | 1 + .../driver/vulkan/renderdoc_vulkan.vcxproj | 1 + renderdoc/driver/vulkan/vk_debug.cpp | 7 + renderdoc/driver/vulkan/vk_debug.h | 14 + renderdoc/driver/vulkan/vk_pixelhistory.cpp | 646 ++++++++++++++++++ renderdoc/driver/vulkan/vk_replay.cpp | 9 - 6 files changed, 669 insertions(+), 9 deletions(-) create mode 100644 renderdoc/driver/vulkan/vk_pixelhistory.cpp diff --git a/renderdoc/driver/vulkan/CMakeLists.txt b/renderdoc/driver/vulkan/CMakeLists.txt index f5aede826..1eadf3751 100644 --- a/renderdoc/driver/vulkan/CMakeLists.txt +++ b/renderdoc/driver/vulkan/CMakeLists.txt @@ -29,6 +29,7 @@ set(sources vk_manager.cpp vk_manager.h vk_memory.cpp + vk_pixelhistory.cpp vk_replay.cpp vk_replay.h vk_resources.cpp diff --git a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj index bf6b80525..8cf2838f6 100644 --- a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj +++ b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj @@ -133,6 +133,7 @@ + diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 3e08d14b6..6b43bffcf 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -1423,6 +1423,13 @@ uint32_t VulkanReplay::PickVertex(uint32_t eventId, int32_t w, int32_t h, const return ret; } +const VulkanCreationInfo::Image &VulkanDebugManager::GetImageInfo(ResourceId img) +{ + auto it = m_pDriver->m_CreationInfo.m_Image.find(img); + RDCASSERT(it != m_pDriver->m_CreationInfo.m_Image.end()); + return it->second; +} + void VulkanDebugManager::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &ret) { VkDevice dev = m_pDriver->GetDev(); diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index 72c5f0ef9..8a8f4f937 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -48,6 +48,10 @@ struct MeshDisplayPipelines struct SPIRVCompilationSettings; +struct CopyPixelParams; + +struct PixelHistoryResources; + class VulkanResourceManager; class VulkanDebugManager @@ -79,6 +83,16 @@ public: void PatchLineStripIndexBuffer(const DrawcallDescription *draw, GPUBuffer &indexBuffer, uint32_t &indexCount); + bool PixelHistorySetupResources(PixelHistoryResources &resources, VkExtent3D extent, + VkFormat format, uint32_t numEvents); + bool PixelHistoryDestroyResources(const PixelHistoryResources &resources); + + void PixelHistoryCopyPixel(VkCommandBuffer cmd, CopyPixelParams &p, size_t offset); + + VkImageLayout GetImageLayout(ResourceId image, VkImageAspectFlags aspect, uint32_t mip); + + const VulkanCreationInfo::Image &GetImageInfo(ResourceId img); + private: // GetBufferData GPUBuffer m_ReadbackWindow; diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp new file mode 100644 index 000000000..9de6ccf0c --- /dev/null +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -0,0 +1,646 @@ +/****************************************************************************** +* The MIT License (MIT) +* +* Copyright (c) 2016-2019 Baldur Karlsson +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +******************************************************************************/ + +#include +#include "driver/vulkan/vk_debug.h" +#include "driver/vulkan/vk_replay.h" +#include "vk_shader_cache.h" + +bool isDirectWrite(ResourceUsage usage) +{ + return ((usage >= ResourceUsage::VS_RWResource && usage <= ResourceUsage::CS_RWResource) || + usage == ResourceUsage::CopyDst || usage == ResourceUsage::Copy || + usage == ResourceUsage::Resolve || usage == ResourceUsage::ResolveDst || + usage == ResourceUsage::GenMips); +} + +struct CopyPixelParams +{ + bool multisampled; + bool floatTex; + bool uintTex; + bool intTex; + + bool depthcopy; + VkImage srcImage; + VkFormat srcImageFormat; + VkImageLayout srcImageLayout; + VkOffset3D imageOffset; + + VkBuffer dstBuffer; +}; + +struct PixelHistoryResources +{ + VkBuffer dstBuffer; + VkDeviceMemory bufferMemory; + + // Used for offscreen rendering for draw call events. + VkImage colorImage; + VkImageView colorImageView; + VkImage stencilImage; + VkImageView stencilImageView; + VkDeviceMemory gpuMem; +}; + +struct PixelHistoryValue +{ + uint8_t color[16]; + uint8_t depth[8]; +}; + +struct EventInfo +{ + PixelHistoryValue premod; + PixelHistoryValue postmod; + uint8_t shadout[16]; + uint8_t fixed_stencil[8]; + uint8_t original_stencil[8]; +}; + +#if 1 + +std::vector VulkanReplay::PixelHistory(std::vector events, + ResourceId target, uint32_t x, uint32_t y, + uint32_t slice, uint32_t mip, + uint32_t sampleIdx, CompType typeHint) +{ + VULKANNOTIMP("PixelHistory"); + return std::vector(); +} + +#else + +struct VulkanPixelHistoryCallback : public VulkanDrawcallCallback +{ + VulkanPixelHistoryCallback(WrappedVulkan *vk, uint32_t x, uint32_t y, VkImage image, + VkFormat format, uint32_t sampleMask, VkQueryPool occlusionPool, + VkImageView colorImageView, VkImageView stencilImageView, + VkImage colorImage, VkImage stencilImage, VkBuffer dstBuffer, + const std::vector &events) + : m_pDriver(vk), + m_X(x), + m_Y(y), + m_Image(image), + m_Format(format), + m_DstBuffer(dstBuffer), + m_SampleMask(sampleMask), + m_OcclusionPool(occlusionPool), + m_ColorImageView(colorImageView), + m_StencilImageView(stencilImageView), + m_ColorImage(colorImage), + m_StencilImage(stencilImage), + m_PrevState(vk, NULL) + { + m_pDriver->SetDrawcallCB(this); + for(size_t i = 0; i < events.size(); i++) + m_Events.insert(std::make_pair(events[i].eventId, events[i])); + } + ~VulkanPixelHistoryCallback() { m_pDriver->SetDrawcallCB(NULL); } + void CopyPixel(uint32_t eid, VkCommandBuffer cmd, size_t offset) + { + CopyPixelParams colourCopyParams = {}; + colourCopyParams.multisampled = false; // TODO: multisampled + colourCopyParams.srcImage = m_Image; + colourCopyParams.srcImageLayout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // TODO: image layout + colourCopyParams.srcImageFormat = m_Format; + colourCopyParams.imageOffset.x = int32_t(m_X); + colourCopyParams.imageOffset.y = int32_t(m_Y); + colourCopyParams.imageOffset.z = 0; + colourCopyParams.dstBuffer = m_DstBuffer; + + m_pDriver->GetDebugManager()->PixelHistoryCopyPixel(cmd, colourCopyParams, offset); + + const DrawcallDescription *draw = m_pDriver->GetDrawcall(eid); + if(draw && draw->depthOut != ResourceId()) + { + // The draw call had a depth image attachment. + ResourceId depthImage = m_pDriver->GetResourceManager()->GetLiveID(draw->depthOut); + const VulkanCreationInfo::Image &imginfo = + m_pDriver->GetDebugManager()->GetImageInfo(depthImage); + CopyPixelParams depthCopyParams = colourCopyParams; + depthCopyParams.depthcopy = true; + depthCopyParams.srcImage = + m_pDriver->GetResourceManager()->GetCurrentHandle(depthImage); + depthCopyParams.srcImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depthCopyParams.srcImageFormat = imginfo.format; + m_pDriver->GetDebugManager()->PixelHistoryCopyPixel( + cmd, depthCopyParams, offset + offsetof(struct PixelHistoryValue, depth)); + } + } + + void PreDraw(uint32_t eid, VkCommandBuffer cmd) + { + auto it = m_Events.find(eid); + if(it == m_Events.end()) + return; + EventUsage event = it->second; + m_PrevState = m_pDriver->GetRenderState(); + + // TODO: handle secondary command buffers. + m_pDriver->GetRenderState().EndRenderPass(cmd); + // Get pre-modification values + size_t storeOffset = m_EventIndices.size() * sizeof(EventInfo); + CopyPixel(eid, cmd, storeOffset); + + // TODO: add all logic for draw calls. + + if(m_PrevState.graphics.pipeline != ResourceId()) + m_pDriver->GetRenderState().BeginRenderPassAndApplyState(cmd, VulkanRenderState::BindGraphics); + } + + bool PostDraw(uint32_t eid, VkCommandBuffer cmd) + { + if(m_Events.find(eid) == m_Events.end()) + return false; + + m_pDriver->GetRenderState().EndRenderPass(cmd); + + size_t storeOffset = m_EventIndices.size() * sizeof(EventInfo); + CopyPixel(eid, cmd, storeOffset + offsetof(struct EventInfo, postmod)); + + m_pDriver->GetRenderState().BeginRenderPassAndApplyState(cmd, VulkanRenderState::BindGraphics); + + // Get post-modification values + m_EventIndices.insert(std::make_pair(eid, m_EventIndices.size())); + return false; + } + + void PostRedraw(uint32_t eid, VkCommandBuffer cmd) + { + // nothing to do + } + + void PreDispatch(uint32_t eid, VkCommandBuffer cmd) + { + if(m_Events.find(eid) == m_Events.end()) + return; + + size_t storeOffset = m_EventIndices.size() * sizeof(EventInfo); + CopyPixel(eid, cmd, storeOffset); + } + bool PostDispatch(uint32_t eid, VkCommandBuffer cmd) + { + if(m_Events.find(eid) == m_Events.end()) + return false; + + size_t storeOffset = m_EventIndices.size() * sizeof(EventInfo); + CopyPixel(eid, cmd, storeOffset + offsetof(struct EventInfo, postmod)); + m_EventIndices.insert(std::make_pair(eid, m_EventIndices.size())); + return false; + } + void PostRedispatch(uint32_t eid, VkCommandBuffer cmd) {} + void PreMisc(uint32_t eid, DrawFlags flags, VkCommandBuffer cmd) + { + if(m_Events.find(eid) == m_Events.end()) + return; + + size_t storeOffset = m_EventIndices.size() * sizeof(EventInfo); + CopyPixel(eid, cmd, storeOffset); + } + bool PostMisc(uint32_t eid, DrawFlags flags, VkCommandBuffer cmd) + { + if(m_Events.find(eid) == m_Events.end()) + return false; + + size_t storeOffset = m_EventIndices.size() * sizeof(EventInfo); + CopyPixel(eid, cmd, storeOffset + offsetof(struct EventInfo, postmod)); + m_EventIndices.insert(std::make_pair(eid, m_EventIndices.size())); + return false; + } + + void PostRemisc(uint32_t eid, DrawFlags flags, VkCommandBuffer cmd) {} + void PreEndCommandBuffer(VkCommandBuffer cmd) {} + void AliasEvent(uint32_t primary, uint32_t alias) + { + // TODO: handled aliased events. + } + + WrappedVulkan *m_pDriver; + VkImage m_Image; + VkFormat m_Format; + std::map m_Events; + std::map m_EventIndices; + VkBuffer m_DstBuffer; + uint32_t m_X, m_Y; + + uint32_t m_SampleMask; + VkQueryPool m_OcclusionPool; + VkImageView m_ColorImageView; + VkImageView m_StencilImageView; + VkImage m_ColorImage; + VkImage m_StencilImage; + + VulkanRenderState m_PrevState; +}; + +bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resources, + VkExtent3D extent, VkFormat format, + uint32_t numEvents) +{ + VkImage colorImage; + VkImageView colorImageView; + VkImage stencilImage; + VkImageView stencilImageView; + VkDeviceMemory gpuMem; + + VkBuffer dstBuffer; + VkDeviceMemory bufferMemory; + + VkResult vkr; + VkDevice dev = m_pDriver->GetDev(); + + // Create Images + VkImageCreateInfo imgInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + imgInfo.imageType = VK_IMAGE_TYPE_2D; + imgInfo.mipLevels = 1; + imgInfo.arrayLayers = 1; + imgInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imgInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + // Device local resources: + imgInfo.format = format; + imgInfo.extent = {extent.width, extent.height, 1}; + imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imgInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &colorImage); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkMemoryRequirements colorImageMrq = {0}; + m_pDriver->vkGetImageMemoryRequirements(dev, colorImage, &colorImageMrq); + + imgInfo.format = VK_FORMAT_D32_SFLOAT_S8_UINT; + imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imgInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &stencilImage); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkMemoryRequirements stencilImageMrq = {0}; + m_pDriver->vkGetImageMemoryRequirements(dev, stencilImage, &stencilImageMrq); + VkDeviceSize offset = AlignUp(colorImageMrq.size, stencilImageMrq.alignment); + + VkMemoryAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, offset + stencilImageMrq.size, + m_pDriver->GetGPULocalMemoryIndex(colorImageMrq.memoryTypeBits), + }; + vkr = m_pDriver->vkAllocateMemory(m_Device, &allocInfo, NULL, &gpuMem); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + vkr = m_pDriver->vkBindImageMemory(m_Device, colorImage, gpuMem, 0); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + vkr = m_pDriver->vkBindImageMemory(m_Device, stencilImage, gpuMem, offset); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkImageViewCreateInfo viewInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + viewInfo.image = colorImage; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = format; + viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + + vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &colorImageView); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + viewInfo.image = stencilImage; + viewInfo.format = VK_FORMAT_D32_SFLOAT_S8_UINT; + viewInfo.subresourceRange = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1}; + + vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &stencilImageView); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkBufferCreateInfo bufferInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bufferInfo.size = AlignUp((uint32_t)(numEvents * sizeof(EventInfo)), 512U); + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + vkr = m_pDriver->vkCreateBuffer(m_Device, &bufferInfo, NULL, &dstBuffer); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + // Allocate memory + VkMemoryRequirements mrq = {}; + m_pDriver->vkGetBufferMemoryRequirements(m_Device, dstBuffer, &mrq); + allocInfo.allocationSize = mrq.size; + allocInfo.memoryTypeIndex = m_pDriver->GetReadbackMemoryIndex(mrq.memoryTypeBits); + vkr = m_pDriver->vkAllocateMemory(m_Device, &allocInfo, NULL, &bufferMemory); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + vkr = m_pDriver->vkBindBufferMemory(m_Device, dstBuffer, bufferMemory, 0); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkCommandBuffer cmd = m_pDriver->GetNextCmd(); + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + vkr = ObjDisp(dev)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkImageMemoryBarrier barriers[2] = {}; + barriers[0] = {}; + barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[0].srcAccessMask = 0; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barriers[0].subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barriers[0].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barriers[0].image = Unwrap(colorImage); + + barriers[1] = barriers[0]; + barriers[1].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + barriers[1].newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + barriers[1].subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, + 1}; + barriers[1].image = Unwrap(stencilImage); + + DoPipelineBarrier(cmd, 2, barriers); + + { + SCOPED_LOCK(m_pDriver->m_ImageLayoutsLock); + m_pDriver->m_ImageLayouts[GetResID(colorImage)].subresourceStates[0].newLayout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + m_pDriver->m_ImageLayouts[GetResID(stencilImage)].subresourceStates[0].newLayout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } + vkr = ObjDisp(dev)->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + + resources.colorImage = colorImage; + resources.colorImageView = colorImageView; + resources.stencilImage = stencilImage; + resources.stencilImageView = stencilImageView; + resources.gpuMem = gpuMem; + + resources.bufferMemory = bufferMemory; + resources.dstBuffer = dstBuffer; + + return true; +} + +bool VulkanDebugManager::PixelHistoryDestroyResources(const PixelHistoryResources &r) +{ + VkDevice dev = m_pDriver->GetDev(); + if(r.gpuMem != VK_NULL_HANDLE) + m_pDriver->vkFreeMemory(dev, r.gpuMem, NULL); + if(r.colorImage != VK_NULL_HANDLE) + m_pDriver->vkDestroyImage(dev, r.colorImage, NULL); + if(r.colorImageView != VK_NULL_HANDLE) + m_pDriver->vkDestroyImageView(dev, r.colorImageView, NULL); + if(r.stencilImage != VK_NULL_HANDLE) + m_pDriver->vkDestroyImage(dev, r.stencilImage, NULL); + if(r.stencilImageView != VK_NULL_HANDLE) + m_pDriver->vkDestroyImageView(dev, r.stencilImageView, NULL); + if(r.dstBuffer != VK_NULL_HANDLE) + m_pDriver->vkDestroyBuffer(dev, r.dstBuffer, NULL); + if(r.bufferMemory != VK_NULL_HANDLE) + m_pDriver->vkFreeMemory(dev, r.bufferMemory, NULL); + return true; +} + +void VulkanDebugManager::PixelHistoryCopyPixel(VkCommandBuffer cmd, CopyPixelParams &p, size_t offset) +{ + std::vector regions; + // Check if depth image includes depth and stencil + VkImageAspectFlags aspectFlags = 0; + VkBufferImageCopy region = {}; + region.bufferOffset = (uint64_t)offset; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageOffset = p.imageOffset; + region.imageExtent.width = 1U; + region.imageExtent.height = 1U; + region.imageExtent.depth = 1U; + if(!p.depthcopy) + { + region.imageSubresource = VkImageSubresourceLayers{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + regions.push_back(region); + aspectFlags = VkImageAspectFlags(VK_IMAGE_ASPECT_COLOR_BIT); + } + else + { + region.imageSubresource = VkImageSubresourceLayers{VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0, 1}; + if(IsDepthOnlyFormat(p.srcImageFormat) || IsDepthAndStencilFormat(p.srcImageFormat)) + { + regions.push_back(region); + aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; + } + if(IsStencilFormat(p.srcImageFormat)) + { + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + region.bufferOffset = offset + 4; + regions.push_back(region); + aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } + + VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + NULL, + VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + p.srcImageLayout, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + Unwrap(p.srcImage), + {aspectFlags, 0, 1, 0, 1}}; + + DoPipelineBarrier(cmd, 1, &barrier); + + ObjDisp(cmd)->CmdCopyImageToBuffer(Unwrap(cmd), Unwrap(p.srcImage), + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, Unwrap(p.dstBuffer), + (uint32_t)regions.size(), regions.data()); + + barrier.image = Unwrap(p.srcImage); + barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.newLayout = p.srcImageLayout; + DoPipelineBarrier(cmd, 1, &barrier); +} + +void CreateOcclusionPool(VkDevice dev, uint32_t poolSize, VkQueryPool *pQueryPool) +{ + VkQueryPoolCreateInfo occlusionPoolCreateInfo = {VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO}; + occlusionPoolCreateInfo.queryType = VK_QUERY_TYPE_OCCLUSION; + occlusionPoolCreateInfo.queryCount = poolSize; + // TODO: check that occlusion feature is available + VkResult vkr = + ObjDisp(dev)->CreateQueryPool(Unwrap(dev), &occlusionPoolCreateInfo, NULL, pQueryPool); + RDCASSERTEQUAL(vkr, VK_SUCCESS); +} + +VkImageLayout VulkanDebugManager::GetImageLayout(ResourceId image, VkImageAspectFlags aspect, + uint32_t mip) +{ + VkImageLayout imgLayout = VK_IMAGE_LAYOUT_UNDEFINED; + const ImageLayouts &imgLayouts = m_pDriver->m_ImageLayouts[image]; + for(const ImageRegionState &resState : imgLayouts.subresourceStates) + { + VkImageSubresourceRange range = resState.subresourceRange; + + if((range.aspectMask & aspect) && + (mip >= range.baseMipLevel && mip < range.baseMipLevel + range.levelCount)) + { + // Consider using the layer count + imgLayout = resState.newLayout; + } + } + return imgLayout; +} + +std::vector VulkanReplay::PixelHistory(std::vector events, + ResourceId target, uint32_t x, uint32_t y, + uint32_t slice, uint32_t mip, + uint32_t sampleIdx, CompType typeHint) +{ + std::vector history; + VkResult vkr; + VkDevice dev = m_pDriver->GetDev(); + + if(events.empty()) + return history; + + const VulkanCreationInfo::Image &imginfo = GetDebugManager()->GetImageInfo(target); + if(imginfo.format == VK_FORMAT_UNDEFINED) + return history; + + // TODO: figure out correct aspect. + VkImageLayout imgLayout = GetDebugManager()->GetImageLayout(target, VK_IMAGE_ASPECT_COLOR_BIT, mip); + RDCASSERTNOTEQUAL(imgLayout, VK_IMAGE_LAYOUT_UNDEFINED); + + // TODO: use the given type hint for typeless textures + SCOPED_TIMER("VkDebugManager::PixelHistory"); + + if(sampleIdx > (uint32_t)imginfo.samples) + sampleIdx = 0; + + uint32_t sampleMask = ~0U; + if(sampleIdx < 32) + sampleMask = 1U << sampleIdx; + + bool multisampled = (imginfo.samples > 1); + + if(sampleIdx == ~0U || !multisampled) + sampleIdx = 0; + + RDCASSERT(m_pDriver->GetDeviceFeatures().occlusionQueryPrecise); + VkPhysicalDeviceProperties props = m_pDriver->GetDeviceProps(); + VkPhysicalDeviceFeatures features = m_pDriver->GetDeviceFeatures(); + + VkQueryPool occlusionPool; + CreateOcclusionPool(dev, (uint32_t)events.size(), &occlusionPool); + + PixelHistoryResources resources = {}; + GetDebugManager()->PixelHistorySetupResources(resources, imginfo.extent, imginfo.format, + (uint32_t)events.size()); + + VulkanPixelHistoryCallback cb( + m_pDriver, x, y, GetResourceManager()->GetCurrentHandle(target), imginfo.format, + sampleMask, occlusionPool, resources.colorImageView, resources.stencilImageView, + resources.colorImage, resources.stencilImage, resources.dstBuffer, events); + m_pDriver->ReplayLog(0, events.back().eventId, eReplay_Full); + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + + for(size_t ev = 0; ev < events.size(); ev++) + { + const DrawcallDescription *draw = m_pDriver->GetDrawcall(events[ev].eventId); + bool clear = bool(draw->flags & DrawFlags::Clear); + bool directWrite = isDirectWrite(events[ev].usage); + // TODO: actually do occlusion query. + uint64_t occlData = 1; + + if(events[ev].view != ResourceId()) + { + // TODO + } + + if(occlData > 0 || clear || directWrite) + { + PixelModification mod; + RDCEraseEl(mod); + + mod.eventId = events[ev].eventId; + mod.directShaderWrite = directWrite; + mod.unboundPS = false; + + if(!clear && !directWrite) + { + // TODO: fill in flags for the modification. + } + history.push_back(mod); + } + } + + // Try to read memory back + + void *bufPtr = NULL; + vkr = m_pDriver->vkMapMemory(dev, resources.bufferMemory, 0, VK_WHOLE_SIZE, 0, (void **)&bufPtr); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + EventInfo *eventsInfo = (EventInfo *)bufPtr; + + for(size_t h = 0; h < history.size(); h++) + { + PixelModification &mod = history[h]; + + ModificationValue preMod, postMod, shadout; + const EventInfo &ei = eventsInfo[cb.m_EventIndices[mod.eventId]]; + preMod.col.floatValue[0] = (float)(ei.premod.color[2] / 255.0); + preMod.col.floatValue[1] = (float)(ei.premod.color[1] / 255.0); + preMod.col.floatValue[2] = (float)(ei.premod.color[0] / 255.0); + preMod.col.floatValue[3] = (float)(ei.premod.color[3] / 255.0); + postMod.col.floatValue[0] = (float)(ei.postmod.color[2] / 255.0); + postMod.col.floatValue[1] = (float)(ei.postmod.color[1] / 255.0); + postMod.col.floatValue[2] = (float)(ei.postmod.color[0] / 255.0); + postMod.col.floatValue[3] = (float)(ei.shadout[3] / 255.0); + shadout.col.floatValue[0] = (float)(ei.shadout[2] / 255.0); + shadout.col.floatValue[1] = (float)(ei.shadout[1] / 255.0); + shadout.col.floatValue[2] = (float)(ei.shadout[0] / 255.0); + shadout.col.floatValue[3] = (float)(ei.shadout[3] / 255.0); + preMod.depth = *((float *)ei.premod.depth); + preMod.stencil = ei.premod.depth[4]; + postMod.depth = *((float *)ei.postmod.depth); + postMod.stencil = ei.postmod.depth[4]; + + mod.preMod = preMod; + mod.shaderOut = shadout; + mod.postMod = postMod; + } + + m_pDriver->vkUnmapMemory(dev, resources.bufferMemory); + GetDebugManager()->PixelHistoryDestroyResources(resources); + ObjDisp(dev)->DestroyQueryPool(Unwrap(dev), occlusionPool, NULL); + + return history; +} + +#endif \ No newline at end of file diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index d30ce8b4f..5047765a5 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -3705,15 +3705,6 @@ void VulkanReplay::RemoveReplacement(ResourceId id) ClearFeedbackCache(); } -std::vector VulkanReplay::PixelHistory(std::vector events, - ResourceId target, uint32_t x, uint32_t y, - uint32_t slice, uint32_t mip, - uint32_t sampleIdx, CompType typeHint) -{ - VULKANNOTIMP("PixelHistory"); - return std::vector(); -} - ShaderDebugTrace VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset) {