mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-11-07 22:28:33 +00:00
319 lines
11 KiB
C#
319 lines
11 KiB
C#
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||
|
using Ryujinx.Graphics.Shader.StructuredIr;
|
||
|
using Ryujinx.Graphics.Shader.Translation;
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
|
||
|
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||
|
{
|
||
|
static class Declarations
|
||
|
{
|
||
|
// At least 16 attributes are guaranteed by the spec.
|
||
|
public const int MaxAttributes = 16;
|
||
|
|
||
|
public static void Declare(CodeGenContext context, StructuredProgramInfo info)
|
||
|
{
|
||
|
context.AppendLine("#version 420 core");
|
||
|
context.AppendLine("#extension GL_ARB_shader_storage_buffer_object : enable");
|
||
|
|
||
|
if (context.Config.Stage == ShaderStage.Compute)
|
||
|
{
|
||
|
context.AppendLine("#extension GL_ARB_compute_shader : enable");
|
||
|
}
|
||
|
|
||
|
context.AppendLine();
|
||
|
|
||
|
context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;");
|
||
|
context.AppendLine();
|
||
|
|
||
|
if (context.Config.Stage == ShaderStage.Geometry)
|
||
|
{
|
||
|
string inPrimitive = "points";
|
||
|
|
||
|
if ((context.Config.Flags & TranslationFlags.Unspecialized) != 0)
|
||
|
{
|
||
|
inPrimitive = DefineNames.InputTopologyName;
|
||
|
}
|
||
|
|
||
|
context.AppendLine($"layout ({inPrimitive}) in;");
|
||
|
|
||
|
string outPrimitive = "triangle_strip";
|
||
|
|
||
|
switch (context.Config.OutputTopology)
|
||
|
{
|
||
|
case OutputTopology.LineStrip: outPrimitive = "line_strip"; break;
|
||
|
case OutputTopology.PointList: outPrimitive = "points"; break;
|
||
|
case OutputTopology.TriangleStrip: outPrimitive = "triangle_strip"; break;
|
||
|
}
|
||
|
|
||
|
int maxOutputVertices = context.Config.MaxOutputVertices;
|
||
|
|
||
|
context.AppendLine($"layout ({outPrimitive}, max_vertices = {maxOutputVertices}) out;");
|
||
|
context.AppendLine();
|
||
|
}
|
||
|
|
||
|
context.AppendLine("layout (std140) uniform Extra");
|
||
|
|
||
|
context.EnterScope();
|
||
|
|
||
|
context.AppendLine("vec2 flip;");
|
||
|
context.AppendLine("int instance;");
|
||
|
|
||
|
context.LeaveScope(";");
|
||
|
|
||
|
context.AppendLine();
|
||
|
|
||
|
context.AppendLine($"precise float {DefaultNames.LocalMemoryName}[0x100];");
|
||
|
context.AppendLine();
|
||
|
|
||
|
if (info.CBuffers.Count != 0)
|
||
|
{
|
||
|
DeclareUniforms(context, info);
|
||
|
|
||
|
context.AppendLine();
|
||
|
}
|
||
|
|
||
|
if (info.SBuffers.Count != 0)
|
||
|
{
|
||
|
DeclareStorage(context, info);
|
||
|
|
||
|
context.AppendLine();
|
||
|
}
|
||
|
|
||
|
if (info.Samplers.Count != 0)
|
||
|
{
|
||
|
DeclareSamplers(context, info);
|
||
|
|
||
|
context.AppendLine();
|
||
|
}
|
||
|
|
||
|
if (context.Config.Stage != ShaderStage.Compute)
|
||
|
{
|
||
|
if (info.IAttributes.Count != 0)
|
||
|
{
|
||
|
DeclareInputAttributes(context, info);
|
||
|
|
||
|
context.AppendLine();
|
||
|
}
|
||
|
|
||
|
if (info.OAttributes.Count != 0 || context.Config.Stage != ShaderStage.Fragment)
|
||
|
{
|
||
|
DeclareOutputAttributes(context, info);
|
||
|
|
||
|
context.AppendLine();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
string localSizeX = "1";
|
||
|
string localSizeY = "1";
|
||
|
string localSizeZ = "1";
|
||
|
|
||
|
if ((context.Config.Flags & TranslationFlags.Unspecialized) != 0)
|
||
|
{
|
||
|
localSizeX = DefineNames.LocalSizeX;
|
||
|
localSizeY = DefineNames.LocalSizeY;
|
||
|
localSizeZ = DefineNames.LocalSizeZ;
|
||
|
}
|
||
|
|
||
|
context.AppendLine(
|
||
|
$"layout (" +
|
||
|
$"local_size_x = {localSizeX}, " +
|
||
|
$"local_size_y = {localSizeY}, " +
|
||
|
$"local_size_z = {localSizeZ}) in;");
|
||
|
context.AppendLine();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void DeclareLocals(CodeGenContext context, StructuredProgramInfo info)
|
||
|
{
|
||
|
foreach (AstOperand decl in info.Locals)
|
||
|
{
|
||
|
string name = context.OperandManager.DeclareLocal(decl);
|
||
|
|
||
|
context.AppendLine(GetVarTypeName(decl.VarType) + " " + name + ";");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static string GetVarTypeName(VariableType type)
|
||
|
{
|
||
|
switch (type)
|
||
|
{
|
||
|
case VariableType.Bool: return "bool";
|
||
|
case VariableType.F32: return "precise float";
|
||
|
case VariableType.S32: return "int";
|
||
|
case VariableType.U32: return "uint";
|
||
|
}
|
||
|
|
||
|
throw new ArgumentException($"Invalid variable type \"{type}\".");
|
||
|
}
|
||
|
|
||
|
private static void DeclareUniforms(CodeGenContext context, StructuredProgramInfo info)
|
||
|
{
|
||
|
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
|
||
|
{
|
||
|
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
||
|
|
||
|
ubName += "_" + DefaultNames.UniformNamePrefix + cbufSlot;
|
||
|
|
||
|
context.CBufferDescriptors.Add(new BufferDescriptor(ubName, cbufSlot));
|
||
|
|
||
|
context.AppendLine("layout (std140) uniform " + ubName);
|
||
|
|
||
|
context.EnterScope();
|
||
|
|
||
|
string ubSize = "[" + NumberFormatter.FormatInt(context.Config.MaxCBufferSize / 16) + "]";
|
||
|
|
||
|
context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Stage, cbufSlot) + ubSize + ";");
|
||
|
|
||
|
context.LeaveScope(";");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void DeclareStorage(CodeGenContext context, StructuredProgramInfo info)
|
||
|
{
|
||
|
foreach (int sbufSlot in info.SBuffers.OrderBy(x => x))
|
||
|
{
|
||
|
string sbName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
||
|
|
||
|
sbName += "_" + DefaultNames.StorageNamePrefix + sbufSlot;
|
||
|
|
||
|
context.SBufferDescriptors.Add(new BufferDescriptor(sbName, sbufSlot));
|
||
|
|
||
|
context.AppendLine("layout (std430) buffer " + sbName);
|
||
|
|
||
|
context.EnterScope();
|
||
|
|
||
|
context.AppendLine("precise float " + OperandManager.GetSbName(context.Config.Stage, sbufSlot) + "[];");
|
||
|
|
||
|
context.LeaveScope(";");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void DeclareSamplers(CodeGenContext context, StructuredProgramInfo info)
|
||
|
{
|
||
|
Dictionary<string, AstTextureOperation> samplers = new Dictionary<string, AstTextureOperation>();
|
||
|
|
||
|
foreach (AstTextureOperation texOp in info.Samplers.OrderBy(x => x.Handle))
|
||
|
{
|
||
|
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp);
|
||
|
|
||
|
if (!samplers.TryAdd(samplerName, texOp))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
string samplerTypeName = GetSamplerTypeName(texOp.Target);
|
||
|
|
||
|
context.AppendLine("uniform " + samplerTypeName + " " + samplerName + ";");
|
||
|
}
|
||
|
|
||
|
foreach (KeyValuePair<string, AstTextureOperation> kv in samplers)
|
||
|
{
|
||
|
string samplerName = kv.Key;
|
||
|
|
||
|
AstTextureOperation texOp = kv.Value;
|
||
|
|
||
|
TextureDescriptor desc;
|
||
|
|
||
|
if ((texOp.Flags & TextureFlags.Bindless) != 0)
|
||
|
{
|
||
|
AstOperand operand = texOp.GetSource(0) as AstOperand;
|
||
|
|
||
|
desc = new TextureDescriptor(samplerName, texOp.Target, operand.CbufSlot, operand.CbufOffset);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
desc = new TextureDescriptor(samplerName, texOp.Target, texOp.Handle);
|
||
|
}
|
||
|
|
||
|
context.TextureDescriptors.Add(desc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
||
|
{
|
||
|
string suffix = context.Config.Stage == ShaderStage.Geometry ? "[]" : string.Empty;
|
||
|
|
||
|
foreach (int attr in info.IAttributes.OrderBy(x => x))
|
||
|
{
|
||
|
string iq = info.InterpolationQualifiers[attr].ToGlslQualifier();
|
||
|
|
||
|
if (iq != string.Empty)
|
||
|
{
|
||
|
iq += " ";
|
||
|
}
|
||
|
|
||
|
context.AppendLine($"layout (location = {attr}) {iq}in vec4 {DefaultNames.IAttributePrefix}{attr}{suffix};");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
||
|
{
|
||
|
if (context.Config.Stage == ShaderStage.Fragment)
|
||
|
{
|
||
|
DeclareUsedOutputAttributes(context, info);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DeclareAllOutputAttributes(context, info);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void DeclareUsedOutputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
||
|
{
|
||
|
foreach (int attr in info.OAttributes.OrderBy(x => x))
|
||
|
{
|
||
|
context.AppendLine($"layout (location = {attr}) out vec4 {DefaultNames.OAttributePrefix}{attr};");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void DeclareAllOutputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
||
|
{
|
||
|
for (int attr = 0; attr < MaxAttributes; attr++)
|
||
|
{
|
||
|
string iq = $"{DefineNames.OutQualifierPrefixName}{attr} ";
|
||
|
|
||
|
context.AppendLine($"layout (location = {attr}) {iq}out vec4 {DefaultNames.OAttributePrefix}{attr};");
|
||
|
}
|
||
|
|
||
|
foreach (int attr in info.OAttributes.OrderBy(x => x).Where(x => x >= MaxAttributes))
|
||
|
{
|
||
|
context.AppendLine($"layout (location = {attr}) out vec4 {DefaultNames.OAttributePrefix}{attr};");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static string GetSamplerTypeName(TextureTarget type)
|
||
|
{
|
||
|
string typeName;
|
||
|
|
||
|
switch (type & TextureTarget.Mask)
|
||
|
{
|
||
|
case TextureTarget.Texture1D: typeName = "sampler1D"; break;
|
||
|
case TextureTarget.Texture2D: typeName = "sampler2D"; break;
|
||
|
case TextureTarget.Texture3D: typeName = "sampler3D"; break;
|
||
|
case TextureTarget.TextureCube: typeName = "samplerCube"; break;
|
||
|
|
||
|
default: throw new ArgumentException($"Invalid sampler type \"{type}\".");
|
||
|
}
|
||
|
|
||
|
if ((type & TextureTarget.Multisample) != 0)
|
||
|
{
|
||
|
typeName += "MS";
|
||
|
}
|
||
|
|
||
|
if ((type & TextureTarget.Array) != 0)
|
||
|
{
|
||
|
typeName += "Array";
|
||
|
}
|
||
|
|
||
|
if ((type & TextureTarget.Shadow) != 0)
|
||
|
{
|
||
|
typeName += "Shadow";
|
||
|
}
|
||
|
|
||
|
return typeName;
|
||
|
}
|
||
|
}
|
||
|
}
|