Create separate pipeline and dummy images for depth-format, for DRefs

* Any pipeline that uses DRef on images (without descriptor indexing at least,
  which we don't assume) must be passed depth-formatted images. This includes
  the dummy images we bind to other slots.
* At the same time we limit depth textures to just 1D, 2D, 2DMS - ignoring 3D
  and Cube.
This commit is contained in:
baldurk
2022-02-08 18:07:39 +00:00
parent f0428e6801
commit b094c45d42
3 changed files with 114 additions and 40 deletions
+33 -7
View File
@@ -3278,7 +3278,8 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
int index = 0;
// we pick RGBA8 formats to be guaranteed they will be supported
VkFormat formats[] = {VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_SINT};
VkFormat formats[] = {VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UINT,
VK_FORMAT_R8G8B8A8_SINT, VK_FORMAT_D16_UNORM};
VkImageType types[] = {VK_IMAGE_TYPE_1D, VK_IMAGE_TYPE_2D, VK_IMAGE_TYPE_3D, VK_IMAGE_TYPE_2D};
VkImageViewType viewtypes[] = {
VK_IMAGE_VIEW_TYPE_1D_ARRAY, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_VIEW_TYPE_3D,
@@ -3311,6 +3312,10 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
{
for(size_t type = 0; type < ARRAY_COUNT(types); type++)
{
// don't create 3D depth
if(formats[fmt] == VK_FORMAT_D16_UNORM && types[type] == VK_IMAGE_TYPE_3D)
continue;
// create 1x1 image of the right size
VkImageCreateInfo imInfo = {
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
@@ -3330,8 +3335,8 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
VK_IMAGE_LAYOUT_UNDEFINED,
};
// make the 2D image cube-compatible
if(type == 1)
// make the 2D image cube-compatible for non-depth
if(type == 1 && formats[fmt] != VK_FORMAT_D16_UNORM)
{
imInfo.arrayLayers = 6;
imInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
@@ -3353,6 +3358,10 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
alloc.offs);
driver->CheckVkResult(vkr);
// don't add dummy writes/infos for depth, we just want the images and views
if(formats[fmt] == VK_FORMAT_D16_UNORM)
continue;
// fill out the descriptor set write to the write binding - set will be filled out
// on demand when we're actually using these writes.
DummyWrites[index].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -3395,6 +3404,8 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
DummyInfos[index + 1].sampler = Unwrap(DummySampler);
DummyInfos[index + 1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
RDCASSERT(index + 1 < (int)ARRAY_COUNT(DummyInfos));
// align up for the dummy buffer
{
VkBufferCreateInfo bufInfo = {
@@ -3433,6 +3444,10 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
cube = true;
}
// don't create 3D depth or cubes
if(formats[fmt] == VK_FORMAT_D16_UNORM && (viewtypes[type] == VK_IMAGE_VIEW_TYPE_3D || cube))
continue;
VkImageViewCreateInfo viewInfo = {
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
NULL,
@@ -3447,6 +3462,9 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
},
};
if(formats[fmt] == VK_FORMAT_D16_UNORM)
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if(cube)
viewInfo.subresourceRange.layerCount = 6;
@@ -3461,10 +3479,6 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
if(cube)
continue;
RDCASSERT((size_t)index < ARRAY_COUNT(DummyInfos), index);
DummyInfos[index].imageView = Unwrap(DummyImageViews[fmt][type]);
// need to update image layout into valid state
VkImageMemoryBarrier barrier = {
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
@@ -3479,8 +3493,18 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS},
};
if(formats[fmt] == VK_FORMAT_D16_UNORM)
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
DoPipelineBarrier(cmd, 1, &barrier);
if(formats[fmt] == VK_FORMAT_D16_UNORM)
continue;
RDCASSERT((size_t)index < ARRAY_COUNT(DummyInfos), index);
DummyInfos[index].imageView = Unwrap(DummyImageViews[fmt][type]);
index++;
}
}
@@ -3489,6 +3513,8 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
DummyInfos[index].imageView = DummyInfos[1].imageView;
DummyInfos[index + 1].imageView = DummyInfos[1].imageView;
RDCASSERT(index + 1 < (int)ARRAY_COUNT(DummyInfos));
if(DummyBuffer != VK_NULL_HANDLE)
{
VkFormat bufViewTypes[] = {
+7 -7
View File
@@ -246,10 +246,10 @@ struct ShaderDebugData
VkFramebuffer Framebuffer = VK_NULL_HANDLE;
VkRenderPass RenderPass = VK_NULL_HANDLE;
VkDescriptorImageInfo DummyImageInfos[3][6] = {};
VkWriteDescriptorSet DummyWrites[3][7] = {};
VkDescriptorImageInfo DummyImageInfos[4][6] = {};
VkWriteDescriptorSet DummyWrites[4][7] = {};
VkShaderModule Module[6] = {};
VkShaderModule Module[7] = {};
std::map<uint32_t, VkPipeline> m_Pipelines;
@@ -590,16 +590,16 @@ private:
// images and views are re-used elsewhere in replay, so index them sensibly
//
// [float/uint/sint][1D/2D/3D/MS/Cube]
// [float/uint/sint/depth][1D/2D/3D/MS/Cube]
//
// the cube image is re-used from the 2D one, so only the view is valid
VkImage DummyImages[3][5] = {};
VkImageView DummyImageViews[3][5] = {};
VkImage DummyImages[4][5] = {};
VkImageView DummyImageViews[4][5] = {};
VkWriteDescriptorSet DummyWrites[14] = {};
VkDescriptorImageInfo DummyInfos[14] = {};
VkSampler DummySampler = VK_NULL_HANDLE;
VkBuffer DummyBuffer = VK_NULL_HANDLE;
VkBufferView DummyBufferView[3] = {};
VkBufferView DummyBufferView[4] = {};
std::map<ResourceId, TextureDisplayViews> TextureViews;
+74 -26
View File
@@ -677,6 +677,8 @@ public:
const VulkanCreationInfo::ImageView &viewProps = m_Creation.m_ImageView[GetResID(view)];
const VulkanCreationInfo::Image &imageProps = m_Creation.m_Image[viewProps.image];
const bool depthTex = IsDepthOrStencilFormat(viewProps.format);
VkDevice dev = m_pDriver->GetDev();
// how many co-ordinates should there be
@@ -1224,7 +1226,7 @@ public:
uniformParams.offset.x, uniformParams.offset.y, uniformParams.offset.z));
}
VkPipeline pipe = MakePipe(constParams, 32, uintTex, sintTex);
VkPipeline pipe = MakePipe(constParams, 32, depthTex, uintTex, sintTex);
if(pipe == VK_NULL_HANDLE)
{
@@ -1266,13 +1268,36 @@ public:
}
// reset descriptor sets to dummy state
uint32_t resetIndex = 0;
if(uintTex)
resetIndex = 1;
else if(sintTex)
resetIndex = 2;
ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(m_DebugData.DummyWrites[resetIndex]),
m_DebugData.DummyWrites[resetIndex], 0, NULL);
if(depthTex)
{
// for depth not all descriptors are valid, in particular we skip 3D and cube
uint32_t resetIndex = 3;
rdcarray<VkWriteDescriptorSet> writes;
for(size_t i = 0; i < ARRAY_COUNT(m_DebugData.DummyWrites[resetIndex]); i++)
{
if(m_DebugData.DummyWrites[resetIndex][i].dstBinding != (uint32_t)ShaderDebugBind::Tex3D &&
m_DebugData.DummyWrites[resetIndex][i].dstBinding != (uint32_t)ShaderDebugBind::TexCube &&
m_DebugData.DummyWrites[resetIndex][i].dstBinding != (uint32_t)ShaderDebugBind::Buffer)
writes.push_back(m_DebugData.DummyWrites[resetIndex][i]);
}
ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), (uint32_t)writes.count(), writes.data(), 0,
NULL);
}
else
{
uint32_t resetIndex = 0;
if(uintTex)
resetIndex = 1;
else if(sintTex)
resetIndex = 2;
ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev),
ARRAY_COUNT(m_DebugData.DummyWrites[resetIndex]),
m_DebugData.DummyWrites[resetIndex], 0, NULL);
}
// overwrite with our data
ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), sampler != VK_NULL_HANDLE ? 3 : 2, writeSets, 0,
@@ -1386,7 +1411,7 @@ public:
ShaderConstParameters pipeParams = {};
pipeParams.operation = (uint32_t)rdcspv::Op::ExtInst;
m_DebugData.MathPipe[floatSizeIdx] =
MakePipe(pipeParams, VarTypeByteSize(params[0].type) * 8, false, false);
MakePipe(pipeParams, VarTypeByteSize(params[0].type) * 8, false, false, false);
if(m_DebugData.MathPipe[floatSizeIdx] == VK_NULL_HANDLE)
{
@@ -1725,8 +1750,8 @@ private:
return data;
}
VkPipeline MakePipe(const ShaderConstParameters &params, uint32_t floatBitSize, bool uintTex,
bool sintTex)
VkPipeline MakePipe(const ShaderConstParameters &params, uint32_t floatBitSize, bool depthTex,
bool uintTex, bool sintTex)
{
VkSpecializationMapEntry specMaps[sizeof(params) / sizeof(uint32_t)];
for(size_t i = 0; i < ARRAY_COUNT(specMaps); i++)
@@ -1743,18 +1768,20 @@ private:
specInfo.pMapEntries = specMaps;
uint32_t shaderIndex = 0;
if(uintTex)
if(depthTex)
shaderIndex = 1;
else if(sintTex)
if(uintTex)
shaderIndex = 2;
else if(sintTex)
shaderIndex = 3;
if(params.operation == (uint32_t)rdcspv::Op::ExtInst)
{
shaderIndex = 3;
shaderIndex = 4;
if(floatBitSize == 16)
shaderIndex = 4;
else if(floatBitSize == 64)
shaderIndex = 5;
else if(floatBitSize == 64)
shaderIndex = 6;
}
if(m_DebugData.Module[shaderIndex] == VK_NULL_HANDLE)
@@ -1769,7 +1796,7 @@ private:
{
RDCASSERTMSG("Assume sampling happens with 32-bit float inputs", floatBitSize == 32,
floatBitSize);
GenerateSamplingShaderModule(spirv, uintTex, sintTex);
GenerateSamplingShaderModule(spirv, depthTex, uintTex, sintTex);
}
VkShaderModuleCreateInfo moduleCreateInfo = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
@@ -1781,8 +1808,9 @@ private:
m_pDriver->CheckVkResult(vkr);
const char *filename[] = {
"/debug_psgather_float.spv", "/debug_psgather_uint.spv", "/debug_psgather_sint.spv",
"/debug_psmath32.spv", "/debug_psmath16.spv", "/debug_psmath64.spv",
"/debug_psgather_float.spv", "/debug_psgather_depth.spv", "/debug_psgather_uint.spv",
"/debug_psgather_sint.spv", "/debug_psmath32.spv", "/debug_psmath16.spv",
"/debug_psmath64.spv",
};
if(!Vulkan_Debug_PSDebugDumpDirPath().empty())
@@ -2173,7 +2201,8 @@ private:
editor.AddFunction(func);
}
void GenerateSamplingShaderModule(rdcarray<uint32_t> &spirv, bool uintTex, bool sintTex)
void GenerateSamplingShaderModule(rdcarray<uint32_t> &spirv, bool depthTex, bool uintTex,
bool sintTex)
{
// this could be done as a glsl shader, but glslang has some bugs compiling the specialisation
// constants, so we generate it by hand - which isn't too hard
@@ -2359,6 +2388,9 @@ private:
{
rdcspv::StorageClass storageClass = rdcspv::StorageClass::UniformConstant;
if(depthTex && (i == (size_t)ShaderDebugBind::Tex3D || i == (size_t)ShaderDebugBind::TexCube))
continue;
if(i == (size_t)ShaderDebugBind::Constants)
storageClass = rdcspv::StorageClass::Uniform;
@@ -2374,9 +2406,11 @@ private:
editor.SetName(bindVars[(size_t)ShaderDebugBind::Tex1D], "Tex1D");
editor.SetName(bindVars[(size_t)ShaderDebugBind::Tex2D], "Tex2D");
editor.SetName(bindVars[(size_t)ShaderDebugBind::Tex3D], "Tex3D");
if(!depthTex)
editor.SetName(bindVars[(size_t)ShaderDebugBind::Tex3D], "Tex3D");
editor.SetName(bindVars[(size_t)ShaderDebugBind::Tex2DMS], "Tex2DMS");
editor.SetName(bindVars[(size_t)ShaderDebugBind::TexCube], "TexCube");
if(!depthTex)
editor.SetName(bindVars[(size_t)ShaderDebugBind::TexCube], "TexCube");
editor.SetName(bindVars[(size_t)ShaderDebugBind::Buffer], "Buffer");
editor.SetName(bindVars[(size_t)ShaderDebugBind::Sampler], "Sampler");
editor.SetName(bindVars[(size_t)ShaderDebugBind::Constants], "CBuffer");
@@ -2545,6 +2579,9 @@ private:
if(i == sampIdx || i == (uint32_t)ShaderDebugBind::Constants)
continue;
if(depthTex && (i == (size_t)ShaderDebugBind::Tex3D || i == (size_t)ShaderDebugBind::TexCube))
continue;
// can't fetch from cubemaps
if(i != (uint32_t)ShaderDebugBind::TexCube)
{
@@ -2659,14 +2696,22 @@ private:
cases.add(rdcspv::OpBranch(breakLabel));
}
bool emitDRef = true;
// on Qualcomm we only emit Dref instructions against 2D textures, otherwise the compiler may
// crash.
if(m_pDriver->GetDriverInfo().QualcommDrefNon2DCompileCrash())
emitDRef = (i == (uint32_t)ShaderDebugBind::Tex2D);
depthTex &= (i == (uint32_t)ShaderDebugBind::Tex2D);
if(emitDRef)
// VUID-StandaloneSpirv-OpImage-04777
// OpImage*Dref must not consume an image whose Dim is 3D
// also skip cube
if(i == (uint32_t)ShaderDebugBind::Tex3D || i == (uint32_t)ShaderDebugBind::TexCube)
depthTex = false;
// don't emit dref's for uint/sint textures
if(uintTex || sintTex)
depthTex = false;
if(depthTex)
{
for(rdcspv::Op op :
{rdcspv::Op::ImageSampleDrefExplicitLod, rdcspv::Op::ImageSampleDrefImplicitLod})
@@ -2734,6 +2779,9 @@ private:
for(rdcspv::Op op : {rdcspv::Op::ImageGather, rdcspv::Op::ImageDrefGather})
{
if(op == rdcspv::Op::ImageDrefGather && !depthTex)
continue;
rdcspv::Id label = editor.MakeId();
targets.push_back({(uint32_t)op * 10 + i, label});