//
// Copyright (C) 2024 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package vulkan_xml
import (
"berberis/cpp_types"
"berberis/vulkan_types"
"encoding/xml"
"errors"
"fmt"
"regexp"
"sort"
"strconv"
"strings"
)
// Vulkan XML includes one platform entity which has many sub entities.
// We need XMLName for root elements, but validity of all other entities
// is guaranteed because of XML attributes.
type registry struct {
XMLName xml.Name `xml:"registry"`
Platforms []platformInfo `xml:"platforms>platform"`
Tags []tagInfo `xml:"tags>tag"`
Types []typeInfo `xml:"types>type"`
Enums []enumInfo `xml:"enums"`
Commands []commandInfo `xml:"commands>command"`
Extensions []struct {
Name string `xml:"name,attr"`
ID int64 `xml:"number,attr"`
Requires []struct {
EnumFields []enumFieldInfo `xml:"enum"`
} `xml:"require"`
} `xml:"extensions>extension"`
Features []struct {
EnumFields []enumFieldInfo `xml:"enum"`
} `xml:"feature>require"`
Comments string `xml:"comment"`
}
type platformInfo struct {
Name string `xml:"name,attr"`
Comment string `xml:"comment,attr"`
}
type tagInfo struct {
Name string `xml:"name,attr"`
Author string `xml:"author,attr"`
Contact string `xml:"contact,attr"`
Comment string `xml:"comment,attr"`
}
type typeInfo struct {
Name string `xml:"name,attr"`
Category string `xml:"category,attr"`
Requires string `xml:"requires,attr"`
Alias string `xml:"alias,attr"`
Members []structuralMemberInfo `xml:"member"`
StructExtends string `xml:"structextends,attr"`
RawXML string `xml:",innerxml"`
Comment string `xml:"comment,attr"`
Api string `xml:"api,attr"`
}
type enumInfo struct {
Name string `xml:"name,attr"`
EnumFields []enumFieldInfo `xml:"enum"`
}
type enumFieldInfo struct {
Name string `xml:"name,attr"`
Alias string `xml:"alias,attr"`
Value string `xml:"value,attr"`
BitPos string `xml:"bitpos,attr"`
Dir string `xml:"dir,attr"`
Extends string `xml:"extends,attr"`
ExtID int64 `xml:"extnumber,attr"`
Offset int64 `xml:"offset,attr"`
}
type commandInfo struct {
Name string `xml:"name,attr"`
Alias string `xml:"alias,attr"`
Proto struct {
Type string `xml:"type,attr"`
RawXML string `xml:",innerxml"`
Comment string `xml:"comment,attr"`
} `xml:"proto"`
Params []structuralMemberInfo `xml:"param"`
RawXML string `xml:",innerxml"`
}
type structuralMemberInfo struct {
Name string `xml:"name,attr"`
Type string `xml:"type,attr"`
Value string `xml:"values,attr"`
Length string `xml:"len,attr"`
AltLength string `xml:"altlen,attr"`
Validstructs string `xml:"validstructs,attr"`
RawXML string `xml:",innerxml"`
Comment string `xml:"comment,attr"`
Api string `xml:"api,attr"`
}
type ExtendedStructInfo interface {
ExtendedWith() []cpp_types.Type
OptionalStruct() bool
OptionalValue() string
}
func ExtendedStruct(base_struct cpp_types.Type, optional_struct bool, optional_value string) cpp_types.Type {
return &extendedStruct{base_struct, []cpp_types.Type{}, optional_struct, optional_value}
}
type extendedStruct struct {
cpp_types.Type
extended_with []cpp_types.Type
optional_struct bool
optional_value string
}
func (extended_struct *extendedStruct) ExtendedWith() []cpp_types.Type {
return extended_struct.extended_with
}
func (extended_struct *extendedStruct) OptionalStruct() bool {
return extended_struct.optional_struct
}
func (extended_struct *extendedStruct) OptionalValue() string {
return extended_struct.optional_value
}
func ExtendedField(name string, typе cpp_types.Type, length, field cpp_types.FieldInfo) cpp_types.FieldInfo {
return &extendedField{cpp_types.Field(name, typе), length, field}
}
type ExtendedFieldInfo interface {
Length() cpp_types.FieldInfo
NestedField() cpp_types.FieldInfo
}
type extendedField struct {
cpp_types.FieldInfo
length cpp_types.FieldInfo
nested_field cpp_types.FieldInfo
}
func (field_info *extendedField) BaseFieldInfo() cpp_types.FieldInfo {
return field_info
}
func (field_info *extendedField) Length() cpp_types.FieldInfo {
return field_info.length
}
func (field_info *extendedField) NestedField() cpp_types.FieldInfo {
return field_info.nested_field
}
// Certain types come from platform files and vk.xml doesn't declare them.
// Not even category name is specified, so we have no idea if these are types
// or includes or anything else.
var known_types = map[string]string{
"_screen_context": "screen/screen.h",
"_screen_window": "screen/screen.h",
"_screen_buffer": "screen/screen.h",
"NvSciSyncAttrList": "nvscisync.h",
"NvSciSyncObj": "nvscisync.h",
"NvSciSyncFence": "nvscisync.h",
"NvSciBufAttrList": "nvscibuf.h",
"NvSciBufObj": "nvscibuf.h",
"char": "vk_platform",
"Display": "X11/Xlib.h",
"DWORD": "windows.h",
"float": "vk_platform",
"double": "vk_platform",
"GgpFrameToken": "ggp_c/vulkan_types.h",
"GgpStreamDescriptor": "ggp_c/vulkan_types.h",
"HANDLE": "windows.h",
"HINSTANCE": "windows.h",
"HMONITOR": "windows.h",
"HWND": "windows.h",
"IDirectFB": "directfb.h",
"IDirectFBSurface": "directfb.h",
"int": "",
"int8_t": "vk_platform",
"int16_t": "vk_platform",
"int32_t": "vk_platform",
"int64_t": "vk_platform",
"LPCWSTR": "windows.h",
"RROutput": "X11/extensions/Xrandr.h",
"SECURITY_ATTRIBUTES": "windows.h",
"size_t": "vk_platform",
"StdVideoDecodeH264Mvc": "vk_video/vulkan_video_codec_h264std_decode.h",
"StdVideoDecodeH264MvcElement": "vk_video/vulkan_video_codec_h264std_decode.h",
"StdVideoDecodeH264MvcElementFlags": "vk_video/vulkan_video_codec_h264std_decode.h",
"StdVideoDecodeH264PictureInfo": "vk_video/vulkan_video_codec_h264std_decode.h",
"StdVideoDecodeH264PictureInfoFlags": "vk_video/vulkan_video_codec_h264std_decode.h",
"StdVideoDecodeH264ReferenceInfo": "vk_video/vulkan_video_codec_h264std_decode.h",
"StdVideoDecodeH264ReferenceInfoFlags": "vk_video/vulkan_video_codec_h264std_decode.h",
"StdVideoDecodeH265PictureInfo": "vk_video/vulkan_video_codec_h265std_decode.h",
"StdVideoDecodeH265PictureInfoFlags": "vk_video/vulkan_video_codec_h265std_decode.h",
"StdVideoDecodeH265ReferenceInfo": "vk_video/vulkan_video_codec_h265std_decode.h",
"StdVideoDecodeH265ReferenceInfoFlags": "vk_video/vulkan_video_codec_h265std_decode.h",
"StdVideoEncodeH264PictureInfo": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH264PictureInfoFlags": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH264RefListModEntry": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH264RefMemMgmtCtrlOperations": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH264RefMgmtFlags": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH264RefPicMarkingEntry": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH264ReferenceInfo": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH264ReferenceListsInfo": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH264ReferenceInfoFlags": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH264SliceHeader": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH264SliceHeaderFlags": "vk_video/vulkan_video_codec_h264std_encode.h",
"StdVideoEncodeH265PictureInfo": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoEncodeH265PictureInfoFlags": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoEncodeH265ReferenceInfo": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoEncodeH265ReferenceListsInfo": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoEncodeH265ReferenceInfoFlags": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoEncodeH265ReferenceModificationFlags": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoEncodeH265ReferenceModifications": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoEncodeH265SliceHeader": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoEncodeH265SliceHeaderFlags": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoEncodeH265SliceSegmentHeader": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoEncodeH265SliceSegmentHeaderFlags": "vk_video/vulkan_video_codec_h265std_encode.h",
"StdVideoH264AspectRatioIdc": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264CabacInitIdc": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264ChromaFormatIdc": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264DisableDeblockingFilterIdc": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264HrdParameters": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264Level": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264LevelIdc": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264MemMgmtControlOp": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264ModificationOfPicNumsIdc": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264PictureParameterSet": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264PictureType": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264PocType": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264PpsFlags": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264ProfileIdc": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264ScalingLists": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264SequenceParameterSet": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264SequenceParameterSetVui": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264SliceType": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264SpsFlags": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264SpsVuiFlags": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264WeightedBiPredIdc": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH264WeightedBipredIdc": "vk_video/vulkan_video_codec_h264std.h",
"StdVideoH265PictureParameterSet": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265DecPicBufMgr": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265HrdFlags": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265HrdParameters": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265Level": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265LevelIdc": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265PictureType": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265PpsFlags": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265PredictorPaletteEntries": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265ProfileIdc": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265ScalingLists": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265SequenceParameterSet": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265SequenceParameterSetVui": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265SliceType": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265SpsFlags": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265SpsVuiFlags": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265SubLayerHrdParameters": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265VideoParameterSet": "vk_video/vulkan_video_codec_h265std.h",
"StdVideoH265VpsFlags": "vk_video/vulkan_video_codec_h265std.h",
"uint8_t": "vk_platform",
"uint16_t": "vk_platform",
"uint32_t": "vk_platform",
"uint64_t": "vk_platform",
"VisualID": "X11/Xlib.h",
"void": "vk_platform",
"Window": "X11/Xlib.h",
"wl_display": "wayland-client.h",
"wl_surface": "wayland-client.h",
"xcb_connection_t": "xcb/xcb.h",
"xcb_visualid_t": "xcb/xcb.h",
"xcb_window_t": "xcb/xcb.h",
"zx_handle_t": "zircon/types.h",
}
// We don't really parse defines since we don't have a full-blown compiler.
// Instead we rely on the fact that there are very few defines in vk.xml and just verify that they match out assumptions.
var known_defines = map[string]string{
"VK_MAKE_VERSION": "// DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead.\n" +
"#define VK_MAKE_VERSION(major, minor, patch) \\\n" +
" ((((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch)))",
"VK_VERSION_MAJOR": "// DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead.\n" +
"#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22U)",
"VK_VERSION_MINOR": "// DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead.\n" +
"#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU)",
"VK_VERSION_PATCH": "// DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead.\n" +
"#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU)",
"VK_MAKE_API_VERSION": "#define VK_MAKE_API_VERSION(variant, major, minor, patch) \\\n" +
" ((((uint32_t)(variant)) << 29U) | (((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch)))",
"VK_API_VERSION_VARIANT": "#define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29U)",
"VK_API_VERSION_MAJOR": "#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22U) & 0x7FU)",
"VK_API_VERSION_MINOR": "#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU)",
"VK_API_VERSION_PATCH": "#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU)",
"VKSC_API_VARIANT": "// Vulkan SC variant number\n#define VKSC_API_VARIANT 1",
"VK_API_VERSION": "// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.\n" +
"//#define VK_API_VERSION VK_MAKE_API_VERSION(0, 1, 0, 0) // Patch version should always be set to 0",
"VK_API_VERSION_1_0": "// Vulkan 1.0 version number\n" +
"#define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)// Patch version should always be set to 0",
"VK_API_VERSION_1_1": "// Vulkan 1.1 version number\n" +
"#define VK_API_VERSION_1_1 VK_MAKE_API_VERSION(0, 1, 1, 0)// Patch version should always be set to 0",
"VK_API_VERSION_1_2": "// Vulkan 1.2 version number\n" +
"#define VK_API_VERSION_1_2 VK_MAKE_API_VERSION(0, 1, 2, 0)// Patch version should always be set to 0",
"VK_API_VERSION_1_3": "// Vulkan 1.3 version number\n" +
"#define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0)// Patch version should always be set to 0",
"VKSC_API_VERSION_1_0": "// Vulkan SC 1.0 version number\n#define VKSC_API_VERSION_1_0 VK_MAKE_API_VERSION(VKSC_API_VARIANT, 1, 0, 0)// Patch version should always be set to 0",
"VK_HEADER_VERSION": "// Version of this file\n" +
"#define VK_HEADER_VERSION ",
"VK_HEADER_VERSION_COMPLETE": "// Complete version of this file\n" +
"#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION",
"VK_DEFINE_HANDLE": "\n#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;",
"VK_USE_64_BIT_PTR_DEFINES": "\n" +
"#ifndef VK_USE_64_BIT_PTR_DEFINES\n" +
" #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64)\n" +
" #define VK_USE_64_BIT_PTR_DEFINES 1\n" +
" #else\n" +
" #define VK_USE_64_BIT_PTR_DEFINES 0\n" +
" #endif\n" +
"#endif",
"VK_NULL_HANDLE": "\n" +
"#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE\n" +
" #if (VK_USE_64_BIT_PTR_DEFINES==1)\n" +
" #if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L))\n" +
" #define VK_NULL_HANDLE nullptr\n" +
" #else\n" +
" #define VK_NULL_HANDLE ((void*)0)\n" +
" #endif\n" +
" #else\n" +
" #define VK_NULL_HANDLE 0ULL\n" +
" #endif\n" +
"#endif\n" +
"#ifndef VK_NULL_HANDLE\n" +
" #define VK_NULL_HANDLE 0\n" +
"#endif",
}
var vulkan_known_defines = map[string]string{
"VK_DEFINE_HANDLE": "\n#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;",
"VK_DEFINE_NON_DISPATCHABLE_HANDLE": "\n" +
"#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE\n" +
" #if (VK_USE_64_BIT_PTR_DEFINES==1)\n" +
" #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;\n" +
" #else\n" +
" #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;\n" +
" #endif\n" +
"#endif",
}
var vulkansc_known_defines = map[string]string{
"VK_DEFINE_HANDLE": "\n#define VK_DEFINE_HANDLE(object) typedef struct object##_T* (object);",
"VK_DEFINE_NON_DISPATCHABLE_HANDLE": "\n" +
"#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE\n" +
" #if (VK_USE_64_BIT_PTR_DEFINES==1)\n" +
" #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *(object);\n" +
" #else\n" +
" #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t (object);\n" +
" #endif\n" +
"#endif",
}
var known_defines_obsoleted = map[string]string{
"VK_MAKE_VERSION": "// DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead.\n" +
"#define VK_MAKE_VERSION(major, minor, patch) \\\n" +
" ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch)))",
"VK_VERSION_MAJOR": "// DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead.\n" +
"#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)",
"VK_VERSION_MINOR": "// DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead.\n" +
"#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU)",
"VK_VERSION_PATCH": "// DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead.\n" +
"#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU)",
"VK_MAKE_API_VERSION": "#define VK_MAKE_API_VERSION(variant, major, minor, patch) \\\n" +
" ((((uint32_t)(variant)) << 29) | (((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch)))",
"VKSC_API_VARIANT": "// Vulkan SC variant number \n#define VKSC_API_VARIANT 1 // DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.",
"VK_API_VERSION_VARIANT": "#define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29)",
"VK_API_VERSION_MAJOR": "#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22) & 0x7FU)",
"VK_API_VERSION_MINOR": "#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU)",
"VK_API_VERSION_PATCH": "#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU)",
"VK_API_VERSION": "// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.\n" +
"//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0",
"VK_API_VERSION_1_0": "// Vulkan 1.0 version number\n" +
"#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)// Patch version should always be set to 0",
"VK_API_VERSION_1_1": "// Vulkan 1.1 version number\n" +
"#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)// Patch version should always be set to 0",
"VK_API_VERSION_1_2": "// Vulkan 1.2 version number\n" +
"#define VK_API_VERSION_1_2 VK_MAKE_VERSION(1, 2, 0)// Patch version should always be set to 0",
"VKSC_API_VERSION_1_0": "VK_MAKE_API_VERSION(VKSC_API_VARIANT, 1, 0, 0)// Patch version should always be set to 0",
"VK_HEADER_VERSION": "// Version of this file\n" +
"#define VK_HEADER_VERSION ",
"VK_HEADER_VERSION_COMPLETE": "// Complete version of this file\n" +
"#define VK_HEADER_VERSION_COMPLETE VK_MAKE_VERSION(1, 2, VK_HEADER_VERSION)",
"VK_USE_64_BIT_PTR_DEFINES": "\n" +
"#ifndef VK_USE_64_BIT_PTR_DEFINES\n" +
" #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)\n" +
" #define VK_USE_64_BIT_PTR_DEFINES 1\n" +
" #else\n" +
" #define VK_USE_64_BIT_PTR_DEFINES 0\n" +
" #endif\n" +
"#endif",
"VK_DEFINE_NON_DISPATCHABLE_HANDLE": "\n#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE)\n" +
"#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)\n" +
" #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;\n" +
"#else\n" +
" #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;\n" +
"#endif\n" +
"#endif",
"VK_NULL_HANDLE": "\n#define VK_NULL_HANDLE 0",
"VK_DEFINE_HANDLE": "\n#define VK_DEFINE_HANDLE(object) typedef struct object##_T* (object);",
}
func Unmarshal(data []byte) (*registry, error) {
var registry registry
err := xml.Unmarshal(data, ®istry)
if err != nil {
return nil, err
}
for i := range registry.Types {
typе := ®istry.Types[i]
if typе.Name == "" {
typе.Name, err = elementFromRawXML("name", typе.RawXML)
if err != nil {
return nil, err
}
}
if typе.Category == "" {
if requires, found := known_types[typе.Name]; !found || typе.Requires != requires {
return nil, errors.New("Unknown type without category: \"" + typе.Name + "\"")
}
typе.Category = "vk_platform"
}
if typе.Alias != "" || (typе.Category != "struct" && typе.Category != "union") {
if len(typе.Members) != 0 {
return nil, errors.New("Members in non-struct type : \"" + typе.Name + "\"")
}
} else {
for j := range typе.Members {
member := &typе.Members[j]
if member.Name == "" {
member.Name, err = elementFromRawXML("name", member.RawXML)
if err != nil {
return nil, err
}
}
if member.Type == "" {
member.Type, err = elementFromRawXML("type", member.RawXML)
if err != nil {
return nil, err
}
}
if member.Comment == "" && strings.Contains(member.RawXML, "") {
member.Comment, err = elementFromRawXML("comment", member.RawXML)
if err != nil {
return nil, err
}
}
}
}
}
for i := range registry.Commands {
command := ®istry.Commands[i]
if command.Name == "" {
command.Name, err = elementFromRawXML("name", command.Proto.RawXML)
if err != nil {
return nil, err
}
}
if command.Alias == "" {
if command.Proto.Type == "" {
command.Proto.Type, err = elementFromRawXML("type", command.Proto.RawXML)
if err != nil {
return nil, err
}
}
if command.Proto.Comment == "" && strings.Contains(command.Proto.RawXML, "") {
command.Proto.Type, err = elementFromRawXML("comment", command.Proto.RawXML)
if err != nil {
return nil, err
}
}
for j := range command.Params {
param := &command.Params[j]
if param.Name == "" {
param.Name, err = elementFromRawXML("name", param.RawXML)
if err != nil {
return nil, err
}
}
if param.Type == "" {
param.Type, err = elementFromRawXML("type", param.RawXML)
if err != nil {
return nil, err
}
}
if param.Comment == "" && strings.Contains(command.Proto.RawXML, "") {
param.Comment, err = elementFromRawXML("comment", param.RawXML)
if err != nil {
return nil, err
}
}
}
}
}
return ®istry, nil
}
func VulkanTypesfromXML(registry *registry) (sorted_type_names []string, types map[string]cpp_types.Type, sorted_command_names []string, commands map[string]cpp_types.Type, extensions map[string]int64, err error) {
types = vulkan_types.PlatformTypes()
// Note that we don't pre-calculate values for enums during initial parsing because vk.xml
// [ab]uses "enum" to define non-integer constants and integers defined-as-C-expression, too.
// E.g. "VK_LOD_CLAMP_NONE" as "1000.0f" or VK_QUEUE_FAMILY_FOREIGN_EXT as "(~0U-2)".
// We return "raw" string value here and only parse them on as-needed basis.
enum_values, enum_types, err := parseEnumValues(registry)
if err != nil {
return nil, nil, nil, nil, nil, err
}
// It's allowed in C/C++ to refer to not-yet defined type and type may even include pointer
// to itself. But other uses of undefined types are forbidden. Mutually directly (non-pointer)
// used types are *forbidden* in C/C++.
// Thus the graph of type uses is acyclic when pointers are excluded and we should be
// able to iteratively resolve all types by retrying failed types, expecting at least one
// type to resolve during an iteration.
// The first loop parsing resolves all directly (non-pointer) used types.
//
// Pointed types just became opaque, if undefined, and will be attempted to be resolved with
// a dedicated pass.
// The second loop (below) replaces opaque types referenced by pointer if they have been
// resolved at some point. Some types are supposed to just be opaque types and be only
// operated using pointers — but only platform-provided types, not vk.xml-defined types.
var xml_types_list []*typeInfo
next_xml_types_list := []*typeInfo{}
for index := range registry.Types {
next_xml_types_list = append(next_xml_types_list, ®istry.Types[index])
}
for len(next_xml_types_list) > 0 {
// If next list is the same as previous one then we have some kind of loop and types couldn't be defined.
if len(xml_types_list) == len(next_xml_types_list) {
return nil, nil, nil, nil, nil, errors.New("Cannot make any progress: type \"" + xml_types_list[0].Name + "\" refers to undefined type: \"" + xml_types_list[0].RawXML + "\"\"")
}
xml_types_list = next_xml_types_list
next_xml_types_list = []*typeInfo{}
for _, xml_type := range xml_types_list {
if _, ok := types[xml_type.Name]; ok {
if xml_type.Category == "vk_platform" {
continue
}
if xml_type.Api == "vulkansc" {
continue
}
return nil, nil, nil, nil, nil, errors.New("Duplicated type \"" + xml_type.Name + "\"")
}
if xml_type.Alias != "" {
if alias_target, ok := types[xml_type.Alias]; ok {
types[xml_type.Name] = cpp_types.AliasType(xml_type.Name, alias_target)
continue
}
next_xml_types_list = append(next_xml_types_list, xml_type)
continue
}
var c_type cpp_types.Type
switch xml_type.Category {
case "basetype":
c_type, err = vulkanBaseTypeFromXML(xml_type)
case "bitmask":
c_type, err = vulkanBitmaskTypeFromXML(xml_type, types)
case "define":
err := vulkanDefineTypeFromXML(xml_type)
if err != nil {
return nil, nil, nil, nil, nil, err
}
continue
case "enum":
c_type, err = vulkanEnumTypeFromXML(xml_type, enum_values, enum_types)
case "funcpointer":
c_type, err = vulkanFuncPoiterTypeFromXML(xml_type, types)
case "handle":
c_type, err = vulkanHandleTypeFromXML(xml_type, types)
case "include":
continue
case "struct":
c_type, err = vulkanStructTypeFromXML(xml_type, xml_type.StructExtends != "", types, enum_values)
case "union":
c_type, err = vulkanUnionTypeFromXML(xml_type, types, enum_values)
case "vk_platform":
return nil, nil, nil, nil, nil, errors.New("Unknown platform type \"" + xml_type.Name + "\"")
default:
return nil, nil, nil, nil, nil, errors.New("Unknown type category \"" + xml_type.Category + "\"")
}
// This type refers the unknown type. But it maybe because it needs some type defined further on in the xml. Defer its parsing to next pass.
if err == unknownType {
next_xml_types_list = append(next_xml_types_list, xml_type)
continue
}
if err != nil {
return nil, nil, nil, nil, nil, err
}
types[xml_type.Name] = c_type
}
}
// Populate extended_with info. We need to be the separate path since structs may refer other structs which are defined later in the vk.xml file.
for _, xml_type := range registry.Types {
if xml_type.Category == "struct" && xml_type.StructExtends != "" {
for _, name := range strings.Split(xml_type.StructExtends, ",") {
var extended_with *[]cpp_types.Type
if types[name].Kind(cpp_types.FirstArch) == cpp_types.Alias {
extended_with = &types[name].Elem(cpp_types.FirstArch).(*extendedStruct).extended_with
} else {
extended_with = &types[name].(*extendedStruct).extended_with
}
*extended_with = append(*extended_with, types[xml_type.Name])
}
}
}
// Resolve potentially circular references.
for type_name := range types {
// Here we rely on the fact that there are no types in Vulkan which are stuctural in one case yet non-structural
// in other cases. And also there are differently-structured structural types either.
typе := types[type_name]
if typе.Kind(cpp_types.FirstArch) == cpp_types.Ptr {
typе = typе.Elem(cpp_types.FirstArch)
}
if typе.Kind(cpp_types.FirstArch) != cpp_types.Func &&
typе.Kind(cpp_types.FirstArch) != cpp_types.Struct &&
typе.Kind(cpp_types.FirstArch) != cpp_types.Union {
continue
}
for i := uint(0); i < typе.NumField(cpp_types.FirstArch); i++ {
field := typе.Field(i, cpp_types.FirstArch)
if field.Type().Kind(cpp_types.FirstArch) != cpp_types.Ptr {
continue
}
pointee_type := field.Type().Elem(cpp_types.FirstArch)
if pointee_type.Kind(cpp_types.FirstArch) == cpp_types.Opaque {
if field_type, ok := types[pointee_type.Name(cpp_types.FirstArch)]; ok && field_type.Kind(cpp_types.FirstArch) != cpp_types.Opaque {
field.Type().(cpp_types.ModifyablePtrType).ReplaceElem(field_type)
}
} else if pointee_type.Kind(cpp_types.FirstArch) == cpp_types.Const &&
pointee_type.Elem(cpp_types.FirstArch).Kind(cpp_types.FirstArch) == cpp_types.Opaque {
if field_type, ok := types[pointee_type.Elem(cpp_types.FirstArch).Name(cpp_types.FirstArch)]; ok && field_type.Kind(cpp_types.FirstArch) != cpp_types.Opaque {
field.Type().(cpp_types.ModifyablePtrType).ReplaceElem(cpp_types.ConstType(field_type))
}
}
}
}
commands = make(map[string]cpp_types.Type)
for index := range registry.Commands {
command := registry.Commands[index]
// We'll link aliases below, after the final commands are constructed.
if command.Alias != "" {
continue
}
if result_type, ok := types[command.Proto.Type]; ok {
if space.ReplaceAllString(command.Proto.RawXML, " ") != fmt.Sprintf("%s %s", command.Proto.Type, command.Name) {
return nil, nil, nil, nil, nil, errors.New("Unexpected prototype \"" + command.Proto.RawXML + "\"")
}
fields_info, err := vulkanStructuralTypeMembersFromXML(command.Name, command.Params, types, enum_values)
if err != nil {
return nil, nil, nil, nil, nil, err
}
// Arrays decay into pointers when used as parameters of functions - but only one, outer, dimension.
// Convert arrays into pointers, leave other types intact.
params_info := []cpp_types.FieldInfo{}
for _, field_info := range fields_info {
if field_info.Type().Kind(cpp_types.FirstArch) == cpp_types.Array {
params_info = append(params_info, ExtendedField(
field_info.Name(),
cpp_types.PointerType(field_info.Type().Elem(cpp_types.FirstArch)),
field_info.BaseFieldInfo().(ExtendedFieldInfo).Length(),
field_info.BaseFieldInfo().(ExtendedFieldInfo).NestedField()))
} else {
params_info = append(params_info, field_info)
}
}
commands[command.Name] = cpp_types.FunctionType(result_type, params_info)
continue
}
return nil, nil, nil, nil, nil, errors.New("Unknown return function type \"" + command.Proto.Type + "\"")
}
// Now link aliases to the final command of the original function.
for index := range registry.Commands {
command := registry.Commands[index]
if command.Alias == "" {
continue
}
commands[command.Name] = commands[command.Alias]
}
sorted_type_names = []string{}
for name := range types {
sorted_type_names = append(sorted_type_names, name)
}
sort.Strings(sorted_type_names)
sorted_command_names = []string{}
for name := range commands {
sorted_command_names = append(sorted_command_names, name)
}
sort.Strings(sorted_command_names)
extensions = make(map[string]int64)
for extension_idx := range registry.Extensions {
extension := ®istry.Extensions[extension_idx]
extensions_spec := int64(-1)
for requires_idx := range extension.Requires {
requires := &extension.Requires[requires_idx]
for enum_field_idx := range requires.EnumFields {
enum_field := &requires.EnumFields[enum_field_idx]
if enum_field.Alias == "" && strings.HasSuffix(enum_field.Name, "_SPEC_VERSION") {
spec_version, err := strconv.ParseInt(enum_field.Value, 10, 32)
if err != nil {
return nil, nil, nil, nil, nil, err
}
if spec_version == -1 || extensions_spec != -1 {
errors.New("Couldn't find extensions SPEC_VERSION")
}
extensions_spec = spec_version
}
}
}
extensions[extension.Name] = extensions_spec
}
return sorted_type_names, types, sorted_command_names, commands, extensions, nil
}
func vulkanBaseTypeFromXML(typе *typeInfo) (cpp_types.Type, error) {
RawXML := strings.TrimSpace(space.ReplaceAllString(typе.RawXML, " "))
if typе.Name == "CAMetalLayer" {
if RawXML != "#ifdef __OBJC__ @class CAMetalLayer; #else typedef void CAMetalLayer; #endif" {
return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return cpp_types.OpaqueType("CAMetalLayer"), nil
}
if typе.Name == "MTLDevice_id" {
if RawXML != "#ifdef __OBJC__ @protocol MTLDevice; typedef id<MTLDevice> MTLDevice_id; #else typedef void* MTLDevice_id; #endif" {
return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return cpp_types.PointerType(cpp_types.VoidType), nil
}
if typе.Name == "MTLCommandQueue_id" {
if RawXML != "#ifdef __OBJC__ @protocol MTLCommandQueue; typedef id<MTLCommandQueue> MTLCommandQueue_id; #else typedef void* MTLCommandQueue_id; #endif" {
return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return cpp_types.PointerType(cpp_types.VoidType), nil
}
if typе.Name == "MTLBuffer_id" {
if RawXML != "#ifdef __OBJC__ @protocol MTLBuffer; typedef id<MTLBuffer> MTLBuffer_id; #else typedef void* MTLBuffer_id; #endif" {
return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return cpp_types.PointerType(cpp_types.VoidType), nil
}
if typе.Name == "MTLTexture_id" {
if RawXML != "#ifdef __OBJC__ @protocol MTLTexture; typedef id<MTLTexture> MTLTexture_id; #else typedef void* MTLTexture_id; #endif" {
return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return cpp_types.PointerType(cpp_types.VoidType), nil
}
if typе.Name == "MTLSharedEvent_id" {
if RawXML != "#ifdef __OBJC__ @protocol MTLSharedEvent; typedef id<MTLSharedEvent> MTLSharedEvent_id; #else typedef void* MTLSharedEvent_id; #endif" {
return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return cpp_types.PointerType(cpp_types.VoidType), nil
}
if typе.Name == "IOSurfaceRef" {
if RawXML != "typedef struct __IOSurface* IOSurfaceRef;" {
return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return cpp_types.PointerType(cpp_types.OpaqueType("__IOSurface")), nil
}
if RawXML == fmt.Sprintf("struct %s;", typе.Name) {
return cpp_types.OpaqueType(typе.Name), nil
}
if RawXML == fmt.Sprintf("typedef uint32_t %s;", typе.Name) {
return cpp_types.AliasType(typе.Name, cpp_types.UInt32TType), nil
}
if RawXML == fmt.Sprintf("typedef uint64_t %s;", typе.Name) {
return cpp_types.AliasType(typе.Name, cpp_types.UInt64TType), nil
}
if RawXML == fmt.Sprintf("typedef void* %s;", typе.Name) {
return cpp_types.AliasType(typе.Name, cpp_types.PointerType(cpp_types.VoidType)), nil
}
return nil, errors.New("Unexpected basetype \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
func vulkanBitmaskTypeFromXML(typе *typeInfo, types map[string]cpp_types.Type) (cpp_types.Type, error) {
RawXML := strings.TrimSpace(space.ReplaceAllString(typе.RawXML, " "))
if RawXML == fmt.Sprintf("typedef VkFlags %s;", typе.Name) {
return cpp_types.AliasType(typе.Name, types["VkFlags"]), nil
}
if RawXML == fmt.Sprintf("typedef VkFlags64 %s;", typе.Name) {
return cpp_types.AliasType(typе.Name, types["VkFlags64"]), nil
}
return nil, errors.New("Unexpected bitmask \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
func vulkanDefineTypeFromXML(typе *typeInfo) error {
if typе.Api == "vulkan" {
if define, ok := vulkan_known_defines[typе.Name]; ok {
if define != typе.RawXML {
return errors.New("Unmatched define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return nil
}
} else if typе.Api == "vulkansc" {
if define, ok := vulkansc_known_defines[typе.Name]; ok {
if define != typе.RawXML {
return errors.New("Unmatched define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return nil
}
} else {
if define, ok := vulkan_known_defines[typе.Name]; ok {
if define == typе.RawXML {
return nil
}
}
if define, ok := vulkansc_known_defines[typе.Name]; ok {
if define != typе.RawXML {
return errors.New("Unmatched define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return nil
}
}
if define, ok := known_defines[typе.Name]; ok {
// Most defines are stable and since we don't parse them we just ensure they match our expectations.
if typе.Name != "VK_HEADER_VERSION" && typе.Name != "VK_HEADER_VERSION_COMPLETE" {
if define != typе.RawXML {
if obsolete_define, ok := known_defines_obsoleted[typе.Name]; ok {
if obsolete_define == typе.RawXML {
return nil
}
return errors.New("Unmatched define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return errors.New("Unknown obsolete define \"" + typе.Name + "\"")
}
return nil
}
// Note: VK_HEADER_VERSION is updated every time vk.xml is updated thus we couldn't hardcode it.
// VK_HEADER_VERSION_COMPLETE is updted when new, incompatible version of Vulkan is released.
if !strings.HasPrefix(typе.RawXML, define) {
return errors.New("Unmatched define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
return nil
}
return errors.New("Unknown define \"" + typе.Name + "\"")
}
func vulkanEnumTypeFromXML(typе *typeInfo, enum_values map[string]*enumFieldInfo, enum_types map[string][]*enumFieldInfo) (cpp_types.Type, error) {
fits_in_int32 := true
fits_in_uint32 := true
// Duplicate logic from Khronos's generator.py: use int32_t if everything fits into int32_t,
// then uint32_t, then int64_t.
basetype := cpp_types.Int32TType
for _, element := range enum_types[typе.Name] {
value, err := enumFieldValue(element, enum_values)
if err != nil {
return nil, err
}
if int64(int32(value)) != value {
fits_in_int32 = false
}
if int64(uint32(value)) != value {
fits_in_uint32 = false
}
}
if !fits_in_int32 {
if fits_in_uint32 {
basetype = cpp_types.UInt32TType
} else {
basetype = cpp_types.Int64TType
}
}
values := []cpp_types.EnumFieldInfo{}
for _, element := range enum_types[typе.Name] {
value, _ := enumFieldValue(element, enum_values)
values = append(values, cpp_types.EnumField(element.Name, basetype, element.Alias, value))
}
return cpp_types.EnumType(typе.Name, basetype, values), nil
}
func vulkanFuncPoiterTypeFromXML(typе *typeInfo, types map[string]cpp_types.Type) (cpp_types.Type, error) {
definition := strings.TrimSpace(typе.RawXML)
if !strings.HasPrefix(definition, "typedef ") ||
!strings.HasSuffix(definition, ");") ||
strings.Count(definition, " (VKAPI_PTR *") != 1 ||
strings.Count(definition, ")(") != 1 {
return nil, errors.New("Couldn't determine function type from \"" + definition + "\"")
}
split := strings.Split(definition[8:len(definition)-2], " (VKAPI_PTR *")
var return_type cpp_types.Type
return_type_string := split[0]
if strings.HasSuffix(return_type_string, "*") {
return_typе, ok := types[return_type_string[0:len(return_type_string)-1]]
if !ok {
return nil, errors.New("Couldn't determine function type \"" + return_type_string + "\"")
}
return_type = cpp_types.PointerType(return_typе)
} else {
return_typе, ok := types[return_type_string]
if !ok {
return nil, errors.New("Couldn't determine function type \"" + return_type_string + "\"")
}
return_type = return_typе
}
parameters := strings.Split(split[1], ")(")[1]
var parameter_types []cpp_types.FieldInfo
if parameters == "void" {
return cpp_types.PointerType(cpp_types.FunctionType(return_type, parameter_types)), nil
}
for _, parameter := range strings.Split(parameters, ",") {
parameter = strings.TrimSpace(parameter)
parameter_type_len := strings.LastIndex(parameter, " ")
parameter_type := strings.TrimSpace(parameter[:parameter_type_len])
parameter_name := strings.TrimSpace(parameter[parameter_type_len+1:])
if strings.HasPrefix(parameter_type, "") &&
strings.HasSuffix(parameter_type, "") {
parameter_types = append(
parameter_types,
ExtendedField(parameter_name, types[parameter_type[6:len(parameter_type)-7]],
nil,
nil))
} else if strings.HasPrefix(parameter_type, "const ") &&
strings.HasSuffix(parameter_type, "*") {
pointee_type_name := parameter_type[12 : len(parameter_type)-8]
if pointee_type, ok := types[pointee_type_name]; ok {
parameter_types = append(
parameter_types,
ExtendedField(
parameter_name,
cpp_types.PointerType(cpp_types.ConstType(pointee_type)),
nil,
nil))
} else {
parameter_types = append(
parameter_types,
ExtendedField(
parameter_name,
cpp_types.PointerType(cpp_types.ConstType(cpp_types.OpaqueType(pointee_type_name))),
nil,
nil))
}
} else if strings.HasPrefix(parameter_type, "") &&
strings.HasSuffix(parameter_type, "*") {
pointee_type_name := parameter_type[6 : len(parameter_type)-8]
if pointee_type, ok := types[pointee_type_name]; ok {
parameter_types = append(
parameter_types,
ExtendedField(
parameter_name,
cpp_types.PointerType(pointee_type),
nil,
nil))
} else {
parameter_types = append(
parameter_types,
ExtendedField(
parameter_name,
cpp_types.PointerType(cpp_types.OpaqueType(pointee_type_name)),
nil,
nil))
}
} else {
return nil, errors.New("Couldn't determine parameter type \"" + parameter_type + "\"")
}
}
return cpp_types.PointerType(cpp_types.FunctionType(return_type, parameter_types)), nil
}
func vulkanHandleTypeFromXML(typе *typeInfo, types map[string]cpp_types.Type) (cpp_types.Type, error) {
if typе.RawXML == fmt.Sprintf("VK_DEFINE_HANDLE(%s)", typе.Name) {
return cpp_types.AliasType(typе.Name, cpp_types.PointerType(cpp_types.OpaqueType(fmt.Sprintf("struct %s_T", typе.Name)))), nil
} else if typе.RawXML == fmt.Sprintf("VK_DEFINE_NON_DISPATCHABLE_HANDLE(%s)", typе.Name) {
return cpp_types.ArchDependentType(
cpp_types.AliasType(typе.Name, cpp_types.UInt64TType),
cpp_types.AliasType(typе.Name, cpp_types.PointerType(cpp_types.OpaqueType(fmt.Sprintf("struct %s_T", typе.Name)))),
cpp_types.AliasType(typе.Name, cpp_types.UInt64TType),
cpp_types.AliasType(typе.Name, cpp_types.PointerType(cpp_types.OpaqueType(fmt.Sprintf("struct %s_T", typе.Name)))),
cpp_types.AliasType(typе.Name, cpp_types.UInt64TType),
cpp_types.AliasType(typе.Name, cpp_types.PointerType(cpp_types.OpaqueType(fmt.Sprintf("struct %s_T", typе.Name))))), nil
}
return nil, errors.New("Unexpected handle \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
}
func vulkanStructTypeFromXML(typе *typeInfo, optional_struct bool, types map[string]cpp_types.Type, enum_values map[string]*enumFieldInfo) (cpp_types.Type, error) {
fields_info, err := vulkanStructuralTypeMembersFromXML(typе.Name, typе.Members, types, enum_values)
if err != nil {
return nil, err
}
optional_enum_value := ""
if optional_struct {
if typе.Members[0].Type != "VkStructureType" || fields_info[0].Name() != "sType" || fields_info[1].Name() != "pNext" {
return nil, errors.New("Struct extension must have first field named VkStructureType sType and second named pNext")
}
optional_enum_value = typе.Members[0].Value
}
return ExtendedStruct(cpp_types.StructType(typе.Name, fields_info), optional_struct, optional_enum_value), nil
}
func vulkanUnionTypeFromXML(typе *typeInfo, types map[string]cpp_types.Type, enum_values map[string]*enumFieldInfo) (cpp_types.Type, error) {
fields_info, err := vulkanStructuralTypeMembersFromXML(typе.Name, typе.Members, types, enum_values)
if err != nil {
return nil, err
}
return cpp_types.UnionType(typе.Name, fields_info), nil
}
var space = regexp.MustCompile(`\s+`)
func vulkanStructuralTypeMembersFromXML(name string, members []structuralMemberInfo, types map[string]cpp_types.Type, enum_values map[string]*enumFieldInfo) (result []cpp_types.FieldInfo, err error) {
fields_info := []*extendedField{}
field_map := make(map[string]*extendedField)
for _, member := range members {
html := strings.TrimSpace(member.RawXML)
// Note: checks below count only opening tags because XML parser guarantees that closing tags are there and they
// match opening tags.
if member.Comment != "" {
if comments := strings.Count(html, ""); comments > 1 {
return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
} else if comments == 1 {
html = strings.Split(html, "")[0] + strings.Split(html, "")[1]
}
}
if strings.Count(html, "") != 1 {
return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
}
text_before_type_name := strings.TrimSpace(strings.Split(html, "")[0])
text_after_type_name := strings.TrimSpace(strings.Split(html, "")[1])
if strings.Count(html, "") > 1 {
return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
} else if strings.Count(html, "") == 1 {
text_after_type_name = strings.Split(text_after_type_name, "")[0] + strings.Split(text_after_type_name, "")[1]
}
text_after_type_name = strings.TrimSpace(space.ReplaceAllString(text_after_type_name, " "))
member_type, raw_type_known := types[member.Type]
// TODO(b/268638193): handle comma-separated list of allowed functions.
if member.Type == "VkBaseInStructure" || member.Type == "VkBaseOutStructure" {
member_type = types[member.Validstructs]
}
if len(text_after_type_name) > 0 && text_after_type_name[0] == '*' {
if raw_type_known {
if text_before_type_name == "const" || text_before_type_name == "const struct" {
member_type = cpp_types.ConstType(member_type)
} else if text_before_type_name != "" && text_before_type_name != "struct" {
return nil, errors.New("Unexpected prefix in \"" + name + "\": \"" + html + "\"\"")
}
} else {
member_type = cpp_types.OpaqueType(member.Type)
// Note that if type is opaque in C (but not C++!) if has to be prefixed with either "const struct" or "struct".
// If we only see "const" or nothing then that type is not opaque and is supposed to be declared somewhere below.
// Return unknownType if that happens.
if text_before_type_name == "" || text_before_type_name == "const" {
return nil, unknownType
} else if text_before_type_name == "const struct" {
member_type = cpp_types.ConstType(member_type)
} else if text_before_type_name != "struct" {
return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
}
}
if text_after_type_name == "*" {
member_type = cpp_types.PointerType(member_type)
} else if text_after_type_name == "**" {
member_type = cpp_types.PointerType(cpp_types.PointerType(member_type))
} else if text_after_type_name == "* const*" || text_after_type_name == "* const *" {
member_type = cpp_types.PointerType(cpp_types.ConstType(cpp_types.PointerType(member_type)))
} else {
return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
}
} else {
if !raw_type_known {
return nil, unknownType
}
if text_before_type_name == "const" {
member_type = cpp_types.ConstType(member_type)
} else if text_before_type_name != "" {
return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
}
// Bitfields are not actually supposed to be used in vk.xml — and it even has comment which says exactly that!
// Unfortunately they are already there and couldn't be removed (backward compatibility!).
// Replace "uint32_t :8" with "uint8_t" and "uint32_t :24" with "uint8_t[3]".
// This is hack but provides proper layout.
if text_after_type_name == ":8" {
if member.Type != "uint32_t" && member.Type != "VkGeometryInstanceFlagsKHR" {
return nil, errors.New("Unsupported bitfield type name \"" + name + "\": \"" + html + "\"\"")
}
member_type = cpp_types.UInt8TType
} else if text_after_type_name == ":24" {
if member.Type != "uint32_t" {
return nil, errors.New("Unsupported bitfield type name \"" + name + "\": \"" + html + "\"\"")
}
member_type = cpp_types.ArrayType(cpp_types.UInt8TType, 3)
} else {
indexes := []uint{}
for strings.HasSuffix(text_after_type_name, "]") {
array_size_text := text_after_type_name[strings.LastIndex(text_after_type_name, "[")+1 : len(text_after_type_name)-1]
text_after_type_name = text_after_type_name[0 : len(text_after_type_name)-len(array_size_text)-2]
if strings.HasPrefix(array_size_text, "") {
if !strings.HasSuffix(array_size_text, "") {
return nil, errors.New("Unsupported array index \"" + array_size_text + "\"\"")
}
array_size_text = enum_values[array_size_text[6:len(array_size_text)-7]].Value
}
array_size, err := strconv.ParseInt(array_size_text, 10, 32)
if err != nil {
return nil, err
}
indexes = append(indexes, uint(array_size))
}
for i := len(indexes) - 1; i >= 0; i-- {
member_type = cpp_types.ArrayType(member_type, indexes[i])
}
if text_after_type_name != "" {
return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
}
}
}
new_field := extendedField{cpp_types.Field(member.Name, member_type), nil, nil}
if member.Api != "vulkansc" {
fields_info = append(fields_info, &new_field)
field_map[member.Name] = &new_field
}
}
for _, member := range members {
// This strange notion is used in VkAccelerationStructureBuildGeometryInfoKHR structure where only one of two fields can be non-NULL:
//
// We treat it as here.
if strings.HasSuffix(member.Length, ",1") {
if length, ok := field_map[member.Length[0:len(member.Length)-2]]; ok {
field_map[member.Name].length = length
} else {
return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
}
// Some corner cases have len like “pAllocateInfo->descriptorSetCount”.
// Currently that only have one level, structures are always input to function,
// and we don't need to convert these.
//
// We need to detect case where that wouldn't be true in the future.
// Only then would we know how to handle these.
//
// We parse these and pass the information to calling module because it's
// not easy to see here whether types are compatible on all platforms here
// or not (and there are more than a couple of such types).
} else if strings.Contains(member.Length, "->") {
split_length := strings.Split(member.Length, "->")
if len(split_length) > 2 {
return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
}
length, ok := field_map[split_length[0]]
if !ok {
return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
}
field_map[member.Name].length = length
// Note: we are dealing with pointer to const data structure here.
// That's why we dereference twice.
length_type := length.Type()
if length_type.Kind(cpp_types.FirstArch) != cpp_types.Ptr {
return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
}
length_type = length_type.Elem(cpp_types.FirstArch)
if length_type.Kind(cpp_types.FirstArch) == cpp_types.Const {
length_type = length_type.Elem(cpp_types.FirstArch)
}
if length_type.Kind(cpp_types.FirstArch) != cpp_types.Struct &&
length_type.Kind(cpp_types.FirstArch) != cpp_types.Union {
return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
}
for i := uint(0); i < length_type.NumField(cpp_types.FirstArch); i++ {
if length_type.Field(i, cpp_types.FirstArch).Name() == split_length[1] {
field_map[member.Name].nested_field = length_type.Field(i, cpp_types.FirstArch)
}
}
if field_map[member.Name].nested_field == nil {
return nil, errors.New("Unexpected field referred by len in \"" + member.Name + "\"")
}
// If len is too complicated it may be represented as LaTeX expression (e.g.
// latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil] for pSampleMask)
// In these cases altlength represents for C, but it may be quite hard to parse that
// too.
// Thankfully for now all such complex fields pass arrays of uint{8,16,32}_t which
// we never translate. Note: we currently don't translate uint64_t even if these
// are not 100% compatible on all platforms. The only direction where that may
// matter would be x86 (32bit) to AArch32 translation (which we don't support),
// but arrays of uint{8,16,32}_t are 100% compatible on all platforums.
//
// Verify that it's so and ignore "len" in that case.
} else if member.AltLength != "" {
typе := field_map[member.Name].Type()
if typе.Kind(cpp_types.FirstArch) != cpp_types.Ptr {
return nil, errors.New("Unexpected altlen field in \"" + member.Name + "\"")
}
element_type := typе.Elem(cpp_types.FirstArch)
if element_type.Kind(cpp_types.FirstArch) == cpp_types.Const {
element_type = element_type.Elem(cpp_types.FirstArch)
}
if element_type.Kind(cpp_types.FirstArch) == cpp_types.Alias {
element_type = element_type.Elem(cpp_types.FirstArch)
}
if element_type.Kind(cpp_types.FirstArch) != cpp_types.UInt8T &&
element_type.Kind(cpp_types.FirstArch) != cpp_types.UInt16T &&
element_type.Kind(cpp_types.FirstArch) != cpp_types.UInt32T {
return nil, errors.New("Unexpected altlen field in \"" + member.Name + "\"")
}
} else if member.Length != "" && member.Length != "null-terminated" && !strings.HasSuffix(member.Length, ",null-terminated") {
if length, ok := field_map[member.Length]; ok {
field_map[member.Name].length = length
} else {
return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
}
}
}
result = make([]cpp_types.FieldInfo, len(fields_info))
for index, field_info := range fields_info {
result[index] = field_info
}
return result, nil
}
var unknownType = errors.New("Couldn't find type")
func elementFromRawXML(element_name string, raw_XML string) (string, error) {
opening_tag := "<" + element_name + ">"
closing_tag := "" + element_name + ">"
if strings.Count(raw_XML, opening_tag) != 1 {
return "", errors.New("Couldn't determine element \"" + element_name + "\" from \"" + raw_XML + "\"")
}
if strings.Count(raw_XML, closing_tag) != 1 {
return "", errors.New("Couldn't determine element \"" + element_name + "\" from \"" + raw_XML + "\"")
}
return strings.Split(strings.Split(
raw_XML, opening_tag)[1], closing_tag)[0], nil
}
func parseEnumValues(registry *registry) (map[string]*enumFieldInfo, map[string][]*enumFieldInfo, error) {
enum_values := make(map[string]*enumFieldInfo)
enum_types := make(map[string][]*enumFieldInfo)
for enum_idx := range registry.Enums {
enum := ®istry.Enums[enum_idx]
for enum_field_idx := range enum.EnumFields {
enum_field := &enum.EnumFields[enum_field_idx]
if _, ok := enum_values[enum_field.Name]; ok {
return nil, nil, errors.New("Duplicated enum value \"" + enum.Name + "\"")
}
enum_values[enum_field.Name] = enum_field
if value, ok := enum_types[enum.Name]; ok {
enum_types[enum.Name] = append(value, enum_field)
} else {
enum_types[enum.Name] = append([]*enumFieldInfo{}, enum_field)
}
}
}
for feature_idx := range registry.Features {
feature := ®istry.Features[feature_idx]
for enum_field_idx := range feature.EnumFields {
enum_field := &feature.EnumFields[enum_field_idx]
if enum_field.Extends != "" {
if _, ok := enum_values[enum_field.Name]; ok {
return nil, nil, errors.New("Duplicated enum value \"" + enum_field.Name + "\"")
}
enum_values[enum_field.Name] = enum_field
enum_types[enum_field.Extends] = append(enum_types[enum_field.Extends], enum_field)
}
}
}
for extension_idx := range registry.Extensions {
extension := ®istry.Extensions[extension_idx]
for requires_idx := range extension.Requires {
requires := &extension.Requires[requires_idx]
for enum_field_idx := range requires.EnumFields {
enum_field := &requires.EnumFields[enum_field_idx]
if enum_field.ExtID == 0 {
enum_field.ExtID = extension.ID
}
if enum_field.Extends != "" {
if old_enum_filed, ok := enum_values[enum_field.Name]; ok {
// Some values are declared twice, once as feature and once as extension.
// It's Ok as long as values match.
if enum_field.Alias != "" && enum_field.Alias == old_enum_filed.Alias {
continue
}
if enum_field.Alias == "" || old_enum_filed.Alias == "" {
continue
}
value, err1 := enumFieldValue(enum_field, nil)
old_value, err2 := enumFieldValue(old_enum_filed, nil)
if value == old_value && err1 == nil && err2 == nil {
continue
}
return nil, nil, errors.New("Duplicated enum value \"" + enum_field.Name + "\"")
}
enum_values[enum_field.Name] = enum_field
enum_types[enum_field.Extends] = append(enum_types[enum_field.Extends], enum_field)
}
}
}
}
return enum_values, enum_types, nil
}
func enumFieldValue(enum_field *enumFieldInfo, all_enum_fields map[string]*enumFieldInfo) (int64, error) {
if enum_field.Value != "" {
if strings.HasPrefix(enum_field.Value, "0x") {
return strconv.ParseInt(enum_field.Value[2:], 16, 64)
}
return strconv.ParseInt(enum_field.Value, 10, 64)
}
if enum_field.BitPos != "" {
result, err := strconv.ParseInt(enum_field.BitPos, 10, 64)
if err != nil {
return 0, err
}
return 1 << result, nil
}
if enum_field.Alias != "" {
return enumFieldValue(all_enum_fields[enum_field.Alias], all_enum_fields)
}
var result = 1000000000 + (enum_field.ExtID-1)*1000 + enum_field.Offset
if enum_field.Dir == "" {
return result, nil
}
return -result, nil
}