comparison svk/generate.nim @ 1486:0ba3f0b2be2e default tip main

did: more
author sam <sam@basx.dev>
date Sat, 03 May 2025 20:16:04 +0700
parents 6e062a84c157
children
comparison
equal deleted inserted replaced
1485:6e062a84c157 1486:0ba3f0b2be2e
211 for f in features: 211 for f in features:
212 for extendenum in f.findAll("enum"): 212 for extendenum in f.findAll("enum"):
213 if extendenum.attr("extends") != "": 213 if extendenum.attr("extends") != "":
214 enums[extendenum.attr("extends")].addValue(extendenum) 214 enums[extendenum.attr("extends")].addValue(extendenum)
215 215
216 var extensionLoaders: seq[(string, seq[string])]
217
216 for extension in extensions.findAll("extension"): 218 for extension in extensions.findAll("extension"):
217 let extNum = extension.attr("number") 219 let extNum = extension.attr("number")
220 extensionLoaders.add (extension.attr("name"), newSeq[string]())
221 for c in extension.findAll("command"):
222 if "Video" notin c.attr("name"):
223 extensionLoaders[^1][1].add c.attr("name")
224
218 for extendenum in extension.findAll("enum"): 225 for extendenum in extension.findAll("enum"):
219 if extendenum.attr("extends") != "": 226 if extendenum.attr("extends") != "":
220 if extendenum.attr("extnumber") == "": 227 if extendenum.attr("extnumber") == "":
221 extendenum.attrs["extnumber"] = extNum 228 extendenum.attrs["extnumber"] = extNum
222 enums[extendenum.attr("extends")].addValue(extendenum) 229 enums[extendenum.attr("extends")].addValue(extendenum)
227 # generate core types =============================================================================== 234 # generate core types ===============================================================================
228 # preamble, much easier to hardcode than to generate from xml 235 # preamble, much easier to hardcode than to generate from xml
229 outFile.writeLine """ 236 outFile.writeLine """
230 237
231 import std/dynlib 238 import std/dynlib
239 import std/strutils
240 import std/tables
232 241
233 import ../semicongine/thirdparty/winim/winim/inc/winbase 242 import ../semicongine/thirdparty/winim/winim/inc/winbase
234 import ../semicongine/thirdparty/winim/winim/inc/windef 243 import ../semicongine/thirdparty/winim/winim/inc/windef
235 import ../semicongine/thirdparty/x11/xlib 244 import ../semicongine/thirdparty/x11/xlib
236 import ../semicongine/thirdparty/x11/x 245 import ../semicongine/thirdparty/x11/x
309 value = value[0 ..^ 2] & "'u32" 318 value = value[0 ..^ 2] & "'u32"
310 elif value.endsWith("ULL"): 319 elif value.endsWith("ULL"):
311 value = value[0 ..^ 4] & "'u64" 320 value = value[0 ..^ 4] & "'u64"
312 if value[0] == '~': 321 if value[0] == '~':
313 value = "not " & value[1 ..^ 1] 322 value = "not " & value[1 ..^ 1]
314 outFile.writeLine &" {c.name}*: {c.datatype} = {value}" 323 if c.name in ["VK_TRUE", "VK_FALSE"]:
324 outFile.writeLine &" {c.name}*: VkBool32 = VkBool32({value})"
325 else:
326 outFile.writeLine &" {c.name}*: {c.datatype} = {value}"
315 outFile.writeLine "" 327 outFile.writeLine ""
316 328
317 # generate enums =============================================================================== 329 # generate enums ===============================================================================
318 const nameCollisions = [ 330 const nameCollisions = [
319 "VK_PIPELINE_CACHE_HEADER_VERSION_ONE", 331 "VK_PIPELINE_CACHE_HEADER_VERSION_ONE",
333 outFile.writeLine &" {ee.name} = {ee.value}" 345 outFile.writeLine &" {ee.name} = {ee.value}"
334 346
335 outFile.writeLine "" 347 outFile.writeLine ""
336 348
337 # generate types =============================================================================== 349 # generate types ===============================================================================
350 var stringConverters: seq[string]
338 for t in types: 351 for t in types:
339 let category = t.attr("category") 352 let category = t.attr("category")
340 let tName = t.attr("name") 353 let tName = t.attr("name")
341 if tName.startsWith("VkVideo"): # we are not doing the video API, sorry 354 if tName.startsWith("VkVideo"): # we are not doing the video API, sorry
342 continue 355 continue
355 elif t.attr("alias") != "": 368 elif t.attr("alias") != "":
356 let a = t.attr("alias") 369 let a = t.attr("alias")
357 outFile.writeLine &" {tName}* = {a}" 370 outFile.writeLine &" {tName}* = {a}"
358 elif category == "bitmask": 371 elif category == "bitmask":
359 if t.len > 0 and t[0].text.startsWith("typedef"): 372 if t.len > 0 and t[0].text.startsWith("typedef"):
360 outFile.writeLine &" {t[2][0].text}* = distinct {t[1][0].text}" 373 outFile.writeLine &" {t[2][0].text.strip()}* = distinct {t[1][0].text.strip()}"
361 elif category == "union": 374 elif category == "union":
362 outFile.writeLine &" {tName}* {{.union.}} = object" 375 outFile.writeLine &" {tName}* {{.union.}} = object"
363 for member in t.findAll("member"): 376 for member in t.findAll("member"):
364 outFile.writeLine &" {member.memberDecl()}" 377 outFile.writeLine &" {member.memberDecl()}"
365 elif category == "handle": 378 elif category == "handle":
366 outFile.writeLine &" {t[2][0].text} = distinct pointer" 379 outFile.writeLine &" {t[2][0].text.strip()} = distinct pointer"
380 stringConverters.add t[2][0].text.strip()
367 elif category == "struct": 381 elif category == "struct":
368 outFile.writeLine &" {tName}* = object" 382 outFile.writeLine &" {tName}* = object"
369 for member in t.findAll("member"): 383 for member in t.findAll("member"):
370 if member.attr("api") == "vulkansc": 384 if member.attr("api") == "vulkansc":
371 continue 385 continue
449 assert "*" notin retType 463 assert "*" notin retType
450 outFile.write &": {doTypename(retType, 0)}" 464 outFile.write &": {doTypename(retType, 0)}"
451 outFile.write " {.stdcall.}\n" 465 outFile.write " {.stdcall.}\n"
452 466
453 outFile.write """ 467 outFile.write """
454 when defined(linux):
455 let vulkanLib = loadLib("libvulkan.so.1")
456 when defined(windows):
457 let vulkanLib = loadLib("vulkan-1.dll")
458 if vulkanLib == nil:
459 raise newException(Exception, "Unable to load vulkan library")
460
461 vkGetInstanceProcAddr = cast[proc(instance: VkInstance, pName: cstring, ): PFN_vkVoidFunction {.stdcall.}](checkedSymAddr(vulkanLib, "vkGetInstanceProcAddr"))
462 468
463 proc loadFunc[T](instance: VkInstance, f: var T, name: string) = 469 proc loadFunc[T](instance: VkInstance, f: var T, name: string) =
464 f = cast[T](vkGetInstanceProcAddr(instance, name)) 470 f = cast[T](vkGetInstanceProcAddr(instance, name))
471
472 proc initVulkanLoader*() =
473 if vkGetInstanceProcAddr != nil:
474 return
475
476 when defined(linux):
477 let vulkanLib = loadLib("libvulkan.so.1")
478 when defined(windows):
479 let vulkanLib = loadLib("vulkan-1.dll")
480 if vulkanLib == nil:
481 raise newException(Exception, "Unable to load vulkan library")
482
483 # init two global functions
484 vkGetInstanceProcAddr = cast[proc(instance: VkInstance, pName: cstring, ): PFN_vkVoidFunction {.stdcall.}](checkedSymAddr(vulkanLib, "vkGetInstanceProcAddr"))
485
486 loadFunc(VkInstance(nil), vkCreateInstance, "vkCreateInstance")
465 487
466 """ 488 """
467 489
468 for f in features: 490 for f in features:
469 let name = f.attr("name").replace(",", "_") 491 let name = f.attr("name").replace(",", "_")
470 if f.attr("struct") != "": 492 if f.attr("struct") != "":
471 continue 493 continue
472 outFile.writeLine &"proc loadFeature_{name}(instance: VkInstance) =" 494 outFile.writeLine &"proc load_{name}(instance: VkInstance) ="
473 var hasEntries = false 495 var hasEntries = false
474 for cmd in f.findAll("command"): 496 for cmd in f.findAll("command"):
497 if cmd.attr("name") == "vkCreateInstance":
498 continue
475 hasEntries = true 499 hasEntries = true
476 let cName = cmd.attr("name") 500 let cName = cmd.attr("name")
477 outFile.writeLine &" loadFunc(instance, {cName}, \"{cName}\")" 501 outFile.writeLine &" loadFunc(instance, {cName}, \"{cName}\")"
478 if not hasEntries: 502 if not hasEntries:
479 outFile.writeLine " discard" 503 outFile.writeLine " discard"
480 outFile.writeLine "" 504 outFile.writeLine ""
481 505
506 for (extName, commands) in extensionLoaders:
507 outFile.writeLine &"proc load_{extName}(instance: VkInstance) ="
508 for c in commands:
509 outFile.writeLine &" loadFunc(instance, {c}, \"{c}\")"
510 if commands.len == 0:
511 outFile.writeLine &" discard"
512 outFile.writeLine ""
513
514 outFile.writeLine "const EXTENSION_LOADERS = {"
515 for (extName, commands) in extensionLoaders:
516 outFile.writeLine &" \"{extName}\": load_{extName},"
517 outFile.writeLine "}.toTable"
518 outFile.writeLine ""
519
520 outFile.writeLine "proc loadExtension*(instance: VkInstance, name: string) ="
521 outFile.writeLine " assert name in EXTENSION_LOADERS"
522 outFile.writeLine " EXTENSION_LOADERS[name](instance)"
523 outFile.writeLine ""
524
525 for strCon in stringConverters:
526 outFile.writeLine &"""proc `$`*(v: {strCon}): string = "0x" & cast[uint](v).toHex()"""
527 outFile.writeLine ""
528
529 # we preload the vkCreateInstance function, so we can create an instance
530 outFile.writeLine ""
531
482 outFile.close() 532 outFile.close()
483 533
484 assert execCmd("nim c " & outPath) == 0 534 assert execCmd("nim c " & outPath) == 0