mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-02-21 16:43:35 +00:00
Geometry shader passthrough emulation
This commit is contained in:
parent
2713703d45
commit
dd54eb4be1
13 changed files with 93 additions and 53 deletions
|
@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.GAL
|
|||
public readonly bool SupportsR4G4Format;
|
||||
public readonly bool SupportsFragmentShaderInterlock;
|
||||
public readonly bool SupportsFragmentShaderOrderingIntel;
|
||||
public readonly bool SupportsGeometryShaderPassthrough;
|
||||
public readonly bool SupportsImageLoadFormatted;
|
||||
public readonly bool SupportsMismatchingViewFormat;
|
||||
public readonly bool SupportsNonConstantTextureOffset;
|
||||
|
@ -44,6 +45,7 @@ namespace Ryujinx.Graphics.GAL
|
|||
bool supportsR4G4Format,
|
||||
bool supportsFragmentShaderInterlock,
|
||||
bool supportsFragmentShaderOrderingIntel,
|
||||
bool supportsGeometryShaderPassthrough,
|
||||
bool supportsImageLoadFormatted,
|
||||
bool supportsMismatchingViewFormat,
|
||||
bool supportsNonConstantTextureOffset,
|
||||
|
@ -69,6 +71,7 @@ namespace Ryujinx.Graphics.GAL
|
|||
SupportsR4G4Format = supportsR4G4Format;
|
||||
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
|
||||
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
|
||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||
SupportsImageLoadFormatted = supportsImageLoadFormatted;
|
||||
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
|
||||
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 1;
|
||||
private const uint CodeGenVersion = 2;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
|
|
@ -105,64 +105,37 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host about the presence of the FrontFacing built-in variable bug.
|
||||
/// </summary>
|
||||
/// <returns>True if the bug is present on the host device used, false otherwise</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostHasFrontFacingBug() => _context.Capabilities.HasFrontFacingBug;
|
||||
|
||||
/// <summary>
|
||||
/// Queries host about the presence of the vector indexing bug.
|
||||
/// </summary>
|
||||
/// <returns>True if the bug is present on the host device used, false otherwise</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostHasVectorIndexingBug() => _context.Capabilities.HasVectorIndexingBug;
|
||||
|
||||
/// <summary>
|
||||
/// Queries host storage buffer alignment required.
|
||||
/// </summary>
|
||||
/// <returns>Host storage buffer alignment in bytes</returns>
|
||||
/// <inheritdoc/>
|
||||
public int QueryHostStorageBufferOffsetAlignment() => _context.Capabilities.StorageBufferOffsetAlignment;
|
||||
|
||||
/// <summary>
|
||||
/// Queries host support for texture formats with BGRA component order (such as BGRA8).
|
||||
/// </summary>
|
||||
/// <returns>True if BGRA formats are supported, false otherwise</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsBgraFormat() => _context.Capabilities.SupportsBgraFormat;
|
||||
|
||||
/// <summary>
|
||||
/// Queries host support for fragment shader ordering critical sections on the shader code.
|
||||
/// </summary>
|
||||
/// <returns>True if fragment shader interlock is supported, false otherwise</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsFragmentShaderInterlock() => _context.Capabilities.SupportsFragmentShaderInterlock;
|
||||
|
||||
/// <summary>
|
||||
/// Queries host support for fragment shader ordering scoped critical sections on the shader code.
|
||||
/// </summary>
|
||||
/// <returns>True if fragment shader ordering is supported, false otherwise</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsFragmentShaderOrderingIntel() => _context.Capabilities.SupportsFragmentShaderOrderingIntel;
|
||||
|
||||
/// <summary>
|
||||
/// Queries host support for readable images without a explicit format declaration on the shader.
|
||||
/// </summary>
|
||||
/// <returns>True if formatted image load is supported, false otherwise</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsGeometryShaderPassthrough() => _context.Capabilities.SupportsGeometryShaderPassthrough;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsImageLoadFormatted() => _context.Capabilities.SupportsImageLoadFormatted;
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU non-constant texture offset support.
|
||||
/// </summary>
|
||||
/// <returns>True if the GPU and driver supports non-constant texture offsets, false otherwise</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsNonConstantTextureOffset() => _context.Capabilities.SupportsNonConstantTextureOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU shader ballot support.
|
||||
/// </summary>
|
||||
/// <returns>True if the GPU and driver supports shader ballot, false otherwise</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot;
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU texture shadow LOD support.
|
||||
/// </summary>
|
||||
/// <returns>True if the GPU and driver supports texture shadow LOD, false otherwise</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
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> _supportsGeometryShaderPassthrough = new Lazy<bool>(() => HasExtension("GL_NV_geometry_shader_passthrough"));
|
||||
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"));
|
||||
|
@ -47,6 +48,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
public static bool SupportsDrawTexture => _supportsDrawTexture.Value;
|
||||
public static bool SupportsFragmentShaderInterlock => _supportsFragmentShaderInterlock.Value;
|
||||
public static bool SupportsFragmentShaderOrdering => _supportsFragmentShaderOrdering.Value;
|
||||
public static bool SupportsGeometryShaderPassthrough => _supportsGeometryShaderPassthrough.Value;
|
||||
public static bool SupportsImageLoadFormatted => _supportsImageLoadFormatted.Value;
|
||||
public static bool SupportsIndirectParameters => _supportsIndirectParameters.Value;
|
||||
public static bool SupportsParallelShaderCompile => _supportsParallelShaderCompile.Value;
|
||||
|
|
|
@ -110,6 +110,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
supportsR4G4Format: false,
|
||||
supportsFragmentShaderInterlock: HwCapabilities.SupportsFragmentShaderInterlock,
|
||||
supportsFragmentShaderOrderingIntel: HwCapabilities.SupportsFragmentShaderOrdering,
|
||||
supportsGeometryShaderPassthrough: HwCapabilities.SupportsGeometryShaderPassthrough,
|
||||
supportsImageLoadFormatted: HwCapabilities.SupportsImageLoadFormatted,
|
||||
supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
|
||||
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
context.AppendLine("#extension GL_ARB_shader_viewport_layer_array : enable");
|
||||
}
|
||||
|
||||
if (context.Config.GpPassthrough)
|
||||
if (context.Config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.AppendLine("#extension GL_NV_geometry_shader_passthrough : enable");
|
||||
}
|
||||
|
@ -127,11 +127,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
{
|
||||
if (context.Config.Stage == ShaderStage.Geometry)
|
||||
{
|
||||
string inPrimitive = context.Config.GpuAccessor.QueryPrimitiveTopology().ToGlslString();
|
||||
InputTopology inputTopology = context.Config.GpuAccessor.QueryPrimitiveTopology();
|
||||
string inPrimitive = inputTopology.ToGlslString();
|
||||
|
||||
context.AppendLine($"layout ({inPrimitive}) in;");
|
||||
|
||||
if (context.Config.GpPassthrough)
|
||||
if (context.Config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.AppendLine($"layout (passthrough) in gl_PerVertex");
|
||||
context.EnterScope();
|
||||
|
@ -144,7 +145,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
{
|
||||
string outPrimitive = context.Config.OutputTopology.ToGlslString();
|
||||
|
||||
int maxOutputVertices = context.Config.MaxOutputVertices;
|
||||
int maxOutputVertices = context.Config.GpPassthrough
|
||||
? inputTopology.ToInputVertices()
|
||||
: context.Config.MaxOutputVertices;
|
||||
|
||||
context.AppendLine($"layout ({outPrimitive}, max_vertices = {maxOutputVertices}) out;");
|
||||
}
|
||||
|
@ -563,7 +566,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
};
|
||||
}
|
||||
|
||||
string pass = (context.Config.PassthroughAttributes & (1 << attr)) != 0 ? "passthrough, " : string.Empty;
|
||||
bool passthrough = (context.Config.PassthroughAttributes & (1 << attr)) != 0;
|
||||
string pass = passthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough() ? "passthrough, " : string.Empty;
|
||||
string name = $"{DefaultNames.IAttributePrefix}{attr}";
|
||||
|
||||
if (context.Config.TransformFeedbackEnabled && context.Config.Stage != ShaderStage.Vertex)
|
||||
|
|
|
@ -425,7 +425,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
var spvType = context.TypePointer(StorageClass.Input, attrType);
|
||||
var spvVar = context.Variable(spvType, StorageClass.Input);
|
||||
|
||||
if (context.Config.PassthroughAttributes != 0)
|
||||
if (context.Config.PassthroughAttributes != 0 && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
}
|
||||
|
@ -534,7 +534,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
{
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)context.InputVertices));
|
||||
|
||||
if (context.Config.GpPassthrough)
|
||||
if (context.Config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
builtInPassthrough = true;
|
||||
}
|
||||
|
@ -581,7 +581,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
|
||||
if (!isOutAttr)
|
||||
{
|
||||
if (!perPatch && (context.Config.PassthroughAttributes & (1 << location)) != 0)
|
||||
if (!perPatch &&
|
||||
(context.Config.PassthroughAttributes & (1 << location)) != 0 &&
|
||||
context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
}
|
||||
|
@ -646,7 +648,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((context.Config.PassthroughAttributes & (1 << location)) != 0)
|
||||
if ((context.Config.PassthroughAttributes & (1 << location)) != 0 &&
|
||||
context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
{
|
||||
context.AddCapability(Capability.Geometry);
|
||||
|
||||
if (config.GpPassthrough)
|
||||
if (config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.AddExtension("SPV_NV_geometry_shader_passthrough");
|
||||
context.AddCapability(Capability.GeometryShaderPassthroughNV);
|
||||
|
@ -230,7 +230,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
_ => throw new InvalidOperationException($"Invalid output topology \"{context.Config.OutputTopology}\".")
|
||||
});
|
||||
|
||||
context.AddExecutionMode(spvFunc, ExecutionMode.OutputVertices, (SpvLiteralInteger)context.Config.MaxOutputVertices);
|
||||
int maxOutputVertices = context.Config.GpPassthrough ? context.InputVertices : context.Config.MaxOutputVertices;
|
||||
|
||||
context.AddExecutionMode(spvFunc, ExecutionMode.OutputVertices, (SpvLiteralInteger)maxOutputVertices);
|
||||
}
|
||||
else if (context.Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
|
|
|
@ -197,6 +197,15 @@ namespace Ryujinx.Graphics.Shader
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU geometry shader passthrough support.
|
||||
/// </summary>
|
||||
/// <returns>True if the GPU and driver supports geometry shader passthrough, false otherwise</returns>
|
||||
bool QueryHostSupportsGeometryShaderPassthrough()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host support for readable images without a explicit format declaration on the shader.
|
||||
/// </summary>
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
AggregateType elemType;
|
||||
|
||||
if (!isOutAttr)
|
||||
if (config.Stage == ShaderStage.Vertex && !isOutAttr)
|
||||
{
|
||||
elemType = config.GpuAccessor.QueryAttributeType(location) switch
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@ using Ryujinx.Graphics.Shader.Decoders;
|
|||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
|
@ -232,6 +233,44 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
PrepareForVertexReturn();
|
||||
}
|
||||
else if (Config.Stage == ShaderStage.Geometry)
|
||||
{
|
||||
void WriteOutput(int index, int primIndex)
|
||||
{
|
||||
Operand x = this.LoadAttribute(Const(index), Const(0), Const(primIndex));
|
||||
Operand y = this.LoadAttribute(Const(index + 4), Const(0), Const(primIndex));
|
||||
Operand z = this.LoadAttribute(Const(index + 8), Const(0), Const(primIndex));
|
||||
Operand w = this.LoadAttribute(Const(index + 12), Const(0), Const(primIndex));
|
||||
|
||||
this.Copy(Attribute(index), x);
|
||||
this.Copy(Attribute(index + 4), y);
|
||||
this.Copy(Attribute(index + 8), z);
|
||||
this.Copy(Attribute(index + 12), w);
|
||||
}
|
||||
|
||||
if (Config.GpPassthrough)
|
||||
{
|
||||
int inputVertices = Config.GpuAccessor.QueryPrimitiveTopology().ToInputVertices();
|
||||
|
||||
for (int primIndex = 0; primIndex < inputVertices; primIndex++)
|
||||
{
|
||||
WriteOutput(AttributeConsts.PositionX, primIndex);
|
||||
|
||||
int passthroughAttributes = Config.PassthroughAttributes;
|
||||
while (passthroughAttributes != 0)
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(passthroughAttributes);
|
||||
WriteOutput(AttributeConsts.UserAttributeBase + index * 16, primIndex);
|
||||
Config.SetOutputUserAttribute(index, perPatch: false);
|
||||
passthroughAttributes &= ~(1 << index);
|
||||
}
|
||||
|
||||
this.EmitVertex();
|
||||
}
|
||||
|
||||
this.EndPrimitive();
|
||||
}
|
||||
}
|
||||
else if (Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
bool supportsBgra = Config.GpuAccessor.QueryHostSupportsBgraFormat();
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
public ShaderStage Stage { get; }
|
||||
|
||||
public bool GpPassthrough { get; }
|
||||
public bool GpPassthroughWithHostSupport => GpPassthrough && GpuAccessor.QueryHostSupportsGeometryShaderPassthrough();
|
||||
public bool LastInVertexPipeline { get; private set; }
|
||||
|
||||
public int ThreadsPerInputPrimitive { get; }
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
internal bool SupportsCustomBorderColor { get; private set; }
|
||||
internal bool SupportsIndirectParameters { get; private set; }
|
||||
internal bool SupportsFragmentShaderInterlock { get; private set; }
|
||||
internal bool SupportsGeometryShaderPassthrough { get; private set; }
|
||||
internal bool SupportsSubgroupSizeControl { get; private set; }
|
||||
|
||||
internal uint QueueFamilyIndex { get; private set; }
|
||||
|
@ -123,6 +124,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
SupportsCustomBorderColor = supportedExtensions.Contains("VK_EXT_custom_border_color");
|
||||
SupportsIndirectParameters = supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName);
|
||||
SupportsFragmentShaderInterlock = supportedExtensions.Contains("VK_EXT_fragment_shader_interlock");
|
||||
SupportsGeometryShaderPassthrough = supportedExtensions.Contains("VK_NV_geometry_shader_passthrough");
|
||||
SupportsSubgroupSizeControl = supportedExtensions.Contains("VK_EXT_subgroup_size_control");
|
||||
|
||||
if (api.TryGetDeviceExtension(_instance, _device, out KhrSwapchain swapchainApi))
|
||||
|
@ -311,6 +313,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
supportsR4G4Format: false,
|
||||
supportsFragmentShaderInterlock: SupportsFragmentShaderInterlock,
|
||||
supportsFragmentShaderOrderingIntel: false,
|
||||
supportsGeometryShaderPassthrough: SupportsGeometryShaderPassthrough,
|
||||
supportsImageLoadFormatted: features.ShaderStorageImageReadWithoutFormat,
|
||||
supportsMismatchingViewFormat: true,
|
||||
supportsNonConstantTextureOffset: false,
|
||||
|
|
Loading…
Reference in a new issue