video_core: Perform quaternion correction and interpolation in fragment shader using barycentric extension. (#7126)

This commit is contained in:
Steveice10
2023-11-09 15:23:56 -08:00
committed by GitHub
parent fcc0fd671a
commit 84f9e9a10f
9 changed files with 100 additions and 7 deletions

View File

@@ -403,7 +403,8 @@ bool Instance::CreateDevice() {
vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR,
vk::PhysicalDeviceCustomBorderColorFeaturesEXT, vk::PhysicalDeviceIndexTypeUint8FeaturesEXT,
vk::PhysicalDeviceFragmentShaderInterlockFeaturesEXT,
vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT>();
vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT,
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR>();
const vk::StructureChain properties_chain =
physical_device.getProperties2<vk::PhysicalDeviceProperties2,
vk::PhysicalDevicePortabilitySubsetPropertiesKHR>();
@@ -436,6 +437,7 @@ bool Instance::CreateDevice() {
};
const bool is_nvidia = driver_id == vk::DriverIdKHR::eNvidiaProprietary;
const bool is_moltenvk = driver_id == vk::DriverIdKHR::eMoltenvk;
const bool is_arm = driver_id == vk::DriverIdKHR::eArmProprietary;
const bool is_qualcomm = driver_id == vk::DriverIdKHR::eQualcommProprietary;
@@ -459,6 +461,9 @@ bool Instance::CreateDevice() {
const bool has_pipeline_creation_cache_control =
add_extension(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME, is_nvidia,
"it is broken on Nvidia drivers");
const bool has_fragment_shader_barycentric =
add_extension(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME, is_moltenvk,
"the PerVertexKHR attribute is not supported by MoltenVK");
const auto family_properties = physical_device.getQueueFamilyProperties();
if (family_properties.empty()) {
@@ -514,6 +519,7 @@ bool Instance::CreateDevice() {
vk::PhysicalDeviceIndexTypeUint8FeaturesEXT{},
vk::PhysicalDeviceFragmentShaderInterlockFeaturesEXT{},
vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT{},
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR{},
};
#define PROP_GET(structName, prop, property) property = properties_chain.get<structName>().prop;
@@ -581,6 +587,13 @@ bool Instance::CreateDevice() {
device_chain.unlink<vk::PhysicalDevicePipelineCreationCacheControlFeaturesEXT>();
}
if (has_fragment_shader_barycentric) {
FEAT_SET(vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR, fragmentShaderBarycentric,
fragment_shader_barycentric)
} else {
device_chain.unlink<vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR>();
}
#undef PROP_GET
#undef FEAT_SET

View File

@@ -168,6 +168,11 @@ public:
return shader_stencil_export;
}
/// Returns true when VK_KHR_fragment_shader_barycentric is supported
bool IsFragmentShaderBarycentricSupported() const {
return fragment_shader_barycentric;
}
/// Returns the vendor ID of the physical device
u32 GetVendorID() const {
return properties.vendorID;
@@ -307,6 +312,7 @@ private:
bool fragment_shader_interlock{};
bool image_format_list{};
bool pipeline_creation_cache_control{};
bool fragment_shader_barycentric{};
bool shader_stencil_export{};
bool tooling_info{};
bool debug_utils_supported{};

View File

@@ -96,6 +96,7 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
.has_geometry_shader = instance.UseGeometryShaders(),
.has_custom_border_color = instance.IsCustomBorderColorSupported(),
.has_fragment_shader_interlock = instance.IsFragmentShaderInterlockSupported(),
.has_fragment_shader_barycentric = instance.IsFragmentShaderBarycentricSupported(),
.has_blend_minmax_factor = false,
.has_minus_one_to_one_range = false,
.has_logic_op = !instance.NeedsLogicOpEmulation(),
@@ -331,8 +332,13 @@ bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) {
bool PipelineCache::UseProgrammableVertexShader(const Pica::Regs& regs,
Pica::Shader::ShaderSetup& setup,
const VertexLayout& layout) {
PicaVSConfig config{regs, setup, instance.IsShaderClipDistanceSupported(),
instance.UseGeometryShaders()};
// Enable the geometry-shader only if we are actually doing per-fragment lighting
// and care about proper quaternions. Otherwise just use standard vertex+fragment shaders.
// We also don't need the geometry shader if we have the barycentric extension.
const bool use_geometry_shader = instance.UseGeometryShaders() && !regs.lighting.disable &&
!instance.IsFragmentShaderBarycentricSupported();
PicaVSConfig config{regs, setup, instance.IsShaderClipDistanceSupported(), use_geometry_shader};
for (u32 i = 0; i < layout.attribute_count; i++) {
const VertexAttribute& attr = layout.attributes[i];

View File

@@ -337,6 +337,14 @@ bool RasterizerVulkan::SetupGeometryShader() {
return false;
}
// Enable the quaternion fix-up geometry-shader only if we are actually doing per-fragment
// lighting and care about proper quaternions. Otherwise just use standard vertex+fragment
// shaders. We also don't need a geometry shader if the barycentric extension is supported.
if (regs.lighting.disable || instance.IsFragmentShaderBarycentricSupported()) {
pipeline_cache.UseTrivialGeometryShader();
return true;
}
return pipeline_cache.UseFixedGeometryShader(regs);
}