GS/Vulkan: Use VK_EXT_provoking_vertex where supported

This commit is contained in:
Connor McLaughlin 2021-12-30 15:20:03 +10:00 committed by refractionpcsx2
parent bf389b94d6
commit 220c7c271b
7 changed files with 99 additions and 1 deletions

View File

@ -149,6 +149,9 @@ namespace Vulkan
m_multisample_state = {};
m_multisample_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
m_provoking_vertex = {};
m_provoking_vertex.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT;
// set defaults
SetNoCullRasterizationState();
SetNoDepthTestState();
@ -420,6 +423,13 @@ namespace Vulkan
m_ci.subpass = subpass;
}
void GraphicsPipelineBuilder::SetProvokingVertex(VkProvokingVertexModeEXT mode)
{
Util::AddPointerToChain(&m_rasterization_state, &m_provoking_vertex);
m_provoking_vertex.provokingVertexMode = mode;
}
SamplerBuilder::SamplerBuilder() { Clear(); }
void SamplerBuilder::Clear()

View File

@ -128,6 +128,8 @@ namespace Vulkan
void SetPipelineLayout(VkPipelineLayout layout);
void SetRenderPass(VkRenderPass render_pass, u32 subpass);
void SetProvokingVertex(VkProvokingVertexModeEXT mode);
private:
VkGraphicsPipelineCreateInfo m_ci;
std::array<VkPipelineShaderStageCreateInfo, MAX_SHADER_STAGES> m_shader_stages;
@ -152,6 +154,8 @@ namespace Vulkan
std::array<VkDynamicState, MAX_DYNAMIC_STATE> m_dynamic_state_values;
VkPipelineMultisampleStateCreateInfo m_multisample_state;
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT m_provoking_vertex;
};
class SamplerBuilder

View File

@ -458,6 +458,9 @@ namespace Vulkan
if (enable_surface && !SupportsExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true))
return false;
m_optional_extensions.vk_ext_provoking_vertex =
SupportsExtension(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, false);
return true;
}
@ -605,6 +608,15 @@ namespace Vulkan
device_info.ppEnabledLayerNames = layer_names;
}
// provoking vertex
VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
if (m_optional_extensions.vk_ext_provoking_vertex)
{
provoking_vertex_feature.provokingVertexLast = VK_TRUE;
Util::AddPointerToChain(&device_info, &provoking_vertex_feature);
}
VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device);
if (res != VK_SUCCESS)
{
@ -622,9 +634,39 @@ namespace Vulkan
{
vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue);
}
ProcessDeviceExtensions();
return true;
}
void Context::ProcessDeviceExtensions()
{
// advanced feature checks
if (vkGetPhysicalDeviceFeatures2)
{
VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
void** pNext = &features2.pNext;
// add in optional feature structs
if (m_optional_extensions.vk_ext_provoking_vertex)
{
*pNext = &provoking_vertex_features;
pNext = &provoking_vertex_features.pNext;
}
// query
vkGetPhysicalDeviceFeatures2(m_physical_device, &features2);
// confirm we actually support it
m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE);
}
Console.WriteLn("VK_EXT_provoking_vertex is %s",
m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported");
}
bool Context::CreateAllocator()
{
VmaAllocatorCreateInfo ci = {};
@ -1124,7 +1166,8 @@ namespace Vulkan
void Context::DeferBufferDestruction(VkBuffer object, VmaAllocation allocation)
{
FrameResources& resources = m_frame_resources[m_current_frame];
resources.cleanup_resources.push_back([this, object, allocation]() { vmaDestroyBuffer(m_allocator, object, allocation); });
resources.cleanup_resources.push_back(
[this, object, allocation]() { vmaDestroyBuffer(m_allocator, object, allocation); });
}
void Context::DeferBufferViewDestruction(VkBufferView object)

View File

@ -46,6 +46,11 @@ namespace Vulkan
TEXTURE_BUFFER_SIZE = 64 * 1024 * 1024,
};
struct OptionalExtensions
{
bool vk_ext_provoking_vertex : 1;
};
~Context();
// Determines if the Vulkan validation layer is available on the system.
@ -89,6 +94,7 @@ namespace Vulkan
__fi const VkPhysicalDeviceProperties& GetDeviceProperties() const { return m_device_properties; }
__fi const VkPhysicalDeviceFeatures& GetDeviceFeatures() const { return m_device_features; }
__fi const VkPhysicalDeviceLimits& GetDeviceLimits() const { return m_device_properties.limits; }
__fi const OptionalExtensions& GetOptionalExtensions() const { return m_optional_extensions; }
// Helpers for getting constants
__fi VkDeviceSize GetUniformBufferAlignment() const
@ -239,6 +245,7 @@ namespace Vulkan
bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer, const char** required_device_extensions,
u32 num_required_device_extensions, const char** required_device_layers, u32 num_required_device_layers,
const VkPhysicalDeviceFeatures* required_features);
void ProcessDeviceExtensions();
bool CreateAllocator();
void DestroyAllocator();
@ -323,6 +330,7 @@ namespace Vulkan
VkPhysicalDeviceFeatures m_device_features = {};
VkPhysicalDeviceProperties m_device_properties = {};
VkPhysicalDeviceMemoryProperties m_device_memory_properties = {};
OptionalExtensions m_optional_extensions = {};
};
} // namespace Vulkan

View File

@ -257,6 +257,20 @@ namespace Vulkan
command_buffer, src_stage_mask, dst_stage_mask, 0, 0, nullptr, 1, &buffer_info, 0, nullptr);
}
void AddPointerToChain(void* head, const void* ptr)
{
VkBaseInStructure* last_st = static_cast<VkBaseInStructure*>(head);
while (last_st->pNext)
{
if (last_st->pNext == ptr)
return;
last_st = const_cast<VkBaseInStructure*>(last_st->pNext);
}
last_st->pNext = static_cast<const VkBaseInStructure*>(ptr);
}
const char* VkResultToString(VkResult res)
{
switch (res)

View File

@ -49,6 +49,9 @@ namespace Vulkan
VkAccessFlags dst_access_mask, VkDeviceSize offset, VkDeviceSize size, VkPipelineStageFlags src_stage_mask,
VkPipelineStageFlags dst_stage_mask);
// Adds a structure to a chain.
void AddPointerToChain(void* head, const void* ptr);
const char* VkResultToString(VkResult res);
void LogVulkanResult(const char* func_name, VkResult res, const char* msg, ...) /*printflike(4, 5)*/;

View File

@ -244,6 +244,7 @@ bool GSDeviceVK::CheckFeatures()
m_features.image_load_store = features.fragmentStoresAndAtomics;
m_features.texture_barrier = true;
m_features.prefer_new_textures = true;
m_features.provoking_vertex_last = g_vulkan_context->GetOptionalExtensions().vk_ext_provoking_vertex;
if (!features.dualSrcBlend)
{
@ -1271,6 +1272,10 @@ 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))
{
@ -1494,6 +1499,10 @@ 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());
@ -1543,6 +1552,10 @@ 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());
@ -1872,6 +1885,9 @@ 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);
VkPipeline pipeline = gpb.Create(g_vulkan_context->GetDevice(), g_vulkan_shader_cache->GetPipelineCache(true));
if (pipeline)
{