diff --git a/renderdoc/CMakeLists.txt b/renderdoc/CMakeLists.txt index 6a63c80d6..83706cbd1 100644 --- a/renderdoc/CMakeLists.txt +++ b/renderdoc/CMakeLists.txt @@ -385,6 +385,7 @@ set(data data/glsl/minmaxtile.comp data/glsl/quadresolve.frag data/glsl/quadwrite.frag + data/glsl/pixelhistory_mscopy.comp data/glsl/pixelhistory_primid.frag data/glsl/shaderdebug_sample.vert data/glsl/texdisplay.frag diff --git a/renderdoc/data/embedded_files.h b/renderdoc/data/embedded_files.h index 81b70dae7..b3f2a3252 100644 --- a/renderdoc/data/embedded_files.h +++ b/renderdoc/data/embedded_files.h @@ -63,6 +63,7 @@ DECLARE_EMBED(glsl_ms2array_comp); DECLARE_EMBED(glsl_deptharr2ms_frag); DECLARE_EMBED(glsl_depthms2arr_frag); DECLARE_EMBED(glsl_gles_texsample_h); +DECLARE_EMBED(glsl_pixelhistory_mscopy_comp); DECLARE_EMBED(glsl_pixelhistory_primid_frag); DECLARE_EMBED(glsl_shaderdebug_sample_vert); DECLARE_EMBED(glsl_texremap_frag); diff --git a/renderdoc/data/glsl/pixelhistory_mscopy.comp b/renderdoc/data/glsl/pixelhistory_mscopy.comp new file mode 100644 index 000000000..2e6927349 --- /dev/null +++ b/renderdoc/data/glsl/pixelhistory_mscopy.comp @@ -0,0 +1,67 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2020 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 "glsl_globals.h" + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +layout(binding = 0) uniform PRECISION usampler2DMSArray srcMS0; +layout(binding = 1) uniform PRECISION usampler2DMSArray srcMS1; + +layout(binding = 2, std140) writeonly buffer pixelhistorydest +{ + uvec4 result[]; +} +dest; + +layout(push_constant) uniform multisamplePush +{ + int depthCopy; + int currentSample; + int x; + int y; + int dstOffset; +} +mscopy; + +#define depthCopy (mscopy.depthCopy) +#define currentSample (mscopy.currentSample) +#define x (mscopy.x) +#define y (mscopy.y) +#define dstOffset (mscopy.dstOffset) + +void main() +{ + if(depthCopy == 0) + { + uvec4 data = texelFetch(srcMS0, ivec3(x, y, 0), currentSample); + dest.result[dstOffset] = data; + } + else if(depthCopy == 1) + { + uint depth = texelFetch(srcMS0, ivec3(x, y, 0), currentSample).r; + uint stencil = texelFetch(srcMS1, ivec3(x, y, 0), currentSample).r; + dest.result[dstOffset] = uvec4(depth, stencil, 0, 0); + } +} diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc index 68bb0da06..264df0ac3 100644 --- a/renderdoc/data/renderdoc.rc +++ b/renderdoc/data/renderdoc.rc @@ -128,6 +128,7 @@ RESOURCE_glsl_mesh_frag TYPE_EMBED "glsl/mesh.frag" RESOURCE_glsl_minmaxtile_comp TYPE_EMBED "glsl/minmaxtile.comp" RESOURCE_glsl_minmaxresult_comp TYPE_EMBED "glsl/minmaxresult.comp" RESOURCE_glsl_histogram_comp TYPE_EMBED "glsl/histogram.comp" +RESOURCE_glsl_pixelhistory_mscopy_comp TYPE_EMBED "glsl/pixelhistory_mscopy.comp" RESOURCE_glsl_pixelhistory_primid_frag TYPE_EMBED "glsl/pixelhistory_primid.frag" RESOURCE_glsl_glsl_ubos_h TYPE_EMBED "glsl/glsl_ubos.h" RESOURCE_glsl_gl_texsample_h TYPE_EMBED "glsl/gl_texsample.h" diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h index 523680371..45eb5b9be 100644 --- a/renderdoc/data/resource.h +++ b/renderdoc/data/resource.h @@ -48,8 +48,9 @@ #define RESOURCE_glsl_gltext_frag 430 #define RESOURCE_glsl_glsl_globals_h 440 #define RESOURCE_glsl_texremap_frag 441 -#define RESOURCE_glsl_pixelhistory_primid_frag 442 -#define RESOURCE_glsl_shaderdebug_sample_vert 443 +#define RESOURCE_glsl_pixelhistory_mscopy_comp 442 +#define RESOURCE_glsl_pixelhistory_primid_frag 443 +#define RESOURCE_glsl_shaderdebug_sample_vert 444 // Next default values for new objects // diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index e6b46d058..f747e5d4f 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -2644,13 +2644,22 @@ void VulkanReplay::PixelHistory::Init(WrappedVulkan *driver, VkDescriptorPool de { {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, NULL}, {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, NULL}, - {2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_ALL, NULL}, + {2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, NULL}, }); CREATE_OBJECT(MSCopyDescSet, descriptorPool, MSCopyDescSetLayout); + CREATE_OBJECT(MSDepthCopyDescSet, descriptorPool, MSCopyDescSetLayout); + + CREATE_OBJECT(MSCopyPipeLayout, MSCopyDescSetLayout, 32); + CREATE_OBJECT(MSCopyPipe, MSCopyPipeLayout, + driver->GetShaderCache()->GetBuiltinModule(BuiltinShader::PixelHistoryMSCopyCS)); } void VulkanReplay::PixelHistory::Destroy(WrappedVulkan *driver) { + if(MSCopyPipe != VK_NULL_HANDLE) + driver->vkDestroyPipeline(driver->GetDev(), MSCopyPipe, NULL); + if(MSCopyPipeLayout != VK_NULL_HANDLE) + driver->vkDestroyPipelineLayout(driver->GetDev(), MSCopyPipeLayout, NULL); if(MSCopyDescSetLayout != VK_NULL_HANDLE) driver->vkDestroyDescriptorSetLayout(driver->GetDev(), MSCopyDescSetLayout, NULL); } diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index fa84eea94..e5ce26e70 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -68,8 +68,6 @@ public: uint32_t samples, VkFormat fmt); void CopyArrayToTex2DMS(VkImage destMS, VkImage srcArray, VkExtent3D extent, uint32_t layers, uint32_t samples, VkFormat fmt); - void CopyTex2DMSPixel(VkCommandBuffer cmd, VkDescriptorSet descSet, VkExtent3D extent, - uint32_t sample, VkFormat fmt); VkPipelineCache GetPipelineCache() { return m_PipelineCache; } VkPipeline GetCustomPipeline() { return m_Custom.TexPipeline; } diff --git a/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp b/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp index 13778f365..f00900076 100644 --- a/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp +++ b/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp @@ -146,27 +146,6 @@ void VulkanDebugManager::CopyTex2DMSToArray(VkImage destArray, VkImage srcMS, Vk ObjDisp(dev)->DestroyImageView(Unwrap(dev), destView, NULL); } -void VulkanDebugManager::CopyTex2DMSPixel(VkCommandBuffer cmd, VkDescriptorSet descSet, - VkExtent3D extent, uint32_t sample, VkFormat fmt) -{ - if(!m_pDriver->GetDeviceFeatures().shaderStorageImageWriteWithoutFormat) - return; - - if(m_MS2ArrayPipe == VK_NULL_HANDLE) - return; - - ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, Unwrap(m_MS2ArrayPipe)); - ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, - Unwrap(m_ArrayMSPipeLayout), 0, 1, UnwrapPtr(descSet), 0, NULL); - - Vec4u params = {0, sample, 0, 0}; - - ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_ArrayMSPipeLayout), VK_SHADER_STAGE_ALL, 0, - sizeof(Vec4u), ¶ms); - // TODO: Specify a single pixel to copy. - ObjDisp(cmd)->CmdDispatch(Unwrap(cmd), extent.width, extent.height, 1); -} - void VulkanDebugManager::CopyDepthTex2DMSToArray(VkImage destArray, VkImage srcMS, VkExtent3D extent, uint32_t layers, uint32_t samples, VkFormat fmt) { diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index 2c68495d3..ad875020f 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -61,7 +61,6 @@ enum struct CopyPixelParams { bool depthCopy; - bool stencilOnly; VkImage srcImage; VkFormat srcImageFormat; VkImageLayout srcImageLayout; @@ -75,16 +74,21 @@ struct PixelHistoryResources // Used for offscreen rendering for draw call events. VkImage colorImage; VkImageView colorImageView; - VkImage stencilImage; - VkImageView stencilImageView; + VkImage dsImage; + VkImageView dsImageView; VkDeviceMemory gpuMem; // Following are only used and created for multi sampled images. - VkImage stagingImage; - VkImageView stagingImageView; - VkImage stencilStagingImage; - VkImageView stencilStagingImageView; + // This is an image view for colorImage which uses a UINT format. + VkImageView colorImageAliasView; + // Image view for target image which uses a UINT format. VkImageView targetImageView; + // Image view for dsImage depth stencil image that includes depth + // aspect only. + VkImageView depthOnlyImageView; + // Image view for dsImage depth stencil image that includes stencil + // aspect only. + VkImageView stencilOnlyImageView; }; struct PixelHistoryCallbackInfo @@ -108,12 +112,8 @@ struct PixelHistoryCallbackInfo VkImageView subImageView; // Image used to get stencil counts. - VkImage stencilImage; - VkImageView stencilImageView; - - // Only used for multi sampled images for copy into a staging resource. - VkImage stagingImage; - VkImage stencilStagingImage; + VkImage dsImage; + VkImageView dsImageView; // Buffer used to copy colour and depth information VkBuffer dstBuffer; @@ -129,7 +129,7 @@ struct PixelHistoryValue float fdepth; } depth; int8_t stencil; - uint8_t padding[3]; + uint8_t padding[3 + 8]; }; struct EventInfo @@ -137,7 +137,9 @@ struct EventInfo PixelHistoryValue premod; PixelHistoryValue postmod; uint8_t dsWithoutShaderDiscard[8]; + uint32_t padding[4]; uint8_t dsWithShaderDiscard[8]; + uint32_t padding1[4]; }; struct PerFragmentInfo @@ -693,118 +695,156 @@ protected: void CopyImagePixel(VkCommandBuffer cmd, CopyPixelParams &p, size_t offset) { - rdcarray regions; VkImageAspectFlags aspectFlags = 0; - VkBufferImageCopy region = {}; - region.bufferOffset = (uint64_t)offset; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - region.imageOffset.x = m_CallbackInfo.x; - region.imageOffset.y = m_CallbackInfo.y; - region.imageOffset.z = 0; - region.imageExtent.width = 1U; - region.imageExtent.height = 1U; - region.imageExtent.depth = 1U; - region.imageSubresource.baseArrayLayer = m_CallbackInfo.targetSubresource.slice; - region.imageSubresource.mipLevel = m_CallbackInfo.targetSubresource.mip; - region.imageSubresource.layerCount = 1; - - // TODO: support depth/stencil copy for multi-sampled images. - if(p.depthCopy && (m_CallbackInfo.samples != VK_SAMPLE_COUNT_1_BIT)) - return; - - if(!p.depthCopy) + if(p.depthCopy) { - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - regions.push_back(region); - aspectFlags = VkImageAspectFlags(VK_IMAGE_ASPECT_COLOR_BIT); - } - else if(p.stencilOnly) - { - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - regions.push_back(region); - aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + if(IsDepthOnlyFormat(p.srcImageFormat) || IsDepthAndStencilFormat(p.srcImageFormat)) + aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; + if(IsStencilFormat(p.srcImageFormat)) + aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; } else { - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - 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; - } + aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; } - VkImage cmdCopySource = p.srcImage; - VkImageLayout cmdCopySourceLayout = p.srcImageLayout; - uint32_t baseArrayLayer = m_CallbackInfo.targetSubresource.slice; + uint32_t baseMip = m_CallbackInfo.targetSubresource.mip; + uint32_t baseSlice = m_CallbackInfo.targetSubresource.slice; + // The images that are created specifically for evaluating pixel history are + // already based on the target mip/slice. + if((p.srcImage == m_CallbackInfo.subImage) || (p.srcImage == m_CallbackInfo.dsImage)) + { + baseMip = 0; + baseSlice = 0; + } + // For pipeline barriers. + VkImageSubresourceRange subresource = {aspectFlags, baseMip, 1, baseSlice, 1}; // For multi-sampled images can't call vkCmdCopyImageToBuffer directly, // copy using a compute shader into a staging image first. if(m_CallbackInfo.samples != VK_SAMPLE_COUNT_1_BIT) { - regions[0].imageSubresource.baseArrayLayer = 0; - 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_SHADER_READ_BIT, - p.srcImageLayout, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - Unwrap(p.srcImage), - {aspectFlags, 0, 1, baseArrayLayer, 1}}; + 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_SHADER_READ_BIT, p.srcImageLayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, Unwrap(p.srcImage), subresource}; + if(p.depthCopy && p.srcImage != m_CallbackInfo.dsImage) + { + // This is an original depth image that is used in a draw. + // The descriptor for MSAA copy has the dsImage created for pixel history. + // So copy the pixel value there first. + VkImageCopy region = {}; + region.srcSubresource = {aspectFlags, baseMip, baseSlice, 1}; + region.srcOffset = {(int32_t)m_CallbackInfo.x, (int32_t)m_CallbackInfo.y, 0}; + region.dstSubresource = {aspectFlags, 0, 0, 1}; + region.dstOffset = {(int32_t)m_CallbackInfo.x, (int32_t)m_CallbackInfo.y, 0}; + region.extent = {1, 1, 1}; + + VkImageMemoryBarrier barriers[2]; + barriers[0] = barrier; + barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barriers[1] = barriers[0]; + barriers[1].image = Unwrap(m_CallbackInfo.dsImage); + barriers[1].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + DoPipelineBarrier(cmd, 2, barriers); + + ObjDisp(cmd)->CmdCopyImage( + Unwrap(cmd), Unwrap(p.srcImage), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + Unwrap(m_CallbackInfo.dsImage), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + // Return src image to its layout. + barrier.image = Unwrap(p.srcImage); + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.newLayout = p.srcImageLayout; + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_ALL_WRITE_BITS; + DoPipelineBarrier(cmd, 1, &barrier); + + barrier.image = Unwrap(m_CallbackInfo.dsImage); + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + } + + // Transition src image to SHADER_READ_ONLY_OPTIMAL. DoPipelineBarrier(cmd, 1, &barrier); - m_pDriver->GetReplay()->CopyPixelForPixelHistory(cmd, m_CallbackInfo.extent, - m_CallbackInfo.targetSubresource.sample, - m_CallbackInfo.targetImageFormat); + m_pDriver->GetReplay()->CopyPixelForPixelHistory( + cmd, {(int32_t)m_CallbackInfo.x, (int32_t)m_CallbackInfo.y}, + m_CallbackInfo.targetSubresource.sample, (uint32_t)offset / 16, p.depthCopy); + + // Transition src image back to its layout. barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; barrier.newLayout = p.srcImageLayout; + + DoPipelineBarrier(cmd, 1, &barrier); + } + else + { + rdcarray regions; + VkBufferImageCopy region = {}; + region.bufferOffset = (uint64_t)offset; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageOffset.x = m_CallbackInfo.x; + region.imageOffset.y = m_CallbackInfo.y; + region.imageOffset.z = 0; + region.imageExtent.width = 1U; + region.imageExtent.height = 1U; + region.imageExtent.depth = 1U; + region.imageSubresource.baseArrayLayer = baseSlice; + region.imageSubresource.mipLevel = baseMip; + region.imageSubresource.layerCount = 1; + + if(!p.depthCopy) + { + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + regions.push_back(region); + } + else + { + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if(IsDepthOnlyFormat(p.srcImageFormat) || IsDepthAndStencilFormat(p.srcImageFormat)) + { + regions.push_back(region); + } + if(IsStencilFormat(p.srcImageFormat)) + { + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + region.bufferOffset = offset + 4; + regions.push_back(region); + } + } + + 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), subresource}; DoPipelineBarrier(cmd, 1, &barrier); - cmdCopySource = m_CallbackInfo.stagingImage; - cmdCopySourceLayout = VK_IMAGE_LAYOUT_GENERAL; - baseArrayLayer = 0; + ObjDisp(cmd)->CmdCopyImageToBuffer( + Unwrap(cmd), Unwrap(p.srcImage), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + Unwrap(m_CallbackInfo.dstBuffer), (uint32_t)regions.size(), regions.data()); + + 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); } - - 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, - cmdCopySourceLayout, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - Unwrap(cmdCopySource), - {aspectFlags, 0, 1, baseArrayLayer, 1}}; - - DoPipelineBarrier(cmd, 1, &barrier); - - ObjDisp(cmd)->CmdCopyImageToBuffer( - Unwrap(cmd), Unwrap(cmdCopySource), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - Unwrap(m_CallbackInfo.dstBuffer), (uint32_t)regions.size(), regions.data()); - - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.newLayout = cmdCopySourceLayout; - DoPipelineBarrier(cmd, 1, &barrier); } WrappedVulkan *m_pDriver; @@ -1032,9 +1072,8 @@ struct VulkanColorAndStencilCallback : public VulkanPixelHistoryCallback { VkRenderPass newRp = CreateRenderPass(pipestate.renderPass, pipestate.GetFramebuffer(), pipestate.subpass); - VkFramebuffer newFb = - CreateFramebuffer(pipestate.renderPass, newRp, pipestate.subpass, - pipestate.GetFramebuffer(), m_CallbackInfo.stencilImageView); + VkFramebuffer newFb = CreateFramebuffer(pipestate.renderPass, newRp, pipestate.subpass, + pipestate.GetFramebuffer(), m_CallbackInfo.dsImageView); uint32_t framebufferIndex = 0; const rdcarray &atts = pipestate.GetFramebufferAttachments(); for(uint32_t i = 0; i < atts.size(); i++) @@ -1065,11 +1104,10 @@ struct VulkanColorAndStencilCallback : public VulkanPixelHistoryCallback ReplayDraw(cmd, eid, true); CopyPixelParams params = {}; - params.srcImage = m_CallbackInfo.stencilImage; + params.srcImage = m_CallbackInfo.dsImage; params.srcImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; params.srcImageFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; params.depthCopy = true; - params.stencilOnly = true; // Copy stencil value that indicates the number of fragments ignoring // shader discard. CopyImagePixel(cmd, params, storeOffset + offsetof(struct EventInfo, dsWithoutShaderDiscard)); @@ -1867,9 +1905,11 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback { VulkanPixelHistoryPerFragmentCallback(WrappedVulkan *vk, PixelHistoryShaderCache *shaderCache, const PixelHistoryCallbackInfo &callbackInfo, - std::map eventFragments) + const std::map &eventFragments, + const std::map &eventPremods) : VulkanPixelHistoryCallback(vk, shaderCache, callbackInfo, VK_NULL_HANDLE), - m_EventFragments(eventFragments) + m_EventFragments(eventFragments), + m_EventPremods(eventPremods) { } @@ -1907,7 +1947,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback VkFramebuffer newFb = CreateFramebuffer(state.renderPass, newRp, state.subpass, state.GetFramebuffer(), - m_CallbackInfo.stencilImageView, m_CallbackInfo.subImageView); + m_CallbackInfo.dsImageView, m_CallbackInfo.subImageView); uint32_t framebufferIndex = 0; const rdcarray &atts = prevState.GetFramebufferAttachments(); @@ -1921,7 +1961,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback } } - Pipelines pipes = CreatePipelines(curPipeline, newRp, eid, false, 0, framebufferIndex); + Pipelines pipes = CreatePerFragmentPipelines(curPipeline, newRp, eid, false, 0, framebufferIndex); state.renderPass = GetResID(newRp); state.SetFramebuffer(m_pDriver, GetResID(newFb)); @@ -1932,9 +1972,12 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback CopyPixelParams colourCopyParams = {}; colourCopyParams.srcImage = m_CallbackInfo.subImage; - colourCopyParams.srcImageLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // TODO: image layout - colourCopyParams.srcImageFormat = VK_FORMAT_R32G32B32A32_SFLOAT; + // Use the layout of the image we are substituting for. + VkImageLayout srcImageLayout = m_pDriver->GetDebugManager()->GetImageLayout( + GetResID(m_CallbackInfo.targetImage), VK_IMAGE_ASPECT_COLOR_BIT, + m_CallbackInfo.targetSubresource.mip, m_CallbackInfo.targetSubresource.slice); + colourCopyParams.srcImageLayout = srcImageLayout; + colourCopyParams.srcImageFormat = m_CallbackInfo.targetImageFormat; const VulkanCreationInfo::Pipeline &p = m_pDriver->GetDebugManager()->GetPipelineInfo(prevState.graphics.pipeline); @@ -1954,7 +1997,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, - Unwrap(m_CallbackInfo.stencilImage), + Unwrap(m_CallbackInfo.dsImage), {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1}}; DoPipelineBarrier(cmd, 1, &barrier); @@ -1971,7 +2014,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback range.baseMipLevel = 0; range.layerCount = 1; range.levelCount = 1; - ObjDisp(cmd)->CmdClearDepthStencilImage(Unwrap(cmd), Unwrap(m_CallbackInfo.stencilImage), + ObjDisp(cmd)->CmdClearDepthStencilImage(Unwrap(cmd), Unwrap(m_CallbackInfo.dsImage), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &dsValue, 1, &range); @@ -2007,7 +2050,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback { CopyPixelParams depthCopyParams = colourCopyParams; depthCopyParams.depthCopy = true; - depthCopyParams.srcImage = m_CallbackInfo.stencilImage; + depthCopyParams.srcImage = m_CallbackInfo.dsImage; depthCopyParams.srcImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthCopyParams.srcImageFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; CopyImagePixel(cmd, depthCopyParams, @@ -2029,13 +2072,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback depthFormat = imginfo.format; } - // Restore the original framebuffer and render pass, so that we can get - // post modification values. - state.SetFramebuffer(prevState.GetFramebuffer(), prevState.GetFramebufferAttachments()); - state.renderPass = prevState.renderPass; - colourCopyParams.srcImage = m_CallbackInfo.targetImage; - colourCopyParams.srcImageFormat = m_CallbackInfo.targetImageFormat; - + const ModificationValue &premod = m_EventPremods[eid]; // For every fragment except the last one, retrieve post-modification // value. for(uint32_t f = 0; f < numFragmentsInEvent - 1; f++) @@ -2054,6 +2091,23 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback rect.baseArrayLayer = 0; rect.layerCount = 1; ObjDisp(cmd)->CmdClearAttachments(Unwrap(cmd), 1, &att, 1, &rect); + + if(f == 0) + { + // Before starting the draw, initialize the pixel to the premodification value + // for this event, for both color and stencil. + VkClearAttachment clearAtts[2] = {}; + clearAtts[0].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + clearAtts[0].colorAttachment = framebufferIndex; + memcpy(clearAtts[0].clearValue.color.float32, premod.col.floatValue, + sizeof(clearAtts[0].clearValue.color)); + + clearAtts[1].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + clearAtts[1].clearValue.depthStencil.depth = premod.depth; + + ObjDisp(cmd)->CmdClearAttachments(Unwrap(cmd), 2, clearAtts, 1, &rect); + } + ObjDisp(cmd)->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_FRONT_AND_BACK, f); const DrawcallDescription *drawcall = m_pDriver->GetDrawcall(eid); if(drawcall->flags & DrawFlags::Indexed) @@ -2072,7 +2126,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback { CopyPixelParams depthCopyParams = colourCopyParams; depthCopyParams.depthCopy = true; - depthCopyParams.srcImage = depthImage; + depthCopyParams.srcImage = m_CallbackInfo.dsImage; depthCopyParams.srcImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthCopyParams.srcImageFormat = depthFormat; CopyImagePixel(cmd, depthCopyParams, (fragsProcessed + f) * sizeof(PerFragmentInfo) + @@ -2090,9 +2144,10 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback } bool PostDraw(uint32_t eid, VkCommandBuffer cmd) { return false; } void PostRedraw(uint32_t eid, VkCommandBuffer cmd) {} - // CreatePipelines for getting per fragment information. - Pipelines CreatePipelines(ResourceId pipe, VkRenderPass rp, uint32_t eid, bool dynamicScissor, - uint32_t fragmentIndex, uint32_t framebufferIndex) + // CreatePerFragmentPipelines for getting per fragment information. + Pipelines CreatePerFragmentPipelines(ResourceId pipe, VkRenderPass rp, uint32_t eid, + bool dynamicScissor, uint32_t fragmentIndex, + uint32_t framebufferIndex) { const VulkanCreationInfo::Pipeline &p = m_pDriver->GetDebugManager()->GetPipelineInfo(pipe); VkGraphicsPipelineCreateInfo pipeCreateInfo = {}; @@ -2178,6 +2233,8 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback dynState->pDynamicStates = dynamicStates.data(); } + pipeCreateInfo.renderPass = rp; + Pipelines pipes = {}; VkResult vkr = m_pDriver->vkCreateGraphicsPipelines(m_pDriver->GetDev(), VK_NULL_HANDLE, 1, &pipeCreateInfo, NULL, &pipes.postModPipe); @@ -2189,6 +2246,11 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback // Disable some tests, leave depthTest and depthWriteEnable as is. // If we disable depth test, depth information would not be written. { + // TODO: this causes post-modification values to be incorrectly mapped to events + // if some fragments failed due to culling. We are disabling culling for reporting + // shader output values and events, but if some events failed culling when we + // replay to get post-modification values the stencil count will not reach the + // expected stencil count, since stencil is not updated if culling failed. rs->cullMode = VK_CULL_MODE_NONE; rs->rasterizerDiscardEnable = VK_FALSE; ds->depthBoundsTestEnable = VK_FALSE; @@ -2196,7 +2258,6 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback ds->depthCompareOp = VK_COMPARE_OP_ALWAYS; } - pipeCreateInfo.renderPass = rp; VkPipelineColorBlendStateCreateInfo *cbs = (VkPipelineColorBlendStateCreateInfo *)pipeCreateInfo.pColorBlendState; // Turn off blending so that we can get shader output values. @@ -2288,6 +2349,9 @@ private: std::map m_EventIndices; // Number of fragments for each event. std::map m_EventFragments; + // Pre-modification values for events to initialize attachments to, + // so that we can get blended post-modification values. + std::map m_EventPremods; // Number of fragments processed so far. uint32_t fragsProcessed = 0; @@ -2440,16 +2504,14 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou { VkImage colorImage; VkImageView colorImageView; - VkImage stencilImage; - VkImageView stencilImageView; - VkImage stagingImage = VK_NULL_HANDLE; - VkImageView stagingImageView = VK_NULL_HANDLE; - VkDeviceSize stagingImageOffset = 0; - VkImage stencilStagingImage = VK_NULL_HANDLE; - VkImageView stencilStagingImageView = VK_NULL_HANDLE; - VkDeviceSize stencilStagingImageOffset = 0; + VkImage dsImage; + VkImageView dsImageView; + + VkImageView colorImageAliasView = VK_NULL_HANDLE; VkImageView targetImageView = VK_NULL_HANDLE; + VkImageView depthOnlyImageView = VK_NULL_HANDLE; + VkImageView stencilOnlyImageView = VK_NULL_HANDLE; VkDeviceMemory gpuMem; @@ -2476,7 +2538,10 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou imgInfo.extent.height = extent.height; imgInfo.extent.depth = 1; imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imgInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + imgInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT; + if(samples != VK_SAMPLE_COUNT_1_BIT) + imgInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &colorImage); RDCASSERTEQUAL(vkr, VK_SUCCESS); @@ -2491,41 +2556,16 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou imgInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &stencilImage); + vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &dsImage); RDCASSERTEQUAL(vkr, VK_SUCCESS); - ImageState stencilImageState = ImageState(stencilImage, ImageInfo(imgInfo), eFrameRef_None); + ImageState stencilImageState = ImageState(dsImage, ImageInfo(imgInfo), eFrameRef_None); VkMemoryRequirements stencilImageMrq = {0}; - m_pDriver->vkGetImageMemoryRequirements(dev, stencilImage, &stencilImageMrq); + m_pDriver->vkGetImageMemoryRequirements(dev, dsImage, &stencilImageMrq); VkDeviceSize offset = AlignUp(totalMemorySize, stencilImageMrq.alignment); totalMemorySize = offset + stencilImageMrq.size; - if(samples != VK_SAMPLE_COUNT_1_BIT) - { - imgInfo.format = format; - imgInfo.arrayLayers = 1; - imgInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imgInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &stagingImage); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - VkMemoryRequirements msImageMrq = {0}; - m_pDriver->vkGetImageMemoryRequirements(dev, stagingImage, &msImageMrq); - stagingImageOffset = AlignUp(totalMemorySize, msImageMrq.alignment); - totalMemorySize = stagingImageOffset + msImageMrq.size; - - imgInfo.format = VK_FORMAT_D32_SFLOAT_S8_UINT; - imgInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &stencilStagingImage); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - VkMemoryRequirements stencilStagingImageMrq = {0}; - m_pDriver->vkGetImageMemoryRequirements(dev, stencilStagingImage, &stencilStagingImageMrq); - stencilStagingImageOffset = AlignUp(totalMemorySize, stencilStagingImageMrq.alignment); - totalMemorySize = stencilStagingImageOffset + stencilStagingImageMrq.size; - } - VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, totalMemorySize, m_pDriver->GetGPULocalMemoryIndex(colorImageMrq.memoryTypeBits), @@ -2536,7 +2576,7 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou vkr = m_pDriver->vkBindImageMemory(m_Device, colorImage, gpuMem, 0); RDCASSERTEQUAL(vkr, VK_SUCCESS); - vkr = m_pDriver->vkBindImageMemory(m_Device, stencilImage, gpuMem, offset); + vkr = m_pDriver->vkBindImageMemory(m_Device, dsImage, gpuMem, offset); RDCASSERTEQUAL(vkr, VK_SUCCESS); VkImageViewCreateInfo viewInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; @@ -2545,26 +2585,21 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou viewInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + if(samples != VK_SAMPLE_COUNT_1_BIT) + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &colorImageView); RDCASSERTEQUAL(vkr, VK_SUCCESS); - viewInfo.image = stencilImage; + viewInfo.image = dsImage; viewInfo.format = VK_FORMAT_D32_SFLOAT_S8_UINT; viewInfo.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1}; - vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &stencilImageView); + vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &dsImageView); RDCASSERTEQUAL(vkr, VK_SUCCESS); if(samples != VK_SAMPLE_COUNT_1_BIT) { - vkr = m_pDriver->vkBindImageMemory(m_Device, stagingImage, gpuMem, stagingImageOffset); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - viewInfo.image = stagingImage; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; - viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, - VK_REMAINING_ARRAY_LAYERS}; - uint32_t bs = GetByteSize(1, 1, 1, format, 0); if(bs == 1) @@ -2583,30 +2618,29 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou RDCERR("Can't copy 2D to Array with format %s", ToStr(format).c_str()); } - vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &stagingImageView); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - viewInfo.image = targetImage; viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, sub.mip, 1, sub.slice, 1}; vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &targetImageView); RDCASSERTEQUAL(vkr, VK_SUCCESS); - viewInfo.image = stencilStagingImage; + viewInfo.format = VK_FORMAT_R32G32B32A32_UINT; + viewInfo.image = colorImage; + viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &colorImageAliasView); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + viewInfo.image = dsImage; viewInfo.format = VK_FORMAT_D32_SFLOAT_S8_UINT; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &depthOnlyImageView); - vkr = m_pDriver->vkBindImageMemory(m_Device, stencilStagingImage, gpuMem, - stencilStagingImageOffset); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &stencilStagingImageView); - RDCASSERTEQUAL(vkr, VK_SUCCESS); + viewInfo.subresourceRange = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1}; + vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &stencilOnlyImageView); } VkBufferCreateInfo bufferInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; bufferInfo.size = AlignUp((uint32_t)(numEvents * sizeof(EventInfo)), 4096U); - bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; vkr = m_pDriver->vkCreateBuffer(m_Device, &bufferInfo, NULL, &dstBuffer); RDCASSERTEQUAL(vkr, VK_SUCCESS); @@ -2643,41 +2677,68 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou resources.colorImage = colorImage; resources.colorImageView = colorImageView; - resources.stencilImage = stencilImage; - resources.stencilImageView = stencilImageView; - resources.stagingImage = stagingImage; - resources.stagingImageView = stagingImageView; - resources.stencilStagingImage = stencilStagingImage; - resources.stencilStagingImageView = stencilStagingImageView; - resources.targetImageView = targetImageView; + resources.dsImage = dsImage; + resources.dsImageView = dsImageView; resources.gpuMem = gpuMem; + resources.colorImageAliasView = colorImageAliasView; + resources.targetImageView = targetImageView; + resources.depthOnlyImageView = depthOnlyImageView; + resources.stencilOnlyImageView = stencilOnlyImageView; + resources.bufferMemory = bufferMemory; resources.dstBuffer = dstBuffer; return true; } -void VulkanReplay::UpdatePixelHistoryDescriptor(VkImageView sourceView, VkImageView destView) +void VulkanReplay::UpdatePixelHistoryDescriptor(VkImageView sourceView, VkImageView depthImageView, + VkImageView stencilImageView, VkBuffer destBuffer) { - VkDescriptorImageInfo srcdesc = {0}; - srcdesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - srcdesc.imageView = Unwrap(sourceView); - srcdesc.sampler = Unwrap(m_General.PointSampler); // not used - we use texelFetch + VkDescriptorBufferInfo destdesc = {0}; + destdesc.buffer = Unwrap(destBuffer); + destdesc.range = VK_WHOLE_SIZE; - VkDescriptorImageInfo destdesc = {0}; - destdesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - destdesc.imageView = Unwrap(destView); + { + VkDescriptorImageInfo srcdesc = {}; + srcdesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + srcdesc.imageView = Unwrap(sourceView); + srcdesc.sampler = Unwrap(m_General.PointSampler); // not used - we use texelFetch - VkWriteDescriptorSet writeSet[] = { - {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_PixelHistory.MSCopyDescSet), 0, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc, NULL, NULL}, - {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_PixelHistory.MSCopyDescSet), 2, 0, 1, - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &destdesc, NULL, NULL}, - }; + VkWriteDescriptorSet writeSet[] = { + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_PixelHistory.MSCopyDescSet), 0, 0, + 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc, NULL, NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_PixelHistory.MSCopyDescSet), 1, 0, + 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc, NULL, NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_PixelHistory.MSCopyDescSet), 2, 0, + 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, NULL, &destdesc, NULL}, + }; - ObjDisp(m_pDriver->GetDev()) - ->UpdateDescriptorSets(Unwrap(m_pDriver->GetDev()), ARRAY_COUNT(writeSet), writeSet, 0, NULL); + ObjDisp(m_pDriver->GetDev()) + ->UpdateDescriptorSets(Unwrap(m_pDriver->GetDev()), ARRAY_COUNT(writeSet), writeSet, 0, NULL); + } + + { + VkDescriptorImageInfo srcdesc[2] = {}; + srcdesc[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + srcdesc[0].imageView = Unwrap(depthImageView); + srcdesc[0].sampler = Unwrap(m_General.PointSampler); // not used - we use texelFetch + + srcdesc[1] = srcdesc[0]; + srcdesc[1].imageView = Unwrap(stencilImageView); + + VkWriteDescriptorSet writeSet[] = { + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_PixelHistory.MSDepthCopyDescSet), 0, + 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc[0], NULL, NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_PixelHistory.MSDepthCopyDescSet), 1, + 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc[1], NULL, NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_PixelHistory.MSDepthCopyDescSet), 2, + 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, NULL, &destdesc, NULL}, + }; + + ObjDisp(m_pDriver->GetDev()) + ->UpdateDescriptorSets(Unwrap(m_pDriver->GetDev()), ARRAY_COUNT(writeSet), writeSet, 0, NULL); + } } bool VulkanDebugManager::PixelHistoryDestroyResources(const PixelHistoryResources &r) @@ -2689,18 +2750,18 @@ bool VulkanDebugManager::PixelHistoryDestroyResources(const PixelHistoryResource 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.stagingImage != VK_NULL_HANDLE) - m_pDriver->vkDestroyImage(dev, r.stagingImage, NULL); - if(r.stagingImageView != VK_NULL_HANDLE) - m_pDriver->vkDestroyImageView(dev, r.stagingImageView, NULL); - if(r.stencilStagingImage != VK_NULL_HANDLE) - m_pDriver->vkDestroyImage(dev, r.stencilStagingImage, NULL); - if(r.stencilStagingImageView != VK_NULL_HANDLE) - m_pDriver->vkDestroyImageView(dev, r.stencilStagingImageView, NULL); + if(r.dsImage != VK_NULL_HANDLE) + m_pDriver->vkDestroyImage(dev, r.dsImage, NULL); + if(r.dsImageView != VK_NULL_HANDLE) + m_pDriver->vkDestroyImageView(dev, r.dsImageView, NULL); + if(r.colorImageAliasView != VK_NULL_HANDLE) + m_pDriver->vkDestroyImageView(dev, r.colorImageAliasView, NULL); + if(r.targetImageView != VK_NULL_HANDLE) + m_pDriver->vkDestroyImageView(dev, r.targetImageView, NULL); + if(r.depthOnlyImageView != VK_NULL_HANDLE) + m_pDriver->vkDestroyImageView(dev, r.depthOnlyImageView, NULL); + if(r.stencilOnlyImageView != VK_NULL_HANDLE) + m_pDriver->vkDestroyImageView(dev, r.stencilOnlyImageView, NULL); if(r.dstBuffer != VK_NULL_HANDLE) m_pDriver->vkDestroyBuffer(dev, r.dstBuffer, NULL); if(r.bufferMemory != VK_NULL_HANDLE) @@ -2876,7 +2937,8 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even imginfo.format, imginfo.samples, sub, (uint32_t)events.size()); if(multisampled) - UpdatePixelHistoryDescriptor(resources.targetImageView, resources.stagingImageView); + UpdatePixelHistoryDescriptor(resources.targetImageView, resources.depthOnlyImageView, + resources.stencilOnlyImageView, resources.dstBuffer); PixelHistoryShaderCache *shaderCache = new PixelHistoryShaderCache(m_pDriver); @@ -2893,11 +2955,9 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even callbackInfo.sampleMask = sampleMask; callbackInfo.subImage = resources.colorImage; callbackInfo.subImageView = resources.colorImageView; - callbackInfo.stencilImage = resources.stencilImage; - callbackInfo.stencilImageView = resources.stencilImageView; + callbackInfo.dsImage = resources.dsImage; + callbackInfo.dsImageView = resources.dsImageView; callbackInfo.dstBuffer = resources.dstBuffer; - callbackInfo.stagingImage = resources.stagingImage; - callbackInfo.stencilStagingImage = resources.stencilStagingImage; VulkanOcclusionCallback occlCb(m_pDriver, shaderCache, callbackInfo, occlusionPool, events); m_pDriver->ReplayLog(0, events.back().eventId, eReplay_Full); @@ -2916,7 +2976,7 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even if(events[ev].view != ResourceId()) { - // TODO + // TODO: Check that the slice and mip matches. } if(directWrite || clear) @@ -2998,6 +3058,7 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even RDCASSERTEQUAL(vkr, VK_SUCCESS); std::map eventsWithFrags; + std::map eventPremods; ResourceFormat fmt = MakeResourceFormat(imginfo.format); for(size_t h = 0; h < history.size();) @@ -3019,8 +3080,8 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even mod.postMod.depth = ei.postmod.depth.fdepth; mod.postMod.stencil = ei.postmod.stencil; - int32_t frags = int32_t(ei.dsWithoutShaderDiscard[0]); - int32_t fragsClipped = int32_t(ei.dsWithShaderDiscard[0]); + int32_t frags = int32_t(ei.dsWithoutShaderDiscard[4]); + int32_t fragsClipped = int32_t(ei.dsWithShaderDiscard[4]); mod.shaderOut.col.intValue[0] = frags; mod.shaderOut.col.intValue[1] = fragsClipped; bool someFragsClipped = (fragsClipped < frags); @@ -3028,7 +3089,10 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even // Draws in secondary command buffers will fail this check, // so nothing else needs to be checked in the callback itself. if(frags > 0) + { eventsWithFrags[mod.eventId] = frags; + eventPremods[mod.eventId] = mod.preMod; + } for(int32_t f = 1; f < frags; f++) { @@ -3040,7 +3104,7 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even RDCDEBUG( "PixelHistory event id: %u, fixed shader stencilValue = %u, original shader stencilValue = " "%u", - mod.eventId, ei.dsWithoutShaderDiscard[0], ei.dsWithShaderDiscard[0]); + mod.eventId, ei.dsWithoutShaderDiscard[4], ei.dsWithShaderDiscard[4]); } m_pDriver->vkUnmapMemory(dev, resources.bufferMemory); @@ -3048,8 +3112,11 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even { // Replay to get shader output value, post modification value and primitive ID for every // fragment. + if(multisampled) + UpdatePixelHistoryDescriptor(resources.colorImageAliasView, resources.depthOnlyImageView, + resources.stencilOnlyImageView, resources.dstBuffer); VulkanPixelHistoryPerFragmentCallback perFragmentCB(m_pDriver, shaderCache, callbackInfo, - eventsWithFrags); + eventsWithFrags, eventPremods); m_pDriver->ReplayLog(0, eventsWithFrags.rbegin()->first, eReplay_Full); m_pDriver->SubmitCmds(); m_pDriver->FlushQ(); @@ -3099,7 +3166,6 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even } uint32_t discardOffset = 0; - ResourceFormat resourceFmt = MakeResourceFormat(imginfo.format); ResourceFormat shaderOutFormat = MakeResourceFormat(VK_FORMAT_R32G32B32A32_SFLOAT); for(size_t h = 0; h < history.size(); h++) { @@ -3125,7 +3191,7 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even if((h < history.size() - 1) && (history[h].eventId == history[h + 1].eventId)) { // Get post-modification value if this is not the last fragment for the event. - FillInColor(resourceFmt, bp[offset].postMod, history[h].postMod); + FillInColor(shaderOutFormat, bp[offset].postMod, history[h].postMod); history[h].postMod.depth = bp[offset].postMod.depth.fdepth; } } diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index cd004cfb6..f71d1b724 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -2795,11 +2795,32 @@ rdcarray VulkanReplay::GetUsage(ResourceId id) return m_pDriver->GetUsage(id); } -void VulkanReplay::CopyPixelForPixelHistory(VkCommandBuffer cmd, VkExtent3D extent, uint32_t sample, - VkFormat fmt) +void VulkanReplay::CopyPixelForPixelHistory(VkCommandBuffer cmd, VkOffset2D offset, uint32_t sample, + uint32_t bufferOffset, bool depthCopy) { - m_pDriver->GetDebugManager()->CopyTex2DMSPixel(cmd, m_PixelHistory.MSCopyDescSet, extent, sample, - fmt); + if(m_PixelHistory.MSCopyPipe == VK_NULL_HANDLE) + return; + + VkDescriptorSet descSet; + if(depthCopy) + descSet = m_PixelHistory.MSDepthCopyDescSet; + else + descSet = m_PixelHistory.MSCopyDescSet; + if(!m_pDriver->GetDeviceFeatures().shaderStorageImageWriteWithoutFormat) + return; + + ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_PixelHistory.MSCopyPipe)); + + uint32_t params[8] = {depthCopy, sample, (uint32_t)offset.x, (uint32_t)offset.y, bufferOffset, 0, + 0, 0}; + ObjDisp(cmd)->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_COMPUTE, + Unwrap(m_PixelHistory.MSCopyPipeLayout), 0, 1, + UnwrapPtr(descSet), 0, NULL); + + ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_PixelHistory.MSCopyPipeLayout), + VK_SHADER_STAGE_ALL, 0, 8 * 4, params); + ObjDisp(cmd)->CmdDispatch(Unwrap(cmd), 1, 1, 1); } void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index e09124a47..b2d7015d0 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -322,7 +322,8 @@ public: float *maxval); bool GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval, float maxval, bool channels[4], rdcarray &histogram); - void UpdatePixelHistoryDescriptor(VkImageView sourceView, VkImageView destView); + void UpdatePixelHistoryDescriptor(VkImageView sourceView, VkImageView depthImageView, + VkImageView stencilImageView, VkBuffer destBuffer); void InitPostVSBuffers(uint32_t eventId); void InitPostVSBuffers(uint32_t eventId, VulkanRenderState &state); @@ -414,8 +415,8 @@ public: void SetDriverInformation(const VkPhysicalDeviceProperties &props); AMDCounters *GetAMDCounters() { return m_pAMDCounters; } - void CopyPixelForPixelHistory(VkCommandBuffer cmd, VkExtent3D extent, uint32_t sample, - VkFormat fmt); + void CopyPixelForPixelHistory(VkCommandBuffer cmd, VkOffset2D offset, uint32_t sample, + uint32_t bufferOffset, bool depthCopy); private: void FetchShaderFeedback(uint32_t eventId); @@ -674,6 +675,9 @@ private: VkDescriptorSetLayout MSCopyDescSetLayout = VK_NULL_HANDLE; VkDescriptorSet MSCopyDescSet = VK_NULL_HANDLE; + VkDescriptorSet MSDepthCopyDescSet = VK_NULL_HANDLE; + VkPipeline MSCopyPipe = VK_NULL_HANDLE; + VkPipelineLayout MSCopyPipeLayout = VK_NULL_HANDLE; } m_PixelHistory; struct HistogramMinMax diff --git a/renderdoc/driver/vulkan/vk_shader_cache.cpp b/renderdoc/driver/vulkan/vk_shader_cache.cpp index bbdfe28fc..ac3fef9f5 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.cpp +++ b/renderdoc/driver/vulkan/vk_shader_cache.cpp @@ -91,6 +91,8 @@ static const BuiltinShaderConfig builtinShaders[] = { rdcspv::ShaderStage::Fragment, FeatureCheck::NoCheck, true}, {BuiltinShader::TexRemapSInt, EmbeddedResource(glsl_texremap_frag), rdcspv::ShaderStage::Fragment, FeatureCheck::NoCheck, true}, + {BuiltinShader::PixelHistoryMSCopyCS, EmbeddedResource(glsl_pixelhistory_mscopy_comp), + rdcspv::ShaderStage::Compute, FeatureCheck::NoCheck, true}, {BuiltinShader::PixelHistoryPrimIDFS, EmbeddedResource(glsl_pixelhistory_primid_frag), rdcspv::ShaderStage::Fragment, FeatureCheck::NoCheck, true}, {BuiltinShader::ShaderDebugSampleVS, EmbeddedResource(glsl_shaderdebug_sample_vert), diff --git a/renderdoc/driver/vulkan/vk_shader_cache.h b/renderdoc/driver/vulkan/vk_shader_cache.h index 35ade9750..d6d0849e4 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.h +++ b/renderdoc/driver/vulkan/vk_shader_cache.h @@ -54,6 +54,7 @@ enum class BuiltinShader TexRemapFloat, TexRemapUInt, TexRemapSInt, + PixelHistoryMSCopyCS, PixelHistoryPrimIDFS, ShaderDebugSampleVS, Count, diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index f45acf989..8382b81fd 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -599,6 +599,7 @@ + diff --git a/util/test/demos/vk/vk_pixel_history_test.cpp b/util/test/demos/vk/vk_pixel_history_test.cpp index 979bf33a4..c47526cf5 100644 --- a/util/test/demos/vk/vk_pixel_history_test.cpp +++ b/util/test/demos/vk/vk_pixel_history_test.cpp @@ -81,6 +81,12 @@ layout(location = 0, index = 0) out vec4 Color; void main() { + if(gl_PrimitiveID == 0) + { + Color = vec4(1, 0, 1, 1); + return; + } + if (gl_SampleID == 0) Color = vec4(1, 0, 0, 1); else if (gl_SampleID == 1) diff --git a/util/test/tests/Vulkan/VK_Pixel_History.py b/util/test/tests/Vulkan/VK_Pixel_History.py index 84db3e3e2..164b72bf2 100644 --- a/util/test/tests/Vulkan/VK_Pixel_History.py +++ b/util/test/tests/Vulkan/VK_Pixel_History.py @@ -117,13 +117,14 @@ class VK_Pixel_History(rdtest.TestCase): beg_renderpass_eid = self.find_draw("Multisampled: begin renderpass").next.eventId - x, y = 100, 200 + x, y = 140, 130 sub.sample = 1 rdtest.log.print("Testing pixel {}, {} at sample {}".format(x, y, sub.sample)) modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) events = [ [[event_id, beg_renderpass_eid], [passed, True], [post_mod_col, (0.0, 1.0, 0.0, 1.0)]], - [[event_id, draw_eid], [passed, True], [post_mod_col, (0.0, 0.0, 1.0, 1.0)]], + [[event_id, draw_eid], [passed, True], [primitive_id, 0], [shader_out_col, (1.0, 0.0, 1.0, 1.0)], [post_mod_col, (1.0, 0.0, 1.0, 1.0)]], + [[event_id, draw_eid], [passed, True], [primitive_id, 1], [shader_out_col, (0.0, 0.0, 1.0, 1.0)], [post_mod_col, (0.0, 0.0, 1.0, 1.0)]], ] self.check_events(events, modifs, True) self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) @@ -133,7 +134,8 @@ class VK_Pixel_History(rdtest.TestCase): modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) events = [ [[event_id, beg_renderpass_eid], [passed, True], [post_mod_col, (0.0, 1.0, 0.0, 1.0)]], - [[event_id, draw_eid], [passed, True], [post_mod_col, (0.0, 1.0, 1.0, 1.0)]], + [[event_id, draw_eid], [passed, True], [primitive_id, 0], [shader_out_col, (1.0, 0.0, 1.0, 1.0)], [post_mod_col, (1.0, 0.0, 1.0, 1.0)]], + [[event_id, draw_eid], [passed, True], [primitive_id, 1], [shader_out_col, (0.0, 1.0, 1.0, 1.0)], [post_mod_col, (0.0, 1.0, 1.0, 1.0)]], ] self.check_events(events, modifs, True) self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)