GS/Vulkan: Make provoking vertex consistent across pipelines

This commit is contained in:
Stenzek 2023-04-15 15:10:21 +10:00 committed by refractionpcsx2
parent 53c9021455
commit ab1d558420
1 changed files with 16 additions and 23 deletions

View File

@ -1529,6 +1529,15 @@ static void AddUtilityVertexAttributes(Vulkan::GraphicsPipelineBuilder& gpb)
gpb.SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
}
static void SetPipelineProvokingVertex(const GSDevice::FeatureSupport& features, Vulkan::GraphicsPipelineBuilder& gpb)
{
// We enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass.
// Normally we wouldn't enable it on the present/swap chain, but apparently the rule is it applies to the last
// pipeline bound before the render pass begun, and in this case, we can't bind null.
if (features.provoking_vertex_last)
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
}
VkShaderModule GSDeviceVK::GetUtilityVertexShader(const std::string& source, const char* replace_main = nullptr)
{
std::stringstream ss;
@ -1769,6 +1778,7 @@ bool GSDeviceVK::CompileConvertPipelines()
ScopedGuard vs_guard([&vs]() { Vulkan::Util::SafeDestroyShaderModule(vs); });
Vulkan::GraphicsPipelineBuilder gpb;
SetPipelineProvokingVertex(m_features, gpb);
AddUtilityVertexAttributes(gpb);
gpb.SetPipelineLayout(m_utility_pipeline_layout);
gpb.SetDynamicViewportAndScissorState();
@ -1777,10 +1787,6 @@ bool GSDeviceVK::CompileConvertPipelines()
gpb.SetNoBlendingState();
gpb.SetVertexShader(vs);
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
if (m_features.provoking_vertex_last)
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
for (ShaderConvert i = ShaderConvert::COPY; static_cast<int>(i) < static_cast<int>(ShaderConvert::Count);
i = static_cast<ShaderConvert>(static_cast<int>(i) + 1))
{
@ -1964,6 +1970,7 @@ bool GSDeviceVK::CompilePresentPipelines()
ScopedGuard vs_guard([&vs]() { Vulkan::Util::SafeDestroyShaderModule(vs); });
Vulkan::GraphicsPipelineBuilder gpb;
SetPipelineProvokingVertex(m_features, gpb);
AddUtilityVertexAttributes(gpb);
gpb.SetPipelineLayout(m_utility_pipeline_layout);
gpb.SetDynamicViewportAndScissorState();
@ -1975,10 +1982,6 @@ bool GSDeviceVK::CompilePresentPipelines()
gpb.SetNoStencilState();
gpb.SetRenderPass(m_swap_chain_render_pass, 0);
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
if (m_features.provoking_vertex_last)
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
for (PresentShader i = PresentShader::COPY; static_cast<int>(i) < static_cast<int>(PresentShader::Count);
i = static_cast<PresentShader>(static_cast<int>(i) + 1))
{
@ -2023,6 +2026,7 @@ bool GSDeviceVK::CompileInterlacePipelines()
ScopedGuard vs_guard([&vs]() { Vulkan::Util::SafeDestroyShaderModule(vs); });
Vulkan::GraphicsPipelineBuilder gpb;
SetPipelineProvokingVertex(m_features, gpb);
AddUtilityVertexAttributes(gpb);
gpb.SetPipelineLayout(m_utility_pipeline_layout);
gpb.SetDynamicViewportAndScissorState();
@ -2033,10 +2037,6 @@ bool GSDeviceVK::CompileInterlacePipelines()
gpb.SetRenderPass(rp, 0);
gpb.SetVertexShader(vs);
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
if (m_features.provoking_vertex_last)
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
for (int i = 0; i < static_cast<int>(m_interlace.size()); i++)
{
VkShaderModule ps = GetUtilityFragmentShader(*shader, StringUtil::StdStringFromFormat("ps_main%d", i).c_str());
@ -2077,6 +2077,7 @@ bool GSDeviceVK::CompileMergePipelines()
ScopedGuard vs_guard([&vs]() { Vulkan::Util::SafeDestroyShaderModule(vs); });
Vulkan::GraphicsPipelineBuilder gpb;
SetPipelineProvokingVertex(m_features, gpb);
AddUtilityVertexAttributes(gpb);
gpb.SetPipelineLayout(m_utility_pipeline_layout);
gpb.SetDynamicViewportAndScissorState();
@ -2086,10 +2087,6 @@ bool GSDeviceVK::CompileMergePipelines()
gpb.SetRenderPass(rp, 0);
gpb.SetVertexShader(vs);
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
if (m_features.provoking_vertex_last)
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
for (int i = 0; i < static_cast<int>(m_merge.size()); i++)
{
VkShaderModule ps = GetUtilityFragmentShader(*shader, StringUtil::StdStringFromFormat("ps_main%d", i).c_str());
@ -2119,6 +2116,7 @@ bool GSDeviceVK::CompilePostProcessingPipelines()
return false;
Vulkan::GraphicsPipelineBuilder gpb;
SetPipelineProvokingVertex(m_features, gpb);
AddUtilityVertexAttributes(gpb);
gpb.SetPipelineLayout(m_utility_pipeline_layout);
gpb.SetDynamicViewportAndScissorState();
@ -2128,10 +2126,6 @@ bool GSDeviceVK::CompilePostProcessingPipelines()
gpb.SetNoBlendingState();
gpb.SetRenderPass(rp, 0);
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
if (m_features.provoking_vertex_last)
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
{
std::optional<std::string> vshader = Host::ReadResourceFileToString("shaders/vulkan/convert.glsl");
if (!vshader)
@ -2267,6 +2261,7 @@ bool GSDeviceVK::CompileImGuiPipeline()
ScopedGuard ps_guard([&ps]() { Vulkan::Util::SafeDestroyShaderModule(ps); });
Vulkan::GraphicsPipelineBuilder gpb;
SetPipelineProvokingVertex(m_features, gpb);
gpb.SetPipelineLayout(m_utility_pipeline_layout);
gpb.SetRenderPass(m_swap_chain_render_pass, 0);
gpb.AddVertexBuffer(0, sizeof(ImDrawVert), VK_VERTEX_INPUT_RATE_VERTEX);
@ -2655,6 +2650,7 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p)
return VK_NULL_HANDLE;
Vulkan::GraphicsPipelineBuilder gpb;
SetPipelineProvokingVertex(m_features, gpb);
// Common state
gpb.SetPipelineLayout(m_tfx_pipeline_layout);
@ -2739,9 +2735,6 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p)
VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, p.cms.wrgba);
}
if (m_features.provoking_vertex_last)
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
// Tests have shown that it's faster to just enable rast order on the entire pass, rather than alternating
// between turning it on and off for different draws, and adding the required barrier between non-rast-order
// and rast-order draws.