diff --git a/Directory.Packages.props b/Directory.Packages.props index d04e237e0..fc27404c2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -39,9 +39,9 @@ - - - + + + @@ -49,4 +49,4 @@ - + \ No newline at end of file diff --git a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs index 952867642..07c7e2618 100644 --- a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs +++ b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs @@ -32,6 +32,7 @@ namespace Ryujinx.Graphics.Vulkan public readonly bool SupportsConditionalRendering; public readonly bool SupportsExtendedDynamicState; public readonly bool SupportsExtendedDynamicState2; + public readonly bool SupportsExtendedDynamicState3; public readonly bool SupportsMultiView; public readonly bool SupportsNullDescriptors; public readonly bool SupportsPushDescriptors; @@ -72,6 +73,7 @@ namespace Ryujinx.Graphics.Vulkan bool supportsConditionalRendering, bool supportsExtendedDynamicState, bool supportsExtendedDynamicState2, + bool supportsExtendedDynamicState3, bool supportsMultiView, bool supportsNullDescriptors, bool supportsPushDescriptors, @@ -111,6 +113,7 @@ namespace Ryujinx.Graphics.Vulkan SupportsConditionalRendering = supportsConditionalRendering; SupportsExtendedDynamicState = supportsExtendedDynamicState; SupportsExtendedDynamicState2 = supportsExtendedDynamicState2; + SupportsExtendedDynamicState3 = supportsExtendedDynamicState3; SupportsMultiView = supportsMultiView; SupportsNullDescriptors = supportsNullDescriptors; SupportsPushDescriptors = supportsPushDescriptors; diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index 5ae36a4b0..f7332a545 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -886,7 +886,15 @@ namespace Ryujinx.Graphics.Vulkan public void SetDepthClamp(bool clamp) { - _newState.DepthClampEnable = clamp; + if (Gd.ExtendedDynamicState3Features.ExtendedDynamicState3DepthClampEnable) + { + DynamicState.SetDepthClampEnable(clamp); + } + else + { + _newState.DepthClampEnable = clamp; + } + SignalStateChange(); } @@ -986,7 +994,7 @@ namespace Ryujinx.Graphics.Vulkan public void SetLogicOpState(bool enable, LogicalOp op) { - if (_supportExtDynamic2 && Gd.ExtendedLogicOp) + if (Gd.ExtendedDynamicState2Features.ExtendedDynamicState2LogicOp) { DynamicState.SetLogicOp(op.Convert()); } @@ -995,21 +1003,53 @@ namespace Ryujinx.Graphics.Vulkan _newState.LogicOp = op.Convert(); } - _newState.LogicOpEnable = enable; + if (Gd.ExtendedDynamicState3Features.ExtendedDynamicState3LogicOpEnable) + { + DynamicState.SetLogicOpEnable(enable); + + } + else + { + _newState.LogicOpEnable = enable; + } SignalStateChange(); } public void SetMultisampleState(MultisampleDescriptor multisample) { - _newState.AlphaToCoverageEnable = multisample.AlphaToCoverageEnable; - _newState.AlphaToOneEnable = multisample.AlphaToOneEnable; + if (Gd.ExtendedDynamicState3Features.ExtendedDynamicState3AlphaToCoverageEnable) + { + DynamicState.SetAlphaToCoverEnable(multisample.AlphaToCoverageEnable); + } + else + { + _newState.AlphaToCoverageEnable = multisample.AlphaToCoverageEnable; + } + + if (Gd.ExtendedDynamicState3Features.ExtendedDynamicState3AlphaToOneEnable) + { + DynamicState.SetAlphaToOneEnable(multisample.AlphaToOneEnable); + } + else + { + _newState.AlphaToOneEnable = multisample.AlphaToOneEnable; + } + SignalStateChange(); } public void SetPatchParameters(int vertices, ReadOnlySpan defaultOuterLevel, ReadOnlySpan defaultInnerLevel) { - _newState.PatchControlPoints = (uint)vertices; + if (Gd.ExtendedDynamicState2Features.ExtendedDynamicState2PatchControlPoints) + { + DynamicState.SetPatchControlPoints((uint)vertices); + } + else + { + _newState.PatchControlPoints = (uint)vertices; + } + SignalStateChange(); // TODO: Default levels (likely needs emulation on shaders?) diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs index 783f2bf71..90d75724a 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs @@ -52,6 +52,15 @@ namespace Ryujinx.Graphics.Vulkan private LogicOp _logicOp; + private uint _patchControlPoints; + + private bool _logicOpEnable; + + private bool _depthClampEnable; + + private bool _alphaToCoverEnable; + private bool _alphaToOneEnable; + [Flags] private enum DirtyFlags { @@ -69,9 +78,14 @@ namespace Ryujinx.Graphics.Vulkan LineWidth = 1 << 10, RasterDiscard = 1 << 11, LogicOp = 1 << 12, + DepthClampEnable = 1 << 13, + LogicOpEnalbe = 1 << 14, + AlphaToCover = 1 << 15, + AlphaToOne = 1 << 16, + PatchControlPoints = 1 << 17, Standard = Blend | DepthBias | Scissor | Stencil | Viewport | LineWidth, Extended = CullMode | FrontFace | DepthTestBool | DepthTestCompareOp | StencilTestEnable, - Extended2 = RasterDiscard | LogicOp, + Extended2 = RasterDiscard | LogicOp | PatchControlPoints, } private DirtyFlags _dirty; @@ -219,6 +233,41 @@ namespace Ryujinx.Graphics.Vulkan _dirty |= DirtyFlags.LogicOp; } + public void SetPatchControlPoints(uint points) + { + _patchControlPoints = points; + + _dirty |= DirtyFlags.PatchControlPoints; + } + + public void SetLogicOpEnable(bool logicOpEnable) + { + _logicOpEnable = logicOpEnable; + + _dirty |= DirtyFlags.LogicOpEnalbe; + } + + public void SetDepthClampEnable(bool depthClampEnable) + { + _depthClampEnable = depthClampEnable; + + _dirty |= DirtyFlags.DepthClampEnable; + } + + public void SetAlphaToCoverEnable(bool alphaToCoverEnable) + { + _alphaToCoverEnable = alphaToCoverEnable; + + _dirty |= DirtyFlags.AlphaToCover; + } + + public void SetAlphaToOneEnable(bool alphaToOneEnable) + { + _alphaToOneEnable = alphaToOneEnable; + + _dirty |= DirtyFlags.AlphaToOne; + } + public void ForceAllDirty(VulkanRenderer gd) { _dirty = DirtyFlags.Standard; @@ -238,10 +287,35 @@ namespace Ryujinx.Graphics.Vulkan _dirty &= ~DirtyFlags.LineWidth; } - if (!gd.ExtendedLogicOp) + if (!gd.ExtendedDynamicState2Features.ExtendedDynamicState2LogicOp) { _dirty &= ~DirtyFlags.LogicOp; } + + if (!gd.ExtendedDynamicState2Features.ExtendedDynamicState2PatchControlPoints) + { + _dirty &= ~DirtyFlags.LogicOp; + } + + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3AlphaToCoverageEnable) + { + _dirty = DirtyFlags.AlphaToCover; + } + + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3AlphaToOneEnable) + { + _dirty = DirtyFlags.AlphaToOne; + } + + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3DepthClampEnable) + { + _dirty = DirtyFlags.DepthClampEnable; + } + + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3LogicOpEnable) + { + _dirty = DirtyFlags.LogicOpEnalbe; + } } public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer) @@ -306,11 +380,36 @@ namespace Ryujinx.Graphics.Vulkan RecordRasterizationDiscard(gd, commandBuffer); } - if (_dirty.HasFlag(DirtyFlags.RasterDiscard)) + if (_dirty.HasFlag(DirtyFlags.LogicOp)) { RecordLogicOp(gd, commandBuffer); } + if (_dirty.HasFlag(DirtyFlags.PatchControlPoints)) + { + RecordPatchControlPoints(gd, commandBuffer); + } + + if (_dirty.HasFlag(DirtyFlags.LogicOpEnalbe)) + { + RecordLogicOpEnable(gd, commandBuffer); + } + + if (_dirty.HasFlag(DirtyFlags.DepthClampEnable)) + { + RecordDepthClampEnable(gd, commandBuffer); + } + + if (_dirty.HasFlag(DirtyFlags.AlphaToCover)) + { + RecordAlphaToCoverEnable(gd, commandBuffer); + } + + if (_dirty.HasFlag(DirtyFlags.AlphaToOne)) + { + RecordAlphaToOneEnable(gd, commandBuffer); + } + _dirty = DirtyFlags.None; } @@ -421,6 +520,31 @@ namespace Ryujinx.Graphics.Vulkan gd.ExtendedDynamicState2Api.CmdSetLogicOp(commandBuffer, _logicOp); } + private readonly void RecordLogicOpEnable(VulkanRenderer gd, CommandBuffer commandBuffer) + { + gd.ExtendedDynamicState3Api.CmdSetLogicOpEnable(commandBuffer, _logicOpEnable); + } + + private readonly void RecordDepthClampEnable(VulkanRenderer gd, CommandBuffer commandBuffer) + { + gd.ExtendedDynamicState3Api.CmdSetDepthClampEnable(commandBuffer, _depthClampEnable); + } + + private readonly void RecordAlphaToCoverEnable(VulkanRenderer gd, CommandBuffer commandBuffer) + { + gd.ExtendedDynamicState3Api.CmdSetAlphaToCoverageEnable(commandBuffer, _alphaToCoverEnable); + } + + private readonly void RecordAlphaToOneEnable(VulkanRenderer gd, CommandBuffer commandBuffer) + { + gd.ExtendedDynamicState3Api.CmdSetAlphaToOneEnable(commandBuffer, _alphaToOneEnable); + } + + private readonly void RecordPatchControlPoints(VulkanRenderer gd, CommandBuffer commandBuffer) + { + gd.ExtendedDynamicState2Api.CmdSetPatchControlPoints(commandBuffer, _patchControlPoints); + } + private readonly void RecordLineWidth(Vk api, CommandBuffer commandBuffer) { if (!OperatingSystem.IsMacOS()) diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs index 4678ef763..b1b4fd92c 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -407,6 +407,7 @@ namespace Ryujinx.Graphics.Vulkan bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState; bool supportsExtDynamicState2 = gd.Capabilities.SupportsExtendedDynamicState2; + bool supportsExtDynamicState3 = gd.Capabilities.SupportsExtendedDynamicState3; fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions = &Internal.VertexAttributeDescriptions[0]) @@ -468,16 +469,24 @@ namespace Ryujinx.Graphics.Vulkan var tessellationState = new PipelineTessellationStateCreateInfo { SType = StructureType.PipelineTessellationStateCreateInfo, - PatchControlPoints = PatchControlPoints, }; + if (!gd.ExtendedDynamicState2Features.ExtendedDynamicState2PatchControlPoints) + { + tessellationState.PatchControlPoints = PatchControlPoints; + } + var rasterizationState = new PipelineRasterizationStateCreateInfo { SType = StructureType.PipelineRasterizationStateCreateInfo, - DepthClampEnable = DepthClampEnable, PolygonMode = PolygonMode, }; + if (!gd.ExtendedDynamicState3Features.ExtendedDynamicState3DepthClampEnable) + { + rasterizationState.DepthClampEnable = DepthClampEnable; + } + if (isMoltenVk) { rasterizationState.LineWidth = 1.0f; @@ -523,10 +532,18 @@ namespace Ryujinx.Graphics.Vulkan SampleShadingEnable = false, RasterizationSamples = TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, SamplesCount), MinSampleShading = 1, - AlphaToCoverageEnable = AlphaToCoverageEnable, - AlphaToOneEnable = AlphaToOneEnable, }; + if (!gd.ExtendedDynamicState3Features.ExtendedDynamicState3AlphaToCoverageEnable) + { + multisampleState.AlphaToCoverageEnable = AlphaToCoverageEnable; + } + + if (!gd.ExtendedDynamicState3Features.ExtendedDynamicState3AlphaToOneEnable) + { + multisampleState.AlphaToOneEnable = AlphaToOneEnable; + } + var depthStencilState = new PipelineDepthStencilStateCreateInfo { SType = StructureType.PipelineDepthStencilStateCreateInfo, @@ -541,19 +558,13 @@ namespace Ryujinx.Graphics.Vulkan StencilFrontFailOp, StencilFrontPassOp, StencilFrontDepthFailOp, - StencilFrontCompareOp, - null, - null, - null); + StencilFrontCompareOp); var stencilBack = new StencilOpState( StencilBackFailOp, StencilBackPassOp, StencilBackDepthFailOp, - StencilBackCompareOp, - null, - null, - null); + StencilBackCompareOp); depthStencilState.Front = stencilFront; depthStencilState.Back = stencilBack; @@ -587,16 +598,20 @@ namespace Ryujinx.Graphics.Vulkan var colorBlendState = new PipelineColorBlendStateCreateInfo { SType = StructureType.PipelineColorBlendStateCreateInfo, - LogicOpEnable = LogicOpEnable, AttachmentCount = ColorBlendAttachmentStateCount, PAttachments = pColorBlendAttachmentState, }; - if (!(supportsExtDynamicState2 && gd.ExtendedLogicOp)) + if (!gd.ExtendedDynamicState2Features.ExtendedDynamicState2LogicOp) { colorBlendState.LogicOp = LogicOp; } + if (!gd.ExtendedDynamicState3Features.ExtendedDynamicState3LogicOpEnable) + { + colorBlendState.LogicOpEnable = LogicOpEnable; + } + PipelineColorBlendAdvancedStateCreateInfoEXT colorBlendAdvancedState; if (!AdvancedBlendSrcPreMultiplied || @@ -624,13 +639,37 @@ namespace Ryujinx.Graphics.Vulkan if (supportsExtDynamicState) { - additionalDynamicStatesCount += isMoltenVk ? 11 : 12; + additionalDynamicStatesCount += isMoltenVk ? 10 : 11; } if (supportsExtDynamicState2) { additionalDynamicStatesCount += 2; - if (gd.ExtendedLogicOp) + if (gd.ExtendedDynamicState2Features.ExtendedDynamicState2LogicOp) + { + additionalDynamicStatesCount++; + } + if (gd.ExtendedDynamicState2Features.ExtendedDynamicState2PatchControlPoints) + { + additionalDynamicStatesCount++; + } + } + + if (supportsExtDynamicState3) + { + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3DepthClampEnable) + { + additionalDynamicStatesCount++; + } + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3LogicOpEnable) + { + additionalDynamicStatesCount++; + } + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3AlphaToCoverageEnable) + { + additionalDynamicStatesCount++; + } + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3AlphaToOneEnable) { additionalDynamicStatesCount++; } @@ -676,10 +715,34 @@ namespace Ryujinx.Graphics.Vulkan dynamicStates[currentIndex++] = DynamicState.DepthBiasEnableExt; dynamicStates[currentIndex++] = DynamicState.RasterizerDiscardEnableExt; - if (gd.ExtendedLogicOp) + if (gd.ExtendedDynamicState2Features.ExtendedDynamicState2LogicOp) { dynamicStates[currentIndex++] = DynamicState.LogicOpExt; } + if (gd.ExtendedDynamicState2Features.ExtendedDynamicState2PatchControlPoints) + { + dynamicStates[currentIndex++] = DynamicState.PatchControlPointsExt; + } + } + + if (supportsExtDynamicState3) + { + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3DepthClampEnable) + { + dynamicStates[currentIndex++] = DynamicState.DepthClampEnableExt; + } + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3LogicOpEnable) + { + dynamicStates[currentIndex++] = DynamicState.LogicOpEnableExt; + } + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3AlphaToCoverageEnable) + { + dynamicStates[currentIndex++] = DynamicState.AlphaToCoverageEnableExt; + } + if (gd.ExtendedDynamicState3Features.ExtendedDynamicState3AlphaToOneEnable) + { + dynamicStates[currentIndex++] = DynamicState.AlphaToOneEnableExt; + } } var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo @@ -689,6 +752,7 @@ namespace Ryujinx.Graphics.Vulkan PDynamicStates = dynamicStates, }; + var pipelineCreateInfo = new GraphicsPipelineCreateInfo { SType = StructureType.GraphicsPipelineCreateInfo, diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index 6b4ca1d3d..4a1aa2b0b 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs @@ -263,7 +263,7 @@ namespace Ryujinx.Graphics.Vulkan return InvalidIndex; } - internal static Device CreateDevice(Vk api, VulkanPhysicalDevice physicalDevice, uint queueFamilyIndex, uint queueCount, out bool extendedLogicOp) + internal static Device CreateDevice(Vk api, VulkanPhysicalDevice physicalDevice, uint queueFamilyIndex, uint queueCount, out PhysicalDeviceExtendedDynamicState2FeaturesEXT extendedDynamicState2Features, out PhysicalDeviceExtendedDynamicState3FeaturesEXT extendedDynamicState3Features) { if (queueCount > QueuesCount) { @@ -322,6 +322,17 @@ namespace Ryujinx.Graphics.Vulkan features2.PNext = &supportedFeaturesExtExtendedDynamicState2; } + PhysicalDeviceExtendedDynamicState3FeaturesEXT supportedFeaturesExtExtendedDynamicState3 = new() + { + SType = StructureType.PhysicalDeviceExtendedDynamicState3FeaturesExt, + PNext = features2.PNext, + }; + + if (physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState3.ExtensionName)) + { + features2.PNext = &supportedFeaturesExtExtendedDynamicState3; + } + PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT supportedFeaturesPrimitiveTopologyListRestart = new() { SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt, @@ -451,18 +462,45 @@ namespace Ryujinx.Graphics.Vulkan pExtendedFeatures = &featuresExtendedDynamicState; - var featuresExtendedDynamicState2 = new PhysicalDeviceExtendedDynamicState2FeaturesEXT() + if (physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName)) { - SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt, - PNext = pExtendedFeatures, - ExtendedDynamicState2 = physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName), - ExtendedDynamicState2LogicOp = supportedFeaturesExtExtendedDynamicState2.ExtendedDynamicState2LogicOp, - ExtendedDynamicState2PatchControlPoints = supportedFeaturesExtExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints, - }; + var featuresExtendedDynamicState2 = new PhysicalDeviceExtendedDynamicState2FeaturesEXT() + { + SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt, + PNext = pExtendedFeatures, + ExtendedDynamicState2 = + physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName), + ExtendedDynamicState2LogicOp = + supportedFeaturesExtExtendedDynamicState2.ExtendedDynamicState2LogicOp, + ExtendedDynamicState2PatchControlPoints = supportedFeaturesExtExtendedDynamicState2 + .ExtendedDynamicState2PatchControlPoints, + }; - extendedLogicOp = supportedFeaturesExtExtendedDynamicState2.ExtendedDynamicState2LogicOp; + pExtendedFeatures = &featuresExtendedDynamicState2; + } - pExtendedFeatures = &featuresExtendedDynamicState2; + extendedDynamicState2Features = supportedFeaturesExtExtendedDynamicState2; + + + if (physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState3.ExtensionName)) + { + var featuresExtendedDynamicState3 = new PhysicalDeviceExtendedDynamicState3FeaturesEXT() + { + SType = StructureType.PhysicalDeviceExtendedDynamicState3FeaturesExt, + PNext = pExtendedFeatures, + ExtendedDynamicState3LogicOpEnable = supportedFeaturesExtExtendedDynamicState3.ExtendedDynamicState3LogicOpEnable, + ExtendedDynamicState3AlphaToCoverageEnable = supportedFeaturesExtExtendedDynamicState3.ExtendedDynamicState3AlphaToCoverageEnable, + ExtendedDynamicState3AlphaToOneEnable = supportedFeaturesExtExtendedDynamicState3.ExtendedDynamicState3AlphaToOneEnable, + ExtendedDynamicState3DepthClampEnable = supportedFeaturesExtExtendedDynamicState3.ExtendedDynamicState3DepthClampEnable, + }; + + pExtendedFeatures = &featuresExtendedDynamicState3; + } + + //Seems to be a error in Silk.Net bidings investigate further later + supportedFeaturesExtExtendedDynamicState3.ExtendedDynamicState3DepthClampEnable = false; + + extendedDynamicState3Features = supportedFeaturesExtExtendedDynamicState3; var featuresVk11 = new PhysicalDeviceVulkan11Features { diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 8829c038b..b0dcce2e2 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -36,6 +36,7 @@ namespace Ryujinx.Graphics.Vulkan internal ExtConditionalRendering ConditionalRenderingApi { get; private set; } internal ExtExtendedDynamicState ExtendedDynamicStateApi { get; private set; } internal ExtExtendedDynamicState2 ExtendedDynamicState2Api { get; private set; } + internal ExtExtendedDynamicState3 ExtendedDynamicState3Api { get; private set; } internal KhrPushDescriptor PushDescriptorApi { get; private set; } internal ExtTransformFeedback TransformFeedbackApi { get; private set; } @@ -99,7 +100,10 @@ namespace Ryujinx.Graphics.Vulkan public bool PreferThreading => true; - public bool ExtendedLogicOp; + public PhysicalDeviceExtendedDynamicState2FeaturesEXT ExtendedDynamicState2Features; + + public PhysicalDeviceExtendedDynamicState3FeaturesEXT ExtendedDynamicState3Features; + public event EventHandler ScreenCaptured; @@ -141,6 +145,11 @@ namespace Ryujinx.Graphics.Vulkan ExtendedDynamicState2Api = extendedDynamicState2Api; } + if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExtendedDynamicState3 extendedDynamicState3Api)) + { + ExtendedDynamicState3Api = extendedDynamicState3Api; + } + if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrPushDescriptor pushDescriptorApi)) { PushDescriptorApi = pushDescriptorApi; @@ -392,6 +401,7 @@ namespace Ryujinx.Graphics.Vulkan _physicalDevice.IsDeviceExtensionPresent(ExtConditionalRendering.ExtensionName), _physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName), _physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName), + _physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState3.ExtensionName), features2.Features.MultiViewport && !(IsMoltenVk && Vendor == Vendor.Amd), // Workaround for AMD on MoltenVK issue featuresRobustness2.NullDescriptor || IsMoltenVk, supportsPushDescriptors && !IsMoltenVk, @@ -456,9 +466,10 @@ namespace Ryujinx.Graphics.Vulkan var queueFamilyIndex = VulkanInitialization.FindSuitableQueueFamily(Api, _physicalDevice, _surface, out uint maxQueueCount); - _device = VulkanInitialization.CreateDevice(Api, _physicalDevice, queueFamilyIndex, maxQueueCount, out bool extendedLogicOp); + _device = VulkanInitialization.CreateDevice(Api, _physicalDevice, queueFamilyIndex, maxQueueCount, out PhysicalDeviceExtendedDynamicState2FeaturesEXT extendedDynamicState2Features, out PhysicalDeviceExtendedDynamicState3FeaturesEXT extendedDynamicState3Features); - ExtendedLogicOp = extendedLogicOp; + ExtendedDynamicState2Features = extendedDynamicState2Features; + ExtendedDynamicState3Features = extendedDynamicState3Features; if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrSwapchain swapchainApi)) {