diff --git a/app/src/main/cpp/skyline/gpu.cpp b/app/src/main/cpp/skyline/gpu.cpp index 0f4f6663..b00a9e49 100644 --- a/app/src/main/cpp/skyline/gpu.cpp +++ b/app/src/main/cpp/skyline/gpu.cpp @@ -126,7 +126,17 @@ namespace skyline::gpu { const vk::raii::PhysicalDevice &physicalDevice, decltype(vk::DeviceQueueCreateInfo::queueCount) &vkQueueFamilyIndex, TraitManager &traits) { - auto deviceFeatures2{physicalDevice.getFeatures2()}; + 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()}; + auto deviceProperties2{physicalDevice.getProperties2< + vk::PhysicalDeviceProperties2, + vk::PhysicalDeviceDriverProperties, + vk::PhysicalDeviceFloatControlsProperties, + vk::PhysicalDeviceSubgroupProperties>()}; traits = TraitManager(deviceFeatures2, enabledFeatures2, deviceExtensions, enabledExtensions, deviceProperties2); traits.ApplyDriverPatches(context); diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index 0aeab963..7bf62e13 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -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 { @@ -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 void Draw(u32 count, u32 first, i32 vertexOffset = 0) { + ValidatePrimitiveRestartState(); + // Shader + Binding Setup auto programState{CompileShaderProgramState()}; auto descriptorSet{gpu.descriptor.AllocateSet(*programState.descriptorSetLayout)}; diff --git a/app/src/main/cpp/skyline/gpu/trait_manager.cpp b/app/src/main/cpp/skyline/gpu/trait_manager.cpp index b3475c53..1dcc2644 100644 --- a/app/src/main/cpp/skyline/gpu/trait_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/trait_manager.cpp @@ -6,7 +6,7 @@ namespace skyline::gpu { TraitManager::TraitManager(const DeviceFeatures2 &deviceFeatures2, DeviceFeatures2 &enabledFeatures2, const std::vector &deviceExtensions, std::vector> &enabledExtensions, const DeviceProperties2 &deviceProperties2) : quirks(deviceProperties2.get().properties, deviceProperties2.get()) { - 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(); + } + #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 ); } diff --git a/app/src/main/cpp/skyline/gpu/trait_manager.h b/app/src/main/cpp/skyline/gpu/trait_manager.h index 5a23aa3e..cf52f433 100644 --- a/app/src/main/cpp/skyline/gpu/trait_manager.h +++ b/app/src/main/cpp/skyline/gpu/trait_manager.h @@ -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; + using DeviceProperties2 = vk::StructureChain< + vk::PhysicalDeviceProperties2, + vk::PhysicalDeviceDriverProperties, + vk::PhysicalDeviceFloatControlsProperties, + vk::PhysicalDeviceSubgroupProperties>; - using DeviceFeatures2 = vk::StructureChain; + 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 &deviceExtensions, std::vector> &enabledExtensions, const DeviceProperties2 &deviceProperties2); diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index ff7b325a..c2118175 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -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); }) diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index dd2f039d..77a8f774 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -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;