aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.GAL/IPipeline.cs2
-rw-r--r--Ryujinx.Graphics.GAL/MultisampleDescriptor.cs19
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs2
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/CommandType.cs1
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/Commands/SetMultisampleStateCommand.cs18
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs6
-rw-r--r--Ryujinx.Graphics.GAL/SupportBufferUpdater.cs1
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs24
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs8
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/Cache/Migration.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs22
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs8
-rw-r--r--Ryujinx.Graphics.OpenGL/HwCapabilities.cs54
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs28
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs2
-rw-r--r--Ryujinx.Graphics.Shader/IGpuAccessor.cs9
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContext.cs31
20 files changed, 217 insertions, 34 deletions
diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs
index 83afcaa3..da04362d 100644
--- a/Ryujinx.Graphics.GAL/IPipeline.cs
+++ b/Ryujinx.Graphics.GAL/IPipeline.cs
@@ -60,6 +60,8 @@ namespace Ryujinx.Graphics.GAL
void SetLogicOpState(bool enable, LogicalOp op);
+ void SetMultisampleState(MultisampleDescriptor multisample);
+
void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel);
void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin);
diff --git a/Ryujinx.Graphics.GAL/MultisampleDescriptor.cs b/Ryujinx.Graphics.GAL/MultisampleDescriptor.cs
new file mode 100644
index 00000000..76e56987
--- /dev/null
+++ b/Ryujinx.Graphics.GAL/MultisampleDescriptor.cs
@@ -0,0 +1,19 @@
+namespace Ryujinx.Graphics.GAL
+{
+ public struct MultisampleDescriptor
+ {
+ public bool AlphaToCoverageEnable { get; }
+ public bool AlphaToCoverageDitherEnable { get; }
+ public bool AlphaToOneEnable { get; }
+
+ public MultisampleDescriptor(
+ bool alphaToCoverageEnable,
+ bool alphaToCoverageDitherEnable,
+ bool alphaToOneEnable)
+ {
+ AlphaToCoverageEnable = alphaToCoverageEnable;
+ AlphaToCoverageDitherEnable = alphaToCoverageDitherEnable;
+ AlphaToOneEnable = alphaToOneEnable;
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs b/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs
index 442a9045..95b33bc6 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs
@@ -179,6 +179,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading
SetLineParametersCommand.Run(ref GetCommand<SetLineParametersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetLogicOpState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetLogicOpStateCommand.Run(ref GetCommand<SetLogicOpStateCommand>(memory), threaded, renderer);
+ _lookup[(int)CommandType.SetMultisampleState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
+ SetMultisampleStateCommand.Run(ref GetCommand<SetMultisampleStateCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetPatchParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetPatchParametersCommand.Run(ref GetCommand<SetPatchParametersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetPointParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
diff --git a/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs b/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs
index 5c42abd1..8f0a0095 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs
@@ -71,6 +71,7 @@
SetIndexBuffer,
SetLineParameters,
SetLogicOpState,
+ SetMultisampleState,
SetPatchParameters,
SetPointParameters,
SetPolygonMode,
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetMultisampleStateCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetMultisampleStateCommand.cs
new file mode 100644
index 00000000..f981c6ce
--- /dev/null
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetMultisampleStateCommand.cs
@@ -0,0 +1,18 @@
+namespace Ryujinx.Graphics.GAL.Multithreading.Commands
+{
+ struct SetMultisampleStateCommand : IGALCommand
+ {
+ public CommandType CommandType => CommandType.SetMultisampleState;
+ private MultisampleDescriptor _multisample;
+
+ public void Set(MultisampleDescriptor multisample)
+ {
+ _multisample = multisample;
+ }
+
+ public static void Run(ref SetMultisampleStateCommand command, ThreadedRenderer threaded, IRenderer renderer)
+ {
+ renderer.Pipeline.SetMultisampleState(command._multisample);
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
index 2a1f474a..aebf210d 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
@@ -184,6 +184,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand();
}
+ public void SetMultisampleState(MultisampleDescriptor multisample)
+ {
+ _renderer.New<SetMultisampleStateCommand>().Set(multisample);
+ _renderer.QueueCommand();
+ }
+
public void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel)
{
_renderer.New<SetPatchParametersCommand>().Set(vertices, defaultOuterLevel, defaultInnerLevel);
diff --git a/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs b/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs
index da7a2461..5d73b45a 100644
--- a/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs
+++ b/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs
@@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.GAL
{
_renderer = renderer;
Handle = renderer.CreateBuffer(SupportBuffer.RequiredSize);
+ renderer.Pipeline.ClearBuffer(Handle, 0, SupportBuffer.RequiredSize, 0);
}
private void MarkDirty(int startOffset, int byteSize)
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index c64c760a..2f5d4fc5 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -166,7 +166,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
nameof(ThreedClassState.BlendEnable),
nameof(ThreedClassState.BlendState)),
- new StateUpdateCallbackEntry(UpdateLogicOpState, nameof(ThreedClassState.LogicOpState))
+ new StateUpdateCallbackEntry(UpdateLogicOpState, nameof(ThreedClassState.LogicOpState)),
+
+ new StateUpdateCallbackEntry(UpdateMultisampleState,
+ nameof(ThreedClassState.AlphaToCoverageDitherEnable),
+ nameof(ThreedClassState.MultisampleControl))
});
}
@@ -1093,6 +1097,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
/// <summary>
+ /// Updates multisample state, based on guest state.
+ /// </summary>
+ private void UpdateMultisampleState()
+ {
+ bool alphaToCoverageEnable = (_state.State.MultisampleControl & 1) != 0;
+ bool alphaToOneEnable = (_state.State.MultisampleControl & 0x10) != 0;
+
+ _context.Renderer.Pipeline.SetMultisampleState(new MultisampleDescriptor(
+ alphaToCoverageEnable,
+ _state.State.AlphaToCoverageDitherEnable,
+ alphaToOneEnable));
+ }
+
+ /// <summary>
/// Updates host shaders based on the guest GPU state.
/// </summary>
private void UpdateShaderState()
@@ -1231,7 +1249,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.EarlyZForce,
_drawState.Topology,
_state.State.TessMode,
- _state.State.ViewportTransformEnable == 0);
+ _state.State.ViewportTransformEnable == 0,
+ (_state.State.MultisampleControl & 1) != 0,
+ _state.State.AlphaToCoverageDitherEnable);
}
/// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
index 81a22831..2a831356 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
@@ -767,7 +767,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
public SamplerIndex SamplerIndex;
public fixed uint Reserved1238[37];
public Boolean32 DepthTestEnable;
- public fixed uint Reserved12D0[5];
+ public fixed uint Reserved12D0[4];
+ public Boolean32 AlphaToCoverageDitherEnable;
public Boolean32 BlendIndependent;
public Boolean32 DepthWriteEnable;
public Boolean32 AlphaTestEnable;
@@ -802,9 +803,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
public Boolean32 PointSpriteEnable;
public fixed uint Reserved1524[3];
public uint ResetCounter;
- public uint Reserved1534;
+ public Boolean32 MultisampleEnable;
public Boolean32 RtDepthStencilEnable;
- public fixed uint Reserved153C[5];
+ public uint MultisampleControl;
+ public fixed uint Reserved1540[4];
public GpuVa RenderEnableAddress;
public Condition RenderEnableCondition;
public PoolState SamplerPoolState;
diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Migration.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Migration.cs
index 4de6eff9..885bcd09 100644
--- a/Ryujinx.Graphics.Gpu/Shader/Cache/Migration.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Migration.cs
@@ -167,6 +167,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
accessorHeader.StateFlags.HasFlag(GuestGpuStateFlags.EarlyZForce),
topology,
tessMode,
+ false,
+ false,
false);
TransformFeedbackDescriptor[] tfdNew = null;
diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs
index bc63f714..e5476426 100644
--- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs
@@ -68,6 +68,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
}
/// <inheritdoc/>
+ public bool QueryAlphaToCoverageDitherEnable()
+ {
+ return _oldSpecState.GraphicsState.AlphaToCoverageEnable && _oldSpecState.GraphicsState.AlphaToCoverageDitherEnable;
+ }
+
+ /// <inheritdoc/>
public int QueryBindingConstantBuffer(int index)
{
return _resourceCounts.UniformBuffersCount++;
diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index 59801001..37b25793 100644
--- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 1;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
- private const uint CodeGenVersion = 3424;
+ private const uint CodeGenVersion = 3069;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";
diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
index 5cd966af..5317aab9 100644
--- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
@@ -67,6 +67,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
}
/// <inheritdoc/>
+ public bool QueryAlphaToCoverageDitherEnable()
+ {
+ return _state.GraphicsState.AlphaToCoverageEnable && _state.GraphicsState.AlphaToCoverageDitherEnable;
+ }
+
+ /// <inheritdoc/>
public int QueryBindingConstantBuffer(int index)
{
return _state.ResourceCounts.UniformBuffersCount++;
diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs b/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs
index 92ec117f..fae670ea 100644
--- a/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs
@@ -31,18 +31,38 @@ namespace Ryujinx.Graphics.Gpu.Shader
public readonly bool ViewportTransformDisable;
/// <summary>
+ /// Indicates whenever alpha-to-coverage is enabled.
+ /// </summary>
+ public readonly bool AlphaToCoverageEnable;
+
+ /// <summary>
+ /// Indicates whenever alpha-to-coverage dithering is enabled.
+ /// </summary>
+ public readonly bool AlphaToCoverageDitherEnable;
+
+ /// <summary>
/// Creates a new GPU graphics state.
/// </summary>
/// <param name="earlyZForce">Early Z force enable</param>
/// <param name="topology">Primitive topology</param>
/// <param name="tessellationMode">Tessellation mode</param>
/// <param name="viewportTransformDisable">Indicates whenever the viewport transform is disabled</param>
- public GpuChannelGraphicsState(bool earlyZForce, PrimitiveTopology topology, TessMode tessellationMode, bool viewportTransformDisable)
+ /// <param name="alphaToCoverageEnable">Indicates whenever alpha-to-coverage is enabled</param>
+ /// <param name="alphaToCoverageDitherEnable">Indicates whenever alpha-to-coverage dithering is enabled</param>
+ public GpuChannelGraphicsState(
+ bool earlyZForce,
+ PrimitiveTopology topology,
+ TessMode tessellationMode,
+ bool viewportTransformDisable,
+ bool alphaToCoverageEnable,
+ bool alphaToCoverageDitherEnable)
{
EarlyZForce = earlyZForce;
Topology = topology;
TessellationMode = tessellationMode;
ViewportTransformDisable = viewportTransformDisable;
+ AlphaToCoverageEnable = alphaToCoverageEnable;
+ AlphaToCoverageDitherEnable = alphaToCoverageDitherEnable;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs
index 587d60a7..7e39c8a3 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs
@@ -455,6 +455,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
return false;
}
+ bool thisA2cDitherEnable = GraphicsState.AlphaToCoverageEnable && GraphicsState.AlphaToCoverageDitherEnable;
+ bool otherA2cDitherEnable = graphicsState.AlphaToCoverageEnable && graphicsState.AlphaToCoverageDitherEnable;
+
+ if (otherA2cDitherEnable != thisA2cDitherEnable)
+ {
+ return false;
+ }
+
return Matches(channel, poolState, checkTextures, isCompute: false);
}
diff --git a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
index 773c9f63..13b5b412 100644
--- a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
+++ b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
@@ -5,19 +5,20 @@ namespace Ryujinx.Graphics.OpenGL
{
static class HwCapabilities
{
- private static readonly Lazy<bool> _supportsAstcCompression = new Lazy<bool>(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
- private static readonly Lazy<bool> _supportsDrawTexture = new Lazy<bool>(() => HasExtension("GL_NV_draw_texture"));
- private static readonly Lazy<bool> _supportsFragmentShaderInterlock = new Lazy<bool>(() => HasExtension("GL_ARB_fragment_shader_interlock"));
- private static readonly Lazy<bool> _supportsFragmentShaderOrdering = new Lazy<bool>(() => HasExtension("GL_INTEL_fragment_shader_ordering"));
- private static readonly Lazy<bool> _supportsImageLoadFormatted = new Lazy<bool>(() => HasExtension("GL_EXT_shader_image_load_formatted"));
- private static readonly Lazy<bool> _supportsIndirectParameters = new Lazy<bool>(() => HasExtension("GL_ARB_indirect_parameters"));
- private static readonly Lazy<bool> _supportsParallelShaderCompile = new Lazy<bool>(() => HasExtension("GL_ARB_parallel_shader_compile"));
- private static readonly Lazy<bool> _supportsPolygonOffsetClamp = new Lazy<bool>(() => HasExtension("GL_EXT_polygon_offset_clamp"));
- private static readonly Lazy<bool> _supportsQuads = new Lazy<bool>(SupportsQuadsCheck);
- private static readonly Lazy<bool> _supportsSeamlessCubemapPerTexture = new Lazy<bool>(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
- private static readonly Lazy<bool> _supportsShaderBallot = new Lazy<bool>(() => HasExtension("GL_ARB_shader_ballot"));
- private static readonly Lazy<bool> _supportsTextureShadowLod = new Lazy<bool>(() => HasExtension("GL_EXT_texture_shadow_lod"));
- private static readonly Lazy<bool> _supportsViewportSwizzle = new Lazy<bool>(() => HasExtension("GL_NV_viewport_swizzle"));
+ private static readonly Lazy<bool> _supportsAlphaToCoverageDitherControl = new Lazy<bool>(() => HasExtension("GL_NV_alpha_to_coverage_dither_control"));
+ private static readonly Lazy<bool> _supportsAstcCompression = new Lazy<bool>(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
+ private static readonly Lazy<bool> _supportsDrawTexture = new Lazy<bool>(() => HasExtension("GL_NV_draw_texture"));
+ private static readonly Lazy<bool> _supportsFragmentShaderInterlock = new Lazy<bool>(() => HasExtension("GL_ARB_fragment_shader_interlock"));
+ private static readonly Lazy<bool> _supportsFragmentShaderOrdering = new Lazy<bool>(() => HasExtension("GL_INTEL_fragment_shader_ordering"));
+ private static readonly Lazy<bool> _supportsImageLoadFormatted = new Lazy<bool>(() => HasExtension("GL_EXT_shader_image_load_formatted"));
+ private static readonly Lazy<bool> _supportsIndirectParameters = new Lazy<bool>(() => HasExtension("GL_ARB_indirect_parameters"));
+ private static readonly Lazy<bool> _supportsParallelShaderCompile = new Lazy<bool>(() => HasExtension("GL_ARB_parallel_shader_compile"));
+ private static readonly Lazy<bool> _supportsPolygonOffsetClamp = new Lazy<bool>(() => HasExtension("GL_EXT_polygon_offset_clamp"));
+ private static readonly Lazy<bool> _supportsQuads = new Lazy<bool>(SupportsQuadsCheck);
+ private static readonly Lazy<bool> _supportsSeamlessCubemapPerTexture = new Lazy<bool>(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
+ private static readonly Lazy<bool> _supportsShaderBallot = new Lazy<bool>(() => HasExtension("GL_ARB_shader_ballot"));
+ private static readonly Lazy<bool> _supportsTextureShadowLod = new Lazy<bool>(() => HasExtension("GL_EXT_texture_shadow_lod"));
+ private static readonly Lazy<bool> _supportsViewportSwizzle = new Lazy<bool>(() => HasExtension("GL_NV_viewport_swizzle"));
private static readonly Lazy<int> _maximumComputeSharedMemorySize = new Lazy<int>(() => GetLimit(All.MaxComputeSharedMemorySize));
private static readonly Lazy<int> _storageBufferOffsetAlignment = new Lazy<int>(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
@@ -43,19 +44,20 @@ namespace Ryujinx.Graphics.OpenGL
public static bool UsePersistentBufferForFlush => _gpuVendor.Value == GpuVendor.AmdWindows || _gpuVendor.Value == GpuVendor.Nvidia;
- public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
- public static bool SupportsDrawTexture => _supportsDrawTexture.Value;
- public static bool SupportsFragmentShaderInterlock => _supportsFragmentShaderInterlock.Value;
- public static bool SupportsFragmentShaderOrdering => _supportsFragmentShaderOrdering.Value;
- public static bool SupportsImageLoadFormatted => _supportsImageLoadFormatted.Value;
- public static bool SupportsIndirectParameters => _supportsIndirectParameters.Value;
- public static bool SupportsParallelShaderCompile => _supportsParallelShaderCompile.Value;
- public static bool SupportsPolygonOffsetClamp => _supportsPolygonOffsetClamp.Value;
- public static bool SupportsQuads => _supportsQuads.Value;
- public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value;
- public static bool SupportsShaderBallot => _supportsShaderBallot.Value;
- public static bool SupportsTextureShadowLod => _supportsTextureShadowLod.Value;
- public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value;
+ public static bool SupportsAlphaToCoverageDitherControl => _supportsAlphaToCoverageDitherControl.Value;
+ public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
+ public static bool SupportsDrawTexture => _supportsDrawTexture.Value;
+ public static bool SupportsFragmentShaderInterlock => _supportsFragmentShaderInterlock.Value;
+ public static bool SupportsFragmentShaderOrdering => _supportsFragmentShaderOrdering.Value;
+ public static bool SupportsImageLoadFormatted => _supportsImageLoadFormatted.Value;
+ public static bool SupportsIndirectParameters => _supportsIndirectParameters.Value;
+ public static bool SupportsParallelShaderCompile => _supportsParallelShaderCompile.Value;
+ public static bool SupportsPolygonOffsetClamp => _supportsPolygonOffsetClamp.Value;
+ public static bool SupportsQuads => _supportsQuads.Value;
+ public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value;
+ public static bool SupportsShaderBallot => _supportsShaderBallot.Value;
+ public static bool SupportsTextureShadowLod => _supportsTextureShadowLod.Value;
+ public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value;
public static bool SupportsMismatchingViewFormat => _gpuVendor.Value != GpuVendor.AmdWindows && _gpuVendor.Value != GpuVendor.IntelWindows;
public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 62d4dee9..fde86424 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -918,6 +918,34 @@ namespace Ryujinx.Graphics.OpenGL
}
}
+ public void SetMultisampleState(MultisampleDescriptor multisample)
+ {
+ if (multisample.AlphaToCoverageEnable)
+ {
+ GL.Enable(EnableCap.SampleAlphaToCoverage);
+
+ if (multisample.AlphaToOneEnable)
+ {
+ GL.Enable(EnableCap.SampleAlphaToOne);
+ }
+ else
+ {
+ GL.Disable(EnableCap.SampleAlphaToOne);
+ }
+
+ if (HwCapabilities.SupportsAlphaToCoverageDitherControl)
+ {
+ GL.NV.AlphaToCoverageDitherControl(multisample.AlphaToCoverageDitherEnable
+ ? NvAlphaToCoverageDitherControl.AlphaToCoverageDitherEnableNv
+ : NvAlphaToCoverageDitherControl.AlphaToCoverageDitherDisableNv);
+ }
+ }
+ else
+ {
+ GL.Disable(EnableCap.SampleAlphaToCoverage);
+ }
+ }
+
public void SetLineParameters(float width, bool smooth)
{
if (smooth)
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 59a7ccdc..54578b79 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -615,7 +615,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
private static void DeclareSupportUniformBlock(CodeGenContext context, ShaderStage stage, int scaleElements)
{
- bool needsSupportBlock = stage == ShaderStage.Fragment ||
+ bool needsSupportBlock = stage == ShaderStage.Fragment ||
(context.Config.LastInVertexPipeline && context.Config.GpuAccessor.QueryViewportTransformDisable());
if (!needsSupportBlock && scaleElements == 0)
diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index 42f210a5..878c7180 100644
--- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -35,6 +35,15 @@ namespace Ryujinx.Graphics.Shader
ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize);
/// <summary>
+ /// Queries whenever the alpha-to-coverage dithering feature is enabled.
+ /// </summary>
+ /// <returns>True if the feature is enabled, false otherwise</returns>
+ bool QueryAlphaToCoverageDitherEnable()
+ {
+ return false;
+ }
+
+ /// <summary>
/// Queries the binding number of a constant buffer.
/// </summary>
/// <param name="index">Constant buffer index</param>
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index ba3b551d..332b3e02 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -205,6 +205,8 @@ namespace Ryujinx.Graphics.Shader.Translation
}
else if (Config.Stage == ShaderStage.Fragment)
{
+ GenerateAlphaToCoverageDitherDiscard();
+
if (Config.OmapDepth)
{
Operand dest = Attribute(AttributeConsts.FragmentOutputDepth);
@@ -266,6 +268,35 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
+ private void GenerateAlphaToCoverageDitherDiscard()
+ {
+ // If the feature is disabled, or alpha is not written, then we're done.
+ if (!Config.GpuAccessor.QueryAlphaToCoverageDitherEnable() || (Config.OmapTargets & 8) == 0)
+ {
+ return;
+ }
+
+ // 11 11 11 10 10 10 10 00
+ // 11 01 01 01 01 00 00 00
+ Operand ditherMask = Const(unchecked((int)0xfbb99110u));
+
+ Operand x = this.BitwiseAnd(this.FP32ConvertToU32(Attribute(AttributeConsts.PositionX)), Const(1));
+ Operand y = this.BitwiseAnd(this.FP32ConvertToU32(Attribute(AttributeConsts.PositionY)), Const(1));
+ Operand xy = this.BitwiseOr(x, this.ShiftLeft(y, Const(1)));
+
+ Operand alpha = Register(3, RegisterType.Gpr);
+ Operand scaledAlpha = this.FPMultiply(this.FPSaturate(alpha), ConstF(8));
+ Operand quantizedAlpha = this.IMinimumU32(this.FP32ConvertToU32(scaledAlpha), Const(7));
+ Operand shift = this.BitwiseOr(this.ShiftLeft(quantizedAlpha, Const(2)), xy);
+ Operand opaque = this.BitwiseAnd(this.ShiftRightU32(ditherMask, shift), Const(1));
+
+ Operand a2cDitherEndLabel = Label();
+
+ this.BranchIfTrue(a2cDitherEndLabel, opaque);
+ this.Discard();
+ this.MarkLabel(a2cDitherEndLabel);
+ }
+
public Operation[] GetOperations()
{
return _operations.ToArray();