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 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 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 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 Generate(CodeGenContext context, StructuredProgramInfo info, int funcIndex) { var function = info.Functions[funcIndex]; (_, var spvFunc) = context.GetFunction(funcIndex); context.AddFunction(spvFunc); context.StartFunction(); Declarations.DeclareParameters(context, function); context.EnterBlock(function.MainBlock); Declarations.DeclareLocals(context, function); Declarations.DeclareLocalForArgs(context, info.Functions); if (funcIndex == 0) { var v4Type = context.TypeVector(context.TypeFP32(), 4); var zero = context.Constant(context.TypeFP32(), 0f); var one = context.Constant(context.TypeFP32(), 1f); // Some games will leave some elements of gl_Position uninitialized, // in those cases, the elements will contain undefined values according // to the spec, but on NVIDIA they seems to be always initialized to (0, 0, 0, 1), // so we do explicit initialization to avoid UB on non-NVIDIA gpus. if (context.Config.Stage == ShaderStage.Vertex) { var elemPointer = context.GetAttributeVectorPointer(new AstOperand(OperandType.Attribute, AttributeConsts.PositionX), true); context.Store(elemPointer, context.CompositeConstruct(v4Type, zero, zero, zero, one)); } // Ensure that unused attributes are set, otherwise the downstream // compiler may eliminate them. // (Not needed for fragment shader as it is the last stage). if (context.Config.Stage != ShaderStage.Compute && context.Config.Stage != ShaderStage.Fragment && !context.Config.GpPassthrough) { for (int attr = 0; attr < Declarations.MaxAttributes; attr++) { if (info.Outputs.Contains(attr)) { continue; } if (context.Config.Options.Flags.HasFlag(TranslationFlags.Feedback)) { throw new NotImplementedException(); } else { int currAttr = AttributeConsts.UserAttributeBase + attr * 16; var elemPointer = context.GetAttributeVectorPointer(new AstOperand(OperandType.Attribute, currAttr), true); context.Store(elemPointer, context.CompositeConstruct(v4Type, zero, zero, zero, one)); } } } } Generate(context, function.MainBlock); context.FunctionEnd(); if (funcIndex == 0) { context.AddEntryPoint(context.Config.Stage.Convert(), spvFunc, "main", context.GetMainInterface()); if (context.Config.Stage == ShaderStage.Fragment) { context.AddExecutionMode(spvFunc, context.Config.Options.TargetApi == TargetApi.Vulkan ? ExecutionMode.OriginUpperLeft : ExecutionMode.OriginLowerLeft); } else if (context.Config.Stage == ShaderStage.Compute) { var localSizeX = (SpvLiteralInteger)context.Config.GpuAccessor.QueryComputeLocalSizeX(); var localSizeY = (SpvLiteralInteger)context.Config.GpuAccessor.QueryComputeLocalSizeY(); var localSizeZ = (SpvLiteralInteger)context.Config.GpuAccessor.QueryComputeLocalSizeZ(); context.AddExecutionMode( spvFunc, ExecutionMode.LocalSize, localSizeX, localSizeY, localSizeZ); } } }
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); } }
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)); } }