internal static Type Resolve(ShaderTranslationContext sc, string typeName, SyntaxTokenList modifiers = default) { Type t = null; foreach (SyntaxToken m in modifiers) { for (int i = 0; i < PointerModifiers.Length; i++) { if (m.ValueText == PointerModifiers[i]) { typeName += "&"; goto PostModifierCheck; // Yes, it's a goto! It's also a nested loop ;) } } } PostModifierCheck: if (!_baseTypeAliases.TryGetValue(typeName, out t)) { t = RetrieveType(typeName); } if (t == null) { Type sType = sc.ShaderType; t = sc.Parent.Reflection.Assembly.GetType($"{sc.ShaderType.Namespace}.{sc.ShaderType.Name}+{typeName}"); if (t == null) { t = ResolveGeneric(sc, typeName); } } return(t); }
private static Type ResolveGeneric(ShaderTranslationContext sc, string typeName) { int bIndex = typeName.IndexOf('<'); Type t = null; if (bIndex > -1) { // TODO garbage generation from arrays? string typeParams = typeName.Substring(bIndex, typeName.Length - bIndex); string[] inners = typeParams.Substring(1, typeParams.Length - 2).Split(_genericTypeDelimiter, StringSplitOptions.None); string outer = typeName.Substring(0, bIndex); Type[] innerTypes = new Type[inners.Length]; for (int i = 0; i < inners.Length; i++) { inners[i] = inners[i].Trim(); innerTypes[i] = Resolve(sc, inners[i]); } string outerTypeName = $"{outer}`{inners.Length}"; Type outerType = Resolve(sc, outerTypeName); t = outerType?.MakeGenericType(innerTypes); } return(t); }
internal override void TranslateFieldPostfix(ShaderTranslationContext sc, VariableDeclaratorSyntax syntax, MappedField field, int fieldIndex, MappedConstantBuffer cBufferMap) { char?regName = null; // Constant buffer fields do not have registers assigned to them. if (cBufferMap == null) { if (field.ResourceBaseType == ShaderResourceBaseType.Sampler) { regName = 's'; } else if (field.ResourceBaseType == ShaderResourceBaseType.Texture || field.ResourceBaseType == ShaderResourceBaseType.Buffer) { regName = 't'; } else if (field.Type.IsUnorderedAccessType) { regName = 'u'; } } int fieldTypeSize = field.Info.FieldType.IsValueType ? Marshal.SizeOf(field.Info.FieldType) : 0; TranslatePostfixAttributes(sc, field.Attributes, regName, fieldIndex, fieldTypeSize, cBufferMap); }
private void MapShaderNodes(TranslationContext context, SyntaxNode node, string strNamespace) { if (node is ClassDeclarationSyntax classNode) { string typeName = $"{strNamespace}.{classNode.Identifier}"; Type t = context.Reflection.Assembly.GetType(typeName, false, false); if (t != null && context.Reflection.IsShaderType(t)) { ShaderTranslationContext sc = Pooling.ShaderContexts.Get(); sc.Initialize(context, classNode, t); context.Shaders.Add(sc); Message($"Mapped {t.FullName}"); // TODO: Remove this return if nested shaders are ever supported. return; } } else if (node is NamespaceDeclarationSyntax nsNode) { if (strNamespace.Length > 0) { strNamespace += "."; } strNamespace += nsNode.Name; } IEnumerable <SyntaxNode> stuff = node.ChildNodes(); foreach (SyntaxNode child in stuff) { MapShaderNodes(context, child, strNamespace); } }
internal void Translate(ShaderTranslationContext sc, SyntaxNode syntax, int depth = 0) { if (sc.IsCompleted(syntax)) { return; } Type t = syntax.GetType(); ScopeInfo lastScope = sc.Source.CurrentScope; if (_processors.TryGetValue(t, out NodeProcessor processor)) { processor.Translate(sc, syntax, sc.Source.CurrentScope); } //else // sc.Source.Append($"{Environment.NewLine}{new string('\t', depth)}// [[No translator for {t.Name}]] "); sc.Complete(syntax); IEnumerable <SyntaxNode> children = syntax.ChildNodes(); foreach (SyntaxNode child in children) { Translate(sc, child, depth + 1); } while (lastScope != sc.Source.CurrentScope) { sc.Source.CloseScope(); } }
private void TranslatePostfixAttributes(ShaderTranslationContext sc, IEnumerable <Attribute> attributes, char?registerName, int fieldIndex, int fieldSize, MappedConstantBuffer cBuffer) { foreach (Attribute a in attributes) { switch (a) { case RegisterAttribute regAtt: if (registerName == null) { continue; } int slotID = (int)(regAtt.Slot + fieldIndex); cBuffer?.BindSlots.Add(new BindPointInfo(regAtt.Model, regAtt.ApplicableEntryPoint, slotID)); if (regAtt.ApplicableEntryPoint == EntryPointType.AnyOrNone) { sc.Source.Append($" : register({registerName}{slotID})"); } else { string profile = regAtt.Model.ToString().Replace("SM", _profileNames[regAtt.ApplicableEntryPoint]); sc.Source.Append($" : register({profile}, {registerName}{slotID})"); } break; case PackOffsetAttribute packAtt: if (cBuffer == null) { continue; } int totalComponentOffset = (packAtt.OffsetRegister * COMPONENTS_PER_REGISTER) + (int)packAtt.OffsetComponent; totalComponentOffset += (int)Math.Floor((fieldSize * fieldIndex) / (float)COMPONENT_BYTE_SIZE); PackOffsetComponent component = (PackOffsetComponent)(totalComponentOffset % COMPONENTS_PER_REGISTER); int register = (int)Math.Floor(totalComponentOffset / (float)COMPONENTS_PER_REGISTER); string componentName = component.ToString().ToLower(); sc.Source.Append($" : packoffset(c{register}.{componentName})"); break; case SemanticAttribute semAtt: if (cBuffer != null) { continue; } string semanticName = semAtt.Semantic.ToString().ToUpper(); sc.Source.Append($" : {semanticName}"); if (semAtt.Slot >= 0) { sc.Source.Append(semAtt.Slot.ToString()); } break; } } }
internal static string GetIntrinsicTranslation(ShaderTranslationContext context, string cSharpName) { if (_intrinsicMethods.TryGetValue(context.Parent.Language.Language, out LanguageInfo info)) { if (info.Intrinsics.TryGetValue(cSharpName, out LanguageMethodInfo methodInfo)) { return(methodInfo.NativeName); } } return(cSharpName); }
internal void Initialize(ShaderTranslationContext sc, TranslationFlags flags) { _flags = flags; _language = sc.Language; _currentScope = Pooling.Scopes.Get(); _currentScope.Type = ScopeType.Class; _currentScope.TypeInfo = new ShaderType(_language, sc.ShaderType.Name, sc.ShaderType); _currentScope.Namespace = $"{sc.ShaderType.Namespace}.{sc.ShaderType.Name}"; _rootScope = _currentScope; _firstSegment = Pooling.SourceSegments.Get(); _firstSegment.Value = ""; _curSegment = _firstSegment; _lastSegment = _curSegment; }
/// <summary> /// Finds an insertion point to declare local syntax, such as a local variable. This is generally used for expanding an initializer into full syntax.<para/> /// A callback is provided to output translated syntax at the correct location before returning to the end of the output source code. /// </summary> /// <param name="sc"></param> /// <param name="callback"></param> internal void DeclareLocal(ShaderTranslationContext sc, Action callback) { // The root scope implements IDeclarativeScope, so eventually we will hit that if no others are avaialble along the way. ScopeInfo si = this; while (si != null) { if (si.Type == ScopeType.Block && si.Parent.Type == ScopeType.Method) { sc.Source.GoToSegment(si.OpeningSegment); callback(); sc.Source.GoToEnd(); return; } si = si.Parent; } }
internal override string TranslateNumber(ShaderTranslationContext context, string number) { // NOTE: hexadecimal literals are supported in HLSL, binary literals are not, so we'll need to translate those. if (number.StartsWith("0b")) // Binary literal. { return(TranslateBinaryLiteral(number)); } else // Hexadecimal + everything else. { int newLength = number.Length; for (int i = number.Length - 1; i >= 0; i--) { if (!char.IsNumber(number[i])) { newLength = i; break; } } return(number.Substring(0, newLength)); } }
internal override void TranslateFieldPrefix(ShaderTranslationContext sc, VariableDeclaratorSyntax syntax, MappedField field, int fieldIndex, MappedConstantBuffer cBufferMap) { if (typeof(IShaderResource).IsAssignableFrom(field.Info.FieldType)) { sc.MappedFields.Add(field); } else { // HLSL puts all global, non-const static variables into the $Global constant buffer. if (cBufferMap == null && field.Info.FieldType.DeclaringType == sc.ShaderType) { MappedConstantBuffer cBufferGlobal = null; if (!sc.ConstantBuffers.TryGetValue(GLOBAL_CBUFFER_NAME, out cBufferGlobal)) { cBufferGlobal = Pooling.MappedConstBuffers.Get(); sc.ConstantBuffers.Add(GLOBAL_CBUFFER_NAME, cBufferGlobal); } cBufferGlobal.AddField(field); } if (typeof(IMatrix).IsAssignableFrom(field.Info.FieldType)) { if (field.StructureType == ShaderStructureType.MatrixRowMajor) { sc.Source.Append("row_major "); } if (field.StructureType == ShaderStructureType.MatrixColumnMajor) { sc.Source.Append("column_Major "); } } } foreach (Attribute at in field.Attributes) { switch (at) { case InterpolationAttribute attInterpolation: foreach (InterpolationMode m in InterpolationAttribute.ModeValues) { if (m == InterpolationMode.None) { continue; } if ((attInterpolation.Flags & m) == m) { sc.Source.Append($" {m.ToString().ToLower()}"); } } break; case ComputeGroupSharedAttribute attGroupShared: sc.Source.Append(" groupshared "); break; case GloballyCoherentAttribute attGlobCoherent: if (field.ResourceBaseType == ShaderResourceBaseType.RWBuffer || field.ResourceBaseType == ShaderResourceBaseType.RWTexture) { sc.Source.Append(" globallycoherent "); } break; } } }
internal override void TranslateConstBufferHeader(ShaderTranslationContext sc, StructDeclarationSyntax syntax, MappedConstantBuffer cBufferMap, IEnumerable <Attribute> attributes) { throw new NotImplementedException(); }
internal override string TranslateNumber(ShaderTranslationContext context, string number) { throw new NotImplementedException(); }
internal override void TranslateForLoopPrefix(ShaderTranslationContext sc, ForStatementSyntax syntax) { // TODO Only unroll if loop iteration count is low enough. sc.Source.Append("[unroll]"); }
internal static ShaderType TranslateType(ShaderTranslationContext sc, string typeName) { ShaderType type = null; if (sc.Language.TranslatedTypes.TryGetValue(typeName, out type)) { return(type); } else { Type originalType = Resolve(sc, typeName); if (originalType != null) { ShaderLanguage.Translation translation = sc.Parent.Language.GetTranslation(originalType); if (translation != null) { type = new ShaderType(sc.Language, translation.NativeText, originalType); sc.Language.TranslatedTypes.TryAdd(typeName, type); return(type); } else // Attempt to find any interfaces on the type which can be translated instead. { Type elementType = originalType.GetElementType(); Type[] iTypes; if (elementType != null) { iTypes = elementType.GetInterfaces(); } else { iTypes = originalType.GetInterfaces(); } foreach (Type implemented in iTypes) { translation = sc.Parent.Language.GetTranslation(implemented); if (translation != null) { string replacement = elementType?.Name ?? originalType.Name; // TODO Does this need optimizing? Benchmark before changing. for (int i = 0; i < IntrinsicPrefixes.Length; i++) { replacement = replacement.Replace(IntrinsicPrefixes[i], ""); } if (translation.UniformSizeIsSingular) { if (typeof(UniformDimensions).IsAssignableFrom(originalType)) { replacement = replacement.Substring(0, replacement.Length - 2); } } replacement = translation.NativeText + replacement; type = new ShaderType(sc.Language, replacement, originalType); sc.Language.TranslatedTypes.TryAdd(typeName, type); return(type); } } // Create a placeholder type instead. type = new ShaderType(sc.Language, typeName, originalType); sc.Language.TranslatedTypes.TryAdd(typeName, type); return(type); } } // We have no known Type instance to use, so try to figure out if it's an array or not, manually. int openIndex = typeName.IndexOf("["); if (openIndex > -1 && typeName.EndsWith("]")) { typeName = typeName.Substring(0, openIndex); int endLen = typeName.Length - openIndex; string reflectiveName = $"System.Object{typeName.Substring(openIndex, endLen)}"; type = new ShaderType(sc.Language, typeName, Type.GetType(reflectiveName)); } else { type = new ShaderType(sc.Language, typeName, typeof(object)); } // Create a placeholder type using object base class instead. sc.Language.TranslatedTypes.TryAdd(typeName, type); return(type); } }
/// <summary> /// Returns true /// </summary> /// <param name="sc">The <see cref="ShaderTranslationContext"/>.</param> /// <param name="syntax">The <see cref="SyntaxNode"/> to be translated.</param> internal abstract void Translate(ShaderTranslationContext sc, SyntaxNode syntax, ScopeInfo scope);
internal abstract void TranslateConstBufferHeader(ShaderTranslationContext sc, StructDeclarationSyntax syntax, MappedConstantBuffer cBufferMap, IEnumerable <Attribute> attributes);
internal override void TranslateForLoopPrefix(ShaderTranslationContext sc, ForStatementSyntax syntax) { throw new NotImplementedException(); }
internal abstract void TranslateFieldPostfix(ShaderTranslationContext sc, VariableDeclaratorSyntax syntax, MappedField field, int fieldIndex, MappedConstantBuffer cBufferMap);
internal override void TranslateFieldPostfix(ShaderTranslationContext sc, VariableDeclaratorSyntax syntax, MappedField field, int fieldIndex, MappedConstantBuffer cBufferMap) { throw new NotImplementedException(); }
internal abstract string TranslateNumber(ShaderTranslationContext sc, string number);
internal abstract void TranslateForLoopPrefix(ShaderTranslationContext sc, ForStatementSyntax syntax);
internal override void TranslateConstBufferHeader(ShaderTranslationContext sc, StructDeclarationSyntax syntax, MappedConstantBuffer cBufferMap, IEnumerable <Attribute> attributes) { sc.Source.AppendLineBreak(); sc.Source.Append($"cbuffer {cBufferMap.TypeInfo.Name}"); TranslatePostfixAttributes(sc, attributes, 'b', 0, 0, cBufferMap); }