Skip to content
Open
  •  
  •  
  •  
Binary file modified .silktouch/vulkan-clangsharp.stout
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a search over the repo for any missing structure type initializers, and looks like we are good:
Image

Binary file not shown.
1 change: 1 addition & 0 deletions eng/silktouch/vulkan/settings.rsp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@../../common.rsp
--define-macro
VK_ENABLE_BETA_EXTENSIONS
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TerraFX also does the same: https://github.com/terrafx/terrafx.interop.vulkan/blob/86629a4d0afc1de12d10111b4d1e8bbd4be4363b/generation/settings.rsp#L36

This macro mainly guards a few enum members. Without these enum members, the generated bindings fail to compile.

TODO_DEFINE_MACROS=HERE
--headerFile
../header.txt
Expand Down
3 changes: 3 additions & 0 deletions generator.json
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,9 @@
"MixKhronosData": {
"SpecPath": "eng/submodules/vulkan/xml/vk.xml",
"Namespace": "Silk.NET.Vulkan",
"StructureTypes": [
"VkStructureType"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to FlagsTypes immediately below, StructureTypes should let us handle OpenXR easily once we get to that point.

],
"FlagsTypes": [
"VkFlags",
"VkFlags64"
Expand Down
172 changes: 164 additions & 8 deletions sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ public Dictionary<
/// This was added for Vulkan Flags/FlagBits remappings.
/// </remarks>
public Dictionary<string, string> AdditionalTypeRemappings = [];

/// <summary>
/// A mapping from struct type to information about the structure type member.
/// </summary>
public Dictionary<string, StructureTypeMember> StructureTypeMembers = [];
}

/// <summary>
Expand All @@ -146,6 +151,12 @@ public record Configuration
/// </summary>
public Dictionary<string, string>? TypeMap { get; init; }

/// <summary>
/// The structure type enums used by the API.
/// Eg: VkStructureType for Vulkan
/// </summary>
public HashSet<string> StructureTypes { get; init; } = [];

/// <summary>
/// The base type used for flags/bitmask enums.
/// For example, VkFlags and VkFlags64 for Vulkan.
Expand Down Expand Up @@ -342,6 +353,58 @@ .. currentConfig.NonStandardExtensionNomenclature

job.AdditionalTypeRemappings[mapFrom] = mapTo;
}

// Gather information about struct structure type enums
if (currentConfig.StructureTypes.Count != 0)
{
foreach (
var typeElement in xml.Elements("registry")
.Elements("types")
.Elements("type")
.Where(x => x.Attribute("category")?.Value == "struct")
)
{
var structName = typeElement.Attribute("name")?.Value;
if (structName == null)
{
continue;
}

foreach (var memberElement in typeElement.Elements("member"))
{
var memberType = memberElement.Element("type")?.Value;
if (memberType == null)
{
continue;
}

if (currentConfig.StructureTypes.Contains(memberType))
{
var memberName = memberElement.Element("name")?.Value;
if (memberName == null)
{
continue;
}

var memberValue = memberElement.Attribute("values")?.Value;
if (memberValue == null)
{
continue;
}

job.StructureTypeMembers.Add(
structName,
new StructureTypeMember()
{
Name = memberName,
Type = memberType,
Value = memberValue,
}
);
}
}
}
}
}

/// <inheritdoc />
Expand Down Expand Up @@ -402,6 +465,18 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default)
).Project;
}

// Rewrite phase 4
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've decided that it's better to use separate rewriters for everything in MixKhronosData.

There is a performance impact of doing this, but it's much more maintainable to keep every transformation independent of the others. The performance impact is roughly 2 seconds for Vulkan so it is very much worth paying. It also does not affect non-Khronos bindings.

I also plan to keep any new metadata storage structures separate from existing structures. This is to further keep things independent. Every transformation should scrape their own data (within reason).

In particular, what I have in mind relates to StructureTypeMembers within this PR and any metadata we need for the Vulkan struct chaining feature later on. I plan to keep metadata used for Vulkan struct chaining separate from the structure type field initialization code added in this PR.

var rewriter4 = new RewriterPhase4(jobData);
foreach (var docId in proj.DocumentIds)
{
var doc =
proj.GetDocument(docId) ?? throw new InvalidOperationException("Document missing");
proj = doc.WithSyntaxRoot(
rewriter4.Visit(await doc.GetSyntaxRootAsync(ct))
?? throw new InvalidOperationException("Visit returned null.")
).Project;
}

// Rename documents to account for FlagBits/Flags differences
foreach (var docId in proj.DocumentIds)
{
Expand Down Expand Up @@ -441,6 +516,13 @@ rsp with
return Task.FromResult(rsps);
}

internal record struct StructureTypeMember
{
public string Name;
public string Type;
public string Value;
}

/// <summary>
/// Contains information about a group of enums.
/// </summary>
Expand Down Expand Up @@ -1620,11 +1702,7 @@ private class RewriterPhase1(JobData job, ILogger logger) : CSharpSyntaxRewriter
var attributes = SingletonList(
AttributeList([Attribute(IdentifierName("Transformed"))])
);

