Workaround AMD bug on logic op with float framebuffer (#6852)

* Workaround AMD bug on logic op with float framebuffer

* Format whitespace

* Update comment
This commit is contained in:
gdkchan 2024-05-23 01:05:32 -03:00 committed by GitHub
parent c1ed150949
commit e65effcb05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 55 additions and 3 deletions

View file

@ -711,5 +711,36 @@ namespace Ryujinx.Graphics.GAL
{ {
return format.IsUint() || format.IsSint(); return format.IsUint() || format.IsSint();
} }
/// <summary>
/// Checks if the texture format is a float or sRGB color format.
/// </summary>
/// <remarks>
/// Does not include normalized, compressed or depth formats.
/// Float and sRGB formats do not participate in logical operations.
/// </remarks>
/// <param name="format">Texture format</param>
/// <returns>True if the format is a float or sRGB color format, false otherwise</returns>
public static bool IsFloatOrSrgb(this Format format)
{
switch (format)
{
case Format.R8G8B8A8Srgb:
case Format.B8G8R8A8Srgb:
case Format.R16Float:
case Format.R16G16Float:
case Format.R16G16B16Float:
case Format.R16G16B16A16Float:
case Format.R32Float:
case Format.R32G32Float:
case Format.R32G32B32Float:
case Format.R32G32B32A32Float:
case Format.R11G11B10Float:
case Format.R9G9B9E5Float:
return true;
}
return false;
}
} }
} }

View file

