mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2025-06-28 13:20:46 -07:00
Add support for advanced blend (part 1/2) (#2801)
* Add blend microcode registers * Add advanced blend support using host extension * Remove debug message * Use pre-generated table for blend functions * XML docs * Rename AdvancedBlendMode to AdvancedBlendOp for consistency * Remove redundant code * Fix some advanced blend related issues on Vulkan * Formatting
This commit is contained in:
@ -79,6 +79,60 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
};
|
||||
}
|
||||
|
||||
public static Silk.NET.Vulkan.BlendOp Convert(this GAL.AdvancedBlendOp op)
|
||||
{
|
||||
return op switch
|
||||
{
|
||||
GAL.AdvancedBlendOp.Zero => Silk.NET.Vulkan.BlendOp.ZeroExt,
|
||||
GAL.AdvancedBlendOp.Src => Silk.NET.Vulkan.BlendOp.SrcExt,
|
||||
GAL.AdvancedBlendOp.Dst => Silk.NET.Vulkan.BlendOp.DstExt,
|
||||
GAL.AdvancedBlendOp.SrcOver => Silk.NET.Vulkan.BlendOp.SrcOverExt,
|
||||
GAL.AdvancedBlendOp.DstOver => Silk.NET.Vulkan.BlendOp.DstOverExt,
|
||||
GAL.AdvancedBlendOp.SrcIn => Silk.NET.Vulkan.BlendOp.SrcInExt,
|
||||
GAL.AdvancedBlendOp.DstIn => Silk.NET.Vulkan.BlendOp.DstInExt,
|
||||
GAL.AdvancedBlendOp.SrcOut => Silk.NET.Vulkan.BlendOp.SrcOutExt,
|
||||
GAL.AdvancedBlendOp.DstOut => Silk.NET.Vulkan.BlendOp.DstOutExt,
|
||||
GAL.AdvancedBlendOp.SrcAtop => Silk.NET.Vulkan.BlendOp.SrcAtopExt,
|
||||
GAL.AdvancedBlendOp.DstAtop => Silk.NET.Vulkan.BlendOp.DstAtopExt,
|
||||
GAL.AdvancedBlendOp.Xor => Silk.NET.Vulkan.BlendOp.XorExt,
|
||||
GAL.AdvancedBlendOp.Plus => Silk.NET.Vulkan.BlendOp.PlusExt,
|
||||
GAL.AdvancedBlendOp.PlusClamped => Silk.NET.Vulkan.BlendOp.PlusClampedExt,
|
||||
GAL.AdvancedBlendOp.PlusClampedAlpha => Silk.NET.Vulkan.BlendOp.PlusClampedAlphaExt,
|
||||
GAL.AdvancedBlendOp.PlusDarker => Silk.NET.Vulkan.BlendOp.PlusDarkerExt,
|
||||
GAL.AdvancedBlendOp.Multiply => Silk.NET.Vulkan.BlendOp.MultiplyExt,
|
||||
GAL.AdvancedBlendOp.Screen => Silk.NET.Vulkan.BlendOp.ScreenExt,
|
||||
GAL.AdvancedBlendOp.Overlay => Silk.NET.Vulkan.BlendOp.OverlayExt,
|
||||
GAL.AdvancedBlendOp.Darken => Silk.NET.Vulkan.BlendOp.DarkenExt,
|
||||
GAL.AdvancedBlendOp.Lighten => Silk.NET.Vulkan.BlendOp.LightenExt,
|
||||
GAL.AdvancedBlendOp.ColorDodge => Silk.NET.Vulkan.BlendOp.ColordodgeExt,
|
||||
GAL.AdvancedBlendOp.ColorBurn => Silk.NET.Vulkan.BlendOp.ColorburnExt,
|
||||
GAL.AdvancedBlendOp.HardLight => Silk.NET.Vulkan.BlendOp.HardlightExt,
|
||||
GAL.AdvancedBlendOp.SoftLight => Silk.NET.Vulkan.BlendOp.SoftlightExt,
|
||||
GAL.AdvancedBlendOp.Difference => Silk.NET.Vulkan.BlendOp.DifferenceExt,
|
||||
GAL.AdvancedBlendOp.Minus => Silk.NET.Vulkan.BlendOp.MinusExt,
|
||||
GAL.AdvancedBlendOp.MinusClamped => Silk.NET.Vulkan.BlendOp.MinusClampedExt,
|
||||
GAL.AdvancedBlendOp.Exclusion => Silk.NET.Vulkan.BlendOp.ExclusionExt,
|
||||
GAL.AdvancedBlendOp.Contrast => Silk.NET.Vulkan.BlendOp.ContrastExt,
|
||||
GAL.AdvancedBlendOp.Invert => Silk.NET.Vulkan.BlendOp.InvertExt,
|
||||
GAL.AdvancedBlendOp.InvertRGB => Silk.NET.Vulkan.BlendOp.InvertRgbExt,
|
||||
GAL.AdvancedBlendOp.InvertOvg => Silk.NET.Vulkan.BlendOp.InvertOvgExt,
|
||||
GAL.AdvancedBlendOp.LinearDodge => Silk.NET.Vulkan.BlendOp.LineardodgeExt,
|
||||
GAL.AdvancedBlendOp.LinearBurn => Silk.NET.Vulkan.BlendOp.LinearburnExt,
|
||||
GAL.AdvancedBlendOp.VividLight => Silk.NET.Vulkan.BlendOp.VividlightExt,
|
||||
GAL.AdvancedBlendOp.LinearLight => Silk.NET.Vulkan.BlendOp.LinearlightExt,
|
||||
GAL.AdvancedBlendOp.PinLight => Silk.NET.Vulkan.BlendOp.PinlightExt,
|
||||
GAL.AdvancedBlendOp.HardMix => Silk.NET.Vulkan.BlendOp.HardmixExt,
|
||||
GAL.AdvancedBlendOp.Red => Silk.NET.Vulkan.BlendOp.RedExt,
|
||||
GAL.AdvancedBlendOp.Green => Silk.NET.Vulkan.BlendOp.GreenExt,
|
||||
GAL.AdvancedBlendOp.Blue => Silk.NET.Vulkan.BlendOp.BlueExt,
|
||||
GAL.AdvancedBlendOp.HslHue => Silk.NET.Vulkan.BlendOp.HslHueExt,
|
||||
GAL.AdvancedBlendOp.HslSaturation => Silk.NET.Vulkan.BlendOp.HslSaturationExt,
|
||||
GAL.AdvancedBlendOp.HslColor => Silk.NET.Vulkan.BlendOp.HslColorExt,
|
||||
GAL.AdvancedBlendOp.HslLuminosity => Silk.NET.Vulkan.BlendOp.HslLuminosityExt,
|
||||
_ => LogInvalidAndReturn(op, nameof(GAL.AdvancedBlendOp), Silk.NET.Vulkan.BlendOp.Add)
|
||||
};
|
||||
}
|
||||
|
||||
public static Silk.NET.Vulkan.BlendOp Convert(this GAL.BlendOp op)
|
||||
{
|
||||
return op switch
|
||||
@ -92,6 +146,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
};
|
||||
}
|
||||
|
||||
public static Silk.NET.Vulkan.BlendOverlapEXT Convert(this GAL.AdvancedBlendOverlap overlap)
|
||||
{
|
||||
return overlap switch
|
||||
{
|
||||
GAL.AdvancedBlendOverlap.Uncorrelated => Silk.NET.Vulkan.BlendOverlapEXT.UncorrelatedExt,
|
||||
GAL.AdvancedBlendOverlap.Disjoint => Silk.NET.Vulkan.BlendOverlapEXT.DisjointExt,
|
||||
GAL.AdvancedBlendOverlap.Conjoint => Silk.NET.Vulkan.BlendOverlapEXT.ConjointExt,
|
||||
_ => LogInvalidAndReturn(overlap, nameof(GAL.AdvancedBlendOverlap), Silk.NET.Vulkan.BlendOverlapEXT.UncorrelatedExt)
|
||||
};
|
||||
}
|
||||
|
||||
public static Silk.NET.Vulkan.CompareOp Convert(this GAL.CompareOp op)
|
||||
{
|
||||
return op switch
|
||||
|
@ -18,6 +18,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
public readonly bool SupportsIndexTypeUint8;
|
||||
public readonly bool SupportsCustomBorderColor;
|
||||
public readonly bool SupportsBlendEquationAdvanced;
|
||||
public readonly bool SupportsBlendEquationAdvancedCorrelatedOverlap;
|
||||
public readonly bool SupportsBlendEquationAdvancedNonPreMultipliedSrcColor;
|
||||
public readonly bool SupportsBlendEquationAdvancedNonPreMultipliedDstColor;
|
||||
public readonly bool SupportsIndirectParameters;
|
||||
public readonly bool SupportsFragmentShaderInterlock;
|
||||
public readonly bool SupportsGeometryShaderPassthrough;
|
||||
@ -44,6 +48,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public HardwareCapabilities(
|
||||
bool supportsIndexTypeUint8,
|
||||
bool supportsCustomBorderColor,
|
||||
bool supportsBlendEquationAdvanced,
|
||||
bool supportsBlendEquationAdvancedCorrelatedOverlap,
|
||||
bool supportsBlendEquationAdvancedNonPreMultipliedSrcColor,
|
||||
bool supportsBlendEquationAdvancedNonPreMultipliedDstColor,
|
||||
bool supportsIndirectParameters,
|
||||
bool supportsFragmentShaderInterlock,
|
||||
bool supportsGeometryShaderPassthrough,
|
||||
@ -69,6 +77,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
SupportsIndexTypeUint8 = supportsIndexTypeUint8;
|
||||
SupportsCustomBorderColor = supportsCustomBorderColor;
|
||||
SupportsBlendEquationAdvanced = supportsBlendEquationAdvanced;
|
||||
SupportsBlendEquationAdvancedCorrelatedOverlap = supportsBlendEquationAdvancedCorrelatedOverlap;
|
||||
SupportsBlendEquationAdvancedNonPreMultipliedSrcColor = supportsBlendEquationAdvancedNonPreMultipliedSrcColor;
|
||||
SupportsBlendEquationAdvancedNonPreMultipliedDstColor = supportsBlendEquationAdvancedNonPreMultipliedDstColor;
|
||||
SupportsIndirectParameters = supportsIndirectParameters;
|
||||
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
|
||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||
|
@ -112,11 +112,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f };
|
||||
new Span<Vector4<float>>(_renderScale).Fill(defaultScale);
|
||||
|
||||
_newState.Initialize();
|
||||
_newState.LineWidth = 1f;
|
||||
_newState.SamplesCount = 1;
|
||||
_storedBlend = new PipelineColorBlendAttachmentState[Constants.MaxRenderTargets];
|
||||
|
||||
_storedBlend = new PipelineColorBlendAttachmentState[8];
|
||||
_newState.Initialize();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
@ -676,6 +674,49 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
// to avoid creating one version of the shader per reference value used.
|
||||
}
|
||||
|
||||
public void SetBlendState(AdvancedBlendDescriptor blend)
|
||||
{
|
||||
for (int index = 0; index < Constants.MaxRenderTargets; index++)
|
||||
{
|
||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
var blendOp = blend.Op.Convert();
|
||||
|
||||
vkBlend = new PipelineColorBlendAttachmentState(
|
||||
blendEnable: true,
|
||||
colorBlendOp: blendOp,
|
||||
alphaBlendOp: blendOp,
|
||||
colorWriteMask: vkBlend.ColorWriteMask);
|
||||
|
||||
if (Gd.Capabilities.SupportsBlendEquationAdvancedNonPreMultipliedSrcColor)
|
||||
{
|
||||
_newState.AdvancedBlendSrcPreMultiplied = blend.SrcPreMultiplied;
|
||||
}
|
||||
|
||||
if (Gd.Capabilities.SupportsBlendEquationAdvancedCorrelatedOverlap)
|
||||
{
|
||||
_newState.AdvancedBlendOverlap = blend.Overlap.Convert();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vkBlend = new PipelineColorBlendAttachmentState(
|
||||
colorWriteMask: vkBlend.ColorWriteMask);
|
||||
}
|
||||
|
||||
if (vkBlend.ColorWriteMask == 0)
|
||||
{
|
||||
_storedBlend[index] = vkBlend;
|
||||
|
||||
vkBlend = new PipelineColorBlendAttachmentState();
|
||||
}
|
||||
}
|
||||
|
||||
SignalStateChange();
|
||||
}
|
||||
|
||||
public void SetBlendState(int index, BlendDescriptor blend)
|
||||
{
|
||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
|
||||
@ -709,6 +750,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
blend.BlendConstant.Blue,
|
||||
blend.BlendConstant.Alpha);
|
||||
|
||||
// Reset advanced blend state back defaults to the cache to help the pipeline cache.
|
||||
_newState.AdvancedBlendSrcPreMultiplied = true;
|
||||
_newState.AdvancedBlendDstPreMultiplied = true;
|
||||
_newState.AdvancedBlendOverlap = BlendOverlapEXT.UncorrelatedExt;
|
||||
|
||||
SignalStateChange();
|
||||
}
|
||||
|
||||
|
@ -285,6 +285,24 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1);
|
||||
}
|
||||
|
||||
public bool AdvancedBlendSrcPreMultiplied
|
||||
{
|
||||
get => ((Internal.Id9 >> 2) & 0x1) != 0UL;
|
||||
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2);
|
||||
}
|
||||
|
||||
public bool AdvancedBlendDstPreMultiplied
|
||||
{
|
||||
get => ((Internal.Id9 >> 3) & 0x1) != 0UL;
|
||||
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3);
|
||||
}
|
||||
|
||||
public BlendOverlapEXT AdvancedBlendOverlap
|
||||
{
|
||||
get => (BlendOverlapEXT)((Internal.Id9 >> 4) & 0x3);
|
||||
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4);
|
||||
}
|
||||
|
||||
public NativeArray<PipelineShaderStageCreateInfo> Stages;
|
||||
public NativeArray<PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT> StageRequiredSubgroupSizes;
|
||||
public PipelineLayout PipelineLayout;
|
||||
@ -303,6 +321,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
RequiredSubgroupSize = RequiredSubgroupSize
|
||||
};
|
||||
}
|
||||
|
||||
AdvancedBlendSrcPreMultiplied = true;
|
||||
AdvancedBlendDstPreMultiplied = true;
|
||||
AdvancedBlendOverlap = BlendOverlapEXT.UncorrelatedExt;
|
||||
|
||||
LineWidth = 1f;
|
||||
SamplesCount = 1;
|
||||
}
|
||||
|
||||
public unsafe Auto<DisposablePipeline> CreateComputePipeline(
|
||||
@ -486,6 +511,23 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PAttachments = pColorBlendAttachmentState
|
||||
};
|
||||
|
||||
PipelineColorBlendAdvancedStateCreateInfoEXT colorBlendAdvancedState;
|
||||
|
||||
if (!AdvancedBlendSrcPreMultiplied ||
|
||||
!AdvancedBlendDstPreMultiplied ||
|
||||
AdvancedBlendOverlap != BlendOverlapEXT.UncorrelatedExt)
|
||||
{
|
||||
colorBlendAdvancedState = new PipelineColorBlendAdvancedStateCreateInfoEXT()
|
||||
{
|
||||
SType = StructureType.PipelineColorBlendAdvancedStateCreateInfoExt,
|
||||
SrcPremultiplied = AdvancedBlendSrcPreMultiplied,
|
||||
DstPremultiplied = AdvancedBlendDstPreMultiplied,
|
||||
BlendOverlap = AdvancedBlendOverlap
|
||||
};
|
||||
|
||||
colorBlendState.PNext = &colorBlendAdvancedState;
|
||||
}
|
||||
|
||||
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
|
||||
int dynamicStatesCount = supportsExtDynamicState ? 9 : 8;
|
||||
|
||||
|
@ -27,6 +27,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ExtTransformFeedback.ExtensionName,
|
||||
KhrDrawIndirectCount.ExtensionName,
|
||||
KhrPushDescriptor.ExtensionName,
|
||||
"VK_EXT_blend_operation_advanced",
|
||||
"VK_EXT_custom_border_color",
|
||||
"VK_EXT_descriptor_indexing", // Enabling this works around an issue with disposed buffer bindings on RADV.
|
||||
"VK_EXT_fragment_shader_interlock",
|
||||
|
@ -149,6 +149,19 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SType = StructureType.PhysicalDeviceProperties2
|
||||
};
|
||||
|
||||
PhysicalDeviceBlendOperationAdvancedPropertiesEXT propertiesBlendOperationAdvanced = new PhysicalDeviceBlendOperationAdvancedPropertiesEXT()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceBlendOperationAdvancedPropertiesExt
|
||||
};
|
||||
|
||||
bool supportsBlendOperationAdvanced = supportedExtensions.Contains("VK_EXT_blend_operation_advanced");
|
||||
|
||||
if (supportsBlendOperationAdvanced)
|
||||
{
|
||||
propertiesBlendOperationAdvanced.PNext = properties2.PNext;
|
||||
properties2.PNext = &propertiesBlendOperationAdvanced;
|
||||
}
|
||||
|
||||
PhysicalDeviceSubgroupSizeControlPropertiesEXT propertiesSubgroupSizeControl = new PhysicalDeviceSubgroupSizeControlPropertiesEXT()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceSubgroupSizeControlPropertiesExt
|
||||
@ -246,9 +259,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
portabilityFlags |= featuresPortabilitySubset.SamplerMipLodBias ? 0 : PortabilitySubsetFlags.NoLodBias;
|
||||
}
|
||||
|
||||
bool customBorderColorSupported = supportedExtensions.Contains("VK_EXT_custom_border_color") &&
|
||||
featuresCustomBorderColor.CustomBorderColors &&
|
||||
featuresCustomBorderColor.CustomBorderColorWithoutFormat;
|
||||
bool supportsCustomBorderColor = supportedExtensions.Contains("VK_EXT_custom_border_color") &&
|
||||
featuresCustomBorderColor.CustomBorderColors &&
|
||||
featuresCustomBorderColor.CustomBorderColorWithoutFormat;
|
||||
|
||||
ref var properties = ref properties2.Properties;
|
||||
|
||||
@ -259,7 +272,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
Capabilities = new HardwareCapabilities(
|
||||
supportedExtensions.Contains("VK_EXT_index_type_uint8"),
|
||||
customBorderColorSupported,
|
||||
supportsCustomBorderColor,
|
||||
supportsBlendOperationAdvanced,
|
||||
propertiesBlendOperationAdvanced.AdvancedBlendCorrelatedOverlap,
|
||||
propertiesBlendOperationAdvanced.AdvancedBlendNonPremultipliedSrcColor,
|
||||
propertiesBlendOperationAdvanced.AdvancedBlendNonPremultipliedDstColor,
|
||||
supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName),
|
||||
supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"),
|
||||
supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"),
|
||||
@ -526,6 +543,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
supportsR4G4B4A4Format: supportsR4G4B4A4Format,
|
||||
supportsSnormBufferTextureFormat: true,
|
||||
supports5BitComponentFormat: supports5BitComponentFormat,
|
||||
supportsBlendEquationAdvanced: Capabilities.SupportsBlendEquationAdvanced,
|
||||
supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock,
|
||||
supportsFragmentShaderOrderingIntel: false,
|
||||
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
||||
|
Reference in New Issue
Block a user