Implement primitive restart support

Maxwell3D also supports using an arbitrary restart index value however no games are known to use this so leave it for now.
This commit is contained in:
Billy Laws 2022-04-13 22:01:39 +01:00 committed by PixelyIon
parent 3f3acc31d8
commit feb179fcff
6 changed files with 85 additions and 7 deletions

View File

@ -126,7 +126,17 @@ namespace skyline::gpu {
const vk::raii::PhysicalDevice &physicalDevice,
decltype(vk::DeviceQueueCreateInfo::queueCount) &vkQueueFamilyIndex,
TraitManager &traits) {
auto deviceFeatures2{physicalDevice.getFeatures2<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceCustomBorderColorFeaturesEXT, vk::PhysicalDeviceVertexAttributeDivisorFeaturesEXT, vk::PhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT, vk::PhysicalDeviceShaderFloat16Int8Features, vk::PhysicalDeviceShaderAtomicInt64Features, vk::PhysicalDeviceUniformBufferStandardLayoutFeatures, vk::PhysicalDeviceShaderDrawParametersFeatures, vk::PhysicalDeviceProvokingVertexFeaturesEXT>()};
auto deviceFeatures2{physicalDevice.getFeatures2<
vk::PhysicalDeviceFeatures2,
vk::PhysicalDeviceCustomBorderColorFeaturesEXT,
vk::PhysicalDeviceVertexAttributeDivisorFeaturesEXT,
vk::PhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT,
vk::PhysicalDeviceShaderFloat16Int8Features,
vk::PhysicalDeviceShaderAtomicInt64Features,
vk::PhysicalDeviceUniformBufferStandardLayoutFeatures,
vk::PhysicalDeviceShaderDrawParametersFeatures,
vk::PhysicalDeviceProvokingVertexFeaturesEXT,
vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT>()};
decltype(deviceFeatures2) enabledFeatures2{}; // We only want to enable features we required due to potential overhead from unused features
#define FEAT_REQ(structName, feature) \
@ -156,7 +166,11 @@ namespace skyline::gpu {
throw exception("Cannot find Vulkan device extension: \"{}\"", requiredExtension.data());
}
auto deviceProperties2{physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, vk::PhysicalDeviceDriverProperties, vk::PhysicalDeviceFloatControlsProperties, vk::PhysicalDeviceSubgroupProperties>()};
auto deviceProperties2{physicalDevice.getProperties2<
vk::PhysicalDeviceProperties2,
vk::PhysicalDeviceDriverProperties,
vk::PhysicalDeviceFloatControlsProperties,
vk::PhysicalDeviceSubgroupProperties>()};
traits = TraitManager(deviceFeatures2, enabledFeatures2, deviceExtensions, enabledExtensions, deviceProperties2);
traits.ApplyDriverPatches(context);

View File

@ -1743,6 +1743,33 @@ namespace skyline::gpu::interconnect {
private:
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyState{};
void ValidatePrimitiveRestartState() {
if (inputAssemblyState.primitiveRestartEnable) {
switch (inputAssemblyState.topology) {
case vk::PrimitiveTopology::eLineStrip:
case vk::PrimitiveTopology::eTriangleStrip:
case vk::PrimitiveTopology::eTriangleFan:
case vk::PrimitiveTopology::eLineStripWithAdjacency:
case vk::PrimitiveTopology::eTriangleStripWithAdjacency:
break; // Doesn't need any extension
case vk::PrimitiveTopology::ePointList:
case vk::PrimitiveTopology::eLineList:
case vk::PrimitiveTopology::eTriangleList:
case vk::PrimitiveTopology::eLineListWithAdjacency:
case vk::PrimitiveTopology::eTriangleListWithAdjacency:
if (!gpu.traits.supportsTopologyListRestart)
Logger::Warn("GPU doesn't support primitive restart with list topologies");
break;
case vk::PrimitiveTopology::ePatchList:
if (!gpu.traits.supportsTopologyPatchListRestart)
Logger::Warn("GPU doesn't support primitive restart with patch list topology");
break;
}
}
}
public:
void SetPrimitiveTopology(maxwell3d::PrimitiveTopology topology) {
auto[vkTopology, shaderTopology] = [topology]() -> std::tuple<vk::PrimitiveTopology, ShaderCompiler::InputTopology> {
@ -1778,6 +1805,10 @@ namespace skyline::gpu::interconnect {
UpdateRuntimeInformation(runtimeInfo.input_topology, shaderTopology, maxwell3d::PipelineStage::Geometry);
}
void SetPrimitiveRestartEnabled(bool enable) {
inputAssemblyState.primitiveRestartEnable = enable;
}
/* Index Buffer */
private:
struct IndexBuffer {
@ -2540,6 +2571,8 @@ namespace skyline::gpu::interconnect {
public:
template<bool IsIndexed>
void Draw(u32 count, u32 first, i32 vertexOffset = 0) {
ValidatePrimitiveRestartState();
// Shader + Binding Setup
auto programState{CompileShaderProgramState()};
auto descriptorSet{gpu.descriptor.AllocateSet(*programState.descriptorSetLayout)};

View File

@ -6,7 +6,7 @@
namespace skyline::gpu {
TraitManager::TraitManager(const DeviceFeatures2 &deviceFeatures2, DeviceFeatures2 &enabledFeatures2, const std::vector<vk::ExtensionProperties> &deviceExtensions, std::vector<std::array<char, VK_MAX_EXTENSION_NAME_SIZE>> &enabledExtensions, const DeviceProperties2 &deviceProperties2) : quirks(deviceProperties2.get<vk::PhysicalDeviceProperties2>().properties, deviceProperties2.get<vk::PhysicalDeviceDriverProperties>()) {
bool hasCustomBorderColorExt{}, hasShaderAtomicInt64Ext{}, hasShaderFloat16Int8Ext{}, hasShaderDemoteToHelperExt, hasVertexAttributeDivisorExt, hasProvokingVertexExt{};
bool hasCustomBorderColorExt{}, hasShaderAtomicInt64Ext{}, hasShaderFloat16Int8Ext{}, hasShaderDemoteToHelperExt{}, hasVertexAttributeDivisorExt{}, hasProvokingVertexExt{}, hasPrimitiveTopologyListRestartExt{};
bool supportsUniformBufferStandardLayout{}; // We require VK_KHR_uniform_buffer_standard_layout but assume it is implicitly supported even when not present
for (auto &extension : deviceExtensions) {
@ -42,6 +42,7 @@ namespace skyline::gpu {
EXT_SET("VK_KHR_shader_float16_int8", hasShaderFloat16Int8Ext);
EXT_SET("VK_KHR_shader_float_controls", supportsFloatControls);
EXT_SET("VK_KHR_uniform_buffer_standard_layout", supportsUniformBufferStandardLayout);
EXT_SET("VK_EXT_primitive_topology_list_restart", hasPrimitiveTopologyListRestartExt);
}
#undef EXT_SET
@ -110,6 +111,13 @@ namespace skyline::gpu {
Logger::Warn("Cannot find VK_KHR_uniform_buffer_standard_layout, assuming implicit support");
}
if (hasPrimitiveTopologyListRestartExt) {
FEAT_SET(vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT, primitiveTopologyListRestart, supportsTopologyListRestart)
FEAT_SET(vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT, primitiveTopologyPatchListRestart, supportsTopologyPatchListRestart)
} else {
enabledFeatures2.unlink<vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT>();
}
#undef FEAT_SET
if (supportsFloatControls)
@ -122,8 +130,8 @@ namespace skyline::gpu {
std::string TraitManager::Summary() {
return fmt::format(
"\n* Supports U8 Indices: {}\n* Supports Sampler Mirror Clamp To Edge: {}\n* Supports Sampler Reduction Mode: {}\n* Supports Custom Border Color (Without Format): {}\n* Supports Last Provoking Vertex: {}\n* Supports Logical Operations: {}\n* Supports Vertex Attribute Divisor: {}\n* Supports Vertex Attribute Zero Divisor: {}\n* Supports Multiple Viewports: {}\n* Supports Shader Viewport Index: {}\n* Supports SPIR-V 1.4: {}\n* Supports Shader Invocation Demotion: {}\n* Supports 16-bit FP: {}\n* Supports 8-bit Integers: {}\n* Supports 16-bit Integers: {}\n* Supports 64-bit Integers: {}\n* Supports Atomic 64-bit Integers: {}\n* Supports Floating Point Behavior Control: {}\n* Supports Image Read Without Format: {}\n* Supports Subgroup Vote: {}\n* Subgroup Size: {}",
supportsUint8Indices, supportsSamplerMirrorClampToEdge, supportsSamplerReductionMode, supportsCustomBorderColor, supportsLastProvokingVertex, supportsLogicOp, supportsVertexAttributeDivisor, supportsVertexAttributeZeroDivisor, supportsMultipleViewports, supportsShaderViewportIndexLayer, supportsSpirv14, supportsShaderDemoteToHelper, supportsFloat16, supportsInt8, supportsInt16, supportsInt64, supportsAtomicInt64, supportsFloatControls, supportsImageReadWithoutFormat, supportsSubgroupVote, subgroupSize
"\n* Supports U8 Indices: {}\n* Supports Sampler Mirror Clamp To Edge: {}\n* Supports Sampler Reduction Mode: {}\n* Supports Custom Border Color (Without Format): {}\n* Supports Last Provoking Vertex: {}\n* Supports Logical Operations: {}\n* Supports Vertex Attribute Divisor: {}\n* Supports Vertex Attribute Zero Divisor: {}\n* Supports Multiple Viewports: {}\n* Supports Shader Viewport Index: {}\n* Supports SPIR-V 1.4: {}\n* Supports Shader Invocation Demotion: {}\n* Supports 16-bit FP: {}\n* Supports 8-bit Integers: {}\n* Supports 16-bit Integers: {}\n* Supports 64-bit Integers: {}\n* Supports Atomic 64-bit Integers: {}\n* Supports Floating Point Behavior Control: {}\n* Supports Image Read Without Format: {}\n* Supports List Primitive Topology Restart: {}\n* Supports Patch List Primitive Topology Restart: {}\n* Supports Subgroup Vote: {}\n* Subgroup Size: {}",
supportsUint8Indices, supportsSamplerMirrorClampToEdge, supportsSamplerReductionMode, supportsCustomBorderColor, supportsLastProvokingVertex, supportsLogicOp, supportsVertexAttributeDivisor, supportsVertexAttributeZeroDivisor, supportsMultipleViewports, supportsShaderViewportIndexLayer, supportsSpirv14, supportsShaderDemoteToHelper, supportsFloat16, supportsInt8, supportsInt16, supportsInt64, supportsAtomicInt64, supportsFloatControls, supportsImageReadWithoutFormat, supportsTopologyListRestart, supportsTopologyPatchListRestart, supportsSubgroupVote, subgroupSize
);
}

View File

@ -32,6 +32,8 @@ namespace skyline::gpu {
bool supportsFloatControls{}; //!< If extensive control over FP behavior is exposed (with VK_KHR_shader_float_controls)
vk::PhysicalDeviceFloatControlsProperties floatControls{}; //!< Specifics of FP behavior control (All members will be zero'd out when unavailable)
bool supportsImageReadWithoutFormat{}; //!< If a storage image can be read without a format
bool supportsTopologyListRestart{}; //!< If the device supports using primitive restart for topology lists (with VK_EXT_primitive_topology_list_restart)
bool supportsTopologyPatchListRestart{}; //!< If the device supports using primitive restart for topology patch lists (with VK_EXT_primitive_topology_list_restart)
bool supportsSubgroupVote{}; //!< If subgroup votes are supported in shaders with SPV_KHR_subgroup_vote
u32 subgroupSize{}; //!< Size of a subgroup on the host GPU
@ -56,9 +58,23 @@ namespace skyline::gpu {
TraitManager() = default;
using DeviceProperties2 = vk::StructureChain<vk::PhysicalDeviceProperties2, vk::PhysicalDeviceDriverProperties, vk::PhysicalDeviceFloatControlsProperties, vk::PhysicalDeviceSubgroupProperties>;
using DeviceProperties2 = vk::StructureChain<
vk::PhysicalDeviceProperties2,
vk::PhysicalDeviceDriverProperties,
vk::PhysicalDeviceFloatControlsProperties,
vk::PhysicalDeviceSubgroupProperties>;
using DeviceFeatures2 = vk::StructureChain<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceCustomBorderColorFeaturesEXT, vk::PhysicalDeviceVertexAttributeDivisorFeaturesEXT, vk::PhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT, vk::PhysicalDeviceShaderFloat16Int8Features, vk::PhysicalDeviceShaderAtomicInt64Features, vk::PhysicalDeviceUniformBufferStandardLayoutFeatures, vk::PhysicalDeviceShaderDrawParametersFeatures, vk::PhysicalDeviceProvokingVertexFeaturesEXT>;
using DeviceFeatures2 = vk::StructureChain<
vk::PhysicalDeviceFeatures2,
vk::PhysicalDeviceCustomBorderColorFeaturesEXT,
vk::PhysicalDeviceVertexAttributeDivisorFeaturesEXT,
vk::PhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT,
vk::PhysicalDeviceShaderFloat16Int8Features,
vk::PhysicalDeviceShaderAtomicInt64Features,
vk::PhysicalDeviceUniformBufferStandardLayoutFeatures,
vk::PhysicalDeviceShaderDrawParametersFeatures,
vk::PhysicalDeviceProvokingVertexFeaturesEXT,
vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT>;
TraitManager(const DeviceFeatures2 &deviceFeatures2, DeviceFeatures2 &enabledFeatures2, const std::vector<vk::ExtensionProperties> &deviceExtensions, std::vector<std::array<char, VK_MAX_EXTENSION_NAME_SIZE>> &enabledExtensions, const DeviceProperties2 &deviceProperties2);

View File

@ -494,6 +494,10 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
context.SetPrimitiveTopology(vertexBeginGl.topology);
})
ENGINE_CASE(primitiveRestartEnable, {
context.SetPrimitiveRestartEnabled(primitiveRestartEnable);
})
ENGINE_STRUCT_CASE(constantBufferSelector, size, {
context.SetConstantBufferSelectorSize(size);
})

View File

@ -227,6 +227,9 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
Register<0x585, u32> vertexEndGl; //!< Method-only register with no real value, used after calling vertexBeginGl to invoke the draw
Register<0x586, type::VertexBeginGl> vertexBeginGl; //!< Similar to glVertexBegin semantically, supplies a primitive topology for draws alongside instancing data
Register<0x591, u32> primitiveRestartEnable;
Register<0x592, u32> primitiveRestartIndex;
Register<0x5A1, u32> provokingVertexIsLast;
Register<0x5F2, type::IndexBuffer> indexBuffer;