@ -24,6 +24,7 @@ namespace Ryujinx.Graphics.Vulkan
public VkFormat[] AttachmentFormats { get; } public VkFormat[] AttachmentFormats { get; }
public int[] AttachmentIndices { get; } public int[] AttachmentIndices { get; }
public uint AttachmentIntegerFormatMask { get; } public uint AttachmentIntegerFormatMask { get; }
public bool LogicOpsAllowed { get; }
public int AttachmentsCount { get; } public int AttachmentsCount { get; }
public int MaxColorAttachmentIndex => AttachmentIndices.Length > 0 ? AttachmentIndices[^1] : -1; public int MaxColorAttachmentIndex => AttachmentIndices.Length > 0 ? AttachmentIndices[^1] : -1;
@ -32,7 +33,9 @@ namespace Ryujinx.Graphics.Vulkan
public FramebufferParams(Device device, TextureView view, uint width, uint height) public FramebufferParams(Device device, TextureView view, uint width, uint height)
{ {
bool isDepthStencil = view.Info.Format.IsDepthOrStencil(); var format = view.Info.Format;
bool isDepthStencil = format.IsDepthOrStencil();
_device = device; _device = device;
_attachments = new[] { view.GetImageViewForAttachment() }; _attachments = new[] { view.GetImageViewForAttachment() };
@ -56,6 +59,8 @@ namespace Ryujinx.Graphics.Vulkan
AttachmentSamples = new[] { (uint)view.Info.Samples }; AttachmentSamples = new[] { (uint)view.Info.Samples };
AttachmentFormats = new[] { view.VkFormat }; AttachmentFormats = new[] { view.VkFormat };
AttachmentIndices = isDepthStencil ? Array.Empty<int>() : new[] { 0 }; AttachmentIndices = isDepthStencil ? Array.Empty<int>() : new[] { 0 };
AttachmentIntegerFormatMask = format.IsInteger() ? 1u : 0u;
LogicOpsAllowed = !format.IsFloatOrSrgb();
AttachmentsCount = 1; AttachmentsCount = 1;
@ -85,6 +90,7 @@ namespace Ryujinx.Graphics.Vulkan
int index = 0; int index = 0;
int bindIndex = 0; int bindIndex = 0;
uint attachmentIntegerFormatMask = 0; uint attachmentIntegerFormatMask = 0;
bool allFormatsFloatOrSrgb = colorsCount != 0;
foreach (ITexture color in colors) foreach (ITexture color in colors)
{ {
@ -101,11 +107,15 @@ namespace Ryujinx.Graphics.Vulkan
AttachmentFormats[index] = texture.VkFormat; AttachmentFormats[index] = texture.VkFormat;
AttachmentIndices[index] = bindIndex; AttachmentIndices[index] = bindIndex;
if (texture.Info.Format.IsInteger()) var format = texture.Info.Format;
if (format.IsInteger())
{ {
attachmentIntegerFormatMask |= 1u << bindIndex; attachmentIntegerFormatMask |= 1u << bindIndex;
} }
allFormatsFloatOrSrgb &= format.IsFloatOrSrgb();
width = Math.Min(width, (uint)texture.Width); width = Math.Min(width, (uint)texture.Width);
height = Math.Min(height, (uint)texture.Height); height = Math.Min(height, (uint)texture.Height);
layers = Math.Min(layers, (uint)texture.Layers); layers = Math.Min(layers, (uint)texture.Layers);
@ -120,6 +130,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
AttachmentIntegerFormatMask = attachmentIntegerFormatMask; AttachmentIntegerFormatMask = attachmentIntegerFormatMask;
LogicOpsAllowed = !allFormatsFloatOrSrgb;
if (depthStencil is TextureView dsTexture && dsTexture.Valid) if (depthStencil is TextureView dsTexture && dsTexture.Valid)
{ {

View file

@ -1498,6 +1498,7 @@ namespace Ryujinx.Graphics.Vulkan
var dstAttachmentFormats = _newState.Internal.AttachmentFormats.AsSpan(); var dstAttachmentFormats = _newState.Internal.AttachmentFormats.AsSpan();
FramebufferParams.AttachmentFormats.CopyTo(dstAttachmentFormats); FramebufferParams.AttachmentFormats.CopyTo(dstAttachmentFormats);
_newState.Internal.AttachmentIntegerFormatMask = FramebufferParams.AttachmentIntegerFormatMask; _newState.Internal.AttachmentIntegerFormatMask = FramebufferParams.AttachmentIntegerFormatMask;
_newState.Internal.LogicOpsAllowed = FramebufferParams.LogicOpsAllowed;
for (int i = FramebufferParams.AttachmentFormats.Length; i < dstAttachmentFormats.Length; i++) for (int i = FramebufferParams.AttachmentFormats.Length; i < dstAttachmentFormats.Length; i++)
{ {

View file

@ -302,6 +302,7 @@ namespace Ryujinx.Graphics.Vulkan
int attachmentCount = 0; int attachmentCount = 0;
int maxColorAttachmentIndex = -1; int maxColorAttachmentIndex = -1;
uint attachmentIntegerFormatMask = 0; uint attachmentIntegerFormatMask = 0;
bool allFormatsFloatOrSrgb = true;
for (int i = 0; i < Constants.MaxRenderTargets; i++) for (int i = 0; i < Constants.MaxRenderTargets; i++)
{ {
@ -314,6 +315,8 @@ namespace Ryujinx.Graphics.Vulkan
{ {
attachmentIntegerFormatMask |= 1u << i; attachmentIntegerFormatMask |= 1u << i;
} }
allFormatsFloatOrSrgb &= state.AttachmentFormats[i].IsFloatOrSrgb();
} }
} }
@ -325,6 +328,7 @@ namespace Ryujinx.Graphics.Vulkan
pipeline.ColorBlendAttachmentStateCount = (uint)(maxColorAttachmentIndex + 1); pipeline.ColorBlendAttachmentStateCount = (uint)(maxColorAttachmentIndex + 1);
pipeline.VertexAttributeDescriptionsCount = (uint)Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount); pipeline.VertexAttributeDescriptionsCount = (uint)Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount);
pipeline.Internal.AttachmentIntegerFormatMask = attachmentIntegerFormatMask; pipeline.Internal.AttachmentIntegerFormatMask = attachmentIntegerFormatMask;
pipeline.Internal.LogicOpsAllowed = attachmentCount == 0 || !allFormatsFloatOrSrgb;
return pipeline; return pipeline;
} }

View file

@ -560,10 +560,14 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
// AMD has a bug where it enables logical operations even for float formats,
// so we need to force disable them here.
bool logicOpEnable = LogicOpEnable && (gd.Vendor != Vendor.Amd || Internal.LogicOpsAllowed);
var colorBlendState = new PipelineColorBlendStateCreateInfo var colorBlendState = new PipelineColorBlendStateCreateInfo
{ {
SType = StructureType.PipelineColorBlendStateCreateInfo, SType = StructureType.PipelineColorBlendStateCreateInfo,
LogicOpEnable = LogicOpEnable, LogicOpEnable = logicOpEnable,
LogicOp = LogicOp, LogicOp = LogicOp,
AttachmentCount = ColorBlendAttachmentStateCount, AttachmentCount = ColorBlendAttachmentStateCount,
PAttachments = pColorBlendAttachmentState, PAttachments = pColorBlendAttachmentState,

View file

@ -34,6 +34,7 @@ namespace Ryujinx.Graphics.Vulkan
public Array8<PipelineColorBlendAttachmentState> ColorBlendAttachmentState; public Array8<PipelineColorBlendAttachmentState> ColorBlendAttachmentState;
public Array9<Format> AttachmentFormats; public Array9<Format> AttachmentFormats;
public uint AttachmentIntegerFormatMask; public uint AttachmentIntegerFormatMask;
public bool LogicOpsAllowed;
public readonly override bool Equals(object obj) public readonly override bool Equals(object obj)
{ {