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:
parent
c1ed150949
commit
e65effcb05
6 changed files with 55 additions and 3 deletions
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue