renderer_vulkan: Fallback to software shaders on unsupported topology

* MoltenVK does not support triangle fans
This commit is contained in:
GPUCode
2022-12-30 15:25:27 +02:00
parent 0e987959a6
commit 3da6c25fd8
6 changed files with 68 additions and 32 deletions

View File

@ -61,7 +61,7 @@ constexpr static std::array RASTERIZER_SETS = {
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eStorageImage,
},
.binding_count = 4, // TODO: Combine cube faces to a single storage image
.binding_count = 7, // TODO: Combine cube faces to a single storage image
// some android devices only expose up to four storage
// slots per pipeline
},

View File

@ -164,7 +164,7 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
// Enable the instance extensions the backend uses
auto extensions = GetInstanceExtensions(window_info.type, false);
auto extensions = GetInstanceExtensions(window_info.type, enable_validation);
// Use required platform-specific flags
auto flags = GetInstanceFlags();
@ -393,7 +393,6 @@ bool Instance::CreateDevice() {
};
AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
AddExtension(VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME);
timeline_semaphores = AddExtension(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME);
extended_dynamic_state = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
push_descriptors = AddExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
@ -452,7 +451,7 @@ bool Instance::CreateDevice() {
};
const u32 queue_count = graphics_queue_family_index != present_queue_family_index ? 2u : 1u;
const vk::StructureChain device_chain = {
vk::StructureChain device_chain = {
vk::DeviceCreateInfo{
.queueCreateInfoCount = queue_count,
.pQueueCreateInfos = queue_infos.data(),
@ -460,24 +459,45 @@ bool Instance::CreateDevice() {
.ppEnabledExtensionNames = enabled_extensions.data(),
},
vk::PhysicalDeviceFeatures2{
.features =
{
.robustBufferAccess = features.robustBufferAccess,
.geometryShader = features.geometryShader,
.dualSrcBlend = features.dualSrcBlend,
.logicOp = features.logicOp,
.depthClamp = features.depthClamp,
.largePoints = features.largePoints,
.samplerAnisotropy = features.samplerAnisotropy,
.fragmentStoresAndAtomics = features.fragmentStoresAndAtomics,
.shaderStorageImageMultisample = features.shaderStorageImageMultisample,
.shaderClipDistance = features.shaderClipDistance,
},
.features{
.robustBufferAccess = features.robustBufferAccess,
.geometryShader = features.geometryShader,
.dualSrcBlend = features.dualSrcBlend,
.logicOp = features.logicOp,
.depthClamp = features.depthClamp,
.largePoints = features.largePoints,
.samplerAnisotropy = features.samplerAnisotropy,
.fragmentStoresAndAtomics = features.fragmentStoresAndAtomics,
.shaderStorageImageMultisample = features.shaderStorageImageMultisample,
.shaderClipDistance = features.shaderClipDistance,
},
},
feature_chain.get<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>(),
feature_chain.get<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>(),
feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(),
feature_chain.get<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>(),
feature_chain.get<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>()};
feature_chain.get<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>(),
};
if (!extended_dynamic_state) {
device_chain.unlink<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
}
if (!custom_border_color) {
device_chain.unlink<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>();
}
if (!index_type_uint8) {
device_chain.unlink<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>();
}
#if VK_KHR_portability_subset
const vk::StructureChain portability_chain =
physical_device.getFeatures2<vk::PhysicalDeviceFeatures2,
vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
const vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features =
portability_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
triangle_fan_supported = portability_features.triangleFans;
#endif
try {
device = physical_device.createDevice(device_chain.get());

View File

@ -185,6 +185,11 @@ public:
return limits.maxTexelBufferElements;
}
/// Returns true if triangle fan is an accepted primitive topology
bool IsTriangleFanSupported() const {
return triangle_fan_supported;
}
private:
/// Returns the optimal supported usage for the requested format
vk::FormatFeatureFlags GetFormatFeatures(vk::Format format);
@ -222,6 +227,7 @@ private:
u32 present_queue_family_index{0};
u32 graphics_queue_family_index{0};
bool triangle_fan_supported{true};
bool timeline_semaphores{};
bool extended_dynamic_state{};
bool push_descriptors{};

View File

@ -19,6 +19,8 @@
namespace Vulkan {
using TriangleTopology = Pica::PipelineRegs::TriangleTopology;
constexpr u64 VERTEX_BUFFER_SIZE = 128 * 1024 * 1024;
constexpr u64 TEXTURE_BUFFER_SIZE = 2 * 1024 * 1024;
@ -391,8 +393,10 @@ bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
const auto [vs_input_index_min, vs_input_index_max, vs_input_size] =
AnalyzeVertexArray(is_indexed);
if (vs_input_size > VERTEX_BUFFER_SIZE) {
LOG_WARNING(Render_Vulkan, "Too large vertex input size {}", vs_input_size);
if (regs.pipeline.triangle_topology == TriangleTopology::Fan &&
!instance.IsTriangleFanSupported()) {
LOG_DEBUG(Render_Vulkan,
"Skipping accelerated draw with unsupported triangle fan topology");
return false;
}
@ -798,10 +802,10 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
depth_surface);
}
static int submit_threshold = 20;
static int submit_threshold = 40;
submit_threshold--;
if (!submit_threshold) {
submit_threshold = 20;
submit_threshold = 40;
scheduler.Flush();
}

View File

@ -66,7 +66,7 @@ void Swapchain::Create() {
.queueFamilyIndexCount = queue_family_indices_count,
.pQueueFamilyIndices = queue_family_indices.data(),
.preTransform = transform,
.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eInherit,
.compositeAlpha = composite_alpha,
.presentMode = present_mode,
.clipped = true,
.oldSwapchain = swapchain,
@ -210,6 +210,12 @@ void Swapchain::SetSurfaceProperties() {
if (!(capabilities.supportedTransforms & transform)) {
transform = capabilities.currentTransform;
}
// Opaque is not supported everywhere.
composite_alpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
if (!(capabilities.supportedCompositeAlpha & vk::CompositeAlphaFlagBitsKHR::eOpaque)) {
composite_alpha = vk::CompositeAlphaFlagBitsKHR::eInherit;
}
}
void Swapchain::Destroy() {
@ -237,14 +243,13 @@ void Swapchain::SetupImages() {
.image = image,
.viewType = vk::ImageViewType::e2D,
.format = surface_format.format,
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
.subresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
image_views.push_back(device.createImageView(view_info));

View File

@ -94,6 +94,7 @@ private:
vk::PresentModeKHR present_mode;
vk::Extent2D extent;
vk::SurfaceTransformFlagBitsKHR transform;
vk::CompositeAlphaFlagBitsKHR composite_alpha;
std::vector<vk::Image> images;
std::vector<vk::ImageView> image_views;
std::vector<vk::Framebuffer> framebuffers;