if (groupInfo.NativeName != null)
{
attributes = attributes.WithNativeName(groupInfo.NativeName);
}
attributes = attributes.WithNativeName(groupInfo.NativeName);

var baseTypeSyntax = ParseTypeName(baseType);

Expand Down Expand Up @@ -1903,9 +1981,6 @@ private bool TryGetManagedEnumType(
/// <summary>
/// This rewriter identifies and extracts vendor extension suffixes into [NameSuffix] attributes.
/// </summary>
/// <remarks>
/// Yes, this is a 3rd rewriter.
/// </remarks>
private class RewriterPhase3(JobData job, Configuration config) : CSharpSyntaxRewriter
{
private SyntaxList<AttributeListSyntax> ProcessAndGetNewAttributes(
Expand Down Expand Up @@ -2189,6 +2264,87 @@ public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
);
}

/// <summary>
/// This rewriter adds default field values for structure type members.
/// </summary>
private class RewriterPhase4(JobData job) : CSharpSyntaxRewriter
{
public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node)
{
var structNativeName = node.AttributeLists.GetNativeNameOrDefault(node.Identifier);
if (
!job.StructureTypeMembers.TryGetValue(structNativeName, out var structureTypeMember)
)
{
return node;
}

// Structs need to have a constructor if we use field initializers
var hasConstructor = false;
var initializerAdded = false;
var members = new List<MemberDeclarationSyntax>();
foreach (var memberNode in node.Members)
{
hasConstructor |= memberNode is ConstructorDeclarationSyntax;
if (memberNode is not FieldDeclarationSyntax memberFieldNode)
{
members.Add(memberNode);
continue;
}

var memberNativeName = memberFieldNode.AttributeLists.GetNativeNameOrDefault(
memberFieldNode.Declaration.Variables.First().Identifier
);

if (memberNativeName != structureTypeMember.Name)
{
members.Add(memberNode);
continue;
}

// Don't replace the default value if one is already provided
if (memberFieldNode.Declaration.Variables.First().Initializer != null)
{
return node;
}

var initializer = EqualsValueClause(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(structureTypeMember.Type),
IdentifierName(structureTypeMember.Value)
)
);

initializerAdded = true;
members.Add(
memberFieldNode.WithDeclaration(
memberFieldNode.Declaration.WithVariables(
[
.. memberFieldNode.Declaration.Variables.Select(variable =>
variable.WithInitializer(initializer)
),
]
)
)
);
}

if (initializerAdded && !hasConstructor)
{
members.Add(
ConstructorDeclaration(node.Identifier)
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))
.WithBody(Block())
);
}

node = node.WithMembers([.. members]);

return node;
}
}

[SuppressMessage("ReSharper", "MoveLocalFunctionAfterJumpStatement")]
internal void ReadGroups(XDocument doc, JobData data, HashSet<string> vendors)
{
Expand Down
6 changes: 6 additions & 0 deletions sources/Vulkan/Vulkan/Enums/BufferUsageFlags2.gen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public enum BufferUsageFlags2 : ulong
[NativeName("VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT")]
ShaderDeviceAddressBit = 0x20000,

[NativeName("VK_BUFFER_USAGE_2_EXECUTION_GRAPH_SCRATCH_BIT_AMDX")]
ExecutionGraphScratchBitAMDX = 0x2000000,

[NativeName("VK_BUFFER_USAGE_2_TRANSFER_SRC_BIT_KHR")]
TransferSrcBitKHR = 0x1,

Expand Down Expand Up @@ -122,6 +125,9 @@ public enum BufferUsageFlags2 : ulong
[NativeName("VK_BUFFER_USAGE_2_MICROMAP_STORAGE_BIT_EXT")]
MicromapStorageBitEXT = 0x1000000,

[NativeName("VK_BUFFER_USAGE_2_COMPRESSED_DATA_DGF1_BIT_AMDX")]
CompressedDataDgf1BitAMDX = 0x200000000,

[NativeName("VK_BUFFER_USAGE_2_DATA_GRAPH_FOREIGN_DESCRIPTOR_BIT_ARM")]
DataGraphForeignDescriptorBitARM = 0x20000000,

Expand Down
3 changes: 3 additions & 0 deletions sources/Vulkan/Vulkan/Enums/PipelineCreateFlags2.gen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public enum PipelineCreateFlags2 : ulong
[NativeName("VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT")]
ProtectedAccessOnlyBit = 0x40000000,

[NativeName("VK_PIPELINE_CREATE_2_EXECUTION_GRAPH_BIT_AMDX")]
ExecutionGraphBitAMDX = 0x100000000,

[NativeName("VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_BUILT_IN_PRIMITIVES_BIT_KHR")]
RayTracingSkipBuiltInPrimitivesBitKHR = 0x1000,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public unsafe partial struct AccelerationStructureBuildGeometryInfoKHR
"VK_KHR_deferred_host_operations+VK_VERSION_1_2",
]
)]
public StructureType SType;
public StructureType SType = StructureType.AccelerationStructureBuildGeometryInfoKHR;

