Work around NV issue with dynamic state setting & rebinding pipeline

This commit is contained in:
baldurk committed 2023-08-31 10:22:46 +01:00
1 parent 2d41648d4d
commit 1d1295b17e
5 files changed
+55 -1

No files matched your search

+11
View File
@@ -1057,6 +1057,17 @@ VkDriverInfo::VkDriverInfo(const VkPhysicalDeviceProperties &physProps,
RDCLOG("Enabling NV texel fetch workaround - update to a newer driver for fix");
texelFetchBrokenDriver = true;
}
// this isn't exactly when the root problem started happening, but it is when it started
// happening in a way that was easy to notice. In this version NV applied a optimisation
// to not re-set static pipeline state when a renderpass was begun, which was previously
// hiding the issue by conservatively re-setting the state.
if(Major() > 532)
{
if(active)
RDCLOG("Enabling NV workaround for static pipeline force-bind to preserve state");
nvidiaStaticPipelineRebindStates = true;
}
}
if(driverProps.driverID == VK_DRIVER_ID_AMD_PROPRIETARY ||
+8
View File
@@ -285,6 +285,13 @@ public:
// on Intel, occlusion queries are broken unless the shader has some effects. When we don't want
// it to have visible effects during pixel history we have to insert some manual side-effects
bool IntelBrokenOcclusionQueries() const { return intelBrokenOcclusionQueries; }
// on NV binding a static pipeline does not re-set static state which may have been perturbed by
// dynamic state setting, if the previous bound pipeline was identical.
// to work around this, whenever we are setting state and we do not have a pipeline to bind, we
// bind a dummy pipeline to ensure the pipeline always changes when we are setting dynamic state.
// If we do have a pipeline to bind, we should never be perturbing dynamic state in between static
// pipeline binds.
bool NVStaticPipelineRebindStates() const { return nvidiaStaticPipelineRebindStates; }
private:
GPUVendor m_Vendor;
@@ -299,6 +306,7 @@ private:
bool qualcommDrefNon2DCompileCrash = false;
bool qualcommLineWidthCrash = false;
bool intelBrokenOcclusionQueries = false;
bool nvidiaStaticPipelineRebindStates = false;
};
enum
+27 -1
View File
@@ -98,7 +98,8 @@ static void create(WrappedVulkan *driver, const char *objName, const int line,
}
pipeLayoutInfo.pSetLayouts = &setLayout;
pipeLayoutInfo.setLayoutCount = 1;
if(setLayout != VK_NULL_HANDLE)
pipeLayoutInfo.setLayoutCount = 1;
VkResult vkr = driver->vkCreatePipelineLayout(driver->GetDev(), &pipeLayoutInfo, NULL, pipeLayout);
if(vkr != VK_SUCCESS)
@@ -708,6 +709,28 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver)
if(RenderDoc::Inst().IsReplayApp())
{
CREATE_OBJECT(m_DummyPipelineLayout, VK_NULL_HANDLE, 0);
ConciseGraphicsPipeline dummyPipeInfo = {
VK_NULL_HANDLE,
m_DummyPipelineLayout,
shaderCache->GetBuiltinModule(BuiltinShader::BlitVS),
shaderCache->GetBuiltinModule(BuiltinShader::FixedColFS),
{},
VK_SAMPLE_COUNT_1_BIT,
false, // sampleRateShading
false, // depthEnable
false, // stencilEnable
VK_STENCIL_OP_REPLACE,
false, // colourOutput
false, // blendEnable
VK_BLEND_FACTOR_ONE,
VK_BLEND_FACTOR_ZERO,
0x0, // writeMask
};
CREATE_OBJECT(m_DummyPipeline, dummyPipeInfo);
VkDescriptorPoolSize descPoolTypes[] = {
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, ARRAY_COUNT(m_DiscardSet)},
};
@@ -803,6 +826,9 @@ VulkanDebugManager::~VulkanDebugManager()
m_pDriver->vkDestroyPipeline(dev, m_MS2BufferPipe, NULL);
m_pDriver->vkDestroyPipeline(dev, m_DepthMS2BufferPipe, NULL);
m_pDriver->vkDestroyPipelineLayout(dev, m_DummyPipelineLayout, NULL);
m_pDriver->vkDestroyPipeline(dev, m_DummyPipeline, NULL);
m_pDriver->vkDestroyDescriptorPool(dev, m_DiscardPool, NULL);
m_pDriver->vkDestroyPipelineLayout(dev, m_DiscardLayout, NULL);
m_pDriver->vkDestroyDescriptorSetLayout(dev, m_DiscardSetLayout, NULL);
+5
View File
@@ -80,6 +80,7 @@ public:
VkDeviceMemory GetReadbackMemory() { return m_ReadbackWindow.mem; }
VkPipelineCache GetPipelineCache() { return m_PipelineCache; }
VkPipeline GetCustomPipeline() { return m_Custom.TexPipeline; }
VkPipeline GetDummyPipeline() { return m_DummyPipeline; }
VkImage GetCustomTexture() { return m_Custom.TexImg; }
VkFramebuffer GetCustomFramebuffer() { return m_Custom.TexFB; }
VkRenderPass GetCustomRenderpass() { return m_Custom.TexRP; }
@@ -145,6 +146,10 @@ private:
VkImage m_DummyStencilImage = {VK_NULL_HANDLE};
VkImageView m_DummyStencilView = {VK_NULL_HANDLE};
// dummy pipeline
VkPipelineLayout m_DummyPipelineLayout;
VkPipeline m_DummyPipeline;
// one per depth/stencil output format, per sample count
VkPipeline m_DepthArray2MSPipe[7][4] = {{VK_NULL_HANDLE}};
+4
View File
@@ -326,6 +326,10 @@ void VulkanRenderState::BindPipeline(WrappedVulkan *vk, VkCommandBuffer cmd,
}
else if(binding == BindInitial)
{
if(vk->GetDriverInfo().NVStaticPipelineRebindStates())
ObjDisp(cmd)->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(vk->GetDebugManager()->GetDummyPipeline()));
// if we're setting up a partial command buffer, bind all dynamic state we have. This will
// then get overridden, but we need it in case a pipeline expects to inherit some dynamic
// state from earlier in the command buffer but there's no pipeline bound yet.