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.Binding) + 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)descriptors[0].Binding); context.AddGlobalVariable(sbVariable); context.StorageBuffersArray = sbVariable; }
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; }
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; }
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); } }
private static SpvInstruction 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); }
public static SpvInstruction ApplyUnscaling( CodeGenContext context, AstTextureOperation texOp, SpvInstruction size, bool isBindless, bool isIndexed) { if (context.Config.Stage.SupportsRenderScale() && !isBindless && !isIndexed) { int index = context.Config.FindTextureDescriptorIndex(texOp); var pointerType = context.TypePointer(StorageClass.Uniform, context.TypeFP32()); var fieldIndex = context.Constant(context.TypeU32(), 4); var scaleIndex = context.Constant(context.TypeU32(), index); if (context.Config.Stage == ShaderStage.Vertex) { var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32()); var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 3)); var scaleCount = context.Load(context.TypeS32(), scaleCountElemPointer); scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount); } scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1)); var scaleElemPointer = context.AccessChain(pointerType, context.SupportBuffer, fieldIndex, scaleIndex); var scale = context.GlslFAbs(context.TypeFP32(), context.Load(context.TypeFP32(), scaleElemPointer)); var passthrough = context.FOrdEqual(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 1f)); var sizeFloat = context.ConvertSToF(context.TypeFP32(), size); var sizeUnscaled = context.FDiv(context.TypeFP32(), sizeFloat, scale); var sizeUnscaledInt = context.ConvertFToS(context.TypeS32(), sizeUnscaled); return(context.Select(context.TypeS32(), passthrough, size, sizeUnscaledInt)); } return(size); }
private static void DeclareSamplers(CodeGenContext context, TextureDescriptor[] descriptors) { foreach (var descriptor in descriptors) { var meta = new TextureMeta(descriptor.CbufSlot, descriptor.HandleIndex, descriptor.Format, descriptor.Type); if (context.Samplers.ContainsKey(meta)) { continue; } bool isBuffer = (descriptor.Type & SamplerType.Mask) == SamplerType.TextureBuffer; int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? (isBuffer ? 4 : 2) : 0; var dim = (meta.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 \"{meta.Type & SamplerType.Mask}\".") }; var imageType = context.TypeImage( context.TypeFP32(), dim, meta.Type.HasFlag(SamplerType.Shadow), meta.Type.HasFlag(SamplerType.Array), meta.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.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); } }
public static byte[] Generate(StructuredProgramInfo info, ShaderConfig config) { CodeGenContext context = new CodeGenContext(config); context.AddCapability(Capability.GroupNonUniformBallot); context.AddCapability(Capability.ImageBuffer); context.AddCapability(Capability.SampledBuffer); context.AddCapability(Capability.SubgroupBallotKHR); context.AddCapability(Capability.SubgroupVoteKHR); context.AddExtension("SPV_KHR_shader_ballot"); context.AddExtension("SPV_KHR_subgroup_vote"); Declarations.DeclareAll(context, info); if ((info.HelperFunctionsMask & NeedsInvocationIdMask) != 0) { Declarations.DeclareInvocationId(context); } for (int funcIndex = 0; funcIndex < info.Functions.Count; funcIndex++) { var function = info.Functions[funcIndex]; var retType = context.GetType(function.ReturnType.Convert()); var funcArgs = new SpvInstruction[function.InArguments.Length + function.OutArguments.Length]; for (int argIndex = 0; argIndex < funcArgs.Length; argIndex++) { var argType = context.GetType(function.GetArgumentType(argIndex).Convert()); var argPointerType = context.TypePointer(StorageClass.Function, argType); funcArgs[argIndex] = argPointerType; } var funcType = context.TypeFunction(retType, false, funcArgs); var spvFunc = context.Function(retType, FunctionControlMask.MaskNone, funcType); context.DeclareFunction(funcIndex, function, spvFunc); } for (int funcIndex = 0; funcIndex < info.Functions.Count; funcIndex++) { Generate(context, info, funcIndex); } return(context.Generate()); }
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); } }
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).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); } }
private static void DeclareUniformBuffers(CodeGenContext context, BufferDescriptor[] descriptors) { 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); 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); } }
public static byte[] Generate(StructuredProgramInfo info, ShaderConfig config) { SpvInstructionPool instPool; SpvLiteralIntegerPool integerPool; lock (PoolLock) { instPool = InstructionPool.Allocate(); integerPool = IntegerPool.Allocate(); } CodeGenContext context = new CodeGenContext(info, config, instPool, integerPool); context.AddCapability(Capability.GroupNonUniformBallot); context.AddCapability(Capability.ImageBuffer); context.AddCapability(Capability.ImageGatherExtended); context.AddCapability(Capability.ImageQuery); context.AddCapability(Capability.SampledBuffer); context.AddCapability(Capability.SubgroupBallotKHR); context.AddCapability(Capability.SubgroupVoteKHR); if (config.TransformFeedbackEnabled && config.LastInVertexPipeline) { context.AddCapability(Capability.TransformFeedback); } if (config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock()) { context.AddCapability(Capability.FragmentShaderPixelInterlockEXT); context.AddExtension("SPV_EXT_fragment_shader_interlock"); } else if (config.Stage == ShaderStage.Geometry) { context.AddCapability(Capability.Geometry); if (config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough()) { context.AddExtension("SPV_NV_geometry_shader_passthrough"); context.AddCapability(Capability.GeometryShaderPassthroughNV); } } else if (config.Stage == ShaderStage.TessellationControl || config.Stage == ShaderStage.TessellationEvaluation) { context.AddCapability(Capability.Tessellation); } context.AddExtension("SPV_KHR_shader_ballot"); context.AddExtension("SPV_KHR_subgroup_vote"); Declarations.DeclareAll(context, info); if ((info.HelperFunctionsMask & NeedsInvocationIdMask) != 0) { Declarations.DeclareInvocationId(context); } for (int funcIndex = 0; funcIndex < info.Functions.Count; funcIndex++) { var function = info.Functions[funcIndex]; var retType = context.GetType(function.ReturnType.Convert()); var funcArgs = new SpvInstruction[function.InArguments.Length + function.OutArguments.Length]; for (int argIndex = 0; argIndex < funcArgs.Length; argIndex++) { var argType = context.GetType(function.GetArgumentType(argIndex).Convert()); var argPointerType = context.TypePointer(StorageClass.Function, argType); funcArgs[argIndex] = argPointerType; } var funcType = context.TypeFunction(retType, false, funcArgs); var spvFunc = context.Function(retType, FunctionControlMask.MaskNone, funcType); context.DeclareFunction(funcIndex, function, spvFunc); } for (int funcIndex = 0; funcIndex < info.Functions.Count; funcIndex++) { Generate(context, info, funcIndex); } byte[] result = context.Generate(); lock (PoolLock) { InstructionPool.Release(instPool); IntegerPool.Release(integerPool); } return(result); }
private static SpvInstruction ApplyScaling2D(CodeGenContext context, SpvInstruction vector, int index) { var pointerType = context.TypePointer(StorageClass.Uniform, context.TypeFP32()); var fieldIndex = context.Constant(context.TypeU32(), 4); var scaleIndex = context.Constant(context.TypeU32(), index); if (context.Config.Stage == ShaderStage.Vertex) { var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32()); var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 3)); var scaleCount = context.Load(context.TypeS32(), scaleCountElemPointer); scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount); } scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1)); var scaleElemPointer = context.AccessChain(pointerType, context.SupportBuffer, fieldIndex, scaleIndex); var scale = context.Load(context.TypeFP32(), scaleElemPointer); var ivector2Type = context.TypeVector(context.TypeS32(), 2); var localVector = context.CoordTemp; var passthrough = context.FOrdEqual(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 1f)); var mergeLabel = context.Label(); if (context.Config.Stage == ShaderStage.Fragment) { var scaledInterpolatedLabel = context.Label(); var scaledNoInterpolationLabel = context.Label(); var needsInterpolation = context.FOrdLessThan(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 0f)); context.SelectionMerge(mergeLabel, SelectionControlMask.MaskNone); context.BranchConditional(needsInterpolation, scaledInterpolatedLabel, scaledNoInterpolationLabel); // scale < 0.0 context.AddLabel(scaledInterpolatedLabel); ApplyScalingInterpolated(context, localVector, vector, scale); context.Branch(mergeLabel); // scale >= 0.0 context.AddLabel(scaledNoInterpolationLabel); ApplyScalingNoInterpolation(context, localVector, vector, scale); context.Branch(mergeLabel); context.AddLabel(mergeLabel); var passthroughLabel = context.Label(); var finalMergeLabel = context.Label(); context.SelectionMerge(finalMergeLabel, SelectionControlMask.MaskNone); context.BranchConditional(passthrough, passthroughLabel, finalMergeLabel); context.AddLabel(passthroughLabel); context.Store(localVector, vector); context.Branch(finalMergeLabel); context.AddLabel(finalMergeLabel); return(context.Load(ivector2Type, localVector)); } else { var passthroughLabel = context.Label(); var scaledLabel = context.Label(); context.SelectionMerge(mergeLabel, SelectionControlMask.MaskNone); context.BranchConditional(passthrough, passthroughLabel, scaledLabel); // scale == 1.0 context.AddLabel(passthroughLabel); context.Store(localVector, vector); context.Branch(mergeLabel); // scale != 1.0 context.AddLabel(scaledLabel); ApplyScalingNoInterpolation(context, localVector, vector, scale); context.Branch(mergeLabel); context.AddLabel(mergeLabel); return(context.Load(ivector2Type, localVector)); } }