| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628 |
- using Ryujinx.Graphics.Shader.IntermediateRepresentation;
- using Ryujinx.Graphics.Shader.StructuredIr;
- using Ryujinx.Graphics.Shader.Translation;
- using Spv.Generator;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using static Spv.Specification;
- using SpvInstruction = Spv.Generator.Instruction;
- namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
- {
- static class Declarations
- {
- public static void DeclareParameters(CodeGenContext context, StructuredFunction function)
- {
- DeclareParameters(context, function.InArguments, 0);
- DeclareParameters(context, function.OutArguments, function.InArguments.Length);
- }
- private static void DeclareParameters(CodeGenContext context, IEnumerable<AggregateType> argTypes, int argIndex)
- {
- foreach (var argType in argTypes)
- {
- var argPointerType = context.TypePointer(StorageClass.Function, context.GetType(argType));
- var spvArg = context.FunctionParameter(argPointerType);
- context.DeclareArgument(argIndex++, spvArg);
- }
- }
- public static void DeclareLocals(CodeGenContext context, StructuredFunction function)
- {
- foreach (AstOperand local in function.Locals)
- {
- var localPointerType = context.TypePointer(StorageClass.Function, context.GetType(local.VarType));
- var spvLocal = context.Variable(localPointerType, StorageClass.Function);
- context.AddLocalVariable(spvLocal);
- context.DeclareLocal(local, spvLocal);
- }
- }
- public static void DeclareLocalForArgs(CodeGenContext context, List<StructuredFunction> functions)
- {
- for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++)
- {
- StructuredFunction function = functions[funcIndex];
- SpvInstruction[] locals = new SpvInstruction[function.InArguments.Length];
- for (int i = 0; i < function.InArguments.Length; i++)
- {
- var type = function.GetArgumentType(i);
- var localPointerType = context.TypePointer(StorageClass.Function, context.GetType(type));
- var spvLocal = context.Variable(localPointerType, StorageClass.Function);
- context.AddLocalVariable(spvLocal);
- locals[i] = spvLocal;
- }
- context.DeclareLocalForArgs(funcIndex, locals);
- }
- }
- public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info)
- {
- DeclareConstantBuffers(context, context.Properties.ConstantBuffers.Values);
- DeclareStorageBuffers(context, context.Properties.StorageBuffers.Values);
- DeclareMemories(context, context.Properties.LocalMemories, context.LocalMemories, StorageClass.Private);
- DeclareMemories(context, context.Properties.SharedMemories, context.SharedMemories, StorageClass.Workgroup);
- DeclareSamplers(context, context.Properties.Textures.Values);
- DeclareImages(context, context.Properties.Images.Values);
- DeclareInputsAndOutputs(context, info);
- }
- private static void DeclareMemories(
- CodeGenContext context,
- IReadOnlyDictionary<int, MemoryDefinition> memories,
- Dictionary<int, SpvInstruction> dict,
- StorageClass storage)
- {
- foreach ((int id, MemoryDefinition memory) in memories)
- {
- var pointerType = context.TypePointer(storage, context.GetType(memory.Type, memory.ArrayLength));
- var variable = context.Variable(pointerType, storage);
- context.AddGlobalVariable(variable);
- dict.Add(id, variable);
- }
- }
- private static void DeclareConstantBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers)
- {
- DeclareBuffers(context, buffers, isBuffer: false);
- }
- private static void DeclareStorageBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers)
- {
- DeclareBuffers(context, buffers, isBuffer: true);
- }
- private static void DeclareBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers, bool isBuffer)
- {
- HashSet<SpvInstruction> decoratedTypes = new();
- foreach (BufferDefinition buffer in buffers)
- {
- int setIndex = context.TargetApi == TargetApi.Vulkan ? buffer.Set : 0;
- int alignment = buffer.Layout == BufferLayout.Std140 ? 16 : 4;
- int alignmentMask = alignment - 1;
- int offset = 0;
- SpvInstruction[] structFieldTypes = new SpvInstruction[buffer.Type.Fields.Length];
- int[] structFieldOffsets = new int[buffer.Type.Fields.Length];
- for (int fieldIndex = 0; fieldIndex < buffer.Type.Fields.Length; fieldIndex++)
- {
- StructureField field = buffer.Type.Fields[fieldIndex];
- int fieldSize = (field.Type.GetSizeInBytes() + alignmentMask) & ~alignmentMask;
- structFieldTypes[fieldIndex] = context.GetType(field.Type, field.ArrayLength);
- structFieldOffsets[fieldIndex] = offset;
- if (field.Type.HasFlag(AggregateType.Array))
- {
- // We can't decorate the type more than once.
- if (decoratedTypes.Add(structFieldTypes[fieldIndex]))
- {
- context.Decorate(structFieldTypes[fieldIndex], Decoration.ArrayStride, (LiteralInteger)fieldSize);
- }
- // Zero lengths are assumed to be a "runtime array" (which does not have a explicit length
- // specified on the shader, and instead assumes the bound buffer length).
- // It is only valid as the last struct element.
- Debug.Assert(field.ArrayLength > 0 || fieldIndex == buffer.Type.Fields.Length - 1);
- offset += fieldSize * field.ArrayLength;
- }
- else
- {
- offset += fieldSize;
- }
- }
- var structType = context.TypeStruct(false, structFieldTypes);
- if (decoratedTypes.Add(structType))
- {
- context.Decorate(structType, isBuffer ? Decoration.BufferBlock : Decoration.Block);
- for (int fieldIndex = 0; fieldIndex < structFieldOffsets.Length; fieldIndex++)
- {
- context.MemberDecorate(structType, fieldIndex, Decoration.Offset, (LiteralInteger)structFieldOffsets[fieldIndex]);
- }
- }
- var pointerType = context.TypePointer(StorageClass.Uniform, structType);
- var variable = context.Variable(pointerType, StorageClass.Uniform);
- context.Name(variable, buffer.Name);
- context.Decorate(variable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
- context.Decorate(variable, Decoration.Binding, (LiteralInteger)buffer.Binding);
- context.AddGlobalVariable(variable);
- if (isBuffer)
- {
- context.StorageBuffers.Add(buffer.Binding, variable);
- }
- else
- {
- context.ConstantBuffers.Add(buffer.Binding, variable);
- }
- }
- }
- private static void DeclareSamplers(CodeGenContext context, IEnumerable<TextureDefinition> samplers)
- {
- foreach (var sampler in samplers)
- {
- int setIndex = context.TargetApi == TargetApi.Vulkan ? sampler.Set : 0;
- var dim = (sampler.Type & SamplerType.Mask) switch
- {
- SamplerType.Texture1D => Dim.Dim1D,
- SamplerType.Texture2D => Dim.Dim2D,
- SamplerType.Texture3D => Dim.Dim3D,
- SamplerType.TextureCube => Dim.Cube,
- SamplerType.TextureBuffer => Dim.Buffer,
- _ => throw new InvalidOperationException($"Invalid sampler type \"{sampler.Type & SamplerType.Mask}\"."),
- };
- var imageType = context.TypeImage(
- context.TypeFP32(),
- dim,
- sampler.Type.HasFlag(SamplerType.Shadow),
- sampler.Type.HasFlag(SamplerType.Array),
- sampler.Type.HasFlag(SamplerType.Multisample),
- 1,
- ImageFormat.Unknown);
- var sampledImageType = context.TypeSampledImage(imageType);
- var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageType);
- var sampledImageVariable = context.Variable(sampledImagePointerType, StorageClass.UniformConstant);
- context.Samplers.Add(sampler.Binding, (imageType, sampledImageType, sampledImageVariable));
- context.SamplersTypes.Add(sampler.Binding, sampler.Type);
- context.Name(sampledImageVariable, sampler.Name);
- context.Decorate(sampledImageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
- context.Decorate(sampledImageVariable, Decoration.Binding, (LiteralInteger)sampler.Binding);
- context.AddGlobalVariable(sampledImageVariable);
- }
- }
- private static void DeclareImages(CodeGenContext context, IEnumerable<TextureDefinition> images)
- {
- foreach (var image in images)
- {
- int setIndex = context.TargetApi == TargetApi.Vulkan ? image.Set : 0;
- var dim = GetDim(image.Type);
- var imageType = context.TypeImage(
- context.GetType(image.Format.GetComponentType()),
- dim,
- image.Type.HasFlag(SamplerType.Shadow),
- image.Type.HasFlag(SamplerType.Array),
- image.Type.HasFlag(SamplerType.Multisample),
- AccessQualifier.ReadWrite,
- GetImageFormat(image.Format));
- var imagePointerType = context.TypePointer(StorageClass.UniformConstant, imageType);
- var imageVariable = context.Variable(imagePointerType, StorageClass.UniformConstant);
- context.Images.Add(image.Binding, (imageType, imageVariable));
- context.Name(imageVariable, image.Name);
- context.Decorate(imageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
- context.Decorate(imageVariable, Decoration.Binding, (LiteralInteger)image.Binding);
- if (image.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
- {
- context.Decorate(imageVariable, Decoration.Coherent);
- }
- context.AddGlobalVariable(imageVariable);
- }
- }
- private static Dim GetDim(SamplerType type)
- {
- return (type & SamplerType.Mask) switch
- {
- SamplerType.Texture1D => Dim.Dim1D,
- SamplerType.Texture2D => Dim.Dim2D,
- SamplerType.Texture3D => Dim.Dim3D,
- SamplerType.TextureCube => Dim.Cube,
- SamplerType.TextureBuffer => Dim.Buffer,
- _ => throw new ArgumentException($"Invalid sampler type \"{type & SamplerType.Mask}\"."),
- };
- }
- private static ImageFormat GetImageFormat(TextureFormat format)
- {
- return format switch
- {
- TextureFormat.Unknown => ImageFormat.Unknown,
- TextureFormat.R8Unorm => ImageFormat.R8,
- TextureFormat.R8Snorm => ImageFormat.R8Snorm,
- TextureFormat.R8Uint => ImageFormat.R8ui,
- TextureFormat.R8Sint => ImageFormat.R8i,
- TextureFormat.R16Float => ImageFormat.R16f,
- TextureFormat.R16Unorm => ImageFormat.R16,
- TextureFormat.R16Snorm => ImageFormat.R16Snorm,
- TextureFormat.R16Uint => ImageFormat.R16ui,
- TextureFormat.R16Sint => ImageFormat.R16i,
- TextureFormat.R32Float => ImageFormat.R32f,
- TextureFormat.R32Uint => ImageFormat.R32ui,
- TextureFormat.R32Sint => ImageFormat.R32i,
- TextureFormat.R8G8Unorm => ImageFormat.Rg8,
- TextureFormat.R8G8Snorm => ImageFormat.Rg8Snorm,
- TextureFormat.R8G8Uint => ImageFormat.Rg8ui,
- TextureFormat.R8G8Sint => ImageFormat.Rg8i,
- TextureFormat.R16G16Float => ImageFormat.Rg16f,
- TextureFormat.R16G16Unorm => ImageFormat.Rg16,
- TextureFormat.R16G16Snorm => ImageFormat.Rg16Snorm,
- TextureFormat.R16G16Uint => ImageFormat.Rg16ui,
- TextureFormat.R16G16Sint => ImageFormat.Rg16i,
- TextureFormat.R32G32Float => ImageFormat.Rg32f,
- TextureFormat.R32G32Uint => ImageFormat.Rg32ui,
- TextureFormat.R32G32Sint => ImageFormat.Rg32i,
- TextureFormat.R8G8B8A8Unorm => ImageFormat.Rgba8,
- TextureFormat.R8G8B8A8Snorm => ImageFormat.Rgba8Snorm,
- TextureFormat.R8G8B8A8Uint => ImageFormat.Rgba8ui,
- TextureFormat.R8G8B8A8Sint => ImageFormat.Rgba8i,
- TextureFormat.R16G16B16A16Float => ImageFormat.Rgba16f,
- TextureFormat.R16G16B16A16Unorm => ImageFormat.Rgba16,
- TextureFormat.R16G16B16A16Snorm => ImageFormat.Rgba16Snorm,
- TextureFormat.R16G16B16A16Uint => ImageFormat.Rgba16ui,
- TextureFormat.R16G16B16A16Sint => ImageFormat.Rgba16i,
- TextureFormat.R32G32B32A32Float => ImageFormat.Rgba32f,
- TextureFormat.R32G32B32A32Uint => ImageFormat.Rgba32ui,
- TextureFormat.R32G32B32A32Sint => ImageFormat.Rgba32i,
- TextureFormat.R10G10B10A2Unorm => ImageFormat.Rgb10A2,
- TextureFormat.R10G10B10A2Uint => ImageFormat.Rgb10a2ui,
- TextureFormat.R11G11B10Float => ImageFormat.R11fG11fB10f,
- _ => throw new ArgumentException($"Invalid texture format \"{format}\"."),
- };
- }
- private static void DeclareInputsAndOutputs(CodeGenContext context, StructuredProgramInfo info)
- {
- int firstLocation = int.MaxValue;
- if (context.Definitions.Stage == ShaderStage.Fragment && context.Definitions.DualSourceBlend)
- {
- foreach (var ioDefinition in info.IoDefinitions)
- {
- if (ioDefinition.IoVariable == IoVariable.FragmentOutputColor && ioDefinition.Location < firstLocation)
- {
- firstLocation = ioDefinition.Location;
- }
- }
- }
- foreach (var ioDefinition in info.IoDefinitions)
- {
- PixelImap iq = PixelImap.Unused;
- if (context.Definitions.Stage == ShaderStage.Fragment)
- {
- var ioVariable = ioDefinition.IoVariable;
- if (ioVariable == IoVariable.UserDefined)
- {
- iq = context.Definitions.ImapTypes[ioDefinition.Location].GetFirstUsedType();
- }
- else
- {
- (_, AggregateType varType) = IoMap.GetSpirvBuiltIn(ioVariable);
- AggregateType elemType = varType & AggregateType.ElementTypeMask;
- if (elemType is AggregateType.S32 or AggregateType.U32)
- {
- iq = PixelImap.Constant;
- }
- }
- }
- else if (IoMap.IsPerVertexBuiltIn(ioDefinition.IoVariable))
- {
- continue;
- }
- bool isOutput = ioDefinition.StorageKind.IsOutput();
- bool isPerPatch = ioDefinition.StorageKind.IsPerPatch();
- DeclareInputOrOutput(context, ioDefinition, isOutput, isPerPatch, iq, firstLocation);
- }
- DeclarePerVertexBlock(context);
- }
- private static void DeclarePerVertexBlock(CodeGenContext context)
- {
- if (context.Definitions.Stage.IsVtg())
- {
- if (context.Definitions.Stage != ShaderStage.Vertex)
- {
- var perVertexInputStructType = CreatePerVertexStructType(context);
- int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.Definitions.InputTopology.ToInputVertices() : 32;
- var perVertexInputArrayType = context.TypeArray(perVertexInputStructType, context.Constant(context.TypeU32(), arraySize));
- var perVertexInputPointerType = context.TypePointer(StorageClass.Input, perVertexInputArrayType);
- var perVertexInputVariable = context.Variable(perVertexInputPointerType, StorageClass.Input);
- context.Name(perVertexInputVariable, "gl_in");
- context.AddGlobalVariable(perVertexInputVariable);
- context.Inputs.Add(new IoDefinition(StorageKind.Input, IoVariable.Position), perVertexInputVariable);
- }
- var perVertexOutputStructType = CreatePerVertexStructType(context);
- void DecorateTfo(IoVariable ioVariable, int fieldIndex)
- {
- if (context.Definitions.TryGetTransformFeedbackOutput(ioVariable, 0, 0, out var transformFeedbackOutput))
- {
- context.MemberDecorate(perVertexOutputStructType, fieldIndex, Decoration.XfbBuffer, (LiteralInteger)transformFeedbackOutput.Buffer);
- context.MemberDecorate(perVertexOutputStructType, fieldIndex, Decoration.XfbStride, (LiteralInteger)transformFeedbackOutput.Stride);
- context.MemberDecorate(perVertexOutputStructType, fieldIndex, Decoration.Offset, (LiteralInteger)transformFeedbackOutput.Offset);
- }
- }
- DecorateTfo(IoVariable.Position, 0);
- DecorateTfo(IoVariable.PointSize, 1);
- DecorateTfo(IoVariable.ClipDistance, 2);
- SpvInstruction perVertexOutputArrayType;
- if (context.Definitions.Stage == ShaderStage.TessellationControl)
- {
- int arraySize = context.Definitions.ThreadsPerInputPrimitive;
- perVertexOutputArrayType = context.TypeArray(perVertexOutputStructType, context.Constant(context.TypeU32(), arraySize));
- }
- else
- {
- perVertexOutputArrayType = perVertexOutputStructType;
- }
- var perVertexOutputPointerType = context.TypePointer(StorageClass.Output, perVertexOutputArrayType);
- var perVertexOutputVariable = context.Variable(perVertexOutputPointerType, StorageClass.Output);
- context.AddGlobalVariable(perVertexOutputVariable);
- context.Outputs.Add(new IoDefinition(StorageKind.Output, IoVariable.Position), perVertexOutputVariable);
- }
- }
- private static SpvInstruction CreatePerVertexStructType(CodeGenContext context)
- {
- var vec4FloatType = context.TypeVector(context.TypeFP32(), 4);
- var floatType = context.TypeFP32();
- var array8FloatType = context.TypeArray(context.TypeFP32(), context.Constant(context.TypeU32(), 8));
- var array1FloatType = context.TypeArray(context.TypeFP32(), context.Constant(context.TypeU32(), 1));
- var perVertexStructType = context.TypeStruct(true, vec4FloatType, floatType, array8FloatType, array1FloatType);
- context.Name(perVertexStructType, "gl_PerVertex");
- context.MemberName(perVertexStructType, 0, "gl_Position");
- context.MemberName(perVertexStructType, 1, "gl_PointSize");
- context.MemberName(perVertexStructType, 2, "gl_ClipDistance");
- context.MemberName(perVertexStructType, 3, "gl_CullDistance");
- context.Decorate(perVertexStructType, Decoration.Block);
- if (context.HostCapabilities.ReducedPrecision)
- {
- context.MemberDecorate(perVertexStructType, 0, Decoration.Invariant);
- }
- context.MemberDecorate(perVertexStructType, 0, Decoration.BuiltIn, (LiteralInteger)BuiltIn.Position);
- context.MemberDecorate(perVertexStructType, 1, Decoration.BuiltIn, (LiteralInteger)BuiltIn.PointSize);
- context.MemberDecorate(perVertexStructType, 2, Decoration.BuiltIn, (LiteralInteger)BuiltIn.ClipDistance);
- context.MemberDecorate(perVertexStructType, 3, Decoration.BuiltIn, (LiteralInteger)BuiltIn.CullDistance);
- return perVertexStructType;
- }
- private static void DeclareInputOrOutput(
- CodeGenContext context,
- IoDefinition ioDefinition,
- bool isOutput,
- bool isPerPatch,
- PixelImap iq = PixelImap.Unused,
- int firstLocation = 0)
- {
- IoVariable ioVariable = ioDefinition.IoVariable;
- var storageClass = isOutput ? StorageClass.Output : StorageClass.Input;
- bool isBuiltIn;
- BuiltIn builtIn = default;
- AggregateType varType;
- if (ioVariable == IoVariable.UserDefined)
- {
- varType = context.Definitions.GetUserDefinedType(ioDefinition.Location, isOutput);
- isBuiltIn = false;
- }
- else if (ioVariable == IoVariable.FragmentOutputColor)
- {
- varType = context.Definitions.GetFragmentOutputColorType(ioDefinition.Location);
- isBuiltIn = false;
- }
- else
- {
- (builtIn, varType) = IoMap.GetSpirvBuiltIn(ioVariable);
- isBuiltIn = true;
- if (varType == AggregateType.Invalid)
- {
- throw new InvalidOperationException($"Unknown variable {ioVariable}.");
- }
- }
- bool hasComponent = context.Definitions.HasPerLocationInputOrOutputComponent(ioVariable, ioDefinition.Location, ioDefinition.Component, isOutput);
- if (hasComponent)
- {
- varType &= AggregateType.ElementTypeMask;
- }
- else if (ioVariable == IoVariable.UserDefined && context.Definitions.HasTransformFeedbackOutputs(isOutput))
- {
- varType &= AggregateType.ElementTypeMask;
- varType |= context.Definitions.GetTransformFeedbackOutputComponents(ioDefinition.Location, ioDefinition.Component) switch
- {
- 2 => AggregateType.Vector2,
- 3 => AggregateType.Vector3,
- 4 => AggregateType.Vector4,
- _ => AggregateType.Invalid,
- };
- }
- var spvType = context.GetType(varType, IoMap.GetSpirvBuiltInArrayLength(ioVariable));
- bool builtInPassthrough = false;
- if (!isPerPatch && IoMap.IsPerVertex(ioVariable, context.Definitions.Stage, isOutput))
- {
- int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.Definitions.InputTopology.ToInputVertices() : 32;
- spvType = context.TypeArray(spvType, context.Constant(context.TypeU32(), arraySize));
- if (context.Definitions.GpPassthrough && context.HostCapabilities.SupportsGeometryShaderPassthrough)
- {
- builtInPassthrough = true;
- }
- }
- if (context.Definitions.Stage == ShaderStage.TessellationControl && isOutput && !isPerPatch)
- {
- spvType = context.TypeArray(spvType, context.Constant(context.TypeU32(), context.Definitions.ThreadsPerInputPrimitive));
- }
- var spvPointerType = context.TypePointer(storageClass, spvType);
- var spvVar = context.Variable(spvPointerType, storageClass);
- if (builtInPassthrough)
- {
- context.Decorate(spvVar, Decoration.PassthroughNV);
- }
- if (isBuiltIn)
- {
- if (isPerPatch)
- {
- context.Decorate(spvVar, Decoration.Patch);
- }
- if (context.HostCapabilities.ReducedPrecision && ioVariable == IoVariable.Position)
- {
- context.Decorate(spvVar, Decoration.Invariant);
- }
- context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)builtIn);
- }
- else if (isPerPatch)
- {
- context.Decorate(spvVar, Decoration.Patch);
- if (ioVariable == IoVariable.UserDefined)
- {
- int location = context.AttributeUsage.GetPerPatchAttributeLocation(ioDefinition.Location);
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
- }
- }
- else if (ioVariable == IoVariable.UserDefined)
- {
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)ioDefinition.Location);
- if (hasComponent)
- {
- context.Decorate(spvVar, Decoration.Component, (LiteralInteger)ioDefinition.Component);
- }
- if (!isOutput &&
- !isPerPatch &&
- (context.AttributeUsage.PassthroughAttributes & (1 << ioDefinition.Location)) != 0 &&
- context.HostCapabilities.SupportsGeometryShaderPassthrough)
- {
- context.Decorate(spvVar, Decoration.PassthroughNV);
- }
- }
- else if (ioVariable == IoVariable.FragmentOutputColor)
- {
- int location = ioDefinition.Location;
- if (context.Definitions.Stage == ShaderStage.Fragment && context.Definitions.DualSourceBlend)
- {
- int index = location - firstLocation;
- if ((uint)index < 2)
- {
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)firstLocation);
- context.Decorate(spvVar, Decoration.Index, (LiteralInteger)index);
- }
- else
- {
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
- }
- }
- else
- {
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
- }
- }
- if (!isOutput)
- {
- switch (iq)
- {
- case PixelImap.Constant:
- context.Decorate(spvVar, Decoration.Flat);
- break;
- case PixelImap.ScreenLinear:
- context.Decorate(spvVar, Decoration.NoPerspective);
- break;
- }
- }
- else if (context.Definitions.TryGetTransformFeedbackOutput(
- ioVariable,
- ioDefinition.Location,
- ioDefinition.Component,
- out var transformFeedbackOutput))
- {
- context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)transformFeedbackOutput.Buffer);
- context.Decorate(spvVar, Decoration.XfbStride, (LiteralInteger)transformFeedbackOutput.Stride);
- context.Decorate(spvVar, Decoration.Offset, (LiteralInteger)transformFeedbackOutput.Offset);
- }
- context.AddGlobalVariable(spvVar);
- var dict = isPerPatch
- ? (isOutput ? context.OutputsPerPatch : context.InputsPerPatch)
- : (isOutput ? context.Outputs : context.Inputs);
- dict.Add(ioDefinition, spvVar);
- }
- }
- }
|