public string GetExpression(AstOperand operand, ShaderConfig config, bool cbIndexable) { switch (operand.Type) { case OperandType.Argument: return(GetArgumentName(operand.Value)); case OperandType.Attribute: return(GetAttributeName(operand, config)); case OperandType.Constant: return(NumberFormatter.FormatInt(operand.Value)); case OperandType.ConstantBuffer: return(GetConstantBufferName(operand.CbufSlot, operand.CbufOffset, config.Stage, cbIndexable)); case OperandType.LocalVariable: return(_locals[operand]); case OperandType.Undefined: return(DefaultNames.UndefinedName); } throw new ArgumentException($"Invalid operand type \"{operand.Type}\"."); }
public string DeclareLocal(AstOperand operand) { string name = $"{DefaultNames.LocalNamePrefix}_{_locals.Count}"; _locals.Add(operand, name); return(name); }
public static string GetConstantBufferName(AstOperand cbuf, GalShaderType shaderType) { string ubName = GetUbName(shaderType, cbuf.CbufSlot); ubName += "[" + (cbuf.CbufOffset >> 2) + "]"; return(ubName + "." + GetSwizzleMask(cbuf.CbufOffset & 3)); }
private static void DeclareSamplers(CodeGenContext context, StructuredProgramInfo info) { Dictionary <string, AstTextureOperation> samplers = new Dictionary <string, AstTextureOperation>(); foreach (AstTextureOperation texOp in info.Samplers.OrderBy(x => x.Handle)) { string indexExpr = NumberFormatter.FormatInt(texOp.ArraySize); string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr); if (!samplers.TryAdd(samplerName, texOp)) { continue; } string samplerTypeName = GetSamplerTypeName(texOp.Type); context.AppendLine("uniform " + samplerTypeName + " " + samplerName + ";"); } foreach (KeyValuePair <string, AstTextureOperation> kv in samplers) { string samplerName = kv.Key; AstTextureOperation texOp = kv.Value; TextureDescriptor desc; if ((texOp.Flags & TextureFlags.Bindless) != 0) { AstOperand operand = texOp.GetSource(0) as AstOperand; desc = new TextureDescriptor(samplerName, texOp.Type, operand.CbufSlot, operand.CbufOffset); context.TextureDescriptors.Add(desc); } else if ((texOp.Type & SamplerType.Indexed) != 0) { for (int index = 0; index < texOp.ArraySize; index++) { string indexExpr = NumberFormatter.FormatInt(index); string indexedSamplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr); desc = new TextureDescriptor(indexedSamplerName, texOp.Type, texOp.Handle + index * 2); context.TextureDescriptors.Add(desc); } } else { desc = new TextureDescriptor(samplerName, texOp.Type, texOp.Handle); context.TextureDescriptors.Add(desc); } } }
private static VariableType GetOperandVarType(AstOperand operand) { if (operand.Type == OperandType.Attribute) { if (_builtInAttributes.TryGetValue(operand.Value & ~3, out BuiltInAttribute builtInAttr)) { return(builtInAttr.Type); } } return(OperandInfo.GetVarType(operand)); }
public static string GetConstantBufferName(IAstNode slot, string offsetExpr, ShaderStage stage) { // Non-constant slots are not supported. // It is expected that upstream stages are never going to generate non-constant // slot access. AstOperand operand = (AstOperand)slot; string ubName = GetUbName(stage, operand.Value); string index0 = "[" + offsetExpr + " >> 2]"; return(GetVec4Indexed(ubName + index0, offsetExpr + " & 3")); }
public string GetExpression(AstOperand operand, ShaderConfig config) { return(operand.Type switch { OperandType.Argument => GetArgumentName(operand.Value), OperandType.Attribute => GetAttributeName(operand.Value, config, perPatch: false), OperandType.AttributePerPatch => GetAttributeName(operand.Value, config, perPatch: true), OperandType.Constant => NumberFormatter.FormatInt(operand.Value), OperandType.ConstantBuffer => GetConstantBufferName(operand, config), OperandType.LocalVariable => _locals[operand], OperandType.Undefined => DefaultNames.UndefinedName, _ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".") });
public static string GetConstantBufferName(IAstNode slot, string offsetExpr, GalShaderType shaderType) { // Non-constant slots are not supported. // It is expected that upstream stages are never going to generate non-constant // slot access. AstOperand operand = (AstOperand)slot; string ubName = GetUbName(shaderType, operand.Value); string index0 = "[" + offsetExpr + " >> 4]"; string index1 = "[" + offsetExpr + " >> 2 & 3]"; return(ubName + index0 + index1); }
public int FindTextureDescriptorIndex(AstTextureOperation texOp) { AstOperand operand = texOp.GetSource(0) as AstOperand; bool bindless = (texOp.Flags & TextureFlags.Bindless) > 0; int cBufSlot = bindless ? operand.CbufSlot : 0; int cBufOffset = bindless ? operand.CbufOffset : 0; return(TextureDescriptors.FindIndex(descriptor => descriptor.Type == texOp.Type && descriptor.HandleIndex == texOp.Handle && descriptor.CbufSlot == cBufSlot && descriptor.CbufOffset == cBufOffset)); }
private int FindDescriptorIndex(List <TextureDescriptor> list, AstTextureOperation texOp) { AstOperand operand = texOp.GetSource(0) as AstOperand; bool bindless = (texOp.Flags & TextureFlags.Bindless) > 0; int cBufSlot = bindless ? operand.CbufSlot : 0; int cBufOffset = bindless ? operand.CbufOffset : 0; return(list.FindIndex(descriptor => descriptor.Type == texOp.Type && descriptor.HandleIndex == texOp.Handle && descriptor.Format == texOp.Format && descriptor.CbufSlot == cBufSlot && descriptor.CbufOffset == cBufOffset)); }
public string GetExpression(AstOperand operand, ShaderConfig config) { return(operand.Type switch { OperandType.Argument => GetArgumentName(operand.Value), OperandType.Attribute => GetAttributeName(operand, config), OperandType.Constant => NumberFormatter.FormatInt(operand.Value), OperandType.ConstantBuffer => GetConstantBufferName( operand.CbufSlot, operand.CbufOffset, config.Stage, config.UsedFeatures.HasFlag(FeatureFlags.CbIndexing)), OperandType.LocalVariable => _locals[operand], OperandType.Undefined => DefaultNames.UndefinedName, _ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".") });
public static string Call(CodeGenContext context, AstOperation operation) { AstOperand funcId = (AstOperand)operation.GetSource(0); Debug.Assert(funcId.Type == OperandType.Constant); var function = context.GetFunction(funcId.Value); string[] args = new string[operation.SourcesCount - 1]; for (int i = 0; i < args.Length; i++) { args[i] = GetSoureExpr(context, operation.GetSource(i + 1), function.GetArgumentType(i)); } return($"{function.Name}({string.Join(", ", args)})"); }
public static string GetSamplerName(GalShaderType shaderType, AstTextureOperation texOp) { string suffix; if ((texOp.Flags & TextureFlags.Bindless) != 0) { AstOperand operand = texOp.GetSource(0) as AstOperand; suffix = "_cb" + operand.CbufSlot + "_" + operand.CbufOffset; } else { suffix = (texOp.Handle - 8).ToString(); } return(GetShaderStagePrefix(shaderType) + "_" + DefaultNames.SamplerNamePrefix + suffix); }
public static VariableType GetNodeDestType(CodeGenContext context, IAstNode node) { if (node is AstOperation operation) { // Load attribute basically just returns the attribute value. // Some built-in attributes may have different types, so we need // to return the type based on the attribute that is being read. if (operation.Inst == Instruction.LoadAttribute) { return(GetOperandVarType((AstOperand)operation.GetSource(0))); } else if (operation.Inst == Instruction.Call) { AstOperand funcId = (AstOperand)operation.GetSource(0); Debug.Assert(funcId.Type == OperandType.Constant); return(context.GetFunction(funcId.Value).ReturnType); } else if (operation is AstTextureOperation texOp && (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)) { return(texOp.Format.GetComponentType()); } return(GetDestVarType(operation.Inst)); } else if (node is AstOperand operand) { if (operand.Type == OperandType.Argument) { int argIndex = operand.Value; return(context.CurrentFunction.GetArgumentType(argIndex)); } return(GetOperandVarType(operand)); } else { throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\"."); } }
public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp, string indexExpr) { string suffix; if ((texOp.Flags & TextureFlags.Bindless) != 0) { AstOperand operand = texOp.GetSource(0) as AstOperand; suffix = "_cb" + operand.CbufSlot + "_" + operand.CbufOffset; } else { suffix = texOp.Handle.ToString("X"); if ((texOp.Type & SamplerType.Indexed) != 0) { suffix += $"a[{indexExpr}]"; } } return(GetShaderStagePrefix(stage) + "_" + DefaultNames.SamplerNamePrefix + suffix); }
public string GetExpression(AstOperand operand, GalShaderType shaderType) { switch (operand.Type) { case OperandType.Attribute: return(GetAttributeName(operand, shaderType)); case OperandType.Constant: return(NumberFormatter.FormatInt(operand.Value)); case OperandType.ConstantBuffer: return(GetConstantBufferName(operand, shaderType)); case OperandType.LocalVariable: return(_locals[operand]); case OperandType.Undefined: return(DefaultNames.UndefinedName); } throw new ArgumentException($"Invalid operand type \"{operand.Type}\"."); }
public static string GetOutAttributeName(AstOperand attr, GalShaderType shaderType) { return(GetAttributeName(attr, shaderType, isOutAttr: true)); }
public static string GetAttributeName(AstOperand attr, ShaderConfig config, bool isOutAttr = false, string indexExpr = "0") { int value = attr.Value; char swzMask = GetSwizzleMask((value >> 2) & 3); if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd) { value -= AttributeConsts.UserAttributeBase; string prefix = isOutAttr ? DefaultNames.OAttributePrefix : DefaultNames.IAttributePrefix; if ((config.Flags & TranslationFlags.Feedback) != 0) { string name = $"{prefix}{(value >> 4)}_{swzMask}"; if (config.Stage == ShaderStage.Geometry && !isOutAttr) { name += $"[{indexExpr}]"; } return(name); } else { string name = $"{prefix}{(value >> 4)}"; if (config.Stage == ShaderStage.Geometry && !isOutAttr) { name += $"[{indexExpr}]"; } return(name + '.' + swzMask); } } else { if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd) { value -= AttributeConsts.FragmentOutputColorBase; return($"{DefaultNames.OAttributePrefix}{(value >> 4)}.{swzMask}"); } else if (_builtInAttributes.TryGetValue(value & ~3, out BuiltInAttribute builtInAttr)) { // TODO: There must be a better way to handle this... if (config.Stage == ShaderStage.Fragment) { switch (value & ~3) { case AttributeConsts.PositionX: return("(gl_FragCoord.x / fp_renderScale[0])"); case AttributeConsts.PositionY: return("(gl_FragCoord.y / fp_renderScale[0])"); case AttributeConsts.PositionZ: return("gl_FragCoord.z"); case AttributeConsts.PositionW: return("gl_FragCoord.w"); } } string name = builtInAttr.Name; if (config.Stage == ShaderStage.Geometry && (value & AttributeConsts.SpecialMask) == 0 && !isOutAttr) { name = $"gl_in[{indexExpr}].{name}"; } return(name); } } // TODO: Warn about unknown built-in attribute. return(isOutAttr ? "// bad_attr0x" + value.ToString("X") : "0.0"); }
public static string GetOutAttributeName(AstOperand attr, ShaderConfig config) { return(GetAttributeName(attr, config, isOutAttr: true)); }
private static void DeclareSamplers(CodeGenContext context, StructuredProgramInfo info) { Dictionary <string, AstTextureOperation> samplers = new Dictionary <string, AstTextureOperation>(); // Texture instructions other than TextureSample (like TextureSize) // may have incomplete sampler type information. In those cases, // we prefer instead the more accurate information from the // TextureSample instruction, if both are available. foreach (AstTextureOperation texOp in info.Samplers.OrderBy(x => x.Handle * 2 + (x.Inst == Instruction.TextureSample ? 0 : 1))) { string indexExpr = NumberFormatter.FormatInt(texOp.ArraySize); string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr); if (!samplers.TryAdd(samplerName, texOp)) { continue; } string samplerTypeName = GetSamplerTypeName(texOp.Type); context.AppendLine("uniform " + samplerTypeName + " " + samplerName + ";"); } foreach (KeyValuePair <string, AstTextureOperation> kv in samplers) { string samplerName = kv.Key; AstTextureOperation texOp = kv.Value; TextureDescriptor desc; if ((texOp.Flags & TextureFlags.Bindless) != 0) { AstOperand operand = texOp.GetSource(0) as AstOperand; desc = new TextureDescriptor(samplerName, texOp.Type, operand.CbufSlot, operand.CbufOffset); context.TextureDescriptors.Add(desc); } else if ((texOp.Type & SamplerType.Indexed) != 0) { for (int index = 0; index < texOp.ArraySize; index++) { string indexExpr = NumberFormatter.FormatInt(index); string indexedSamplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr); desc = new TextureDescriptor(indexedSamplerName, texOp.Type, texOp.Handle + index * 2); context.TextureDescriptors.Add(desc); } } else { desc = new TextureDescriptor(samplerName, texOp.Type, texOp.Handle); context.TextureDescriptors.Add(desc); } } }
public static string GetOutAttributeName(AstOperand attr, ShaderStage stage) { return(GetAttributeName(attr, stage, isOutAttr: true)); }
private static string GetAttributeName(AstOperand attr, GalShaderType shaderType, bool isOutAttr = false) { int value = attr.Value; string swzMask = GetSwizzleMask((value >> 2) & 3); if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd) { value -= AttributeConsts.UserAttributeBase; string prefix = isOutAttr ? DefaultNames.OAttributePrefix : DefaultNames.IAttributePrefix; string name = $"{prefix}{(value >> 4)}"; if (shaderType == GalShaderType.Geometry && !isOutAttr) { name += "[0]"; } name += "." + swzMask; return(name); } else { if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd) { value -= AttributeConsts.FragmentOutputColorBase; return($"{DefaultNames.OAttributePrefix}{(value >> 4)}.{swzMask}"); } else if (_builtInAttributes.TryGetValue(value & ~3, out BuiltInAttribute builtInAttr)) { // TODO: There must be a better way to handle this... if (shaderType == GalShaderType.Fragment) { switch (value & ~3) { case AttributeConsts.PositionX: return("gl_FragCoord.x"); case AttributeConsts.PositionY: return("gl_FragCoord.y"); case AttributeConsts.PositionZ: return("gl_FragCoord.z"); case AttributeConsts.PositionW: return("1.0"); } } string name = builtInAttr.Name; if (shaderType == GalShaderType.Geometry && !isOutAttr) { name = "gl_in[0]." + name; } return(name); } } // TODO: Warn about unknown built-in attribute. return(isOutAttr ? "// bad_attr0x" + value.ToString("X") : "0.0"); }