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,
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 // some android devices only expose up to four storage
// slots per pipeline // slots per pipeline
}, },

View File

@ -164,7 +164,7 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
// Enable the instance extensions the backend uses // 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 // Use required platform-specific flags
auto flags = GetInstanceFlags(); auto flags = GetInstanceFlags();
@ -393,7 +393,6 @@ bool Instance::CreateDevice() {
}; };
AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
AddExtension(VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME);
timeline_semaphores = AddExtension(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME); timeline_semaphores = AddExtension(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME);
extended_dynamic_state = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); extended_dynamic_state = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
push_descriptors = AddExtension(VK_KHR_PUSH_DESCRIPTOR_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 u32 queue_count = graphics_queue_family_index != present_queue_family_index ? 2u : 1u;
const vk::StructureChain device_chain = { vk::StructureChain device_chain = {
vk::DeviceCreateInfo{ vk::DeviceCreateInfo{
.queueCreateInfoCount = queue_count, .queueCreateInfoCount = queue_count,
.pQueueCreateInfos = queue_infos.data(), .pQueueCreateInfos = queue_infos.data(),
@ -460,24 +459,45 @@ bool Instance::CreateDevice() {
.ppEnabledExtensionNames = enabled_extensions.data(), .ppEnabledExtensionNames = enabled_extensions.data(),
}, },
vk::PhysicalDeviceFeatures2{ vk::PhysicalDeviceFeatures2{
.features = .features{
{ .robustBufferAccess = features.robustBufferAccess,
.robustBufferAccess = features.robustBufferAccess, .geometryShader = features.geometryShader,
.geometryShader = features.geometryShader, .dualSrcBlend = features.dualSrcBlend,
.dualSrcBlend = features.dualSrcBlend, .logicOp = features.logicOp,
.logicOp = features.logicOp, .depthClamp = features.depthClamp,
.depthClamp = features.depthClamp, .largePoints = features.largePoints,
.largePoints = features.largePoints, .samplerAnisotropy = features.samplerAnisotropy,
.samplerAnisotropy = features.samplerAnisotropy, .fragmentStoresAndAtomics = features.fragmentStoresAndAtomics,
.fragmentStoresAndAtomics = features.fragmentStoresAndAtomics, .shaderStorageImageMultisample = features.shaderStorageImageMultisample,
.shaderStorageImageMultisample = features.shaderStorageImageMultisample, .shaderClipDistance = features.shaderClipDistance,
.shaderClipDistance = features.shaderClipDistance, },
},
}, },
feature_chain.get<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>(),
feature_chain.get<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>(), feature_chain.get<vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>(),
feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(), 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 { try {
device = physical_device.createDevice(device_chain.get()); device = physical_device.createDevice(device_chain.get());

View File

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

View File

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

View File

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

View File

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