Git Product home page Git Product logo

vk-gen's Introduction

vk-gen

vk-gen is a tool used to create Go bindings for the Vulkan graphics API. It uses the Vulkan XML specification to generate all type definitions and native function calls for the API. It generates the code for go-vk, but it can just as well be used to create a modified binding set in your own projects (for example, excluding certain vendor extensions, including beta extensions, or to generate code from a specific version of the Vulkan headers).

Basic Usage

You do not need to install this tool to use go-vk in a project. Install if you need to generate for a specific version of the API or want to produce a binding using only a subset of Vulkan.

Install: go install github.com/bbredesen/vk-gen@latest

Download the latest registry file: curl https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/registry/vk.xml > vk.xml

(Or, replace "main" in the URL above with the tagged version you want to generate against: e.g., https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/v1.2.203/registry/vk.xml for the last version 1.2 specification.)

Run the tool: vk-gen

Use -inFile to specify a registry filename or path (defaults to ./vk.xml)

Use -outDir to specify the destination folder for writing go-vk files (defaults to ./vk/)

The static_include folder in this repository contains static template files that are copied directly into the output folder. These files are directly copied to the output, but are not evaluated or compiled into this tool. If using the Go language server, you can set -static_include in your directoryFilters setting. See (https://github.com/golang/tools/blob/master/gopls/doc/settings.md) for details.

exceptions.json

There are a number of datatypes and values in vk.xml which need special handling, frequently because the spec uses C data type formats or types that don't translate 1-to-1 to Go's type system. While we could probably work around many of them by parsing the C code in the XML file, it is much simpler to set these exceptions in a separate file with a standard format.

NOTE: There are a number of "legacy" entries in this file left over from development, but which are now unused. A future issue/PR will clean this up, but they don't hurt anything at the moment.

union

  • go:internalSize - Go has no notion of union types. This field allows you to specify a size for the public to internal translation result. By default, vk-gen will use the size of the first member in the union, but that is not necessarily the largest member. This value must be a string and is copied to an array declaration. It can be anything that resolves to a constant in Go, though most typically it will be an integer value (represented as a string). The value should be the aligned (?) data size in bytes of the largest member of the union.

vk-gen's People

Contributors

asmaloney avatar bbredesen avatar dependabot[bot] avatar minegame159 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

vk-gen's Issues

Many extension constants are written to external.go

The intent of exten.go is to group the constant name and spec version strings for all extensions. Some values are written to exten.go, but the majority are written into external.go. This bug does not appear to be present in platform specific extensions (i.e. exten_win32.go has all of the win32 extension values), but that could be a sampling error d/t the relatively small number of platform extensions.

Some extensions are even split between the two files, i.e. spec version is in exten.go and extension name is in external.go.

The quantity and specific set of extensions that are written in one or another file is different on each run of vk-gen, even with the same input file.

Sort extension constants in output

Extension names and spec versions are coming out in an undefined order, which causes them to be listed in that order on pkg.go.dev. Sort the constants after they come out of the map, so that related extension name and spec versions are next to each other in the output. This is already being done for enumerated values, command names, etc.

Current output:

QCOM_IMAGE_PROCESSING_SPEC_VERSION                       = 1
EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_SPEC_VERSION         = 2
EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME               = "VK_EXT_display_surface_counter"
NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION                = 3
KHR_RAY_QUERY_SPEC_VERSION                               = 1
EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME             = "VK_EXT_graphics_pipeline_library"
// ...

Desired output:

EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME               = "VK_EXT_display_surface_counter"
EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION                 = 1
// etc...

GetPipelinePropertiesEXT generates with compiler error under Vk 1.3

GetPipelinePropertiesEXT includes a VkBaseOutStructure pointer as a parameter...only place in the API that does this. That struct is currently marked as an exception with "!ignore", to stop a recursive loop in Resolve().

The quick manual fix to be able to compile is replacing the parameter type with "!ignore" with "struct{}" after generation, but that will definitely cause a crash or undefined behavior if this function is called.

It is not totally clear from the spec how this is meant to work, but I suspect that this is a level of indirection where the base out struct's pNext pointer is written, and the developer has to check stype on the next struct to consume the data.

Fix TBD.

!ignore appearing in generated code

I haven't dug into this too deeply, but when I generate on macOS I get the following:

ERRO[0001] Failed to format source file  error="exit status 2" goimports output="vk/command.go:6252:107: missing ',' in parameter list\n" path=vk/command.go

It looks like !ignore is supposed to strip some things, but maybe can't do it on a return type?

func GetPipelinePropertiesEXT(device Device, pipelineInfo *PipelineInfoEXT) (r Result, pipelineProperties !ignore) {

(Aside: does "!ignore" mean "don't ignore this" or "ignore this"? I've read the doc on it, but it's unclear if "!" is "not" or just a lexeme to differentiate it from a regular string.)

Old comments/code cleanup

In main and def packages, there is a lot of old code commented out, left over from initial development. Most of this can be removed to clean up the code base. Leave doc comments in place unless they are clearly tied to the code being removed.

Duplicate struct members when generating on darwin

Trying to run the generation on macos now, having a few issues. Im using vk.xml version 1.3.242

  • struct.go line ~7950, duplicated code:
	var psl_pStages *_vkPipelineShaderStageCreateInfo
	if len(s.PStages) > 0 {
		sl_pStages := make([]_vkPipelineShaderStageCreateInfo, len(s.PStages))
		for i, v := range s.PStages {
			sl_pStages[i] = *(v.Vulkanize())
		}
		psl_pStages = &sl_pStages[0]
	}

related struct member pStages is also duplicated.

  • struct.go line ~20877, PipelineCacheCreateInfo has duplicate member InitialDataSize.

  • struct.go line ~22138, PipelineShaderStageCreateInfo has duplicate member PName

Platform specific constants accessed in enum_string_N.go causes compilation errors

Hey!

First of all, exciting to see a new VK wrapper for Go! Im interested in evaluating it for my https://github.com/johanhenriksson/goworld project, and willing to contribute if it works out well :) I'd like to depend on a library that I could keep up to date myself if required.

I noticed there's been little testing on OSX, and indeed it does not seem to work at the moment. Tried to run one of the samples quickly, and im running in to these compilation errrors (excluded a bunch more similar ones):

# github.com/bbredesen/go-vk
../../../go/pkg/mod/github.com/bbredesen/[email protected]/enum_win32_string_0.go:21:9: undefined: FullScreenExclusiveEXT
../../../go/pkg/mod/github.com/bbredesen/[email protected]/enum_string_5.go:496:8: undefined: ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT
../../../go/pkg/mod/github.com/bbredesen/[email protected]/enum_string_6.go:975:8: undefined: STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR
../../../go/pkg/mod/github.com/bbredesen/[email protected]/enum_string_6.go:976:8: undefined: STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR

Most of them have _WIN32 or _NV in their names, so I assume they are just platform specific constants not available on my platform. Perhaps they need to be moved into conditionally compiled files?

I haven't had a chance to look at the code generator yet, is there any support for keeping certain defines/code in platform specific go files?

Go-like handling of Result as an error

To be more like conventional Go, need to look at wrapping Result with an error, and returning nil on vk.SUCCESS (or simply define vk.SUCCESS as nil). One requirement is the to directly compare a result code to the error, which probably means pre-declaring all result codes as errors, rather than instantiating them at the point the error is returned from Vulkan.

i.e., the developer must be able to do something like this:

instance, err := vk.CreateInstance(...)
// Type of err is vk.Result, which implements error
if err != nil {
  switch err {
  case vk.OUT_OF_HOST_MEMORY:
    // ...
  }
}

See this comment thread: https://www.reddit.com/r/golang/comments/11jzhhx/announcing_govk_a_go_binding_for_the_vulkan/jb72s0m/?context=10000

Crash when union in exceptions.json not previously defined

Found when running against 1.2.177, exceptions.json has a union type defined (VkAccelerationStructureMotionInstanceDataNV), which does not exist in that version of vk.xml.

Crash is here

func ReadUnionExceptionsFromJSON(exceptions gjson.Result, tr TypeRegistry, vr ValueRegistry) {
	exceptions.Get("union").ForEach(func(key, exVal gjson.Result) bool {
		if key.String() == "!comment" {
			return true
		} // Ignore comments

		UpdateUnionTypeFromJSON(key, exVal, tr[key.String()].(*unionType)) // <-- Crash here
                 // This type coercion fail because the map lookup returns nil

		return true
	})
}

Mark "code generated by" with tagged release or commit number

For tracking what version of vk-gen was used to generate go-vk, the "Generated code" comment at the top of each file should be marked with a commit number. Figuring out how that will be identified is TBD, may require a shell script to get the info from git. Also need to identify, if possible, what spec version vk.xml is.

Also, clean up the timestamp to remove monotonic clock marker, fractional seconds. Use time.Round(0) or convert to UTC.

Current header:
// Code generated by go-vk from vk.xml at 2023-03-06 11:50:15.7116574 -0600 CST m=+1.971386201. DO NOT EDIT.

Desired format:
// Code generated from $file ver $vkVersion at $shortTimestamp using $executableOrRepository $version. DO NOT EDIT.
i.e.:
// Code generated from vk.xml ver 1.3.240 at 2023-03-06 11:50:15 -0600 CST using vk-gen v1.2.7 DO NOT EDIT.

Add support for video encoding

XML file for externally defined video encoding types in similar format to vk.xml is available at https://github.com/KhronosGroup/Vulkan-Docs/blob/main/xml/video.xml

Types for video components are currently placeholders in exceptions.json. The linked XML file above has enums, structs etc. for the video components. On first review, it appears that several include types patterned like "vk_video/vulkan_video_codec*.h" will be needed in exceptions.json

Several structs are actually encoded bitfields that will need to be handled. See StdVideoH264PpsFlags for an example.

CmdSetSampleMaskEXT is not passing address of sampleMask[0] to trampoline

Signature: func CmdSetSampleMaskEXT(commandBuffer CommandBuffer, samples SampleCountFlagBits, sampleMask []SampleMask)

sampleMask is correctly defined as a slice. This function is unusual because the size of the slice is encoded in a bitfield, rather than directly provided.

The pointer being provided to the trampoline is a direct assignment of the slice, rather than the address first element.

Currently generated code:

	var pSampleMask *SampleMask
	if sampleMask != nil {
		pSampleMask = sampleMask
	}

Expected output:

	var pSampleMask *SampleMask
	if sampleMask != nil {
		pSampleMask = &sampleMask[0]
	}

Unable to use vulkan extensions

go-vk or vk-gen is current unable to use extensions of vulkan because the need to be loaded with vkGetInstanceProcAddr which is currently not supported for loading

MacOS support progress/discussion

So I managed to get a bit further on MacOS support tonight.

  • Modified sample 01 to use GLFW for cross-platform window management
  • Successfully created a VkSurfaceKHR handle from the GLFW window

To get it working I had to change the default library name from libMoltenVK.dylib to the standard libvulkan.1.dylib. I havent looked into it, but i seem to recall that being correct for newer versions of MVK.

I'm currently stuck at a crash in vk.GetPhysicalDeviceSurfaceSupportKHR, with the output

libc++abi: terminating with uncaught exception of type std::__1::system_error: mutex lock failed: Invalid argument
SIGABRT: abort

I'm not sure what's causing it, but I'm a little bit suspicious towards the use of dlsym for loading function pointers. As far as I can tell the recommended way is to use vkGetInstanceProcAdd and vkGetDeviceProcAddr, and other platform-specific methods are not supported except as a way to locate those two methods.

Exceptions needed for new Metal types in 1.3.242

The following types need exceptions as basetypes. These are causing a crash when running against 1.3.242 and later. They are defined in the xml as objc id types, or as void* if OBJC is not defined by the compiler.

<type name="MTLDevice_id"/>
<type name="MTLCommandQueue_id"/>
<type name="MTLBuffer_id"/>
<type name="MTLTexture_id"/>
<type name="MTLSharedEvent_id"/>
<type name="IOSurfaceRef"/>

Binding allocated return vals need to be Vulkanized before trampoline

Error found with GetPhysicalDeviceFeatures2, bug presumably affects any command that requires a structure to be populated by Vulkan.

Current code:

var pFeatures _vkPhysicalDeviceFeatures2
ptr_pFeatures := &pFeatures

execTrampoline(keyvkGetPhysicalDeviceFeatures2, uintptr(physicalDevice), uintptr(unsafe.Pointer(ptr_pFeatures)))

features = *(pFeatures.Goify())

In the example above, Vulkan will silently fail and not modify the struct because pFeatures does not have sType set. (Not sure why it isn't caught by validation layers, but that isn't the issue here.)

Need to modify vk-gen output to allocate that struct and call Vulkanize() before the trampoline call, something like:

pFeatures := (&PhysicalDeviceFeatures2{}).Vulkanize()

execTrampoline(keyvkGetPhysicalDeviceFeatures2, uintptr(physicalDevice), uintptr(unsafe.Pointer(pFeatures)))

features = *(pFeatures.Goify())
return

"~0U" appearing in generated code

When I generate on macOS (for macos) I get the following:

ERRO[0001] Failed to format source file   error="exit status 2" goimports output="vk/external.go:10:37: expected ')', found U\nvk/external.go:11:1: expected declaration, found FALSE\n" path=vk/external.go

Generated:

const (
REMAINING_3D_SLICES_EXT uint32 = (~0U)
FALSE uint32 = 0
TRUE uint32 = 1
...

Remove lazyCommands map, directly declare all commands

lazyCommands is a map that is populated at runtime through init(). Commands will never be added to the map or changed at runtime though...they are generated from vk.xml and are set in stone at compile time.

Eliminate the lazy commands map and declare each vkCommand individually in a var( ... ) block. Commands will still be lazy-evaluated when first called. I would expect there to be some startup performance improvement, but it is worth benchmarking both models before committing this change.

"!" in exceptions.json syntax is confusing

(From short discussion in this issue.)

When reading the exceptions.json file, I was reading "!ignore" as "not ignore" which really didn't make sense ๐Ÿ˜„ Even reading the docs on it didn't really clarify it for me.

I would suggest changing the way these are marked up to avoid this confusion.

Thinking out loud (and not having a picture of where you want to take this), I wonder if having a "traits" or "flags" or "attributes" field that allows for multiple boolean things would make sense? Something like:

"traits": "trait1, trait2, ignore"

Maybe then "!" can actually become "not":

"traits": "comment, ignore"

vs.

"traits": "!comment, ignore"

This would allow for future expansion of this kind of thing without adding new fields for each.

Union DescriptorDataEXT treating singular pointer as slice

DescriptorDataEXT is being incorrectly generated by expecting a slice of pointers in the As functions, instead of a single pointer:

type DescriptorDataEXT struct {
	PSampler                *Sampler
	// other members
}

func (u *DescriptorDataEXT) AsPSampler(vals []*Sampler) {
	copy(u.PSampler[:], vals) // Compile error on this line, PSampler is not a slice
	u.asPSampler = true
	// other asMembers = false
}

Logic in func (t *unionType) PrintPublicDeclaration(w io.Writer) is assuming that if the registry member is a pointer, and not resolving to unsafe.Pointer, then it must be a slice, which is not correct.

Identified in vk.xml 1.3.240

"No platform type for !comment" warning at runtime

Very minor issue at runtime:

WARN[0001] no existing registry entry for platform type in exceptions.json registry type="!comment"

newOrUpdatePlatformTypeFromJSON needs to ignore the "!comment" key. Validate at the same time that no other registry or definer type has the same issue (meaning they should all ignore "!comment"s).

Doesn't work anymore

INFO[0000] no existing registry entry for external type  registry type=PFN_vkGetInstanceProcAddrLUNARG
INFO[0001] Running goimports                             file=struct.go
ERRO[0001] Failed to format source file                  error="exit status 2" goimports output="../../vk/struct.go:35180:15: expected operand, found ')'\n../../vk/struct.go:35182:3: expected ')', found 'return'\n../../vk/struct.go:35185:3: missing ',' in composite literal\n../../vk/struct.go:35186:8: missing ',' in composite literal\n../../vk/struct.go:35189:15: expected operand, found ')'\n../../vk/struct.go:35191:3: expected ')', found 'return'\n../../vk/struct.go:35194:1: missing ',' in composite literal\n../../vk/struct.go:35196:7: missing ',' in composite literal\n../../vk/struct.go:35200:1: missing ',' in composite literal\n../../vk/struct.go:35201:7: missing ',' in composite literal\n../../vk/struct.go:35210:3: missing ',' in composite literal\n" path=../../vk/struct.go
panic: runtime error: index out of range [1] with length 1

It seems to be generating invalid code here

...
MaxLevel : ()(s.maxLevel),
...

"Code generated by go-vk from vk.xml" showing on pkg.go.dev

The "Code generated by go-vk from vk.xml..." header is showing up (repeatedly) on pkg.go.dev, at the start of the Overview section of the documentation. I think the fix is very simple: add a blank line between that header and the package declaration.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.