| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 |
- using Ryujinx.Common;
- using Ryujinx.Graphics.Shader.StructuredIr;
- using Ryujinx.Graphics.Shader.Translation;
- using Spv.Generator;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using static Spv.Specification;
- namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
- {
- static class Declarations
- {
- // At least 16 attributes are guaranteed by the spec.
- public const int MaxAttributes = 16;
- private static readonly string[] StagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" };
- 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<VariableType> argTypes, int argIndex)
- {
- foreach (var argType in argTypes)
- {
- var argPointerType = context.TypePointer(StorageClass.Function, context.GetType(argType.Convert()));
- 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.Convert()));
- var spvLocal = context.Variable(localPointerType, StorageClass.Function);
- context.AddLocalVariable(spvLocal);
- context.DeclareLocal(local, spvLocal);
- }
- var ivector2Type = context.TypeVector(context.TypeS32(), 2);
- var coordTempPointerType = context.TypePointer(StorageClass.Function, ivector2Type);
- var coordTemp = context.Variable(coordTempPointerType, StorageClass.Function);
- context.AddLocalVariable(coordTemp);
- context.CoordTemp = coordTemp;
- }
- public static void DeclareLocalForArgs(CodeGenContext context, List<StructuredFunction> functions)
- {
- for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++)
- {
- StructuredFunction function = functions[funcIndex];
- Instruction[] locals = new Instruction[function.InArguments.Length];
- for (int i = 0; i < function.InArguments.Length; i++)
- {
- var type = function.GetArgumentType(i).Convert();
- 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)
- {
- if (context.Config.Stage == ShaderStage.Compute)
- {
- int localMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeLocalMemorySize(), 4);
- if (localMemorySize != 0)
- {
- DeclareLocalMemory(context, localMemorySize);
- }
- int sharedMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeSharedMemorySize(), 4);
- if (sharedMemorySize != 0)
- {
- DeclareSharedMemory(context, sharedMemorySize);
- }
- }
- else if (context.Config.LocalMemorySize != 0)
- {
- int localMemorySize = BitUtils.DivRoundUp(context.Config.LocalMemorySize, 4);
- DeclareLocalMemory(context, localMemorySize);
- }
- DeclareSupportBuffer(context);
- DeclareUniformBuffers(context, context.Config.GetConstantBufferDescriptors());
- DeclareStorageBuffers(context, context.Config.GetStorageBufferDescriptors());
- DeclareSamplers(context, context.Config.GetTextureDescriptors());
- DeclareImages(context, context.Config.GetImageDescriptors());
- DeclareInputAttributes(context, info, perPatch: false);
- DeclareOutputAttributes(context, info, perPatch: false);
- DeclareInputAttributes(context, info, perPatch: true);
- DeclareOutputAttributes(context, info, perPatch: true);
- }
- private static void DeclareLocalMemory(CodeGenContext context, int size)
- {
- context.LocalMemory = DeclareMemory(context, StorageClass.Private, size);
- }
- private static void DeclareSharedMemory(CodeGenContext context, int size)
- {
- context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size);
- }
- private static Instruction DeclareMemory(CodeGenContext context, StorageClass storage, int size)
- {
- var arrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), size));
- var pointerType = context.TypePointer(storage, arrayType);
- var variable = context.Variable(pointerType, storage);
- context.AddGlobalVariable(variable);
- return variable;
- }
- private static void DeclareSupportBuffer(CodeGenContext context)
- {
- if (!context.Config.Stage.SupportsRenderScale() && !(context.Config.LastInVertexPipeline && context.Config.GpuAccessor.QueryViewportTransformDisable()))
- {
- return;
- }
- var isBgraArrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), SupportBuffer.FragmentIsBgraCount));
- var viewportInverseVectorType = context.TypeVector(context.TypeFP32(), 4);
- var renderScaleArrayType = context.TypeArray(context.TypeFP32(), context.Constant(context.TypeU32(), SupportBuffer.RenderScaleMaxCount));
- context.Decorate(isBgraArrayType, Decoration.ArrayStride, (LiteralInteger)SupportBuffer.FieldSize);
- context.Decorate(renderScaleArrayType, Decoration.ArrayStride, (LiteralInteger)SupportBuffer.FieldSize);
- var supportBufferStructType = context.TypeStruct(false, context.TypeU32(), isBgraArrayType, viewportInverseVectorType, context.TypeS32(), renderScaleArrayType);
- context.MemberDecorate(supportBufferStructType, 0, Decoration.Offset, (LiteralInteger)SupportBuffer.FragmentAlphaTestOffset);
- context.MemberDecorate(supportBufferStructType, 1, Decoration.Offset, (LiteralInteger)SupportBuffer.FragmentIsBgraOffset);
- context.MemberDecorate(supportBufferStructType, 2, Decoration.Offset, (LiteralInteger)SupportBuffer.ViewportInverseOffset);
- context.MemberDecorate(supportBufferStructType, 3, Decoration.Offset, (LiteralInteger)SupportBuffer.FragmentRenderScaleCountOffset);
- context.MemberDecorate(supportBufferStructType, 4, Decoration.Offset, (LiteralInteger)SupportBuffer.GraphicsRenderScaleOffset);
- context.Decorate(supportBufferStructType, Decoration.Block);
- var supportBufferPointerType = context.TypePointer(StorageClass.Uniform, supportBufferStructType);
- var supportBufferVariable = context.Variable(supportBufferPointerType, StorageClass.Uniform);
- context.Decorate(supportBufferVariable, Decoration.DescriptorSet, (LiteralInteger)0);
- context.Decorate(supportBufferVariable, Decoration.Binding, (LiteralInteger)0);
- context.AddGlobalVariable(supportBufferVariable);
- context.SupportBuffer = supportBufferVariable;
- }
- private static void DeclareUniformBuffers(CodeGenContext context, BufferDescriptor[] descriptors)
- {
- if (descriptors.Length == 0)
- {
- return;
- }
- uint ubSize = Constants.ConstantBufferSize / 16;
- var ubArrayType = context.TypeArray(context.TypeVector(context.TypeFP32(), 4), context.Constant(context.TypeU32(), ubSize), true);
- context.Decorate(ubArrayType, Decoration.ArrayStride, (LiteralInteger)16);
- var ubStructType = context.TypeStruct(true, ubArrayType);
- context.Decorate(ubStructType, Decoration.Block);
- context.MemberDecorate(ubStructType, 0, Decoration.Offset, (LiteralInteger)0);
- if (context.Config.UsedFeatures.HasFlag(FeatureFlags.CbIndexing))
- {
- int count = descriptors.Max(x => x.Slot) + 1;
- var ubStructArrayType = context.TypeArray(ubStructType, context.Constant(context.TypeU32(), count));
- var ubPointerType = context.TypePointer(StorageClass.Uniform, ubStructArrayType);
- var ubVariable = context.Variable(ubPointerType, StorageClass.Uniform);
- context.Name(ubVariable, $"{GetStagePrefix(context.Config.Stage)}_u");
- context.Decorate(ubVariable, Decoration.DescriptorSet, (LiteralInteger)0);
- context.Decorate(ubVariable, Decoration.Binding, (LiteralInteger)context.Config.FirstConstantBufferBinding);
- context.AddGlobalVariable(ubVariable);
- context.UniformBuffersArray = ubVariable;
- }
- else
- {
- var ubPointerType = context.TypePointer(StorageClass.Uniform, ubStructType);
- foreach (var descriptor in descriptors)
- {
- var ubVariable = context.Variable(ubPointerType, StorageClass.Uniform);
- context.Name(ubVariable, $"{GetStagePrefix(context.Config.Stage)}_c{descriptor.Slot}");
- context.Decorate(ubVariable, Decoration.DescriptorSet, (LiteralInteger)0);
- context.Decorate(ubVariable, Decoration.Binding, (LiteralInteger)descriptor.Binding);
- context.AddGlobalVariable(ubVariable);
- context.UniformBuffers.Add(descriptor.Slot, ubVariable);
- }
- }
- }
- private static void DeclareStorageBuffers(CodeGenContext context, BufferDescriptor[] descriptors)
- {
- if (descriptors.Length == 0)
- {
- return;
- }
- int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 1 : 0;
- int count = descriptors.Max(x => x.Slot) + 1;
- var sbArrayType = context.TypeRuntimeArray(context.TypeU32());
- context.Decorate(sbArrayType, Decoration.ArrayStride, (LiteralInteger)4);
- var sbStructType = context.TypeStruct(true, sbArrayType);
- context.Decorate(sbStructType, Decoration.BufferBlock);
- context.MemberDecorate(sbStructType, 0, Decoration.Offset, (LiteralInteger)0);
- var sbStructArrayType = context.TypeArray(sbStructType, context.Constant(context.TypeU32(), count));
- var sbPointerType = context.TypePointer(StorageClass.Uniform, sbStructArrayType);
- var sbVariable = context.Variable(sbPointerType, StorageClass.Uniform);
- context.Name(sbVariable, $"{GetStagePrefix(context.Config.Stage)}_s");
- context.Decorate(sbVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
- context.Decorate(sbVariable, Decoration.Binding, (LiteralInteger)context.Config.FirstStorageBufferBinding);
- context.AddGlobalVariable(sbVariable);
- context.StorageBuffersArray = sbVariable;
- }
- private static void DeclareSamplers(CodeGenContext context, TextureDescriptor[] descriptors)
- {
- foreach (var descriptor in descriptors)
- {
- var meta = new TextureMeta(descriptor.CbufSlot, descriptor.HandleIndex, descriptor.Format);
- if (context.Samplers.ContainsKey(meta))
- {
- continue;
- }
- int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 2 : 0;
- var dim = (descriptor.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 \"{descriptor.Type & SamplerType.Mask}\".")
- };
- var imageType = context.TypeImage(
- context.TypeFP32(),
- dim,
- descriptor.Type.HasFlag(SamplerType.Shadow),
- descriptor.Type.HasFlag(SamplerType.Array),
- descriptor.Type.HasFlag(SamplerType.Multisample),
- 1,
- ImageFormat.Unknown);
- var nameSuffix = meta.CbufSlot < 0 ? $"_tcb_{meta.Handle:X}" : $"_cb{meta.CbufSlot}_{meta.Handle:X}";
- var sampledImageType = context.TypeSampledImage(imageType);
- var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageType);
- var sampledImageVariable = context.Variable(sampledImagePointerType, StorageClass.UniformConstant);
- context.Samplers.Add(meta, (imageType, sampledImageType, sampledImageVariable));
- context.SamplersTypes.Add(meta, descriptor.Type);
- context.Name(sampledImageVariable, $"{GetStagePrefix(context.Config.Stage)}_tex{nameSuffix}");
- context.Decorate(sampledImageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
- context.Decorate(sampledImageVariable, Decoration.Binding, (LiteralInteger)descriptor.Binding);
- context.AddGlobalVariable(sampledImageVariable);
- }
- }
- private static void DeclareImages(CodeGenContext context, TextureDescriptor[] descriptors)
- {
- foreach (var descriptor in descriptors)
- {
- var meta = new TextureMeta(descriptor.CbufSlot, descriptor.HandleIndex, descriptor.Format);
- if (context.Images.ContainsKey(meta))
- {
- continue;
- }
- int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 3 : 0;
- var dim = GetDim(descriptor.Type);
- var imageType = context.TypeImage(
- context.GetType(meta.Format.GetComponentType().Convert()),
- dim,
- descriptor.Type.HasFlag(SamplerType.Shadow),
- descriptor.Type.HasFlag(SamplerType.Array),
- descriptor.Type.HasFlag(SamplerType.Multisample),
- AccessQualifier.ReadWrite,
- GetImageFormat(meta.Format));
- var nameSuffix = meta.CbufSlot < 0 ?
- $"_tcb_{meta.Handle:X}_{meta.Format.ToGlslFormat()}" :
- $"_cb{meta.CbufSlot}_{meta.Handle:X}_{meta.Format.ToGlslFormat()}";
- var imagePointerType = context.TypePointer(StorageClass.UniformConstant, imageType);
- var imageVariable = context.Variable(imagePointerType, StorageClass.UniformConstant);
- context.Images.Add(meta, (imageType, imageVariable));
- context.Name(imageVariable, $"{GetStagePrefix(context.Config.Stage)}_img{nameSuffix}");
- context.Decorate(imageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
- context.Decorate(imageVariable, Decoration.Binding, (LiteralInteger)descriptor.Binding);
- if (descriptor.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 DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info, bool perPatch)
- {
- bool iaIndexing = context.Config.UsedFeatures.HasFlag(FeatureFlags.IaIndexing);
- var inputs = perPatch ? info.InputsPerPatch : info.Inputs;
- foreach (int attr in inputs)
- {
- if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: false, perPatch))
- {
- continue;
- }
- bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
- if (iaIndexing && isUserAttr && !perPatch)
- {
- if (context.InputsArray == null)
- {
- var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
- attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
- if (context.Config.Stage == ShaderStage.Geometry)
- {
- attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)context.InputVertices));
- }
- var spvType = context.TypePointer(StorageClass.Input, attrType);
- var spvVar = context.Variable(spvType, StorageClass.Input);
- if (context.Config.PassthroughAttributes != 0 && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
- {
- context.Decorate(spvVar, Decoration.PassthroughNV);
- }
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0);
- context.AddGlobalVariable(spvVar);
- context.InputsArray = spvVar;
- }
- }
- else
- {
- PixelImap iq = PixelImap.Unused;
- if (context.Config.Stage == ShaderStage.Fragment)
- {
- if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
- {
- iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
- }
- else
- {
- AttributeInfo attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr: false);
- AggregateType elemType = attrInfo.Type & AggregateType.ElementTypeMask;
- if (attrInfo.IsBuiltin && (elemType == AggregateType.S32 || elemType == AggregateType.U32))
- {
- iq = PixelImap.Constant;
- }
- }
- }
- DeclareInputOrOutput(context, attr, perPatch, isOutAttr: false, iq);
- }
- }
- }
- private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info, bool perPatch)
- {
- bool oaIndexing = context.Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing);
- var outputs = perPatch ? info.OutputsPerPatch : info.Outputs;
- foreach (int attr in outputs)
- {
- if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: true, perPatch))
- {
- continue;
- }
- bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
- if (oaIndexing && isUserAttr && !perPatch)
- {
- if (context.OutputsArray == null)
- {
- var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
- attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
- if (context.Config.Stage == ShaderStage.TessellationControl)
- {
- attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
- }
- var spvType = context.TypePointer(StorageClass.Output, attrType);
- var spvVar = context.Variable(spvType, StorageClass.Output);
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0);
- context.AddGlobalVariable(spvVar);
- context.OutputsArray = spvVar;
- }
- }
- else
- {
- DeclareOutputAttribute(context, attr, perPatch);
- }
- }
- if (context.Config.Stage == ShaderStage.Vertex)
- {
- DeclareOutputAttribute(context, AttributeConsts.PositionX, perPatch: false);
- }
- }
- private static void DeclareOutputAttribute(CodeGenContext context, int attr, bool perPatch)
- {
- DeclareInputOrOutput(context, attr, perPatch, isOutAttr: true);
- }
- public static void DeclareInvocationId(CodeGenContext context)
- {
- DeclareInputOrOutput(context, AttributeConsts.LaneId, perPatch: false, isOutAttr: false);
- }
- private static void DeclareInputOrOutput(CodeGenContext context, int attr, bool perPatch, bool isOutAttr, PixelImap iq = PixelImap.Unused)
- {
- bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
- if (isUserAttr && context.Config.TransformFeedbackEnabled && !perPatch &&
- ((isOutAttr && context.Config.LastInVertexPipeline) ||
- (!isOutAttr && context.Config.Stage == ShaderStage.Fragment)))
- {
- DeclareTransformFeedbackInputOrOutput(context, attr, isOutAttr, iq);
- return;
- }
- var dict = perPatch
- ? (isOutAttr ? context.OutputsPerPatch : context.InputsPerPatch)
- : (isOutAttr ? context.Outputs : context.Inputs);
- var attrInfo = perPatch
- ? AttributeInfo.FromPatch(context.Config, attr, isOutAttr)
- : AttributeInfo.From(context.Config, attr, isOutAttr);
- if (dict.ContainsKey(attrInfo.BaseValue))
- {
- return;
- }
- var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
- var attrType = context.GetType(attrInfo.Type, attrInfo.Length);
- bool builtInPassthrough = false;
- if (AttributeInfo.IsArrayAttributeSpirv(context.Config.Stage, isOutAttr) && !perPatch && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
- {
- int arraySize = context.Config.Stage == ShaderStage.Geometry ? context.InputVertices : 32;
- attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)arraySize));
- if (context.Config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
- {
- builtInPassthrough = true;
- }
- }
- if (context.Config.Stage == ShaderStage.TessellationControl && isOutAttr && !perPatch)
- {
- attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
- }
- var spvType = context.TypePointer(storageClass, attrType);
- var spvVar = context.Variable(spvType, storageClass);
- if (builtInPassthrough)
- {
- context.Decorate(spvVar, Decoration.PassthroughNV);
- }
- if (attrInfo.IsBuiltin)
- {
- if (perPatch)
- {
- context.Decorate(spvVar, Decoration.Patch);
- }
- context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue));
- if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr)
- {
- var tfOutput = context.Info.GetTransformFeedbackOutput(attrInfo.BaseValue);
- if (tfOutput.Valid)
- {
- context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
- context.Decorate(spvVar, Decoration.XfbStride, (LiteralInteger)tfOutput.Stride);
- context.Decorate(spvVar, Decoration.Offset, (LiteralInteger)tfOutput.Offset);
- }
- }
- }
- else if (perPatch)
- {
- context.Decorate(spvVar, Decoration.Patch);
- int location = context.Config.GetPerPatchAttributeLocation((attr - AttributeConsts.UserAttributePerPatchBase) / 16);
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
- }
- else if (isUserAttr)
- {
- int location = (attr - AttributeConsts.UserAttributeBase) / 16;
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
- if (!isOutAttr &&
- !perPatch &&
- (context.Config.PassthroughAttributes & (1 << location)) != 0 &&
- context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
- {
- context.Decorate(spvVar, Decoration.PassthroughNV);
- }
- }
- else if (attr >= AttributeConsts.FragmentOutputColorBase && attr < AttributeConsts.FragmentOutputColorEnd)
- {
- int location = (attr - AttributeConsts.FragmentOutputColorBase) / 16;
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
- }
- if (!isOutAttr)
- {
- switch (iq)
- {
- case PixelImap.Constant:
- context.Decorate(spvVar, Decoration.Flat);
- break;
- case PixelImap.ScreenLinear:
- context.Decorate(spvVar, Decoration.NoPerspective);
- break;
- }
- }
- context.AddGlobalVariable(spvVar);
- dict.Add(attrInfo.BaseValue, spvVar);
- }
- private static void DeclareTransformFeedbackInputOrOutput(CodeGenContext context, int attr, bool isOutAttr, PixelImap iq = PixelImap.Unused)
- {
- var dict = isOutAttr ? context.Outputs : context.Inputs;
- var attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr);
- bool hasComponent = true;
- int component = (attr >> 2) & 3;
- int components = 1;
- var type = attrInfo.Type & AggregateType.ElementTypeMask;
- if (context.Config.LastInPipeline && isOutAttr)
- {
- components = context.Info.GetTransformFeedbackOutputComponents(attr);
- if (components > 1)
- {
- attr &= ~0xf;
- type = AggregateType.Vector | AggregateType.FP32;
- hasComponent = false;
- }
- }
- if (dict.ContainsKey(attr))
- {
- return;
- }
- var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
- var attrType = context.GetType(type, components);
- if (AttributeInfo.IsArrayAttributeSpirv(context.Config.Stage, isOutAttr) && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
- {
- int arraySize = context.Config.Stage == ShaderStage.Geometry ? context.InputVertices : 32;
- attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)arraySize));
- }
- if (context.Config.Stage == ShaderStage.TessellationControl && isOutAttr)
- {
- attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
- }
- var spvType = context.TypePointer(storageClass, attrType);
- var spvVar = context.Variable(spvType, storageClass);
- Debug.Assert(attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd);
- int location = (attr - AttributeConsts.UserAttributeBase) / 16;
- context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
- if (hasComponent)
- {
- context.Decorate(spvVar, Decoration.Component, (LiteralInteger)component);
- }
- if (isOutAttr)
- {
- var tfOutput = context.Info.GetTransformFeedbackOutput(attr);
- if (tfOutput.Valid)
- {
- context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
- context.Decorate(spvVar, Decoration.XfbStride, (LiteralInteger)tfOutput.Stride);
- context.Decorate(spvVar, Decoration.Offset, (LiteralInteger)tfOutput.Offset);
- }
- }
- else
- {
- if ((context.Config.PassthroughAttributes & (1 << location)) != 0 &&
- context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
- {
- context.Decorate(spvVar, Decoration.PassthroughNV);
- }
- switch (iq)
- {
- case PixelImap.Constant:
- context.Decorate(spvVar, Decoration.Flat);
- break;
- case PixelImap.ScreenLinear:
- context.Decorate(spvVar, Decoration.NoPerspective);
- break;
- }
- }
- context.AddGlobalVariable(spvVar);
- dict.Add(attr, spvVar);
- }
- private static BuiltIn GetBuiltIn(CodeGenContext context, int attr)
- {
- return attr switch
- {
- AttributeConsts.TessLevelOuter0 => BuiltIn.TessLevelOuter,
- AttributeConsts.TessLevelInner0 => BuiltIn.TessLevelInner,
- AttributeConsts.Layer => BuiltIn.Layer,
- AttributeConsts.ViewportIndex => BuiltIn.ViewportIndex,
- AttributeConsts.PointSize => BuiltIn.PointSize,
- AttributeConsts.PositionX => context.Config.Stage == ShaderStage.Fragment ? BuiltIn.FragCoord : BuiltIn.Position,
- AttributeConsts.ClipDistance0 => BuiltIn.ClipDistance,
- AttributeConsts.PointCoordX => BuiltIn.PointCoord,
- AttributeConsts.TessCoordX => BuiltIn.TessCoord,
- AttributeConsts.InstanceId => BuiltIn.InstanceId,
- AttributeConsts.VertexId => BuiltIn.VertexId,
- AttributeConsts.BaseInstance => BuiltIn.BaseInstance,
- AttributeConsts.BaseVertex => BuiltIn.BaseVertex,
- AttributeConsts.InstanceIndex => BuiltIn.InstanceIndex,
- AttributeConsts.VertexIndex => BuiltIn.VertexIndex,
- AttributeConsts.DrawIndex => BuiltIn.DrawIndex,
- AttributeConsts.FrontFacing => BuiltIn.FrontFacing,
- AttributeConsts.FragmentOutputDepth => BuiltIn.FragDepth,
- AttributeConsts.ThreadKill => BuiltIn.HelperInvocation,
- AttributeConsts.ThreadIdX => BuiltIn.LocalInvocationId,
- AttributeConsts.CtaIdX => BuiltIn.WorkgroupId,
- AttributeConsts.LaneId => BuiltIn.SubgroupLocalInvocationId,
- AttributeConsts.InvocationId => BuiltIn.InvocationId,
- AttributeConsts.PrimitiveId => BuiltIn.PrimitiveId,
- AttributeConsts.PatchVerticesIn => BuiltIn.PatchVertices,
- AttributeConsts.EqMask => BuiltIn.SubgroupEqMask,
- AttributeConsts.GeMask => BuiltIn.SubgroupGeMask,
- AttributeConsts.GtMask => BuiltIn.SubgroupGtMask,
- AttributeConsts.LeMask => BuiltIn.SubgroupLeMask,
- AttributeConsts.LtMask => BuiltIn.SubgroupLtMask,
- AttributeConsts.SupportBlockViewInverseX => BuiltIn.Position,
- AttributeConsts.SupportBlockViewInverseY => BuiltIn.Position,
- _ => throw new ArgumentException($"Invalid attribute number 0x{attr:X}.")
- };
- }
- private static string GetStagePrefix(ShaderStage stage)
- {
- return StagePrefixes[(int)stage];
- }
- }
- }
|