2024-06-22 13:38:09 +00:00
|
|
|
using Ryujinx.Common;
|
2023-08-12 14:12:35 +00:00
|
|
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
2024-08-31 20:42:56 +00:00
|
|
|
using Ryujinx.Graphics.Shader.StructuredIr;
|
2023-08-04 03:21:22 +00:00
|
|
|
using Ryujinx.Graphics.Shader.Translation;
|
|
|
|
using System;
|
2023-08-05 03:51:24 +00:00
|
|
|
using System.Collections.Generic;
|
2023-08-12 14:12:35 +00:00
|
|
|
using System.Linq;
|
2024-08-31 20:42:56 +00:00
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
|
|
|
{
|
|
|
|
static class Declarations
|
|
|
|
{
|
2023-10-09 15:33:28 +00:00
|
|
|
/*
|
|
|
|
* Description of MSL Binding Strategy
|
|
|
|
*
|
|
|
|
* There are a few fundamental differences between how GLSL and MSL handle I/O.
|
|
|
|
* This comment will set out to describe the reasons why things are done certain ways
|
|
|
|
* and to describe the overall binding model that we're striving for here.
|
|
|
|
*
|
|
|
|
* Main I/O Structs
|
|
|
|
*
|
|
|
|
* Each stage will have a main input and output struct labeled as [Stage][In/Out], i.e VertexIn.
|
|
|
|
* Every attribute within these structs will be labeled with an [[attribute(n)]] property,
|
|
|
|
* and the overall struct will be labeled with [[stage_in]] for input structs, and defined as the
|
|
|
|
* output type of the main shader function for the output struct. This struct also contains special
|
|
|
|
* attribute-based properties like [[position]], therefore these are not confined to 'user-defined' variables.
|
|
|
|
*
|
|
|
|
* Samplers & Textures
|
|
|
|
*
|
|
|
|
* Metal does not have a combined image sampler like sampler2D in GLSL, as a result we need to bind
|
|
|
|
* an individual texture and a sampler object for each instance of a combined image sampler.
|
|
|
|
* Therefore, the binding indices of straight up textures (i.e. without a sampler) must start
|
|
|
|
* after the last sampler/texture pair (n + Number of Pairs).
|
|
|
|
*
|
|
|
|
* Uniforms
|
|
|
|
*
|
|
|
|
* MSL does not have a concept of uniforms comparable to that of GLSL. As a result, instead of
|
|
|
|
* being declared outside of any function body, uniforms are part of the function signature in MSL.
|
|
|
|
* This applies to anything bound to the shader not included in the main I/O structs.
|
|
|
|
*/
|
|
|
|
|
2024-08-31 20:42:56 +00:00
|
|
|
public static void Declare(CodeGenContext context, StructuredProgramInfo info)
|
|
|
|
{
|
|
|
|
context.AppendLine("#include <metal_stdlib>");
|
|
|
|
context.AppendLine("#include <simd/simd.h>");
|
|
|
|
context.AppendLine();
|
|
|
|
context.AppendLine("using namespace metal;");
|
2023-08-05 03:51:24 +00:00
|
|
|
context.AppendLine();
|
2023-08-04 03:21:22 +00:00
|
|
|
|
|
|
|
if ((info.HelperFunctionsMask & HelperFunctionsMask.SwizzleAdd) != 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
2023-08-05 03:51:24 +00:00
|
|
|
|
2023-08-15 13:17:00 +00:00
|
|
|
DeclareInputAttributes(context, info.IoDefinitions.Where(x => IsUserDefined(x, StorageKind.Input)));
|
2023-10-09 15:33:28 +00:00
|
|
|
context.AppendLine();
|
|
|
|
DeclareOutputAttributes(context, info.IoDefinitions.Where(x => x.StorageKind == StorageKind.Output));
|
2024-05-29 15:21:59 +00:00
|
|
|
context.AppendLine();
|
2024-06-25 13:25:31 +00:00
|
|
|
DeclareBufferStructures(context, context.Properties.ConstantBuffers.Values, true);
|
|
|
|
DeclareBufferStructures(context, context.Properties.StorageBuffers.Values, false);
|
|
|
|
DeclareTextures(context, context.Properties.Textures.Values);
|
2024-06-22 13:38:09 +00:00
|
|
|
|
|
|
|
if ((info.HelperFunctionsMask & HelperFunctionsMask.FindLSB) != 0)
|
|
|
|
{
|
|
|
|
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Msl/HelperFunctions/FindLSB.metal");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((info.HelperFunctionsMask & HelperFunctionsMask.FindMSBS32) != 0)
|
|
|
|
{
|
|
|
|
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Msl/HelperFunctions/FindMSBS32.metal");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((info.HelperFunctionsMask & HelperFunctionsMask.FindMSBU32) != 0)
|
|
|
|
{
|
|
|
|
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Msl/HelperFunctions/FindMSBU32.metal");
|
|
|
|
}
|
2023-08-12 14:12:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool IsUserDefined(IoDefinition ioDefinition, StorageKind storageKind)
|
|
|
|
{
|
|
|
|
return ioDefinition.StorageKind == storageKind && ioDefinition.IoVariable == IoVariable.UserDefined;
|
2023-08-04 03:21:22 +00:00
|
|
|
}
|
|
|
|
|
2024-06-21 09:31:21 +00:00
|
|
|
public static void DeclareLocals(CodeGenContext context, StructuredFunction function, ShaderStage stage, bool isMainFunc = false)
|
2023-08-04 03:21:22 +00:00
|
|
|
{
|
2024-06-21 09:31:21 +00:00
|
|
|
if (isMainFunc)
|
|
|
|
{
|
|
|
|
DeclareMemories(context, context.Properties.LocalMemories.Values, isShared: false);
|
|
|
|
DeclareMemories(context, context.Properties.SharedMemories.Values, isShared: true);
|
|
|
|
|
2024-06-21 15:58:58 +00:00
|
|
|
switch (stage)
|
|
|
|
{
|
|
|
|
case ShaderStage.Vertex:
|
|
|
|
context.AppendLine("VertexOut out;");
|
|
|
|
// TODO: Only add if necessary
|
|
|
|
context.AppendLine("uint instance_index = instance_id + base_instance;");
|
|
|
|
break;
|
|
|
|
case ShaderStage.Fragment:
|
|
|
|
context.AppendLine("FragmentOut out;");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Only add if necessary
|
|
|
|
if (stage != ShaderStage.Compute)
|
|
|
|
{
|
|
|
|
// MSL does not give us access to [[thread_index_in_simdgroup]]
|
|
|
|
// outside compute. But we may still need to provide this value in frag/vert.
|
|
|
|
context.AppendLine("uint thread_index_in_simdgroup = simd_prefix_exclusive_sum(1);");
|
|
|
|
}
|
2023-10-11 00:00:56 +00:00
|
|
|
}
|
2023-10-09 15:33:28 +00:00
|
|
|
|
2023-08-04 03:21:22 +00:00
|
|
|
foreach (AstOperand decl in function.Locals)
|
|
|
|
{
|
|
|
|
string name = context.OperandManager.DeclareLocal(decl);
|
|
|
|
|
2024-06-25 13:25:31 +00:00
|
|
|
context.AppendLine(GetVarTypeName(decl.VarType) + " " + name + ";");
|
2023-08-04 03:21:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-25 13:25:31 +00:00
|
|
|
public static string GetVarTypeName(AggregateType type, bool atomic = false)
|
2023-08-04 03:21:22 +00:00
|
|
|
{
|
2024-06-21 15:58:58 +00:00
|
|
|
var s32 = atomic ? "atomic_int" : "int";
|
|
|
|
var u32 = atomic ? "atomic_uint" : "uint";
|
|
|
|
|
2023-08-04 03:21:22 +00:00
|
|
|
return type switch
|
|
|
|
{
|
|
|
|
AggregateType.Void => "void",
|
|
|
|
AggregateType.Bool => "bool",
|
|
|
|
AggregateType.FP32 => "float",
|
2024-06-21 15:58:58 +00:00
|
|
|
AggregateType.S32 => s32,
|
|
|
|
AggregateType.U32 => u32,
|
2023-08-04 03:21:22 +00:00
|
|
|
AggregateType.Vector2 | AggregateType.Bool => "bool2",
|
|
|
|
AggregateType.Vector2 | AggregateType.FP32 => "float2",
|
|
|
|
AggregateType.Vector2 | AggregateType.S32 => "int2",
|
|
|
|
AggregateType.Vector2 | AggregateType.U32 => "uint2",
|
|
|
|
AggregateType.Vector3 | AggregateType.Bool => "bool3",
|
|
|
|
AggregateType.Vector3 | AggregateType.FP32 => "float3",
|
|
|
|
AggregateType.Vector3 | AggregateType.S32 => "int3",
|
|
|
|
AggregateType.Vector3 | AggregateType.U32 => "uint3",
|
|
|
|
AggregateType.Vector4 | AggregateType.Bool => "bool4",
|
|
|
|
AggregateType.Vector4 | AggregateType.FP32 => "float4",
|
|
|
|
AggregateType.Vector4 | AggregateType.S32 => "int4",
|
|
|
|
AggregateType.Vector4 | AggregateType.U32 => "uint4",
|
|
|
|
_ => throw new ArgumentException($"Invalid variable type \"{type}\"."),
|
|
|
|
};
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
2023-08-05 03:51:24 +00:00
|
|
|
|
2024-05-20 17:07:27 +00:00
|
|
|
private static void DeclareMemories(CodeGenContext context, IEnumerable<MemoryDefinition> memories, bool isShared)
|
|
|
|
{
|
2024-06-21 09:31:21 +00:00
|
|
|
string prefix = isShared ? "threadgroup " : string.Empty;
|
|
|
|
|
2024-05-20 17:07:27 +00:00
|
|
|
foreach (var memory in memories)
|
|
|
|
{
|
2024-05-29 15:21:59 +00:00
|
|
|
string arraySize = "";
|
|
|
|
if ((memory.Type & AggregateType.Array) != 0)
|
|
|
|
{
|
|
|
|
arraySize = $"[{memory.ArrayLength}]";
|
|
|
|
}
|
2024-06-25 13:25:31 +00:00
|
|
|
var typeName = GetVarTypeName(memory.Type & ~AggregateType.Array);
|
2024-06-21 09:31:21 +00:00
|
|
|
context.AppendLine($"{prefix}{typeName} {memory.Name}{arraySize};");
|
2024-05-29 15:21:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-25 13:25:31 +00:00
|
|
|
private static void DeclareBufferStructures(CodeGenContext context, IEnumerable<BufferDefinition> buffers, bool constant)
|
2024-05-29 15:21:59 +00:00
|
|
|
{
|
2024-06-25 13:25:31 +00:00
|
|
|
var name = constant ? "ConstantBuffers" : "StorageBuffers";
|
|
|
|
var count = constant ? Defaults.MaxUniformBuffersPerStage : Defaults.MaxStorageBuffersPerStage;
|
|
|
|
var addressSpace = constant ? "constant" : "device";
|
|
|
|
|
|
|
|
var argBufferPointers = new string[count];
|
|
|
|
|
2024-05-29 15:21:59 +00:00
|
|
|
foreach (BufferDefinition buffer in buffers)
|
|
|
|
{
|
2024-06-25 13:25:31 +00:00
|
|
|
var needsPadding = buffer.Layout == BufferLayout.Std140;
|
|
|
|
|
|
|
|
argBufferPointers[buffer.Binding] = $"{addressSpace} {Defaults.StructPrefix}_{buffer.Name}* {buffer.Name};";
|
|
|
|
|
|
|
|
context.AppendLine($"struct {Defaults.StructPrefix}_{buffer.Name}");
|
2024-05-29 15:21:59 +00:00
|
|
|
context.EnterScope();
|
|
|
|
|
|
|
|
foreach (StructureField field in buffer.Type.Fields)
|
|
|
|
{
|
2024-06-25 13:25:31 +00:00
|
|
|
var type = field.Type;
|
|
|
|
type |= (needsPadding && (field.Type & AggregateType.Array) != 0) ? AggregateType.Vector4 : AggregateType.Invalid;
|
|
|
|
|
|
|
|
type &= ~AggregateType.Array;
|
|
|
|
|
|
|
|
string typeName = GetVarTypeName(type);
|
2024-06-21 09:31:21 +00:00
|
|
|
string arraySuffix = "";
|
2024-05-29 15:21:59 +00:00
|
|
|
|
2024-06-21 09:31:21 +00:00
|
|
|
if (field.Type.HasFlag(AggregateType.Array))
|
2024-05-29 15:21:59 +00:00
|
|
|
{
|
2024-06-21 09:31:21 +00:00
|
|
|
if (field.ArrayLength > 0)
|
|
|
|
{
|
|
|
|
arraySuffix = $"[{field.ArrayLength}]";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Probably UB, but this is the approach that MVK takes
|
|
|
|
arraySuffix = "[1]";
|
|
|
|
}
|
2024-05-29 15:21:59 +00:00
|
|
|
}
|
2024-06-21 09:31:21 +00:00
|
|
|
|
|
|
|
context.AppendLine($"{typeName} {field.Name}{arraySuffix};");
|
2024-05-29 15:21:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
context.LeaveScope(";");
|
|
|
|
context.AppendLine();
|
2024-05-20 17:07:27 +00:00
|
|
|
}
|
2024-06-25 13:25:31 +00:00
|
|
|
|
|
|
|
context.AppendLine($"struct {name}");
|
|
|
|
context.EnterScope();
|
|
|
|
|
|
|
|
for (int i = 0; i < argBufferPointers.Length; i++)
|
|
|
|
{
|
|
|
|
if (argBufferPointers[i] == null)
|
|
|
|
{
|
|
|
|
// We need to pad the struct definition in order to read
|
|
|
|
// non-contiguous resources correctly.
|
|
|
|
context.AppendLine($"ulong padding_{i};");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
context.AppendLine(argBufferPointers[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
context.LeaveScope(";");
|
|
|
|
context.AppendLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void DeclareTextures(CodeGenContext context, IEnumerable<TextureDefinition> textures)
|
|
|
|
{
|
|
|
|
context.AppendLine("struct Textures");
|
|
|
|
context.EnterScope();
|
|
|
|
|
|
|
|
var argBufferPointers = new string[Defaults.MaxTexturesPerStage * 2];
|
|
|
|
|
|
|
|
foreach (TextureDefinition texture in textures)
|
|
|
|
{
|
|
|
|
var textureTypeName = texture.Type.ToMslTextureType();
|
|
|
|
argBufferPointers[texture.Binding] = $"{textureTypeName} tex_{texture.Name};";
|
|
|
|
|
|
|
|
if (!texture.Separate)
|
|
|
|
{
|
|
|
|
argBufferPointers[Defaults.MaxTexturesPerStage + texture.Binding] = $"sampler samp_{texture.Name};";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < argBufferPointers.Length; i++)
|
|
|
|
{
|
|
|
|
if (argBufferPointers[i] == null)
|
|
|
|
{
|
|
|
|
// We need to pad the struct definition in order to read
|
|
|
|
// non-contiguous resources correctly.
|
|
|
|
context.AppendLine($"ulong padding_{i};");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
context.AppendLine(argBufferPointers[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
context.LeaveScope(";");
|
|
|
|
context.AppendLine();
|
2024-05-20 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2023-08-15 13:17:00 +00:00
|
|
|
private static void DeclareInputAttributes(CodeGenContext context, IEnumerable<IoDefinition> inputs)
|
|
|
|
{
|
|
|
|
if (context.Definitions.IaIndexing)
|
|
|
|
{
|
|
|
|
// Not handled
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-06-25 13:25:31 +00:00
|
|
|
if (inputs.Any() || context.Definitions.Stage != ShaderStage.Compute)
|
2023-08-15 13:17:00 +00:00
|
|
|
{
|
|
|
|
string prefix = "";
|
|
|
|
|
|
|
|
switch (context.Definitions.Stage)
|
|
|
|
{
|
|
|
|
case ShaderStage.Vertex:
|
2024-03-19 21:18:59 +00:00
|
|
|
context.AppendLine($"struct VertexIn");
|
2023-08-15 13:17:00 +00:00
|
|
|
break;
|
|
|
|
case ShaderStage.Fragment:
|
2024-03-20 01:04:31 +00:00
|
|
|
context.AppendLine($"struct FragmentIn");
|
2023-08-15 13:17:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
context.EnterScope();
|
|
|
|
|
2024-05-22 19:07:12 +00:00
|
|
|
if (context.Definitions.Stage == ShaderStage.Fragment)
|
|
|
|
{
|
|
|
|
// TODO: check if it's needed
|
2024-06-25 13:25:31 +00:00
|
|
|
context.AppendLine("float4 position [[position, invariant]];");
|
2024-05-29 17:31:10 +00:00
|
|
|
context.AppendLine("bool front_facing [[front_facing]];");
|
2024-06-25 13:51:54 +00:00
|
|
|
context.AppendLine("float2 point_coord [[point_coord]];");
|
2024-05-22 19:07:12 +00:00
|
|
|
}
|
|
|
|
|
2023-08-15 13:17:00 +00:00
|
|
|
foreach (var ioDefinition in inputs.OrderBy(x => x.Location))
|
|
|
|
{
|
2024-06-28 20:13:59 +00:00
|
|
|
string iq = string.Empty;
|
|
|
|
|
|
|
|
if (context.Definitions.Stage == ShaderStage.Fragment)
|
|
|
|
{
|
|
|
|
iq = context.Definitions.ImapTypes[ioDefinition.Location].GetFirstUsedType() switch
|
|
|
|
{
|
|
|
|
PixelImap.Constant => "[[flat]] ",
|
|
|
|
PixelImap.ScreenLinear => "[[center_no_perspective]] ",
|
|
|
|
_ => string.Empty,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-05-22 19:02:21 +00:00
|
|
|
string type = ioDefinition.IoVariable switch
|
|
|
|
{
|
2024-05-22 19:07:12 +00:00
|
|
|
// IoVariable.Position => "float4",
|
2024-05-22 19:02:21 +00:00
|
|
|
IoVariable.GlobalId => "uint3",
|
|
|
|
IoVariable.VertexId => "uint",
|
|
|
|
IoVariable.VertexIndex => "uint",
|
2024-06-25 13:51:54 +00:00
|
|
|
// IoVariable.PointCoord => "float2",
|
2024-06-25 13:25:31 +00:00
|
|
|
_ => GetVarTypeName(context.Definitions.GetUserDefinedType(ioDefinition.Location, isOutput: false))
|
2024-05-22 19:02:21 +00:00
|
|
|
};
|
|
|
|
string name = ioDefinition.IoVariable switch
|
|
|
|
{
|
2024-05-22 19:07:12 +00:00
|
|
|
// IoVariable.Position => "position",
|
2024-05-22 19:02:21 +00:00
|
|
|
IoVariable.GlobalId => "global_id",
|
|
|
|
IoVariable.VertexId => "vertex_id",
|
|
|
|
IoVariable.VertexIndex => "vertex_index",
|
2024-06-25 13:51:54 +00:00
|
|
|
// IoVariable.PointCoord => "point_coord",
|
2024-06-25 13:25:31 +00:00
|
|
|
_ => $"{Defaults.IAttributePrefix}{ioDefinition.Location}"
|
2024-05-22 19:02:21 +00:00
|
|
|
};
|
|
|
|
string suffix = ioDefinition.IoVariable switch
|
2024-03-20 01:04:31 +00:00
|
|
|
{
|
2024-06-25 13:25:31 +00:00
|
|
|
// IoVariable.Position => "[[position, invariant]]",
|
2024-05-22 19:02:21 +00:00
|
|
|
IoVariable.GlobalId => "[[thread_position_in_grid]]",
|
|
|
|
IoVariable.VertexId => "[[vertex_id]]",
|
|
|
|
// TODO: Avoid potential redeclaration
|
|
|
|
IoVariable.VertexIndex => "[[vertex_id]]",
|
2024-06-25 13:51:54 +00:00
|
|
|
// IoVariable.PointCoord => "[[point_coord]]",
|
2024-05-22 19:02:21 +00:00
|
|
|
IoVariable.UserDefined => context.Definitions.Stage == ShaderStage.Fragment ? $"[[user(loc{ioDefinition.Location})]]" : $"[[attribute({ioDefinition.Location})]]",
|
2024-03-20 01:04:31 +00:00
|
|
|
_ => ""
|
|
|
|
};
|
2023-08-15 13:17:00 +00:00
|
|
|
|
2024-06-28 20:13:59 +00:00
|
|
|
context.AppendLine($"{type} {name} {iq}{suffix};");
|
2023-08-15 13:17:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
context.LeaveScope(";");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-09 15:33:28 +00:00
|
|
|
|
2024-05-30 15:11:48 +00:00
|
|
|
private static void DeclareOutputAttributes(CodeGenContext context, IEnumerable<IoDefinition> outputs)
|
2023-10-09 15:33:28 +00:00
|
|
|
{
|
|
|
|
if (context.Definitions.IaIndexing)
|
|
|
|
{
|
|
|
|
// Not handled
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-05-30 15:11:48 +00:00
|
|
|
if (outputs.Any() || context.Definitions.Stage == ShaderStage.Fragment)
|
2023-10-09 15:33:28 +00:00
|
|
|
{
|
|
|
|
string prefix = "";
|
|
|
|
|
|
|
|
switch (context.Definitions.Stage)
|
|
|
|
{
|
|
|
|
case ShaderStage.Vertex:
|
2024-03-19 21:18:59 +00:00
|
|
|
context.AppendLine($"struct VertexOut");
|
2023-10-09 15:33:28 +00:00
|
|
|
break;
|
|
|
|
case ShaderStage.Fragment:
|
2024-03-19 21:18:59 +00:00
|
|
|
context.AppendLine($"struct FragmentOut");
|
2023-10-09 15:33:28 +00:00
|
|
|
break;
|
|
|
|
case ShaderStage.Compute:
|
2024-03-20 01:11:48 +00:00
|
|
|
context.AppendLine($"struct KernelOut");
|
2023-10-09 15:33:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
context.EnterScope();
|
|
|
|
|
2024-05-30 15:11:48 +00:00
|
|
|
foreach (var ioDefinition in outputs.OrderBy(x => x.Location))
|
2023-10-09 15:33:28 +00:00
|
|
|
{
|
2024-03-19 21:18:59 +00:00
|
|
|
string type = ioDefinition.IoVariable switch
|
|
|
|
{
|
|
|
|
IoVariable.Position => "float4",
|
|
|
|
IoVariable.PointSize => "float",
|
2024-06-25 13:25:31 +00:00
|
|
|
IoVariable.FragmentOutputColor => GetVarTypeName(context.Definitions.GetFragmentOutputColorType(ioDefinition.Location)),
|
2024-05-23 00:27:37 +00:00
|
|
|
IoVariable.FragmentOutputDepth => "float",
|
2024-06-25 13:25:31 +00:00
|
|
|
_ => GetVarTypeName(context.Definitions.GetUserDefinedType(ioDefinition.Location, isOutput: true))
|
2024-03-19 21:18:59 +00:00
|
|
|
};
|
2023-10-11 00:00:56 +00:00
|
|
|
string name = ioDefinition.IoVariable switch
|
|
|
|
{
|
|
|
|
IoVariable.Position => "position",
|
2024-03-19 21:18:59 +00:00
|
|
|
IoVariable.PointSize => "point_size",
|
2024-05-20 16:38:08 +00:00
|
|
|
IoVariable.FragmentOutputColor => $"color{ioDefinition.Location}",
|
2024-05-23 00:27:37 +00:00
|
|
|
IoVariable.FragmentOutputDepth => "depth",
|
2024-06-25 13:25:31 +00:00
|
|
|
_ => $"{Defaults.OAttributePrefix}{ioDefinition.Location}"
|
2023-10-11 00:00:56 +00:00
|
|
|
};
|
|
|
|
string suffix = ioDefinition.IoVariable switch
|
|
|
|
{
|
2024-06-25 13:25:31 +00:00
|
|
|
IoVariable.Position => "[[position, invariant]]",
|
2024-05-22 19:02:21 +00:00
|
|
|
IoVariable.PointSize => "[[point_size]]",
|
|
|
|
IoVariable.UserDefined => $"[[user(loc{ioDefinition.Location})]]",
|
|
|
|
IoVariable.FragmentOutputColor => $"[[color({ioDefinition.Location})]]",
|
2024-05-23 00:27:37 +00:00
|
|
|
IoVariable.FragmentOutputDepth => "[[depth(any)]]",
|
2023-10-11 00:00:56 +00:00
|
|
|
_ => ""
|
|
|
|
};
|
2023-10-09 15:33:28 +00:00
|
|
|
|
2024-05-22 19:02:21 +00:00
|
|
|
context.AppendLine($"{type} {name} {suffix};");
|
2023-10-09 15:33:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
context.LeaveScope(";");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-06-22 13:38:09 +00:00
|
|
|
|
|
|
|
private static void AppendHelperFunction(CodeGenContext context, string filename)
|
|
|
|
{
|
|
|
|
string code = EmbeddedResources.ReadAllText(filename);
|
|
|
|
|
|
|
|
code = code.Replace("\t", CodeGenContext.Tab);
|
|
|
|
|
|
|
|
context.AppendLine(code);
|
|
|
|
context.AppendLine();
|
|
|
|
}
|
2024-08-31 20:42:56 +00:00
|
|
|
}
|
2024-03-18 18:51:44 +00:00
|
|
|
}
|