From 2cb546686bf1ca3c9a87d1f75d10fdc2d1eb3b6e Mon Sep 17 00:00:00 2001 From: Aliya Pazylbekova Date: Mon, 27 Apr 2020 10:26:03 -0400 Subject: [PATCH] Vk Pixel History: multi sampled colour Colour only, depth/stencil copy not supported. This means that we only report pre-mod and post-mod colour values for events. Since stencil copy is not supported, number of fragments is not reported, and shader output is not queried. --- renderdoc/data/glsl/ms2array.comp | 15 +- renderdoc/driver/vulkan/vk_debug.cpp | 22 + renderdoc/driver/vulkan/vk_debug.h | 9 +- .../driver/vulkan/vk_msaa_array_conv.cpp | 21 + renderdoc/driver/vulkan/vk_pixelhistory.cpp | 429 ++++++++++++------ renderdoc/driver/vulkan/vk_replay.cpp | 7 + renderdoc/driver/vulkan/vk_replay.h | 13 + util/test/demos/vk/vk_pixel_history_test.cpp | 57 ++- util/test/tests/Vulkan/Vk_Pixel_History.py | 37 ++ 9 files changed, 456 insertions(+), 154 deletions(-) diff --git a/renderdoc/data/glsl/ms2array.comp b/renderdoc/data/glsl/ms2array.comp index d2c46e8dc..fad78ca54 100644 --- a/renderdoc/data/glsl/ms2array.comp +++ b/renderdoc/data/glsl/ms2array.comp @@ -70,9 +70,18 @@ uniform ivec4 mscopy; void main() { ivec3 id = ivec3(gl_GlobalInvocationID); - - int slice = int(id.z / numMultiSamples); - int sampleIdx = int(id.z % numMultiSamples); + int slice; + int sampleIdx; + if(numMultiSamples == 0) + { + slice = currentSlice; + sampleIdx = currentSample; + } + else + { + slice = int(id.z / numMultiSamples); + sampleIdx = int(id.z % numMultiSamples); + } uvec4 data = texelFetch(srcMS, ivec3(int(id.x), int(id.y), slice), sampleIdx); diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 2d55d59f2..96381970b 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -1714,6 +1714,10 @@ void VulkanReplay::CreateResources() m_PixelPick.Init(m_pDriver, m_General.DescriptorPool); + RenderDoc::Inst().SetProgress(LoadProgress::DebugManagerInit, 0.75f); + + m_PixelHistory.Init(m_pDriver, m_General.DescriptorPool); + RenderDoc::Inst().SetProgress(LoadProgress::DebugManagerInit, 0.8f); m_Histogram.Init(m_pDriver, m_General.DescriptorPool); @@ -1765,6 +1769,7 @@ void VulkanReplay::DestroyResources() m_Overlay.Destroy(m_pDriver); m_VertexPick.Destroy(m_pDriver); m_PixelPick.Destroy(m_pDriver); + m_PixelHistory.Destroy(m_pDriver); m_Histogram.Destroy(m_pDriver); m_PostVS.Destroy(m_pDriver); @@ -2594,6 +2599,23 @@ void VulkanReplay::PixelPicking::Destroy(WrappedVulkan *driver) driver->vkDestroyRenderPass(driver->GetDev(), RP, NULL); } +void VulkanReplay::PixelHistory::Init(WrappedVulkan *driver, VkDescriptorPool descriptorPool) +{ + CREATE_OBJECT(MSCopyDescSetLayout, + { + {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}, + }); + CREATE_OBJECT(MSCopyDescSet, descriptorPool, MSCopyDescSetLayout); +} + +void VulkanReplay::PixelHistory::Destroy(WrappedVulkan *driver) +{ + if(MSCopyDescSetLayout != VK_NULL_HANDLE) + driver->vkDestroyDescriptorSetLayout(driver->GetDev(), MSCopyDescSetLayout, NULL); +} + void VulkanReplay::HistogramMinMax::Init(WrappedVulkan *driver, VkDescriptorPool descriptorPool) { VulkanShaderCache *shaderCache = driver->GetShaderCache(); diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index 7f9366880..fa84eea94 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -68,6 +68,8 @@ 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; } @@ -86,8 +88,9 @@ public: void PatchLineStripIndexBuffer(const DrawcallDescription *draw, GPUBuffer &indexBuffer, uint32_t &indexCount); - bool PixelHistorySetupResources(PixelHistoryResources &resources, VkExtent3D extent, - VkFormat format, uint32_t numEvents); + bool PixelHistorySetupResources(PixelHistoryResources &resources, VkImage targetImage, + VkExtent3D extent, VkFormat format, VkSampleCountFlagBits samples, + const Subresource &sub, uint32_t numEvents); bool PixelHistoryDestroyResources(const PixelHistoryResources &resources); void PixelHistoryCopyPixel(VkCommandBuffer cmd, CopyPixelParams &p, size_t offset); @@ -114,13 +117,11 @@ private: // CopyArrayToTex2DMS & CopyTex2DMSToArray VkDescriptorPool m_ArrayMSDescriptorPool; - VkDescriptorSetLayout m_ArrayMSDescSetLayout = VK_NULL_HANDLE; VkPipelineLayout m_ArrayMSPipeLayout = VK_NULL_HANDLE; VkDescriptorSet m_ArrayMSDescSet = VK_NULL_HANDLE; VkPipeline m_Array2MSPipe = VK_NULL_HANDLE; VkPipeline m_MS2ArrayPipe = VK_NULL_HANDLE; - VkSampler m_ArrayMSSampler = VK_NULL_HANDLE; // [0] = non-MSAA, [1] = MSAA diff --git a/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp b/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp index f00900076..13778f365 100644 --- a/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp +++ b/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp @@ -146,6 +146,27 @@ 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 74a150979..2c68495d3 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -60,21 +60,11 @@ enum struct CopyPixelParams { - bool multisampled; - bool floatTex; - bool uintTex; - bool intTex; - bool depthCopy; bool stencilOnly; VkImage srcImage; VkFormat srcImageFormat; VkImageLayout srcImageLayout; - VkOffset3D imageOffset; - uint32_t slice; - uint32_t mipLevel; - - VkBuffer dstBuffer; }; struct PixelHistoryResources @@ -88,6 +78,13 @@ struct PixelHistoryResources VkImage stencilImage; VkImageView stencilImageView; VkDeviceMemory gpuMem; + + // Following are only used and created for multi sampled images. + VkImage stagingImage; + VkImageView stagingImageView; + VkImage stencilStagingImage; + VkImageView stencilStagingImageView; + VkImageView targetImageView; }; struct PixelHistoryCallbackInfo @@ -99,6 +96,7 @@ struct PixelHistoryCallbackInfo uint32_t layers; uint32_t mipLevels; VkSampleCountFlagBits samples; + VkExtent3D extent; // Information about the location of the pixel for which history was requested. Subresource targetSubresource; uint32_t x; @@ -113,6 +111,10 @@ struct PixelHistoryCallbackInfo VkImage stencilImage; VkImageView stencilImageView; + // Only used for multi sampled images for copy into a staging resource. + VkImage stagingImage; + VkImage stencilStagingImage; + // Buffer used to copy colour and depth information VkBuffer dstBuffer; }; @@ -592,7 +594,7 @@ protected: VkAttachmentDescription dsAtt = {}; dsAtt.format = VK_FORMAT_D32_SFLOAT_S8_UINT; - dsAtt.samples = VK_SAMPLE_COUNT_1_BIT; + dsAtt.samples = m_CallbackInfo.samples; dsAtt.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; dsAtt.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; dsAtt.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; @@ -689,6 +691,122 @@ protected: return framebuffer; } + 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) + { + 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; + } + 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; + } + } + + VkImage cmdCopySource = p.srcImage; + VkImageLayout cmdCopySourceLayout = p.srcImageLayout; + uint32_t baseArrayLayer = m_CallbackInfo.targetSubresource.slice; + + // 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}}; + + DoPipelineBarrier(cmd, 1, &barrier); + m_pDriver->GetReplay()->CopyPixelForPixelHistory(cmd, m_CallbackInfo.extent, + m_CallbackInfo.targetSubresource.sample, + m_CallbackInfo.targetImageFormat); + + 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); + + cmdCopySource = m_CallbackInfo.stagingImage; + cmdCopySourceLayout = VK_IMAGE_LAYOUT_GENERAL; + 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_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; PixelHistoryShaderCache *m_ShaderCache; PixelHistoryCallbackInfo m_CallbackInfo; @@ -947,30 +1065,21 @@ struct VulkanColorAndStencilCallback : public VulkanPixelHistoryCallback ReplayDraw(cmd, eid, true); CopyPixelParams params = {}; - params.multisampled = false; params.srcImage = m_CallbackInfo.stencilImage; params.srcImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; params.srcImageFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; - params.imageOffset.x = int32_t(m_CallbackInfo.x); - params.imageOffset.y = int32_t(m_CallbackInfo.y); - params.imageOffset.z = 0; - params.dstBuffer = m_CallbackInfo.dstBuffer; params.depthCopy = true; params.stencilOnly = true; - params.mipLevel = m_CallbackInfo.targetSubresource.mip; - params.slice = m_CallbackInfo.targetSubresource.slice; // Copy stencil value that indicates the number of fragments ignoring // shader discard. - m_pDriver->GetDebugManager()->PixelHistoryCopyPixel( - cmd, params, storeOffset + offsetof(struct EventInfo, dsWithoutShaderDiscard)); + CopyImagePixel(cmd, params, storeOffset + offsetof(struct EventInfo, dsWithoutShaderDiscard)); // Replay the draw with the original fragment shader to get the actual number // of fragments, accounting for potential shader discard. pipestate.graphics.pipeline = GetResID(replacements.originalShaderStencil); ReplayDraw(cmd, eid, true); - m_pDriver->GetDebugManager()->PixelHistoryCopyPixel( - cmd, params, storeOffset + offsetof(struct EventInfo, dsWithShaderDiscard)); + CopyImagePixel(cmd, params, storeOffset + offsetof(struct EventInfo, dsWithShaderDiscard)); } // Restore the state. @@ -1150,19 +1259,12 @@ private: VkCommandBuffer cmd, size_t offset) { CopyPixelParams colourCopyParams = {}; - colourCopyParams.multisampled = false; // TODO: multisampled colourCopyParams.srcImage = srcImage; - colourCopyParams.srcImageLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // TODO: image layout colourCopyParams.srcImageFormat = srcFormat; - colourCopyParams.imageOffset.x = int32_t(m_CallbackInfo.x); - colourCopyParams.imageOffset.y = int32_t(m_CallbackInfo.y); - colourCopyParams.imageOffset.z = 0; - colourCopyParams.dstBuffer = m_CallbackInfo.dstBuffer; - colourCopyParams.slice = m_CallbackInfo.targetSubresource.slice; - colourCopyParams.mipLevel = m_CallbackInfo.targetSubresource.mip; - - m_pDriver->GetDebugManager()->PixelHistoryCopyPixel(cmd, colourCopyParams, offset); + colourCopyParams.srcImageLayout = m_pDriver->GetDebugManager()->GetImageLayout( + GetResID(srcImage), VK_IMAGE_ASPECT_COLOR_BIT, m_CallbackInfo.targetSubresource.mip, + m_CallbackInfo.targetSubresource.slice); + CopyImagePixel(cmd, colourCopyParams, offset); if(depthImage != VK_NULL_HANDLE) { @@ -1171,8 +1273,7 @@ private: depthCopyParams.srcImage = depthImage; depthCopyParams.srcImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthCopyParams.srcImageFormat = depthFormat; - m_pDriver->GetDebugManager()->PixelHistoryCopyPixel( - cmd, depthCopyParams, offset + offsetof(struct PixelHistoryValue, depth)); + CopyImagePixel(cmd, depthCopyParams, offset + offsetof(struct PixelHistoryValue, depth)); } } @@ -1830,17 +1931,10 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback pipesIter[1] = pipes.shaderOutPipe; CopyPixelParams colourCopyParams = {}; - colourCopyParams.multisampled = false; // TODO: multisampled colourCopyParams.srcImage = m_CallbackInfo.subImage; colourCopyParams.srcImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // TODO: image layout colourCopyParams.srcImageFormat = VK_FORMAT_R32G32B32A32_SFLOAT; - colourCopyParams.imageOffset.x = int32_t(m_CallbackInfo.x); - colourCopyParams.imageOffset.y = int32_t(m_CallbackInfo.y); - colourCopyParams.imageOffset.z = 0; - colourCopyParams.dstBuffer = m_CallbackInfo.dstBuffer; - colourCopyParams.slice = m_CallbackInfo.targetSubresource.slice; - colourCopyParams.mipLevel = m_CallbackInfo.targetSubresource.mip; const VulkanCreationInfo::Pipeline &p = m_pDriver->GetDebugManager()->GetPipelineInfo(prevState.graphics.pipeline); @@ -1916,11 +2010,11 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback depthCopyParams.srcImage = m_CallbackInfo.stencilImage; depthCopyParams.srcImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthCopyParams.srcImageFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; - m_pDriver->GetDebugManager()->PixelHistoryCopyPixel( - cmd, depthCopyParams, storeOffset + offsetof(struct PixelHistoryValue, depth)); + CopyImagePixel(cmd, depthCopyParams, + storeOffset + offsetof(struct PixelHistoryValue, depth)); } } - m_pDriver->GetDebugManager()->PixelHistoryCopyPixel(cmd, colourCopyParams, storeOffset); + CopyImagePixel(cmd, colourCopyParams, storeOffset); } } @@ -1971,9 +2065,8 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback drawcall->vertexOffset, drawcall->instanceOffset); state.EndRenderPass(cmd); - m_pDriver->GetDebugManager()->PixelHistoryCopyPixel( - cmd, colourCopyParams, (fragsProcessed + f) * sizeof(PerFragmentInfo) + - offsetof(struct PerFragmentInfo, postMod)); + CopyImagePixel(cmd, colourCopyParams, (fragsProcessed + f) * sizeof(PerFragmentInfo) + + offsetof(struct PerFragmentInfo, postMod)); if(depthImage != VK_NULL_HANDLE) { @@ -1982,10 +2075,9 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback depthCopyParams.srcImage = depthImage; depthCopyParams.srcImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthCopyParams.srcImageFormat = depthFormat; - m_pDriver->GetDebugManager()->PixelHistoryCopyPixel( - cmd, depthCopyParams, (fragsProcessed + f) * sizeof(PerFragmentInfo) + - offsetof(struct PerFragmentInfo, postMod) + - offsetof(struct PixelHistoryValue, depth)); + CopyImagePixel(cmd, depthCopyParams, (fragsProcessed + f) * sizeof(PerFragmentInfo) + + offsetof(struct PerFragmentInfo, postMod) + + offsetof(struct PixelHistoryValue, depth)); } } @@ -2342,13 +2434,23 @@ private: }; bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resources, - VkExtent3D extent, VkFormat format, - uint32_t numEvents) + VkImage targetImage, VkExtent3D extent, + VkFormat format, VkSampleCountFlagBits samples, + const Subresource &sub, uint32_t numEvents) { 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; + VkImageView targetImageView = VK_NULL_HANDLE; + VkDeviceMemory gpuMem; VkBuffer dstBuffer; @@ -2357,12 +2459,14 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou VkResult vkr; VkDevice dev = m_pDriver->GetDev(); + VkDeviceSize totalMemorySize = 0; + // 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.samples = samples; imgInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imgInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -2377,29 +2481,53 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &colorImage); RDCASSERTEQUAL(vkr, VK_SUCCESS); - VkImage wrappedColorImage = colorImage; - ImageState colorImageState = ImageState(wrappedColorImage, ImageInfo(imgInfo), eFrameRef_None); + ImageState colorImageState = ImageState(colorImage, ImageInfo(imgInfo), eFrameRef_None); VkMemoryRequirements colorImageMrq = {0}; m_pDriver->vkGetImageMemoryRequirements(dev, colorImage, &colorImageMrq); + totalMemorySize = colorImageMrq.size; 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_TRANSFER_DST_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; vkr = m_pDriver->vkCreateImage(dev, &imgInfo, NULL, &stencilImage); RDCASSERTEQUAL(vkr, VK_SUCCESS); - VkImage wrappedStencilImage = stencilImage; - ImageState stencilImageState = ImageState(wrappedStencilImage, ImageInfo(imgInfo), eFrameRef_None); + ImageState stencilImageState = ImageState(stencilImage, ImageInfo(imgInfo), eFrameRef_None); VkMemoryRequirements stencilImageMrq = {0}; m_pDriver->vkGetImageMemoryRequirements(dev, stencilImage, &stencilImageMrq); - VkDeviceSize offset = AlignUp(colorImageMrq.size, stencilImageMrq.alignment); + 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, offset + stencilImageMrq.size, + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, totalMemorySize, m_pDriver->GetGPULocalMemoryIndex(colorImageMrq.memoryTypeBits), }; vkr = m_pDriver->vkAllocateMemory(m_Device, &allocInfo, NULL, &gpuMem); @@ -2427,6 +2555,55 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou vkr = m_pDriver->vkCreateImageView(m_Device, &viewInfo, NULL, &stencilImageView); 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) + viewInfo.format = VK_FORMAT_R8_UINT; + else if(bs == 2) + viewInfo.format = VK_FORMAT_R16_UINT; + else if(bs == 4) + viewInfo.format = VK_FORMAT_R32_UINT; + else if(bs == 8) + viewInfo.format = VK_FORMAT_R32G32_UINT; + else if(bs == 16) + viewInfo.format = VK_FORMAT_R32G32B32A32_UINT; + + if(viewInfo.format == VK_FORMAT_UNDEFINED) + { + 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_D32_SFLOAT_S8_UINT; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + viewInfo.subresourceRange.baseArrayLayer = 0; + + 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); + } + 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; @@ -2468,6 +2645,11 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou 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.gpuMem = gpuMem; resources.bufferMemory = bufferMemory; @@ -2476,6 +2658,28 @@ bool VulkanDebugManager::PixelHistorySetupResources(PixelHistoryResources &resou return true; } +void VulkanReplay::UpdatePixelHistoryDescriptor(VkImageView sourceView, VkImageView destView) +{ + 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 + + VkDescriptorImageInfo destdesc = {0}; + destdesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + destdesc.imageView = Unwrap(destView); + + 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}, + }; + + ObjDisp(m_pDriver->GetDev()) + ->UpdateDescriptorSets(Unwrap(m_pDriver->GetDev()), ARRAY_COUNT(writeSet), writeSet, 0, NULL); +} + bool VulkanDebugManager::PixelHistoryDestroyResources(const PixelHistoryResources &r) { VkDevice dev = m_pDriver->GetDev(); @@ -2489,6 +2693,14 @@ bool VulkanDebugManager::PixelHistoryDestroyResources(const PixelHistoryResource 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.dstBuffer != VK_NULL_HANDLE) m_pDriver->vkDestroyBuffer(dev, r.dstBuffer, NULL); if(r.bufferMemory != VK_NULL_HANDLE) @@ -2496,79 +2708,6 @@ bool VulkanDebugManager::PixelHistoryDestroyResources(const PixelHistoryResource return true; } -void VulkanDebugManager::PixelHistoryCopyPixel(VkCommandBuffer cmd, CopyPixelParams &p, size_t offset) -{ - rdcarray 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, p.mipLevel, p.slice, 1}; - regions.push_back(region); - aspectFlags = VkImageAspectFlags(VK_IMAGE_ASPECT_COLOR_BIT); - } - else if(p.stencilOnly) - { - region.imageSubresource = - VkImageSubresourceLayers{VK_IMAGE_ASPECT_STENCIL_BIT, p.mipLevel, p.slice, 1}; - aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - regions.push_back(region); - } - else - { - region.imageSubresource = - VkImageSubresourceLayers{VK_IMAGE_ASPECT_DEPTH_BIT, p.mipLevel, p.slice, 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(WrappedVulkan *vk, uint32_t poolSize, VkQueryPool *pQueryPool) { VkDevice dev = vk->GetDev(); @@ -2708,15 +2847,8 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even if(imginfo.format == VK_FORMAT_UNDEFINED) return history; - uint32_t mip = sub.mip; - uint32_t slice = sub.slice; uint32_t sampleIdx = sub.sample; - // TODO: figure out correct aspect. - VkImageLayout imgLayout = - GetDebugManager()->GetImageLayout(target, VK_IMAGE_ASPECT_COLOR_BIT, mip, slice); - RDCASSERTNOTEQUAL(imgLayout, VK_IMAGE_LAYOUT_UNDEFINED); - // TODO: use the given type hint for typeless textures SCOPED_TIMER("VkDebugManager::PixelHistory"); @@ -2737,17 +2869,24 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even CreateOcclusionPool(m_pDriver, (uint32_t)events.size(), &occlusionPool); PixelHistoryResources resources = {}; - GetDebugManager()->PixelHistorySetupResources(resources, imginfo.extent, imginfo.format, + // TODO: perhaps should do this after making an occlusion query, since we will + // get a smaller subset of events that passed the occlusion query. + VkImage targetImage = GetResourceManager()->GetCurrentHandle(target); + GetDebugManager()->PixelHistorySetupResources(resources, targetImage, imginfo.extent, + imginfo.format, imginfo.samples, sub, (uint32_t)events.size()); + if(multisampled) + UpdatePixelHistoryDescriptor(resources.targetImageView, resources.stagingImageView); PixelHistoryShaderCache *shaderCache = new PixelHistoryShaderCache(m_pDriver); - VkImage targetImage = GetResourceManager()->GetCurrentHandle(target); + PixelHistoryCallbackInfo callbackInfo = {}; callbackInfo.targetImage = targetImage; callbackInfo.targetImageFormat = imginfo.format; callbackInfo.layers = imginfo.arrayLayers; callbackInfo.mipLevels = imginfo.mipLevels; callbackInfo.samples = imginfo.samples; + callbackInfo.extent = imginfo.extent; callbackInfo.targetSubresource = sub; callbackInfo.x = x; callbackInfo.y = y; @@ -2757,6 +2896,8 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even callbackInfo.stencilImage = resources.stencilImage; callbackInfo.stencilImageView = resources.stencilImageView; 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); diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 9f0e24a28..cd004cfb6 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -2795,6 +2795,13 @@ rdcarray VulkanReplay::GetUsage(ResourceId id) return m_pDriver->GetUsage(id); } +void VulkanReplay::CopyPixelForPixelHistory(VkCommandBuffer cmd, VkExtent3D extent, uint32_t sample, + VkFormat fmt) +{ + m_pDriver->GetDebugManager()->CopyTex2DMSPixel(cmd, m_PixelHistory.MSCopyDescSet, extent, sample, + fmt); +} + void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms, bytebuf &data) { diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index 74ab70259..388b3975a 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -319,6 +319,7 @@ 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 InitPostVSBuffers(uint32_t eventId); void InitPostVSBuffers(uint32_t eventId, VulkanRenderState &state); @@ -410,6 +411,9 @@ public: void SetDriverInformation(const VkPhysicalDeviceProperties &props); AMDCounters *GetAMDCounters() { return m_pAMDCounters; } + void CopyPixelForPixelHistory(VkCommandBuffer cmd, VkExtent3D extent, uint32_t sample, + VkFormat fmt); + private: void FetchShaderFeedback(uint32_t eventId); void ClearFeedbackCache(); @@ -653,6 +657,15 @@ private: VkRenderPass RP = VK_NULL_HANDLE; } m_PixelPick; + struct PixelHistory + { + void Init(WrappedVulkan *driver, VkDescriptorPool descriptorPool); + void Destroy(WrappedVulkan *driver); + + VkDescriptorSetLayout MSCopyDescSetLayout = VK_NULL_HANDLE; + VkDescriptorSet MSCopyDescSet = VK_NULL_HANDLE; + } m_PixelHistory; + struct HistogramMinMax { void Init(WrappedVulkan *driver, VkDescriptorPool descriptorPool); diff --git a/util/test/demos/vk/vk_pixel_history_test.cpp b/util/test/demos/vk/vk_pixel_history_test.cpp index a34fb7ee9..979bf33a4 100644 --- a/util/test/demos/vk/vk_pixel_history_test.cpp +++ b/util/test/demos/vk/vk_pixel_history_test.cpp @@ -74,18 +74,32 @@ void main() )EOSHADER"; - std::string whitepixel = R"EOSHADER( + std::string mspixel = R"EOSHADER( #version 420 core layout(location = 0, index = 0) out vec4 Color; void main() { - Color = vec4(1,1,1,1); + if (gl_SampleID == 0) + Color = vec4(1, 0, 0, 1); + else if (gl_SampleID == 1) + Color = vec4(0, 0, 1, 1); + else if (gl_SampleID == 2) + Color = vec4(0, 1, 1, 1); + else if (gl_SampleID == 3) + Color = vec4(1, 1, 1, 1); } )EOSHADER"; + void Prepare(int argc, char **argv) + { + features.sampleRateShading = true; + + VulkanGraphicsTest::Prepare(argc, argv); + } + int main() { optDevExts.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); @@ -287,6 +301,30 @@ void main() subrp, {subview}, {mainWindow->scissor.extent.width / 4, mainWindow->scissor.extent.height / 4})); + renderPassCreateInfo.attachments[0].samples = VK_SAMPLE_COUNT_4_BIT; + + VkRenderPass submsrp = createRenderPass(renderPassCreateInfo); + + pipeCreateInfo.stages[1] = + CompileShaderModule(mspixel, ShaderLang::glsl, ShaderStage::frag, "main"); + + pipeCreateInfo.renderPass = submsrp; + pipeCreateInfo.multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT; + VkPipeline mspipe = createGraphicsPipeline(pipeCreateInfo); + + AllocatedImage submsimg( + this, vkh::ImageCreateInfo(mainWindow->scissor.extent.width, + mainWindow->scissor.extent.height, 0, mainWindow->format, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 1, 4, VK_SAMPLE_COUNT_4_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); + + VkImageView submsview = createImageView(vkh::ImageViewCreateInfo( + submsimg.image, VK_IMAGE_VIEW_TYPE_2D, mainWindow->format, {}, + vkh::ImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 2, 1))); + + VkFramebuffer submsfb = createFramebuffer(vkh::FramebufferCreateInfo( + submsrp, {submsview}, {mainWindow->scissor.extent.width, mainWindow->scissor.extent.height})); + while(Running()) { VkCommandBuffer cmd = GetCommandBuffer(); @@ -349,6 +387,20 @@ void main() vkCmdEndRenderPass(cmd); + { + setMarker(cmd, "Multisampled: begin renderpass"); + vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(submsrp, submsfb, mainWindow->scissor, + {vkh::ClearValue(0.f, 1.0f, 0.f, 1.0f)}), + VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, mspipe); + + setMarker(cmd, "Multisampled: test"); + vkCmdDraw(cmd, 6, 1, 3, 0); + + vkCmdEndRenderPass(cmd); + } + v = mainWindow->viewport; v.width /= 4.0f; v.height /= 4.0f; @@ -403,7 +455,6 @@ void main() FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); vkEndCommandBuffer(cmd); - Submit(0, 1, {cmd}); Present(); diff --git a/util/test/tests/Vulkan/Vk_Pixel_History.py b/util/test/tests/Vulkan/Vk_Pixel_History.py index dde312052..84db3e3e2 100644 --- a/util/test/tests/Vulkan/Vk_Pixel_History.py +++ b/util/test/tests/Vulkan/Vk_Pixel_History.py @@ -26,6 +26,7 @@ class VK_Pixel_History(rdtest.TestCase): return self.primary_test() + self.multisampled_image_test() self.secondary_cmd_test() def primary_test(self): @@ -101,6 +102,42 @@ class VK_Pixel_History(rdtest.TestCase): self.check_events(events, modifs, False) self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) + def multisampled_image_test(self): + test_marker: rd.DrawcallDescription = self.find_draw("Multisampled: test") + draw_eid = test_marker.next.eventId + self.controller.SetFrameEvent(draw_eid, True) + + pipe: rd.PipeState = self.controller.GetPipelineState() + rt: rd.BoundResource = pipe.GetOutputTargets()[0] + sub = rd.Subresource() + tex = rt.resourceId + tex_details = self.get_texture(tex) + if tex_details.arraysize > 1: + sub.slice = rt.firstSlice + + beg_renderpass_eid = self.find_draw("Multisampled: begin renderpass").next.eventId + + x, y = 100, 200 + 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)]], + ] + self.check_events(events, modifs, True) + self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) + + sub.sample = 2 + 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, 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) + def secondary_cmd_test(self): secondary_marker: rd.DrawcallDescription = self.find_draw("Secondary: red and blue") self.controller.SetFrameEvent(secondary_marker.next.eventId, True)