diff --git a/Directory.Packages.props b/Directory.Packages.props index a932475479..e737016291 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -39,9 +39,9 @@ - - - + + + diff --git a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs index 952867642d..07c7e26180 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 bf22a120a5..5024fdd4e1 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -884,7 +884,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(); } @@ -989,7 +997,7 @@ namespace Ryujinx.Graphics.Vulkan public void SetLogicOpState(bool enable, LogicalOp op) { - if (_supportExtDynamic2 && Gd.ExtendedLogicOp) + if (Gd.ExtendedDynamicState2Features.ExtendedDynamicState2LogicOp) { DynamicState.SetLogicOp(op.Convert()); } @@ -998,21 +1006,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 783f2bf710..90d75724ab 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 7c6f6a83ff..e4fe002d95 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -404,7 +404,7 @@ namespace Ryujinx.Graphics.Vulkan { UpdateVertexAttributeDescriptions(gd); } - + bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState; bool supportsExtDynamicState2 = gd.Capabilities.SupportsExtendedDynamicState2; @@ -457,7 +457,7 @@ namespace Ryujinx.Graphics.Vulkan { primitiveRestartEnable = true; } - + var inputAssemblyState = new PipelineInputAssemblyStateCreateInfo { SType = StructureType.PipelineInputAssemblyStateCreateInfo, @@ -494,12 +494,12 @@ namespace Ryujinx.Graphics.Vulkan rasterizationState.DepthBiasEnable = DepthBiasEnable; rasterizationState.RasterizerDiscardEnable = RasterizerDiscardEnable; } - + var viewportState = new PipelineViewportStateCreateInfo { SType = StructureType.PipelineViewportStateCreateInfo, }; - + if (!supportsExtDynamicState) { viewportState.ViewportCount = ViewportsCount; @@ -534,7 +534,7 @@ namespace Ryujinx.Graphics.Vulkan MinDepthBounds = MinDepthBounds, MaxDepthBounds = MaxDepthBounds, }; - + if (!supportsExtDynamicState) { var stencilFront = new StencilOpState( @@ -613,9 +613,54 @@ namespace Ryujinx.Graphics.Vulkan colorBlendState.PNext = &colorBlendAdvancedState; } - - int dynamicStatesCount = supportsExtDynamicState ? (isMoltenVk ? 18 : 19) : (isMoltenVk ? 7 : 8); + int baseDynamicStatesCount = 7; + int additionalDynamicStatesCount = 0; + + if (!isMoltenVk) + { + baseDynamicStatesCount++; + } + + if (supportsExtDynamicState) + { + additionalDynamicStatesCount += isMoltenVk ? 10 : 11; + } + + if (supportsExtDynamicState2) + { + additionalDynamicStatesCount += 2; + 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++; + } + } + + int dynamicStatesCount = baseDynamicStatesCount + additionalDynamicStatesCount; DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount]; dynamicStates[0] = DynamicState.Viewport; @@ -625,33 +670,64 @@ namespace Ryujinx.Graphics.Vulkan dynamicStates[4] = DynamicState.StencilWriteMask; dynamicStates[5] = DynamicState.StencilReference; dynamicStates[6] = DynamicState.BlendConstants; - - if(!isMoltenVk) + + int currentIndex = 7; + + if (!isMoltenVk) { - dynamicStates[7] = DynamicState.LineWidth; + dynamicStates[currentIndex++] = DynamicState.LineWidth; } - + if (supportsExtDynamicState) { - int index = (isMoltenVk ? 7 : 8); - if (!isMoltenVk) { - dynamicStates[index++] = DynamicState.VertexInputBindingStrideExt; + if (!isMoltenVk) + { + dynamicStates[currentIndex++] = DynamicState.VertexInputBindingStrideExt; } - dynamicStates[index++] = DynamicState.CullModeExt; - dynamicStates[index++] = DynamicState.FrontFaceExt; - dynamicStates[index++] = DynamicState.DepthTestEnableExt; - dynamicStates[index++] = DynamicState.DepthWriteEnableExt; - dynamicStates[index++] = DynamicState.DepthCompareOpExt; - dynamicStates[index++] = DynamicState.StencilTestEnableExt; - dynamicStates[index++] = DynamicState.ViewportWithCountExt; - dynamicStates[index++] = DynamicState.ScissorWithCountExt; - dynamicStates[index] = DynamicState.StencilOpExt; + dynamicStates[currentIndex++] = DynamicState.CullModeExt; + dynamicStates[currentIndex++] = DynamicState.FrontFaceExt; + dynamicStates[currentIndex++] = DynamicState.DepthTestEnableExt; + dynamicStates[currentIndex++] = DynamicState.DepthWriteEnableExt; + dynamicStates[currentIndex++] = DynamicState.DepthCompareOpExt; + dynamicStates[currentIndex++] = DynamicState.StencilTestEnableExt; + dynamicStates[currentIndex++] = DynamicState.ViewportWithCountExt; + dynamicStates[currentIndex++] = DynamicState.ScissorWithCountExt; + dynamicStates[currentIndex++] = DynamicState.StencilOpExt; } if (supportsExtDynamicState2) { - dynamicStates[16] = DynamicState.DepthBiasEnableExt; - dynamicStates[17] = DynamicState.RasterizerDiscardEnableExt; + dynamicStates[currentIndex++] = DynamicState.DepthBiasEnableExt; + dynamicStates[currentIndex++] = DynamicState.RasterizerDiscardEnableExt; + + 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 diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index 6b4ca1d3d2..4a1aa2b0be 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 1807711d67..69d0759511 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)) {