[NativeName("pNext")]
[SupportedApiProfile(
Expand Down Expand Up @@ -132,4 +132,14 @@ public unsafe partial struct AccelerationStructureBuildGeometryInfoKHR
]
)]
public DeviceOrHostAddressKHR ScratchData;

[SupportedApiProfile(
"vulkan",
["VK_KHR_acceleration_structure"],
ImpliesSets = [
"VK_KHR_deferred_host_operations+VK_VERSION_1_1+VK_EXT_descriptor_indexing+VK_KHR_buffer_device_address",
"VK_KHR_deferred_host_operations+VK_VERSION_1_2",
]
)]
public AccelerationStructureBuildGeometryInfoKHR() { }
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Structs that have field initializers need a constructor.

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public unsafe partial struct AccelerationStructureBuildSizesInfoKHR
"VK_KHR_deferred_host_operations+VK_VERSION_1_2",
]
)]
public StructureType SType;
public StructureType SType = StructureType.AccelerationStructureBuildSizesInfoKHR;

[NativeName("pNext")]
[SupportedApiProfile(
Expand Down Expand Up @@ -66,4 +66,14 @@ public unsafe partial struct AccelerationStructureBuildSizesInfoKHR
]
)]
public ulong BuildScratchSize;

[SupportedApiProfile(
"vulkan",
["VK_KHR_acceleration_structure"],
ImpliesSets = [
"VK_KHR_deferred_host_operations+VK_VERSION_1_1+VK_EXT_descriptor_indexing+VK_KHR_buffer_device_address",
"VK_KHR_deferred_host_operations+VK_VERSION_1_2",
]
)]
public AccelerationStructureBuildSizesInfoKHR() { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public unsafe partial struct AccelerationStructureCaptureDescriptorDataInfoEXT
"VK_VERSION_1_3",
]
)]
public StructureType SType;
public StructureType SType = StructureType.AccelerationStructureCaptureDescriptorDataInfoEXT;

[NativeName("pNext")]
[SupportedApiProfile(
Expand Down Expand Up @@ -70,4 +70,19 @@ public unsafe partial struct AccelerationStructureCaptureDescriptorDataInfoEXT
]
)]
public AccelerationStructureHandleNV AccelerationStructureNV;

[SupportedApiProfile(
"vulkan",
[
"VK_EXT_descriptor_buffer+VK_KHR_acceleration_structure",
"VK_EXT_descriptor_buffer+VK_NV_ray_tracing",
],
ImpliesSets = [
"VK_KHR_synchronization2+VK_KHR_buffer_device_address+VK_EXT_descriptor_indexing+VK_KHR_get_physical_device_properties2",
"VK_KHR_synchronization2+VK_KHR_buffer_device_address+VK_EXT_descriptor_indexing+VK_VERSION_1_1",
"VK_KHR_synchronization2+VK_VERSION_1_2",
"VK_VERSION_1_3",
]
)]
public AccelerationStructureCaptureDescriptorDataInfoEXT() { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public unsafe partial struct AccelerationStructureCreateInfoKHR
"VK_KHR_deferred_host_operations+VK_VERSION_1_2",
]
)]
public StructureType SType;
public StructureType SType = StructureType.AccelerationStructureCreateInfoKHR;

[NativeName("pNext")]
[SupportedApiProfile(
Expand Down Expand Up @@ -99,4 +99,14 @@ public unsafe partial struct AccelerationStructureCreateInfoKHR
]
)]
public ulong DeviceAddress;

[SupportedApiProfile(
"vulkan",
["VK_KHR_acceleration_structure"],
ImpliesSets = [
"VK_KHR_deferred_host_operations+VK_VERSION_1_1+VK_EXT_descriptor_indexing+VK_KHR_buffer_device_address",
"VK_KHR_deferred_host_operations+VK_VERSION_1_2",
]
)]
public AccelerationStructureCreateInfoKHR() { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public unsafe partial struct AccelerationStructureCreateInfoNV
"VK_VERSION_1_1",
]
)]
public StructureType SType;
public StructureType SType = StructureType.AccelerationStructureCreateInfoNV;

[NativeName("pNext")]
[SupportedApiProfile(
Expand Down Expand Up @@ -55,4 +55,14 @@ public unsafe partial struct AccelerationStructureCreateInfoNV
]
)]
public AccelerationStructureInfoNV Info;

[SupportedApiProfile(
"vulkan",
["VK_NV_ray_tracing"],
ImpliesSets = [
"VK_KHR_get_physical_device_properties2+VK_KHR_get_memory_requirements2",
"VK_VERSION_1_1",
]
)]
public AccelerationStructureCreateInfoNV() { }
}
Loading
Loading