comparison svk/generate.nim @ 1481:a99f3227130c default tip

did: continue on vulkan-api generator
author sam <sam@basx.dev>
date Sun, 27 Apr 2025 01:06:59 +0700
parents 0b302531f5c5
children
comparison
equal deleted inserted replaced
1480:0b302531f5c5 1481:a99f3227130c
31 "uint32_t": "uint32", 31 "uint32_t": "uint32",
32 "uint64_t": "uint64", 32 "uint64_t": "uint64",
33 "int64_t": "int64", 33 "int64_t": "int64",
34 "size_t": "csize_t", 34 "size_t": "csize_t",
35 "int": "cint", 35 "int": "cint",
36 "void*": "pointer",
37 "char*": "cstring",
38 "ptr char": "cstring",
39 "ptr void": "pointer",
40 # "VK_DEFINE_HANDLE": "VkHandle", # not required, can directly defined as a distinct pointer, (in C is a pointer to an empty struct type)
41 # "VK_DEFINE_NON_DISPATCHABLE_HANDLE": "VkNonDispatchableHandle", # same here
42 }.toTable 36 }.toTable
43 37
44 # load xml 38 # load xml
45 let xml = (system.currentSourcePath.parentDir() / "vk.xml").loadXml() 39 let xml = (system.currentSourcePath.parentDir() / "vk.xml").loadXml()
46 let platforms = xml.findAll("platforms")[0] 40 let platforms = xml.findAll("platforms")[0]
93 v = -v 87 v = -v
94 value = $(v) 88 value = $(v)
95 89
96 edef.values.add EnumEntry(name: n.attr("name"), value: value) 90 edef.values.add EnumEntry(name: n.attr("name"), value: value)
97 91
92 func doTypename(typename: string, isPointer: bool): string =
93 result = TYPEMAP.getOrDefault(typename.strip(), typename.strip()).strip(chars = {'_'})
94
95 if typename == "void":
96 assert isPointer
97
98 if isPointer:
99 if typename == "void":
100 result = "pointer"
101 elif typename == "char":
102 result = "cstring"
103 else:
104 result = "ptr " & result
105
106 func doIdentifier(typename: string): string =
107 if typename in ["type", "object"]:
108 return &"`{typename}`"
109 return typename.strip()
110
111 func doMember(typename, theType: string, isPointer: bool, value: string): string =
112 if value == "":
113 &"{doIdentifier(typename)}: {doTypename(theType, isPointer)}"
114 else:
115 &"{doIdentifier(typename)}: {doTypename(theType, isPointer)} = {value}"
116
98 func memberDecl(n: XmlNode): string = 117 func memberDecl(n: XmlNode): string =
99 for i in 0 ..< n.len: 118 for i in 0 ..< n.len:
100 if n[i].kind == xnElement and n[i].tag == "comment": 119 if n[i].kind == xnElement and n[i].tag == "comment":
101 n.delete(i) 120 n.delete(i)
102 break 121 break
103 assert n.tag == "member" 122 assert n.tag == "member"
104 debugecho n.toSeq, " ", n.len
105 if n.len == 2: 123 if n.len == 2:
106 return &"{n[1][0].text}: {n[0][0]}" 124 return doMember(n[1][0].text, n[0][0].text, false, n.attr("values"))
107 elif n.len == 3: 125 elif n.len == 3:
126 assert "*" notin n[0][0].text.strip()
108 if n[1].kind == xnElement and n[1].tag == "name": 127 if n[1].kind == xnElement and n[1].tag == "name":
109 return 128 # bitfield
110 &"{n[1][0].text}: array[{n[2].text[1 ..< ^1]}, {TYPEMAP.getOrDefault(n[0][0].text, n[0][0].text)}]]" 129 if n[2].text.strip().startsWith(":"):
130 return
131 &"{doIdentifier(n[1][0].text)} {{.bitsize:{n[2].text.strip()[1 .. ^1]}.}}: {doTypename(n[0][0].text, false)}"
132 # array definition
133 elif n[2].text.strip().startsWith("["):
134 let arrayDim = n[2].text[1 ..< ^1]
135 if "][" in arrayDim:
136 let dims = arrayDim.split("][", 1)
137 let (dim1, dim2) = (dims[0], dims[1])
138 return doMember(
139 n[1][0].text,
140 &"array[{dim1}, array[{dim2}, {doTypename(n[0][0].text, false)}]]",
141 false,
142 n.attr("values"),
143 )
144 else:
145 return doMember(
146 n[1][0].text,
147 &"array[{arrayDim}, {doTypename(n[0][0].text, false)}]",
148 false,
149 n.attr("values"),
150 )
151 else:
152 debugecho n.toSeq
153 doAssert false, "This should not happen"
111 else: 154 else:
155 # pointer definition
112 assert n[1].text.strip() == "*" 156 assert n[1].text.strip() == "*"
113 return &"{n[2][0].text}: ptr {n[0][0].text}" 157 return doMember(n[2][0].text, n[0][0].text, true, n.attr("values"))
114 elif n.len == 4: 158 elif n.len == 4:
115 if n[0].text.strip() in ["struct", "const struct"]: 159 if n[0].text.strip() in ["struct", "const struct"]:
116 return &"{n[3][0].text}: ptr {n[1][0].text}" 160 return doMember(n[3][0].text, n[1][0].text, true, n.attr("values"))
117 else: 161 else:
162 assert n[0].text.strip() == "const" # can be ignored
163 assert n[1].tag == "type"
118 assert n[2].text.strip() in ["*", "* const *", "* const*"] 164 assert n[2].text.strip() in ["*", "* const *", "* const*"]
119 return &"?" 165 # can be ignored, basically every type is a pointer
166 assert n[3].tag == "name"
167 assert n[1].len == 1
168 assert n[3].len == 1
169 return doMember(n[3][0].text, n[1][0].text, true, n.attr("values"))
120 elif n.len in [5, 6]: 170 elif n.len in [5, 6]:
121 return &"{n[1][0].text}: array[{n[3][0].text}, {n[0][0].text}]" 171 # array definition, using const-value for array length
172 # <type>uint8_t</type>,<name>pipelineCacheUUID</name>[<enum>VK_UUID_SIZE</enum>]
173 assert n[2].text.strip() == "["
174 assert n[4].text.strip() == "]"
175 return doMember(
176 n[1][0].text,
177 &"array[{n[3][0].text}, {doTypename(n[0][0].text, false)}]",
178 false,
179 n.attr("values"),
180 )
122 assert false 181 assert false
123 182
124 for e in xmlenums: 183 for e in xmlenums:
125 if e.attr("type") == "constants": 184 if e.attr("type") == "constants":
126 for c in e.findAll("enum"): 185 for c in e.findAll("enum"):
150 if extendenum.attr("extends") != "": 209 if extendenum.attr("extends") != "":
151 if extendenum.attr("extnumber") == "": 210 if extendenum.attr("extnumber") == "":
152 extendenum.attrs["extnumber"] = extNum 211 extendenum.attrs["extnumber"] = extNum
153 enums[extendenum.attr("extends")].addValue(extendenum) 212 enums[extendenum.attr("extends")].addValue(extendenum)
154 213
155 let outPath = (system.currentSourcePath.parentDir() / "api.nim") 214 let outPath = (system.currentSourcePath.parentDir() / "vkapi.nim")
156 let outFile = open(outPath, fmWrite) 215 let outFile = open(outPath, fmWrite)
157 216
158 # generate core types =============================================================================== 217 # generate core types ===============================================================================
159 # preamble, much easier to hardcode than to generate from xml 218 # preamble, much easier to hardcode than to generate from xml
160 outFile.writeLine """ 219 outFile.writeLine """
220
221 import ../semicongine/thirdparty/winim/winim/inc/winbase
222 import ../semicongine/thirdparty/winim/winim/inc/windef
223 import ../semicongine/thirdparty/x11/xlib
224 import ../semicongine/thirdparty/x11/x
225 import ../semicongine/thirdparty/x11/xrandr
226
161 func VK_MAKE_API_VERSION*( 227 func VK_MAKE_API_VERSION*(
162 variant: uint32, major: uint32, minor: uint32, patch: uint32 228 variant: uint32, major: uint32, minor: uint32, patch: uint32
163 ): uint32 {.compileTime.} = 229 ): uint32 {.compileTime.} =
164 (variant shl 29) or (major shl 22) or (minor shl 12) or patch 230 (variant shl 29) or (major shl 22) or (minor shl 12) or patch
165 """ 231 """
166 232
167 outFile.writeLine "type" 233 outFile.writeLine "type"
168 outFile.writeLine """ 234 outFile.writeLine """
235 # some unused native types
236 #
237 # android
238 ANativeWindow = object
239 AHardwareBuffer = object
240
241 # apple
242 CAMetalLayer = object
243 MTLDevice = object
244 MTLCommandQueue = object
245 MTLBuffer = object
246 MTLTexture = object
247 MTLSharedEvent = object
248 MTLSharedEvent_id = object
249
250 # wayland
251 wl_display = object
252 wl_surface = object
253
254 # XCB
255 xcb_connection_t = object
256 xcb_window_t = object
257 xcb_visualid_t = object
258
259 # directfb
260 IDirectFB = object
261 IDirectFBSurface = object
262
263 # Zircon
264 zx_handle_t = object
265
266 # GGP C
267 GgpStreamDescriptor = object
268 GgpFrameToken = object
269
270 # Screen (nintendo switch?)
271 screen_context = object
272 screen_window = object
273 screen_buffer = object
274
275 # Nvidia
276 NvSciSyncAttrList = object
277 NvSciSyncObj = object
278 NvSciSyncFence = object
279 NvSciBufAttrList = object
280 NvSciBufObj = object
281
282 # some base vulkan base types
169 VkSampleMask = distinct uint32 283 VkSampleMask = distinct uint32
170 VkBool32 = distinct uint32 284 VkBool32 = distinct uint32
171 VkFlags = distinct uint32 285 VkFlags = distinct uint32
172 VkFlags64 = distinct uint64 286 VkFlags64 = distinct uint64
173 VkDeviceSize = distinct uint64 287 VkDeviceSize = distinct uint64
174 VkDeviceAddress = distinct uint64 288 VkDeviceAddress = distinct uint64
175 VkRemoteAddressNV = pointer 289 VkRemoteAddressNV = pointer
176 """ 290 """
177
178 for t in types:
179 if t.attr("api") == "vulkansc":
180 continue
181 if t.attr("alias") != "":
182 continue
183 if t.attr("deprecated") == "true":
184 continue
185 if t.attr("category") == "include":
186 continue
187 if t.attr("category") == "define":
188 continue
189 if t.attr("category") == "bitmask":
190 if t.len > 0 and t[0].text.startsWith("typedef"):
191 outFile.writeLine &" {t[2][0].text} = distinct {t[1][0].text}"
192 elif t.attr("category") == "union":
193 let n = t.attr("name")
194 outFile.writeLine &" {n}* {{.union.}} = object"
195 for member in t.findAll("member"):
196 outFile.writeLine &" {member.memberDecl()}"
197 elif t.attr("category") == "handle":
198 outFile.writeLine &" {t[2][0].text} = distinct pointer"
199 elif t.attr("category") == "struct":
200 let n = t.attr("name")
201 outFile.writeLine &" {n}* = object"
202 for member in t.findAll("member"):
203 outFile.writeLine &" {member.memberDecl()}"
204 # TODO: funcpointer
205
206 outFile.writeLine ""
207 291
208 # generate consts =============================================================================== 292 # generate consts ===============================================================================
209 outFile.writeLine "const" 293 outFile.writeLine "const"
210 for c in consts: 294 for c in consts:
211 var value = c.value 295 var value = c.value
217 value = "not " & value[1 ..^ 1] 301 value = "not " & value[1 ..^ 1]
218 outFile.writeLine &" {c.name}*: {c.datatype} = {value}" 302 outFile.writeLine &" {c.name}*: {c.datatype} = {value}"
219 outFile.writeLine "" 303 outFile.writeLine ""
220 304
221 # generate enums =============================================================================== 305 # generate enums ===============================================================================
306 const nameCollisions = [
307 "VK_PIPELINE_CACHE_HEADER_VERSION_ONE",
308 "VK_PIPELINE_CACHE_HEADER_VERSION_SAFETY_CRITICAL_ONE",
309 "VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT",
310 ]
222 outFile.writeLine "type" 311 outFile.writeLine "type"
223 for edef in enums.values(): 312 for edef in enums.values():
224 if edef.values.len > 0: 313 if edef.values.len > 0:
225 outFile.writeLine &" {edef.name}* {{.size: 4.}} = enum" 314 outFile.writeLine &" {edef.name}* {{.size: 4.}} = enum"
226 for ee in edef.values: 315 for ee in edef.values:
227 outFile.writeLine &" {ee.name} = {ee.value}" 316 # due to the nim identifier-system, there might be collisions between typenames and enum-member names
317 if ee.name in nameCollisions:
318 outFile.writeLine &" {ee.name}_VALUE = {ee.value}"
319 else:
320 outFile.writeLine &" {ee.name} = {ee.value}"
321
322 outFile.writeLine ""
323
324 # generate types ===============================================================================
325 for t in types:
326 let category = t.attr("category")
327 if t.attr("api") == "vulkansc":
328 continue
329 elif t.attr("deprecated") == "true":
330 continue
331 elif category == "include":
332 continue
333 elif category == "define":
334 continue
335 elif t.attr("requires").startsWith("vk_video"):
336 continue
337 elif t.attr("alias") != "":
338 let a = t.attr("alias")
339 let n = t.attr("name")
340 outFile.writeLine &" {n} = {a}"
341 elif category == "bitmask":
342 if t.len > 0 and t[0].text.startsWith("typedef"):
343 outFile.writeLine &" {t[2][0].text} = distinct {t[1][0].text}"
344 elif category == "union":
345 let n = t.attr("name")
346 outFile.writeLine &" {n}* {{.union.}} = object"
347 for member in t.findAll("member"):
348 outFile.writeLine &" {member.memberDecl()}"
349 elif category == "handle":
350 outFile.writeLine &" {t[2][0].text} = distinct pointer"
351 elif category == "struct":
352 let n = t.attr("name")
353 outFile.writeLine &" {n}* = object"
354 for member in t.findAll("member"):
355 if member.attr("api") == "vulkansc":
356 continue
357 outFile.writeLine &" {member.memberDecl()}"
358 elif category == "funcpointer":
359 #[
360 <type category="funcpointer">typedef void* (VKAPI_PTR *<name>PFN_vkAllocationFunction</name>)(
361 <type>void</type>* pUserData,
362 <type>size_t</type> size,
363 <type>size_t</type> alignment,
364 <type>VkSystemAllocationScope</type> allocationScope);
365 </type>
366 PFN_vkAllocationFunction* = proc(
367 pUserData: pointer,
368 size: csize_t,
369 alignment: csize_t,
370 allocationScope: VkSystemAllocationScope,
371 ): pointer {.cdecl.}
372 ]#
373 assert t[0].text.startsWith("typedef ")
374 outFile.writeLine &" {t[1][0].text}* = proc()"
375 else:
376 doAssert category in ["", "basetype", "enum"], "unknown type category: " & category
228 outFile.writeLine "" 377 outFile.writeLine ""
229 378
230 outFile.writeLine """ 379 outFile.writeLine """
231 when defined(linux): 380 when defined(linux):
232 include ../semicongine/rendering/vulkan/platform/xlib 381 include ../semicongine/rendering/vulkan/platform/xlib