Skip to content

Commit

Permalink
Workaround AMD bug on logic op with float framebuffer (#6852)
Browse files Browse the repository at this point in the history
* Workaround AMD bug on logic op with float framebuffer

* Format whitespace

* Update comment
  • Loading branch information
gdkchan committed May 23, 2024
1 parent c1ed150 commit e65effc
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 3 deletions.
31 changes: 31 additions & 0 deletions src/Ryujinx.Graphics.GAL/Format.cs
Original file line number Diff line number Diff line change
Expand Up @@ -711,5 +711,36 @@ public static bool IsInteger(this Format format)
{
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;
}
}
}
15 changes: 13 additions & 2 deletions src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class FramebufferParams
public VkFormat[] AttachmentFormats { get; }
public int[] AttachmentIndices { get; }
public uint AttachmentIntegerFormatMask { get; }
public bool LogicOpsAllowed { get; }

public int AttachmentsCount { get; }
public int MaxColorAttachmentIndex => AttachmentIndices.Length > 0 ? AttachmentIndices[^1] : -1;
Expand All @@ -32,7 +33,9 @@ class FramebufferParams

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;
_attachments = new[] { view.GetImageViewForAttachment() };
Expand All @@ -56,6 +59,8 @@ public FramebufferParams(Device device, TextureView view, uint width, uint heigh
AttachmentSamples = new[] { (uint)view.Info.Samples };
AttachmentFormats = new[] { view.VkFormat };
AttachmentIndices = isDepthStencil ? Array.Empty<int>() : new[] { 0 };
AttachmentIntegerFormatMask = format.IsInteger() ? 1u : 0u;
LogicOpsAllowed = !format.IsFloatOrSrgb();

AttachmentsCount = 1;

Expand Down Expand Up @@ -85,6 +90,7 @@ public FramebufferParams(Device device, ITexture[] colors, ITexture depthStencil
int index = 0;
int bindIndex = 0;
uint attachmentIntegerFormatMask = 0;
bool allFormatsFloatOrSrgb = colorsCount != 0;

foreach (ITexture color in colors)
{
Expand All @@ -101,11 +107,15 @@ public FramebufferParams(Device device, ITexture[] colors, ITexture depthStencil
AttachmentFormats[index] = texture.VkFormat;
AttachmentIndices[index] = bindIndex;

if (texture.Info.Format.IsInteger())
var format = texture.Info.Format;

if (format.IsInteger())
{
attachmentIntegerFormatMask |= 1u << bindIndex;
}

allFormatsFloatOrSrgb &= format.IsFloatOrSrgb();

width = Math.Min(width, (uint)texture.Width);
height = Math.Min(height, (uint)texture.Height);
layers = Math.Min(layers, (uint)texture.Layers);
Expand All @@ -120,6 +130,7 @@ public FramebufferParams(Device device, ITexture[] colors, ITexture depthStencil
}

AttachmentIntegerFormatMask = attachmentIntegerFormatMask;
LogicOpsAllowed = !allFormatsFloatOrSrgb;

if (depthStencil is TextureView dsTexture && dsTexture.Valid)
{
Expand Down
1 change: 1 addition & 0 deletions src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1498,6 +1498,7 @@ protected void UpdatePipelineAttachmentFormats()
var dstAttachmentFormats = _newState.Internal.AttachmentFormats.AsSpan();
FramebufferParams.AttachmentFormats.CopyTo(dstAttachmentFormats);
_newState.Internal.AttachmentIntegerFormatMask = FramebufferParams.AttachmentIntegerFormatMask;
_newState.Internal.LogicOpsAllowed = FramebufferParams.LogicOpsAllowed;

for (int i = FramebufferParams.AttachmentFormats.Length; i < dstAttachmentFormats.Length; i++)
{
Expand Down
4 changes: 4 additions & 0 deletions src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ public static PipelineState ToVulkanPipelineState(this ProgramPipelineState stat
int attachmentCount = 0;
int maxColorAttachmentIndex = -1;
uint attachmentIntegerFormatMask = 0;
bool allFormatsFloatOrSrgb = true;

for (int i = 0; i < Constants.MaxRenderTargets; i++)
{
Expand All @@ -314,6 +315,8 @@ public static PipelineState ToVulkanPipelineState(this ProgramPipelineState stat
{
attachmentIntegerFormatMask |= 1u << i;
}

allFormatsFloatOrSrgb &= state.AttachmentFormats[i].IsFloatOrSrgb();
}
}

Expand All @@ -325,6 +328,7 @@ public static PipelineState ToVulkanPipelineState(this ProgramPipelineState stat
pipeline.ColorBlendAttachmentStateCount = (uint)(maxColorAttachmentIndex + 1);
pipeline.VertexAttributeDescriptionsCount = (uint)Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount);
pipeline.Internal.AttachmentIntegerFormatMask = attachmentIntegerFormatMask;
pipeline.Internal.LogicOpsAllowed = attachmentCount == 0 || !allFormatsFloatOrSrgb;

return pipeline;
}
Expand Down
6 changes: 5 additions & 1 deletion src/Ryujinx.Graphics.Vulkan/PipelineState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -560,10 +560,14 @@ public void Initialize()
}
}

// 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
{
SType = StructureType.PipelineColorBlendStateCreateInfo,
LogicOpEnable = LogicOpEnable,
LogicOpEnable = logicOpEnable,
LogicOp = LogicOp,
AttachmentCount = ColorBlendAttachmentStateCount,
PAttachments = pColorBlendAttachmentState,
Expand Down
1 change: 1 addition & 0 deletions src/Ryujinx.Graphics.Vulkan/PipelineUid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct PipelineUid : IRefEquatable<PipelineUid>
public Array8<PipelineColorBlendAttachmentState> ColorBlendAttachmentState;
public Array9<Format> AttachmentFormats;
public uint AttachmentIntegerFormatMask;
public bool LogicOpsAllowed;

public readonly override bool Equals(object obj)
{
Expand Down

0 comments on commit e65effc

Please sign in to comment.