Move gl_Layer from vertex to geometry if GPU does not support it on vertex (#3866)
* Move gl_Layer from vertex to geometry if GPU does not support it on vertex * Shader cache version bump * PR feedback
This commit is contained in:
parent
7373ec5792
commit
2e43d01d36
13 changed files with 190 additions and 17 deletions
|
@ -258,6 +258,15 @@ namespace Ryujinx.Graphics.Shader
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host support for writes to Layer from vertex or tessellation shader stages.
|
||||
/// </summary>
|
||||
/// <returns>True if writes to layer from vertex or tessellation are supported, false otherwise</returns>
|
||||
bool QueryHostSupportsLayerVertexTessellation()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU non-constant texture offset support.
|
||||
/// </summary>
|
||||
|
|
|
@ -278,13 +278,21 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
private static int FixedFuncToUserAttribute(ShaderConfig config, int attr, bool isOutput)
|
||||
{
|
||||
if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.ClipDistance0)
|
||||
bool supportsLayerFromVertexOrTess = config.GpuAccessor.QueryHostSupportsLayerVertexTessellation();
|
||||
int fixedStartAttr = supportsLayerFromVertexOrTess ? 0 : 1;
|
||||
|
||||
if (attr == AttributeConsts.Layer && config.Stage != ShaderStage.Geometry && !supportsLayerFromVertexOrTess)
|
||||
{
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.FrontColorDiffuseR, 0, isOutput);
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.Layer, 0, isOutput);
|
||||
config.SetLayerOutputAttribute(attr);
|
||||
}
|
||||
else if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.ClipDistance0)
|
||||
{
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.FrontColorDiffuseR, fixedStartAttr, isOutput);
|
||||
}
|
||||
else if (attr >= AttributeConsts.TexCoordBase && attr < AttributeConsts.TexCoordEnd)
|
||||
{
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.TexCoordBase, 4, isOutput);
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.TexCoordBase, fixedStartAttr + 4, isOutput);
|
||||
}
|
||||
|
||||
return attr;
|
||||
|
|
|
@ -48,6 +48,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
public int Cb1DataSize { get; private set; }
|
||||
|
||||
public bool LayerOutputWritten { get; private set; }
|
||||
public int LayerOutputAttribute { get; private set; }
|
||||
|
||||
public bool NextUsesFixedFuncAttributes { get; private set; }
|
||||
public int UsedInputAttributes { get; private set; }
|
||||
public int UsedOutputAttributes { get; private set; }
|
||||
|
@ -131,6 +134,20 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
_usedImages = new Dictionary<TextureInfo, TextureMeta>();
|
||||
}
|
||||
|
||||
public ShaderConfig(
|
||||
ShaderStage stage,
|
||||
OutputTopology outputTopology,
|
||||
int maxOutputVertices,
|
||||
IGpuAccessor gpuAccessor,
|
||||
TranslationOptions options) : this(gpuAccessor, options)
|
||||
{
|
||||
Stage = stage;
|
||||
ThreadsPerInputPrimitive = 1;
|
||||
OutputTopology = outputTopology;
|
||||
MaxOutputVertices = maxOutputVertices;
|
||||
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
||||
}
|
||||
|
||||
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(gpuAccessor, options)
|
||||
{
|
||||
Stage = header.Stage;
|
||||
|
@ -240,6 +257,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
}
|
||||
}
|
||||
|
||||
public void SetLayerOutputAttribute(int attr)
|
||||
{
|
||||
LayerOutputWritten = true;
|
||||
LayerOutputAttribute = attr;
|
||||
}
|
||||
|
||||
public void SetInputUserAttributeFixedFunc(int index)
|
||||
{
|
||||
UsedInputAttributes |= 1 << index;
|
||||
|
@ -694,5 +717,20 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
return FindDescriptorIndex(GetImageDescriptors(), texOp);
|
||||
}
|
||||
|
||||
public ShaderProgramInfo CreateProgramInfo()
|
||||
{
|
||||
return new ShaderProgramInfo(
|
||||
GetConstantBufferDescriptors(),
|
||||
GetStorageBufferDescriptors(),
|
||||
GetTextureDescriptors(),
|
||||
GetImageDescriptors(),
|
||||
Stage,
|
||||
UsedFeatures.HasFlag(FeatureFlags.InstanceId),
|
||||
UsedFeatures.HasFlag(FeatureFlags.DrawParameters),
|
||||
UsedFeatures.HasFlag(FeatureFlags.RtLayer),
|
||||
ClipDistancesWritten,
|
||||
OmapTargets);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -79,17 +79,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
var sInfo = StructuredProgram.MakeStructuredProgram(funcs, config);
|
||||
|
||||
var info = new ShaderProgramInfo(
|
||||
config.GetConstantBufferDescriptors(),
|
||||
config.GetStorageBufferDescriptors(),
|
||||
config.GetTextureDescriptors(),
|
||||
config.GetImageDescriptors(),
|
||||
config.Stage,
|
||||
config.UsedFeatures.HasFlag(FeatureFlags.InstanceId),
|
||||
config.UsedFeatures.HasFlag(FeatureFlags.DrawParameters),
|
||||
config.UsedFeatures.HasFlag(FeatureFlags.RtLayer),
|
||||
config.ClipDistancesWritten,
|
||||
config.OmapTargets);
|
||||
var info = config.CreateProgramInfo();
|
||||
|
||||
return config.Options.TargetLanguage switch
|
||||
{
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
|
||||
using Ryujinx.Graphics.Shader.CodeGen.Spirv;
|
||||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
using static Ryujinx.Graphics.Shader.Translation.Translator;
|
||||
|
@ -18,6 +23,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
public ShaderStage Stage => _config.Stage;
|
||||
public int Size => _config.Size;
|
||||
public int Cb1DataSize => _config.Cb1DataSize;
|
||||
public bool LayerOutputWritten => _config.LayerOutputWritten;
|
||||
|
||||
public IGpuAccessor GpuAccessor => _config.GpuAccessor;
|
||||
|
||||
|
@ -149,5 +155,94 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
return Translator.Translate(code, _config);
|
||||
}
|
||||
|
||||
public ShaderProgram GenerateGeometryPassthrough()
|
||||
{
|
||||
int outputAttributesMask = _config.UsedOutputAttributes;
|
||||
int layerOutputAttr = _config.LayerOutputAttribute;
|
||||
|
||||
OutputTopology outputTopology;
|
||||
int maxOutputVertices;
|
||||
|
||||
switch (GpuAccessor.QueryPrimitiveTopology())
|
||||
{
|
||||
case InputTopology.Points:
|
||||
outputTopology = OutputTopology.PointList;
|
||||
maxOutputVertices = 1;
|
||||
break;
|
||||
case InputTopology.Lines:
|
||||
case InputTopology.LinesAdjacency:
|
||||
outputTopology = OutputTopology.LineStrip;
|
||||
maxOutputVertices = 2;
|
||||
break;
|
||||
default:
|
||||
outputTopology = OutputTopology.TriangleStrip;
|
||||
maxOutputVertices = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
ShaderConfig config = new ShaderConfig(ShaderStage.Geometry, outputTopology, maxOutputVertices, GpuAccessor, _config.Options);
|
||||
|
||||
EmitterContext context = new EmitterContext(default, config, false);
|
||||
|
||||
for (int v = 0; v < maxOutputVertices; v++)
|
||||
{
|
||||
int outAttrsMask = outputAttributesMask;
|
||||
|
||||
while (outAttrsMask != 0)
|
||||
{
|
||||
int attrIndex = BitOperations.TrailingZeroCount(outAttrsMask);
|
||||
|
||||
outAttrsMask &= ~(1 << attrIndex);
|
||||
|
||||
for (int c = 0; c < 4; c++)
|
||||
{
|
||||
int attr = AttributeConsts.UserAttributeBase + attrIndex * 16 + c * 4;
|
||||
|
||||
Operand value = context.LoadAttribute(Const(attr), Const(0), Const(v));
|
||||
|
||||
if (attr == layerOutputAttr)
|
||||
{
|
||||
context.Copy(Attribute(AttributeConsts.Layer), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Copy(Attribute(attr), value);
|
||||
config.SetOutputUserAttribute(attrIndex);
|
||||
}
|
||||
|
||||
config.SetInputUserAttribute(attrIndex, c);
|
||||
}
|
||||
}
|
||||
|
||||
for (int c = 0; c < 4; c++)
|
||||
{
|
||||
int attr = AttributeConsts.PositionX + c * 4;
|
||||
|
||||
Operand value = context.LoadAttribute(Const(attr), Const(0), Const(v));
|
||||
|
||||
context.Copy(Attribute(attr), value);
|
||||
}
|
||||
|
||||
context.EmitVertex();
|
||||
}
|
||||
|
||||
context.EndPrimitive();
|
||||
|
||||
var operations = context.GetOperations();
|
||||
var cfg = ControlFlowGraph.Create(operations);
|
||||
var function = new Function(cfg.Blocks, "main", false, 0, 0);
|
||||
|
||||
var sInfo = StructuredProgram.MakeStructuredProgram(new[] { function }, config);
|
||||
|
||||
var info = config.CreateProgramInfo();
|
||||
|
||||
return config.Options.TargetLanguage switch
|
||||
{
|
||||
TargetLanguage.Glsl => new ShaderProgram(info, TargetLanguage.Glsl, GlslGenerator.Generate(sInfo, config)),
|
||||
TargetLanguage.Spirv => new ShaderProgram(info, TargetLanguage.Spirv, SpirvGenerator.Generate(sInfo, config)),
|
||||
_ => throw new NotImplementedException(config.Options.TargetLanguage.ToString())
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue