/// <summary> /// Gets the data related to the shader metadata for a given shader type. /// </summary> /// <param name="root32BitConstantCount">The total number of needed 32 bit constants in the shader root signature.</param> /// <param name="isImplicitTextureUsed">Indicates whether the current shader uses an implicit texture.</param> /// <param name="isSamplerUsed">Whether the static sampler is used by the shader.</param> /// <param name="capturedFields">The sequence of captured fields for the shader.</param> /// <returns>The metadata info for the shader.</returns> public static DispatchMetadataInfo GetInfo( int root32BitConstantCount, bool isImplicitTextureUsed, bool isSamplerUsed, ImmutableArray <FieldInfo> capturedFields) { ImmutableArray <ResourceDescriptor> .Builder descriptors = ImmutableArray.CreateBuilder <ResourceDescriptor>(); int constantBufferOffset = 1; int readOnlyResourceOffset = 0; int readWriteResourceOffset = 0; int resourceOffset = 0; // Add the implicit texture descriptor, if needed if (isImplicitTextureUsed) { descriptors.Add(new ResourceDescriptor(1, readWriteResourceOffset++, resourceOffset++)); } // Populate the sequence of resource descriptors foreach (FieldInfo.Resource resource in capturedFields.OfType <FieldInfo.Resource>()) { if (HlslKnownTypes.IsConstantBufferType(resource.TypeName)) { descriptors.Add(new ResourceDescriptor(2, constantBufferOffset++, resourceOffset++)); } else if (HlslKnownTypes.IsReadOnlyTypedResourceType(resource.TypeName)) { descriptors.Add(new ResourceDescriptor(0, readOnlyResourceOffset++, resourceOffset++)); } else { descriptors.Add(new ResourceDescriptor(1, readWriteResourceOffset++, resourceOffset++)); } } return(new( root32BitConstantCount, isSamplerUsed, descriptors.ToImmutable())); }
/// <summary> /// Loads a specified <see cref="ReadableMember"/> and adds it to the shader model /// </summary> /// <param name="memberInfo">The target <see cref="ReadableMember"/> to load</param> /// <param name="name">The optional explicit name to use for the field</param> /// <param name="parents">The list of parent fields to reach the current <see cref="ReadableMember"/> from a given <see cref="Action{T}"/></param> private void LoadFieldInfo(ReadableMember memberInfo, string?name = null, IReadOnlyList <ReadableMember>?parents = null) { Type fieldType = memberInfo.MemberType; string fieldName = HlslKnownKeywords.GetMappedName(name ?? memberInfo.Name); // Constant buffer if (HlslKnownTypes.IsConstantBufferType(fieldType)) { DescriptorRanges.Add(new DescriptorRange1(DescriptorRangeType.ConstantBufferView, 1, _ConstantBuffersCount)); // Track the buffer field memberInfo.Parents = parents; _CapturedMembers.Add(memberInfo); string typeName = HlslKnownTypes.GetMappedName(fieldType.GenericTypeArguments[0]); _BuffersList.Add(new ConstantBufferFieldInfo(fieldType, typeName, fieldName, _ConstantBuffersCount++)); } else if (HlslKnownTypes.IsReadOnlyBufferType(fieldType)) { // Root parameter for a readonly buffer DescriptorRanges.Add(new DescriptorRange1(DescriptorRangeType.ShaderResourceView, 1, _ReadOnlyBuffersCount)); // Track the buffer field memberInfo.Parents = parents; _CapturedMembers.Add(memberInfo); string typeName = HlslKnownTypes.GetMappedName(fieldType); _BuffersList.Add(new ReadOnlyBufferFieldInfo(fieldType, typeName, fieldName, _ReadOnlyBuffersCount++)); } else if (HlslKnownTypes.IsReadWriteBufferType(fieldType)) { // Root parameter for a read write buffer DescriptorRanges.Add(new DescriptorRange1(DescriptorRangeType.UnorderedAccessView, 1, _ReadWriteBuffersCount)); // Track the buffer field memberInfo.Parents = parents; _CapturedMembers.Add(memberInfo); string typeName = HlslKnownTypes.GetMappedName(fieldType); _BuffersList.Add(new ReadWriteBufferFieldInfo(fieldType, typeName, fieldName, _ReadWriteBuffersCount++)); } else if (HlslKnownTypes.IsKnownScalarType(fieldType) || HlslKnownTypes.IsKnownVectorType(fieldType)) { // Register the captured field memberInfo.Parents = parents; _CapturedMembers.Add(memberInfo); string typeName = HlslKnownTypes.GetMappedName(fieldType); _FieldsList.Add(new CapturedFieldInfo(fieldType, typeName, fieldName)); } else if (fieldType.IsClass && fieldName.StartsWith("CS$<>")) { // Captured scope, update the parents list List <ReadableMember> updatedParents = parents?.ToList() ?? new List <ReadableMember>(); updatedParents.Add(memberInfo); // Recurse on the new compiler generated class IReadOnlyList <FieldInfo> fields = fieldType.GetFields().ToArray(); foreach (FieldInfo fieldInfo in fields) { LoadFieldInfo(fieldInfo, null, updatedParents); } } else if (fieldType.IsDelegate() && memberInfo.GetValue(Action.Target) is Delegate func && (func.Method.IsStatic || func.Method.DeclaringType.IsStatelessDelegateContainer()) && (HlslKnownTypes.IsKnownScalarType(func.Method.ReturnType) || HlslKnownTypes.IsKnownVectorType(func.Method.ReturnType)) && fieldType.GenericTypeArguments.All(type => HlslKnownTypes.IsKnownScalarType(type) || HlslKnownTypes.IsKnownVectorType(type))) { // Captured static delegates with a return type LoadStaticMethodSource(fieldName, func.Method); } }