Categories
Uncategorized

Vulkan (. 1) to generate a library Vulkan apispec

Vulkan (. 1) to generate a library Vulkan apispec

My Vulkan.net libraries in (https://github.com/bitzhuwei/Vulkan.net) open source, welcomed the exchange.

apispec.html

In Vulkan SDK installation folder, there is a Documentation \ apispec.html file. This is a description of the code generated by the Vulkan API. It contains the enumerated types, structure, function declarations Vulkan API, and all this detailed notes.

Because it is generated automatically, so its format is very rules. Just a few to several

, several

to

, XElement can be directly used to load and parse it.


Because it contains annotations for each enumeration type and its members, including the comments for each structure and its members, including the comment for each function declarations and arguments, I thought, if I can convert it to C # code, that would be a wonderful Vulkan library ah!

I found online a few Vulkan library, basically have no comment, it makes me very easy to use, a serious impediment to learning speed. Many types of structure members are roughened IntPtr, rather than specific types of indicators, which also makes a lot of trouble.

Then do their own hands Vulkan library now!

classification

First of all, to the huge apispec.html content of the document is divided into several categories, namely C macro definitions, Command (function declarations), Enum, Extension, Flag, Handle, PFN, Scalar Type and Struct. Where C macro definitions and Extension being less than, on the matter, Scalar Type the number of small, do not contain the substance, can be directly written by hand.

We turn analyzed according to Enum, Handle, Flag, PFN, Struct and order Command, as the latter may depend on the former.

Enum

We observe apispec.html the description of the Enum:

<h4 id="_name_798">Name
class="paragraph"> <p>VkAccelerationStructureMemoryRequirementsTypeNV - Acceleration structure memory requirement type

class="sect3">

"_c_specification_798">C Specification

class="paragraph">

Possible values of type in VkAccelerationStructureMemoryRequirementsInfoNV are:,

"VkAccelerationStructureMemoryRequirementsTypeNV" class="listingblock">
class="content">
class="highlight"><code class="language-c++" data-lang="c++">typedef enum VkAccelerationStructureMemoryRequirementsTypeNV {
    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0,
    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1,
    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2,
    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
} VkAccelerationStructureMemoryRequirementsTypeNV;
class="sect3">
<h4 id="_description_798">Description
class="ulist">

  • <p>VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV
    requests the memory requirement
    for the VkAccelerationStructureNV
    backing store.

  • <p>VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV
    requests the memory requirement
    for scratch space during the initial
    build.

  • <p>VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV
    requests the memory requirement
    for scratch space during an update.

class="sect3">
<h4 id="_see_also_798">See Also

We found that for each Enum type, apispec have this rule: from a

Name

tag beginning next

tag is a comment on this Enum, followed by the tag is defined in the Enum; then, from

Descriptor

start to

See Also

end, these two labels All

between

tags, annotations are a member of Enum, and that the comments are based on the name this member at the beginning of (this can be used to identify this comment to which members belong).

With these rules, you can resolve to C # code. Parsing code is very simple, is not explained.

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Xml.Linq;
  4 
  5 namespace ApiSpec {
  6     class EnumsParser {
  7 
  8         static readonly char[] inLineSeparator = new char[] { ' ', '\t', '\r', '\n', };
  9         static readonly char[] lineSeparator = new char[] { '\r', '\n' };
 10         const string leftBrace = "{";
 11         const string rightBrace = "}";
 12 
 13         const string filename = "Enums.content.xml";
 14         const string strName = "Name";
 15         const string strCSpecification = "C Specification";
 16         const string strDescription = "Description";
 17         const string strSeeAlso = "See Also";
 18         const string strDocNotes = "Document Notes";
 19 
 20         class EnumDefinetion {
 21             /*typedef enum VkAccelerationStructureMemoryRequirementsTypeNV {
 22     VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0,
 23     VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1,
 24     VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2,
 25     VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
 26 } VkAccelerationStructureMemoryRequirementsTypeNV;
 27              */
 28             public string raw;
 29 
 30             public string[] Dump() {
 31                 string[] lines = this.raw.Split(lineSeparator, StringSplitOptions.RemoveEmptyEntries);
 32                 if (lines == null || lines.Length < 2) { return lines; }
 33 
 34                 {
 35                     string[] parts = lines[0].Split(inLineSeparator, StringSplitOptions.RemoveEmptyEntries);
 36                     lines[0] = $"public enum {parts[2]} {leftBrace}";
 37                 }
 38                 {
 39                     int last = lines.Length - 1;
 40                     lines[last] = $"{rightBrace}";
 41                 }
 42 
 43                 return lines;
 44             }
 45         }
 46 
 47         class EnumItemComment {
 48             public List<string> lstComment = new List<string>();
 49 
 50             public Dictionary<string, string> Dump() {
 51                 Dictionary<string, string> dict = new Dictionary<string, string>();
 52                 foreach (var item in lstComment) {
 53                     int left = item.IndexOf("");
 54                     int right = item.IndexOf("");
 55                     if (left != -1 && right != -1) {
 56                         string key = item.Substring(left + "".Length, right - (left + "".Length));
 57                         if (!dict.ContainsKey(key)) {
 58                             dict.Add(key, item);
 59                         }
 60                     }
 61                 }
 62 
 63                 return dict;
 64             }
 65         }
 66 
 67         public static void DumpEnums() {
 68             XElement root = XElement.Load(filename);
 69             var lstDefinition = new List(); bool inside = false;
 70             TraverseNodesEnumDefinitions(root, lstDefinition, ref inside);
 71             var listEnumItemComment = new List(); inside = false;
 72             TraverseNodesEnumItemComments(root, listEnumItemComment, ref inside);
 73             var lstEnumComment = new List<string>(); inside = false;
 74             TraverseNodesEnumComments(root, lstEnumComment, ref inside);
 75 
 76             using (var sw = new System.IO.StreamWriter("Enums.gen.cs")) {
 77                 for (int i = 0; i < lstDefinition.Count; i++) {
 78                     EnumDefinetion definition = lstDefinition[i];
 79                     //sw.WriteLine(definition.raw);
 80                     string[] definitionLines = definition.Dump();
 81                     EnumItemComment itemComment = listEnumItemComment[i];
 82                     Dictionary<string, string> item2Comment = itemComment.Dump();
 83 
 84                     sw.WriteLine($"// Enum: {i}");
 85                     string enumComment = lstEnumComment[i];
 86                     sw.WriteLine($"/// {enumComment}");
 87                     {
 88                         string line = definitionLines[0];
 89                         if (line.Contains("FlagBits")) { sw.WriteLine("[Flags]"); }
 90                         sw.WriteLine(line);
 91                     }
 92                     for (int j = 1; j < definitionLines.Length - 1; j++) {
 93                         string line = definitionLines[j];
 94                         if (item2Comment != null) {
 95                             string strComment = ParseItemComment(line, item2Comment);
 96                             if (strComment != string.Empty) {
 97                                 strComment = strComment.Replace("\r\n", "\n");
 98                                 strComment = strComment.Replace("\r", "\n");
 99                                 strComment = strComment.Replace("\n", $"{Environment.NewLine}    /// ");
100                                 sw.WriteLine($"    /// {strComment}");
101                             }
102                         }
103                         sw.WriteLine(line);
104                     }
105                     {
106                         string line = definitionLines[definitionLines.Length - 1];
107                         sw.WriteLine(line); // }
108                     }
109                 }
110             }
111             Console.WriteLine("Done");
112         }
113 
114         /*

Name

115
116

VkAccessFlagBits - Bitmask specifying memory access types that will participate in a memory dependency

117
*/ 118 private static void TraverseNodesEnumComments(XElement node, List<string> list, ref bool inside) { 119 if (node.Name == "h4") { 120 if (node.Value == "Name") { 121 inside = true; 122 } 123 } 124 else if (node.Name == "p") { 125 if (inside) { 126 string text = node.ToString(); 127 text = text.Substring("

".Length, text.Length - "

".Length); 128 text = text.Trim(); 129 list.Add(text); 130 inside = false; 131 } 132 } 133 134 foreach (XElement item in node.Elements()) { 135 TraverseNodesEnumComments(item, list, ref inside); 136 } 137 } 138 139 /* line: VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0, 140 * 141 comment: VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV is a top-level 142 acceleration structure containing instance data referring to 143 bottom-level level acceleration structures. 144 VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV is a bottom-level 145 acceleration structure containing the AABBs or geometry to be 146 intersected. 147 */ 148 static readonly char[] equalSeparator = new char[] { '=', ' ', '\t', '\r', '\n', }; 149 private static string ParseItemComment(string line, Dictionary<string, string> dict) { 150 string result = string.Empty; 151 string[] parts = line.Split(equalSeparator, StringSplitOptions.RemoveEmptyEntries); 152 if (parts.Length == 2) { 153 string key = parts[0]; 154 if (dict.ContainsKey(key)) { 155 result = dict[key]; 156 } 157 } 158 159 return result; 160 } 161 162 /// 163 /// 164 /// 165 /// 166 /// 167 /// 168 private static void TraverseNodesEnumItemComments(XElement node, List list, ref bool inside) { 169 if (node.Name == "h4") { 170 if (node.Value == "Description") { 171 inside = true; 172 var comment = new EnumItemComment(); 173 list.Add(comment); 174 } 175 else if (node.Value == "See Also") { 176 inside = false; 177 } 178 } 179 else if (node.Name == "p") { 180 if (inside) { 181 EnumItemComment comment = list[list.Count - 1]; 182 string text = node.ToString(); 183 text = text.Substring("

".Length, text.Length - "

".Length); 184 text = text.Trim(); 185 comment.lstComment.Add(text); 186 } 187 } 188 189 foreach (XElement item in node.Elements()) { 190 TraverseNodesEnumItemComments(item, list, ref inside); 191 } 192 } 193 194 195 private static void TraverseNodesEnumDefinitions(XElement node, List list, ref bool inside) { 196 if (node.Name == "h4") { 197 if (node.Value == "C Specification") { 198 inside = true; 199 } 200 } 201 else if (node.Name == "code") { 202 if (inside) { 203 XAttribute attrClass = node.Attribute("class"); 204 if (attrClass != null && attrClass.Value == "language-c++") { 205 string v = node.Value; 206 var item = new EnumDefinetion() { raw = v, }; 207 list.Add(item); 208 inside = false; 209 } 210 } 211 } 212 213 foreach (XElement item in node.Elements()) { 214 TraverseNodesEnumDefinitions(item, list, ref inside); 215 } 216 } 217 } 218 }

EnumsParser

Parsed Enum type 143, the first two of which are as follows:

 1     // Enum: 0
 2     /// VkAccelerationStructureMemoryRequirementsTypeNV - Acceleration structure memory requirement type
 3     public enum VkAccelerationStructureMemoryRequirementsTypeNV {
 4         /// VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV
 5         /// requests the memory requirement for the VkAccelerationStructureNV
 6         /// backing store.
 7         VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0,
 8         /// VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV
 9         /// requests the memory requirement for scratch space during the initial
10         /// build.
11         VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1,
12         /// VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV
13         /// requests the memory requirement for scratch space during an update.
14         VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2,
15         VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
16     }
17     // Enum: 1
18     /// VkAccelerationStructureTypeNV - Type of acceleration structure
19     public enum VkAccelerationStructureTypeNV {
20         /// VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV is a top-level
21         /// acceleration structure containing instance data referring to
22         /// bottom-level level acceleration structures.
23         VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0,
24         /// VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV is a bottom-level
25         /// acceleration structure containing the AABBs or geometry to be
26         /// intersected.
27         VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1,
28         VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
29     }

In order to maintain the original Vulkan API's (also to save myself), Enum member name remains so long uppercase + underscore version better.

Handle

Handle herein refers Vulkan opaque objects for the programmer in the handle, for example, a type of the object VkInstance, programmer see here only handle a UInt32, its actual content managed by the internal Vulkan. So just find here the names of each Handle, rewrite it as a struct can.

Handle apispec.html in the description of the following:

<h3 id="_vkaccelerationstructurenv3">VkAccelerationStructureNV(3)

Just find each

tag, you can find the name of the individual Handle. Parsed to obtain 37 Handle, wherein Handle 2 as follows:

 1     // Object Handles: 1
 2     /// VkBuffer - Opaque handle to a buffer object
 3     /// Buffers represent linear arrays of data which are used for various purposesby binding them to a graphics or compute pipeline via descriptor sets or viacertain commands, or by directly specifying them as parameters to certaincommands.
 4     /// Buffers are represented by VkBuffer handles:
 5     /// 
 6     public struct VkBuffer {
 7         public UInt64 handle;
 8     }
 9 
10     // Object Handles: 21
11     /// VkInstance - Opaque handle to an instance object
12     /// There is no global state in Vulkan and all per-application state is storedin a VkInstance object.Creating a VkInstance object initializes the Vulkan library and allowsthe application to pass information about itself to the implementation.
13     /// Instances are represented by VkInstance handles:
14     /// 
15     public struct VkInstance {
16         public UInt32 handle;
17     }

For such struct above, a length equal to the length of the inner member. So, in fact VkInstance just an alias, this alias UInt32 greatly strengthened the role of type, speeds programming.

Note that some Handle use UInt64, some use UInt32, which is not free to change, otherwise it will be stuck Vulkan not move. Of course, as long as the same byte length, can replace, for example, may be used instead of IntPtr UInt32, because both are 4 bytes.

Flag

In apispec.html in, Flag is actually an alias, a name that is used C language typedef defined. Two examples are as follows:

1 <p>VkAccessFlags - Bitmask of VkAccessFlagBits

2 <p>VkBufferViewCreateFlags - Reserved for future use

It is currently the only two kinds apispec Flag description form. For them, we can replace each with the following code:

1 using VkAccessFlags = ApiSpec.Generated.VkAccessFlagBits;
2 // VkBufferViewCreateFlags - Reserved for future use

Analytic method is very simple, with string.Split () Split click.

These codes using the resulting, for parsing and rear Struct Command.

PFN

PFN here is a function pointer mean, that is a delegate in C # that set. Enum and its analytical methods is very similar, not repeat them. After eight parsed definition of function pointers, wherein several follows:

 1     // PFN: 0
 2     /// PFN_vkAllocationFunction - Application-defined memory allocation function
 3     public unsafe delegate void* PFN_vkAllocationFunction(
 4     /// pUserData is the value specified for
 5     /// VkAllocationCallbacks::pUserData in the allocator specified
 6     /// by the application.
 7     void* pUserData,
 8     /// size is the size in bytes of the requested allocation.
 9     Int32 size,
10     /// alignment is the requested alignment of the allocation in bytes
11     /// and must be a power of two.
12     Int32 alignment,
13     /// allocationScope is a VkSystemAllocationScope value
14     /// specifying the allocation scope of the lifetime of the allocation, as
15     /// described here.
16     VkSystemAllocationScope allocationScope);
17     // PFN: 1
18     /// PFN_vkDebugReportCallbackEXT - Application-defined debug report callback function
19     public unsafe delegate VkBool32 PFN_vkDebugReportCallbackEXT(
20     /// flags specifies the VkDebugReportFlagBitsEXT that triggered
21     /// this callback.
22     VkDebugReportFlagBitsEXT flags,
23     /// objectType is a VkDebugReportObjectTypeEXT value specifying
24     /// the type of object being used or created at the time the event was
25     /// triggered.
26     VkDebugReportObjectTypeEXT _objectType,
27     /// object is the object where the issue was detected.
28     /// If objectType is VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
29     /// object is undefined.
30     UInt64 _object,
31     /// location is a component (layer, driver, loader) defined value that
32     /// specifies the location of the trigger.
33     /// This is an optional value.
34     Int32 location,
35     /// messageCode is a layer-defined value indicating what test
36     /// triggered this callback.
37     Int32 messageCode,
38     /// pLayerPrefix is a null-terminated string that is an abbreviation
39     /// of the name of the component making the callback.
40     /// pLayerPrefix is only valid for the duration of the callback.
41     IntPtr pLayerPrefix,
42     /// pMessage is a null-terminated string detailing the trigger
43     /// conditions.
44     /// pMessage is only valid for the duration of the callback.
45     IntPtr pMessage,
46     /// pUserData is the user data given when the
47     /// VkDebugReportCallbackEXT was created.
48     void* pUserData);

You can see, the comment function parameters and comments are very detailed, it looked fun.

Struct

For the Struct and Enum resolution also similar, not repeat them. Parsed to obtain 434 structures. Several of the following:

 1     // Struct: 4
 2     /// VkAllocationCallbacks - Structure containing callback function pointers for memory allocation
 3     /// 
 4     public unsafe struct VkAllocationCallbacks {
 5         ///  pUserData is a value to be interpreted by the implementation of
 6         /// the callbacks.
 7         /// When any of the callbacks in VkAllocationCallbacks are called, the
 8         /// Vulkan implementation will pass this value as the first parameter to the
 9         /// callback.
10         /// This value can vary each time an allocator is passed into a command,
11         /// even when the same object takes an allocator in multiple commands.
12         public void* pUserData;
13         ///  pfnAllocation is a pointer to an application-defined memory
14         /// allocation function of type PFN_vkAllocationFunction.
15         public /*PFN_vkAllocationFunction*/IntPtr pfnAllocation;
16         ///  pfnReallocation is a pointer to an application-defined memory
17         /// reallocation function of type PFN_vkReallocationFunction.
18         public /*PFN_vkReallocationFunction*/IntPtr pfnReallocation;
19         ///  pfnFree is a pointer to an application-defined memory free
20         /// function of type PFN_vkFreeFunction.
21         public /*PFN_vkFreeFunction*/IntPtr pfnFree;
22         ///  pfnInternalAllocation is a pointer to an application-defined
23         /// function that is called by the implementation when the implementation
24         /// makes internal allocations, and it is of type
25         /// PFN_vkInternalAllocationNotification.
26         public /*PFN_vkInternalAllocationNotification*/IntPtr pfnInternalAllocation;
27         ///  pfnInternalFree is a pointer to an application-defined function
28         /// that is called by the implementation when the implementation frees
29         /// internal allocations, and it is of type
30         /// PFN_vkInternalFreeNotification.
31         public /*PFN_vkInternalFreeNotification*/IntPtr pfnInternalFree;
32 }
33     // Struct: 9
34     /// VkApplicationInfo - Structure specifying application info
35     /// 
36     public unsafe struct VkApplicationInfo {
37         ///  sType is the type of this structure.
38         public VkStructureType sType;
39         ///  pNext is NULL or a pointer to an extension-specific structure.
40         public /*-const-*/ void* pNext;
41         ///  pApplicationName is NULL or is a pointer to a null-terminated
42         /// UTF-8 string containing the name of the application.
43         public IntPtr pApplicationName;
44         ///  applicationVersion is an unsigned integer variable containing the
45         /// developer-supplied version number of the application.
46         public UInt32 applicationVersion;
47         ///  pEngineName is NULL or is a pointer to a null-terminated UTF-8
48         /// string containing the name of the engine (if any) used to create the
49         /// application.
50         public IntPtr pEngineName;
51         ///  engineVersion is an unsigned integer variable containing the
52         /// developer-supplied version number of the engine used to create the
53         /// application.
54         public UInt32 engineVersion;
55         ///  apiVersion
56         ///   must be the highest version of Vulkan that the
57         /// application is designed to use, encoded as described in
58         /// html/vkspec.html#extendingvulkan-coreversions-versionnumbers.
59         /// The patch version number specified in apiVersion is ignored when
60         /// creating an instance object.
61         /// Only the major and minor versions of the instance must match those
62         /// requested in apiVersion.
63         public UInt32 apiVersion;
64 }
65     // Struct: 193
66     /// VkInstanceCreateInfo - Structure specifying parameters of a newly created instance
67     /// 
68     public unsafe struct VkInstanceCreateInfo {
69         ///  sType is the type of this structure.
70         public VkStructureType sType;
71         ///  pNext is NULL or a pointer to an extension-specific structure.
72         public /*-const-*/ void* pNext;
73         ///  flags is reserved for future use.
74         public VkInstanceCreateFlags flags;
75         ///  pApplicationInfo is NULL or a pointer to an instance of
76         /// VkApplicationInfo.
77         /// If not NULL, this information helps implementations recognize behavior
78         /// inherent to classes of applications.
79         /// VkApplicationInfo is defined in detail below.
80         public /*-const-*/ VkApplicationInfo* pApplicationInfo;
81         ///  enabledLayerCount is the number of global layers to enable.
82         public UInt32 enabledLayerCount;
83         ///  ppEnabledLayerNames is a pointer to an array of
84         /// enabledLayerCount null-terminated UTF-8 strings containing the
85         /// names of layers to enable for the created instance.
86         /// See the html/vkspec.html#extendingvulkan-layers section for further details.
87         public IntPtr /*-const-*/ * ppEnabledLayerNames;
88         ///  enabledExtensionCount is the number of global extensions to
89         /// enable.
90         public UInt32 enabledExtensionCount;
91         ///  ppEnabledExtensionNames is a pointer to an array of
92         /// enabledExtensionCount null-terminated UTF-8 strings containing the
93         /// names of extensions to enable.
94         public IntPtr /*-const-*/ * ppEnabledExtensionNames;
95     }

Here are a few points to note.

After the function entrusted with in a struct, the struct pointer can not be used in the form of (SomeStruct *), so there had to replace the specific functions entrusted by IntPtr.

In IntPtr pApplicationName should assign it with Marshal.StringToHGlobalAnsi (string s). Function Marshal.StringToHGlobalAnsi (string s) creates a copy of s in unmanaged memory and then returns a pointer to this copy. Such pApplicationName will point to a fixed position of the string. Of course, after use, the copy should be freed with Marshal.FreeHGlobal (IntPtr hglobal). To simplify this process, I offer an extension function:

 1         /// 
 2         /// Set a string to specified .
 3         /// 
 4         /// 
 5         /// address of string.
 6         public static void Set(this string value, ref IntPtr target) {
 7             {   // free unmanaged memory.
 8                 if (target != IntPtr.Zero) {
 9                     Marshal.FreeHGlobal(target);
10                     target = IntPtr.Zero;
11                 }
12             }
13             {
14                 if (value != null && value.Length > 0) {
15                     target = Marshal.StringToHGlobalAnsi(value);
16                 }
17                 else {
18                     target = IntPtr.Zero;
19                 }
20             }
21         }

Once Marshal.StringToHGlobalAnsi () memory release function will expand on this, but can not guarantee this time. That is, it can be guaranteed, but also simply call up to 1 times the memory release function Marshal.FreeHGlobal (IntPtr hglobal).

In public IntPtr / * - const - * / * ppEnabledLayerNames; also has a similar problem, this points to an IntPtr array members, each member of the array is a IntPtr, IntPtr each have a point of Marshal.StringToHGlobalAnsi (string s ) returns the value provided. So this requires another extension functions to simplify it:

 1         /// 
 2         /// Set an array of structs to specified  and .
 3         /// Enumeration types are not allowed to use this method.
 4         /// If you have to, convert them to byte/short/ushort/int/uint according to their underlying types first.
 5         /// 
 6         /// 
 7         /// address of first element/array.
 8         /// How many elements?
 9         public static void Set(this T[] value, ref IntPtr target, ref UInt32 count) where T : struct {
10             {   // free unmanaged memory.
11                 if (target != IntPtr.Zero) {
12                     Marshal.FreeHGlobal(target);
13                     target = IntPtr.Zero;
14                     count = 0;
15                 }
16             }
17             {
18                 count = (UInt32)value.Length;
19 
20                 int elementSize = Marshal.SizeOf();
21                 int byteLength = (int)(count * elementSize);
22                 IntPtr array = Marshal.AllocHGlobal(byteLength);
23                 var dst = (byte*)array;
24                 GCHandle pin = GCHandle.Alloc(value, GCHandleType.Pinned);
25                 IntPtr address = Marshal.UnsafeAddrOfPinnedArrayElement(value, 0);
26                 var src = (byte*)address;
27                 for (int i = 0; i < byteLength; i++) {
28                     dst[i] = src[i];
29                 }
30                 pin.Free();
31 
32                 target = array;
33             }
34         }

In this function arguments, I use the ref IntPtr target, rather than ref T * target, because C # does not allow this. The compiler that can not get a managed type ( "T") in size, or declare a pointer to it. So when you call this extension function, you have to first create a temporary variable IntPtr ptr = IntPtr.Zero, after you call the extension function, then ptr given the specific type of pointer. E.g:

1         var deviceInfo = new VkDeviceCreateInfo();
2         IntPtr ptr = IntPtr.Zero;
3         new VkDeviceQueueCreateInfo[] { queueInfo }.Set(ref ptr, ref deviceInfo.queueCreateInfoCount);
4         deviceInfo.pQueueCreateInfos = (VkDeviceQueueCreateInfo*)ptr;

The good news is an array of strings for string [] and (

boolbyteshortintlongcharsbyteushortuintulongfloatdouble

) These 12 special basic types of arrays, you can directly use the Set extension functions. Because I specifically wrote a particular extension function for them.

Command

For Command parsing Struct also similar, not repeat them. After 326 parsed command, a few examples are as follows:

 1         // Command: 4
 2         /// vkAllocateCommandBuffers - Allocate command buffers from an existing command pool
 3         /// 
 4         ///  device is the logical device that owns the command pool.
 5         ///  pAllocateInfo is a pointer to an instance of the
 6         /// VkCommandBufferAllocateInfo structure describing parameters of the
 7         /// allocation.
 8         ///  pCommandBuffers is a pointer to an array of VkCommandBuffer
 9         /// handles in which the resulting command buffer objects are returned.
10         /// The array must be at least the length specified by the
11         /// commandBufferCount member of pAllocateInfo.
12         /// Each allocated command buffer begins in the initial state.
13         [DllImport(VulkanLibrary, CallingConvention = CallingConvention.Winapi)]
14         public static extern VkResult vkAllocateCommandBuffers(
15             VkDevice device,
16             /*-const-*/ VkCommandBufferAllocateInfo* pAllocateInfo,
17             VkCommandBuffer* pCommandBuffers);
18         // Command: 324
19         /// vkUpdateDescriptorSets - Update the contents of a descriptor set object
20         /// 
21         ///  device is the logical device that updates the descriptor sets.
22         ///  descriptorWriteCount is the number of elements in the
23         /// pDescriptorWrites array.
24         ///  pDescriptorWrites is a pointer to an array of
25         /// VkWriteDescriptorSet structures describing the descriptor sets to
26         /// write to.
27         ///  descriptorCopyCount is the number of elements in the
28         /// pDescriptorCopies array.
29         ///  pDescriptorCopies is a pointer to an array of
30         /// VkCopyDescriptorSet structures describing the descriptor sets to
31         /// copy between.
32         [DllImport(VulkanLibrary, CallingConvention = CallingConvention.Winapi)]
33         public static extern void vkUpdateDescriptorSets(
34             VkDevice device,
35             UInt32 descriptorWriteCount,
36             /*-const-*/ VkWriteDescriptorSet* pDescriptorWrites,
37             UInt32 descriptorCopyCount,
38             /*-const-*/ VkCopyDescriptorSet* pDescriptorCopies);

There is a void ** This function uses two hands, I think it is really ugly and hard to use, use IntPtr * instead.

Management of unmanaged memory (release) problems

Each struct should be responsible for the release of their own problems unmanaged resources used by themselves. Such a pointer to a member of a struct T * p; the assignment, should also copy a copy of the data, a copy of the assignment to p. In this way it releases the resource, it will not affect other place. In fact, each spread function Set (..) I is to use a copy of the assignment.

If a member of a struct pointer T * p; in fact just get a target, that is, the array element has only one, so this address can be assigned directly to an element of p, and does not free up resources. E.g:

 1     UInt32 index = 0;
 2     var info = new VkSwapchainCreateInfoKHR();
 3     {
 4         info.sType = VkStructureType.VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
 5         // other stuff ..
 6         //new UInt32[] { 0 }.Set(ref info.QueueFamilyIndices, ref info.QueueFamilyIndexCount);
 7         info.pQueueFamilyIndices = &index; info.queueFamilyIndexCount = 1;
 8     }
 9     
10     VkSwapchainKHR swapchain;
11     vkAPI.vkCreateSwapchainKHR(device, &info, null, &swapchain);

This is a secure, portable, programmers do not need to write directly to Marshal. AllocHGlobal () memory management.

So, if the programmer forgets to release some resources struct out? Vulkan said that programmers should know what they are doing, or why they use Vulkan. I think so, these struct will not be used repeatedly, and therefore, they leak up to a little bit of memory, so do not take up more and more memory as the server code, so out of the way.

to sum up

With so interesting comment, whole grade are not the same.

 

 

Leave a Reply