Vk Pixel History: MSAA depth/stencil copy, shader out

Use a separate compute shader module for MSAA copy, and output
directly into the destination buffer instead of creating
staging resources.

Support case where there is no depth stencil attachment to get post mod
values in per fragment reporting. Previously used the original
framebuffer that might not have had depth/stencil view, so couldn't
count the fragments. Now use the sub image.

To get the post mod color, we need to blend with the premod color, so
we use vkCmdCopyImage to copy from the original image.
This commit is contained in:
Aliya Pazylbekova
2020-05-06 19:35:25 +01:00
committed by Baldur Karlsson
parent 8a4f0a111d
commit 41b911d1d0
16 changed files with 435 additions and 275 deletions
+1
View File
@@ -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
+1
View File
@@ -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);
@@ -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);
}
}
+1
View File
@@ -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"
+3 -2
View File
@@ -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
//
+10 -1
View File
@@ -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);
}
-2
View File
@@ -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; }
@@ -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), &params);
// 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)
{
+305 -239
View File
@@ -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<VkBufferImageCopy> 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, &region);
// 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<VkBufferImageCopy> 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<ResourceId> &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<uint32_t, uint32_t> eventFragments)
const std::map<uint32_t, uint32_t> &eventFragments,
const std::map<uint32_t, ModificationValue> &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<ResourceId> &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<uint32_t, uint32_t> m_EventIndices;
// Number of fragments for each event.
std::map<uint32_t, uint32_t> m_EventFragments;
// Pre-modification values for events to initialize attachments to,
// so that we can get blended post-modification values.
std::map<uint32_t, ModificationValue> 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<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> 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<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> 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<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> even
if(events[ev].view != ResourceId())
{
// TODO
// TODO: Check that the slice and mip matches.
}
if(directWrite || clear)
@@ -2998,6 +3058,7 @@ rdcarray<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> even
RDCASSERTEQUAL(vkr, VK_SUCCESS);
std::map<uint32_t, uint32_t> eventsWithFrags;
std::map<uint32_t, ModificationValue> eventPremods;
ResourceFormat fmt = MakeResourceFormat(imginfo.format);
for(size_t h = 0; h < history.size();)
@@ -3019,8 +3080,8 @@ rdcarray<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> 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<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> 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<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> 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<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> 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<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> 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<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> 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;
}
}
+25 -4
View File
@@ -2795,11 +2795,32 @@ rdcarray<EventUsage> 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,
+7 -3
View File
@@ -322,7 +322,8 @@ public:
float *maxval);
bool GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval,
float maxval, bool channels[4], rdcarray<uint32_t> &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
@@ -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),
@@ -54,6 +54,7 @@ enum class BuiltinShader
TexRemapFloat,
TexRemapUInt,
TexRemapSInt,
PixelHistoryMSCopyCS,
PixelHistoryPrimIDFS,
ShaderDebugSampleVS,
Count,
+1
View File
@@ -599,6 +599,7 @@
<None Include="data\glsl\minmaxresult.comp" />
<None Include="data\glsl\minmaxtile.comp" />
<None Include="data\glsl\ms2array.comp" />
<None Include="data\glsl\pixelhistory_mscopy.comp" />
<None Include="data\glsl\pixelhistory_primid.frag" />
<None Include="data\glsl\quadresolve.frag" />
<None Include="data\glsl\quadwrite.frag" />
@@ -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)
+5 -3
View File
@@ -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)