Skip to content

Commit

Permalink
Merge branch 'main' into find-goimports
Browse files Browse the repository at this point in the history
  • Loading branch information
bbredesen committed Mar 28, 2023
2 parents 2982f8f + bc31f5f commit 850d4a7
Show file tree
Hide file tree
Showing 27 changed files with 139 additions and 396 deletions.
4 changes: 4 additions & 0 deletions DesignNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

vk.xml schema documentation: [https://registry.khronos.org/vulkan/specs/1.3/registry.html]

This file documents some of the thought process and tasks during development of vk-gen. This file remains for historical
reference, but the codebase has grown beyond what is detailed here and you should not assume that this file describes
precisely how the tool works.

## vk.xml and exceptions.json
There are several significant barriers to generating the Go-binding for Vulkan:

Expand Down
7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
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](https://github.com/bbredesen/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, incluidng beta extensions, or to generate code from a
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
Expand Down Expand Up @@ -40,10 +40,7 @@ issue/PR will clean this up, but they don't hurt anything at the moment.

* `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 neccesarily the largest member. This value must be a string and is copied to an array declaration. It can be
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.

## TODO

* VkDescriptorDataEXT - Pointer members are being recognized as slices, compile error on slice copy.
39 changes: 1 addition & 38 deletions def/array_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ func (t *arrayType) Category() TypeCategory { return CatArray }
func (t *arrayType) Resolve(tr TypeRegistry, vr ValueRegistry) *IncludeSet {

return t.resolvedPointsAtType.Resolve(tr, vr)
// is := includeSet{
// includeTypeNames: ,
// }
}

func (t *arrayType) IsIdenticalPublicAndInternal() bool {
Expand Down Expand Up @@ -62,53 +59,19 @@ func (t *arrayType) PrintVulkanizeContent(forMember *structMember, preamble io.W
fmt.Fprintf(preamble, "copy(rval.%s[:], s.%s)\n", forMember.InternalName(), forMember.PublicName())

structMemberAssignment = ""
} else {
// pre := fmt.Sprintf(sliceTranslationTemplate,
// forMember.InternalName(), t.resolvedPointsAtType.InternalName(), forMember.PublicName(),
// forMember.PublicName(),
// forMember.InternalName(), t.resolvedPointsAtType.TranslateToInternal("v"),
// )
// fmt.Fprint(preamble, pre)
// structMemberAssignment = "&(sl_" + forMember.InternalName() + "[0])"
// }
// } else {
// if t.resolvedPointsAtType.IsIdenticalPublicAndInternal() {
// structMemberAssignment = fmt.Sprintf("(%s)(s.%s)", t.InternalName(), forMember.PublicName())
// } else {
// structMemberAssignment = t.resolvedPointsAtType.TranslateToInternal("s." + forMember.PublicName())
// if t.resolvedPointsAtType.Category() == CatStruct {
// structMemberAssignment = strings.TrimLeft(structMemberAssignment, "*")
// }
// }
}

return
}
func (t *arrayType) PrintGoifyContent(forMember *structMember, preamble, epilogue io.Writer) (structMemberAssignment string) {
structMemberAssignment = "0 /* TODO ARRAY NOT HANDLED */"

// if t.resolvedPointsAtType.IsIdenticalPublicAndInternal() {
// if this is an array to types that are "IsIdentical..." then just
// copy the array as a block and move on
// fmt.Fprintf(epilogue, t.TranslateToPublic("s."+forMember.InternalName()))

if t.resolvedPointsAtType.InternalName() == "byte" {
// fmt.Fprintf(epilogue, "rval.%s = nullTermBytesToString(s.%s[:])\n", forMember.PublicName(), forMember.InternalName())
structMemberAssignment = fmt.Sprintf("nullTermBytesToString(s.%s[:])", forMember.InternalName())
return
}

fmt.Fprintf(epilogue, "copy(rval.%s[:], s.%s[:])\n", forMember.PublicName(), forMember.InternalName())

structMemberAssignment = ""
// } else {
// structMemberAssignment = t.resolvedPointsAtType.TranslateToPublic("s." + forMember.InternalName())
// }
return
}

// const sliceTranslationTemplate string = `
// sl_%s := make([]%s, len(s.%s))
// for i, v := range s.%s {
// sl_%s[i] = %s
// }
// `
8 changes: 0 additions & 8 deletions def/base_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ func (t *baseType) PrintPublicDeclaration(w io.Writer) {
t.PrintDocLink(w)
if t.publicTypeNameOverride != "" {
return
// fmt.Fprintf(w, "type %s %s\n", t.PublicName(), t.publicTypeNameOverride)
} else {
fmt.Fprintf(w, "type %s %s\n", t.PublicName(), t.resolvedUnderlyingType.InternalName())
}
Expand Down Expand Up @@ -129,13 +128,6 @@ func ReadBaseTypeExceptionsFromJSON(exceptions gjson.Result, tr TypeRegistry, vr
entry := NewOrUpdateBaseTypeFromJSON(key.String(), exVal, tr, vr)
tr[key.String()] = entry

// exVal.Get("constants").ForEach(func(ck, cv gjson.Result) bool {
// newVal := NewConstantValue(ck.String(), cv.String(), key.String())

// vr[newVal.RegistryName()] = newVal
// return true
// })

return true
})

Expand Down
145 changes: 50 additions & 95 deletions def/command_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ type commandType struct {

parameters []*commandParam

bindingParams []*commandParam
returnParams []*commandParam
// identicalInternalExternal bool
// isReturnedOnly bool
bindingParams []*commandParam
returnParams []*commandParam
bindingParamCount int
}

// Two exceptions to camelCase rules used for function return params
// Exceptions to camelCase rules used for function return params
func init() {
// rename return params to avoid typenames
strcase.ConfigureAcronym("Result", "r")
Expand Down Expand Up @@ -73,18 +71,12 @@ func (t *commandType) Resolve(tr TypeRegistry, vr ValueRegistry) *IncludeSet {
}
}

// if t.publicName == "" { // publicName may already be set by an entry from exceptions.json
// t.publicName = RenameIdentifier(t.registryName)
// }

for _, p := range t.parameters {
p.parentCommand = t

iset.MergeWith(p.Resolve(tr, vr))
}

// t.identicalInternalExternal = t.determineIdentical()

iset.ResolvedTypes[t.registryName] = t

t.isResolved = true
Expand Down Expand Up @@ -128,19 +120,9 @@ func (t *commandType) PrintPublicDeclaration(w io.Writer) {
fmt.Fprintf(w, "var %s = %s\n\n", t.PublicName(), t.resolvedAliasType.PublicName())
return
}
// funcReturnNames, funcReturnTypes := &strings.Builder{}, &strings.Builder{}

preamble, epilogue, outputTranslation := &strings.Builder{}, &strings.Builder{}, &strings.Builder{}

// var doubleCallArrayParam *commandParam
// var doubleCallArrayTypeName string

// var isDoubleCallCommand bool

// for _, p := range t.bindingParams {
// funcParams = funcParams + ", " + p.publicName + " " + p.resolvedType.PublicName()
// }

funcReturnParams := make([]*commandParam, 0)
var trampolineReturns *commandParam
funcInputParams := make([]*commandParam, 0)
Expand All @@ -154,6 +136,7 @@ func (t *commandType) PrintPublicDeclaration(w io.Writer) {
trampolineReturns = retParam
}

// Iterative dev process:
// Start with a simple output scenario - vkEndCommandBuffer takes a single
// input (ignore for the moment) and returns a VkResult
// Deal with simple inputs, like handles and primitive/scalar types
Expand All @@ -167,20 +150,6 @@ func (t *commandType) PrintPublicDeclaration(w io.Writer) {
// - Go return values
// - Trampoline parameters, with or without translation

// if p.isDoubleCallArray {
// isDoubleCallCommand = true
// // This gets saved for later printing the calls
// doubleCallArrayParam = p

// fmt.Fprintf(funcReturnNames, ", %s", p.publicName)
// retSliceType := p.resolvedType.(*pointerType).resolvedPointsAtType
// fmt.Fprintf(funcReturnTypes, "[]%s", retSliceType.PublicName())
// } else if p.isOutput {
// fmt.Fprintf(funcReturnNames, ", %s", p.publicName)
// fmt.Fprintf(funcReturnTypes, ", %s", p.resolvedType.PublicName())
// } else {
// fmt.Fprintf(funcParams, ", %s %s", p.publicName, p.resolvedType.PublicName())
// }
if p.resolvedType.Category() == CatPointer {
paramTypeAsPointer := p.resolvedType.(*pointerType)

Expand Down Expand Up @@ -230,6 +199,20 @@ func (t *commandType) PrintPublicDeclaration(w io.Writer) {

funcTrampolineParams = append(funcTrampolineParams, p)

} else if p.altLenSpec != "" {
// This is another edge case where the length of the array is embedded in a bitfield. For now, the
// user must provide the bitfield and must ensure that their slice is the appropriate length.
// See vkCmdSetSampleMaskEXT for an example. Addressed as "no action" relative to other slices in
// Resolve(). Fix for issue #17
fmt.Fprintf(preamble, " // %s is an edge case input slice, with an alternative length encoding. Developer must provide the length themselves.\n", p.publicName)
fmt.Fprintf(preamble, " // No handling for internal vs. external types at this time, the only case this appears as of 1.3.240 is a handle type with a bitfield length encoding\n")
fmt.Fprintf(preamble, " var %s *%s\n", p.internalName, p.resolvedType.(*pointerType).resolvedPointsAtType.PublicName())
fmt.Fprintf(preamble, " if %s != nil {\n", p.publicName)
fmt.Fprintf(preamble, " %s = &%s[0]\n", p.internalName, p.publicName)
fmt.Fprintf(preamble, " }\n")

funcTrampolineParams = append(funcTrampolineParams, p)

} else {
// Parameter is a singular input
if p.resolvedType.IsIdenticalPublicAndInternal() {
Expand Down Expand Up @@ -309,7 +292,7 @@ func (t *commandType) PrintPublicDeclaration(w io.Writer) {
t.printTrampolineCall(epilogue, funcTrampolineParams, trampolineReturns)
fmt.Fprintln(epilogue)

// If the output requires tranlation, iterate the slice and translate here
// If the output requires translation, iterate the slice and translate here
fmt.Fprintf(epilogue, outputTranslation.String())

}
Expand Down Expand Up @@ -366,12 +349,10 @@ func (t *commandType) PrintPublicDeclaration(w io.Writer) {
stringParts := strings.Split(p.lenSpec, "->")
translatedLenMember := stringParts[0] + "." + stringParts[1]

// fmt.Fprintf(preamble, " sl_%s := make([]%s, %s)\n", p.internalName, p.resolvedType.InternalName(), translatedLenMember)
// fmt.Fprintf(preamble, " %s := &sl_%s[0]\n", p.internalName, p.internalName)
fmt.Fprintf(preamble, " %s = make(%s, %s)\n", p.publicName, p.resolvedType.PublicName(), translatedLenMember)
fmt.Fprintf(preamble, " %s := &%s[0]\n", p.internalName, p.publicName)

// At a practical level, this is only used to return an array of handles, we can avoid tranlation altogether; see
// At a practical level, this is only used to return an array of handles, we can avoid translation altogether; see
// AllocateCommandBuffers for an example. It is possible that a future API release will need
// updates here.

Expand All @@ -397,19 +378,22 @@ func (t *commandType) PrintPublicDeclaration(w io.Writer) {
} else {
fmt.Fprintf(preamble, "// %s is a binding-allocated single return value and will be populated by Vulkan, but requiring translation\n", p.publicName)
if p.resolvedType.Category() == CatPointer {
fmt.Fprintf(preamble, "var %s %s\n", p.internalName, p.resolvedType.(*pointerType).resolvedPointsAtType.InternalName())
fmt.Fprintf(preamble, "ptr_%s := &%s\n", p.internalName, p.internalName)

fmt.Fprintf(epilogue, " %s = %s\n", p.publicName, p.resolvedType.(*pointerType).resolvedPointsAtType.TranslateToPublic(p.internalName))
underlyingType := p.resolvedType.(*pointerType).resolvedPointsAtType
if underlyingType.Category() == CatStruct || underlyingType.Category() == CatUnion {
// Pointer type will end up calling Vulkanize()
fmt.Fprintf(preamble, "var %s %s = %s\n", p.internalName, p.resolvedType.InternalName(), p.resolvedType.TranslateToInternal(p.publicName))

fmt.Fprintf(epilogue, " %s = %s\n", p.publicName, p.resolvedType.(*pointerType).resolvedPointsAtType.TranslateToPublic(p.internalName))
} else {
fmt.Fprintf(preamble, "var internal_%s %s = %s\n", p.publicName, underlyingType.InternalName(), underlyingType.TranslateToInternal(p.publicName))
fmt.Fprintf(preamble, "var %s = &internal_%s\n", p.internalName, p.publicName)
fmt.Fprintf(epilogue, " %s = %s\n", p.publicName, underlyingType.TranslateToPublic("internal_"+p.publicName))
}
} else {
fmt.Fprintf(preamble, "var %s %s\n", p.internalName, p.resolvedType.InternalName())
fmt.Fprintf(preamble, "ptr_%s := &%s\n", p.internalName, p.internalName)

fmt.Fprintf(epilogue, " %s = *%s\n", p.publicName, p.resolvedType.TranslateToPublic(p.internalName))
// Vulkan *must* be accepting a pointer, if it is planning to fill in any kind of data
panic("found non-pointer return value from vulkan!")
}

p.internalName = "ptr_" + p.internalName // Done after the fact so the internal pointer will be used in the tramp params

fmt.Fprintln(preamble)

}
Expand Down Expand Up @@ -520,47 +504,8 @@ func (t *commandType) printTrampolineCall(w io.Writer, trampParams []*commandPar
}
}

func (t *commandType) PrintInternalDeclaration(w io.Writer) {

// var preamble, structDecl, epilogue strings.Builder

// if t.identicalInternalExternal {
// fmt.Fprintf(w, "type %s = %s\n", t.InternalName(), t.PublicName())
// } else {
// if t.isReturnedOnly {
// fmt.Fprintf(w, "// WARNING - This struct is returned only, which is not yet handled in the binding\n")
// }
// // _vk type declaration
// fmt.Fprintf(w, "type %s struct {\n", t.InternalName())
// for _, m := range t.members {
// m.PrintInternalDeclaration(w)
// }

// fmt.Fprintf(w, "}\n")
// }

// // Vulkanize declaration
// // Set required values, like the stype
// // Expand slices to pointer and length parameters
// // Convert strings, and string arrays
// fmt.Fprintf(&preamble, "func (s *%s) Vulkanize() *%s {\n", t.PublicName(), t.InternalName())

// if t.identicalInternalExternal {
// fmt.Fprintf(&structDecl, " rval := %s(*s)\n", t.InternalName())
// } else {
// fmt.Fprintf(&structDecl, " rval := %s{\n", t.InternalName())
// for _, m := range t.members {
// m.PrintVulcDeclarationAsssignment(&preamble, &structDecl, &epilogue)
// }
// fmt.Fprintf(&structDecl, " }\n")
// }
// fmt.Fprintf(&epilogue, " return &rval\n")
// fmt.Fprintf(&epilogue, "}\n")

// fmt.Fprint(w, preamble.String(), structDecl.String(), epilogue.String())

// Goify declaration (if applicable?)
}
// There is no internal declaration for commands, this function is empty
func (t *commandType) PrintInternalDeclaration(w io.Writer) {}

type commandParam struct {
registryName string
Expand All @@ -573,8 +518,8 @@ type commandParam struct {
optionalParamString string
isAlwaysOptional bool

pointerLevel int
lenSpec string
pointerLevel int
lenSpec, altLenSpec string

parentCommand *commandType
isResolved bool
Expand Down Expand Up @@ -607,7 +552,17 @@ func (p *commandParam) Resolve(tr TypeRegistry, vr ValueRegistry) *IncludeSet {
}

// check for length specification
if p.lenSpec != "" {
if p.altLenSpec != "" {
// If altlen is present, then the array is a fixed length per the spec.
// as of 1.3.240, only vkCmdSetSampleMaskEXT has an altlen parameter, where the expected array length is
// embedded in a sample mask bitfield.
//
// Fix for issue #17 is to recognize this parameter as a slice, but we won't try to calculate the bitfield.
// (i.e., the developer needs to just pass a SampleMaskBits value that matches the slice)
//
// Net effect is to do noting here in Resolve.

} else if p.lenSpec != "" {
for _, otherP := range p.parentCommand.parameters {
if otherP.registryName == p.lenSpec {
otherP.isLenMemberFor = append(otherP.isLenMemberFor, p)
Expand All @@ -631,7 +586,6 @@ func (p *commandParam) Resolve(tr TypeRegistry, vr ValueRegistry) *IncludeSet {
if p.isConstParam {
if p.lenSpec == "" {
p.isInput = true
// p.requiresTranslation = !p.resolvedType.IsIdenticalPublicAndInternal()

} else if p.lenMemberParam != nil {
// if this param is a const pointer with a len specifier that maps to
Expand Down Expand Up @@ -728,6 +682,7 @@ func NewCommandParamFromXML(elt *xmlquery.Node, forCommand *commandType) *comman
rval.isConstParam = strings.HasPrefix(elt.InnerText(), "const")
rval.pointerLevel = strings.Count(elt.InnerText(), "*")
rval.lenSpec = elt.SelectAttr("len")
rval.altLenSpec = elt.SelectAttr("altlen")

rval.parentCommand = forCommand

Expand All @@ -736,7 +691,7 @@ func NewCommandParamFromXML(elt *xmlquery.Node, forCommand *commandType) *comman

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

Expand Down
Loading

0 comments on commit 850d4a7

Please sign in to comment.