diff --git a/.silktouch/openal-clangsharp.stout b/.silktouch/openal-clangsharp.stout index cd15a37e8e..994e242e2e 100644 Binary files a/.silktouch/openal-clangsharp.stout and b/.silktouch/openal-clangsharp.stout differ diff --git a/.silktouch/opengl-clangsharp.stout b/.silktouch/opengl-clangsharp.stout index 9134b29332..0696b43007 100644 Binary files a/.silktouch/opengl-clangsharp.stout and b/.silktouch/opengl-clangsharp.stout differ diff --git a/.silktouch/vulkan-clangsharp.stout b/.silktouch/vulkan-clangsharp.stout index b6dc0b1f4a..d905b7ace2 100644 Binary files a/.silktouch/vulkan-clangsharp.stout and b/.silktouch/vulkan-clangsharp.stout differ diff --git a/generator.json b/generator.json index 83293d8003..8bbae05cda 100644 --- a/generator.json +++ b/generator.json @@ -147,6 +147,7 @@ "SpecPath": "eng/submodules/opengl/xml/gl.xml", "Namespace": "Silk.NET.OpenGL", "TypeMap": { + "GLenum": "uint", "TraceMaskMESA": "uint", "PathRenderingTokenNV": "byte", "PathCoordType": "byte" @@ -252,6 +253,10 @@ "MixKhronosData": { "SpecPath": "eng/submodules/openal-soft/registry/xml/al.xml", "Namespace": "Silk.NET.OpenAL", + "TypeMap": { + "ALenum": "uint", + "ALCenum": "uint" + }, "NonStandardExtensionNomenclature": true, "Vendors": [ "SOFT", diff --git a/sources/OpenGL/OpenGL/Enums/FragmentShaderDestMask.gen.cs b/sources/OpenGL/OpenGL/Enums/FragmentShaderDestMask.gen.cs index de8a534448..5a3ac06402 100644 --- a/sources/OpenGL/OpenGL/Enums/FragmentShaderDestMask.gen.cs +++ b/sources/OpenGL/OpenGL/Enums/FragmentShaderDestMask.gen.cs @@ -8,17 +8,18 @@ namespace Silk.NET.OpenGL; [NativeName("FragmentShaderDestMaskATI")] +[Flags] public enum FragmentShaderDestMask : uint { [NativeName("GL_NONE")] - None = 0, + None = 0x0, [NativeName("GL_RED_BIT_ATI")] - RedBitATI = 1, + RedBitATI = 0x1, [NativeName("GL_GREEN_BIT_ATI")] - GreenBitATI = 2, + GreenBitATI = 0x2, [NativeName("GL_BLUE_BIT_ATI")] - BlueBitATI = 4, + BlueBitATI = 0x4, } diff --git a/sources/OpenGL/OpenGL/Enums/FragmentShaderDestModMask.gen.cs b/sources/OpenGL/OpenGL/Enums/FragmentShaderDestModMask.gen.cs index 59bc20c93d..cf98b9ca92 100644 --- a/sources/OpenGL/OpenGL/Enums/FragmentShaderDestModMask.gen.cs +++ b/sources/OpenGL/OpenGL/Enums/FragmentShaderDestModMask.gen.cs @@ -8,29 +8,30 @@ namespace Silk.NET.OpenGL; [NativeName("FragmentShaderDestModMaskATI")] +[Flags] public enum FragmentShaderDestModMask : uint { [NativeName("GL_NONE")] - None = 0, + None = 0x0, [NativeName("GL_2X_BIT_ATI")] - X2XBitATI = 1, + X2XBitATI = 0x1, [NativeName("GL_4X_BIT_ATI")] - X4XBitATI = 2, + X4XBitATI = 0x2, [NativeName("GL_8X_BIT_ATI")] - X8XBitATI = 4, + X8XBitATI = 0x4, [NativeName("GL_HALF_BIT_ATI")] - HalfBitATI = 8, + HalfBitATI = 0x8, [NativeName("GL_QUARTER_BIT_ATI")] - QuarterBitATI = 16, + QuarterBitATI = 0x10, [NativeName("GL_EIGHTH_BIT_ATI")] - EighthBitATI = 32, + EighthBitATI = 0x20, [NativeName("GL_SATURATE_BIT_ATI")] - SaturateBitATI = 64, + SaturateBitATI = 0x40, } diff --git a/sources/OpenGL/OpenGL/Enums/PathFontStyle.gen.cs b/sources/OpenGL/OpenGL/Enums/PathFontStyle.gen.cs index 0243f93931..63ade9981e 100644 --- a/sources/OpenGL/OpenGL/Enums/PathFontStyle.gen.cs +++ b/sources/OpenGL/OpenGL/Enums/PathFontStyle.gen.cs @@ -8,14 +8,15 @@ namespace Silk.NET.OpenGL; [NativeName("PathFontStyle")] +[Flags] public enum PathFontStyle : uint { [NativeName("GL_NONE")] - None = 0, + None = 0x0, [NativeName("GL_BOLD_BIT_NV")] - BoldBitNV = 1, + BoldBitNV = 0x1, [NativeName("GL_ITALIC_BIT_NV")] - ItalicBitNV = 2, + ItalicBitNV = 0x2, } diff --git a/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs b/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs index 85dc14d268..0c26dd5429 100644 --- a/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs +++ b/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs @@ -440,22 +440,55 @@ rsp with return Task.FromResult(rsps); } - /// The name of the group. This is the name used for the C# enum. - /// The native name of the group, if available. This is the name used for the [NativeName] attribute. - /// - /// - /// - /// - /// - internal record EnumGroup( - string Name, - string? NativeName, - string? Type, - List Enums, - bool KnownBitmask, - string? ExclusiveVendor, - string? Namespace - ); + /// + /// Contains information about a group of enums. + /// + /// + /// There are two bitmask properties to better handle OpenGL-style enums. + /// Some enums are explicitly stated to be bitmasks while some have to be inferred. + /// + internal record EnumGroup + { + /// + /// The name of the group. This is the name used for the C# enum. + /// + public required string Name { get; init; } + + /// + /// The native name of the group. This is the name used for the [NativeName] attribute. + /// + public required string NativeName { get; init; } + + /// + /// The base type of the group. + /// + public string? BaseType { get; init; } + + /// + /// Members of this group extracted from other parts of the generated bindings. + /// + public List Enums { get; init; } = []; + + /// + /// Whether the group is explicitly known to be a bitmask, i.e., it is stated in the XML spec. + /// + public bool IsDefinitelyBitmask { get; init; } + + /// + /// Whether the group is likely a bitmask based on heuristics. + /// + public bool IsMaybeBitmask { get; init; } + + /// + /// The identified exclusive vendor for the group. Eg: NV. + /// + public string? ExclusiveVendor { get; init; } + + /// + /// The namespace for the group. Eg: GL. + /// + public string? Namespace { get; init; } + } private record ProfileEvaluation( Version? StartVersion, @@ -1544,7 +1577,7 @@ private class RewriterPhase1(JobData job, ILogger logger) : CSharpSyntaxRewriter { if (!AlreadyPresentGroups.Contains(groupName)) { - var baseType = groupInfo.Type ?? groupName; + var baseType = groupInfo.BaseType ?? groupName; while (job.TypeMap.TryGetValue(baseType, out var ty)) { baseType = ty; @@ -1759,7 +1792,10 @@ .. node.Members.Where(m => ); } - if (job.Groups.TryGetValue(identifier, out var group) && group.KnownBitmask) + if ( + job.Groups.TryGetValue(identifier, out var group) + && (group.IsDefinitelyBitmask || group.IsMaybeBitmask) + ) { // Add [Flags] attribute var flagsAttribute = AttributeList( @@ -2161,9 +2197,6 @@ internal void ReadGroups(XDocument doc, JobData data, HashSet vendors) // this information will mostly be used to enhance the enums scraped from the headers (eg: native name and bitmask information). var anyNamespaced = doc.Element("registry")?.Elements("enums").Attributes("namespace").Any() ?? false; - var anyGLStyleGroups = - doc.Element("registry")?.Elements("enums").Elements("enum").Attributes("group").Any() - ?? false; var likelyOpenCL = false; // OpenCL specific var topLevelIntentionalExclusions = new HashSet(); // OpenCL specific @@ -2174,24 +2207,46 @@ internal void ReadGroups(XDocument doc, JobData data, HashSet vendors) var isBitmask = block.Attribute("type")?.Value == "bitmask"; // OpenGL/EGL/WGL/GLX namespace - var enumNamespace = block.Attribute("namespace")?.Value; - var groupName = - enumNamespace is not null && !enumNamespace.All(char.IsUpper) - ? enumNamespace - : null; + var groupName = block.Attribute("group")?.Value; var nativeName = groupName; + var enumNamespace = block.Attribute("namespace")?.Value; + var baseType = enumNamespace != null ? $"{enumNamespace}enum" : null; - // OpenGL-style enums have an uint base type - var baseType = anyGLStyleGroups ? "uint" : null; + string? namespaceGroupName = null; + if (enumNamespace != null) + { + if (!enumNamespace.All(char.IsUpper)) + { + // Use the namespace name directly if it is not all uppercase + // Eg: WGLLayerPlaneMask + namespaceGroupName = enumNamespace; + } + else + { + // Otherwise, suffix the name with -Enum + // Eg: GLEnum, ALEnum, WGLEnum + namespaceGroupName = $"{enumNamespace}Enum"; + } + } - // Create an ungrouped group as well i.e. GLEnum, WGLEnum, etc - if (enumNamespace is not null) + // Create a group for the namespace as well i.e. GLEnum, WGLEnum, etc + if (namespaceGroupName is not null) { - groupName ??= $"{enumNamespace}Enum"; - nativeName ??= $"{enumNamespace}enum"; + if (!data.Groups.TryGetValue(namespaceGroupName, out var namespaceGroup)) + { + namespaceGroup = new EnumGroup() + { + Name = namespaceGroupName, + NativeName = $"{enumNamespace}enum", + BaseType = baseType, + Namespace = enumNamespace, + }; + + data.Groups[namespaceGroupName] = namespaceGroup; + } } - // OpenCL enum name + // Vulkan/OpenXR/OpenCL enum name if (!anyNamespaced) { groupName ??= block.Attribute("name")?.Value; @@ -2213,7 +2268,9 @@ internal void ReadGroups(XDocument doc, JobData data, HashSet vendors) // skip over the block. We continue on in the top-level case to permanently prevent any group operations // from occurring on the top-level intentional exclusions because they're special numbers/constants. var topLevelIntentionalExclusion = - groupName is not null && IsIntentionalExclusion(groupName); + groupName != null + && namespaceGroupName == null + && IsIntentionalExclusion(groupName); static bool IsIntentionalExclusion(string groupName) => groupName.StartsWith("Constants") // these are constants || groupName is "MiscNumbers" or "SpecialNumbers"; @@ -2230,46 +2287,49 @@ static bool IsUngroupable(string groupName) => } // Initialize the group before enum members are parsed below - // This ensures two things: + // This ensures 3 things: // 1. The native name is correct - // 2. Empty groups are recorded properly - if ( - groupName != null - && !IsUngroupable(groupName) - && !data.Groups.ContainsKey(groupName) - ) + // 2. Whether the enum is a bitmask is correct + // 3. Empty groups are recorded properly + if (groupName != null && !IsUngroupable(groupName)) { - data.Groups[groupName] = new EnumGroup( - groupName, - nativeName, - baseType, - [], - isBitmask, - VendorFromString(groupName, vendors), - enumNamespace - ); + data.Groups[groupName] = data.Groups.TryGetValue(groupName, out var group) + ? group with + { + IsDefinitelyBitmask = isBitmask, + } + : new EnumGroup() + { + Name = groupName, + NativeName = nativeName ?? groupName, + BaseType = baseType, + + IsDefinitelyBitmask = isBitmask, + ExclusiveVendor = VendorFromString(groupName, vendors), + Namespace = enumNamespace, + }; } // Parse enum members - foreach (var @enum in block.Elements("enum")) + foreach (var member in block.Elements("enum")) { - var enumName = - @enum.Attribute("name")?.Value + var memberName = + member.Attribute("name")?.Value ?? throw new InvalidDataException("Expected \"name\" attribute on ."); if (topLevelIntentionalExclusion) { - topLevelIntentionalExclusions.Add(enumName); + topLevelIntentionalExclusions.Add(memberName); continue; } // Get the group hash set for this enum. - if (!data.EnumsToGroups.TryGetValue(enumName, out var enumToGroups)) + if (!data.EnumsToGroups.TryGetValue(memberName, out var enumToGroups)) { - data.EnumsToGroups[enumName] = enumToGroups = []; + data.EnumsToGroups[memberName] = enumToGroups = []; } // Parse OpenGL-style groups - var glGroups = @enum + var additionalGroups = member .Attribute("group") ?.Value.Split( _listSeparators, @@ -2277,46 +2337,62 @@ static bool IsUngroupable(string groupName) => ); // Get the vendor (if the enum name ends with a vendor that is). - var thisVendor = VendorFromString(enumName, vendors); + var memberVendor = VendorFromString(memberName, vendors); // Add the enum member to the namespace enum, the main enum group, and its additional OpenGL-style groups - var memberGroups = (groupName is null ? Enumerable.Empty() : [groupName]) - .Concat(block.Attribute("group")?.Value is { Length: > 0 } g ? [g] : []) - .Concat(glGroups ?? []) - .Distinct(); - foreach (var group in memberGroups) + var memberGroupNames = new HashSet(); + if (namespaceGroupName != null) { - if (IsUngroupable(group)) + memberGroupNames.Add(namespaceGroupName); + } + + if (groupName != null) + { + memberGroupNames.Add(groupName); + } + + if (additionalGroups != null) + { + memberGroupNames.UnionWith(additionalGroups); + } + + foreach (var memberGroupName in memberGroupNames) + { + if (IsUngroupable(memberGroupName)) { continue; } // Update the group info. - data.Groups[group] = data.Groups.TryGetValue(group, out var groupInfo) - ? groupInfo with + data.Groups[memberGroupName] = data.Groups.TryGetValue( + memberGroupName, + out var memberGroup + ) + ? memberGroup with { - KnownBitmask = isBitmask && groupInfo.KnownBitmask, + IsMaybeBitmask = isBitmask && memberGroup.IsMaybeBitmask, ExclusiveVendor = - thisVendor is not null && groupInfo.ExclusiveVendor == thisVendor - ? thisVendor + memberVendor is not null + && memberGroup.ExclusiveVendor == memberVendor + ? memberVendor : null, Namespace = - enumNamespace is not null && groupInfo.Namespace == enumNamespace + enumNamespace is not null && memberGroup.Namespace == enumNamespace ? enumNamespace : null, } - : new EnumGroup( - group, - group, - baseType, - [], - isBitmask, - thisVendor, - enumNamespace - ); + : new EnumGroup() + { + Name = memberGroupName, + NativeName = memberGroupName, + BaseType = baseType, + IsMaybeBitmask = isBitmask, + ExclusiveVendor = memberVendor, + Namespace = enumNamespace, + }; // Mark this enum. - enumToGroups.Add(group); + enumToGroups.Add(memberGroupName); } } } @@ -2460,16 +2536,18 @@ var @enum in doc.Elements("registry") // it's actually correct for once. if (!data.Groups.ContainsKey(@enum.Value)) { - data.Groups[@enum.Value] = new EnumGroup( - @enum.Value, - @enum.Value, + data.Groups[@enum.Value] = new EnumGroup() + { + Name = @enum.Value, + NativeName = @enum.Value, // cl_properties and cl_bitfield are both cl_ulong which is ulong - "ulong", - [], - @enum.Parent?.Element("type")?.Value == "cl_bitfield", - VendorFromString(@enum.Value, vendors), - null - ); + // We currently use cl_bitfield to represent the backing type of OpenCL enums + // Decision was made here: https://github.com/dotnet/Silk.NET/pull/2534#discussion_r2686840153 + BaseType = "cl_bitfield", + + IsDefinitelyBitmask = @enum.Parent?.Element("type")?.Value == "cl_bitfield", + ExclusiveVendor = VendorFromString(@enum.Value, vendors), + }; } } @@ -2626,16 +2704,16 @@ is var splitList } else { - data.Groups[groupStr] = new EnumGroup( - groupStr, - groupStr, - null, - [], - (typeStr is not null && typeStr.Contains("bitfield")) + data.Groups[groupStr] = new EnumGroup() + { + Name = groupStr, + NativeName = groupStr, + + IsDefinitelyBitmask = + (typeStr is not null && typeStr.Contains("bitfield")) || group.Contains("flags"), - thisVendor, - null - ); + ExclusiveVendor = thisVendor, + }; } // Get the group hash set for this enum. diff --git a/tests/SilkTouch/SilkTouch/Khronos/MixKhronosDataTests.cs b/tests/SilkTouch/SilkTouch/Khronos/MixKhronosDataTests.cs index b9a7cf62ef..e3be2fda66 100644 --- a/tests/SilkTouch/SilkTouch/Khronos/MixKhronosDataTests.cs +++ b/tests/SilkTouch/SilkTouch/Khronos/MixKhronosDataTests.cs @@ -447,15 +447,13 @@ public enum GLEnum { } { { "GLEnum", - new MixKhronosData.EnumGroup( - "GLEnum", - "GLenum", - "Glenum", - [], - false, - null, - "GL" - ) + new MixKhronosData.EnumGroup() + { + Name = "GLEnum", + NativeName = "GLenum", + BaseType = "GLenum", + Namespace = "GL", + } }, }, },